text: // Utility function
  function Util () {};
  
  /* 
  	class manipulation functions
  */
  Util.hasClass = function(el, className) {
  	return el.classList.contains(className);
  };
  
  Util.addClass = function(el, className) {
  	var classList = className.split(' ');
   	el.classList.add(classList[0]);
   	if (classList.length > 1) Util.addClass(el, classList.slice(1).join(' '));
  };
  
  Util.removeClass = function(el, className) {
  	var classList = className.split(' ');
  	el.classList.remove(classList[0]);	
  	if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(' '));
  };
  
  Util.toggleClass = function(el, className, bool) {
  	if(bool) Util.addClass(el, className);
  	else Util.removeClass(el, className);
  };
  
  Util.setAttributes = function(el, attrs) {
    for(var key in attrs) {
      el.setAttribute(key, attrs[key]);
    }
  };
  
  /* 
    DOM manipulation
  */
  Util.getChildrenByClassName = function(el, className) {
    var children = el.children,
      childrenByClass = [];
    for (var i = 0; i < children.length; i++) {
      if (Util.hasClass(children[i], className)) childrenByClass.push(children[i]);
    }
    return childrenByClass;
  };
  
  Util.is = function(elem, selector) {
    if(selector.nodeType){
      return elem === selector;
    }
  
    var qa = (typeof(selector) === 'string' ? document.querySelectorAll(selector) : selector),
      length = qa.length,
      returnArr = [];
  
    while(length--){
      if(qa[length] === elem){
        return true;
      }
    }
  
    return false;
  };
  
  /* 
  	Animate height of an element
  */
  Util.setHeight = function(start, to, element, duration, cb, timeFunction) {
  	var change = to - start,
  	    currentTime = null;
  
    var animateHeight = function(timestamp){  
      if (!currentTime) currentTime = timestamp;         
      var progress = timestamp - currentTime;
      if(progress > duration) progress = duration;
      var val = parseInt((progress/duration)*change + start);
      if(timeFunction) {
        val = Math[timeFunction](progress, start, to - start, duration);
      }
      element.style.height = val+"px";
      if(progress < duration) {
          window.requestAnimationFrame(animateHeight);
      } else {
      	if(cb) cb();
      }
    };
    
    //set the height of the element before starting animation -> fix bug on Safari
    element.style.height = start+"px";
    window.requestAnimationFrame(animateHeight);
  };
  
  /* 
  	Smooth Scroll
  */
  
  Util.scrollTo = function(final, duration, cb, scrollEl) {
    var element = scrollEl || window;
    var start = element.scrollTop || document.documentElement.scrollTop,
      currentTime = null;
  
    if(!scrollEl) start = window.scrollY || document.documentElement.scrollTop;
        
    var animateScroll = function(timestamp){
    	if (!currentTime) currentTime = timestamp;        
      var progress = timestamp - currentTime;
      if(progress > duration) progress = duration;
      var val = Math.easeInOutQuad(progress, start, final-start, duration);
      element.scrollTo(0, val);
      if(progress < duration) {
        window.requestAnimationFrame(animateScroll);
      } else {
        cb && cb();
      }
    };
  
    window.requestAnimationFrame(animateScroll);
  };
  
  /* 
    Focus utility classes
  */
  
  //Move focus to an element
  Util.moveFocus = function (element) {
    if( !element ) element = document.getElementsByTagName("body")[0];
    element.focus();
    if (document.activeElement !== element) {
      element.setAttribute('tabindex','-1');
      element.focus();
    }
  };
  
  /* 
    Misc
  */
  
  Util.getIndexInArray = function(array, el) {
    return Array.prototype.indexOf.call(array, el);
  };
  
  Util.cssSupports = function(property, value) {
    if('CSS' in window) {
      return CSS.supports(property, value);
    } else {
      var jsProperty = property.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase();});
      return jsProperty in document.body.style;
    }
  };
  
  // merge a set of user options into plugin defaults
  // https://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
  Util.extend = function() {
    // Variables
    var extended = {};
    var deep = false;
    var i = 0;
    var length = arguments.length;
  
    // Check if a deep merge
    if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
      deep = arguments[0];
      i++;
    }
  
    // Merge the object into the extended object
    var merge = function (obj) {
      for ( var prop in obj ) {
        if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
          // If deep merge and property is an object, merge properties
          if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
            extended[prop] = extend( true, extended[prop], obj[prop] );
          } else {
            extended[prop] = obj[prop];
          }
        }
      }
    };
  
    // Loop through each object and conduct a merge
    for ( ; i < length; i++ ) {
      var obj = arguments[i];
      merge(obj);
    }
  
    return extended;
  };
  
  // Check if Reduced Motion is enabled
  Util.osHasReducedMotion = function() {
    if(!window.matchMedia) return false;
    var matchMediaObj = window.matchMedia('(prefers-reduced-motion: reduce)');
    if(matchMediaObj) return matchMediaObj.matches;
    return false; // return false if not supported
  }; 
  
  /* 
  	Polyfills
  */
  //Closest() method
  if (!Element.prototype.matches) {
  	Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
  }
  
  if (!Element.prototype.closest) {
  	Element.prototype.closest = function(s) {
  		var el = this;
  		if (!document.documentElement.contains(el)) return null;
  		do {
  			if (el.matches(s)) return el;
  			el = el.parentElement || el.parentNode;
  		} while (el !== null && el.nodeType === 1); 
  		return null;
  	};
  }
  
  //Custom Event() constructor
  if ( typeof window.CustomEvent !== "function" ) {
  
    function CustomEvent ( event, params ) {
      params = params || { bubbles: false, cancelable: false, detail: undefined };
      var evt = document.createEvent( 'CustomEvent' );
      evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
      return evt;
     }
  
    CustomEvent.prototype = window.Event.prototype;
  
    window.CustomEvent = CustomEvent;
  }
  
  /* 
  	Animation curves
  */
  Math.easeInOutQuad = function (t, b, c, d) {
  	t /= d/2;
  	if (t < 1) return c/2*t*t + b;
  	t--;
  	return -c/2 * (t*(t-2) - 1) + b;
  };
  
  Math.easeInQuart = function (t, b, c, d) {
  	t /= d;
  	return c*t*t*t*t + b;
  };
  
  Math.easeOutQuart = function (t, b, c, d) { 
    t /= d;
  	t--;
  	return -c * (t*t*t*t - 1) + b;
  };
  
  Math.easeInOutQuart = function (t, b, c, d) {
  	t /= d/2;
  	if (t < 1) return c/2*t*t*t*t + b;
  	t -= 2;
  	return -c/2 * (t*t*t*t - 2) + b;
  };
  
  Math.easeOutElastic = function (t, b, c, d) {
    var s=1.70158;var p=d*0.7;var a=c;
    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
    if (a < Math.abs(c)) { a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin (c/a);
    return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
  };
  
  
  /* JS Utility Classes */
  
  // make focus ring visible only for keyboard navigation (i.e., tab key) 
  (function() {
    var focusTab = document.getElementsByClassName('js-tab-focus'),
      shouldInit = false,
      outlineStyle = false,
      eventDetected = false;
  
    function detectClick() {
      if(focusTab.length > 0) {
        resetFocusStyle(false);
        window.addEventListener('keydown', detectTab);
      }
      window.removeEventListener('mousedown', detectClick);
      outlineStyle = false;
      eventDetected = true;
    };
  
    function detectTab(event) {
      if(event.keyCode !== 9) return;
      resetFocusStyle(true);
      window.removeEventListener('keydown', detectTab);
      window.addEventListener('mousedown', detectClick);
      outlineStyle = true;
    };
  
    function resetFocusStyle(bool) {
      var outlineStyle = bool ? '' : 'none';
      for(var i = 0; i < focusTab.length; i++) {
        focusTab[i].style.setProperty('outline', outlineStyle);
      }
    };
  
    function initFocusTabs() {
      if(shouldInit) {
        if(eventDetected) resetFocusStyle(outlineStyle);
        return;
      }
      shouldInit = focusTab.length > 0;
      window.addEventListener('mousedown', detectClick);
    };
  
    initFocusTabs();
    window.addEventListener('initFocusTabs', initFocusTabs);
  }());
  
  function resetFocusTabsStyle() {
    window.dispatchEvent(new CustomEvent('initFocusTabs'));
  };
  // File#: _1_3d-card
  // Usage: codyhouse.co/license
  (function() {
    var TdCard = function(element) {
      this.element = element;
      this.maxRotation = parseInt(this.element.getAttribute('data-rotation')) || 2; // rotation max value
      this.perspective = this.element.getAttribute('data-perspective') || '300px'; // perspective value
      this.rotateX = 0;
      this.rotateY = 0;
      this.partRotateX = 0;
      this.partRotateY = 0;
      this.deltaRotation = 0.3;
      this.animating = false;
      initTdEvents(this);
    };
  
    function initTdEvents(tdCard) {
      // detect mouse hovering over the card
      tdCard.element.addEventListener('mousemove', function(event){
        if(tdCard.animating) return;
        tdCard.animating = window.requestAnimationFrame(moveCard.bind(tdCard, event, false));
      });
  
      // detect mouse leaving the card
      tdCard.element.addEventListener('mouseleave', function(event){
        if(tdCard.animating) window.cancelAnimationFrame(tdCard.animating);
        tdCard.animating = window.requestAnimationFrame(moveCard.bind(tdCard, event, true));
      });
    };
  
    function moveCard(event, leaving) {
      // get final rotation values
      setRotationLevel(this, event, leaving);
      
      // update rotation values
      updateRotationLevel(this);
    };
  
    function setRotationLevel(tdCard, event, leaving) {
      if(leaving) {
        tdCard.rotateX = 0;
        tdCard.rotateY = 0;
        return;
      }
  
      var wrapperPosition = tdCard.element.getBoundingClientRect();
      var rotateY = 2*(tdCard.maxRotation/wrapperPosition.width)*(event.clientX - wrapperPosition.left - wrapperPosition.width/2);
      var rotateX = 2*(tdCard.maxRotation/wrapperPosition.height)*(wrapperPosition.top - event.clientY + wrapperPosition.height/2);
  
      if(rotateY > tdCard.maxRotation) rotateY = tdCard.maxRotation;
      if(rotateY < -1*tdCard.maxRotation) rotateY = -tdCard.maxRotation;
      if(rotateX > tdCard.maxRotation) rotateX = tdCard.maxRotation;
      if(rotateX < -1*tdCard.maxRotation) rotateX = -tdCard.maxRotation;
  
      tdCard.rotateX = rotateX;
      tdCard.rotateY = rotateY;
    };
  
    function updateRotationLevel(tdCard) {
      if( (tdCard.partRotateX == tdCard.rotateX) && (tdCard.partRotateY == tdCard.rotateY)) {
        tdCard.animating = false;
        return;
      }
  
      tdCard.partRotateX = getPartRotation(tdCard.partRotateX, tdCard.rotateX, tdCard.deltaRotation);
      tdCard.partRotateY = getPartRotation(tdCard.partRotateY, tdCard.rotateY, tdCard.deltaRotation);
      // set partial rotation
      rotateCard(tdCard);
      // keep rotating the card
      tdCard.animating = window.requestAnimationFrame(function(){
        updateRotationLevel(tdCard);
      });
    };
  
    function getPartRotation(start, end, delta) {
      if(start == end) return end;
      var newVal = start;
      if(start < end) {
        newVal = start + delta;
        if(newVal > end) newVal = end;
      } else if(start > end) {
        newVal = start - delta;
        if(newVal < end) newVal = end;
      }
      return newVal;
    }
  
    function rotateCard(tdCard) {
      tdCard.element.style.transform = 'perspective('+tdCard.perspective+') rotateX('+tdCard.partRotateX+'deg) rotateY('+tdCard.partRotateY+'deg)';
    };
  
    window.TdCard = TdCard;
  
    //initialize the TdCard objects
    var tdCards = document.getElementsByClassName('js-td-card');
    if( tdCards.length > 0 && Util.cssSupports('transform', 'translateZ(0px)')) {
      for( var i = 0; i < tdCards.length; i++) {
        (function(i){
          new TdCard(tdCards[i]);
        })(i);
      }
    };
  }());
  // File#: _1_3d-drawer
  // Usage: codyhouse.co/license
  (function() {
  	var TdDrawer = function(element) {
      this.element = element;
      this.mianContent = document.getElementsByClassName('js-td-drawer-main');
  		this.content = document.getElementsByClassName('js-td-drawer__body');
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.selectedTrigger = null;
      this.showClass = "td-drawer--is-visible";
      this.showMainClass = "td-drawer-main--drawer-is-visible";
  		initDrawer(this);
    };
    
    function initDrawer(drawer) {
      // open drawer when clicking on trigger buttons
  		if ( drawer.triggers ) {
  			for(var i = 0; i < drawer.triggers.length; i++) {
  				drawer.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					if(Util.hasClass(drawer.element, drawer.showClass)) {
  						closeDrawer(drawer);
  						return;
  					}
  					drawer.selectedTrigger = event.target;
  					showDrawer(drawer);
  					initDrawerEvents(drawer);
  				});
  			}
  		}
  		
  		// if drawer is already open -> we should initialize the drawer events
  		if(Util.hasClass(drawer.element, drawer.showClass)) initDrawerEvents(drawer);
    };
  
    function showDrawer(drawer) {
      if(drawer.content.length  > 0 ) drawer.content[0].scrollTop = 0;
      if(drawer.mianContent.length  > 0 ) Util.addClass(drawer.mianContent[0], drawer.showMainClass);
  		Util.addClass(drawer.element, drawer.showClass);
  	  getFocusableElements(drawer);
  		Util.moveFocus(drawer.element);
  		// wait for the end of transitions before moving focus
  		drawer.element.addEventListener("transitionend", function cb(event) {
  			Util.moveFocus(drawer.element);
  			drawer.element.removeEventListener("transitionend", cb);
  		});
  		emitDrawerEvents(drawer, 'drawerIsOpen');
    };
  
    function closeDrawer(drawer) {
      if(drawer.mianContent.length  > 0 ) Util.removeClass(drawer.mianContent[0], drawer.showMainClass);
      Util.removeClass(drawer.element, drawer.showClass);
  		drawer.firstFocusable = null;
  		drawer.lastFocusable = null;
  		if(drawer.selectedTrigger) drawer.selectedTrigger.focus();
  		//remove listeners
  		cancelDrawerEvents(drawer);
  		emitDrawerEvents(drawer, 'drawerIsClose');
    };
  
    function initDrawerEvents(drawer) {
      //add event listeners
      drawer.element.addEventListener('keydown', handleEvent.bind(drawer));
      drawer.element.addEventListener('click', handleEvent.bind(drawer));
    };
  
    function cancelDrawerEvents(drawer) {
  		//remove event listeners
  		drawer.element.removeEventListener('keydown', handleEvent.bind(drawer));
  		drawer.element.removeEventListener('click', handleEvent.bind(drawer));
    };
  
    function handleEvent(event) {
      switch(event.type) {
        case 'click': {
          initClick(this, event);
        }
        case 'keydown': {
          initKeyDown(this, event);
        }
      }
    };
  
    function initKeyDown(drawer, event) {
      if( event.keyCode && event.keyCode == 27 || event.key && event.key == 'Escape' ) {
        //close drawer window on esc
        closeDrawer(drawer);
      } else if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
        //trap focus inside drawer
        trapFocus(drawer, event);
      }
    };
  
    function initClick(drawer, event) {
      //close drawer when clicking on close button or drawer bg layer 
  		if( !event.target.closest('.js-td-drawer__close') && !Util.hasClass(event.target, 'js-td-drawer') ) return;
  		event.preventDefault();
  		closeDrawer(drawer);
    };
  
    function trapFocus(drawer, event) {
      if( drawer.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of drawer
  			event.preventDefault();
  			drawer.lastFocusable.focus();
  		}
  		if( drawer.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of drawer
  			event.preventDefault();
  			drawer.firstFocusable.focus();
  		}
    };
  
    function getFocusableElements(drawer) {
      //get all focusable elements inside the drawer
  		var allFocusable = drawer.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(drawer, allFocusable);
  		getLastVisible(drawer, allFocusable);
    };
  
    function getFirstVisible(drawer, elements) {
      //get first visible focusable element inside the drawer
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				drawer.firstFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function getLastVisible(drawer, elements) {
      //get last visible focusable element inside the drawer
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				drawer.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function emitDrawerEvents(drawer, eventName) {
      var event = new CustomEvent(eventName, {detail: drawer.selectedTrigger});
  		drawer.element.dispatchEvent(event);
    };
  
  	//initialize the Drawer objects
  	var drawer = document.getElementsByClassName('js-td-drawer');
  	if( drawer.length > 0 ) {
  		for( var i = 0; i < drawer.length; i++) {
  			(function(i){new TdDrawer(drawer[i]);})(i);
  		}
  	}
  }());
  // File#: _1_accordion
  // Usage: codyhouse.co/license
  (function() {
  	var Accordion = function(element) {
  		this.element = element;
  		this.items = Util.getChildrenByClassName(this.element, 'js-accordion__item');
  		this.version = this.element.getAttribute('data-version') ? '-'+this.element.getAttribute('data-version') : '';
  		this.showClass = 'accordion'+this.version+'__item--is-open';
  		this.animateHeight = (this.element.getAttribute('data-animation') == 'on');
  		this.multiItems = !(this.element.getAttribute('data-multi-items') == 'off'); 
  		// deep linking options
  		this.deepLinkOn = this.element.getAttribute('data-deep-link') == 'on';
  		// init accordion
  		this.initAccordion();
  	};
  
  	Accordion.prototype.initAccordion = function() {
  		//set initial aria attributes
  		for( var i = 0; i < this.items.length; i++) {
  			var button = this.items[i].getElementsByTagName('button')[0],
  				content = this.items[i].getElementsByClassName('js-accordion__panel')[0],
  				isOpen = Util.hasClass(this.items[i], this.showClass) ? 'true' : 'false';
  			Util.setAttributes(button, {'aria-expanded': isOpen, 'aria-controls': 'accordion-content-'+i, 'id': 'accordion-header-'+i});
  			Util.addClass(button, 'js-accordion__trigger');
  			Util.setAttributes(content, {'aria-labelledby': 'accordion-header-'+i, 'id': 'accordion-content-'+i});
  		}
  
  		//listen for Accordion events
  		this.initAccordionEvents();
  
  		// check deep linking option
  		this.initDeepLink();
  	};
  
  	Accordion.prototype.initAccordionEvents = function() {
  		var self = this;
  
  		this.element.addEventListener('click', function(event) {
  			var trigger = event.target.closest('.js-accordion__trigger');
  			//check index to make sure the click didn't happen inside a children accordion
  			if( trigger && Util.getIndexInArray(self.items, trigger.parentElement) >= 0) self.triggerAccordion(trigger);
  		});
  	};
  
  	Accordion.prototype.triggerAccordion = function(trigger) {
  		var bool = (trigger.getAttribute('aria-expanded') === 'true');
  
  		this.animateAccordion(trigger, bool, false);
  
  		if(!bool && this.deepLinkOn) {
  			history.replaceState(null, '', '#'+trigger.getAttribute('aria-controls'));
  		}
  	};
  
  	Accordion.prototype.animateAccordion = function(trigger, bool, deepLink) {
  		var self = this;
  		var item = trigger.closest('.js-accordion__item'),
  			content = item.getElementsByClassName('js-accordion__panel')[0],
  			ariaValue = bool ? 'false' : 'true';
  
  		if(!bool) Util.addClass(item, this.showClass);
  		trigger.setAttribute('aria-expanded', ariaValue);
  		self.resetContentVisibility(item, content, bool);
  
  		if( !this.multiItems && !bool || deepLink) this.closeSiblings(item);
  	};
  
  	Accordion.prototype.resetContentVisibility = function(item, content, bool) {
  		Util.toggleClass(item, this.showClass, !bool);
  		content.removeAttribute("style");
  		if(bool && !this.multiItems) { // accordion item has been closed -> check if there's one open to move inside viewport 
  			this.moveContent();
  		}
  	};
  
  	Accordion.prototype.closeSiblings = function(item) {
  		//if only one accordion can be open -> search if there's another one open
  		var index = Util.getIndexInArray(this.items, item);
  		for( var i = 0; i < this.items.length; i++) {
  			if(Util.hasClass(this.items[i], this.showClass) && i != index) {
  				this.animateAccordion(this.items[i].getElementsByClassName('js-accordion__trigger')[0], true, false);
  				return false;
  			}
  		}
  	};
  
  	Accordion.prototype.moveContent = function() { // make sure title of the accordion just opened is inside the viewport
  		var openAccordion = this.element.getElementsByClassName(this.showClass);
  		if(openAccordion.length == 0) return;
  		var boundingRect = openAccordion[0].getBoundingClientRect();
  		if(boundingRect.top < 0 || boundingRect.top > window.innerHeight) {
  			var windowScrollTop = window.scrollY || document.documentElement.scrollTop;
  			window.scrollTo(0, boundingRect.top + windowScrollTop);
  		}
  	};
  
  	Accordion.prototype.initDeepLink = function() {
  		if(!this.deepLinkOn) return;
  		var hash = window.location.hash.substr(1);
  		if(!hash || hash == '') return;
  		var trigger = this.element.querySelector('.js-accordion__trigger[aria-controls="'+hash+'"]');
  		if(trigger && trigger.getAttribute('aria-expanded') !== 'true') {
  			this.animateAccordion(trigger, false, true);
  			setTimeout(function(){trigger.scrollIntoView(true);});
  		}
  	};
  
  	window.Accordion = Accordion;
  	
  	//initialize the Accordion objects
  	var accordions = document.getElementsByClassName('js-accordion');
  	if( accordions.length > 0 ) {
  		for( var i = 0; i < accordions.length; i++) {
  			(function(i){new Accordion(accordions[i]);})(i);
  		}
  	}
  }());
  // File#: _1_adaptive-navigation
  // Usage: codyhouse.co/license
  (function() {
    var AdaptNav = function(element) {
      this.element = element;
      this.list = this.element.getElementsByClassName('js-adapt-nav__list')[0];
      this.items = this.element.getElementsByClassName('js-adapt-nav__item');
      this.moreBtn = this.element.getElementsByClassName('js-adapt-nav__item--more')[0];
      this.dropdown = this.moreBtn.getElementsByTagName('ul')[0];
      this.dropdownItems = this.dropdown.getElementsByTagName('a');
      this.dropdownClass = 'adapt-nav__dropdown--is-visible';
      this.resizing = false;
      // check if items already outrun nav
      this.outrunIndex = this.items.length;
      // reset alignment
      this.resetAlignment = Util.hasClass(this.list, 'justify-end');
      initAdaptNav(this);
    };
  
    function initAdaptNav(nav) {
      nav.resizing = true;
      resetOutrun(nav, '', true); // initially hide all elements
      resetAdaptNav.bind(nav)(); // reset navigation based on available space
  
      // listen to resize
      window.addEventListener('resize', function(event){
        if(nav.resizing) return;
        nav.resizing = true;
        window.requestAnimationFrame(resetAdaptNav.bind(nav));
      });
  
      // wait for font to be loaded
      if(document.fonts) {
        document.fonts.ready.then(function() {
          if(nav.resizing) return;
          nav.resizing = true;
          window.requestAnimationFrame(resetAdaptNav.bind(nav));
        });
      }
  
      /* dropdown behaviour */
      // init aria-labels
  		Util.setAttributes(nav.moreBtn, {'aria-expanded': 'false', 'aria-haspopup': 'true', 'aria-controls': nav.dropdown.getAttribute('id')});
      
      // toggle dropdown on click
      nav.moreBtn.addEventListener('click', function(event){
        if( nav.dropdown.contains(event.target) ) return;
  			event.preventDefault();
  			toggleMoreDropdown(nav, !Util.hasClass(nav.dropdown, nav.dropdownClass), true);
      });
  
      // keyboard events 
  		nav.dropdown.addEventListener('keydown', function(event) {
  			// use up/down arrow to navigate list of menu items
  			if( (event.keyCode && event.keyCode == 40) || (event.key && event.key.toLowerCase() == 'arrowdown') ) {
  				navigateItems(nav, event, 'next');
  			} else if( (event.keyCode && event.keyCode == 38) || (event.key && event.key.toLowerCase() == 'arrowup') ) {
  				navigateItems(nav, event, 'prev');
  			}
      });
  
  		window.addEventListener('keyup', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key.toLowerCase() == 'tab' ) { //close dropdown if focus is outside dropdown element
  				if (!nav.moreBtn.contains(document.activeElement)) toggleMoreDropdown(nav, false, false);
  			} else if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {// close menu on 'Esc'
          toggleMoreDropdown(nav, false, false);
  			} 
  		});
      
      // close menu when clicking outside it
  		window.addEventListener('click', function(event){
  			if( !nav.moreBtn.contains(event.target)) toggleMoreDropdown(nav, false);
  		});
    };
  
    function resetAdaptNav() { // reset nav appearance
      var totalWidth = getListWidth(this.list),
        moreWidth = getFullWidth(this.moreBtn),
        maxPosition = totalWidth - moreWidth,
        cloneList = '',
        hideAll = false;
  
      // take care of possible right alignment
      if(this.resetAlignment) Util.removeClass(this.list, 'justify-end');
  
      cloneList = resetOutrun(this, cloneList, false);
      // loop through items -> create clone (if required) and append to dropdown
      for(var i = 0; i < this.outrunIndex; i++) {
        if( Util.hasClass(this.items[i], 'is-hidden')) {
          Util.addClass(this.items[i], 'adapt-nav__item--hidden');
          Util.removeClass(this.items[i], 'is-hidden');
        }
        var right = this.items[i].offsetWidth + this.items[i].offsetLeft + parseFloat(window.getComputedStyle(this.items[i]).getPropertyValue("margin-right"));
        if(right >= maxPosition || hideAll) {
          var clone = this.items[i].cloneNode(true);
          cloneList = cloneList + modifyClone(clone);
          Util.addClass(this.items[i], 'is-hidden');
          hideAll = true;
        } else {
          Util.removeClass(this.items[i], 'is-hidden');
        }
        Util.removeClass(this.items[i], 'adapt-nav__item--hidden');
      }
  
      if(this.resetAlignment) Util.addClass(this.list, 'justify-end');
  
      Util.toggleClass(this.moreBtn, 'adapt-nav__item--hidden', (cloneList == ''));
      this.dropdown.innerHTML = cloneList;
      Util.addClass(this.element, 'adapt-nav--is-visible');
      this.outrunIndex = this.items.length;
      this.resizing = false;
    };
  
    function resetOutrun(nav, cloneList, bool) {
      if(nav.items[0].offsetLeft < 0 || (bool && nav.outrunIndex > 1)) {
        nav.outrunIndex = nav.outrunIndex - 1;
        var clone = nav.items[nav.outrunIndex].cloneNode(true);
        Util.addClass(nav.items[nav.outrunIndex], 'is-hidden');
        cloneList = modifyClone(clone) + cloneList;
        return resetOutrun(nav, cloneList, bool);
      } else {
        if(bool) nav.outrunIndex = nav.items.length;
        return cloneList;
      }
    };
  
    function getListWidth(list) { // get total width of container minus right padding
      var style = window.getComputedStyle(list);
      return parseFloat(list.getBoundingClientRect().width) - parseFloat(style.getPropertyValue("padding-right"));
    };
  
    function getFullWidth(item) { // get width of 'More Links' button
      return parseFloat(window.getComputedStyle(item).getPropertyValue("width"));
    };
  
    function toggleMoreDropdown(nav, bool, moveFocus) { // toggle menu visibility
      Util.toggleClass(nav.dropdown, nav.dropdownClass, bool);
  		if(bool) {
  			nav.moreBtn.setAttribute('aria-expanded', 'true');
  			Util.moveFocus(nav.dropdownItems[0]);
        nav.dropdown.addEventListener("transitionend", function(event) {Util.moveFocus(nav.dropdownItems[0]);}, {once: true});
        placeDropdown(nav);
  		} else {
  			nav.moreBtn.setAttribute('aria-expanded', 'false');
        if(moveFocus) Util.moveFocus(nav.moreBtn.getElementsByTagName('button')[0]);
        nav.dropdown.style.right = '';
  		}
    };
  
    function placeDropdown(nav) { // make sure dropdown is visible the viewport
      var dropdownLeft = nav.dropdown.getBoundingClientRect().left;
      if(dropdownLeft < 0) nav.dropdown.style.right = (dropdownLeft - 4)+'px';
    };
  
    function navigateItems(nav, event, direction) { // navigate through dropdown items
      event.preventDefault();
  		var index = Util.getIndexInArray(nav.dropdownItems, event.target),
  			nextIndex = direction == 'next' ? index + 1 : index - 1;
  		if(nextIndex < 0) nextIndex = nav.dropdownItems.length - 1;
  		if(nextIndex > nav.dropdownItems.length - 1) nextIndex = 0;
  		Util.moveFocus(nav.dropdownItems[nextIndex]);
    };
    
    function modifyClone(clone) { // assign new classes to cloned elements inside the dropdown
      Util.addClass(clone, 'adapt-nav__dropdown-item');
      Util.removeClass(clone, 'js-adapt-nav__item is-hidden adapt-nav__item--hidden adapt-nav__item');
      var link = clone.getElementsByClassName('adapt-nav__link');
      if(link.length > 0) {
        Util.addClass(link[0], 'adapt-nav__dropdown-link js-tab-focus');
        link[0].style.outline = 'none';
        Util.removeClass(link[0], 'adapt-nav__link');
      }
      return clone.outerHTML;
    };
  
    //initialize the AdaptNav objects
    var adaptNavs = document.getElementsByClassName('js-adapt-nav'),
      flexSupported = Util.cssSupports('align-items', 'stretch');
  	if( adaptNavs.length > 0) {
  		for( var i = 0; i < adaptNavs.length; i++) {(function(i){
        if(flexSupported) new AdaptNav(adaptNavs[i]);
        else Util.addClass(adaptNavs[i], 'adapt-nav--is-visible');
      })(i);}
  	}
  }());
  // File#: _1_adv-multiple-custom-select
  // Usage: codyhouse.co/license
  (function() {
    var AdvMultiSelect = function(element) {
      this.element = element;
      this.select = this.element.getElementsByTagName('select')[0];
      this.optGroups = this.select.getElementsByTagName('optgroup');
      this.options = this.select.getElementsByTagName('option');
      this.optionData = getOptionsData(this); // create custom templates
      this.selectId = this.select.getAttribute('id');
      this.selectLabel = document.querySelector('[for='+this.selectId+']')
      this.list = this.element.getElementsByClassName('js-advm-select__list')[0];
      // used for keyboard/mouse multiple selection
      this.startSelection = false; 
      this.latestSelection = false;
      // detect touch device
      this.touchDevice = false;
      // reset buttons
      this.resetBtns = (this.selectId) ? document.querySelectorAll('[aria-controls="'+this.selectId +'"]') : [];
  
      initAdvMultiSelect(this); // init markup
      initAdvMultiSelectEvents(this); // init event listeners
    };
  
    function getOptionsData(select) {
      var obj = [],
        dataset = select.options[0].dataset;
  
      function camelCaseToDash( myStr ) {
        return myStr.replace( /([a-z])([A-Z])/g, '$1-$2' ).toLowerCase();
      }
      for (var prop in dataset) {
        if (Object.prototype.hasOwnProperty.call(dataset, prop)) {
          obj.push(camelCaseToDash(prop));
        }
      }
      return obj;
    };
  
    function initAdvMultiSelect(select) {
      // create custom structure
      createAdvStructure(select);
      // store all custom options and labels
      select.customOptions = select.list.getElementsByClassName('js-advm-select__option');
      select.customLabels = select.list.getElementsByClassName('js-advm-select__label');
      // make custom list focusable
      select.list.setAttribute('tabindex', 0);
      // hide native select and show custom structure
      Util.addClass(select.select, 'is-hidden');
      Util.removeClass(select.list, 'is-hidden');
    };
  
    function initAdvMultiSelectEvents(select) {
      if(select.selectLabel) {
        // move focus to custom select list when clicking on <select> label
        select.selectLabel.addEventListener('click', function(){
          select.list.focus();
        });
      }
  
      // new option is selected in custom list
      select.list.addEventListener('click', function(event){
        var target = event.target,
          option = target.closest('.js-advm-select__option');
        if(!option) return;
        mouseSelection(select, option, event);
        select.touchDevice = false;
      });
  
      select.list.addEventListener('touchend', function(event){ // touch devices
        select.touchDevice = true;
      });
  
      // keyboard navigation
      select.list.addEventListener('keydown', function(event){
        // use up/down arrows or space key to select new options
        if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
          event.preventDefault();
          keyboardSelection(select, 'prev', event);
        } else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
          event.preventDefault();
          keyboardSelection(select, 'next', event);
        } else if(event.keyCode && event.keyCode == 32 || event.key && event.key.toLowerCase() == ' ') {
          event.preventDefault();
          var option = document.activeElement.closest('.js-advm-select__option');
          if(!option) return;
          selectOption([option], !(option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') == 'true'));
          select.startSelection = option;
          select.latestSelection = select.startSelection;
        }
      });
  
      // reset selection
      if(select.resetBtns.length > 0) {
        for(var i = 0; i < select.resetBtns.length; i++) {
          select.resetBtns[i].addEventListener('click', function(event){
            event.preventDefault();
            resetSelect(select);
          });
        }
      }
    };
  
    function createAdvStructure(select) {
      // store optgroup and option structure
      var optgroup = select.list.querySelector('[role="group"]'),
        option = select.list.querySelector('.js-advm-select__option'),
        optgroupClone = false,
        optgroupLabel = false,
        optionClone = false;
      if(optgroup) {
        optgroupClone = optgroup.cloneNode();
        optgroupLabel = select.list.querySelector('.js-advm-select__label');
      }
      if(option) optionClone = option.cloneNode(true);
  
      var listCode = '';
  
      if(select.optGroups.length > 0) {
        for(var i = 0; i < select.optGroups.length; i++) {
          listCode = listCode + getOptGroupCode(select, select.optGroups[i], optgroupClone, optionClone, optgroupLabel, i);
        }
      } else {
        for(var i = 0; i < select.options.length; i++) {
          listCode = listCode + getOptionCode(select, select.options[i], optionClone);
        }
      }
  
      select.list.innerHTML = listCode;
    };
  
    function getOptGroupCode(select, optGroup, optGroupClone, optionClone, optgroupLabel, index) {
      if(!optGroupClone || !optionClone) return '';
      var code = '';
      var options = optGroup.getElementsByTagName('option');
      for(var i = 0; i < options.length; i++) {
        code = code + getOptionCode(select, options[i], optionClone);
      }
      if(optgroupLabel) {
        var label = optgroupLabel.cloneNode(true);
        var id = label.getAttribute('id') + '-'+index;
        label.setAttribute('id', id);
        optGroupClone.setAttribute('describedby', id);
        code = label.outerHTML.replace('{optgroup-label}', optGroup.getAttribute('label')) + code;
      } 
      optGroupClone.innerHTML = code;
      return optGroupClone.outerHTML;
    };
  
    function getOptionCode(select, option, optionClone) {
      optionClone.setAttribute('data-value', option.value);
      option.selected ? optionClone.setAttribute('aria-selected', 'true') : optionClone.removeAttribute('aria-selected');
      var optionHtml = optionClone.outerHTML;
      optionHtml = optionHtml.replace('{option-label}', option.text);
      for(var i = 0; i < select.optionData.length; i++) {
        optionHtml = optionHtml.replace('{'+select.optionData[i]+'}', option.getAttribute('data-'+select.optionData[i]));
      }
      return optionHtml;
    };
  
    function mouseSelection(select, option, event) {
      var isSelected = (option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') == 'true'); // option already selected
      if((event.ctrlKey || event.metaKey) && !select.touchDevice) {
        // add/remove clicked element from the selection 
        selectOption([option], !isSelected);
        if(!isSelected) {
          select.startSelection = option;
          select.latestSelection = select.startSelection;
        }
      } else if(event.shiftKey && !isSelected) {
        // select all options between latest selected and clicked option 
        selectInBetween(select, option);
      } else {
        if(!select.touchDevice) {
          // deselect all others and select this one only
          singleSelect(select, option);
        } else {
          // add this item to the selection or deselect it
         selectOption([option], !isSelected);
        }
      }
      select.startSelection = option;
      select.latestSelection = select.startSelection;
      // reset tabindex
      resetTabindex(select);
      // new option has been selected -> update native <select> element
      updateNativeSelect(select);
    };
  
    function keyboardSelection(select, direction, event) {
      var lastSelectedIndex = -1;
      if(select.latestSelection) {
        lastSelectedIndex = Util.getIndexInArray(select.customOptions, select.latestSelection);
      }
      if(event.ctrlKey || event.metaKey) {
        // in this case we are only moving the focus, so take latest focused option
        var focusedOption = document.activeElement.closest('.js-advm-select__option');
        if(focusedOption) lastSelectedIndex = Util.getIndexInArray(select.customOptions, focusedOption);
      }
      var index = (direction == 'next') ? lastSelectedIndex + 1: lastSelectedIndex - 1;
      if(index < 0 || index >= select.customOptions.length) return;
      var option = select.customOptions[index];
  
      if(event.ctrlKey || event.metaKey) {
        // ctrl/command + up/down -> move focus
        Util.moveFocus(option);
      } else if(event.shiftKey) {
        // shift + up/down -> select new item
        //remove previously selected options
        selectOption(select.list.querySelectorAll('[aria-selected="true"]'), false);
        // select new options
        selectInBetween(select, option);
        select.latestSelection = option;
      } else {
        // only up/down -> deselect all others and select this one only
        singleSelect(select, option);
        select.startSelection = option;
        select.latestSelection = select.startSelection;
      }
      // reset tabindex
      if(!event.ctrlKey && !event.metaKey) resetTabindex(select);
      // new option has been selected -> update native <select> element
      updateNativeSelect(select);
    };
  
    function selectInBetween(select, option) {
      // keyboard/mouse navigation + shift -> select optiong between to elements
      var optionsBetween = getOptionsBetween(select, option);
      selectOption(optionsBetween, true);
    };
  
    function singleSelect(select, option) {
      // select a single option, deselecting all the others
      var selectedOptions = select.list.querySelectorAll('[aria-selected="true"]');
      selectOption(selectedOptions, false);
      selectOption([option], true);
    };
  
    function selectOption(options, bool) {
      for(var i = 0; i < options.length; i++) {
        (bool) ? options[i].setAttribute('aria-selected', 'true') : options[i].removeAttribute('aria-selected');
      }
      if(bool) options[options.length - 1].scrollIntoView({block: 'nearest'});
    };
  
    function getOptionsBetween(select, option) {
      var options = [];
      var optIndex = Util.getIndexInArray(select.customOptions, option),
        latestOptIndex = 0;
      if(select.startSelection) {
        latestOptIndex = Util.getIndexInArray(select.customOptions, select.startSelection);
      }
      var min = Math.min(optIndex, latestOptIndex),
        max = Math.max(optIndex, latestOptIndex);
      for(var i = min; i <= max; i++) {
        options.push(select.customOptions[i]);
      }
      return options;
    };
  
    function updateNativeSelect(select) {
      // update native select element
      for(var i = 0; i < select.customOptions.length; i++) {
        select.options[i].selected = (select.customOptions[i].hasAttribute('aria-selected') && select.customOptions[i].getAttribute('aria-selected') == 'true')
      }
      select.select.dispatchEvent(new CustomEvent('change', {bubbles: true})); // trigger change event
    };
  
    function resetTabindex(select) {
      var focusableEl = select.list.querySelectorAll('[tabindex]');
      for(var i = 0; i < focusableEl.length; i++) {
        focusableEl[i].removeAttribute('tabindex');
      }
      // move focus on list
      select.list.focus();
    };
  
    function resetSelect(select) {
      selectOption(select.list.querySelectorAll('[aria-selected="true"]'), false);
      updateNativeSelect(select);
    };
  
    //initialize the AdvMultiSelect objects
    var advMultiSelect = document.getElementsByClassName('js-advm-select');
    if( advMultiSelect.length > 0 ) {
      for( var i = 0; i < advMultiSelect.length; i++) {
        (function(i){new AdvMultiSelect(advMultiSelect[i]);})(i);
      }
    }
  }());
  // File#: _1_alert-card
  // Usage: codyhouse.co/license
  (function() {
    function initAlertCard(card) {
      card.addEventListener('click', function(event) {
        if(event.target.closest('.js-alert-card__close-btn')) Util.addClass(card, 'is-hidden');
      });
    };
  
    var alertCards = document.getElementsByClassName('js-alert-card');
    if(alertCards.length > 0) {
      for(var i = 0; i < alertCards.length; i++) {
        (function(i){initAlertCard(alertCards[i])})(i);
      }
    }
  }());
  // File#: _1_alert
  // Usage: codyhouse.co/license
  (function() {
  	var alertClose = document.getElementsByClassName('js-alert__close-btn');
  	if( alertClose.length > 0 ) {
  		for( var i = 0; i < alertClose.length; i++) {
  			(function(i){initAlertEvent(alertClose[i]);})(i);
  		}
  	};
  }());
  
  function initAlertEvent(element) {
  	element.addEventListener('click', function(event){
  		event.preventDefault();
  		Util.removeClass(element.closest('.js-alert'), 'alert--is-visible');
  	});
  };
  // File#: _1_anim-menu-btn
  // Usage: codyhouse.co/license
  (function() {
  	var menuBtns = document.getElementsByClassName('js-anim-menu-btn');
  	if( menuBtns.length > 0 ) {
  		for(var i = 0; i < menuBtns.length; i++) {(function(i){
  			initMenuBtn(menuBtns[i]);
  		})(i);}
  
  		function initMenuBtn(btn) {
  			btn.addEventListener('click', function(event){	
  				event.preventDefault();
  				var status = !Util.hasClass(btn, 'anim-menu-btn--state-b');
  				Util.toggleClass(btn, 'anim-menu-btn--state-b', status);
  				// emit custom event
  				var event = new CustomEvent('anim-menu-btn-clicked', {detail: status});
  				btn.dispatchEvent(event);
  			});
  		};
  	}
  }());
  // File#: _1_animated-headline
  // Usage: codyhouse.co/license
  (function() {
    var TextAnim = function(element) {
      this.element = element;
      this.wordsWrapper = this.element.getElementsByClassName(' js-text-anim__wrapper');
      this.words = this.element.getElementsByClassName('js-text-anim__word');
      this.selectedWord = 0;
      // interval between two animations
      this.loopInterval = parseFloat(getComputedStyle(this.element).getPropertyValue('--text-anim-pause'))*1000 || 1000;
      // duration of single animation (e.g., time for a single word to rotate)
      this.transitionDuration = parseFloat(getComputedStyle(this.element).getPropertyValue('--text-anim-duration'))*1000 || 1000;
      // keep animating after first loop was completed
      this.loop = (this.element.getAttribute('data-loop') && this.element.getAttribute('data-loop') == 'off') ? false : true;
      this.wordInClass = 'text-anim__word--in';
      this.wordOutClass = 'text-anim__word--out';
      // check for specific animations
      this.isClipAnim = Util.hasClass(this.element, 'text-anim--clip');
      if(this.isClipAnim) {
        this.animBorderWidth = parseInt(getComputedStyle(this.element).getPropertyValue('--text-anim-border-width')) || 2;
        this.animPulseClass = 'text-anim__wrapper--pulse';
      }
      initTextAnim(this);
    };
  
    function initTextAnim(element) {
      // make sure there's a word with the wordInClass
      setSelectedWord(element);
      // if clip animation -> add pulse class
      if(element.isClipAnim) {
        Util.addClass(element.wordsWrapper[0], element.animPulseClass);
      }
      // init loop
      loopWords(element);
    };
  
    function setSelectedWord(element) {
      var selectedWord = element.element.getElementsByClassName(element.wordInClass);
      if(selectedWord.length == 0) {
        Util.addClass(element.words[0], element.wordInClass);
      } else {
        element.selectedWord = Util.getIndexInArray(element.words, selectedWord[0]);
      }
    };
  
    function loopWords(element) {
      // stop animation after first loop was completed
      if(!element.loop && element.selectedWord == element.words.length - 1) {
        return;
      }
      var newWordIndex = getNewWordIndex(element);
      setTimeout(function() {
        if(element.isClipAnim) { // clip animation only
          switchClipWords(element, newWordIndex);
        } else {
          switchWords(element, newWordIndex);
        }
      }, element.loopInterval);
    };
  
    function switchWords(element, newWordIndex) {
      // switch words
      Util.removeClass(element.words[element.selectedWord], element.wordInClass);
      Util.addClass(element.words[element.selectedWord], element.wordOutClass);
      Util.addClass(element.words[newWordIndex], element.wordInClass);
      // reset loop
      resetLoop(element, newWordIndex);
    };
  
    function resetLoop(element, newIndex) {
      setTimeout(function() { 
        // set new selected word
        Util.removeClass(element.words[element.selectedWord], element.wordOutClass);
        element.selectedWord = newIndex;
        loopWords(element); // restart loop
      }, element.transitionDuration);
    };
  
    function switchClipWords(element, newWordIndex) {
      // clip animation only
      var startWidth =  element.words[element.selectedWord].offsetWidth,
        endWidth = element.words[newWordIndex].offsetWidth;
      
      // remove pulsing animation
      Util.removeClass(element.wordsWrapper[0], element.animPulseClass);
      // close word
      animateWidth(startWidth, element.animBorderWidth, element.wordsWrapper[0], element.transitionDuration, function() {
        // switch words
        Util.removeClass(element.words[element.selectedWord], element.wordInClass);
        Util.addClass(element.words[newWordIndex], element.wordInClass);
        element.selectedWord = newWordIndex;
  
        // open word
        animateWidth(element.animBorderWidth, endWidth, element.wordsWrapper[0], element.transitionDuration, function() {
          // add pulsing class
          Util.addClass(element.wordsWrapper[0], element.animPulseClass);
          loopWords(element);
        });
      });
    };
  
    function getNewWordIndex(element) {
      // get index of new word to be shown
      var index = element.selectedWord + 1;
      if(index >= element.words.length) index = 0;
      return index;
    };
  
    function animateWidth(start, to, element, duration, cb) {
      // animate width of a word for the clip animation
      var currentTime = null;
  
      var animateProperty = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        
        var val = Math.easeInOutQuart(progress, start, to - start, duration);
        element.style.width = val+"px";
        if(progress < duration) {
            window.requestAnimationFrame(animateProperty);
        } else {
          cb();
        }
      };
    
      //set the width of the element before starting animation -> fix bug on Safari
      element.style.width = start+"px";
      window.requestAnimationFrame(animateProperty);
    };
  
    window.TextAnim = TextAnim;
  
    // init TextAnim objects
    var textAnim = document.getElementsByClassName('js-text-anim'),
      reducedMotion = Util.osHasReducedMotion();
    if( textAnim ) {
      if(reducedMotion) return;
      for( var i = 0; i < textAnim.length; i++) {
        (function(i){ new TextAnim(textAnim[i]);})(i);
      }
    }
  }());
  // File#: _1_article-preview-v3
  // Usage: codyhouse.co/license
  (function() {
    var Story3 = function(element) {
      this.element = element;
      // data attributes
      this.src = this.element.getAttribute('data-story-img-src');
      this.align = this.element.getAttribute('data-story-img-align') ? this.element.getAttribute('data-story-img-align') : 'right';
      this.offset = this.element.getAttribute('data-story-img-offset-x') ? this.element.getAttribute('data-story-img-offset-x') : '0px';
      this.width = this.element.getAttribute('data-story-img-width') ? this.element.getAttribute('data-story-img-width') : '30%';
      this.customClasses = this.element.getAttribute('data-story-img-class') ? this.element.getAttribute('data-story-img-class') : 'display@lg';
      // preview classes
      this.previewClass = 'story-v3__preview-img js-story-v3__preview-img'+' '+this.customClasses;
      this.previewVisibleClass = 'story-v3__preview-img--is-visible';
      this.preview = false; // will use this to store the preview img element
      // params needed for event listening
      this.eventBind = false;
      this.mousePosition = false;
      // used during mousemove
      this.previewMoving = false;
      initStory3(this);
    };
  
    function initStory3(story) {
      // create img preview element
      createPreview(story);
      // bind events
      story.eventBind = handleEvent.bind(story);
      story.element.addEventListener('mouseenter', story.eventBind);
    };
  
    function createPreview(story) {
      story.preview = document.createElement('img');
      story.element.appendChild(story.preview);
      Util.addClass(story.preview, story.previewClass);
      Util.setAttributes(story.preview, {'aria-hidden': true, 'src': story.src});
    };
  
    function handleEvent(event) {
      switch(event.type) {
        case 'mouseenter': {
          showPreview(this, event);
          break;
        }
        case 'mouseleave': {
          hidePreview(this, event);
          break;
        }
        case 'mousemove': {
          movePreview(this, event);
          break;
        }
      }
    };
  
    function showPreview(story, event) {
      // show preview
      story.preview.setAttribute('style', getPreviewStyle(story));
      Util.addClass(story.preview, story.previewVisibleClass);
      // bind events
      story.element.addEventListener('mouseleave', story.eventBind);
      story.element.addEventListener('mousemove', story.eventBind);
      // store mouse position
      story.mousePosition = [event.clientX, event.clientY];
    };
  
    function hidePreview(story, event) {
      // hide image
      Util.removeClass(story.preview, story.previewVisibleClass);
      story.preview.style.transform = '';
      // remove events
      story.element.removeEventListener('mouseleave', story.eventBind);
  		story.element.removeEventListener('mousemove', story.eventBind);
    };
  
    function movePreview(story, event) { // parallax effect
      if(story.previewMoving) return;
      story.previewMoving = true;
      window.requestAnimationFrame(function(){
        updatePreviewPosition(story, event);
        story.previewMoving = false;
      });
    };
  
    function updatePreviewPosition(story, event) {
      // move preview image
      var translateX = event.clientX - story.mousePosition[0],
        translateY = event.clientY - story.mousePosition[1];
      translateX = resetTranslateValue(translateX);
      translateY = resetTranslateValue(translateY); 
      story.preview.style.transform = 'translateY(calc(-50% + '+translateY+'px)) translateX('+translateX+'px)';
    };
  
    function getPreviewStyle(story) {
      var storyRect = story.element.getBoundingClientRect(),
        horizontalStyle = '';
      if(story.align == 'right') {
        horizontalStyle = 'right:'+getValue(storyRect.width, story.offset)+'px;';
      } else {
        horizontalStyle = 'left:'+getValue(storyRect.width, story.offset)+'px;';
      }
      var style = 'width: '+getValue(storyRect.width, story.width)+'px;'+horizontalStyle;
  
      return style;
    };
  
    function getValue(width, val) {
      if(val.indexOf('%') > -1) {
        return width*parseInt(val)/100;
      } else {
        return parseInt(val);
      }
    };
  
    function resetTranslateValue(val) {
      return parseInt(val/30);
    };
  
    window.Story3 = Story3;
  
    // init the Story3 objects
    var story3 = document.getElementsByClassName('js-story-v3');
    if(story3.length > 0) {
      for( var i = 0; i < story3.length; i++) {
        (function(i){ new Story3(story3[i]);})(i);
      }
    }
  }());
  // File#: _1_back-to-top
  // Usage: codyhouse.co/license
  (function() {
    var backTop = document.getElementsByClassName('js-back-to-top')[0];
    if( backTop ) {
      var dataElement = backTop.getAttribute('data-element');
      var scrollElement = dataElement ? document.querySelector(dataElement) : window;
      var scrollDuration = parseInt(backTop.getAttribute('data-duration')) || 300, //scroll to top duration
        scrollOffsetInit = parseInt(backTop.getAttribute('data-offset-in')) || parseInt(backTop.getAttribute('data-offset')) || 0, //show back-to-top if scrolling > scrollOffset
        scrollOffsetOutInit = parseInt(backTop.getAttribute('data-offset-out')) || 0, 
        scrollOffset = 0,
        scrollOffsetOut = 0,
        scrolling = false;
  
      // check if target-in/target-out have been set
      var targetIn = backTop.getAttribute('data-target-in') ? document.querySelector(backTop.getAttribute('data-target-in')) : false,
        targetOut = backTop.getAttribute('data-target-out') ? document.querySelector(backTop.getAttribute('data-target-out')) : false;
  
      updateOffsets();
      
      //detect click on back-to-top link
      backTop.addEventListener('click', function(event) {
        event.preventDefault();
        if(!window.requestAnimationFrame) {
          scrollElement.scrollTo(0, 0);
        } else {
          dataElement ? Util.scrollTo(0, scrollDuration, false, scrollElement) : Util.scrollTo(0, scrollDuration);
        } 
        //move the focus to the #top-element - don't break keyboard navigation
        Util.moveFocus(document.getElementById(backTop.getAttribute('href').replace('#', '')));
      });
      
      //listen to the window scroll and update back-to-top visibility
      checkBackToTop();
      if (scrollOffset > 0 || scrollOffsetOut > 0) {
        scrollElement.addEventListener("scroll", function(event) {
          if( !scrolling ) {
            scrolling = true;
            (!window.requestAnimationFrame) ? setTimeout(function(){checkBackToTop();}, 250) : window.requestAnimationFrame(checkBackToTop);
          }
        });
      }
  
      function checkBackToTop() {
        updateOffsets();
        var windowTop = scrollElement.scrollTop || document.documentElement.scrollTop;
        if(!dataElement) windowTop = window.scrollY || document.documentElement.scrollTop;
        var condition =  windowTop >= scrollOffset;
        if(scrollOffsetOut > 0) {
          condition = (windowTop >= scrollOffset) && (window.innerHeight + windowTop < scrollOffsetOut);
        }
        Util.toggleClass(backTop, 'back-to-top--is-visible', condition);
        scrolling = false;
      }
  
      function updateOffsets() {
        scrollOffset = getOffset(targetIn, scrollOffsetInit, true);
        scrollOffsetOut = getOffset(targetOut, scrollOffsetOutInit);
      }
  
      function getOffset(target, startOffset, bool) {
        var offset = 0;
        if(target) {
          var windowTop = scrollElement.scrollTop || document.documentElement.scrollTop;
          if(!dataElement) windowTop = window.scrollY || document.documentElement.scrollTop;
          var boundingClientRect = target.getBoundingClientRect();
          offset = bool ? boundingClientRect.bottom : boundingClientRect.top;
          offset = offset + windowTop;
        }
        if(startOffset && startOffset) {
          offset = offset + parseInt(startOffset);
        }
        return offset;
      }
    }
  }());
  // File#: _1_btn-slide-fx
  // Usage: codyhouse.co/license
  (function() {
    var BtnSlideFx = function(element) {
  		this.element = element;
      this.hover = false; 
  		btnSlideFxEvents(this);
  	};
  
    function btnSlideFxEvents(btn) {
      btn.element.addEventListener('mouseenter', function(event){ // detect mouse hover
        btn.hover = true;
        triggerBtnSlideFxAnimation(btn.element, 'from');
      });
      btn.element.addEventListener('mouseleave', function(event){ // detect mouse leave
        btn.hover = false;
        triggerBtnSlideFxAnimation(btn.element, 'to');
      });
      btn.element.addEventListener('transitionend', function(event){ // reset btn classes at the end of enter/leave animation
        resetBtnSlideFxAnimation(btn.element);
      });
    };
  
    function getEnterDirection(element, event) { // return mouse movement direction
      var deltaLeft = Math.abs(element.getBoundingClientRect().left - event.clientX),
        deltaRight = Math.abs(element.getBoundingClientRect().right - event.clientX),
        deltaTop = Math.abs(element.getBoundingClientRect().top - event.clientY),
        deltaBottom = Math.abs(element.getBoundingClientRect().bottom - event.clientY);
      var deltaXDir = (deltaLeft < deltaRight) ? 'left' : 'right',
        deltaX = (deltaLeft < deltaRight) ? deltaLeft : deltaRight,
        deltaYDir = (deltaTop < deltaBottom) ? 'top' : 'bottom',
        deltaY = (deltaTop < deltaBottom) ? deltaTop : deltaBottom;
      return (deltaX < deltaY) ? deltaXDir : deltaYDir;
    };
    
    function triggerBtnSlideFxAnimation(element, direction) { // trigger animation -> apply in/out and direction classes
      var inStep = (direction == 'from') ? '-out' : '',
        outStep = (direction == 'from') ? '' : '-out';
      Util.removeClass(element, 'btn-slide-fx-hover'+inStep);
      resetBtnSlideFxAnimation(element);
      Util.addClass(element, 'btn--slide-fx-'+direction+'-'+getEnterDirection(element, event)); // set direction 
      setTimeout(function(){Util.addClass(element, 'btn-slide-fx-animate');}, 5); // add transition
      setTimeout(function(){Util.addClass(element, 'btn-slide-fx-hover'+outStep);}, 10); // trigger transition
    };
  
    function resetBtnSlideFxAnimation(element) { // remove animation classes
      Util.removeClass(element, 'btn--slide-fx-from-left btn--slide-fx-from-right btn--slide-fx-from-bottom btn--slide-fx-from-top btn--slide-fx-to-left btn--slide-fx-to-right btn--slide-fx-to-bottom btn--slide-fx-to-top btn-slide-fx-animate');
    };
  
  	//initialize the BtnSlideFx objects
  	var btnSlideFx = document.getElementsByClassName('js-btn--slide-fx');
  	if( btnSlideFx.length > 0 ) {
  		for( var i = 0; i < btnSlideFx.length; i++) {
        (function(i){new BtnSlideFx(btnSlideFx[i]);})(i);
  		}
    }
  }());
  // File#: _1_chameleonic-header
  // Usage: codyhouse.co/license
  (function() {
    var ChaHeader = function(element) {
      this.element = element;
      this.sections = document.getElementsByClassName('js-cha-section');
      this.header = this.element.getElementsByClassName('js-cha-header')[0];
      // handle mobile behaviour
      this.headerTrigger = this.element.getElementsByClassName('js-cha-header__trigger');
      this.modal = document.getElementsByClassName('js-cha-modal');
      this.focusMenu = false;
      this.firstFocusable = null;
  		this.lastFocusable = null;
      initChaHeader(this);
    };
  
    function initChaHeader(element) {
      // set initial status
      for(var j = 0; j < element.sections.length; j++) {
        initSection(element, j);
      }
  
      // handle mobile behaviour
      if(element.headerTrigger.length > 0) {
        initMobileVersion(element);
      }
  
      // make sure header element is visible when in focus
      element.header.addEventListener('focusin', function(event){
        checkHeaderVisible(element);
      });
    };
  
    function initSection(element, index) {
      // clone header element inside each section
      var cloneItem = (index == 0) ? element.element : element.element.cloneNode(true);
      Util.removeClass(cloneItem, 'js-cha-header-clip');
      var customClasses = element.sections[index].getAttribute('data-header-class');
      // hide clones to SR
      cloneItem.setAttribute('aria-hidden', 'true');
      if( customClasses ) Util.addClass(cloneItem.getElementsByClassName('js-cha-header')[0], customClasses);
      // keyborad users - make sure cloned items are not tabbable
      if(index != 0) {
        // reset tab index
        resetTabIndex(cloneItem);
        element.sections[index].insertBefore(cloneItem, element.sections[index].firstChild);
      }
    }
  
    function resetTabIndex(clone) {
      var focusable = clone.querySelectorAll('[href], button, input');
      for(var i = 0; i < focusable.length; i++) {
        focusable[i].setAttribute('tabindex', '-1');
      }
    };
  
    function initMobileVersion(element) {
      //detect click on nav trigger
      var triggers = document.getElementsByClassName('js-cha-header__trigger');
      for(var i = 0; i < triggers.length; i++) {
        triggers[i].addEventListener("click", function(event) {
          event.preventDefault();
          var ariaExpanded = !Util.hasClass(element.modal[0], 'is-visible');
          //show nav and update button aria value
          Util.toggleClass(element.modal[0], 'is-visible', ariaExpanded);
          element.headerTrigger[0].setAttribute('aria-expanded', ariaExpanded);
          if(ariaExpanded) { //opening menu -> move focus to first element inside nav
            getFocusableElements(element);
            element.firstFocusable.focus();
          } else if(element.focusMenu) {
            if(window.scrollY < element.focusMenu.offsetTop) element.focusMenu.focus();
            element.focusMenu = false;
          }
        });
      }
  
      // close modal on click
      element.modal[0].addEventListener("click", function(event) {
        if(!event.target.closest('.js-cha-modal__close')) return;
        closeModal(element);
      });
      
      // listen for key events
  		window.addEventListener('keydown', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(element.headerTrigger[0].getAttribute('aria-expanded') == 'true' && isVisible(element.headerTrigger[0])) {
            closeModal(element);
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				trapFocus(element, event);
  			}
  		});
    };
  
    function closeModal(element) {
      element.focusMenu = element.headerTrigger[0]; // move focus to menu trigger when menu is close
  		element.headerTrigger[0].click();
    };
  
    function trapFocus(element, event) {
      if( element.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of modal
  			event.preventDefault();
  			element.lastFocusable.focus();
  		}
  		if( element.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of modal
  			event.preventDefault();
  			element.firstFocusable.focus();
  		}
    };
  
    function getFocusableElements(element) {
  		//get all focusable elements inside the modal
  		var allFocusable = element.modal[0].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(element, allFocusable);
  		getLastVisible(element, allFocusable);
  	};
  
  	function getFirstVisible(element, elements) {
  		//get first visible focusable element inside the modal
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				element.firstFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	function getLastVisible(element, elements) {
  		//get last visible focusable element inside the modal
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				element.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
    
    function checkHeaderVisible(element) {
      if(window.scrollY > element.sections[0].offsetHeight - element.header.offsetHeight) window.scrollTo(0, 0);
    };
  
    function isVisible(element) {
  		return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  	};
  
    // init the ChaHeader Object
    var chaHader = document.getElementsByClassName('js-cha-header-clip'),
      clipPathSupported = Util.cssSupports('clip-path', 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)') || Util.cssSupports('-webkit-clip-path', 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)');
    if(chaHader.length > 0 && clipPathSupported) {
      for(var i = 0; i < chaHader.length; i++) {
        new ChaHeader(chaHader[i]);
      }
    }
  }());
  // File#: _1_character-count
  // Usage: codyhouse.co/license
  (function() {
  	var CharacterCount = function(element) {
  		this.element = element;
  		this.input = this.element.getElementsByClassName('js-character-count__input')[0];
  		this.characterLimit = Number(this.input.getAttribute('maxlength')) || 200;
  		this.counter = this.element.getElementsByClassName('js-character-count__counter')[0];
  		this.initCount();
  	};
  
  	CharacterCount.prototype.initCount = function() {
  		var self = this;
  		this.counter.textContent = this.getCount();//set counter value 
  		this.input.addEventListener('input', function(event){ //listen for content changes
  		  self.counter.textContent = self.getCount();
  		});
  	};
  
  	CharacterCount.prototype.getCount = function() {
  		return this.characterLimit - this.input.value.length;
  	};
  	
  	//initialize the CharacterCount objects
  	var characterCounts = document.getElementsByClassName('js-character-count');
  	if( characterCounts.length > 0 ) {
  		for( var i = 0; i < characterCounts.length; i++) {
  			(function(i){new CharacterCount(characterCounts[i]);})(i);
  		}
  	};
  }());
  // File#: _1_choice-accordion
  // Usage: codyhouse.co/license
  (function() {
    var ChoiceAccordion = function(element) {
      this.element = element;
      this.btns = this.element.getElementsByClassName('js-choice-accordion__btn');
      this.inputs = getChoiceInput(this);
      this.contents = getChoiceContent(this);
      this.isRadio = this.inputs[0].type == 'radio';
      this.animateHeight = (this.element.getAttribute('data-animation') == 'on');
      initAccordion(this);
      resetCheckedStatus(this, false); // set initial classes
      initChoiceAccordionEvent(this); // add listeners
    };
  
    function getChoiceInput(element) { // store input elements in an object property
      var inputs = [],
        fallbacks = element.element.getElementsByClassName('js-choice-accordion__fallback');
      for(var i = 0; i < fallbacks.length; i++) {
        inputs.push(fallbacks[i].getElementsByTagName('input')[0]);
      }
      return inputs;
    }
  
    function getChoiceContent(element) { // store content elements in an object property
      var contents = [];
      for(var i = 0; i < element.btns.length; i++) {
        var content = Util.getChildrenByClassName(element.btns[i].parentNode, 'js-choice-accordion__panel');
        if(content.length > 0 ) contents.push(content[0]);
        else  contents.push(false);
      }
      return contents;
    }
  
    function initAccordion(element) { //set initial aria attributes
  		for( var i = 0; i < element.inputs.length; i++) {
        if(!element.contents[i]) return; // no content to trigger
        var isOpen = element.inputs[i].checked,
          id = element.inputs[i].getAttribute('id');
        if(!id) id = 'choice-accordion-header-'+i;
        
        Util.setAttributes(element.inputs[i], {'aria-expanded': isOpen, 'aria-controls': 'choice-accordion-content-'+i, 'id': id});
        Util.setAttributes(element.contents[i], {'aria-labelledby': id, 'id': 'choice-accordion-content-'+i});
        Util.toggleClass(element.contents[i], 'is-hidden', !isOpen);
  		}
    };
  
    function initChoiceAccordionEvent(choiceAcc) {
      choiceAcc.element.addEventListener('click', function(event){ // update status on click
        if(Util.getIndexInArray(choiceAcc.inputs, event.target) > -1) return; // triggered by change in input element -> will be detected by the 'change' event
  
        var selectedBtn = event.target.closest('.js-choice-accordion__btn');
        if(!selectedBtn) return;
        
        var index = Util.getIndexInArray(choiceAcc.btns, selectedBtn);
        if(choiceAcc.isRadio && choiceAcc.inputs[index].checked) { // radio input already checked
          choiceAcc.inputs[index].focus(); // move focus to input element
          return; 
        }
  
        choiceAcc.inputs[index].checked = !choiceAcc.inputs[index].checked;
        choiceAcc.inputs[index].dispatchEvent(new CustomEvent('change')); // trigger change event
        choiceAcc.inputs[index].focus(); // move focus to input element
      });
  
      for(var i = 0; i < choiceAcc.btns.length; i++) {(function(i){ // change + focus events
        choiceAcc.inputs[i].addEventListener('change', function(event){
          choiceAcc.isRadio ? resetCheckedStatus(choiceAcc, true) : resetSingleStatus(choiceAcc, i, true);
        });
  
        choiceAcc.inputs[i].addEventListener('focus', function(event){
          resetFocusStatus(choiceAcc, i, true);
        });
  
        choiceAcc.inputs[i].addEventListener('blur', function(event){
          resetFocusStatus(choiceAcc, i, false);
        });
      })(i);}
    };
  
    function resetCheckedStatus(choiceAcc, bool) {
      for(var i = 0; i < choiceAcc.btns.length; i++) {
        resetSingleStatus(choiceAcc, i, bool);
      }
    };
  
    function resetSingleStatus(choiceAcc, index, bool) { // toggle .choice-accordion__btn--checked class
      Util.toggleClass(choiceAcc.btns[index], 'choice-accordion__btn--checked', choiceAcc.inputs[index].checked);
      if(bool) resetSingleContent(choiceAcc, index, choiceAcc.inputs[index].checked); // no need to run this when component is initialized
    };
  
    function resetFocusStatus(choiceAcc, index, bool) { // toggle .choice-accordion__btn--focus class
      Util.toggleClass(choiceAcc.btns[index], 'choice-accordion__btn--focus', bool);
    };
  
    function resetSingleContent(choiceAcc, index, bool) { // show accordion content
      var input = choiceAcc.inputs[index],
        content = choiceAcc.contents[index];
  
  		if(bool && content) Util.removeClass(content, 'is-hidden');
  		input.setAttribute('aria-expanded', bool);
  
  		if(choiceAcc.animateHeight && content) {
  			//store initial and final height - animate accordion content height
  			var initHeight = !bool ? content.offsetHeight: 0,
  				finalHeight = !bool ? 0 : content.offsetHeight;
      }
  
  		if(window.requestAnimationFrame && choiceAcc.animateHeight && !reducedMotion && content) {
  			Util.setHeight(initHeight, finalHeight, content, 200, function(){
  				resetContentVisibility(content, bool);
  			});
  		} else {
  			resetContentVisibility(content, bool);
  		}
    };
  
  	function resetContentVisibility(content, bool) {
      if(!content) return;
  		Util.toggleClass(content, 'is-hidden', !bool);
  		content.removeAttribute("style");
  	};
  
    //initialize the ChoiceAccordions objects
    var choiceAccordion = document.getElementsByClassName('js-choice-accordion'),
      reducedMotion = Util.osHasReducedMotion();
  	if( choiceAccordion.length > 0 ) {
  		for( var i = 0; i < choiceAccordion.length; i++) {
  			(function(i){new ChoiceAccordion(choiceAccordion[i]);})(i);
  		}
  	};
  }());
  // File#: _1_choice-buttons
  // Usage: codyhouse.co/license
  (function() {
    var ChoiceButton = function(element) {
      this.element = element;
      this.btns = this.element.getElementsByClassName('js-choice-btn');
      this.inputs = getChoiceInput(this);
      this.isRadio = this.inputs[0].type.toString() == 'radio';
      resetCheckedStatus(this); // set initial classes
      initChoiceButtonEvent(this); // add listeners
    };
  
    function getChoiceInput(element) { // store input elements in an object property
      var inputs = [];
      for(var i = 0; i < element.btns.length; i++) {
        inputs.push(element.btns[i].getElementsByTagName('input')[0]);
      }
      return inputs;
    };
  
    function initChoiceButtonEvent(choiceBtn) {
      choiceBtn.element.addEventListener('click', function(event){ // update status on click
        if(Util.getIndexInArray(choiceBtn.inputs, event.target) > -1) return; // triggered by change in input element -> will be detected by the 'change' event
  
        var selectedBtn = event.target.closest('.js-choice-btn');
        if(!selectedBtn) return;
        var index = Util.getIndexInArray(choiceBtn.btns, selectedBtn);
        if(choiceBtn.isRadio && choiceBtn.inputs[index].checked) { // radio input already checked
          if(event.target.tagName.toLowerCase() != "input") choiceBtn.inputs[index].focus(); // move focus to input element
          return; 
        }
  
        choiceBtn.inputs[index].checked = !choiceBtn.inputs[index].checked;
        choiceBtn.inputs[index].dispatchEvent(new CustomEvent('change')); // trigger change event
        if(event.target.tagName.toLowerCase() != "input") choiceBtn.inputs[index].focus(); // move focus to input element
      });
  
      for(var i = 0; i < choiceBtn.btns.length; i++) {(function(i){ // change + focus events
        choiceBtn.inputs[i].addEventListener('change', function(event){
          choiceBtn.isRadio ? resetCheckedStatus(choiceBtn) : resetSingleStatus(choiceBtn, i);
        });
  
        choiceBtn.inputs[i].addEventListener('focus', function(event){
          resetFocusStatus(choiceBtn, i, true);
        });
  
        choiceBtn.inputs[i].addEventListener('blur', function(event){
          resetFocusStatus(choiceBtn, i, false);
        });
      })(i);}
    };
  
    function resetCheckedStatus(choiceBtn) {
      for(var i = 0; i < choiceBtn.btns.length; i++) {
        resetSingleStatus(choiceBtn, i);
      }
    };
  
    function resetSingleStatus(choiceBtn, index) { // toggle .choice-btn--checked class
      Util.toggleClass(choiceBtn.btns[index], 'choice-btn--checked', choiceBtn.inputs[index].checked);
    };
  
    function resetFocusStatus(choiceBtn, index, bool) { // toggle .choice-btn--focus class
      Util.toggleClass(choiceBtn.btns[index], 'choice-btn--focus', bool);
    };
  
    //initialize the ChoiceButtons objects
  	var choiceButton = document.getElementsByClassName('js-choice-btns');
  	if( choiceButton.length > 0 ) {
  		for( var i = 0; i < choiceButton.length; i++) {
  			(function(i){new ChoiceButton(choiceButton[i]);})(i);
  		}
  	};
  }());
  // File#: _1_choice-images
  // Usage: codyhouse.co/license
  (function() {
    var ChoiceImgs = function(element) {
      this.element = element;
      this.imgs = this.element.getElementsByClassName('js-choice-img');
      this.isRadio = this.imgs[0].getAttribute('role') == 'radio';
      resetChoiceImgs(this); // set initial aria values
      initChoiceImgsEvent(this);
    };
  
    function initChoiceImgsEvent(choiceImgs) {
      // on click -> select new item
      choiceImgs.element.addEventListener('click', function(event){
        var selectedImg = event.target.closest('.js-choice-img');
        if(!selectedImg) return;
        var index = Util.getIndexInArray(choiceImgs.imgs, selectedImg);
        if(choiceImgs.isRadio) {
          setRadio(choiceImgs, selectedImg, index);
        } else {
          setCheckbox(choiceImgs, selectedImg, index);
        }
      });
  
      // keyboard events
      choiceImgs.element.addEventListener('keydown', function(event){
        var selectedImg = event.target.closest('.js-choice-img');
        if(!selectedImg) return;
        
        if( (event.keyCode && event.keyCode == 32) || (event.key && event.key.toLowerCase() == ' ') ) {
          // spacebar ->if this is a checkbox choice, toggle the state
          if(choiceImgs.isRadio) return;
          event.preventDefault();
          var index = Util.getIndexInArray(choiceImgs.imgs, selectedImg);
          setCheckbox(choiceImgs, selectedImg, index);
        } else if((event.keyCode && (event.keyCode == 40 || event.keyCode == 39) ) || (event.key && (event.key.toLowerCase() == 'arrowdown' || event.key.toLowerCase() == 'arrowright'))) {
          // arrow right/arrow down
          if(!choiceImgs.isRadio) return;
          event.preventDefault();
          navigateRadioImgs(choiceImgs, 1);
        } else if((event.keyCode && (event.keyCode == 38 || event.keyCode == 37) ) || (event.key && (event.key.toLowerCase() == 'arrowup' || event.key.toLowerCase() == 'arrowleft'))) {
          // arrow left/up down
          if(!choiceImgs.isRadio) return;
          event.preventDefault();
          navigateRadioImgs(choiceImgs, -1);
        }
      });
    };
  
    function setCheckbox(choiceImgs, selectedImg, index) {
      var check = selectedImg.getAttribute('aria-checked') == 'false' ? 'true' : 'false';
      selectedImg.setAttribute('aria-checked', check);
      selectedImg.focus(); // move focus to input element
    };
  
    function setRadio(choiceImgs, selectedImg, index) {
      var check = selectedImg.getAttribute('aria-checked') == 'false' ? 'true' : 'false';
      if(check == 'true') {
        selectedImg.setAttribute('aria-checked', check);
        selectedImg.setAttribute('tabindex', '0');
        for(var i = 0; i < choiceImgs.imgs.length; i++) {
          if(i != index) {
            choiceImgs.imgs[i].setAttribute('aria-checked', 'false');
            choiceImgs.imgs[i].removeAttribute('tabindex');
          }
        }
      }
      selectedImg.focus(); // move focus to input element
    };
  
    function navigateRadioImgs(choiceImgs, increment) {
      // navigate radio items with keyboard
      var selectedImg = choiceImgs.element.querySelector('[aria-checked="true"]');
      if(!selectedImg) return;
      var index = Util.getIndexInArray(choiceImgs.imgs, selectedImg);
      index = index + increment;
      if(index < 0) index =  choiceImgs.imgs.length - 1;
      if(index >= choiceImgs.imgs.length) index = 0;
      setRadio(choiceImgs, choiceImgs.imgs[index], index);
    };
  
    function resetChoiceImgs(choiceImgs) {
      for(var i = 0; i < choiceImgs.imgs.length; i++) {
        var check = choiceImgs.imgs[i].getAttribute('aria-checked');
        if(check == 'true') {
          choiceImgs.imgs[i].setAttribute('tabindex', '0'); // make it focusable
        } else {
          // if radio -> element not focusable
          // if checkbox -> element still focusable
          choiceImgs.isRadio ? choiceImgs.imgs[i].removeAttribute('tabindex') : choiceImgs.imgs[i].setAttribute('tabindex', '0');
        }
      }
    };
  
    //initialize the ChoiceImgs objects
  	var choiceImg = document.getElementsByClassName('js-choice-imgs');
  	if( choiceImg.length > 0 ) {
  		for( var i = 0; i < choiceImg.length; i++) {
  			(function(i){new ChoiceImgs(choiceImg[i]);})(i);
  		}
  	};
  }());
  // File#: _1_choice-tags
  // Usage: codyhouse.co/license
  (function() {
    var ChoiceTags = function(element) {
      this.element = element;
      this.labels = this.element.getElementsByClassName('js-choice-tag');
      this.inputs = getChoiceInput(this);
      this.isRadio = this.inputs[0].type.toString() == 'radio';
      this.checkedClass = 'choice-tag--checked';
      initChoiceTags(this);
      initChoiceTagEvent(this);
    }
  
    function getChoiceInput(element) {
      var inputs = [];
      for(var i = 0; i < element.labels.length; i++) {
        inputs.push(element.labels[i].getElementsByTagName('input')[0]);
      }
      return inputs;
    };
  
    function initChoiceTags(element) {
      // if tag is selected by default - add checkedClass to the label element
      for(var i = 0; i < element.inputs.length; i++) {
        Util.toggleClass(element.labels[i], element.checkedClass, element.inputs[i].checked);
      }
    };
  
    function initChoiceTagEvent(element) {
      element.element.addEventListener('change', function(event) {
        var inputIndex = Util.getIndexInArray(element.inputs, event.target);
        if(inputIndex < 0) return;
        Util.toggleClass(element.labels[inputIndex], element.checkedClass, event.target.checked);
        if(element.isRadio && event.target.checked) resetRadioTags(element, inputIndex);
      });
    };
  
    function resetRadioTags(element, index) {
      // when a radio input is checked - reset all the others
      for(var i = 0; i < element.labels.length; i++) {
        if(i != index) Util.removeClass(element.labels[i], element.checkedClass);
      }
    };
  
    //initialize the ChoiceTags objects
  	var choiceTags = document.getElementsByClassName('js-choice-tags');
  	if( choiceTags.length > 0 ) {
  		for( var i = 0; i < choiceTags.length; i++) {
  			(function(i){new ChoiceTags(choiceTags[i]);})(i);
  		}
  	};
  }());
  // File#: _1_circular-progress-bar
  // Usage: codyhouse.co/license
  (function() {	
    var CProgressBar = function(element) {
      this.element = element;
      this.fill = this.element.getElementsByClassName('c-progress-bar__fill')[0];
      this.fillLength = getProgressBarFillLength(this);
      this.label = this.element.getElementsByClassName('js-c-progress-bar__value');
      this.value = parseFloat(this.element.getAttribute('data-progress'));
      // before checking if data-animation is set -> check for reduced motion
      updatedProgressBarForReducedMotion(this);
      this.animate = this.element.hasAttribute('data-animation') && this.element.getAttribute('data-animation') == 'on';
      this.animationDuration = this.element.hasAttribute('data-duration') ? this.element.getAttribute('data-duration') : 1000;
      // animation will run only on browsers supporting IntersectionObserver
      this.canAnimate = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
      // this element is used to announce the percentage value to SR
      this.ariaLabel = this.element.getElementsByClassName('js-c-progress-bar__aria-value');
      // check if we need to update the bar color
      this.changeColor =  Util.hasClass(this.element, 'c-progress-bar--color-update') && Util.cssSupports('color', 'var(--color-value)');
      if(this.changeColor) {
        this.colorThresholds = getProgressBarColorThresholds(this);
      }
      initProgressBar(this);
      // store id to reset animation
      this.animationId = false;
    };
  
    // public function
    CProgressBar.prototype.setProgressBarValue = function(value) {
      setProgressBarValue(this, value);
    };
  
    function getProgressBarFillLength(progressBar) {
      return parseFloat(2*Math.PI*progressBar.fill.getAttribute('r')).toFixed(2);
    };
  
    function getProgressBarColorThresholds(progressBar) {
      var thresholds = [];
      var i = 1;
      while (!isNaN(parseInt(getComputedStyle(progressBar.element).getPropertyValue('--c-progress-bar-color-'+i)))) {
        thresholds.push(parseInt(getComputedStyle(progressBar.element).getPropertyValue('--c-progress-bar-color-'+i)));
        i = i + 1;
      }
      return thresholds;
    };
  
    function updatedProgressBarForReducedMotion(progressBar) {
      // if reduced motion is supported and set to reduced -> remove animations
      if(osHasReducedMotion) progressBar.element.removeAttribute('data-animation');
    };
  
    function initProgressBar(progressBar) {
      // set shape initial dashOffset
      setShapeOffset(progressBar);
      // set initial bar color
      if(progressBar.changeColor) updateProgressBarColor(progressBar, progressBar.value);
      // if data-animation is on -> reset the progress bar and animate when entering the viewport
      if(progressBar.animate && progressBar.canAnimate) animateProgressBar(progressBar);
      else setProgressBarValue(progressBar, progressBar.value);
      // reveal fill and label -> --animate and --color-update variations only
      setTimeout(function(){Util.addClass(progressBar.element, 'c-progress-bar--init');}, 30);
  
      // dynamically update value of progress bar
      progressBar.element.addEventListener('updateProgress', function(event){
        // cancel request animation frame if it was animating
        if(progressBar.animationId) window.cancelAnimationFrame(progressBar.animationId);
        
        var final = event.detail.value,
          duration = (event.detail.duration) ? event.detail.duration : progressBar.animationDuration;
        var start = getProgressBarValue(progressBar);
        // trigger update animation
        updateProgressBar(progressBar, start, final, duration, function(){
          emitProgressBarEvents(progressBar, 'progressCompleted', progressBar.value+'%');
          // update value of label for SR
          if(progressBar.ariaLabel.length > 0) progressBar.ariaLabel[0].textContent = final+'%';
        });
      });
    }; 
  
    function setShapeOffset(progressBar) {
      var center = progressBar.fill.getAttribute('cx');
      progressBar.fill.setAttribute('transform', "rotate(-90 "+center+" "+center+")");
      progressBar.fill.setAttribute('stroke-dashoffset', progressBar.fillLength);
      progressBar.fill.setAttribute('stroke-dasharray', progressBar.fillLength);
    };
  
    function animateProgressBar(progressBar) {
      // reset inital values
      setProgressBarValue(progressBar, 0);
      
      // listen for the element to enter the viewport -> start animation
      var observer = new IntersectionObserver(progressBarObserve.bind(progressBar), { threshold: [0, 0.1] });
      observer.observe(progressBar.element);
    };
  
    function progressBarObserve(entries, observer) { // observe progressBar position -> start animation when inside viewport
      var self = this;
      if(entries[0].intersectionRatio.toFixed(1) > 0 && !this.animationTriggered) {
        updateProgressBar(this, 0, this.value, this.animationDuration, function(){
          emitProgressBarEvents(self, 'progressCompleted', self.value+'%');
        });
      }
    };
  
    function setProgressBarValue(progressBar, value) {
      var offset = ((100 - value)*progressBar.fillLength/100).toFixed(2);
      progressBar.fill.setAttribute('stroke-dashoffset', offset);
      if(progressBar.label.length > 0 ) progressBar.label[0].textContent = value;
      if(progressBar.changeColor) updateProgressBarColor(progressBar, value);
    };
  
    function updateProgressBar(progressBar, start, to, duration, cb) {
      var change = to - start,
        currentTime = null;
  
      var animateFill = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        var val = parseInt((progress/duration)*change + start);
        // make sure value is in correct range
        if(change > 0 && val > to) val = to;
        if(change < 0 && val < to) val = to;
        if(progress >= duration) val = to;
  
        setProgressBarValue(progressBar, val);
        if(progress < duration) {
          progressBar.animationId = window.requestAnimationFrame(animateFill);
        } else {
          progressBar.animationId = false;
          cb();
        }
      };
      if ( window.requestAnimationFrame && !osHasReducedMotion ) {
        progressBar.animationId = window.requestAnimationFrame(animateFill);
      } else {
        setProgressBarValue(progressBar, to);
        cb();
      }
    };
  
    function updateProgressBarColor(progressBar, value) {
      var className = 'c-progress-bar--fill-color-'+ progressBar.colorThresholds.length;
      for(var i = progressBar.colorThresholds.length; i > 0; i--) {
        if( !isNaN(progressBar.colorThresholds[i - 1]) && value <= progressBar.colorThresholds[i - 1]) {
          className = 'c-progress-bar--fill-color-' + i;
        } 
      }
      
      removeProgressBarColorClasses(progressBar);
      Util.addClass(progressBar.element, className);
    };
  
    function removeProgressBarColorClasses(progressBar) {
      var classes = progressBar.element.className.split(" ").filter(function(c) {
        return c.lastIndexOf('c-progress-bar--fill-color-', 0) !== 0;
      });
      progressBar.element.className = classes.join(" ").trim();
    };
  
    function getProgressBarValue(progressBar) {
      return (100 - Math.round((parseFloat(progressBar.fill.getAttribute('stroke-dashoffset'))/progressBar.fillLength)*100));
    };
  
    function emitProgressBarEvents(progressBar, eventName, detail) {
      progressBar.element.dispatchEvent(new CustomEvent(eventName, {detail: detail}));
    };
  
    window.CProgressBar = CProgressBar;
  
    //initialize the CProgressBar objects
    var circularProgressBars = document.getElementsByClassName('js-c-progress-bar');
    var osHasReducedMotion = Util.osHasReducedMotion();
    if( circularProgressBars.length > 0 ) {
      for( var i = 0; i < circularProgressBars.length; i++) {
        (function(i){new CProgressBar(circularProgressBars[i]);})(i);
      }
    }
  }());
  // File#: _1_col-table
  // Usage: codyhouse.co/license
  (function() {
    var ColTable = function(element) {
      this.element = element;
      this.header = this.element.getElementsByTagName('thead')[0];
      this.body = this.element.getElementsByTagName('tbody')[0];
      this.headerRows = this.header.getElementsByTagName('th');
      this.tableRows = this.body.getElementsByTagName('tr');
      this.collapsedLayoutClass = 'cl-table--collapsed';
      this.mainColCellClass = 'cl-table__th-inner';
      initTable(this);
    };
  
    function initTable(table) {
      // create additional table content + set table roles
      addTableContent(table);
      setTableRoles(table);
  
      // custom event emitted when window is resized
      table.element.addEventListener('update-col-table', function(event){
        checkTableLayour(table);
      });
  
      // mobile version - listent to click/key enter on the row -> expand it
      table.element.addEventListener('click', function(event){
        revealColDetails(table, event);
      });
      table.element.addEventListener('keydown', function(event){
        if(event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {
          revealColDetails(table, event);
        }
      });
    };
  
    function checkTableLayour(table) {
      var layout = getComputedStyle(table.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(table.element, table.collapsedLayoutClass, layout != 'expanded');
    };
  
    function addTableContent(table) {
      // for the collapsed version, add a ul with list of details for each table column heading
      var content = [];
      for(var i = 0; i < table.tableRows.length; i++) {
        var cells = table.tableRows[i].getElementsByClassName('cl-table__cell');
        for(var j = 1; j < cells.length; j++) {
          if( i == 0) content[j] = '';
          content[j] = content[j] + '<li class="cl-table__item"><span class="cl-table__label">'+cells[0].innerHTML+':</span><span>'+cells[j].innerHTML+'</span></li>';
        }
      }
      // append new content to each col th
      for(var j = 1; j < table.headerRows.length; j++) {
        var colContent = '<input type="text" class="cl-table__input" aria-hidden="true"><span class="cl-table__th-inner">'+table.headerRows[j].innerHTML+'<i class="cl-table__th-icon" aria-hidden="true"></i></span><ul class="cl-table__list" aria-hidden="true">'+content[j]+'</ul>';
        table.headerRows[j].innerHTML = colContent;
        Util.addClass(table.headerRows[j], 'js-'+table.mainColCellClass);
      }
    };
  
    function setTableRoles(table) {
      var trElements = table.header.getElementsByTagName('tr');
      for(var i=0; i < trElements.length; i++) {
        trElements[i].setAttribute('role', 'row');
      }
      var thElements = table.header.getElementsByTagName('th');
      for(var i=0; i < thElements.length; i++) {
        thElements[i].setAttribute('role', 'cell');
      }
    };
  
    function revealColDetails(table, event) {
      var col = event.target.closest('.js-'+table.mainColCellClass);
      if(!col || event.target.closest('.cl-table__list')) return;
      Util.toggleClass(col, 'cl-table__cell--show-list', !Util.hasClass(col, 'cl-table__cell--show-list'));
    };
  
    //initialize the ColTable objects
  	var colTables = document.getElementsByClassName('js-cl-table');
  	if( colTables.length > 0 ) {
      var j = 0,
      colTablesArray = [];
  		for( var i = 0; i < colTables.length; i++) {
        var beforeContent = getComputedStyle(colTables[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){colTablesArray.push(new ColTable(colTables[i]));})(i);
          j = j + 1;
        }
      }
      
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-col-table');
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < colTablesArray.length; i++) {
            (function(i){colTablesArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  
        (window.requestAnimationFrame) // init table layout
          ? window.requestAnimationFrame(doneResizing)
          : doneResizing();
      }
  	}
  }());
  // File#: _1_collapse
  // Usage: codyhouse.co/license
  (function() {
    var Collapse = function(element) {
      this.element = element;
      this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
      this.animate = this.element.getAttribute('data-collapse-animate') == 'on';
      this.animating = false;
      initCollapse(this);
    };
  
    function initCollapse(element) {
      if ( element.triggers ) {
        // set initial 'aria-expanded' attribute for trigger elements
        updateTriggers(element, !Util.hasClass(element.element, 'is-hidden'));
  
        // detect click on trigger elements
  			for(var i = 0; i < element.triggers.length; i++) {
  				element.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					toggleVisibility(element);
  				});
  			}
      }
      
      // custom event
      element.element.addEventListener('collapseToggle', function(event){
        toggleVisibility(element);
      });
    };
  
    function toggleVisibility(element) {
      var bool = Util.hasClass(element.element, 'is-hidden');
      if(element.animating) return;
      element.animating = true;
      animateElement(element, bool);
      updateTriggers(element, bool);
    };
  
    function animateElement(element, bool) {
      // bool === true -> show content
      if(!element.animate || !window.requestAnimationFrame) {
        Util.toggleClass(element.element, 'is-hidden', !bool);
        element.animating = false;
        return;
      }
  
      // animate content height
      Util.removeClass(element.element, 'is-hidden');
      var initHeight = !bool ? element.element.offsetHeight: 0,
        finalHeight = !bool ? 0 : element.element.offsetHeight;
  
      Util.addClass(element.element, 'overflow-hidden');
      
      Util.setHeight(initHeight, finalHeight, element.element, 200, function(){
        if(!bool) Util.addClass(element.element, 'is-hidden');
        element.element.removeAttribute("style");
        Util.removeClass(element.element, 'overflow-hidden');
        element.animating = false;
      }, 'easeInOutQuad');
    };
  
    function updateTriggers(element, bool) {
      for(var i = 0; i < element.triggers.length; i++) {
        bool ? element.triggers[i].setAttribute('aria-expanded', 'true') : element.triggers[i].removeAttribute('aria-expanded');
      };
    };
  
    window.Collapse = Collapse;
  
    //initialize the Collapse objects
  	var collapses = document.getElementsByClassName('js-collapse');
  	if( collapses.length > 0 ) {
      for( var i = 0; i < collapses.length; i++) {
        new Collapse(collapses[i]);
      }
    }
  }());
  // File#: _1_color-swatches
  // Usage: codyhouse.co/license
  (function() {
    var ColorSwatches = function(element) {
      this.element = element;
      this.select = false;
      initCustomSelect(this); // replace <select> with custom <ul> list
      this.list = this.element.getElementsByClassName('js-color-swatches__list')[0];
      this.swatches = this.list.getElementsByClassName('js-color-swatches__option');
      this.labels = this.list.getElementsByClassName('js-color-swatch__label');
      this.selectedLabel = this.element.getElementsByClassName('js-color-swatches__color');
      this.focusOutId = false;
      initColorSwatches(this);
    };
  
    function initCustomSelect(element) {
      var select = element.element.getElementsByClassName('js-color-swatches__select');
      if(select.length == 0) return;
      element.select = select[0];
      var customContent = '';
      for(var i = 0; i < element.select.options.length; i++) {
        var ariaChecked = i == element.select.selectedIndex ? 'true' : 'false',
          customClass = i == element.select.selectedIndex ? ' color-swatches__item--selected' : '',
          customAttributes = getSwatchCustomAttr(element.select.options[i]);
        customContent = customContent + '<li class="color-swatches__item js-color-swatches__item'+customClass+'" role="radio" aria-checked="'+ariaChecked+'" data-value="'+element.select.options[i].value+'"><span class="js-color-swatches__option js-tab-focus" tabindex="0"'+customAttributes+'><span class="sr-only js-color-swatch__label">'+element.select.options[i].text+'</span><span aria-hidden="true" style="'+element.select.options[i].getAttribute('data-style')+'" class="color-swatches__swatch"></span></span></li>';
      }
  
      var list = document.createElement("ul");
      Util.setAttributes(list, {'class': 'color-swatches__list js-color-swatches__list', 'role': 'radiogroup'});
  
      list.innerHTML = customContent;
      element.element.insertBefore(list, element.select);
      Util.addClass(element.select, 'is-hidden');
    };
  
    function initColorSwatches(element) {
      // detect focusin/focusout event - update selected color label
      element.list.addEventListener('focusin', function(event){
        if(element.focusOutId) clearTimeout(element.focusOutId);
        updateSelectedLabel(element, document.activeElement);
      });
      element.list.addEventListener('focusout', function(event){
        element.focusOutId = setTimeout(function(){
          resetSelectedLabel(element);
        }, 200);
      });
  
      // mouse move events
      for(var i = 0; i < element.swatches.length; i++) {
        handleHoverEvents(element, i);
      }
  
      // --select variation only
      if(element.select) {
        // click event - select new option
        element.list.addEventListener('click', function(event){
          // update selected option
          resetSelectedOption(element, event.target);
        });
  
        // space key - select new option
        element.list.addEventListener('keydown', function(event){
          if( (event.keyCode && event.keyCode == 32 || event.key && event.key == ' ') || (event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter')) {
            // update selected option
            resetSelectedOption(element, event.target);
          }
        });
      }
    };
  
    function handleHoverEvents(element, index) {
      element.swatches[index].addEventListener('mouseenter', function(event){
        updateSelectedLabel(element, element.swatches[index]);
      });
      element.swatches[index].addEventListener('mouseleave', function(event){
        resetSelectedLabel(element);
      });
    };
  
    function resetSelectedOption(element, target) { // for --select variation only - new option selected
      var option = target.closest('.js-color-swatches__item');
      if(!option) return;
      var selectedSwatch =  element.list.querySelector('.color-swatches__item--selected');
      if(selectedSwatch) {
        Util.removeClass(selectedSwatch, 'color-swatches__item--selected');
        selectedSwatch.setAttribute('aria-checked', 'false');
      }
      Util.addClass(option, 'color-swatches__item--selected');
      option.setAttribute('aria-checked', 'true');
      // update select element
      updateNativeSelect(element.select, option.getAttribute('data-value'));
    };
  
    function resetSelectedLabel(element) {
      var selectedSwatch =  element.list.getElementsByClassName('color-swatches__item--selected');
      if(selectedSwatch.length > 0 ) updateSelectedLabel(element, selectedSwatch[0]);
    };
  
    function updateSelectedLabel(element, swatch) {
      var newLabel = swatch.getElementsByClassName('js-color-swatch__label');
      if(newLabel.length == 0 ) return;
      element.selectedLabel[0].textContent = newLabel[0].textContent;
    };
  
    function updateNativeSelect(select, value) {
  		for (var i = 0; i < select.options.length; i++) {
  			if (select.options[i].value == value) {
  				select.selectedIndex = i; // set new value
  				select.dispatchEvent(new CustomEvent('change')); // trigger change event
  				break;
  			}
  		}
    };
    
    function getSwatchCustomAttr(swatch) {
      var customAttrArray = swatch.getAttribute('data-custom-attr');
      if(!customAttrArray) return '';
      var customAttr = ' ',
        list = customAttrArray.split(',');
      for(var i = 0; i < list.length; i++) {
        var attr = list[i].split(':')
        customAttr = customAttr + attr[0].trim()+'="'+attr[1].trim()+'" ';
      }
      return customAttr;
    };
  
    //initialize the ColorSwatches objects
  	var swatches = document.getElementsByClassName('js-color-swatches');
  	if( swatches.length > 0 ) {
      for( var i = 0; i < swatches.length; i++) {
        new ColorSwatches(swatches[i]);
      }
    }
  }());
  // File#: _1_confetti-button
  // Usage: codyhouse.co/license
  (function() {
    var ConfettiBtn = function(element) {
      this.element = element;
      this.btn = this.element.getElementsByClassName('js-confetti-btn__btn');
      this.icon = this.element.getElementsByClassName('js-confetti-btn__icon');
      this.animating = false;
      this.animationClass = 'confetti-btn--animate';
      this.positionVariables = '--conf-btn-click-';
      initConfettiBtn(this);
  	};
  
    function initConfettiBtn(element) {
      if(element.btn.length < 1 || element.icon.length < 1) return;
      element.btn[0].addEventListener('click', function(event){
        if(element.animating) return;
        element.animating = true;
        setAnimationPosition(element, event);
        Util.addClass(element.element, element.animationClass);
        resetAnimation(element);
      });
    };
  
    function setAnimationPosition(element, event) { // change icon position based on click position
      
      var btnBoundingRect = element.btn[0].getBoundingClientRect();
      document.documentElement.style.setProperty(element.positionVariables+'x', (event.clientX - btnBoundingRect.left)+'px');
      document.documentElement.style.setProperty(element.positionVariables+'y', (event.clientY - btnBoundingRect.top)+'px');
    };
  
    function resetAnimation(element) { // reset the button at the end of the icon animation
      
      element.icon[0].addEventListener('animationend', function cb(){
        element.icon[0].removeEventListener('animationend', cb);
        Util.removeClass(element.element, element.animationClass);
        element.animating = false;
      });
    };
  
    var confettiBtn = document.getElementsByClassName('js-confetti-btn');
    if(confettiBtn.length > 0) {
      for(var i = 0; i < confettiBtn.length; i++) {
        (function(i){new ConfettiBtn(confettiBtn[i]);})(i);
      }
    }
  }());
  // File#: _1_countdown
  // Usage: codyhouse.co/license
  (function() {
    var CountDown = function(element) {
      this.element = element;
      this.labels = this.element.getAttribute('data-labels') ? this.element.getAttribute('data-labels').split(',') : [];
      this.intervalId;
      // set visible labels
      this.setVisibleLabels();
      //create countdown HTML
      this.createCountDown();
      //store time elements
      this.days = this.element.getElementsByClassName('js-countdown__value--0')[0];
      this.hours = this.element.getElementsByClassName('js-countdown__value--1')[0];
      this.mins = this.element.getElementsByClassName('js-countdown__value--2')[0];
      this.secs = this.element.getElementsByClassName('js-countdown__value--3')[0];
      this.endTime = this.getEndTime();
      //init counter
      this.initCountDown();
    };
  
    CountDown.prototype.setVisibleLabels = function() {
      this.visibleLabels = this.element.getAttribute('data-visible-labels') ? this.element.getAttribute('data-visible-labels').split(',') : [];
      this.visibleLabels = this.visibleLabels.map(function(label){
        return label.trim();
      });
    };
  
    CountDown.prototype.createCountDown = function() {
      var wrapper = document.createElement("div");
      Util.setAttributes(wrapper, {'aria-hidden': 'true', 'class': 'countdown__timer'});
  
      for(var i = 0; i < 4; i++) {
        var timeItem = document.createElement("span"),
          timeValue = document.createElement("span"),
          timeLabel = document.createElement('span');
        
        timeItem.setAttribute('class', 'countdown__item');
        timeValue.setAttribute('class', 'countdown__value countdown__value--'+i+' js-countdown__value--'+i);
        timeItem.appendChild(timeValue);
  
        if( this.labels && this.labels.length > 0 ) {
          timeLabel.textContent = this.labels[i].trim();
          timeLabel.setAttribute('class', 'countdown__label');
          timeItem.appendChild(timeLabel);
        }
        
        wrapper.appendChild(timeItem);
      }
      // append new content to countdown element
      this.element.insertBefore(wrapper, this.element.firstChild);
      // this.element.appendChild(wrapper);
    };
  
    CountDown.prototype.getEndTime = function() {
      // get number of remaining seconds 
      if(this.element.getAttribute('data-timer')) return Number(this.element.getAttribute('data-timer'))*1000 + new Date().getTime();
      else if(this.element.getAttribute('data-countdown')) return Number(new Date(this.element.getAttribute('data-countdown')).getTime());
    };
  
    CountDown.prototype.initCountDown = function() {
      var self = this;
      this.intervalId = setInterval(function(){
        self.updateCountDown(false);
      }, 1000);
      this.updateCountDown(true);
    };
    
    CountDown.prototype.updateCountDown = function(bool) {
      // original countdown function
      // https://gist.github.com/adriennetacke/f5a25c304f1b7b4a6fa42db70415bad2
      var time = parseInt( (this.endTime - new Date().getTime())/1000 ),
        days = 0,
        hours = 0,
        mins = 0,
        seconds = 0;
  
      if(isNaN(time) || time < 0) {
        clearInterval(this.intervalId);
        this.emitEndEvent();
      } else {
        days = parseInt(time / 86400);
        time = (time % 86400);
        hours = parseInt(time / 3600);
        time = (time % 3600);
        mins = parseInt(time / 60);
        time = (time % 60);
        seconds = parseInt(time);
      }
      
      // hide days/hours/mins if not available 
      if(bool && days == 0 && this.visibleLabels.indexOf('d') < 0) this.days.parentElement.style.display = "none";
      if(bool && days == 0 && hours == 0 && this.visibleLabels.indexOf('h') < 0) this.hours.parentElement.style.display = "none";
      if(bool && days == 0 && hours == 0 && mins == 0 && this.visibleLabels.indexOf('m') < 0) this.mins.parentElement.style.display = "none";
      
      this.days.textContent = days;
      this.hours.textContent = this.getTimeFormat(hours);
      this.mins.textContent = this.getTimeFormat(mins);
      this.secs.textContent = this.getTimeFormat(seconds);
    };
  
    CountDown.prototype.getTimeFormat = function(time) {
      return ('0'+ time).slice(-2);
    };
  
    CountDown.prototype.emitEndEvent = function(time) {
      var event = new CustomEvent('countDownFinished');
      this.element.dispatchEvent(event);
    };
  
    //initialize the CountDown objects
    var countDown = document.getElementsByClassName('js-countdown');
    if( countDown.length > 0 ) {
      for( var i = 0; i < countDown.length; i++) {
        (function(i){new CountDown(countDown[i]);})(i);
      }
    }
  }());
  // File#: _1_countup
  // Usage: codyhouse.co/license
  (function() {	
    var CountUp = function(opts) {
      this.options = Util.extend(CountUp.defaults , opts);
      this.element = this.options.element;
      this.initialValue = parseFloat(this.options.initial);
      this.finalValue = parseFloat(this.element.textContent);
      this.deltaValue = parseFloat(this.options.delta);
      this.intervalId;
      this.animationTriggered = false;
      // animation will run only on browsers supporting IntersectionObserver
      this.canAnimate = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
      initCountUp(this);
    };
  
    CountUp.prototype.reset = function() { // reset element to its initial value
      if(!this.canAnimate) return;
      window.cancelAnimationFrame(this.intervalId);
      this.element.textContent = this.initialValue;
    };  
  
    CountUp.prototype.restart = function() { // restart element animation
      countUpAnimate(this);
    };
  
    function initCountUp(countup) {
      // reset initial value
      countup.initialValue = getCountupStart(countup);
      if(!countup.canAnimate) { // IntersectionObserver not supported
        countUpShow(countup);
        return;
      }
  
      // reset countUp for SR
      initCountUpSr(countup);
  
      // listen for the element to enter the viewport -> start animation
      var observer = new IntersectionObserver(countupObserve.bind(countup), { threshold: [0, 0.1] });
      observer.observe(countup.element);
  
      // listen to events
      countup.element.addEventListener('countUpReset', function(){countup.reset();});
      countup.element.addEventListener('countUpRestart', function(){countup.restart();});
    };
  
    function countUpShow(countup) { // reveal countup after it has been initialized
      Util.addClass(countup.element.closest('.countup'), 'countup--is-visible');
    };
  
    function countupObserve(entries, observer) { // observe countup position -> start animation when inside viewport
      if(entries[0].intersectionRatio.toFixed(1) > 0 && !this.animationTriggered) {
        countUpAnimate(this);
      }
    };
  
    function countUpAnimate(countup) { // animate countup
      countup.element.textContent = countup.initialValue;
      countUpShow(countup);
      window.cancelAnimationFrame(countup.intervalId);
      var currentTime = null;
  
      function runCountUp(timestamp) {
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > countup.options.duration) progress = countup.options.duration;
        var val = getValEaseOut(progress, countup.initialValue, countup.finalValue - countup.initialValue, countup.options.duration);
        countup.element.textContent = getCountUpValue(val, countup);
        if(progress < countup.options.duration) {
          countup.intervalId = window.requestAnimationFrame(runCountUp);
        } else {
          countUpComplete(countup);
        }
      };
  
      countup.intervalId = window.requestAnimationFrame(runCountUp);
    };
  
    function getCountUpValue(val, countup) { // reset new countup value to proper decimal places+separator
      if(countup.options.decimal) {val = parseFloat(val.toFixed(countup.options.decimal));}
      else {val = parseInt(val);}
      if(countup.options.separator) val = val.toLocaleString('en');
      return val;
    }
  
    function countUpComplete(countup) { // emit event when animation is over
      countup.element.dispatchEvent(new CustomEvent('countUpComplete'));
      countup.animationTriggered = true;
    };
  
    function initCountUpSr(countup) { // make sure countup is accessible
      // hide elements that will be animated to SR
      countup.element.setAttribute('aria-hidden', 'true');
      // create new element with visible final value - accessible to SR only
      var srValue = document.createElement('span');
      srValue.textContent = countup.finalValue;
      Util.addClass(srValue, 'sr-only');
      countup.element.parentNode.insertBefore(srValue, countup.element.nextSibling);
    };
  
    function getCountupStart(countup) {
      return countup.deltaValue > 0 ? countup.finalValue - countup.deltaValue : countup.initialValue;
    };
  
    function getValEaseOut(t, b, c, d) { 
      t /= d;
      return -c * t*(t-2) + b;
    };
  
    CountUp.defaults = {
      element : '',
      separator : false,
      duration: 3000,
      decimal: false,
      initial: 0,
      delta: 0
    };
  
    window.CountUp = CountUp;
  
    //initialize the CountUp objects
    var countUp = document.getElementsByClassName('js-countup');
    if( countUp.length > 0 ) {
      for( var i = 0; i < countUp.length; i++) {(function(i){
      	var separator = (countUp[i].getAttribute('data-countup-sep')) ? countUp[i].getAttribute('data-countup-sep') : false,
          duration = (countUp[i].getAttribute('data-countup-duration')) ? countUp[i].getAttribute('data-countup-duration') : CountUp.defaults.duration,
          decimal = (countUp[i].getAttribute('data-countup-decimal')) ? countUp[i].getAttribute('data-countup-decimal') : false,
      		initial = (countUp[i].getAttribute('data-countup-start')) ? countUp[i].getAttribute('data-countup-start') : 0,
          delta = (countUp[i].getAttribute('data-countup-delta')) ? countUp[i].getAttribute('data-countup-delta') : 0;
      	new CountUp({element: countUp[i], separator : separator, duration: duration, decimal: decimal, initial: initial, delta: delta});
      })(i);}
    }
  }());
  // File#: _1_cross-table
  // Usage: codyhouse.co/license
  (function() {
    var CrossTables = function(element) {
      this.element = element;
      this.header = this.element.getElementsByClassName('js-cross-table__header')[0];
      this.body = this.element.getElementsByClassName('js-cross-table__body')[0];
      this.headerItems = this.header.getElementsByClassName('cross-table__cell');
      this.rows = this.body.getElementsByClassName('cross-table__row');
      this.rowSections = this.element.getElementsByClassName('js-cross-table__row--w-full');
      this.singleLayoutClass = 'cross-table--cards';
      initCrossTable(this);
    };
  
    function initCrossTable(table) {
      // create additional table content + set proper roles
      setTableRoles(table);
      addTableContent(table);
  
      // custom event emitted when window is resized
      table.element.addEventListener('update-cross-table', function(event){
        checkTableLayour(table);
      });
    };
  
    function checkTableLayour(table) {
      var layout = getComputedStyle(table.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(table.element, table.singleLayoutClass, layout != 'expanded'); // reset table class
      resetTableLayout(table, layout); // reset table style
    };
  
    function resetTableLayout(table, layout) {
      // reset style based on layout state
      if(table.rowSections.length == 0) return;
      if(layout == 'expanded') {
        table.body.removeAttribute('style');
        for(var i = 0; i < table.rowSections.length; i++) {
          table.rowSections[i].removeAttribute('style'); 
        }
      } else {
        table.body.setAttribute('style', 'padding-top:'+table.rowSections[0].offsetHeight+'px');
        for(var i = 0; i < table.rowSections.length; i++) {
          table.rowSections[i].setAttribute('style', 'left:'+table.rowSections[i].nextElementSibling.offsetLeft+'px');
        }
      }
    };
  
    function setTableRoles(table) {
      // table
      table.element.setAttribute('role', 'table');
      // body and header
      table.header.setAttribute('role', 'rowgroup');
      table.body.setAttribute('role', 'rowgroup');
      // tr, th, td
      var trElements = table.element.getElementsByTagName('tr');
      for(var i=0; i < trElements.length; i++) {
        trElements[i].setAttribute('role', 'row');
      }
      var thElements = table.element.getElementsByTagName('th');
      for(var i=0; i < thElements.length; i++) {
        thElements[i].setAttribute('role', 'rowheader');
      }
      var tdElements = table.element.getElementsByTagName('td');
      for(var i=0; i < tdElements.length; i++) {
        tdElements[i].setAttribute('role', 'cell');
      }
    };
  
    function addTableContent(table) {
      // store header labels
      var headerLables = [];
      for(var i = 0; i < table.headerItems.length; i++) {
        var headerLabelEl = table.headerItems[i].getElementsByClassName('js-cross-table__label'),
          headerLabel = (headerLabelEl.length > 0 ) ? headerLabelEl[0].innerHTML : table.headerItems[i].innerHTML;
        headerLables.push(headerLabel);
      }
      // insert label inside each cell - viible in crads layout only
      for(var i = 0; i < table.rows.length; i++) {
        if( !Util.hasClass(table.rows[i], 'js-cross-table__row--w-full') ) {
          var cells = table.rows[i].children;
          for(var j = 1; j < headerLables.length; j++) {
            if(cells[j]) {
              cells[j].innerHTML = '<span aria-hidden="true" class="cross-table__label">'+headerLables[j]+':</span> <span>'+cells[j].innerHTML+'</span>';
            }
          }
        }
      }
    };
  
    var crossTables = document.getElementsByClassName('js-cross-table');
    if( crossTables.length > 0 ) {
      var j = 0,
      crossTablesArray = [];
      for( var i = 0; i < crossTables.length; i++) {
        var beforeContent = getComputedStyle(crossTables[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){ crossTablesArray.push(new CrossTables(crossTables[i]));})(i);
          j = j + 1;
        }
      }
  
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-cross-table');
        // reset table layout on resize
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < crossTablesArray.length; i++) {
            (function(i){crossTablesArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  
        (window.requestAnimationFrame) // init table layout
          ? window.requestAnimationFrame(doneResizing)
          : doneResizing();
      }
    }
  }());
  // File#: _1_custom-cursor
  // Usage: codyhouse.co/license
  (function() {
    var CustomCursor = function(element) {
      this.element = element;
      this.targets = document.querySelectorAll('[data-custom-cursor="'+this.element.getAttribute('id')+'"]');
      this.target = false;
      this.moving = false;
  
      // cursor classes
      this.inClass = 'c-cursor--in';
      this.outClass = 'c-cursor--out';
      this.positionClass = 'c-cursor--';
    
      initCustomCursor(this);
    };
  
    function initCustomCursor(obj) {
      if(obj.targets.length == 0) return;
      // init events
      for( var i = 0; i < obj.targets.length; i++) {
        (function(i){
          obj.targets[i].addEventListener('mouseenter', handleEvent.bind(obj));
        })(i);
      }
    };
  
    function handleEvent(event) {
      switch(event.type) {
        case 'mouseenter': {
          initMouseEnter(this, event);
          break;
        }
        case 'mouseleave': {
          initMouseLeave(this, event);
          break;
        }
        case 'mousemove': {
          initMouseMove(this, event);
          break;
        }
      }
    };
  
    function initMouseEnter(obj, event) {
      removeTargetEvents(obj);
      obj.target = event.currentTarget;
      // listen for move and leave events
      obj.target.addEventListener('mousemove', handleEvent.bind(obj));
      obj.target.addEventListener('mouseleave', handleEvent.bind(obj));
      // show custom cursor
      toggleCursor(obj, true);
    };
  
    function initMouseLeave(obj, event) {
      removeTargetEvents(obj);
      toggleCursor(obj, false);
      if(obj.moving) {
        window.cancelAnimationFrame(obj.moving);
        obj.moving = false;
      }
    };
  
    function removeTargetEvents(obj) {
      if(obj.target) {
        obj.target.removeEventListener('mousemove', handleEvent.bind(obj));
  		  obj.target.removeEventListener('mouseleave', handleEvent.bind(obj));
        obj.target = false;
      }
    };
  
    function initMouseMove(obj, event) {
      if(obj.moving) return;
      obj.moving = window.requestAnimationFrame(function(){
        moveCursor(obj, event);
      });
    };
  
    function moveCursor(obj, event) {
      obj.element.style.transform = 'translateX('+event.clientX+'px) translateY('+event.clientY+'px)';
      // set position classes
      updatePositionClasses(obj, event.clientX, event.clientY);
      obj.moving = false;
    };
  
    function updatePositionClasses(obj, xposition, yposition) {
      if(!obj.target) return;
      var targetBoundingRect = obj.target.getBoundingClientRect();
      var isLeft = xposition < (targetBoundingRect.left + targetBoundingRect.width/2),
        isTop = yposition < (targetBoundingRect.top + targetBoundingRect.height/2);
  
      // reset classes
      Util.toggleClass(obj.element, obj.positionClass+'left', isLeft);
      Util.toggleClass(obj.element, obj.positionClass+'right', !isLeft);
      Util.toggleClass(obj.element, obj.positionClass+'top', isTop);
      Util.toggleClass(obj.element, obj.positionClass+'bottom', !isTop);
    };
  
    function toggleCursor(obj, bool) {
      Util.toggleClass(obj.element, obj.outClass, !bool);
      Util.toggleClass(obj.element, obj.inClass, bool);
    };
  
    window.CustomCursor = CustomCursor;
  
    var cCursor = document.getElementsByClassName('js-c-cursor');
    if( cCursor.length > 0 && !Util.osHasReducedMotion()) {
      for( var i = 0; i < cCursor.length; i++) {
        (function(i){new CustomCursor(cCursor[i]);})(i);
      }
    }
  }());
  // File#: _1_custom-select
  // Usage: codyhouse.co/license
  (function() {
    // NOTE: you need the js code when using the --custom-dropdown/--minimal variation of the Custom Select component. Default version does nor require JS.
    
    var CustomSelect = function(element) {
      this.element = element;
      this.select = this.element.getElementsByTagName('select')[0];
      this.optGroups = this.select.getElementsByTagName('optgroup');
      this.options = this.select.getElementsByTagName('option');
      this.selectedOption = getSelectedOptionText(this);
      this.selectId = this.select.getAttribute('id');
      this.trigger = false;
      this.dropdown = false;
      this.customOptions = false;
      this.arrowIcon = this.element.getElementsByTagName('svg');
      this.label = document.querySelector('[for="'+this.selectId+'"]');
  
      this.optionIndex = 0; // used while building the custom dropdown
  
      initCustomSelect(this); // init markup
      initCustomSelectEvents(this); // init event listeners
    };
    
    function initCustomSelect(select) {
      // create the HTML for the custom dropdown element
      select.element.insertAdjacentHTML('beforeend', initButtonSelect(select) + initListSelect(select));
      
      // save custom elements
      select.dropdown = select.element.getElementsByClassName('js-select__dropdown')[0];
      select.trigger = select.element.getElementsByClassName('js-select__button')[0];
      select.customOptions = select.dropdown.getElementsByClassName('js-select__item');
      
      // hide default select
      Util.addClass(select.select, 'is-hidden');
      if(select.arrowIcon.length > 0 ) select.arrowIcon[0].style.display = 'none';
  
      // place dropdown
      placeDropdown(select);
    };
  
    function initCustomSelectEvents(select) {
      // option selection in dropdown
      initSelection(select);
  
      // click events
      select.trigger.addEventListener('click', function(){
        toggleCustomSelect(select, false);
      });
      if(select.label) {
        // move focus to custom trigger when clicking on <select> label
        select.label.addEventListener('click', function(){
          Util.moveFocus(select.trigger);
        });
      }
      // keyboard navigation
      select.dropdown.addEventListener('keydown', function(event){
        if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
          keyboardCustomSelect(select, 'prev', event);
        } else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
          keyboardCustomSelect(select, 'next', event);
        }
      });
      // native <select> element has been updated -> update custom select as well
      select.element.addEventListener('select-updated', function(event){
        resetCustomSelect(select);
      });
    };
  
    function toggleCustomSelect(select, bool) {
      var ariaExpanded;
      if(bool) {
        ariaExpanded = bool;
      } else {
        ariaExpanded = select.trigger.getAttribute('aria-expanded') == 'true' ? 'false' : 'true';
      }
      select.trigger.setAttribute('aria-expanded', ariaExpanded);
      if(ariaExpanded == 'true') {
        var selectedOption = getSelectedOption(select);
        Util.moveFocus(selectedOption); // fallback if transition is not supported
        select.dropdown.addEventListener('transitionend', function cb(){
          Util.moveFocus(selectedOption);
          select.dropdown.removeEventListener('transitionend', cb);
        });
        placeDropdown(select); // place dropdown based on available space
      }
    };
  
    function placeDropdown(select) {
      // remove placement classes to reset position
      Util.removeClass(select.dropdown, 'select__dropdown--right select__dropdown--up');
      var triggerBoundingRect = select.trigger.getBoundingClientRect();
      Util.toggleClass(select.dropdown, 'select__dropdown--right', (document.documentElement.clientWidth - 5 < triggerBoundingRect.left + select.dropdown.offsetWidth));
      // check if there's enough space up or down
      var moveUp = (window.innerHeight - triggerBoundingRect.bottom - 5) < triggerBoundingRect.top;
      Util.toggleClass(select.dropdown, 'select__dropdown--up', moveUp);
      // check if we need to set a max width
      var maxHeight = moveUp ? triggerBoundingRect.top - 20 : window.innerHeight - triggerBoundingRect.bottom - 20;
      // set max-height based on available space
      select.dropdown.setAttribute('style', 'max-height: '+maxHeight+'px; width: '+triggerBoundingRect.width+'px;');
    };
  
    function keyboardCustomSelect(select, direction, event) { // navigate custom dropdown with keyboard
      event.preventDefault();
      var index = Util.getIndexInArray(select.customOptions, document.activeElement);
      index = (direction == 'next') ? index + 1 : index - 1;
      if(index < 0) index = select.customOptions.length - 1;
      if(index >= select.customOptions.length) index = 0;
      Util.moveFocus(select.customOptions[index]);
    };
  
    function initSelection(select) { // option selection
      select.dropdown.addEventListener('click', function(event){
        var option = event.target.closest('.js-select__item');
        if(!option) return;
        selectOption(select, option);
      });
    };
    
    function selectOption(select, option) {
      if(option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') == 'true') {
        // selecting the same option
        select.trigger.setAttribute('aria-expanded', 'false'); // hide dropdown
      } else { 
        var selectedOption = select.dropdown.querySelector('[aria-selected="true"]');
        if(selectedOption) selectedOption.setAttribute('aria-selected', 'false');
        option.setAttribute('aria-selected', 'true');
        select.trigger.getElementsByClassName('js-select__label')[0].textContent = option.textContent;
        select.trigger.setAttribute('aria-expanded', 'false');
        // new option has been selected -> update native <select> element _ arai-label of trigger <button>
        updateNativeSelect(select, option.getAttribute('data-index'));
        updateTriggerAria(select); 
      }
      // move focus back to trigger
      select.trigger.focus();
    };
  
    function updateNativeSelect(select, index) {
      select.select.selectedIndex = index;
      select.select.dispatchEvent(new CustomEvent('change', {bubbles: true})); // trigger change event
    };
  
    function updateTriggerAria(select) {
      select.trigger.setAttribute('aria-label', select.options[select.select.selectedIndex].innerHTML+', '+select.label.textContent);
    };
  
    function getSelectedOptionText(select) {// used to initialize the label of the custom select button
      var label = '';
      if('selectedIndex' in select.select) {
        label = select.options[select.select.selectedIndex].text;
      } else {
        label = select.select.querySelector('option[selected]').text;
      }
      return label;
  
    };
    
    function initButtonSelect(select) { // create the button element -> custom select trigger
      // check if we need to add custom classes to the button trigger
      var customClasses = select.element.getAttribute('data-trigger-class') ? ' '+select.element.getAttribute('data-trigger-class') : '';
  
      var label = select.options[select.select.selectedIndex].innerHTML+', '+select.label.textContent;
    
      var button = '<button type="button" class="js-select__button select__button'+customClasses+'" aria-label="'+label+'" aria-expanded="false" aria-controls="'+select.selectId+'-dropdown"><span aria-hidden="true" class="js-select__label select__label">'+select.selectedOption+'</span>';
      if(select.arrowIcon.length > 0 && select.arrowIcon[0].outerHTML) {
        var clone = select.arrowIcon[0].cloneNode(true);
        Util.removeClass(clone, 'select__icon');
        button = button +clone.outerHTML;
      }
      
      return button+'</button>';
  
    };
  
    function initListSelect(select) { // create custom select dropdown
      var list = '<div class="js-select__dropdown select__dropdown" aria-describedby="'+select.selectId+'-description" id="'+select.selectId+'-dropdown">';
      list = list + getSelectLabelSR(select);
      if(select.optGroups.length > 0) {
        for(var i = 0; i < select.optGroups.length; i++) {
          var optGroupList = select.optGroups[i].getElementsByTagName('option'),
            optGroupLabel = '<li><span class="select__item select__item--optgroup">'+select.optGroups[i].getAttribute('label')+'</span></li>';
          list = list + '<ul class="select__list" role="listbox">'+optGroupLabel+getOptionsList(select, optGroupList) + '</ul>';
        }
      } else {
        list = list + '<ul class="select__list" role="listbox">'+getOptionsList(select, select.options) + '</ul>';
      }
      return list;
    };
  
    function getSelectLabelSR(select) {
      if(select.label) {
        return '<p class="sr-only" id="'+select.selectId+'-description">'+select.label.textContent+'</p>'
      } else {
        return '';
      }
    };
    
    function resetCustomSelect(select) {
      // <select> element has been updated (using an external control) - update custom select
      var selectedOption = select.dropdown.querySelector('[aria-selected="true"]');
      if(selectedOption) selectedOption.setAttribute('aria-selected', 'false');
      var option = select.dropdown.querySelector('.js-select__item[data-index="'+select.select.selectedIndex+'"]');
      option.setAttribute('aria-selected', 'true');
      select.trigger.getElementsByClassName('js-select__label')[0].textContent = option.textContent;
      select.trigger.setAttribute('aria-expanded', 'false');
      updateTriggerAria(select); 
    };
  
    function getOptionsList(select, options) {
      var list = '';
      for(var i = 0; i < options.length; i++) {
        var selected = options[i].hasAttribute('selected') ? ' aria-selected="true"' : ' aria-selected="false"',
          disabled = options[i].hasAttribute('disabled') ? ' disabled' : '';
        list = list + '<li><button type="button" class="reset js-select__item select__item select__item--option" role="option" data-value="'+options[i].value+'" '+selected+disabled+' data-index="'+select.optionIndex+'">'+options[i].text+'</button></li>';
        select.optionIndex = select.optionIndex + 1;
      };
      return list;
    };
  
    function getSelectedOption(select) {
      var option = select.dropdown.querySelector('[aria-selected="true"]');
      if(option) return option;
      else return select.dropdown.getElementsByClassName('js-select__item')[0];
    };
  
    function moveFocusToSelectTrigger(select) {
      if(!document.activeElement.closest('.js-select')) return
      select.trigger.focus();
    };
    
    function checkCustomSelectClick(select, target) { // close select when clicking outside it
      if( !select.element.contains(target) ) toggleCustomSelect(select, 'false');
    };
    
    //initialize the CustomSelect objects
    var customSelect = document.getElementsByClassName('js-select');
    if( customSelect.length > 0 ) {
      var selectArray = [];
      for( var i = 0; i < customSelect.length; i++) {
        (function(i){selectArray.push(new CustomSelect(customSelect[i]));})(i);
      }
  
      // listen for key events
      window.addEventListener('keyup', function(event){
        if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
          // close custom select on 'Esc'
          selectArray.forEach(function(element){
            moveFocusToSelectTrigger(element); // if focus is within dropdown, move it to dropdown trigger
            toggleCustomSelect(element, 'false'); // close dropdown
          });
        } 
      });
      // close custom select when clicking outside it
      window.addEventListener('click', function(event){
        selectArray.forEach(function(element){
          checkCustomSelectClick(element, event.target);
        });
      });
    }
  }());
  // File#: _1_date-picker
  // Usage: codyhouse.co/license
  (function() {
    var DatePicker = function(opts) {
      this.options = Util.extend(DatePicker.defaults , opts);
      this.element = this.options.element;
      this.input = this.element.getElementsByClassName('js-date-input__text')[0];
      this.trigger = this.element.getElementsByClassName('js-date-input__trigger')[0];
      this.triggerLabel = this.trigger.getAttribute('aria-label');
      this.datePicker = this.element.getElementsByClassName('js-date-picker')[0];
      this.body = this.datePicker.getElementsByClassName('js-date-picker__dates')[0];
      this.navigation = this.datePicker.getElementsByClassName('js-date-picker__month-nav')[0];
      this.heading = this.datePicker.getElementsByClassName('js-date-picker__month-label')[0];
      this.pickerVisible = false;
      // date format
      this.dateIndexes = getDateIndexes(this); // store indexes of date parts (d, m, y)
      // set initial date
      resetCalendar(this);
      // selected date
      this.dateSelected = false;
      this.selectedDay = false;
      this.selectedMonth = false;
      this.selectedYear = false;
      // focus trap
      this.firstFocusable = false;
      this.lastFocusable = false;
      // date value - for custom control variation
      this.dateValueEl = this.element.getElementsByClassName('js-date-input__value');
      if(this.dateValueEl.length > 0) {
        this.dateValueLabelInit = this.dateValueEl[0].textContent; // initial input value
      }
      initCalendarAria(this);
      initCalendarEvents(this);
      // place picker according to available space
      placeCalendar(this);
    };
  
    DatePicker.prototype.showCalendar = function() {
      showCalendar(this);
    };
  
    DatePicker.prototype.showNextMonth = function() {
      showNext(this, true);
    };
  
    DatePicker.prototype.showPrevMonth = function() {
      showPrev(this, true);
    };
  
    function initCalendarAria(datePicker) {
      // reset calendar button label
      resetLabelCalendarTrigger(datePicker);
      if(datePicker.dateValueEl.length > 0) {
        resetCalendar(datePicker);
        resetLabelCalendarValue(datePicker);
      }
      // create a live region used to announce new month selection to SR
      var srLiveReagion = document.createElement('div');
      srLiveReagion.setAttribute('aria-live', 'polite');
      Util.addClass(srLiveReagion, 'sr-only js-date-input__sr-live');
      datePicker.element.appendChild(srLiveReagion);
      datePicker.srLiveReagion = datePicker.element.getElementsByClassName('js-date-input__sr-live')[0];
    };
  
    function initCalendarEvents(datePicker) {
      datePicker.input.addEventListener('focus', function(event){
        toggleCalendar(datePicker, true); // toggle calendar when focus is on input
      });
      if(datePicker.trigger) {
        datePicker.trigger.addEventListener('click', function(event){ // open calendar when clicking on calendar button
          event.preventDefault();
          datePicker.pickerVisible = false;
          toggleCalendar(datePicker);
          datePicker.trigger.setAttribute('aria-expanded', 'true');
        });
      }
  
      // select a date inside the date picker
      datePicker.body.addEventListener('click', function(event){
        event.preventDefault();
        var day = event.target.closest('button');
        if(day) {
          datePicker.dateSelected = true;
          datePicker.selectedDay = day.innerText;
          datePicker.selectedMonth = datePicker.currentMonth;
          datePicker.selectedYear = datePicker.currentYear;
          setInputValue(datePicker);
          datePicker.input.focus(); // focus on the input element and close picker
          resetLabelCalendarTrigger(datePicker);
          resetLabelCalendarValue(datePicker);
        }
      });
  
      // navigate using month nav
      datePicker.navigation.addEventListener('click', function(event){
        event.preventDefault();
        var btn = event.target.closest('.js-date-picker__month-nav-btn');
        if(btn) {
          Util.hasClass(btn, 'js-date-picker__month-nav-btn--prev') ? showPrev(datePicker, true) : showNext(datePicker, true);
        }
      });
  
      // hide calendar
      window.addEventListener('keydown', function(event){ // close calendar on esc
        if(event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape') {
          if(document.activeElement.closest('.js-date-picker')) {
            datePicker.input.focus(); //if focus is inside the calendar -> move the focus to the input element 
          } else { // do not move focus -> only close calendar
            hideCalendar(datePicker); 
          }
        }
      });
      window.addEventListener('click', function(event){
        if(!event.target.closest('.js-date-picker') && !event.target.closest('.js-date-input') && datePicker.pickerVisible) {
          hideCalendar(datePicker);
        }
      });
  
      // navigate through days of calendar
      datePicker.body.addEventListener('keydown', function(event){
        var day = datePicker.currentDay;
        if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
          day = day + 7;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
          day = day + 1;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
          day = day - 1;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
          day = day - 7;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 35 || event.key && event.key.toLowerCase() == 'end') { // move focus to last day of week
          event.preventDefault();
          day = day + 6 - getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, day);
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 36 || event.key && event.key.toLowerCase() == 'home') { // move focus to first day of week
          event.preventDefault();
          day = day - getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, day);
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 34 || event.key && event.key.toLowerCase() == 'pagedown') {
          event.preventDefault();
          showNext(datePicker); // show next month
        } else if(event.keyCode && event.keyCode == 33 || event.key && event.key.toLowerCase() == 'pageup') {
          event.preventDefault();
          showPrev(datePicker); // show prev month
        }
      });
  
      // trap focus inside calendar
      datePicker.datePicker.addEventListener('keydown', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
          //trap focus inside modal
          trapFocus(event, datePicker);
        }
      });
  
      datePicker.input.addEventListener('keydown', function(event){
        if(event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {
          // update calendar on input enter
          resetCalendar(datePicker);
          resetLabelCalendarTrigger(datePicker);
          resetLabelCalendarValue(datePicker);
          hideCalendar(datePicker);
        } else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown' && datePicker.pickerVisible) { // move focus to calendar using arrow down
          datePicker.body.querySelector('button[tabindex="0"]').focus();
        };
      });
    };
  
    function getCurrentDay(date) {
      return (date) 
        ? getDayFromDate(date)
        : new Date().getDate();
    };
  
    function getCurrentMonth(date) {
      return (date) 
        ? getMonthFromDate(date)
        : new Date().getMonth();
    };
  
    function getCurrentYear(date) {
      return (date) 
        ? getYearFromDate(date)
        : new Date().getFullYear();
    };
  
    function getDayFromDate(date) {
      var day = parseInt(date.split('-')[2]);
      return isNaN(day) ? getCurrentDay(false) : day;
    };
  
    function getMonthFromDate(date) {
      var month = parseInt(date.split('-')[1]) - 1;
      return isNaN(month) ? getCurrentMonth(false) : month;
    };
  
    function getYearFromDate(date) {
      var year = parseInt(date.split('-')[0]);
      return isNaN(year) ? getCurrentYear(false) : year;
    };
  
    function showNext(datePicker, bool) {
      // show next month
      datePicker.currentYear = (datePicker.currentMonth === 11) ? datePicker.currentYear + 1 : datePicker.currentYear;
      datePicker.currentMonth = (datePicker.currentMonth + 1) % 12;
      datePicker.currentDay = checkDayInMonth(datePicker);
      showCalendar(datePicker, bool);
      datePicker.srLiveReagion.textContent = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
    };
  
    function showPrev(datePicker, bool) {
      // show prev month
      datePicker.currentYear = (datePicker.currentMonth === 0) ? datePicker.currentYear - 1 : datePicker.currentYear;
      datePicker.currentMonth = (datePicker.currentMonth === 0) ? 11 : datePicker.currentMonth - 1;
      datePicker.currentDay = checkDayInMonth(datePicker);
      showCalendar(datePicker, bool);
      datePicker.srLiveReagion.textContent = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
    };
  
    function checkDayInMonth(datePicker) {
      return (datePicker.currentDay > daysInMonth(datePicker.currentYear, datePicker.currentMonth)) ? 1 : datePicker.currentDay;
    };
  
    function daysInMonth(year, month) {
      return 32 - new Date(year, month, 32).getDate();
    };
  
    function resetCalendar(datePicker) {
      var currentDate = false,
        selectedDate = datePicker.input.value;
  
      datePicker.dateSelected = false;
      if( selectedDate != '') {
        var date = getDateFromInput(datePicker);
        datePicker.dateSelected = true;
        currentDate = date;
      } 
      datePicker.currentDay = getCurrentDay(currentDate);
      datePicker.currentMonth = getCurrentMonth(currentDate); 
      datePicker.currentYear = getCurrentYear(currentDate); 
      
      datePicker.selectedDay = datePicker.dateSelected ? datePicker.currentDay : false;
      datePicker.selectedMonth = datePicker.dateSelected ? datePicker.currentMonth : false;
      datePicker.selectedYear = datePicker.dateSelected ? datePicker.currentYear : false;
    };
  
    function showCalendar(datePicker, bool) {
      // show calendar element
      var firstDay = getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, '01');
      datePicker.body.innerHTML = '';
      datePicker.heading.innerHTML = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
  
      // creating all cells
      var date = 1,
        calendar = '';
      for (var i = 0; i < 6; i++) {
        for (var j = 0; j < 7; j++) {
          if (i === 0 && j < firstDay) {
            calendar = calendar + '<li></li>';
          } else if (date > daysInMonth(datePicker.currentYear, datePicker.currentMonth)) {
            break;
          } else {
            var classListDate = '',
              tabindexValue = '-1';
            if (date === datePicker.currentDay) {
              tabindexValue = '0';
            } 
            if(!datePicker.dateSelected && getCurrentMonth() == datePicker.currentMonth && getCurrentYear() == datePicker.currentYear && date == getCurrentDay()){
              classListDate = classListDate+' date-picker__date--today'
            }
            if (datePicker.dateSelected && date === datePicker.selectedDay && datePicker.currentYear === datePicker.selectedYear && datePicker.currentMonth === datePicker.selectedMonth) {
              classListDate = classListDate+'  date-picker__date--selected';
            }
            calendar = calendar + '<li><button class="date-picker__date'+classListDate+'" tabindex="'+tabindexValue+'" type="button">'+date+'</button></li>';
            date++;
          }
        }
      }
      datePicker.body.innerHTML = calendar; // appending days into calendar body
      
      // show calendar
      if(!datePicker.pickerVisible) Util.addClass(datePicker.datePicker, 'date-picker--is-visible');
      datePicker.pickerVisible = true;
  
      //  if bool is false, move focus to calendar day
      if(!bool) datePicker.body.querySelector('button[tabindex="0"]').focus();
  
      // store first/last focusable elements
      getFocusableElements(datePicker);
  
      //place calendar
      placeCalendar(datePicker);
    };
  
    function hideCalendar(datePicker) {
      Util.removeClass(datePicker.datePicker, 'date-picker--is-visible');
      datePicker.pickerVisible = false;
  
      // reset first/last focusable
      datePicker.firstFocusable = false;
      datePicker.lastFocusable = false;
  
      // reset trigger aria-expanded attribute
      if(datePicker.trigger) datePicker.trigger.setAttribute('aria-expanded', 'false');
    };
  
    function toggleCalendar(datePicker, bool) {
      if(!datePicker.pickerVisible) {
        resetCalendar(datePicker);
        showCalendar(datePicker, bool);
      } else {
        hideCalendar(datePicker);
      }
    };
  
    function getDayOfWeek(year, month, day) {
      var weekDay = (new Date(year, month, day)).getDay() - 1;
      if(weekDay < 0) weekDay = 6;
      return weekDay;
    };
  
    function getDateIndexes(datePicker) {
      var dateFormat = datePicker.options.dateFormat.toLowerCase().replace(/-/g, '');
      return [dateFormat.indexOf('d'), dateFormat.indexOf('m'), dateFormat.indexOf('y')];
    };
  
    function setInputValue(datePicker) {
      datePicker.input.value = getDateForInput(datePicker);
    };
  
    function getDateForInput(datePicker) {
      var dateArray = [];
      dateArray[datePicker.dateIndexes[0]] = getReadableDate(datePicker.selectedDay);
      dateArray[datePicker.dateIndexes[1]] = getReadableDate(datePicker.selectedMonth+1);
      dateArray[datePicker.dateIndexes[2]] = datePicker.selectedYear;
      return dateArray[0]+datePicker.options.dateSeparator+dateArray[1]+datePicker.options.dateSeparator+dateArray[2];
    };
  
    function getDateFromInput(datePicker) {
      var dateArray = datePicker.input.value.split(datePicker.options.dateSeparator);
      return dateArray[datePicker.dateIndexes[2]]+'-'+dateArray[datePicker.dateIndexes[1]]+'-'+dateArray[datePicker.dateIndexes[0]];
    };
  
    function getReadableDate(date) {
      return (date < 10) ? '0'+date : date;
    };
  
    function resetDayValue(day, datePicker) {
      var totDays = daysInMonth(datePicker.currentYear, datePicker.currentMonth);
      if( day > totDays) {
        datePicker.currentDay = day - totDays;
        showNext(datePicker, false);
      } else if(day < 1) {
        var newMonth = datePicker.currentMonth == 0 ? 11 : datePicker.currentMonth - 1;
        datePicker.currentDay = daysInMonth(datePicker.currentYear, newMonth) + day;
        showPrev(datePicker, false);
      } else {
        datePicker.currentDay = day;
        datePicker.body.querySelector('button[tabindex="0"]').setAttribute('tabindex', '-1');
        // set new tabindex to selected item
        var buttons = datePicker.body.getElementsByTagName("button");
        for (var i = 0; i < buttons.length; i++) {
          if (buttons[i].textContent == datePicker.currentDay) {
            buttons[i].setAttribute('tabindex', '0');
            buttons[i].focus();
            break;
          }
        }
        getFocusableElements(datePicker); // update first focusable/last focusable element
      }
    };
  
    function resetLabelCalendarTrigger(datePicker) {
      if(!datePicker.trigger) return;
      // reset accessible label of the calendar trigger
      (datePicker.selectedYear && datePicker.selectedMonth !== false && datePicker.selectedDay) 
        ? datePicker.trigger.setAttribute('aria-label', datePicker.triggerLabel+', selected date is '+ new Date(datePicker.selectedYear, datePicker.selectedMonth, datePicker.selectedDay).toDateString())
        : datePicker.trigger.setAttribute('aria-label', datePicker.triggerLabel);
    };
  
    function resetLabelCalendarValue(datePicker) {
      // this is used for the --custom-control variation -> there's a label that should be updated with the selected date
      if(datePicker.dateValueEl.length < 1) return;
      (datePicker.selectedYear && datePicker.selectedMonth !== false && datePicker.selectedDay) 
        ? datePicker.dateValueEl[0].textContent = getDateForInput(datePicker)
        : datePicker.dateValueEl[0].textContent = datePicker.dateValueLabelInit;
    };
  
    function getFocusableElements(datePicker) {
      var allFocusable = datePicker.datePicker.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
      getFirstFocusable(allFocusable, datePicker);
      getLastFocusable(allFocusable, datePicker);
    }
  
    function getFirstFocusable(elements, datePicker) {
      for(var i = 0; i < elements.length; i++) {
  			if( (elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length) &&  elements[i].getAttribute('tabindex') != '-1') {
  				datePicker.firstFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function getLastFocusable(elements, datePicker) {
      //get last visible focusable element inside the modal
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( (elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length) &&  elements[i].getAttribute('tabindex') != '-1' ) {
  				datePicker.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function trapFocus(event, datePicker) {
      if( datePicker.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of calendar
  			event.preventDefault();
  			datePicker.lastFocusable.focus();
  		}
  		if( datePicker.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of calendar
  			event.preventDefault();
  			datePicker.firstFocusable.focus();
  		}
    };
  
    function placeCalendar(datePicker) {
      // reset position
      datePicker.datePicker.style.left = '0px';
      datePicker.datePicker.style.right = 'auto';
      
      //check if you need to modify the calendar postion
      var pickerBoundingRect = datePicker.datePicker.getBoundingClientRect();
  
      if(pickerBoundingRect.right > window.innerWidth) {
        datePicker.datePicker.style.left = 'auto';
        datePicker.datePicker.style.right = '0px';
      }
    };
  
    DatePicker.defaults = {
      element : '',
      months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      dateFormat: 'd-m-y',
      dateSeparator: '/'
    };
  
    window.DatePicker = DatePicker;
  
    var datePicker = document.getElementsByClassName('js-date-input'),
      flexSupported = Util.cssSupports('align-items', 'stretch');
    if( datePicker.length > 0 ) {
  		for( var i = 0; i < datePicker.length; i++) {(function(i){
        if(!flexSupported) {
          Util.addClass(datePicker[i], 'date-input--hide-calendar');
          return;
        }
        var opts = {element: datePicker[i]};
        if(datePicker[i].getAttribute('data-date-format')) {
          opts.dateFormat = datePicker[i].getAttribute('data-date-format');
        }
        if(datePicker[i].getAttribute('data-date-separator')) {
          opts.dateSeparator = datePicker[i].getAttribute('data-date-separator');
        }
        if(datePicker[i].getAttribute('data-months')) {
          opts.months = datePicker[i].getAttribute('data-months').split(',').map(function(item) {return item.trim();});
        }
        new DatePicker(opts);
      })(i);}
  	}
  }());
  
  
  // File#: _1_details
  // Usage: codyhouse.co/license
  (function() {
  	var Details = function(element, index) {
  		this.element = element;
  		this.summary = this.element.getElementsByClassName('js-details__summary')[0];
  		this.details = this.element.getElementsByClassName('js-details__content')[0];
  		this.htmlElSupported = 'open' in this.element;
  		this.initDetails(index);
  		this.initDetailsEvents();
  	};
  
  	Details.prototype.initDetails = function(index) {
  		// init aria attributes 
  		Util.setAttributes(this.summary, {'aria-expanded': 'false', 'aria-controls': 'details--'+index, 'role': 'button'});
  		Util.setAttributes(this.details, {'aria-hidden': 'true', 'id': 'details--'+index});
  	};
  
  	Details.prototype.initDetailsEvents = function() {
  		var self = this;
  		if( this.htmlElSupported ) { // browser supports the <details> element 
  			this.element.addEventListener('toggle', function(event){
  				var ariaValues = self.element.open ? ['true', 'false'] : ['false', 'true'];
  				// update aria attributes when details element status change (open/close)
  				self.updateAriaValues(ariaValues);
  			});
  		} else { //browser does not support <details>
  			this.summary.addEventListener('click', function(event){
  				event.preventDefault();
  				var isOpen = self.element.getAttribute('open'),
  					ariaValues = [];
  
  				isOpen ? self.element.removeAttribute('open') : self.element.setAttribute('open', 'true');
  				ariaValues = isOpen ? ['false', 'true'] : ['true', 'false'];
  				self.updateAriaValues(ariaValues);
  			});
  		}
  	};
  
  	Details.prototype.updateAriaValues = function(values) {
  		this.summary.setAttribute('aria-expanded', values[0]);
  		this.details.setAttribute('aria-hidden', values[1]);
  	};
  
  	//initialize the Details objects
  	var detailsEl = document.getElementsByClassName('js-details');
  	if( detailsEl.length > 0 ) {
  		for( var i = 0; i < detailsEl.length; i++) {
  			(function(i){new Details(detailsEl[i], i);})(i);
  		}
  	}
  }());
  // File#: _1_diagonal-movement
  // Usage: codyhouse.co/license
  /*
    Modified version of the jQuery-menu-aim plugin
    https://github.com/kamens/jQuery-menu-aim
    - Replaced jQuery with Vanilla JS
    - Minor changes
  */
  (function() {
    var menuAim = function(opts) {
      init(opts);
    };
  
    window.menuAim = menuAim;
  
    function init(opts) {
      var activeRow = null,
        mouseLocs = [],
        lastDelayLoc = null,
        timeoutId = null,
        options = Util.extend({
          menu: '',
          rows: false, //if false, get direct children - otherwise pass nodes list 
          submenuSelector: "*",
          submenuDirection: "right",
          tolerance: 75,  // bigger = more forgivey when entering submenu
          enter: function(){},
          exit: function(){},
          activate: function(){},
          deactivate: function(){},
          exitMenu: function(){}
        }, opts),
        menu = options.menu;
  
      var MOUSE_LOCS_TRACKED = 3,  // number of past mouse locations to track
        DELAY = 300;  // ms delay when user appears to be entering submenu
  
      /**
       * Keep track of the last few locations of the mouse.
       */
      var mouseMoveFallback = function(event) {
        (!window.requestAnimationFrame) ? mousemoveDocument(event) : window.requestAnimationFrame(function(){mousemoveDocument(event);});
      };
  
      var mousemoveDocument = function(e) {
        mouseLocs.push({x: e.pageX, y: e.pageY});
  
        if (mouseLocs.length > MOUSE_LOCS_TRACKED) {
          mouseLocs.shift();
        }
      };
  
      /**
       * Cancel possible row activations when leaving the menu entirely
       */
      var mouseleaveMenu = function() {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
  
        // If exitMenu is supplied and returns true, deactivate the
        // currently active row on menu exit.
        if (options.exitMenu(this)) {
          if (activeRow) {
            options.deactivate(activeRow);
          }
  
          activeRow = null;
        }
      };
  
      /**
       * Trigger a possible row activation whenever entering a new row.
       */
      var mouseenterRow = function() {
        if (timeoutId) {
          // Cancel any previous activation delays
          clearTimeout(timeoutId);
        }
  
        options.enter(this);
        possiblyActivate(this);
      },
      mouseleaveRow = function() {
        options.exit(this);
      };
  
      /*
       * Immediately activate a row if the user clicks on it.
       */
      var clickRow = function() {
        activate(this);
      };  
  
      /**
       * Activate a menu row.
       */
      var activate = function(row) {
        if (row == activeRow) {
          return;
        }
  
        if (activeRow) {
          options.deactivate(activeRow);
        }
  
        options.activate(row);
        activeRow = row;
      };
  
      /**
       * Possibly activate a menu row. If mouse movement indicates that we
       * shouldn't activate yet because user may be trying to enter
       * a submenu's content, then delay and check again later.
       */
      var possiblyActivate = function(row) {
        var delay = activationDelay();
  
        if (delay) {
          timeoutId = setTimeout(function() {
            possiblyActivate(row);
          }, delay);
        } else {
          activate(row);
        }
      };
  
      /**
       * Return the amount of time that should be used as a delay before the
       * currently hovered row is activated.
       *
       * Returns 0 if the activation should happen immediately. Otherwise,
       * returns the number of milliseconds that should be delayed before
       * checking again to see if the row should be activated.
       */
      var activationDelay = function() {
        if (!activeRow || !Util.is(activeRow, options.submenuSelector)) {
          // If there is no other submenu row already active, then
          // go ahead and activate immediately.
          return 0;
        }
  
        function getOffset(element) {
          var rect = element.getBoundingClientRect();
          return { top: rect.top + window.pageYOffset, left: rect.left + window.pageXOffset };
        };
  
        var offset = getOffset(menu),
            upperLeft = {
                x: offset.left,
                y: offset.top - options.tolerance
            },
            upperRight = {
                x: offset.left + menu.offsetWidth,
                y: upperLeft.y
            },
            lowerLeft = {
                x: offset.left,
                y: offset.top + menu.offsetHeight + options.tolerance
            },
            lowerRight = {
                x: offset.left + menu.offsetWidth,
                y: lowerLeft.y
            },
            loc = mouseLocs[mouseLocs.length - 1],
            prevLoc = mouseLocs[0];
  
        if (!loc) {
          return 0;
        }
  
        if (!prevLoc) {
          prevLoc = loc;
        }
  
        if (prevLoc.x < offset.left || prevLoc.x > lowerRight.x || prevLoc.y < offset.top || prevLoc.y > lowerRight.y) {
          // If the previous mouse location was outside of the entire
          // menu's bounds, immediately activate.
          return 0;
        }
  
        if (lastDelayLoc && loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {
          // If the mouse hasn't moved since the last time we checked
          // for activation status, immediately activate.
          return 0;
        }
  
        // Detect if the user is moving towards the currently activated
        // submenu.
        //
        // If the mouse is heading relatively clearly towards
        // the submenu's content, we should wait and give the user more
        // time before activating a new row. If the mouse is heading
        // elsewhere, we can immediately activate a new row.
        //
        // We detect this by calculating the slope formed between the
        // current mouse location and the upper/lower right points of
        // the menu. We do the same for the previous mouse location.
        // If the current mouse location's slopes are
        // increasing/decreasing appropriately compared to the
        // previous's, we know the user is moving toward the submenu.
        //
        // Note that since the y-axis increases as the cursor moves
        // down the screen, we are looking for the slope between the
        // cursor and the upper right corner to decrease over time, not
        // increase (somewhat counterintuitively).
        function slope(a, b) {
          return (b.y - a.y) / (b.x - a.x);
        };
  
        var decreasingCorner = upperRight,
          increasingCorner = lowerRight;
  
        // Our expectations for decreasing or increasing slope values
        // depends on which direction the submenu opens relative to the
        // main menu. By default, if the menu opens on the right, we
        // expect the slope between the cursor and the upper right
        // corner to decrease over time, as explained above. If the
        // submenu opens in a different direction, we change our slope
        // expectations.
        if (options.submenuDirection == "left") {
          decreasingCorner = lowerLeft;
          increasingCorner = upperLeft;
        } else if (options.submenuDirection == "below") {
          decreasingCorner = lowerRight;
          increasingCorner = lowerLeft;
        } else if (options.submenuDirection == "above") {
          decreasingCorner = upperLeft;
          increasingCorner = upperRight;
        }
  
        var decreasingSlope = slope(loc, decreasingCorner),
          increasingSlope = slope(loc, increasingCorner),
          prevDecreasingSlope = slope(prevLoc, decreasingCorner),
          prevIncreasingSlope = slope(prevLoc, increasingCorner);
  
        if (decreasingSlope < prevDecreasingSlope && increasingSlope > prevIncreasingSlope) {
          // Mouse is moving from previous location towards the
          // currently activated submenu. Delay before activating a
          // new menu row, because user may be moving into submenu.
          lastDelayLoc = loc;
          return DELAY;
        }
  
        lastDelayLoc = null;
        return 0;
      };
  
      var reset = function(triggerDeactivate) {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
  
        if (activeRow && triggerDeactivate) {
          options.deactivate(activeRow);
        }
  
        activeRow = null;
      };
  
      var destroyInstance = function() {
        menu.removeEventListener('mouseleave', mouseleaveMenu);  
        document.removeEventListener('mousemove', mouseMoveFallback);
        if(rows.length > 0) {
          for(var i = 0; i < rows.length; i++) {
            rows[i].removeEventListener('mouseenter', mouseenterRow);  
            rows[i].removeEventListener('mouseleave', mouseleaveRow);
            rows[i].removeEventListener('click', clickRow);  
          }
        }
        
      };
  
      /**
       * Hook up initial menu events
       */
      menu.addEventListener('mouseleave', mouseleaveMenu);  
      var rows = (options.rows) ? options.rows : menu.children;
      if(rows.length > 0) {
        for(var i = 0; i < rows.length; i++) {(function(i){
          rows[i].addEventListener('mouseenter', mouseenterRow);  
          rows[i].addEventListener('mouseleave', mouseleaveRow);
          rows[i].addEventListener('click', clickRow);  
        })(i);}
      }
  
      document.addEventListener('mousemove', mouseMoveFallback);
  
      /* Reset/destroy menu */
      menu.addEventListener('reset', function(event){
        reset(event.detail);
      });
      menu.addEventListener('destroy', destroyInstance);
    };
  }());
  
  
  // File#: _1_dialog
  // Usage: codyhouse.co/license
  (function() {
    var Dialog = function(element) {
      this.element = element;
      this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
      this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.selectedTrigger = null;
  		this.showClass = "dialog--is-visible";
      initDialog(this);
    };
  
    function initDialog(dialog) {
      if ( dialog.triggers ) {
  			for(var i = 0; i < dialog.triggers.length; i++) {
  				dialog.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					dialog.selectedTrigger = event.target;
  					showDialog(dialog);
  					initDialogEvents(dialog);
  				});
  			}
      }
      
      // listen to the openDialog event -> open dialog without a trigger button
  		dialog.element.addEventListener('openDialog', function(event){
  			if(event.detail) self.selectedTrigger = event.detail;
  			showDialog(dialog);
  			initDialogEvents(dialog);
  		});
    };
  
    function showDialog(dialog) {
  		Util.addClass(dialog.element, dialog.showClass);
      getFocusableElements(dialog);
  		dialog.firstFocusable.focus();
  		// wait for the end of transitions before moving focus
  		dialog.element.addEventListener("transitionend", function cb(event) {
  			dialog.firstFocusable.focus();
  			dialog.element.removeEventListener("transitionend", cb);
  		});
  		emitDialogEvents(dialog, 'dialogIsOpen');
    };
  
    function closeDialog(dialog) {
      Util.removeClass(dialog.element, dialog.showClass);
  		dialog.firstFocusable = null;
  		dialog.lastFocusable = null;
  		if(dialog.selectedTrigger) dialog.selectedTrigger.focus();
  		//remove listeners
  		cancelDialogEvents(dialog);
  		emitDialogEvents(dialog, 'dialogIsClose');
    };
    
    function initDialogEvents(dialog) {
      //add event listeners
  		dialog.element.addEventListener('keydown', handleEvent.bind(dialog));
  		dialog.element.addEventListener('click', handleEvent.bind(dialog));
    };
  
    function cancelDialogEvents(dialog) {
  		//remove event listeners
  		dialog.element.removeEventListener('keydown', handleEvent.bind(dialog));
  		dialog.element.removeEventListener('click', handleEvent.bind(dialog));
    };
    
    function handleEvent(event) {
  		// handle events
  		switch(event.type) {
        case 'click': {
          initClick(this, event);
        }
        case 'keydown': {
          initKeyDown(this, event);
        }
  		}
    };
    
    function initKeyDown(dialog, event) {
  		if( event.keyCode && event.keyCode == 27 || event.key && event.key == 'Escape' ) {
  			//close dialog on esc
  			closeDialog(dialog);
  		} else if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  			//trap focus inside dialog
  			trapFocus(dialog, event);
  		}
  	};
  
  	function initClick(dialog, event) {
  		//close dialog when clicking on close button
  		if( !event.target.closest('.js-dialog__close') ) return;
  		event.preventDefault();
  		closeDialog(dialog);
  	};
  
  	function trapFocus(dialog, event) {
  		if( dialog.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of dialog
  			event.preventDefault();
  			dialog.lastFocusable.focus();
  		}
  		if( dialog.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of dialog
  			event.preventDefault();
  			dialog.firstFocusable.focus();
  		}
  	};
  
    function getFocusableElements(dialog) {
      //get all focusable elements inside the dialog
  		var allFocusable = dialog.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(dialog, allFocusable);
  		getLastVisible(dialog, allFocusable);
    };
  
    function getFirstVisible(dialog, elements) {
      //get first visible focusable element inside the dialog
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				dialog.firstFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function getLastVisible(dialog, elements) {
      //get last visible focusable element inside the dialog
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				dialog.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function emitDialogEvents(dialog, eventName) {
      var event = new CustomEvent(eventName, {detail: dialog.selectedTrigger});
  		dialog.element.dispatchEvent(event);
    };
  
    //initialize the Dialog objects
  	var dialogs = document.getElementsByClassName('js-dialog');
  	if( dialogs.length > 0 ) {
  		for( var i = 0; i < dialogs.length; i++) {
  			(function(i){new Dialog(dialogs[i]);})(i);
  		}
  	}
  }());
  // File#: _1_drawer
  // Usage: codyhouse.co/license
  (function() {
  	var Drawer = function(element) {
  		this.element = element;
  		this.content = document.getElementsByClassName('js-drawer__body')[0];
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.selectedTrigger = null;
  		this.isModal = Util.hasClass(this.element, 'js-drawer--modal');
  		this.showClass = "drawer--is-visible";
  		this.preventScrollEl = this.getPreventScrollEl();
  		this.initDrawer();
  	};
  
  	Drawer.prototype.getPreventScrollEl = function() {
  		var scrollEl = false;
  		var querySelector = this.element.getAttribute('data-drawer-prevent-scroll');
  		if(querySelector) scrollEl = document.querySelector(querySelector);
  		return scrollEl;
  	};
  
  	Drawer.prototype.initDrawer = function() {
  		var self = this;
  		//open drawer when clicking on trigger buttons
  		if ( this.triggers ) {
  			for(var i = 0; i < this.triggers.length; i++) {
  				this.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					if(Util.hasClass(self.element, self.showClass)) {
  						self.closeDrawer(event.target);
  						return;
  					}
  					self.selectedTrigger = event.target;
  					self.showDrawer();
  					self.initDrawerEvents();
  				});
  			}
  		}
  
  		// if drawer is already open -> we should initialize the drawer events
  		if(Util.hasClass(this.element, this.showClass)) this.initDrawerEvents();
  	};
  
  	Drawer.prototype.showDrawer = function() {
  		var self = this;
  		this.content.scrollTop = 0;
  		Util.addClass(this.element, this.showClass);
  		this.getFocusableElements();
  		Util.moveFocus(this.element);
  		// wait for the end of transitions before moving focus
  		this.element.addEventListener("transitionend", function cb(event) {
  			Util.moveFocus(self.element);
  			self.element.removeEventListener("transitionend", cb);
  		});
  		this.emitDrawerEvents('drawerIsOpen', this.selectedTrigger);
  		// change the overflow of the preventScrollEl
  		if(this.preventScrollEl) this.preventScrollEl.style.overflow = 'hidden';
  	};
  
  	Drawer.prototype.closeDrawer = function(target) {
  		Util.removeClass(this.element, this.showClass);
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		if(this.selectedTrigger) this.selectedTrigger.focus();
  		//remove listeners
  		this.cancelDrawerEvents();
  		this.emitDrawerEvents('drawerIsClose', target);
  		// change the overflow of the preventScrollEl
  		if(this.preventScrollEl) this.preventScrollEl.style.overflow = '';
  	};
  
  	Drawer.prototype.initDrawerEvents = function() {
  		//add event listeners
  		this.element.addEventListener('keydown', this);
  		this.element.addEventListener('click', this);
  	};
  
  	Drawer.prototype.cancelDrawerEvents = function() {
  		//remove event listeners
  		this.element.removeEventListener('keydown', this);
  		this.element.removeEventListener('click', this);
  	};
  
  	Drawer.prototype.handleEvent = function (event) {
  		switch(event.type) {
  			case 'click': {
  				this.initClick(event);
  			}
  			case 'keydown': {
  				this.initKeyDown(event);
  			}
  		}
  	};
  
  	Drawer.prototype.initKeyDown = function(event) {
  		if( event.keyCode && event.keyCode == 27 || event.key && event.key == 'Escape' ) {
  			//close drawer window on esc
  			this.closeDrawer(false);
  		} else if( this.isModal && (event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' )) {
  			//trap focus inside drawer
  			this.trapFocus(event);
  		}
  	};
  
  	Drawer.prototype.initClick = function(event) {
  		//close drawer when clicking on close button or drawer bg layer 
  		if( !event.target.closest('.js-drawer__close') && !Util.hasClass(event.target, 'js-drawer') ) return;
  		event.preventDefault();
  		this.closeDrawer(event.target);
  	};
  
  	Drawer.prototype.trapFocus = function(event) {
  		if( this.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of drawer
  			event.preventDefault();
  			this.lastFocusable.focus();
  		}
  		if( this.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of drawer
  			event.preventDefault();
  			this.firstFocusable.focus();
  		}
  	}
  
  	Drawer.prototype.getFocusableElements = function() {
  		//get all focusable elements inside the drawer
  		var allFocusable = this.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		this.getFirstVisible(allFocusable);
  		this.getLastVisible(allFocusable);
  	};
  
  	Drawer.prototype.getFirstVisible = function(elements) {
  		//get first visible focusable element inside the drawer
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				this.firstFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	Drawer.prototype.getLastVisible = function(elements) {
  		//get last visible focusable element inside the drawer
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				this.lastFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	Drawer.prototype.emitDrawerEvents = function(eventName, target) {
  		var event = new CustomEvent(eventName, {detail: target});
  		this.element.dispatchEvent(event);
  	};
  
  	window.Drawer = Drawer;
  
  	//initialize the Drawer objects
  	var drawer = document.getElementsByClassName('js-drawer');
  	if( drawer.length > 0 ) {
  		for( var i = 0; i < drawer.length; i++) {
  			(function(i){new Drawer(drawer[i]);})(i);
  		}
  	}
  }());
  // File#: _1_emoji-feedback
  // Usage: codyhouse.co/license
  (function() {
    function initEmojiRate(element) {
      var commentSection = element.getElementsByClassName('js-emoji-rate__comment');
      if(commentSection.length == 0) return;
      element.addEventListener('change', function() {
        // show comment input if user selects one of the radio btns
        showComment(commentSection[0]);
      });
    };
  
    function showComment(comment) {
      if(!Util.hasClass(comment, 'is-hidden')) return;
      // reveal comment section
      Util.removeClass(comment, 'is-hidden');
      var initHeight = 0,
  			finalHeight = comment.offsetHeight;
      if(window.requestAnimationFrame && !reducedMotion) {
        Util.setHeight(initHeight, finalHeight, comment, 200, function(){
          // move focus to textarea
          var textArea = comment.querySelector('textarea');
          if(textArea) textArea.focus();
          // remove inline style
          comment.style.height = '';
        }, 'easeInOutQuad');
      }
    };
  
    var emojiRate = document.getElementsByClassName('js-emoji-rate'),
      reducedMotion = Util.osHasReducedMotion();
    if( emojiRate.length > 0 ) {
  		for( var i = 0; i < emojiRate.length; i++) {
  			(function(i){initEmojiRate(emojiRate[i]);})(i);
  		}
  	}
  }());
  // File#: _1_expandable-search
  // Usage: codyhouse.co/license
  (function() {
  	var expandableSearch = document.getElementsByClassName('js-expandable-search');
  	if(expandableSearch.length > 0) {
  		for( var i = 0; i < expandableSearch.length; i++) {
  			(function(i){ // if user types in search input, keep the input expanded when focus is lost
  				expandableSearch[i].getElementsByClassName('js-expandable-search__input')[0].addEventListener('input', function(event){
  					Util.toggleClass(event.target, 'expandable-search__input--has-content', event.target.value.length > 0);
  				});
  			})(i);
  		}
  	}
  }());
  // File#: _1_expandable-side-navigation
  // Usage: codyhouse.co/license
  (function() {
    var Exsidenav = function(element) {
  		this.element = element;
      this.controls = this.element.getElementsByClassName('js-exsidenav__control');
      this.index = 0;
  		initExsidenav(this);
  	};
  
    function initExsidenav(element) {
      // set aria attributes
      initAria(element);
      // detect click on control buttons
      element.element.addEventListener('click', function(event){
        var control = event.target.closest('.js-exsidenav__control');
        if(control) toggleNav(control);
      });
    };
  
    function initAria(element) {
      // set aria attributes -> aria-controls and aria-expanded
      var randomNum = getRandomInt(0, 1000);
      for(var i = 0; i < element.controls.length; i++) {
        var newId = 'exsidenav-'+randomNum+'-'+element.index,
          id = element.controls[i].nextElementSibling.getAttribute('id');
        if(!id) {
          id = newId;
          element.controls[i].nextElementSibling.setAttribute('id', newId);
        }
        element.index = element.index + 1;
        element.controls[i].setAttribute('aria-controls', id);
        if(!element.controls[i].getAttribute('aria-expanded')) element.controls[i].setAttribute('aria-expanded', 'false');
      }
    };
  
    function toggleNav(control) {
      // open/close sub list
      var bool = (control.getAttribute('aria-expanded') === 'true'),
        ariaValue = bool ? 'false' : 'true';
      control.setAttribute('aria-expanded', ariaValue);
    };
  
    function getRandomInt(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min) + min); 
    };
  
    window.Exsidenav = Exsidenav;
  	
  	//initialize the Exsidenav objects
  	var exsidenav = document.getElementsByClassName('js-exsidenav');
  	if( exsidenav.length > 0 ) {
  		for( var i = 0; i < exsidenav.length; i++) {
  			(function(i){new Exsidenav(exsidenav[i]);})(i);
  		}
  	}
  }());
  // File#: _1_expandable-table
  // Usage: codyhouse.co/license
  (function() {
    var ExTable = function(element) {
      this.element = element;
      this.rows = this.element.getElementsByClassName('js-ex-table__body')[0].getElementsByTagName('tr');
      this.layout = '';
      getTableLayout(this);
      initTable(this);
    };
  
    function initTable(table) {
      // init aria-expanded attributes for 'More' buttons
      var moreButtons = table.element.getElementsByClassName('js-ex-table__btn');
      for(var i = 0; i < moreButtons.length; i++) {
        var rowExpanded = moreButtons[i].closest('.ex-table__row--show-more-content') ? true : false;
        moreButtons[i].setAttribute('aria-expanded', rowExpanded);
      }
      
      // custom event emitted when window is resized
      table.element.addEventListener('update-table', function(event){
        checkTableLayout(table);
        resetTableStyle(table);
      });
  
      // detect click on more Button - toggle additional table content
      table.element.addEventListener('click', function(event){
        var button = event.target.closest('.js-ex-table__btn');
        if(!button) return;
        var tableRow = button.parentNode.parentNode,
          showMore = !Util.hasClass(tableRow, 'ex-table__row--show-more-content');
        Util.toggleClass(tableRow, 'ex-table__row--show-more-content', showMore);
        button.setAttribute('aria-expanded', showMore);
        if(!showMore) resetRowStyle(table, tableRow, showMore);
        resetTableStyle(table);
      });
    };
  
    function getTableLayout(table) {
      table.layout = getComputedStyle(table.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
    };
  
    function checkTableLayout(table) { // check table layout
      getTableLayout(table);
      Util.toggleClass(table.element, tableExpandedLayoutClass, table.layout != 'collapsed');
      Util.addClass(table.element, 'ex-table--loaded');
    };
  
    function resetTableStyle(table) { // update table style according to layout
      for(var i = 0; i < table.rows.length; i++) {
        if( Util.hasClass(table.rows[i], 'ex-table__row--show-more-content')) {
          resetRowStyle(table, table.rows[i], true);
        }
      }
    };
  
    function resetRowStyle(table, row, showBool) {
      var content = row.getElementsByClassName('js-ex-table__more-content');
      if(content.length== 0 ) return;
      if(table.layout == 'expanded') {
        resetExpandedRowStyle(table, row, content[0], showBool);
      } else {
        resetCompressedRowStyle(row, content[0]);
      }
    };
  
    function resetExpandedRowStyle(table, row, content, showBool) {
      // row style applied when table layout is expanded
      if(showBool) {
        var offsetHeight = content.offsetHeight,
          cells = row.children;
        for(var i = 0; i < cells.length; i++) {
          cells[i].setAttribute('style', 'border-bottom-width:'+offsetHeight+'px;');
        }
        content.setAttribute('style', 'top: '+parseFloat(row.offsetHeight + row.offsetTop - offsetHeight)+'px;');
      } else {
        resetCompressedRowStyle(row, content);
      }
    };
  
    function resetCompressedRowStyle(row, content) {
      // row style applied when table layout is compressed
      content.removeAttribute('style');
      var cells = row.children;
      for(var i = 0; i < cells.length; i++) {
        cells[i].removeAttribute('style');
      }
    };
  
    var tables = document.getElementsByClassName('js-ex-table'),
      tableExpandedLayoutClass = 'ex-table--expanded';
    if( tables.length > 0 ) {
      var j = 0,
        arrayTables = [];
      for( var i = 0; i < tables.length; i++) {
        var beforeContent = getComputedStyle(tables[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){ arrayTables.push(new ExTable(tables[i]));})(i);
          j = j + 1;
        } else {
          Util.addClass(tables[i], 'ex-table--loaded');
        }
      }
      
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-table');
        window.addEventListener('resize', function(event){ // update table layout on resize
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < arrayTables.length; i++) {
            (function(i){arrayTables[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  
        (window.requestAnimationFrame) // init tables
          ? window.requestAnimationFrame(doneResizing)
          : doneResizing();
      }
    }
  }());
  // File#: _1_file-upload
  // Usage: codyhouse.co/license
  (function() {
  	var InputFile = function(element) {
  		this.element = element;
  		this.input = this.element.getElementsByClassName('file-upload__input')[0];
  		this.label = this.element.getElementsByClassName('file-upload__label')[0];
  		this.multipleUpload = this.input.hasAttribute('multiple'); // allow for multiple files selection
  		
  		// this is the label text element -> when user selects a file, it will be changed from the default value to the name of the file 
  		this.labelText = this.element.getElementsByClassName('file-upload__text')[0];
  		this.initialLabel = this.labelText.textContent;
  
  		initInputFileEvents(this);
  	}; 
  
  	function initInputFileEvents(inputFile) {
  		// make label focusable
  		inputFile.label.setAttribute('tabindex', '0');
  		inputFile.input.setAttribute('tabindex', '-1');
  
  		// move focus from input to label -> this is triggered when a file is selected or the file picker modal is closed
  		inputFile.input.addEventListener('focusin', function(event){ 
  			inputFile.label.focus();
  		});
  
  		// press 'Enter' key on label element -> trigger file selection
  		inputFile.label.addEventListener('keydown', function(event) {
  			if( event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {inputFile.input.click();}
  		});
  
  		// file has been selected -> update label text
  		inputFile.input.addEventListener('change', function(event){ 
  			updateInputLabelText(inputFile);
  		});
  	};
  
  	function updateInputLabelText(inputFile) {
  		var label = '';
  		if(inputFile.input.files && inputFile.input.files.length < 1) { 
  			label = inputFile.initialLabel; // no selection -> revert to initial label
  		} else if(inputFile.multipleUpload && inputFile.input.files && inputFile.input.files.length > 1) {
  			label = inputFile.input.files.length+ ' files'; // multiple selection -> show number of files
  		} else {
  			label = inputFile.input.value.split('\\').pop(); // single file selection -> show name of the file
  		}
  		inputFile.labelText.textContent = label;
  	};
  
    //initialize the InputFile objects
  	var inputFiles = document.getElementsByClassName('file-upload');
  	if( inputFiles.length > 0 ) {
  		for( var i = 0; i < inputFiles.length; i++) {
  			(function(i){new InputFile(inputFiles[i]);})(i);
  		}
  	}
  }());
  // File#: _1_filter-navigation
  // Usage: codyhouse.co/license
  (function() {
    var FilterNav = function(element) {
      this.element = element;
      this.wrapper = this.element.getElementsByClassName('js-filter-nav__wrapper')[0];
      this.nav = this.element.getElementsByClassName('js-filter-nav__nav')[0];
      this.list = this.nav.getElementsByClassName('js-filter-nav__list')[0];
      this.control = this.element.getElementsByClassName('js-filter-nav__control')[0];
      this.modalClose = this.element.getElementsByClassName('js-filter-nav__close-btn')[0];
      this.placeholder = this.element.getElementsByClassName('js-filter-nav__placeholder')[0];
      this.marker = this.element.getElementsByClassName('js-filter-nav__marker');
      this.layout = 'expanded';
      initFilterNav(this);
    };
  
    function initFilterNav(element) {
      checkLayout(element); // init layout
      if(element.layout == 'expanded') placeMarker(element);
      element.element.addEventListener('update-layout', function(event){ // on resize - modify layout
        checkLayout(element);
      });
  
      // update selected item
      element.wrapper.addEventListener('click', function(event){
        var newItem = event.target.closest('.js-filter-nav__btn');
        if(newItem) {
          updateCurrentItem(element, newItem);
          return;
        }
        // close modal list - mobile version only
        if(Util.hasClass(event.target, 'js-filter-nav__wrapper') || event.target.closest('.js-filter-nav__close-btn')) toggleModalList(element, false);
      });
  
      // open modal list - mobile version only
      element.control.addEventListener('click', function(event){
        toggleModalList(element, true);
      });
      
      // listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(element.control.getAttribute('aria-expanded') == 'true' && isVisible(element.control)) {
  					toggleModalList(element, false);
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(element.control.getAttribute('aria-expanded') == 'true' && isVisible(element.control) && !document.activeElement.closest('.js-filter-nav__wrapper')) toggleModalList(element, false);
  			}
  		});
    };
  
    function updateCurrentItem(element, btn) {
      if(btn.getAttribute('aria-current') == 'true') {
        toggleModalList(element, false);
        return;
      }
      var activeBtn = element.wrapper.querySelector('[aria-current]');
      if(activeBtn) activeBtn.removeAttribute('aria-current');
      btn.setAttribute('aria-current', 'true');
      // update trigger label on selection (visible on mobile only)
      element.placeholder.textContent = btn.textContent;
      toggleModalList(element, false);
      if(element.layout == 'expanded') placeMarker(element);
    };
  
    function toggleModalList(element, bool) {
      element.control.setAttribute('aria-expanded', bool);
      Util.toggleClass(element.wrapper, 'filter-nav__wrapper--is-visible', bool);
      if(bool) {
        element.nav.querySelectorAll('[href], button:not([disabled])')[0].focus();
      } else if(isVisible(element.control)) {
        element.control.focus();
      }
    };
  
    function isVisible(element) {
  		return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  	};
  
    function checkLayout(element) {
      if(element.layout == 'expanded' && switchToCollapsed(element)) { // check if there's enough space 
        element.layout = 'collapsed';
        Util.removeClass(element.element, 'filter-nav--expanded');
        Util.addClass(element.element, 'filter-nav--collapsed');
        Util.removeClass(element.modalClose, 'is-hidden');
        Util.removeClass(element.control, 'is-hidden');
      } else if(element.layout == 'collapsed' && switchToExpanded(element)) {
        element.layout = 'expanded';
        Util.addClass(element.element, 'filter-nav--expanded');
        Util.removeClass(element.element, 'filter-nav--collapsed');
        Util.addClass(element.modalClose, 'is-hidden');
        Util.addClass(element.control, 'is-hidden');
      }
      // place background element
      if(element.layout == 'expanded') placeMarker(element);
    };
  
    function switchToCollapsed(element) {
      return element.nav.scrollWidth > element.nav.offsetWidth;
    };
  
    function switchToExpanded(element) {
      element.element.style.visibility = 'hidden';
      Util.addClass(element.element, 'filter-nav--expanded');
      Util.removeClass(element.element, 'filter-nav--collapsed');
      var switchLayout = element.nav.scrollWidth <= element.nav.offsetWidth;
      Util.removeClass(element.element, 'filter-nav--expanded');
      Util.addClass(element.element, 'filter-nav--collapsed');
      element.element.style.visibility = 'visible';
      return switchLayout;
    };
  
    function placeMarker(element) {
      var activeElement = element.wrapper.querySelector('.js-filter-nav__btn[aria-current="true"]');
      if(element.marker.length == 0 || !activeElement ) return;
      element.marker[0].style.width = activeElement.offsetWidth+'px';
      element.marker[0].style.transform = 'translateX('+(activeElement.getBoundingClientRect().left - element.list.getBoundingClientRect().left)+'px)';
    };
  
    var filterNav = document.getElementsByClassName('js-filter-nav');
    if(filterNav.length > 0) {
      var filterNavArray = [];
      for(var i = 0; i < filterNav.length; i++) {
        filterNavArray.push(new FilterNav(filterNav[i]));
      }
  
      var resizingId = false,
        customEvent = new CustomEvent('update-layout');
  
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 100);
      });
  
      // wait for font to be loaded
      if(document.fonts) {
        document.fonts.onloadingdone = function (fontFaceSetEvent) {
          doneResizing();
        };
      }
  
      function doneResizing() {
        for( var i = 0; i < filterNavArray.length; i++) {
          (function(i){filterNavArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
    }
  }());
  // File#: _1_filter
  // Usage: codyhouse.co/license
  
  (function() {
    var Filter = function(opts) {
      this.options = Util.extend(Filter.defaults , opts); // used to store custom filter/sort functions
      this.element = this.options.element;
      this.elementId = this.element.getAttribute('id');
      this.items = this.element.querySelectorAll('.js-filter__item');
      this.controllers = document.querySelectorAll('[aria-controls="'+this.elementId+'"]'); // controllers wrappers
      this.fallbackMessage = document.querySelector('[data-fallback-gallery-id="'+this.elementId+'"]');
      this.filterString = []; // combination of different filter values
      this.sortingString = '';  // sort value - will include order and type of argument (e.g., number or string)
      // store info about sorted/filtered items
      this.filterList = []; // list of boolean for each this.item -> true if still visible , otherwise false
      this.sortingList = []; // list of new ordered this.item -> each element is [item, originalIndex]
      
      // store grid info for animation
      this.itemsGrid = []; // grid coordinates
      this.itemsInitPosition = []; // used to store coordinates of this.items before animation
      this.itemsIterPosition = []; // used to store coordinates of this.items before animation - intermediate state
      this.itemsFinalPosition = []; // used to store coordinates of this.items after filtering
      
      // animation off
      this.animateOff = this.element.getAttribute('data-filter-animation') == 'off';
      // used to update this.itemsGrid on resize
      this.resizingId = false;
      // default acceleration style - improve animation
      this.accelerateStyle = 'will-change: transform, opacity; transform: translateZ(0); backface-visibility: hidden;';
  
      // handle multiple changes
      this.animating = false;
      this.reanimate = false;
  
      initFilter(this);
    };
  
    function initFilter(filter) {
      resetFilterSortArray(filter, true, true); // init array filter.filterList/filter.sortingList
      createGridInfo(filter); // store grid coordinates in filter.itemsGrid
      initItemsOrder(filter); // add data-orders so that we can reset the sorting
  
      // events handling - filter update
      for(var i = 0; i < filter.controllers.length; i++) {
        filter.filterString[i] = ''; // reset filtering
  
        // get proper filter/sorting string based on selected controllers
        (function(i){
          filter.controllers[i].addEventListener('change', function(event) {  
            if(event.target.tagName.toLowerCase() == 'select') { // select elements
              (!event.target.getAttribute('data-filter'))
                ? setSortingString(filter, event.target.value, event.target.options[event.target.selectedIndex])
                : setFilterString(filter, i, 'select');
            } else if(event.target.tagName.toLowerCase() == 'input' && (event.target.getAttribute('type') == 'radio' || event.target.getAttribute('type') == 'checkbox') ) { // input (radio/checkboxed) elements
              (!event.target.getAttribute('data-filter'))
                ? setSortingString(filter, event.target.getAttribute('data-sort'), event.target)
                : setFilterString(filter, i, 'input');
            } else {
              // generic inout element
              (!filter.controllers[i].getAttribute('data-filter'))
                ? setSortingString(filter, filter.controllers[i].getAttribute('data-sort'), filter.controllers[i])
                : setFilterString(filter, i, 'custom');
            }
  
            updateFilterArray(filter);
          });
  
          filter.controllers[i].addEventListener('click', function(event) { // retunr if target is select/input elements
            var filterEl = event.target.closest('[data-filter]');
            var sortEl = event.target.closest('[data-sort]');
            if(!filterEl && !sortEl) return;
            if(filterEl && ( filterEl.tagName.toLowerCase() == 'input' || filterEl.tagName.toLowerCase() == 'select')) return;
            if(sortEl && (sortEl.tagName.toLowerCase() == 'input' || sortEl.tagName.toLowerCase() == 'select')) return;
            if(sortEl && Util.hasClass(sortEl, 'js-filter__custom-control')) return;
            if(filterEl && Util.hasClass(filterEl, 'js-filter__custom-control')) return;
            // this will be executed only for a list of buttons -> no inputs
            event.preventDefault();
            resetControllersList(filter, i, filterEl, sortEl);
            sortEl 
              ? setSortingString(filter, sortEl.getAttribute('data-sort'), sortEl)
              : setFilterString(filter, i, 'button');
            updateFilterArray(filter);
          });
  
          // target search inputs -> update them on 'input'
          filter.controllers[i].addEventListener('input', function(event) {
            if(event.target.tagName.toLowerCase() == 'input' && (event.target.getAttribute('type') == 'search' || event.target.getAttribute('type') == 'text') ) {
              setFilterString(filter, i, 'custom');
              updateFilterArray(filter);
            }
          });
        })(i);
      }
  
      // handle resize - update grid coordinates in filter.itemsGrid
      window.addEventListener('resize', function() {
        clearTimeout(filter.resizingId);
        filter.resizingId = setTimeout(function(){createGridInfo(filter)}, 300);
      });
  
      // check if there are filters/sorting values already set
      checkInitialFiltering(filter);
  
      // reset filtering results if filter selection was changed by an external control (e.g., form reset) 
      filter.element.addEventListener('update-filter-results', function(event){
        // reset filters first
        for(var i = 0; i < filter.controllers.length; i++) filter.filterString[i] = '';
        filter.sortingString = '';
        checkInitialFiltering(filter);
      });
    };
  
    function checkInitialFiltering(filter) {
      for(var i = 0; i < filter.controllers.length; i++) { // check if there's a selected option
        // buttons list
        var selectedButton = filter.controllers[i].getElementsByClassName('js-filter-selected');
        if(selectedButton.length > 0) {
          var sort = selectedButton[0].getAttribute('data-sort');
          sort
            ? setSortingString(filter, selectedButton[0].getAttribute('data-sort'), selectedButton[0])
            : setFilterString(filter, i, 'button');
          continue;
        }
  
        // input list
        var selectedInput = filter.controllers[i].querySelectorAll('input:checked');
        if(selectedInput.length > 0) {
          var sort = selectedInput[0].getAttribute('data-sort');
          sort
            ? setSortingString(filter, sort, selectedInput[0])
            : setFilterString(filter, i, 'input');
          continue;
        }
        // select item
        if(filter.controllers[i].tagName.toLowerCase() == 'select') {
          var sort = filter.controllers[i].getAttribute('data-sort');
          sort
            ? setSortingString(filter, filter.controllers[i].value, filter.controllers[i].options[filter.controllers[i].selectedIndex])
            : setFilterString(filter, i, 'select');
           continue;
        }
        // check if there's a generic custom input
        var radioInput = filter.controllers[i].querySelector('input[type="radio"]'),
          checkboxInput = filter.controllers[i].querySelector('input[type="checkbox"]');
        if(!radioInput && !checkboxInput) {
          var sort = filter.controllers[i].getAttribute('data-sort');
          var filterString = filter.controllers[i].getAttribute('data-filter');
          if(sort) setSortingString(filter, sort, filter.controllers[i]);
          else if(filterString) setFilterString(filter, i, 'custom');
        }
      }
  
      updateFilterArray(filter);
    };
  
    function setSortingString(filter, value, item) { 
      // get sorting string value-> sortName:order:type
      var order = item.getAttribute('data-sort-order') ? 'desc' : 'asc';
      var type = item.getAttribute('data-sort-number') ? 'number' : 'string';
      filter.sortingString = value+':'+order+':'+type;
    };
  
    function setFilterString(filter, index, type) { 
      // get filtering array -> [filter1:filter2, filter3, filter4:filter5]
      if(type == 'input') {
        var checkedInputs = filter.controllers[index].querySelectorAll('input:checked');
        filter.filterString[index] = '';
        for(var i = 0; i < checkedInputs.length; i++) {
          filter.filterString[index] = filter.filterString[index] + checkedInputs[i].getAttribute('data-filter') + ':';
        }
      } else if(type == 'select') {
        if(filter.controllers[index].multiple) { // select with multiple options
          filter.filterString[index] = getMultipleSelectValues(filter.controllers[index]);
        } else { // select with single option
          filter.filterString[index] = filter.controllers[index].value;
        }
      } else if(type == 'button') {
        var selectedButtons = filter.controllers[index].querySelectorAll('.js-filter-selected');
        filter.filterString[index] = '';
        for(var i = 0; i < selectedButtons.length; i++) {
          filter.filterString[index] = filter.filterString[index] + selectedButtons[i].getAttribute('data-filter') + ':';
        }
      } else if(type == 'custom') {
        filter.filterString[index] = filter.controllers[index].getAttribute('data-filter');
      }
    };
  
    function resetControllersList(filter, index, target1, target2) {
      // for a <button>s list -> toggle js-filter-selected + custom classes
      var multi = filter.controllers[index].getAttribute('data-filter-checkbox'),
        customClass = filter.controllers[index].getAttribute('data-selected-class');
      
      customClass = (customClass) ? 'js-filter-selected '+ customClass : 'js-filter-selected';
      if(multi == 'true') { // multiple options can be on
        (target1) 
          ? Util.toggleClass(target1, customClass, !Util.hasClass(target1, 'js-filter-selected'))
          : Util.toggleClass(target2, customClass, !Util.hasClass(target2, 'js-filter-selected'));
      } else { // only one element at the time
        // remove the class from all siblings
        var selectedOption = filter.controllers[index].querySelector('.js-filter-selected');
        if(selectedOption) Util.removeClass(selectedOption, customClass);
        (target1) 
          ? Util.addClass(target1, customClass)
          : Util.addClass(target2, customClass);
      }
    };
  
    function updateFilterArray(filter) { // sort/filter strings have been updated -> so you can update the gallery
      if(filter.animating) {
        filter.reanimate = true;
        return;
      }
      filter.animating = true;
      filter.reanimate = false;
      createGridInfo(filter); // get new grid coordinates
      sortingGallery(filter); // update sorting list 
      filteringGallery(filter); // update filter list
      resetFallbackMessage(filter, true); // toggle fallback message
      if(reducedMotion || filter.animateOff) {
        resetItems(filter);
      } else {
        updateItemsAttributes(filter);
      }
    };
  
    function sortingGallery(filter) {
      // use sorting string to reorder gallery
      var sortOptions = filter.sortingString.split(':');
      if(sortOptions[0] == '' || sortOptions[0] == '*') {
        // no sorting needed
        restoreSortOrder(filter);
      } else { // need to sort
        if(filter.options[sortOptions[0]]) { // custom sort function -> user takes care of it
          filter.sortingList = filter.options[sortOptions[0]](filter.sortingList);
        } else {
          filter.sortingList.sort(function(left, right) {
            var leftVal = left[0].getAttribute('data-sort-'+sortOptions[0]),
            rightVal = right[0].getAttribute('data-sort-'+sortOptions[0]);
            if(sortOptions[2] == 'number') {
              leftVal = parseFloat(leftVal);
              rightVal = parseFloat(rightVal);
            }
            if(sortOptions[1] == 'desc') return leftVal <= rightVal ? 1 : -1;
            else return leftVal >= rightVal ? 1 : -1;
          });
        }
      }
    };
  
    function filteringGallery(filter) {
      // use filtering string to reorder gallery
      resetFilterSortArray(filter, true, false);
      // we can have multiple filters
      for(var i = 0; i < filter.filterString.length; i++) {
        //check if multiple filters inside the same controller
        if(filter.filterString[i] != '' && filter.filterString[i] != '*' && filter.filterString[i] != ' ') {
          singleFilterGallery(filter, filter.filterString[i].split(':'));
        }
      }
    };
  
    function singleFilterGallery(filter, subfilter) {
      if(!subfilter || subfilter == '' || subfilter == '*') return;
      // check if we have custom options
      var customFilterArray = [];
      for(var j = 0; j < subfilter.length; j++) {
        if(filter.options[subfilter[j]]) { // custom function
          customFilterArray[subfilter[j]] = filter.options[subfilter[j]](filter.items);
        }
      }
  
      for(var i = 0; i < filter.items.length; i++) {
        var filterValues = filter.items[i].getAttribute('data-filter').split(' ');
        var present = false;
        for(var j = 0; j < subfilter.length; j++) {
          if(filter.options[subfilter[j]] && customFilterArray[subfilter[j]][i]) { // custom function
            present = true;
            break;
          } else if(subfilter[j] == '*' || filterValues.indexOf(subfilter[j]) > -1) {
            present = true;
            break;
          }
        }
        filter.filterList[i] = !present ? false : filter.filterList[i];
      }
    };
  
    function updateItemsAttributes(filter) { // set items before triggering the update animation
      // get offset of all elements before animation
      storeOffset(filter, filter.itemsInitPosition);
      // set height of container
      filter.element.setAttribute('style', 'height: '+parseFloat(filter.element.offsetHeight)+'px; width: '+parseFloat(filter.element.offsetWidth)+'px;');
  
      for(var i = 0; i < filter.items.length; i++) { // remove is-hidden class from items now visible and scale to zero
        if( Util.hasClass(filter.items[i], 'is-hidden') && filter.filterList[i]) {
          filter.items[i].setAttribute('data-scale', 'on');
          filter.items[i].setAttribute('style', filter.accelerateStyle+'transform: scale(0.5); opacity: 0;')
          Util.removeClass(filter.items[i], 'is-hidden');
        }
      }
      // get new elements offset
      storeOffset(filter, filter.itemsIterPosition);
      // translate items so that they are in the right initial position
      for(var i = 0; i < filter.items.length; i++) {
        if( filter.items[i].getAttribute('data-scale') != 'on') {
          filter.items[i].setAttribute('style', filter.accelerateStyle+'transform: translateX('+parseInt(filter.itemsInitPosition[i][0] - filter.itemsIterPosition[i][0])+'px) translateY('+parseInt(filter.itemsInitPosition[i][1] - filter.itemsIterPosition[i][1])+'px);');
        }
      }
  
      animateItems(filter)
    };
  
    function animateItems(filter) {
      var transitionValue = 'transform '+filter.options.duration+'ms cubic-bezier(0.455, 0.03, 0.515, 0.955), opacity '+filter.options.duration+'ms';
  
      // get new index of items in the list
      var j = 0;
      for(var i = 0; i < filter.sortingList.length; i++) {
        var item = filter.items[filter.sortingList[i][1]];
          
        if(Util.hasClass(item, 'is-hidden') || !filter.filterList[filter.sortingList[i][1]]) {
          // item is hidden or was previously hidden -> final position equal to first one
          filter.itemsFinalPosition[filter.sortingList[i][1]] = filter.itemsIterPosition[filter.sortingList[i][1]];
          if(item.getAttribute('data-scale') == 'on') j = j + 1; 
        } else {
          filter.itemsFinalPosition[filter.sortingList[i][1]] = [filter.itemsGrid[j][0], filter.itemsGrid[j][1]]; // left/top
          j = j + 1; 
        }
      } 
  
      setTimeout(function(){
        for(var i = 0; i < filter.items.length; i++) {
          if(filter.filterList[i] && filter.items[i].getAttribute('data-scale') == 'on') { // scale up item
            filter.items[i].setAttribute('style', filter.accelerateStyle+'transition: '+transitionValue+'; transform: translateX('+parseInt(filter.itemsFinalPosition[i][0] - filter.itemsIterPosition[i][0])+'px) translateY('+parseInt(filter.itemsFinalPosition[i][1] - filter.itemsIterPosition[i][1])+'px) scale(1); opacity: 1;');
          } else if(filter.filterList[i]) { // translate item
            filter.items[i].setAttribute('style', filter.accelerateStyle+'transition: '+transitionValue+'; transform: translateX('+parseInt(filter.itemsFinalPosition[i][0] - filter.itemsIterPosition[i][0])+'px) translateY('+parseInt(filter.itemsFinalPosition[i][1] - filter.itemsIterPosition[i][1])+'px);');
          } else { // scale down item
            filter.items[i].setAttribute('style', filter.accelerateStyle+'transition: '+transitionValue+'; transform: scale(0.5); opacity: 0;');
          }
        };
      }, 50);  
      
      // wait for the end of transition of visible elements
      setTimeout(function(){
        resetItems(filter);
      }, (filter.options.duration + 100));
    };
  
    function resetItems(filter) {
      // animation was off or animation is over -> reset attributes
      for(var i = 0; i < filter.items.length; i++) {
        filter.items[i].removeAttribute('style');
        Util.toggleClass(filter.items[i], 'is-hidden', !filter.filterList[i]);
        filter.items[i].removeAttribute('data-scale');
      }
      
      for(var i = 0; i < filter.items.length; i++) {// reorder
        filter.element.appendChild(filter.items[filter.sortingList[i][1]]);
      }
  
      filter.items = [];
      filter.items = filter.element.querySelectorAll('.js-filter__item');
      resetFilterSortArray(filter, false, true);
      filter.element.removeAttribute('style');
      filter.animating = false;
      if(filter.reanimate) {
        updateFilterArray(filter);
      }
  
      resetFallbackMessage(filter, false); // toggle fallback message
  
      // emit custom event - end of filtering
      filter.element.dispatchEvent(new CustomEvent('filter-selection-updated'));
    };
  
    function resetFilterSortArray(filter, filtering, sorting) {
      for(var i = 0; i < filter.items.length; i++) {
        if(filtering) filter.filterList[i] = true;
        if(sorting) filter.sortingList[i] = [filter.items[i], i];
      }
    };
  
    function createGridInfo(filter) {
      var containerWidth = parseFloat(window.getComputedStyle(filter.element).getPropertyValue('width')),
        itemStyle, itemWidth, itemHeight, marginX, marginY, colNumber;
  
      // get offset first visible element
      for(var i = 0; i < filter.items.length; i++) {
        if( !Util.hasClass(filter.items[i], 'is-hidden') ) {
          itemStyle = window.getComputedStyle(filter.items[i]),
          itemWidth = parseFloat(itemStyle.getPropertyValue('width')),
          itemHeight = parseFloat(itemStyle.getPropertyValue('height')),
          marginX = parseFloat(itemStyle.getPropertyValue('margin-left')) + parseFloat(itemStyle.getPropertyValue('margin-right')),
          marginY = parseFloat(itemStyle.getPropertyValue('margin-bottom')) + parseFloat(itemStyle.getPropertyValue('margin-top'));
          if(marginX == 0 && marginY == 0) {
            // grid is set using the gap property and not margins
            var margins = resetMarginValues(filter);
            marginX = margins[0];
            marginY = margins[1];
          }
          var colNumber = parseInt((containerWidth + marginX)/(itemWidth+marginX));
          filter.itemsGrid[0] = [filter.items[i].offsetLeft, filter.items[i].offsetTop]; // left, top
          break;
        }
      }
  
      for(var i = 1; i < filter.items.length; i++) {
        var x = i < colNumber ? i : i % colNumber,
          y = i < colNumber ? 0 : Math.floor(i/colNumber);
        filter.itemsGrid[i] = [filter.itemsGrid[0][0] + x*(itemWidth+marginX), filter.itemsGrid[0][1] + y*(itemHeight+marginY)];
      }
    };
  
    function storeOffset(filter, array) {
      for(var i = 0; i < filter.items.length; i++) {
        array[i] = [filter.items[i].offsetLeft, filter.items[i].offsetTop];
      }
    };
  
    function initItemsOrder(filter) {
      for(var i = 0; i < filter.items.length; i++) {
        filter.items[i].setAttribute('data-init-sort-order', i);
      }
    };
  
    function restoreSortOrder(filter) {
      for(var i = 0; i < filter.items.length; i++) {
        filter.sortingList[parseInt(filter.items[i].getAttribute('data-init-sort-order'))] = [filter.items[i], i];
      }
    };
  
    function resetFallbackMessage(filter, bool) {
      if(!filter.fallbackMessage) return;
      var show = true;
      for(var i = 0; i < filter.filterList.length; i++) {
        if(filter.filterList[i]) {
          show = false;
          break;
        }
      };
      if(bool) { // reset visibility before animation is triggered
        if(!show) Util.addClass(filter.fallbackMessage, 'is-hidden');
        return;
      }
      Util.toggleClass(filter.fallbackMessage, 'is-hidden', !show);
    };
  
    function getMultipleSelectValues(multipleSelect) {
      // get selected options of a <select multiple> element
      var options = multipleSelect.options,
        value = '';
      for(var i = 0; i < options.length; i++) {
        if(options[i].selected) {
          if(value != '') value = value + ':';
          value = value + options[i].value;
        }
      }
      return value;
    };
  
    function resetMarginValues(filter) {
      var gapX = getComputedStyle(filter.element).getPropertyValue('--gap-x'),
        gapY = getComputedStyle(filter.element).getPropertyValue('--gap-y'),
        gap = getComputedStyle(filter.element).getPropertyValue('--gap'),
        gridGap = [0, 0];
      // if the gap property is used to create the grid (not margin left/right) -> get gap values rather than margins
      // check if the --gap/--gap-x/--gap-y
      var newDiv = document.createElement('div'),
        cssText = 'position: absolute; opacity: 0; width: 0px; height: 0px';
      if(gapX && gapY) {
        cssText = 'position: absolute; opacity: 0; width: '+gapX+'; height: '+gapY;
      } else if(gap) {
        cssText = 'position: absolute; opacity: 0; width: '+gap+'; height: '+gap;
      } else if(gapX) {
        cssText = 'position: absolute; opacity: 0; width: '+gapX+'; height: 0px';
      } else if(gapY) {
        cssText = 'position: absolute; opacity: 0; width: 0px; height: '+gapY;
      }
      newDiv.style.cssText = cssText;
      filter.element.appendChild(newDiv);
      var boundingRect = newDiv.getBoundingClientRect();
      gridGap = [boundingRect.width, boundingRect.height];
      filter.element.removeChild(newDiv);
      return gridGap;
    };
  
    Filter.defaults = {
      element : false,
      duration: 400
    };
  
    window.Filter = Filter;
  
    // init Filter object
    var filterGallery = document.getElementsByClassName('js-filter'),
      reducedMotion = Util.osHasReducedMotion();
    if( filterGallery.length > 0 ) {
      for( var i = 0; i < filterGallery.length; i++) {
        var duration = filterGallery[i].getAttribute('data-filter-duration');
        if(!duration) duration = Filter.defaults.duration;
        new Filter({element: filterGallery[i], duration: duration});
      }
    }
  }());
  // File#: _1_flash-message
  // Usage: codyhouse.co/license
  (function() {
  	var FlashMessage = function(element) {
  		this.element = element;
  		this.showClass = "flash-message--is-visible";
  		this.messageDuration = parseInt(this.element.getAttribute('data-duration')) || 3000;
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.temeoutId = null;
  		this.isVisible = false;
  		this.initFlashMessage();
  	};
  
  	FlashMessage.prototype.initFlashMessage = function() {
  		var self = this;
  		//open modal when clicking on trigger buttons
  		if ( self.triggers ) {
  			for(var i = 0; i < self.triggers.length; i++) {
  				self.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					self.showFlashMessage();
  				});
  			}
  		}
  		//listen to the event that triggers the opening of a flash message
  		self.element.addEventListener('showFlashMessage', function(){
  			self.showFlashMessage();
  		});
  	};
  
  	FlashMessage.prototype.showFlashMessage = function() {
  		var self = this;
  		Util.addClass(self.element, self.showClass);
  		self.isVisible = true;
  		//hide other flash messages
  		self.hideOtherFlashMessages();
  		if( self.messageDuration > 0 ) {
  			//hide the message after an interveal (this.messageDuration)
  			self.temeoutId = setTimeout(function(){
  				self.hideFlashMessage();
  			}, self.messageDuration);
  		}
  	};
  
  	FlashMessage.prototype.hideFlashMessage = function() {
  		Util.removeClass(this.element, this.showClass);
  		this.isVisible = false;
  		//reset timeout
  		clearTimeout(this.temeoutId);
  		this.temeoutId = null;
  	};
  
  	FlashMessage.prototype.hideOtherFlashMessages = function() {
  		var event = new CustomEvent('flashMessageShown', { detail: this.element });
  		window.dispatchEvent(event);
  	};
  
  	FlashMessage.prototype.checkFlashMessage = function(message) {
  		if( !this.isVisible ) return; 
  		if( this.element == message) return;
  		this.hideFlashMessage();
  	};
  
  	//initialize the FlashMessage objects
  	var flashMessages = document.getElementsByClassName('js-flash-message');
  	if( flashMessages.length > 0 ) {
  		var flashMessagesArray = [];
  		for( var i = 0; i < flashMessages.length; i++) {
  			(function(i){flashMessagesArray.push(new FlashMessage(flashMessages[i]));})(i);
  		}
  
  		//listen for a flash message to be shown -> close the others
  		window.addEventListener('flashMessageShown', function(event){
  			flashMessagesArray.forEach(function(element){
  				element.checkFlashMessage(event.detail);
  			});
  		});
  	}
  }());
  // File#: _1_floating-action-button
  // Usage: codyhouse.co/license
  (function() {
    var Fab = function(element) {
  		this.element = element;
  		this.fabButton = this.element.getElementsByClassName('js-fab__btn');
      this.fabPopover = this.element.getElementsByClassName('js-fab__popover');
      this.fabPopoverInner = this.element.getElementsByClassName('js-fab__popover-inner');
      this.visibleClass = 'fab--active';
      this.animating = false;
      // focusable elements
      this.firstFocusable = false;
  		this.lastFocusable = false;
      // offset variables
      this.offsetIn = 0;
      this.offsetOut = 0;
      this.targetIn = this.element.getAttribute('data-target-in') ? document.querySelector(this.element.getAttribute('data-target-in')) : false;
      this.targetOut = this.element.getAttribute('data-target-out') ? document.querySelector(this.element.getAttribute('data-target-out')) : false;
      if(this.fabButton.length < 1 || this.fabPopover.length < 1) return;
  		initFab(this);
  	};
  
    // public methods
    Fab.prototype.setVariables = function() {
  		setFabVariables(this);
  	};
  
    Fab.prototype.resetVisibility = function() {
  		resetFabVisibility(this);
  	};
  
    // private methods
    function initFab(element) {
      resetFabVisibility(element);
      setFabVariables(element);
      initFabEvents(element);
    };
  
    function setFabVariables(element) {
      // set CSS variables
      element.fabPopoverInner[0].style.height = '';
      var height = element.fabPopover[0].offsetHeight+'px';
  
      element.element.style.setProperty('--fab-popover-height', height);
      element.fabPopoverInner[0].style.height = height;
    };
  
    function initFabEvents(element) {
      if(document.fonts) {
        // wait for fonts to be loaded and set popover height
        document.fonts.ready.then(function() {
          setFabVariables(element);
        });
      }
  
      // toggle popover when clicking on fab button
      element.fabButton[0].addEventListener('click', function() {
        if(element.animating) return;
        element.animating = true;
        toggleFab(element);
      });
  
      // close popover when clicking on fab background
      element.element.addEventListener('click', function(event){
        if(!event.target.closest('.js-fab__btn') && !event.target.closest('.js-fab__popover-inner')) toggleFab(element);
      });
  
      // trap focus
      element.element.addEventListener('keydown', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
          //trap focus inside popover
          trapFocus(element, event);
        } else if(event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
          if(Util.hasClass(element.element, element.visibleClass)) toggleFab(element);
        }
      });
    };
  
    function toggleFab(element) {
      var isOpen = Util.hasClass(element.element, element.visibleClass);
  
      if(isOpen) {
        Util.removeClass(element.element, element.visibleClass);
        element.fabButton[0].removeAttribute('aria-expanded');
        element.fabButton[0].focus();
      } else {
        Util.addClass(element.element, element.visibleClass);
        element.fabButton[0].setAttribute('aria-expanded', 'true');
      }
  
      // wait for the end of the transition
      element.fabPopover[0].addEventListener('transitionend', function cb(){
        element.animating = false;
        element.fabPopover[0].removeEventListener('transitionend', cb);
        if(!isOpen) focusPopover(element);
      });
    };
  
    function focusPopover(element) {
      getFocusableElements(element);
      if(element.firstFocusable) {
  			element.firstFocusable.focus();
  		}
    };
  
    // trapping focus
    function getFocusableElements(element) {
      // get all focusable elements inside the popover
  		var allFocusable = element.fabPopover[0].querySelectorAll(focusableElString);
  		getFirstVisible(element, allFocusable);
  		getLastVisible(element, allFocusable);
    };
  
    function getFirstVisible(element, focusableElments) {
  		// get first visible focusable element inside the popover
  		for(var i = 0; i < focusableElments.length; i++) {
  			if( isVisible(focusableElments[i]) ) {
  				element.firstFocusable = focusableElments[i];
  				break;
  			}
  		}
  	};
  
    function getLastVisible(element, focusableElments) {
  		// get last visible focusable element inside the popover
  		for(var i = focusableElments.length - 1; i >= 0; i--) {
  			if( isVisible(focusableElments[i]) ) {
  				element.lastFocusable = focusableElments[i];
  				break;
  			}
  		}
    };
  
    function trapFocus(element, event) {
      if( element.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of popover
  			event.preventDefault();
  			element.lastFocusable.focus();
  		}
  		if( element.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of popover
  			event.preventDefault();
  			element.firstFocusable.focus();
  		}
    };
  
    function isVisible(element) {
  		// check if element is visible
  		return element.offsetWidth || element.offsetHeight || element.getClientRects().length;
  	};
  
    // offset functions 
    function resetFabVisibility(element) {
      getFabBtnOffsets(element); // get offset values - show/hide fab button 
      var scrollTop = document.documentElement.scrollTop,
        topTarget = false,
        bottomTarget = false;
      if(element.offsetIn <= scrollTop || element.offsetIn == 0) {
        topTarget = true;
      }
      if(element.offsetOut == 0 || scrollTop < element.offsetOut) {
        bottomTarget = true;
      }
      Util.toggleClass(element.element, 'fab--in', bottomTarget && topTarget);
  
      // if popover is visible -> close it
      if( (!bottomTarget || !topTarget) && Util.hasClass(element.element, element.visibleClass)) toggleFab(element);
    };
  
    function getFabBtnOffsets(element) { // get offset in and offset out values
      // update offsetIn
      element.offsetIn = 0;
      if(element.targetIn) {
        var boundingClientRect = element.targetIn.getBoundingClientRect();
        element.offsetIn = boundingClientRect.top + document.documentElement.scrollTop + boundingClientRect.height;
      }
      var dataOffsetIn = element.element.getAttribute('data-offset-in');
      if(dataOffsetIn) {
        element.offsetIn = element.offsetIn + parseInt(dataOffsetIn);
      }
      // update offsetOut
      element.offsetOut = 0;
      if(element.targetOut) {
        var boundingClientRect = element.targetOut.getBoundingClientRect();
        element.offsetOut = boundingClientRect.top + document.documentElement.scrollTop - window.innerHeight;
      }
      var dataOffsetOut = element.element.getAttribute('data-offset-out');
      if(dataOffsetOut) {
        element.offsetOut = element.offsetOut + parseInt(dataOffsetOut);
      }
    };
  
    //initialize the Fab objects
  	var fabs = document.getElementsByClassName('js-fab');
    // generic focusable elements string selector
  	var focusableElString = '[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary';
  	if( fabs.length > 0 ) {
  		var fabsArray = [];
  		for( var i = 0; i < fabs.length; i++) {
  			(function(i){fabsArray.push(new Fab(fabs[i]));})(i);
  		}
  
      // reset fab height on resize
      var resizingId = false;
  
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing);
      });
  
      window.addEventListener('scroll', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneScrolling);
      });
  
      function doneResizing() {
        fabsArray.forEach(function(element){
  				element.setVariables();
          element.resetVisibility();
  			});
      };
  
      function doneScrolling() {
        fabsArray.forEach(function(element){
  				element.resetVisibility();
  			});
      };
  	}
  }());
  // File#: _1_floating-label
  // Usage: codyhouse.co/license
  (function() {
  	var floatingLabels = document.getElementsByClassName('floating-label');
  	if( floatingLabels.length > 0 ) {
  		var placeholderSupported = checkPlaceholderSupport(); // check if browser supports :placeholder
  		for(var i = 0; i < floatingLabels.length; i++) {
  			(function(i){initFloatingLabel(floatingLabels[i])})(i);
  		}
  
  		function initFloatingLabel(element) {
  			if(!placeholderSupported) { // :placeholder is not supported -> show label right away
  				Util.addClass(element.getElementsByClassName('form-label')[0], 'form-label--floating');
  				return;
  			}
  			var input = element.getElementsByClassName('form-control')[0];
  			input.addEventListener('input', function(event){
  				resetFloatingLabel(element, input);
  			});
  		};
  
  		function resetFloatingLabel(element, input) { // show label if input is not empty
  			Util.toggleClass(element.getElementsByClassName('form-label')[0], 'form-label--floating', input.value.length > 0);
  		};
  
  		function checkPlaceholderSupport() {
  			var input = document.createElement('input');
      	return ('placeholder' in input);
  		};
  	}
  }());
  // File#: _1_form-validator
  // Usage: codyhouse.co/license
  (function() {
    var FormValidator = function(opts) {
      this.options = Util.extend(FormValidator.defaults , opts);
  		this.element = this.options.element;
      this.input = [];
      this.textarea = [];
      this.select = [];
      this.errorFields = [];
      this.errorFieldListeners = [];
  		initFormValidator(this);
  	};
  
    //public functions
    FormValidator.prototype.validate = function(cb) {
      validateForm(this);
      if(cb) cb(this.errorFields);
    };
  
    // private methods
    function initFormValidator(formValidator) {
      formValidator.input = formValidator.element.querySelectorAll('input');
      formValidator.textarea = formValidator.element.querySelectorAll('textarea');
      formValidator.select = formValidator.element.querySelectorAll('select');
    };
  
    function validateForm(formValidator) {
      // reset input with errors
      formValidator.errorFields = []; 
      // remove change/input events from fields with error
      resetEventListeners(formValidator);
      
      // loop through fields and push to errorFields if there are errors
      for(var i = 0; i < formValidator.input.length; i++) {
        validateField(formValidator, formValidator.input[i]);
      }
  
      for(var i = 0; i < formValidator.textarea.length; i++) {
        validateField(formValidator, formValidator.textarea[i]);
      }
  
      for(var i = 0; i < formValidator.select.length; i++) {
        validateField(formValidator, formValidator.select[i]);
      }
  
      // show errors if any was found
      for(var i = 0; i < formValidator.errorFields.length; i++) {
        showError(formValidator, formValidator.errorFields[i]);
      }
  
      // move focus to first field with error
      if(formValidator.errorFields.length > 0) formValidator.errorFields[0].focus();
    };
  
    function validateField(formValidator, field) {
      if(!field.checkValidity()) {
        formValidator.errorFields.push(field);
        return;
      }
      // check for custom functions
      var customValidate = field.getAttribute('data-validate');
      if(customValidate && formValidator.options.customValidate[customValidate]) {
        formValidator.options.customValidate[customValidate](field, function(result) {
          if(!result) formValidator.errorFields.push(field);
        });
      }
    };
  
    function showError(formValidator, field) {
      // add error classes
      toggleErrorClasses(formValidator, field, true);
  
      // add event listener
      var index = formValidator.errorFieldListeners.length;
      formValidator.errorFieldListeners[index] = function() {
        toggleErrorClasses(formValidator, field, false);
        field.removeEventListener('change', formValidator.errorFieldListeners[index]);
        field.removeEventListener('input', formValidator.errorFieldListeners[index]);
      };
      field.addEventListener('change', formValidator.errorFieldListeners[index]);
      field.addEventListener('input', formValidator.errorFieldListeners[index]);
    };
  
    function toggleErrorClasses(formValidator, field, bool) {
      bool ? Util.addClass(field, formValidator.options.inputErrorClass) : Util.removeClass(field, formValidator.options.inputErrorClass);
      if(formValidator.options.inputWrapperErrorClass) {
        var wrapper = field.closest('.js-form-validate__input-wrapper');
        if(wrapper) {
          bool ? Util.addClass(wrapper, formValidator.options.inputWrapperErrorClass) : Util.removeClass(wrapper, formValidator.options.inputWrapperErrorClass);
        }
      }
    };
  
    function resetEventListeners(formValidator) {
      for(var i = 0; i < formValidator.errorFields.length; i++) {
        toggleErrorClasses(formValidator, formValidator.errorFields[i], false);
        formValidator.errorFields[i].removeEventListener('change', formValidator.errorFieldListeners[i]);
        formValidator.errorFields[i].removeEventListener('input', formValidator.errorFieldListeners[i]);
      }
  
      formValidator.errorFields = [];
      formValidator.errorFieldListeners = [];
    };
    
    FormValidator.defaults = {
      element : '',
      inputErrorClass : 'form-control--error',
      inputWrapperErrorClass: 'form-validate__input-wrapper--error',
      customValidate: {}
    };
    window.FormValidator = FormValidator;
  }());
  // File#: _1_google-maps
  // Usage: codyhouse.co/license
  function initGoogleMap() {
  	var contactMap = document.getElementsByClassName('js-google-maps');
  	if(contactMap.length > 0) {
  		for(var i = 0; i < contactMap.length; i++) {
  			initContactMap(contactMap[i]);
  		}
  	}
  };
  
  function initContactMap(wrapper) {
  	var coordinate = wrapper.getAttribute('data-coordinates').split(',');
  	var map = new google.maps.Map(wrapper, {zoom: 10, center: {lat: Number(coordinate[0]), lng:  Number(coordinate[1])}});
  	var marker = new google.maps.Marker({position: {lat: Number(coordinate[0]), lng:  Number(coordinate[1])}, map: map});
  };
  // File#: _1_hiding-nav
  // Usage: codyhouse.co/license
  (function() {
    var hidingNav = document.getElementsByClassName('js-hide-nav');
    if(hidingNav.length > 0 && window.requestAnimationFrame) {
      var mainNav = Array.prototype.filter.call(hidingNav, function(element) {
        return Util.hasClass(element, 'js-hide-nav--main');
      }),
      subNav = Array.prototype.filter.call(hidingNav, function(element) {
        return Util.hasClass(element, 'js-hide-nav--sub');
      });
      
      var scrolling = false,
        previousTop = window.scrollY,
        currentTop = window.scrollY,
        scrollDelta = 10,
        scrollOffset = 150, // scrollY needs to be bigger than scrollOffset to hide navigation
        headerHeight = 0; 
  
      var navIsFixed = false; // check if main navigation is fixed
      if(mainNav.length > 0 && Util.hasClass(mainNav[0], 'hide-nav--fixed')) navIsFixed = true;
  
      // store button that triggers navigation on mobile
      var triggerMobile = getTriggerMobileMenu();
      var prevElement = createPrevElement();
      var mainNavTop = 0;
      // list of classes the hide-nav has when it is expanded -> do not hide if it has those classes
      var navOpenClasses = hidingNav[0].getAttribute('data-nav-target-class'),
        navOpenArrayClasses = [];
      if(navOpenClasses) navOpenArrayClasses = navOpenClasses.split(' ');
      getMainNavTop();
      if(mainNavTop > 0) {
        scrollOffset = scrollOffset + mainNavTop;
      }
      
      // init navigation and listen to window scroll event
      getHeaderHeight();
      initSecondaryNav();
      initFixedNav();
      resetHideNav();
      window.addEventListener('scroll', function(event){
        if(scrolling) return;
        scrolling = true;
        window.requestAnimationFrame(resetHideNav);
      });
  
      window.addEventListener('resize', function(event){
        if(scrolling) return;
        scrolling = true;
        window.requestAnimationFrame(function(){
          if(headerHeight > 0) {
            getMainNavTop();
            getHeaderHeight();
            initSecondaryNav();
            initFixedNav();
          }
          // reset both navigation
          hideNavScrollUp();
  
          scrolling = false;
        });
      });
  
      function getHeaderHeight() {
        headerHeight = mainNav[0].offsetHeight;
      };
  
      function initSecondaryNav() { // if there's a secondary nav, set its top equal to the header height
        if(subNav.length < 1 || mainNav.length < 1) return;
        subNav[0].style.top = (headerHeight - 1)+'px';
      };
  
      function initFixedNav() {
        if(!navIsFixed || mainNav.length < 1) return;
        mainNav[0].style.marginBottom = '-'+headerHeight+'px';
      };
  
      function resetHideNav() { // check if navs need to be hidden/revealed
        currentTop = window.scrollY;
        if(currentTop - previousTop > scrollDelta && currentTop > scrollOffset) {
          hideNavScrollDown();
        } else if( previousTop - currentTop > scrollDelta || (previousTop - currentTop > 0 && currentTop < scrollOffset) ) {
          hideNavScrollUp();
        } else if( previousTop - currentTop > 0 && subNav.length > 0 && subNav[0].getBoundingClientRect().top > 0) {
          setTranslate(subNav[0], '0%');
        }
        // if primary nav is fixed -> toggle bg class
        if(navIsFixed) {
          var scrollTop = window.scrollY || window.pageYOffset;
          Util.toggleClass(mainNav[0], 'hide-nav--has-bg', (scrollTop > headerHeight + mainNavTop));
        }
        previousTop = currentTop;
        scrolling = false;
      };
  
      function hideNavScrollDown() {
        // if there's a secondary nav -> it has to reach the top before hiding nav
        if( subNav.length  > 0 && subNav[0].getBoundingClientRect().top > headerHeight) return;
        // on mobile -> hide navigation only if dropdown is not open
        if(triggerMobile && triggerMobile.getAttribute('aria-expanded') == "true") return;
        // check if main nav has one of the following classes
        if( mainNav.length > 0 && (!navOpenClasses || !checkNavExpanded())) {
          setTranslate(mainNav[0], '-100%'); 
          mainNav[0].addEventListener('transitionend', addOffCanvasClass);
        }
        if( subNav.length  > 0 ) setTranslate(subNav[0], '-'+headerHeight+'px');
      };
  
      function hideNavScrollUp() {
        if( mainNav.length > 0 ) {setTranslate(mainNav[0], '0%'); Util.removeClass(mainNav[0], 'hide-nav--off-canvas');mainNav[0].removeEventListener('transitionend', addOffCanvasClass);}
        if( subNav.length  > 0 ) setTranslate(subNav[0], '0%');
      };
  
      function addOffCanvasClass() {
        mainNav[0].removeEventListener('transitionend', addOffCanvasClass);
        Util.addClass(mainNav[0], 'hide-nav--off-canvas');
      };
  
      function setTranslate(element, val) {
        element.style.transform = 'translateY('+val+')';
      };
  
      function getTriggerMobileMenu() {
        // store trigger that toggle mobile navigation dropdown
        var triggerMobileClass = hidingNav[0].getAttribute('data-mobile-trigger');
        if(!triggerMobileClass) return false;
        if(triggerMobileClass.indexOf('#') == 0) { // get trigger by ID
          var trigger = document.getElementById(triggerMobileClass.replace('#', ''));
          if(trigger) return trigger;
        } else { // get trigger by class name
          var trigger = hidingNav[0].getElementsByClassName(triggerMobileClass);
          if(trigger.length > 0) return trigger[0];
        }
        
        return false;
      };
  
      function createPrevElement() {
        // create element to be inserted right before the mainNav to get its top value
        if( mainNav.length < 1) return false;
        var newElement = document.createElement("div"); 
        newElement.setAttribute('aria-hidden', 'true');
        mainNav[0].parentElement.insertBefore(newElement, mainNav[0]);
        var prevElement =  mainNav[0].previousElementSibling;
        prevElement.style.opacity = '0';
        return prevElement;
      };
  
      function getMainNavTop() {
        if(!prevElement) return;
        mainNavTop = prevElement.getBoundingClientRect().top + window.scrollY;
      };
  
      function checkNavExpanded() {
        var navIsOpen = false;
        for(var i = 0; i < navOpenArrayClasses.length; i++){
          if(Util.hasClass(mainNav[0], navOpenArrayClasses[i].trim())) {
            navIsOpen = true;
            break;
          }
        }
        return navIsOpen;
      };
      
    } else {
      // if window requestAnimationFrame is not supported -> add bg class to fixed header
      var mainNav = document.getElementsByClassName('js-hide-nav--main');
      if(mainNav.length < 1) return;
      if(Util.hasClass(mainNav[0], 'hide-nav--fixed')) Util.addClass(mainNav[0], 'hide-nav--has-bg');
    }
  }());
  // File#: _1_image-magnifier
  // Usage: codyhouse.co/license
  
  (function() {
    var ImageMagnifier = function(element) {
      this.element = element;
      this.asset = this.element.getElementsByClassName('js-img-mag__asset')[0];
      this.ready = false;
      this.scale = 1;
      this.intervalId = false;
      this.moving = false;
      this.moveEvent = false;
      initImageMagnifier(this);
    };
  
    function initImageMagnifier(imgMag) {
      // wait for the image to be loaded
      imgMag.asset.addEventListener('load', function(){
        initImageMagnifierMove(imgMag);
      });
      if(imgMag.asset.complete) {
        initImageMagnifierMove(imgMag);
      }
    };
  
    function initImageMagnifierMove(imgMag) {
      if(imgMag.ready) return;
      imgMag.ready = true;
      initImageMagnifierScale(imgMag); // get image scale
      // listen to mousenter event
      imgMag.element.addEventListener('mouseenter', handleEvent.bind(imgMag));
    };
  
    function initImageMagnifierScale(imgMag) {
      var customScale = imgMag.element.getAttribute('data-scale');
      if(customScale) { // use custom scale set in HTML
        imgMag.scale = customScale;
      } else { // use natural width of image to get the scale value
        imgMag.scale = imgMag.asset.naturalWidth/imgMag.element.offsetWidth;
        // round to 2 places decimal
        imgMag.scale = Math.floor((imgMag.scale*100))/100;
        if(imgMag.scale > 1.2)  imgMag.scale = imgMag.scale - 0.2;
      }
    };
  
    function initImageMove(imgMag) { // add move event listeners
      imgMag.moveEvent = handleEvent.bind(imgMag);
      imgMag.element.addEventListener('mousemove', imgMag.moveEvent);
      imgMag.element.addEventListener('mouseleave', imgMag.moveEvent);
    };
  
    function cancelImageMove(imgMag) { // remove move event listeners
  		if(imgMag.intervalId) {
  			(!window.requestAnimationFrame) ? clearInterval(imgMag.intervalId) : window.cancelAnimationFrame(imgMag.intervalId);
  			imgMag.intervalId = false;
      }
      if(imgMag.moveEvent) {
        imgMag.element.removeEventListener('mousemove', imgMag.moveEvent);
        imgMag.element.removeEventListener('mouseleave', imgMag.moveEvent);
        imgMag.moveEvent = false;
      }
    };
  
    function handleEvent(event) {
  		switch(event.type) {
  			case 'mouseenter':
  				startMove(this, event);
  				break;
  			case 'mousemove':
  				move(this, event);
  				break;
  			case 'mouseleave':
  				endMove(this);
  				break;
  		}
    };
    
    function startMove(imgMag, event) {
      imgMag.moving = true;
      initImageMove(imgMag); // listen to mousemove event
      zoomImageMagnifier(imgMag, event);
    };
  
    function move(imgMag, event) {
      if(!imgMag.moving || imgMag.intervalId) return;
      (!window.requestAnimationFrame) 
        ? imgMag.intervalId = setTimeout(function(){zoomImageMagnifier(imgMag, event);}, 250)
        : imgMag.intervalId = window.requestAnimationFrame(function(){zoomImageMagnifier(imgMag, event);});
    };
  
    function endMove(imgMag) {
      imgMag.moving = false;
      cancelImageMove(imgMag); // remove event listeners
      imgMag.asset.removeAttribute('style'); // reset image style
    };
  
    function zoomImageMagnifier(imgMag, event) { // zoom effect on mousemove
      var elementRect = imgMag.element.getBoundingClientRect();
      var translateX = (elementRect.left - event.clientX);
      var translateY = (elementRect.top - event.clientY);
      if(translateX > 0) translateX = 0;if(translateX < -1*elementRect.width) translateX = -1*elementRect.width;
      if(translateY > 0) translateY = 0;if(translateY < -1*elementRect.height) translateX = -1*elementRect.height;
      var transform = 'translateX('+translateX*(imgMag.scale - 1)+'px) translateY('+translateY*(imgMag.scale - 1)+'px) scale('+imgMag.scale+')';
      imgMag.asset.setAttribute('style', 'transform: '+transform+';');
      imgMag.intervalId = false;
    };
  
    // init ImageMagnifier object
    var imageMag = document.getElementsByClassName('js-img-mag');
    if( imageMag.length > 0 ) {
      for( var i = 0; i < imageMag.length; i++) {
        new ImageMagnifier(imageMag[i]);
      }
    }
  }());
  // File#: _1_immersive-section-transition
  // Usage: codyhouse.co/license
  (function() {
    var ImmerseSectionTr = function(element) {
      this.element = element;
      this.media = this.element.getElementsByClassName('js-immerse-section-tr__media');
      this.scrollContent = this.element.getElementsByClassName('js-immerse-section-tr__content');
      if(this.media.length < 1) return;
      this.figure = this.media[0].getElementsByClassName('js-immerse-section-tr__figure');
      if(this.figure.length < 1) return;
      this.visibleFigure = false;
      this.mediaScale = 1;
      this.mediaInitHeight = 0;
      this.elementPadding = 0;
      this.scrollingFn = false;
      this.scrolling = false;
      this.active = false;
      this.scrollDelta = 0; // amount to scroll for full-screen scaleup
      initImmerseSectionTr(this);
    };
  
    function initImmerseSectionTr(element) {
      initContainer(element);
      resetSection(element);
  
      // listen to resize event and reset values
      element.element.addEventListener('update-immerse-section', function(event){
        resetSection(element);
      });
  
      // detect when the element is sticky - update scale value and opacity layer 
      var observer = new IntersectionObserver(immerseSectionTrCallback.bind(element));
      observer.observe(element.media[0]);
    };
  
    function resetSection(element) {
      getVisibleFigure(element);
      checkEffectActive(element);
      if(element.active) {
        Util.removeClass(element.element, 'immerse-section-tr--disabled');
        updateMediaHeight(element);
        getMediaScale(element); 
        updateMargin(element);
        setScaleValue.bind(element)();
      } else {
        // reset appearance
        Util.addClass(element.element, 'immerse-section-tr--disabled');
        element.media[0].style = '';
        element.scrollContent[0].style = '';
        updateScale(element, 1);
        updateOpacity(element, 0);
      }
      element.element.dispatchEvent(new CustomEvent('immersive-section-updated', {detail: {active: element.active, asset: element.visibleFigure}}));
    };
  
    function getVisibleFigure(element) { // get visible figure element
      element.visibleFigure = false;
      for(var i = 0; i < element.figure.length; i++) {
        if(window.getComputedStyle(element.figure[i]).getPropertyValue('display') != 'none') {
          element.visibleFigure = element.figure[i];
          break;
        }
      }
    };
  
    function updateMediaHeight(element) { // set sticky element padding/margin + height
      element.mediaInitHeight = element.visibleFigure.offsetHeight;
      element.scrollDelta = (window.innerHeight - element.visibleFigure.offsetHeight) > (window.innerWidth - element.visibleFigure.offsetWidth)
        ? (window.innerHeight - element.visibleFigure.offsetHeight)/2
        : (window.innerWidth - element.visibleFigure.offsetWidth)/2;
      if(element.scrollDelta > window.innerHeight) element.scrollDelta = window.innerHeight;
      if(element.scrollDelta < 200) element.scrollDelta = 200;
      element.media[0].style.height = window.innerHeight+'px';
      element.media[0].style.paddingTop = (window.innerHeight - element.visibleFigure.offsetHeight)/2+'px';
      element.media[0].style.marginTop = (element.visibleFigure.offsetHeight - window.innerHeight)/2+'px';
    };
  
    function getMediaScale(element) { // get media final scale value
      var scaleX = roundValue(window.innerWidth/element.visibleFigure.offsetWidth),
        scaleY = roundValue(window.innerHeight/element.visibleFigure.offsetHeight);
  
      element.mediaScale = Math.max(scaleX, scaleY);
      element.elementPadding = parseInt(window.getComputedStyle(element.element).getPropertyValue('padding-top'));
    };
  
    function roundValue(value) {
      return (Math.ceil(value*100)/100).toFixed(2);
    };
  
    function updateMargin(element) { // update distance between media and content elements
      if(element.scrollContent.length > 0) element.scrollContent[0].style.marginTop = element.scrollDelta+'px';
    };
  
    function setScaleValue() { // update asset scale value
      if(!this.active) return; // effect is not active
      var offsetTop = (window.innerHeight - this.mediaInitHeight)/2;
      var top = this.element.getBoundingClientRect().top + this.elementPadding;
  
      if( top < offsetTop && top > offsetTop - this.scrollDelta) {
        var scale = 1 + (top - offsetTop)*(1 - this.mediaScale)/this.scrollDelta;
        updateScale(this, scale);
        updateOpacity(this, 0);
      } else if(top >= offsetTop) {
        updateScale(this, 1);
        updateOpacity(this, 0);
      } else {
        updateScale(this, this.mediaScale);
        updateOpacity(this, 1.8*( offsetTop - this.scrollDelta - top)/ window.innerHeight);
      }
  
      this.scrolling = false;
    };
  
    function updateScale(element, value) { // apply new scale value
      element.visibleFigure.style.transform = 'scale('+value+')';
      element.visibleFigure.style.msTransform = 'scale('+value+')';
    };
  
    function updateOpacity(element, value) { // update layer opacity
      element.element.style.setProperty('--immerse-section-tr-opacity', value);
    };
  
    function immerseSectionTrCallback(entries) { // intersectionObserver callback
      if(entries[0].isIntersecting) {
        if(this.scrollingFn) return; // listener for scroll event already added
        immerseSectionTrScrollEvent(this);
      } else {
        if(!this.scrollingFn) return; // listener for scroll event already removed
        window.removeEventListener('scroll', this.scrollingFn);
        this.scrollingFn = false;
      }
    };
  
    function immerseSectionTrScrollEvent(element) { // listen to scroll when asset element is inside the viewport
      element.scrollingFn = immerseSectionTrScrolling.bind(element);
      window.addEventListener('scroll', element.scrollingFn);
    };
  
    function immerseSectionTrScrolling() { // update asset scale on scroll
      if(this.scrolling) return;
      this.scrolling = true;
      window.requestAnimationFrame(setScaleValue.bind(this));
    };
  
    function initContainer(element) {
      // add a padding to the container to fix the collapsing-margin issue
      if(parseInt(window.getComputedStyle(element.element).getPropertyValue('padding-top')) == 0) element.element.style.paddingTop = '1px';
    };
  
    function checkEffectActive(element) { //check if effect needs to be activated
      element.active = true;
      if(element.visibleFigure.offsetHeight >= window.innerHeight) element.active = false;
      if( window.innerHeight - element.visibleFigure.offsetHeight >= 600) element.active = false;
    };
  
    //initialize the ImmerseSectionTr objects
    var immerseSections = document.getElementsByClassName('js-immerse-section-tr'),
      reducedMotion = Util.osHasReducedMotion(),
      intObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  
    if(immerseSections.length < 1 ) return;
  	if( !reducedMotion && intObserverSupported) {
      var immerseSectionsArray = [];
  		for( var i = 0; i < immerseSections.length; i++) {
        (function(i){immerseSectionsArray.push(new ImmerseSectionTr(immerseSections[i]));})(i);
      }
  
      if(immerseSectionsArray.length > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-immerse-section');
        
        window.addEventListener('resize', function() {
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 500);
        });
  
        function doneResizing() {
          for( var i = 0; i < immerseSectionsArray.length; i++) {
            (function(i){immerseSectionsArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
      };
    } else { // effect deactivated
      for( var i = 0; i < immerseSections.length; i++) Util.addClass(immerseSections[i], 'immerse-section-tr--disabled');
    }
  }());
  // File#: _1_infinite-scroll
  // Usage: codyhouse.co/license
  (function() {
    var InfiniteScroll = function(opts) {
      this.options = Util.extend(InfiniteScroll.defaults, opts);
      this.element = this.options.element;
      this.loader = document.getElementsByClassName('js-infinite-scroll__loader');
      this.loadBtn = document.getElementsByClassName('js-infinite-scroll__btn');
      this.loading = false;
      this.currentPageIndex = this.element.getAttribute('data-current-page') ? parseInt(this.element.getAttribute('data-current-page')) : 0;
      this.index = this.currentPageIndex;
      initLoad(this);
    };
  
    function initLoad(infiniteScroll) {
      setPathValues(infiniteScroll); // get dynamic content paths
  
      getTresholdPixel(infiniteScroll);
      
      if(infiniteScroll.options.container) { // get container of dynamic content
        infiniteScroll.container = infiniteScroll.element.querySelector(infiniteScroll.options.container);
      }
      
      if((!infiniteScroll.options.loadBtn || infiniteScroll.options.loadBtnDelay) && infiniteScroll.loadBtn.length > 0) { // hide load more btn
        Util.addClass(infiniteScroll.loadBtn[0], 'sr-only');
      }
  
      if(!infiniteScroll.options.loadBtn || infiniteScroll.options.loadBtnDelay) {
        if(intersectionObserverSupported) { // check element scrolling
          initObserver(infiniteScroll);
        } else {
          infiniteScroll.scrollEvent = handleEvent.bind(infiniteScroll);
          window.addEventListener('scroll', infiniteScroll.scrollEvent);
        }
      }
      
      initBtnEvents(infiniteScroll); // listen for click on load Btn
      
      if(!infiniteScroll.options.path) { // content has been loaded using a custom function
        infiniteScroll.element.addEventListener('loaded-new', function(event){
          contentWasLoaded(infiniteScroll, event.detail.path, event.detail.checkNext); // reset element
          // emit 'content-loaded' event -> this could be useful when new content needs to be initialized
        infiniteScroll.element.dispatchEvent(new CustomEvent('content-loaded', {detail: event.detail.path}));
        });
      }
    };
  
    function setPathValues(infiniteScroll) { // path can be strin or comma-separated list
      if(!infiniteScroll.options.path) return;
      var split = infiniteScroll.options.path.split(',');
      if(split.length > 1) {
        infiniteScroll.options.path = [];
        for(var i = 0; i < split.length; i++) infiniteScroll.options.path.push(split[i].trim());
      }
    };
  
    function getTresholdPixel(infiniteScroll) { // get the threshold value in pixels - will be used only if intersection observer is not supported
      infiniteScroll.thresholdPixel = infiniteScroll.options.threshold.indexOf('px') > -1 ? parseInt(infiniteScroll.options.threshold.replace('px', '')) : parseInt(window.innerHeight*parseInt(infiniteScroll.options.threshold.replace('%', ''))/100);
    };
  
    function initObserver(infiniteScroll) { // intersection observer supported
      // append an element to the bottom of the container that will be observed
      var observed = document.createElement("div");
      Util.setAttributes(observed, {'aria-hidden': 'true', 'class': 'js-infinite-scroll__observed', 'style': 'width: 100%; height: 1px; margin-top: -1px; visibility: hidden;'});
      infiniteScroll.element.appendChild(observed);
  
      infiniteScroll.observed = infiniteScroll.element.getElementsByClassName('js-infinite-scroll__observed')[0];
  
      var config = {rootMargin: '0px 0px '+infiniteScroll.options.threshold+' 0px'};
      infiniteScroll.observer = new IntersectionObserver(observerLoadContent.bind(infiniteScroll), config);
      infiniteScroll.observer.observe(infiniteScroll.observed);
    };
  
    function observerLoadContent(entry) { 
      if(this.loading) return;
      if(entry[0].intersectionRatio > 0) loadMore(this);
    };
  
    function handleEvent(event) { // handle click/scroll events
      switch(event.type) {
        case 'click': {
          initClick(this, event); // click on load more button
          break;
        }
        case 'scroll': { // triggered only if intersection onserver is not supported
          initScroll(this);
          break;
        }
      }
    };
  
    function initScroll(infiniteScroll) { // listen to scroll event (only if intersectionObserver is not supported)
      (!window.requestAnimationFrame) ? setTimeout(checkLoad.bind(infiniteScroll)) : window.requestAnimationFrame(checkLoad.bind(infiniteScroll));
    };
  
    function initBtnEvents(infiniteScroll) { // load more button events - click + focus (for keyboard accessibility)
      if(infiniteScroll.loadBtn.length == 0) return;
      infiniteScroll.clickEvent = handleEvent.bind(infiniteScroll);
      infiniteScroll.loadBtn[0].addEventListener('click', infiniteScroll.clickEvent);
      
      if(infiniteScroll.options.loadBtn && !infiniteScroll.options.loadBtnDelay) {
        Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
        if(infiniteScroll.loader.length > 0 ) Util.addClass(infiniteScroll.loader[0], 'is-hidden');
      }
  
      // toggle class sr-only if link is in focus/loses focus
      infiniteScroll.loadBtn[0].addEventListener('focusin', function(){
        if(Util.hasClass(infiniteScroll.loadBtn[0], 'sr-only')) {
          Util.addClass(infiniteScroll.loadBtn[0], 'js-infinite-scroll__btn-focus');
          Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
        }
      });
      infiniteScroll.loadBtn[0].addEventListener('focusout', function(){
        if(Util.hasClass(infiniteScroll.loadBtn[0], 'js-infinite-scroll__btn-focus')) {
          Util.removeClass(infiniteScroll.loadBtn[0], 'js-infinite-scroll__btn-focus');
          Util.addClass(infiniteScroll.loadBtn[0], 'sr-only');
        }
      });
    };
  
    function initClick(infiniteScroll, event) { // click on 'Load More' button
      event.preventDefault();
      Util.addClass(infiniteScroll.loadBtn[0], 'sr-only');
      loadMore(infiniteScroll);
    };
  
    function checkLoad() { // while scrolling -> check if we need to load new content (only if intersectionObserver is not supported)
      if(this.loading) return;
      if(!needLoad(this)) return;
      loadMore(this);
    };
  
    function loadMore(infiniteScroll) { // new conten needs to be loaded
      infiniteScroll.loading = true;
      if(infiniteScroll.loader.length > 0) Util.removeClass(infiniteScroll.loader[0], 'is-hidden');
      var moveFocus = false;
      if(infiniteScroll.loadBtn.length > 0 ) moveFocus = Util.hasClass(infiniteScroll.loadBtn[0], 'js-infinite-scroll__btn-focus');
      // check if need to add content or user has custom load function
      if(infiniteScroll.options.path) {
        contentBasicLoad(infiniteScroll, moveFocus); // load content
      } else {
        emitCustomEvents(infiniteScroll, 'load-new', moveFocus); // user takes care of loading content
      }
    };
  
    function contentBasicLoad(infiniteScroll, moveFocus) {
      var filePath = getFilePath(infiniteScroll);
      // load file content
      getNewContent(filePath, function(content){
        var checkNext = insertNewContent(infiniteScroll, content, moveFocus);
        contentWasLoaded(infiniteScroll, filePath, checkNextPageAvailable(infiniteScroll, checkNext));
        // emit 'content-loaded' event -> this could be useful when new content needs to be initialized
        infiniteScroll.element.dispatchEvent(new CustomEvent('content-loaded', {detail: filePath}));
      });
    };
  
    function getFilePath(infiniteScroll) { // get path of the file to load
      return (Array.isArray(infiniteScroll.options.path)) 
        ? infiniteScroll.options.path[infiniteScroll.index]
        : infiniteScroll.options.path.replace('{n}', infiniteScroll.index+1);
    };
  
    function getNewContent(path, cb) {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) cb(this.responseText);
      };
      xhttp.open("GET", path, true);
      xhttp.send();
    };
  
    function insertNewContent(infiniteScroll, content, moveFocus) {
      var next = false;
      if(infiniteScroll.options.container) {
        var div = document.createElement("div");
        div.innerHTML = content;
        var wrapper = div.querySelector(infiniteScroll.options.container);
        if(wrapper) {
          content = wrapper.innerHTML;
          next = wrapper.getAttribute('data-path');
        }
      }
      var lastItem = false;
      if(moveFocus) lastItem = getLastChild(infiniteScroll);
      if(infiniteScroll.container) {
        infiniteScroll.container.insertAdjacentHTML('beforeend', content);
      } else {
        (infiniteScroll.loader.length > 0) 
          ? infiniteScroll.loader[0].insertAdjacentHTML('beforebegin', content)
          : infiniteScroll.element.insertAdjacentHTML('beforeend', content);
      }
      if(moveFocus && lastItem) Util.moveFocus(lastItem);
  
      return next;
    };
  
    function getLastChild(infiniteScroll) {
      if(infiniteScroll.container) return infiniteScroll.container.lastElementChild;
      if(infiniteScroll.loader.length > 0) return infiniteScroll.loader[0].previousElementSibling;
      return infiniteScroll.element.lastElementChild;
    };
  
    function checkNextPageAvailable(infiniteScroll, checkNext) { // check if there's still content to be loaded
      if(Array.isArray(infiniteScroll.options.path)) {
        return infiniteScroll.options.path.length > infiniteScroll.index + 1;
      }
      return checkNext;
    };
  
    function contentWasLoaded(infiniteScroll, url, checkNext) { // new content has been loaded - reset status 
      if(infiniteScroll.loader.length > 0) Util.addClass(infiniteScroll.loader[0], 'is-hidden'); // hide loader
      
      if(infiniteScroll.options.updateHistory && url) { // update browser history
        var pageArray = location.pathname.split('/'),
          actualPage = pageArray[pageArray.length - 1] ;
        if( actualPage != url && history.pushState ) window.history.replaceState({path: url},'',url);
      }
      
      if(!checkNext) { // no need to load additional pages - remove scroll listening and/or click listening
        removeScrollEvents(infiniteScroll);
        if(infiniteScroll.clickEvent) {
          infiniteScroll.loadBtn[0].removeEventListener('click', infiniteScroll.clickEvent);
          Util.addClass(infiniteScroll.loadBtn[0], 'is-hidden');
          Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
        }
      }
      
      if(checkNext && infiniteScroll.options.loadBtn) { // check if we need to switch from scrolling to click -> add/remove proper listener
        if(!infiniteScroll.options.loadBtnDelay) {
          Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
        } else if(infiniteScroll.index - infiniteScroll.currentPageIndex + 1 >= infiniteScroll.options.loadBtnDelay && infiniteScroll.loadBtn.length > 0) {
          removeScrollEvents(infiniteScroll);
          Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
        }
      }
  
      if(checkNext && infiniteScroll.loadBtn.length > 0 && Util.hasClass(infiniteScroll.loadBtn[0], 'js-infinite-scroll__btn-focus')) { // keyboard accessibility
        Util.removeClass(infiniteScroll.loadBtn[0], 'sr-only');
      }
  
      infiniteScroll.index = infiniteScroll.index + 1;
      infiniteScroll.loading = false;
    };
  
    function removeScrollEvents(infiniteScroll) {
      if(infiniteScroll.scrollEvent) window.removeEventListener('scroll', infiniteScroll.scrollEvent);
      if(infiniteScroll.observer) infiniteScroll.observer.unobserve(infiniteScroll.observed);
    };
  
    function needLoad(infiniteScroll) { // intersectionObserverSupported not supported -> check if threshold has been reached
      return infiniteScroll.element.getBoundingClientRect().bottom - window.innerHeight <= infiniteScroll.thresholdPixel;
    };
  
    function emitCustomEvents(infiniteScroll, eventName, moveFocus) { // applicable when user takes care of loading new content
  		var event = new CustomEvent(eventName, {detail: {index: infiniteScroll.index+1, moveFocus: moveFocus}});
  		infiniteScroll.element.dispatchEvent(event);
  	};
  
    InfiniteScroll.defaults = {
      element : '',
      path : false, // path of files to be loaded: set to comma-separated list or string (should include {n} to be replaced by integer index). If not set, user will take care of loading new content
      container: false, // Append new content to this element. Additionally, when loaded a new page, only content of the element will be appended
      threshold: '200px', // distance between viewport and scroll area for loading new content
      updateHistory: false, // push new url to browser history
      loadBtn: false, // use a button to load more content
      loadBtnDelay: false // set to an integer if you want the load more button to be visible only after a number of loads on scroll - loadBtn needs to be 'on'
    };
  
    window.InfiniteScroll = InfiniteScroll;
  
    //initialize the InfiniteScroll objects
    var infiniteScroll = document.getElementsByClassName('js-infinite-scroll'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  
    if( infiniteScroll.length > 0) {
      for( var i = 0; i < infiniteScroll.length; i++) {
        (function(i){
          var path = infiniteScroll[i].getAttribute('data-path') ? infiniteScroll[i].getAttribute('data-path') : false,
          container = infiniteScroll[i].getAttribute('data-container') ? infiniteScroll[i].getAttribute('data-container') : false,
          updateHistory = ( infiniteScroll[i].getAttribute('data-history') && infiniteScroll[i].getAttribute('data-history') == 'on') ? true : false,
          loadBtn = ( infiniteScroll[i].getAttribute('data-load-btn') && infiniteScroll[i].getAttribute('data-load-btn') == 'on') ? true : false,
          loadBtnDelay = infiniteScroll[i].getAttribute('data-load-btn-delay') ? infiniteScroll[i].getAttribute('data-load-btn-delay') : false,
          threshold = infiniteScroll[i].getAttribute('data-threshold') ? infiniteScroll[i].getAttribute('data-threshold') : '200px';
          new InfiniteScroll({element: infiniteScroll[i], path : path, container : container, updateHistory: updateHistory, loadBtn: loadBtn, loadBtnDelay: loadBtnDelay, threshold: threshold});
        })(i);
      }
    };
  }());
  // File#: _1_language-picker
  // Usage: codyhouse.co/license
  (function() {
  	var LanguagePicker = function(element) {
  		this.element = element;
  		this.select = this.element.getElementsByTagName('select')[0];
  		this.options = this.select.getElementsByTagName('option');
  		this.selectedOption = getSelectedOptionText(this);
  		this.pickerId = this.select.getAttribute('id');
  		this.trigger = false;
  		this.dropdown = false;
  		this.firstLanguage = false;
  		// dropdown arrow inside the button element
  		this.arrowSvgPath = '<svg viewBox="0 0 16 16"><polygon points="3,5 8,11 13,5 "></polygon></svg>';
  		this.globeSvgPath = '<svg viewBox="0 0 16 16"><path d="M8,0C3.6,0,0,3.6,0,8s3.6,8,8,8s8-3.6,8-8S12.4,0,8,0z M13.9,7H12c-0.1-1.5-0.4-2.9-0.8-4.1 C12.6,3.8,13.6,5.3,13.9,7z M8,14c-0.6,0-1.8-1.9-2-5H10C9.8,12.1,8.6,14,8,14z M6,7c0.2-3.1,1.3-5,2-5s1.8,1.9,2,5H6z M4.9,2.9 C4.4,4.1,4.1,5.5,4,7H2.1C2.4,5.3,3.4,3.8,4.9,2.9z M2.1,9H4c0.1,1.5,0.4,2.9,0.8,4.1C3.4,12.2,2.4,10.7,2.1,9z M11.1,13.1 c0.5-1.2,0.7-2.6,0.8-4.1h1.9C13.6,10.7,12.6,12.2,11.1,13.1z"></path></svg>';
  
  		initLanguagePicker(this);
  		initLanguagePickerEvents(this);
  	};
  
  	function initLanguagePicker(picker) {
  		// create the HTML for the custom dropdown element
  		picker.element.insertAdjacentHTML('beforeend', initButtonPicker(picker) + initListPicker(picker));
  		
  		// save picker elements
  		picker.dropdown = picker.element.getElementsByClassName('language-picker__dropdown')[0];
  		picker.languages = picker.dropdown.getElementsByClassName('language-picker__item');
  		picker.firstLanguage = picker.languages[0];
  		picker.trigger = picker.element.getElementsByClassName('language-picker__button')[0];
  	};
  
  	function initLanguagePickerEvents(picker) {
  		// make sure to add the icon class to the arrow dropdown inside the button element
  		var svgs = picker.trigger.getElementsByTagName('svg');
  		Util.addClass(svgs[0], 'icon');
  		Util.addClass(svgs[1], 'icon');
  		// language selection in dropdown
  		// ⚠️ Important: you need to modify this function in production
  		initLanguageSelection(picker);
  
  		// click events
  		picker.trigger.addEventListener('click', function(){
  			toggleLanguagePicker(picker, false);
  		});
  		// keyboard navigation
  		picker.dropdown.addEventListener('keydown', function(event){
  			if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
  				keyboardNavigatePicker(picker, 'prev');
  			} else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
  				keyboardNavigatePicker(picker, 'next');
  			}
  		});
  	};
  
  	function toggleLanguagePicker(picker, bool) {
  		var ariaExpanded;
  		if(bool) {
  			ariaExpanded = bool;
  		} else {
  			ariaExpanded = picker.trigger.getAttribute('aria-expanded') == 'true' ? 'false' : 'true';
  		}
  		picker.trigger.setAttribute('aria-expanded', ariaExpanded);
  		if(ariaExpanded == 'true') {
  			picker.firstLanguage.focus(); // fallback if transition is not supported
  			picker.dropdown.addEventListener('transitionend', function cb(){
  				picker.firstLanguage.focus();
  				picker.dropdown.removeEventListener('transitionend', cb);
  			});
  			// place dropdown
  			placeDropdown(picker);
  		}
  	};
  
  	function placeDropdown(picker) {
  		var triggerBoundingRect = picker.trigger.getBoundingClientRect();
  		Util.toggleClass(picker.dropdown, 'language-picker__dropdown--right', (window.innerWidth < triggerBoundingRect.left + picker.dropdown.offsetWidth));
  		Util.toggleClass(picker.dropdown, 'language-picker__dropdown--up', (window.innerHeight < triggerBoundingRect.bottom + picker.dropdown.offsetHeight));
  	};
  
  	function checkLanguagePickerClick(picker, target) { // if user clicks outside the language picker -> close it
  		if( !picker.element.contains(target) ) toggleLanguagePicker(picker, 'false');
  	};
  
  	function moveFocusToPickerTrigger(picker) {
  		if(picker.trigger.getAttribute('aria-expanded') == 'false') return;
  		if(document.activeElement.closest('.language-picker__dropdown') == picker.dropdown) picker.trigger.focus();
  	};
  
  	function initButtonPicker(picker) { // create the button element -> picker trigger
  		// check if we need to add custom classes to the button trigger
  		var customClasses = picker.element.getAttribute('data-trigger-class') ? ' '+picker.element.getAttribute('data-trigger-class') : '';
  	
  		var button = '<button class="language-picker__button'+customClasses+'" aria-label="'+picker.select.value+' '+picker.element.getElementsByTagName('label')[0].textContent+'" aria-expanded="false" aria-controls="'+picker.pickerId+'-dropdown">';
  		button = button + '<span aria-hidden="true" class="language-picker__label language-picker__flag language-picker__flag--'+picker.select.value+'">'+picker.globeSvgPath+'<em>'+picker.selectedOption+'</em>';
  		button = button +picker.arrowSvgPath+'</span>';
  		return button+'</button>';
  	};
  
  	function initListPicker(picker) { // create language picker dropdown
  		var list = '<div class="language-picker__dropdown" aria-describedby="'+picker.pickerId+'-description" id="'+picker.pickerId+'-dropdown">';
  		list = list + '<p class="sr-only" id="'+picker.pickerId+'-description">'+picker.element.getElementsByTagName('label')[0].textContent+'</p>';
  		list = list + '<ul class="language-picker__list" role="listbox">';
  		for(var i = 0; i < picker.options.length; i++) {
  			var selected = picker.options[i].selected ? ' aria-selected="true"' : '',
  				language = picker.options[i].getAttribute('lang');
  			list = list + '<li><a lang="'+language+'" hreflang="'+language+'" href="'+getLanguageUrl(picker.options[i])+'"'+selected+' role="option" data-value="'+picker.options[i].value+'" class="language-picker__item language-picker__flag language-picker__flag--'+picker.options[i].value+'"><span>'+picker.options[i].text+'</span></a></li>';
  		};
  		return list;
  	};
  
  	function getSelectedOptionText(picker) { // used to initialize the label of the picker trigger button
  		var label = '';
  		if('selectedIndex' in picker.select) {
  			label = picker.options[picker.select.selectedIndex].text;
  		} else {
  			label = picker.select.querySelector('option[selected]').text;
  		}
  		return label;
  	};
  
  	function getLanguageUrl(option) {
  		// ⚠️ Important: You should replace this return value with the real link to your website in the selected language
  		// option.value gives you the value of the language that you can use to create your real url (e.g, 'english' or 'italiano')
  		return '#';
  	};
  
  	function initLanguageSelection(picker) {
  		picker.element.getElementsByClassName('language-picker__list')[0].addEventListener('click', function(event){
  			var language = event.target.closest('.language-picker__item');
  			if(!language) return;
  			
  			if(language.hasAttribute('aria-selected') && language.getAttribute('aria-selected') == 'true') {
  				// selecting the same language
  				event.preventDefault();
  				picker.trigger.setAttribute('aria-expanded', 'false'); // hide dropdown
  			} else { 
  				// ⚠️ Important: this 'else' code needs to be removed in production. 
  				// The user has to be redirected to the new url -> nothing to do here
  				event.preventDefault();
  				picker.element.getElementsByClassName('language-picker__list')[0].querySelector('[aria-selected="true"]').removeAttribute('aria-selected');
  				language.setAttribute('aria-selected', 'true');
  				picker.trigger.getElementsByClassName('language-picker__label')[0].setAttribute('class', 'language-picker__label language-picker__flag language-picker__flag--'+language.getAttribute('data-value'));
  				picker.trigger.getElementsByClassName('language-picker__label')[0].getElementsByTagName('em')[0].textContent = language.textContent;
  				picker.trigger.setAttribute('aria-expanded', 'false');
  			}
  		});
  	};
  
  	function keyboardNavigatePicker(picker, direction) {
  		var index = Util.getIndexInArray(picker.languages, document.activeElement);
  		index = (direction == 'next') ? index + 1 : index - 1;
  		if(index < 0) index = picker.languages.length - 1;
  		if(index >= picker.languages.length) index = 0;
  		Util.moveFocus(picker.languages[index]);
  	};
  
  	//initialize the LanguagePicker objects
  	var languagePicker = document.getElementsByClassName('js-language-picker');
  	if( languagePicker.length > 0 ) {
  		var pickerArray = [];
  		for( var i = 0; i < languagePicker.length; i++) {
  			(function(i){pickerArray.push(new LanguagePicker(languagePicker[i]));})(i);
  		}
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
  				// close language picker on 'Esc'
  				pickerArray.forEach(function(element){
  					moveFocusToPickerTrigger(element); // if focus is within dropdown, move it to dropdown trigger
  					toggleLanguagePicker(element, 'false'); // close dropdown
  				});
  			} 
  		});
  		// close language picker when clicking outside it
  		window.addEventListener('click', function(event){
  			pickerArray.forEach(function(element){
  				checkLanguagePickerClick(element, event.target);
  			});
  		});
  	}
  }());
  // File#: _1_lazy-load
  // Usage: codyhouse.co/license
  (function() {
    var LazyLoad = function(elements) {
      this.elements = elements;
      initLazyLoad(this);
    };
  
    function initLazyLoad(asset) {
      if(lazySupported) setAssetsSrc(asset);
      else if(intersectionObsSupported) observeAssets(asset);
      else scrollAsset(asset);
    };
  
    function setAssetsSrc(asset) {
      for(var i = 0; i < asset.elements.length; i++) {
        if(asset.elements[i].getAttribute('data-bg') || asset.elements[i].tagName.toLowerCase() == 'picture') { // this could be an element with a bg image or a <source> element inside a <picture>
          observeSingleAsset(asset.elements[i]);
        } else {
          setSingleAssetSrc(asset.elements[i]);
        } 
      }
    };
  
    function setSingleAssetSrc(img) {
      if(img.tagName.toLowerCase() == 'picture') {
        setPictureSrc(img);
      } else {
        setSrcSrcset(img);
        var bg = img.getAttribute('data-bg');
        if(bg) img.style.backgroundImage = bg;
        if(!lazySupported || bg) img.removeAttribute("loading");
      }
    };
  
    function setPictureSrc(picture) {
      var pictureChildren = picture.children;
      for(var i = 0; i < pictureChildren.length; i++) setSrcSrcset(pictureChildren[i]);
      picture.removeAttribute("loading");
    };
  
    function setSrcSrcset(img) {
      var src = img.getAttribute('data-src');
      if(src) img.src = src;
      var srcset = img.getAttribute('data-srcset');
      if(srcset) img.srcset = srcset;
    };
  
    function observeAssets(asset) {
      for(var i = 0; i < asset.elements.length; i++) {
        observeSingleAsset(asset.elements[i]);
      }
    };
  
    function observeSingleAsset(img) {
      if( !img.getAttribute('data-src') && !img.getAttribute('data-srcset') && !img.getAttribute('data-bg') && img.tagName.toLowerCase() != 'picture') return; // using the native lazyload with no need js lazy-loading
  
      var threshold = img.getAttribute('data-threshold') || '200px';
      var config = {rootMargin: threshold};
      var observer = new IntersectionObserver(observerLoadContent.bind(img), config);
      observer.observe(img);
    };
  
    function observerLoadContent(entries, observer) { 
      if(entries[0].isIntersecting) {
        setSingleAssetSrc(this);
        observer.unobserve(this);
      }
    };
  
    function scrollAsset(asset) {
      asset.elements = Array.prototype.slice.call(asset.elements);
      asset.listening = false;
      asset.scrollListener = eventLazyLoad.bind(asset);
      document.addEventListener("scroll", asset.scrollListener);
      asset.resizeListener = eventLazyLoad.bind(asset);
      document.addEventListener("resize", asset.resizeListener);
      eventLazyLoad.bind(asset)(); // trigger before starting scrolling/resizing
    };
  
    function eventLazyLoad() {
      var self = this;
      if(self.listening) return;
      self.listening = true;
      setTimeout(function() {
        for(var i = 0; i < self.elements.length; i++) {
          if ((self.elements[i].getBoundingClientRect().top <= window.innerHeight && self.elements[i].getBoundingClientRect().bottom >= 0) && getComputedStyle(self.elements[i]).display !== "none") {
            setSingleAssetSrc(self.elements[i]);
  
            self.elements = self.elements.filter(function(image) {
              return image.hasAttribute("loading");
            });
  
            if (self.elements.length === 0) {
              if(self.scrollListener) document.removeEventListener("scroll", self.scrollListener);
              if(self.resizeListener) window.removeEventListener("resize", self.resizeListener);
            }
          }
        }
        self.listening = false;
      }, 200);
    };
  
    window.LazyLoad = LazyLoad;
  
    var lazyLoads = document.querySelectorAll('[loading="lazy"]'),
      lazySupported = 'loading' in HTMLImageElement.prototype,
      intersectionObsSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
    
    if( lazyLoads.length > 0 ) {
      new LazyLoad(lazyLoads);
    };
    
  }());
  // File#: _1_list-filter
  // Usage: codyhouse.co/license
  (function() {
    var ListFilter = function(element) {
      this.element = element;
      this.search = this.element.getElementsByClassName('js-list-filter__search');
      this.list = this.element.getElementsByClassName('js-list-filter__list')[0];
      this.items = this.list.getElementsByClassName('js-list-filter__item');
      this.noResults = this.element.getElementsByClassName('js-list-filter__no-results-msg');
      this.searchTags = [];
      this.resultsNr = this.element.getElementsByClassName('js-list-filter__results-nr');
      this.visibleItemsNr = 0;
      initListFilter(this);
  	};
  
    function initListFilter(element) {
      // get the filterable list of tags
      for(var i = 0; i < element.items.length; i++) {
        var tags = '';
        var label = element.items[i].getElementsByClassName('js-list-filter__label');
        if(label.length > 0) {
          tags = label[0].textContent;
        }
        var additionalTags = element.items[i].getAttribute('data-filter-tags');
        if(additionalTags) tags = tags + ' ' + additionalTags;
        element.searchTags.push(tags);
      }
  
      // filter list based on search input value
      filterItems(element, element.search[0].value.trim());
  
      // filter list when search input is updated
      element.search[0].addEventListener('input', function(){
        filterItems(element, element.search[0].value.trim());
      });
  
      // remove item from the list when clicking on the remove button
      element.list.addEventListener('click', function(event){
        var removeBtn = event.target.closest('.js-list-filter__action-btn--remove');
        if(!removeBtn) return;
        event.preventDefault();
        removeItem(element, removeBtn);
      });
    };
  
    function filterItems(element, value) {
      var array = [];
      var searchArray = value.toLowerCase().split(' ');
      for(var i = 0; i < element.items.length; i++) {
        value == '' ? array.push(false) : array.push(filterItem(element, i, searchArray));
      }
      updateVisibility(element, array);
    };
  
    function filterItem(element, index, searchArray) {
      // return false if item should be visible
      var found = true;
      for(var i = 0; i < searchArray.length; i++) {
        if(searchArray[i] != '' && searchArray[i] != ' ' && element.searchTags[index].toLowerCase().indexOf(searchArray[i]) < 0) {
          found = false;
          break;
        }
      }
      return !found;
    };
  
    function updateVisibility(element, list) {
      element.visibleItemsNr = 0;
      for(var i = 0; i < list.length; i++) {
        // hide/show items
        if(!list[i]) element.visibleItemsNr = element.visibleItemsNr + 1;
        Util.toggleClass(element.items[i], 'is-hidden', list[i]);
      }
      // hide/show no results message
      if(element.noResults.length > 0) Util.toggleClass(element.noResults[0], 'is-hidden', element.visibleItemsNr > 0);
  
      updateResultsNr(element);
    };
  
    function updateResultsNr(element) {
      // update number of results
      if(element.resultsNr.length > 0) element.resultsNr[0].innerHTML = element.visibleItemsNr;
    };
  
    function removeItem(element, btn) {
      var item = btn.closest('.js-list-filter__item');
      if(!item) return;
      var index = Util.getIndexInArray(element.items, item);
      // remove item from the DOM
      item.remove();
      // update list of search tags
      element.searchTags.splice(index, 1);
      // update number of results
      element.visibleItemsNr = element.visibleItemsNr - 1;
      updateResultsNr(element);
    }
  
    //initialize the ListFilter objects
  	var listFilters = document.getElementsByClassName('js-list-filter');
  	if( listFilters.length > 0 ) {
  		for( var i = 0; i < listFilters.length; i++) {
  			(function(i){new ListFilter(listFilters[i]);})(i);
  		}
  	}
  }());
  // File#: _1_main-header
  // Usage: codyhouse.co/license
  (function() {
  	var mainHeader = document.getElementsByClassName('js-header');
  	if( mainHeader.length > 0 ) {
  		var trigger = mainHeader[0].getElementsByClassName('js-header__trigger')[0],
  			nav = mainHeader[0].getElementsByClassName('js-header__nav')[0];
  
  		// we'll use these to store the node that needs to receive focus when the mobile menu is closed 
  		var focusMenu = false;
  
  		//detect click on nav trigger
  		trigger.addEventListener("click", function(event) {
  			event.preventDefault();
  			toggleNavigation(!Util.hasClass(nav, 'header__nav--is-visible'));
  		});
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(trigger.getAttribute('aria-expanded') == 'true' && isVisible(trigger)) {
  					focusMenu = trigger; // move focus to menu trigger when menu is close
  					trigger.click();
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(trigger.getAttribute('aria-expanded') == 'true' && isVisible(trigger) && !document.activeElement.closest('.js-header')) trigger.click();
  			}
  		});
  
  		// listen for resize
  		var resizingId = false;
  		window.addEventListener('resize', function() {
  			clearTimeout(resizingId);
  			resizingId = setTimeout(doneResizing, 500);
  		});
  
  		function doneResizing() {
  			if( !isVisible(trigger) && Util.hasClass(mainHeader[0], 'header--expanded')) toggleNavigation(false); 
  		};
  	}
  
  	function isVisible(element) {
  		return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  	};
  
  	function toggleNavigation(bool) { // toggle navigation visibility on small device
  		Util.toggleClass(nav, 'header__nav--is-visible', bool);
  		Util.toggleClass(mainHeader[0], 'header--expanded', bool);
  		trigger.setAttribute('aria-expanded', bool);
  		if(bool) { //opening menu -> move focus to first element inside nav
  			nav.querySelectorAll('[href], input:not([disabled]), button:not([disabled])')[0].focus();
  		} else if(focusMenu) {
  			focusMenu.focus();
  			focusMenu = false;
  		}
  	};
  }());
  // File#: _1_masonry
  // Usage: codyhouse.co/license
  
  (function() {
    var Masonry = function(element) {
      this.element = element;
      this.list = this.element.getElementsByClassName('js-masonry__list')[0];
      this.items = this.element.getElementsByClassName('js-masonry__item');
      this.activeColumns = 0;
      this.colStartWidth = 0; // col min-width (defined in CSS using --masonry-col-auto-size variable)
      this.colWidth = 0; // effective column width
      this.colGap = 0;
      // store col heights and items
      this.colHeights = [];
      this.colItems = [];
      // flex full support
      this.flexSupported = checkFlexSupported(this.items[0]);
      getGridLayout(this); // get initial grid params
      setGridLayout(this); // set grid params (width of elements)
      initMasonryLayout(this); // init gallery layout
    };
  
    function checkFlexSupported(item) {
      var itemStyle = window.getComputedStyle(item);
      return itemStyle.getPropertyValue('flex-basis') != 'auto';
    };
  
    function getGridLayout(grid) { // this is used to get initial grid details (width/grid gap)
      var itemStyle = window.getComputedStyle(grid.items[0]);
      if( grid.colStartWidth == 0) {
        grid.colStartWidth = parseFloat(itemStyle.getPropertyValue('width'));
      }
      grid.colGap = parseFloat(itemStyle.getPropertyValue('margin-right'));
    };
  
    function setGridLayout(grid) { // set width of items in the grid
      var containerWidth = parseFloat(window.getComputedStyle(grid.element).getPropertyValue('width'));
      grid.activeColumns = parseInt((containerWidth + grid.colGap)/(grid.colStartWidth+grid.colGap));
      if(grid.activeColumns == 0) grid.activeColumns = 1;
      grid.colWidth = parseFloat((containerWidth - (grid.activeColumns - 1)*grid.colGap)/grid.activeColumns);
      for(var i = 0; i < grid.items.length; i++) {
        grid.items[i].style.width = grid.colWidth+'px'; // reset items width
      }
    };
  
    function initMasonryLayout(grid) {
      if(grid.flexSupported) {
        checkImgLoaded(grid); // reset layout when images are loaded
      } else {
        Util.addClass(grid.element, 'masonry--loaded'); // make sure the gallery is visible
      }
  
      grid.element.addEventListener('masonry-resize', function(){ // window has been resized -> reset masonry layout
        getGridLayout(grid);
        setGridLayout(grid);
        if(grid.flexSupported) layItems(grid); 
      });
  
      grid.element.addEventListener('masonry-reset', function(event){ // reset layout (e.g., new items added to the gallery)
        if(grid.flexSupported) checkImgLoaded(grid); 
      });
    };
  
    function layItems(grid) {
      Util.addClass(grid.element, 'masonry--loaded'); // make sure the gallery is visible
      grid.colHeights = [];
      grid.colItems = [];
  
      // grid layout has already been set -> update container height and order of items
      for(var j = 0; j < grid.activeColumns; j++) {
        grid.colHeights.push(0); // reset col heights
        grid.colItems[j] = []; // reset items order
      }
      
      for(var i = 0; i < grid.items.length; i++) {
        var minHeight = Math.min.apply( Math, grid.colHeights ),
          index = grid.colHeights.indexOf(minHeight);
        if(grid.colItems[index]) grid.colItems[index].push(i);
        grid.items[i].style.flexBasis = 0; // reset flex basis before getting height
        var itemHeight = grid.items[i].getBoundingClientRect().height || grid.items[i].offsetHeight || 1;
        grid.colHeights[index] = grid.colHeights[index] + grid.colGap + itemHeight;
      }
  
      // reset height of container
      var masonryHeight = Math.max.apply( Math, grid.colHeights ) + 5;
      grid.list.style.cssText = 'height: '+ masonryHeight + 'px;';
  
      // go through elements and set flex order
      var order = 0;
      for(var i = 0; i < grid.colItems.length; i++) {
        for(var j = 0; j < grid.colItems[i].length; j++) {
          grid.items[grid.colItems[i][j]].style.order = order;
          order = order + 1;
        }
        // change flex-basis of last element of each column, so that next element shifts to next col
        var lastItemCol = grid.items[grid.colItems[i][grid.colItems[i].length - 1]];
        lastItemCol.style.flexBasis = masonryHeight - grid.colHeights[i] + lastItemCol.getBoundingClientRect().height - 5 + 'px';
      }
  
      // emit custom event when grid has been reset
      grid.element.dispatchEvent(new CustomEvent('masonry-laid'));
    };
  
    function checkImgLoaded(grid) {
      var imgs = grid.list.getElementsByTagName('img');
  
      function countLoaded() {
        var setTimeoutOn = false;
        for(var i = 0; i < imgs.length; i++) {
          if(!imgs[i].complete) {
            setTimeoutOn = true;
            break;
          } else if (typeof imgs[i].naturalHeight !== "undefined" && imgs[i].naturalHeight == 0) {
            setTimeoutOn = true;
            break;
          }
        }
  
        if(!setTimeoutOn) {
          layItems(grid);
        } else {
          setTimeout(function(){
            countLoaded();
          }, 100);
        }
      };
  
      if(imgs.length == 0) {
        layItems(grid); // no need to wait -> no img available
      } else {
        countLoaded();
      }
    };
  
    //initialize the Masonry objects
    var masonries = document.getElementsByClassName('js-masonry'), 
      flexSupported = Util.cssSupports('flex-basis', 'auto'),
      masonriesArray = [];
  
    if( masonries.length > 0) {
      for( var i = 0; i < masonries.length; i++) {
        if(!flexSupported) {
          Util.addClass(masonries[i], 'masonry--loaded'); // reveal gallery
        } else {
          (function(i){masonriesArray.push(new Masonry(masonries[i]));})(i); // init Masonry Layout
        }
      }
  
      if(!flexSupported) return;
  
      // listen to window resize -> reorganize items in gallery
      var resizingId = false,
        customEvent = new CustomEvent('masonry-resize');
        
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 500);
      });
  
      function doneResizing() {
        for( var i = 0; i < masonriesArray.length; i++) {
          (function(i){masonriesArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
    };
  }());
  // File#: _1_menu
  // Usage: codyhouse.co/license
  (function() {
  	var Menu = function(element) {
  		this.element = element;
  		this.elementId = this.element.getAttribute('id');
  		this.menuItems = this.element.getElementsByClassName('js-menu__content');
  		this.trigger = document.querySelectorAll('[aria-controls="'+this.elementId+'"]');
  		this.selectedTrigger = false;
  		this.menuIsOpen = false;
  		this.initMenu();
  		this.initMenuEvents();
  	};	
  
  	Menu.prototype.initMenu = function() {
  		// init aria-labels
  		for(var i = 0; i < this.trigger.length; i++) {
  			Util.setAttributes(this.trigger[i], {'aria-expanded': 'false', 'aria-haspopup': 'true'});
  		}
  		// init tabindex
  		for(var i = 0; i < this.menuItems.length; i++) {
  			this.menuItems[i].setAttribute('tabindex', '0');
  		}
  	};
  
  	Menu.prototype.initMenuEvents = function() {
  		var self = this;
  		for(var i = 0; i < this.trigger.length; i++) {(function(i){
  			self.trigger[i].addEventListener('click', function(event){
  				event.preventDefault();
  				// if the menu had been previously opened by another trigger element -> close it first and reopen in the right position
  				if(Util.hasClass(self.element, 'menu--is-visible') && self.selectedTrigger !=  self.trigger[i]) {
  					self.toggleMenu(false, false); // close menu
  				}
  				// toggle menu
  				self.selectedTrigger = self.trigger[i];
  				self.toggleMenu(!Util.hasClass(self.element, 'menu--is-visible'), true);
  			});
  		})(i);}
  		
  		// keyboard events
  		this.element.addEventListener('keydown', function(event) {
  			// use up/down arrow to navigate list of menu items
  			if( !Util.hasClass(event.target, 'js-menu__content') ) return;
  			if( (event.keyCode && event.keyCode == 40) || (event.key && event.key.toLowerCase() == 'arrowdown') ) {
  				self.navigateItems(event, 'next');
  			} else if( (event.keyCode && event.keyCode == 38) || (event.key && event.key.toLowerCase() == 'arrowup') ) {
  				self.navigateItems(event, 'prev');
  			}
  		});
  	};
  
  	Menu.prototype.toggleMenu = function(bool, moveFocus) {
  		var self = this;
  		// toggle menu visibility
  		Util.toggleClass(this.element, 'menu--is-visible', bool);
  		this.menuIsOpen = bool;
  		if(bool) {
  			this.selectedTrigger.setAttribute('aria-expanded', 'true');
  			Util.moveFocus(this.menuItems[0]);
  			this.element.addEventListener("transitionend", function(event) {Util.moveFocus(self.menuItems[0]);}, {once: true});
  			// position the menu element
  			this.positionMenu();
  			// add class to menu trigger
  			Util.addClass(this.selectedTrigger, 'menu-control--active');
  		} else if(this.selectedTrigger) {
  			this.selectedTrigger.setAttribute('aria-expanded', 'false');
  			if(moveFocus) Util.moveFocus(this.selectedTrigger);
  			// remove class from menu trigger
  			Util.removeClass(this.selectedTrigger, 'menu-control--active');
  			this.selectedTrigger = false;
  		}
  	};
  
  	Menu.prototype.positionMenu = function(event, direction) {
  		var selectedTriggerPosition = this.selectedTrigger.getBoundingClientRect(),
  			menuOnTop = (window.innerHeight - selectedTriggerPosition.bottom) < selectedTriggerPosition.top;
  			// menuOnTop = window.innerHeight < selectedTriggerPosition.bottom + this.element.offsetHeight;
  			
  		var left = selectedTriggerPosition.left,
  			right = (window.innerWidth - selectedTriggerPosition.right),
  			isRight = (window.innerWidth < selectedTriggerPosition.left + this.element.offsetWidth);
  
  		var horizontal = isRight ? 'right: '+right+'px;' : 'left: '+left+'px;',
  			vertical = menuOnTop
  				? 'bottom: '+(window.innerHeight - selectedTriggerPosition.top)+'px;'
  				: 'top: '+selectedTriggerPosition.bottom+'px;';
  		// check right position is correct -> otherwise set left to 0
  		if( isRight && (right + this.element.offsetWidth) > window.innerWidth) horizontal = 'left: '+ parseInt((window.innerWidth - this.element.offsetWidth)/2)+'px;';
  		var maxHeight = menuOnTop ? selectedTriggerPosition.top - 20 : window.innerHeight - selectedTriggerPosition.bottom - 20;
  		this.element.setAttribute('style', horizontal + vertical +'max-height:'+Math.floor(maxHeight)+'px;');
  	};
  
  	Menu.prototype.navigateItems = function(event, direction) {
  		event.preventDefault();
  		var index = Util.getIndexInArray(this.menuItems, event.target),
  			nextIndex = direction == 'next' ? index + 1 : index - 1;
  		if(nextIndex < 0) nextIndex = this.menuItems.length - 1;
  		if(nextIndex > this.menuItems.length - 1) nextIndex = 0;
  		Util.moveFocus(this.menuItems[nextIndex]);
  	};
  
  	Menu.prototype.checkMenuFocus = function() {
  		var menuParent = document.activeElement.closest('.js-menu');
  		if (!menuParent || !this.element.contains(menuParent)) this.toggleMenu(false, false);
  	};
  
  	Menu.prototype.checkMenuClick = function(target) {
  		if( !this.element.contains(target) && !target.closest('[aria-controls="'+this.elementId+'"]')) this.toggleMenu(false);
  	};
  
  	window.Menu = Menu;
  
  	//initialize the Menu objects
  	var menus = document.getElementsByClassName('js-menu');
  	if( menus.length > 0 ) {
  		var menusArray = [];
  		var scrollingContainers = [];
  		for( var i = 0; i < menus.length; i++) {
  			(function(i){
  				menusArray.push(new Menu(menus[i]));
  				var scrollableElement = menus[i].getAttribute('data-scrollable-element');
  				if(scrollableElement && !scrollingContainers.includes(scrollableElement)) scrollingContainers.push(scrollableElement);
  			})(i);
  		}
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key.toLowerCase() == 'tab' ) {
  				//close menu if focus is outside menu element
  				menusArray.forEach(function(element){
  					element.checkMenuFocus();
  				});
  			} else if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
  				// close menu on 'Esc'
  				menusArray.forEach(function(element){
  					element.toggleMenu(false, false);
  				});
  			} 
  		});
  		// close menu when clicking outside it
  		window.addEventListener('click', function(event){
  			menusArray.forEach(function(element){
  				element.checkMenuClick(event.target);
  			});
  		});
  		// on resize -> close all menu elements
  		window.addEventListener('resize', function(event){
  			menusArray.forEach(function(element){
  				element.toggleMenu(false, false);
  			});
  		});
  		// on scroll -> close all menu elements
  		window.addEventListener('scroll', function(event){
  			menusArray.forEach(function(element){
  				if(element.menuIsOpen) element.toggleMenu(false, false);
  			});
  		});
  		// take into account additinal scrollable containers
  		for(var j = 0; j < scrollingContainers.length; j++) {
  			var scrollingContainer = document.querySelector(scrollingContainers[j]);
  			if(scrollingContainer) {
  				scrollingContainer.addEventListener('scroll', function(event){
  					menusArray.forEach(function(element){
  						if(element.menuIsOpen) element.toggleMenu(false, false);
  					});
  				});
  			}
  		}
  	}
  }());
  // File#: _1_modal-window
  // Usage: codyhouse.co/license
  (function() {
  	var Modal = function(element) {
  		this.element = element;
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.moveFocusEl = null; // focus will be moved to this element when modal is open
  		this.modalFocus = this.element.getAttribute('data-modal-first-focus') ? this.element.querySelector(this.element.getAttribute('data-modal-first-focus')) : null;
  		this.selectedTrigger = null;
  		this.preventScrollEl = this.getPreventScrollEl();
  		this.showClass = "modal--is-visible";
  		this.initModal();
  	};
  
  	Modal.prototype.getPreventScrollEl = function() {
  		var scrollEl = false;
  		var querySelector = this.element.getAttribute('data-modal-prevent-scroll');
  		if(querySelector) scrollEl = document.querySelector(querySelector);
  		return scrollEl;
  	};
  
  	Modal.prototype.initModal = function() {
  		var self = this;
  		//open modal when clicking on trigger buttons
  		if ( this.triggers ) {
  			for(var i = 0; i < this.triggers.length; i++) {
  				this.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
  					if(Util.hasClass(self.element, self.showClass)) {
  						self.closeModal();
  						return;
  					}
  					self.selectedTrigger = event.target;
  					self.showModal();
  					self.initModalEvents();
  				});
  			}
  		}
  
  		// listen to the openModal event -> open modal without a trigger button
  		this.element.addEventListener('openModal', function(event){
  			if(event.detail) self.selectedTrigger = event.detail;
  			self.showModal();
  			self.initModalEvents();
  		});
  
  		// listen to the closeModal event -> close modal without a trigger button
  		this.element.addEventListener('closeModal', function(event){
  			if(event.detail) self.selectedTrigger = event.detail;
  			self.closeModal();
  		});
  
  		// if modal is open by default -> initialise modal events
  		if(Util.hasClass(this.element, this.showClass)) this.initModalEvents();
  	};
  
  	Modal.prototype.showModal = function() {
  		var self = this;
  		Util.addClass(this.element, this.showClass);
  		this.getFocusableElements();
  		if(this.moveFocusEl) {
  			this.moveFocusEl.focus();
  			// wait for the end of transitions before moving focus
  			this.element.addEventListener("transitionend", function cb(event) {
  				self.moveFocusEl.focus();
  				self.element.removeEventListener("transitionend", cb);
  			});
  		}
  		this.emitModalEvents('modalIsOpen');
  		// change the overflow of the preventScrollEl
  		if(this.preventScrollEl) this.preventScrollEl.style.overflow = 'hidden';
  	};
  
  	Modal.prototype.closeModal = function() {
  		if(!Util.hasClass(this.element, this.showClass)) return;
  		console.log('close')
  		Util.removeClass(this.element, this.showClass);
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.moveFocusEl = null;
  		if(this.selectedTrigger) this.selectedTrigger.focus();
  		//remove listeners
  		this.cancelModalEvents();
  		this.emitModalEvents('modalIsClose');
  		// change the overflow of the preventScrollEl
  		if(this.preventScrollEl) this.preventScrollEl.style.overflow = '';
  	};
  
  	Modal.prototype.initModalEvents = function() {
  		//add event listeners
  		this.element.addEventListener('keydown', this);
  		this.element.addEventListener('click', this);
  	};
  
  	Modal.prototype.cancelModalEvents = function() {
  		//remove event listeners
  		this.element.removeEventListener('keydown', this);
  		this.element.removeEventListener('click', this);
  	};
  
  	Modal.prototype.handleEvent = function (event) {
  		switch(event.type) {
  			case 'click': {
  				this.initClick(event);
  			}
  			case 'keydown': {
  				this.initKeyDown(event);
  			}
  		}
  	};
  
  	Modal.prototype.initKeyDown = function(event) {
  		if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  			//trap focus inside modal
  			this.trapFocus(event);
  		} else if( (event.keyCode && event.keyCode == 13 || event.key && event.key == 'Enter') && event.target.closest('.js-modal__close')) {
  			event.preventDefault();
  			this.closeModal(); // close modal when pressing Enter on close button
  		}	
  	};
  
  	Modal.prototype.initClick = function(event) {
  		//close modal when clicking on close button or modal bg layer 
  		if( !event.target.closest('.js-modal__close') && !Util.hasClass(event.target, 'js-modal') ) return;
  		event.preventDefault();
  		this.closeModal();
  	};
  
  	Modal.prototype.trapFocus = function(event) {
  		if( this.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of modal
  			event.preventDefault();
  			this.lastFocusable.focus();
  		}
  		if( this.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of modal
  			event.preventDefault();
  			this.firstFocusable.focus();
  		}
  	}
  
  	Modal.prototype.getFocusableElements = function() {
  		//get all focusable elements inside the modal
  		var allFocusable = this.element.querySelectorAll(focusableElString);
  		this.getFirstVisible(allFocusable);
  		this.getLastVisible(allFocusable);
  		this.getFirstFocusable();
  	};
  
  	Modal.prototype.getFirstVisible = function(elements) {
  		//get first visible focusable element inside the modal
  		for(var i = 0; i < elements.length; i++) {
  			if( isVisible(elements[i]) ) {
  				this.firstFocusable = elements[i];
  				break;
  			}
  		}
  	};
  
  	Modal.prototype.getLastVisible = function(elements) {
  		//get last visible focusable element inside the modal
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( isVisible(elements[i]) ) {
  				this.lastFocusable = elements[i];
  				break;
  			}
  		}
  	};
  
  	Modal.prototype.getFirstFocusable = function() {
  		if(!this.modalFocus || !Element.prototype.matches) {
  			this.moveFocusEl = this.firstFocusable;
  			return;
  		}
  		var containerIsFocusable = this.modalFocus.matches(focusableElString);
  		if(containerIsFocusable) {
  			this.moveFocusEl = this.modalFocus;
  		} else {
  			this.moveFocusEl = false;
  			var elements = this.modalFocus.querySelectorAll(focusableElString);
  			for(var i = 0; i < elements.length; i++) {
  				if( isVisible(elements[i]) ) {
  					this.moveFocusEl = elements[i];
  					break;
  				}
  			}
  			if(!this.moveFocusEl) this.moveFocusEl = this.firstFocusable;
  		}
  	};
  
  	Modal.prototype.emitModalEvents = function(eventName) {
  		var event = new CustomEvent(eventName, {detail: this.selectedTrigger});
  		this.element.dispatchEvent(event);
  	};
  
  	function isVisible(element) {
  		return element.offsetWidth || element.offsetHeight || element.getClientRects().length;
  	};
  
  	window.Modal = Modal;
  
  	//initialize the Modal objects
  	var modals = document.getElementsByClassName('js-modal');
  	// generic focusable elements string selector
  	var focusableElString = '[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary';
  	if( modals.length > 0 ) {
  		var modalArrays = [];
  		for( var i = 0; i < modals.length; i++) {
  			(function(i){modalArrays.push(new Modal(modals[i]));})(i);
  		}
  
  		window.addEventListener('keydown', function(event){ //close modal window on esc
  			if(event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape') {
  				for( var i = 0; i < modalArrays.length; i++) {
  					(function(i){modalArrays[i].closeModal();})(i);
  				};
  			}
  		});
  	}
  }());
  // File#: _1_newsletter-input
  // Usage: codyhouse.co/license
  (function() {
    var NewsInput = function(opts) {
      this.options = Util.extend(NewsInput.defaults, opts);
      this.element = this.options.element;
      this.input = this.element.getElementsByClassName('js-news-form__input');
      this.button = this.element.getElementsByClassName('js-news-form__btn');
      this.submitting = false;
      initNewsInput(this);
    };
  
    function initNewsInput(element) {
      if(element.input.length < 1 || element.input.button < 1) return;
      // check email value
      element.input[0].addEventListener('input', function(event){
        // hide success/error messages
        Util.removeClass(element.element, 'news-form--success news-form--error');
        // enable/disable form
        checkEmailFormat(element);
      });
  
      // animate newsletter when submitting form 
      element.element.addEventListener('submit', function(event){
        event.preventDefault();
        if(element.submitting) return;
        element.submitting = true;
        element.response = false;
        
        // start button animation
        Util.addClass(element.element, 'news-form--loading news-form--circle-loop');
        // at the end of each animation cicle, restart animation if there was no response from the submit function yet
        element.element.addEventListener('animationend', function cb(event){
          if(element.response) { // complete button animation
            element.element.removeEventListener('animationend', cb);
            showResponseMessage(element, element.response);
          } else { // keep loading animation going
            Util.removeClass(element.element, 'news-form--circle-loop');
            element.element.offsetWidth;
            Util.addClass(element.element, 'news-form--circle-loop');
          }
        });
        
        // custom submit function
        element.options.submit(element.input[0].value, function(response){
          element.response = response;
          element.submitting = false;
          if(!animationSupported) showResponseMessage(element, response);
        });
      });
    };
  
    function showResponseMessage(element, response) {
      Util.removeClass(element.element, 'news-form--loading news-form--circle-loop');
      (response == 'success')
        ? Util.addClass(element.element, 'news-form--success')
        : Util.addClass(element.element, 'news-form--error');
    };
  
    function checkEmailFormat(element) {
      var email = element.input[0].value;
      var atPosition = email.indexOf("@"),
        dotPosition = email.lastIndexOf("."); 
      var enableForm = (atPosition >= 1 && dotPosition >= atPosition + 2 && dotPosition < email.length - 1);
      if(enableForm) {
        Util.addClass(element.element, 'news-form--enabled');
        element.button[0].removeAttribute('disabled');
      } else {
        Util.removeClass(element.element, 'news-form--enabled');
        element.button[0].setAttribute('disabled', true);
      }
    };
  
    window.NewsInput = NewsInput;
  
    NewsInput.defaults = {
      element : '',
      submit: false, // function used to return results
    };
  
    var animationSupported = Util.cssSupports('animation', 'name');
  }());
  // File#: _1_notice
  // Usage: codyhouse.co/license
  (function() {
    function initNoticeEvents(notice) {
      notice.addEventListener('click', function(event){
        if(event.target.closest('.js-notice__hide-control')) {
          event.preventDefault();
          Util.addClass(notice, 'notice--hide');
        }
      });
    };
    
    var noticeElements = document.getElementsByClassName('js-notice');
    if(noticeElements.length > 0) {
      for(var i=0; i < noticeElements.length; i++) {(function(i){
        initNoticeEvents(noticeElements[i]);
      })(i);}
    }
  }());
  // File#: _1_number-input
  // Usage: codyhouse.co/license
  (function() {
  	var InputNumber = function(element) {
  		this.element = element;
  		this.input = this.element.getElementsByClassName('js-number-input__value')[0];
  		this.min = parseFloat(this.input.getAttribute('min'));
  		this.max = parseFloat(this.input.getAttribute('max'));
  		this.step = parseFloat(this.input.getAttribute('step'));
  		if(isNaN(this.step)) this.step = 1;
  		this.precision = getStepPrecision(this.step);
  		initInputNumberEvents(this);
  	};
  
  	function initInputNumberEvents(input) {
  		// listen to the click event on the custom increment buttons
  		input.element.addEventListener('click', function(event){ 
  			var increment = event.target.closest('.js-number-input__btn');
  			if(increment) {
  				event.preventDefault();
  				updateInputNumber(input, increment);
  			}
  		});
  
  		// when input changes, make sure the new value is acceptable
  		input.input.addEventListener('focusout', function(event){
  			var value = parseFloat(input.input.value);
  			if( value < input.min ) value = input.min;
  			if( value > input.max ) value = input.max;
  			// check value is multiple of step
  			value = checkIsMultipleStep(input, value);
  			if( value != parseFloat(input.input.value)) input.input.value = value;
  
  		});
  	};
  
  	function getStepPrecision(step) {
  		// if step is a floating number, return its precision
  		return (step.toString().length - Math.floor(step).toString().length - 1);
  	};
  
  	function updateInputNumber(input, btn) {
  		var value = ( Util.hasClass(btn, 'number-input__btn--plus') ) ? parseFloat(input.input.value) + input.step : parseFloat(input.input.value) - input.step;
  		if( input.precision > 0 ) value = value.toFixed(input.precision);
  		if( value < input.min ) value = input.min;
  		if( value > input.max ) value = input.max;
  		input.input.value = value;
  		input.input.dispatchEvent(new CustomEvent('change', {bubbles: true})); // trigger change event
  	};
  
  	function checkIsMultipleStep(input, value) {
  		// check if the number inserted is a multiple of the step value
  		var remain = (value*10*input.precision)%(input.step*10*input.precision);
  		if( remain != 0) value = value - remain;
  		if( input.precision > 0 ) value = value.toFixed(input.precision);
  		return value;
  	};
  
  	//initialize the InputNumber objects
  	var inputNumbers = document.getElementsByClassName('js-number-input');
  	if( inputNumbers.length > 0 ) {
  		for( var i = 0; i < inputNumbers.length; i++) {
  			(function(i){new InputNumber(inputNumbers[i]);})(i);
  		}
  	}
  }());
  // File#: _1_off-canvas-content
  // Usage: codyhouse.co/license
  (function() {
  	var OffCanvas = function(element) {
  		this.element = element;
  		this.wrapper = document.getElementsByClassName('js-off-canvas')[0];
  		this.main = document.getElementsByClassName('off-canvas__main')[0];
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.closeBtn = this.element.getElementsByClassName('js-off-canvas__close-btn');
  		this.selectedTrigger = false;
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.animating = false;
  		initOffCanvas(this);
  	};	
  
  	function initOffCanvas(panel) {
  		panel.element.setAttribute('aria-hidden', 'true');
  		for(var i = 0 ; i < panel.triggers.length; i++) { // listen to the click on off-canvas content triggers
  			panel.triggers[i].addEventListener('click', function(event){
  				panel.selectedTrigger = event.currentTarget;
  				event.preventDefault();
  				togglePanel(panel);
  			});
  		}
  
  		// listen to the triggerOpenPanel event -> open panel without a trigger button
  		panel.element.addEventListener('triggerOpenPanel', function(event){
  			if(event.detail) panel.selectedTrigger = event.detail;
  			openPanel(panel);
  		});
  		// listen to the triggerClosePanel event -> open panel without a trigger button
  		panel.element.addEventListener('triggerClosePanel', function(event){
  			closePanel(panel);
  		});
  	};
  
  	function togglePanel(panel) {
  		var status = (panel.element.getAttribute('aria-hidden') == 'true') ? 'close' : 'open';
  		if(status == 'close') openPanel(panel);
  		else closePanel(panel);
  	};
  
  	function openPanel(panel) {
  		if(panel.animating) return; // already animating
  		emitPanelEvents(panel, 'openPanel', '');
  		panel.animating = true;
  		panel.element.setAttribute('aria-hidden', 'false');
  		Util.addClass(panel.wrapper, 'off-canvas--visible');
  		getFocusableElements(panel);
  		var transitionEl = panel.element;
  		if(panel.closeBtn.length > 0 && !Util.hasClass(panel.closeBtn[0], 'js-off-canvas__a11y-close-btn')) transitionEl = 	panel.closeBtn[0];
  		transitionEl.addEventListener('transitionend', function cb(){
  			// wait for the end of transition to move focus and update the animating property
  			panel.animating = false;
  			Util.moveFocus(panel.element);
  			transitionEl.removeEventListener('transitionend', cb);
  		});
  		if(!transitionSupported) panel.animating = false;
  		initPanelEvents(panel);
  	};
  
  	function closePanel(panel, bool) {
  		if(panel.animating) return;
  		panel.animating = true;
  		panel.element.setAttribute('aria-hidden', 'true');
  		Util.removeClass(panel.wrapper, 'off-canvas--visible');
  		panel.main.addEventListener('transitionend', function cb(){
  			panel.animating = false;
  			if(panel.selectedTrigger) panel.selectedTrigger.focus();
  			setTimeout(function(){panel.selectedTrigger = false;}, 10);
  			panel.main.removeEventListener('transitionend', cb);
  		});
  		if(!transitionSupported) panel.animating = false;
  		cancelPanelEvents(panel);
  		emitPanelEvents(panel, 'closePanel', bool);
  	};
  
  	function initPanelEvents(panel) { //add event listeners
  		panel.element.addEventListener('keydown', handleEvent.bind(panel));
  		panel.element.addEventListener('click', handleEvent.bind(panel));
  	};
  
  	function cancelPanelEvents(panel) { //remove event listeners
  		panel.element.removeEventListener('keydown', handleEvent.bind(panel));
  		panel.element.removeEventListener('click', handleEvent.bind(panel));
  	};
  
  	function handleEvent(event) {
  		switch(event.type) {
  			case 'keydown':
  				initKeyDown(this, event);
  				break;
  			case 'click':
  				initClick(this, event);
  				break;
  		}
  	};
  
  	function initClick(panel, event) { // close panel when clicking on close button
  		if( !event.target.closest('.js-off-canvas__close-btn')) return;
  		event.preventDefault();
  		closePanel(panel, 'close-btn');
  	};
  
  	function initKeyDown(panel, event) {
  		if( event.keyCode && event.keyCode == 27 || event.key && event.key == 'Escape' ) {
  			//close off-canvas panel on esc
  			closePanel(panel, 'key');
  		} else if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  			//trap focus inside panel
  			trapFocus(panel, event);
  		}
  	};
  
  	function trapFocus(panel, event) {
  		if( panel.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of panel
  			event.preventDefault();
  			panel.lastFocusable.focus();
  		}
  		if( panel.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of panel
  			event.preventDefault();
  			panel.firstFocusable.focus();
  		}
  	};
  
  	function getFocusableElements(panel) { //get all focusable elements inside the off-canvas content
  		var allFocusable = panel.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(panel, allFocusable);
  		getLastVisible(panel, allFocusable);
  	};
  
  	function getFirstVisible(panel, elements) { //get first visible focusable element inside the off-canvas content
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				panel.firstFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	function getLastVisible(panel, elements) { //get last visible focusable element inside the off-canvas content
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				panel.lastFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	function emitPanelEvents(panel, eventName, target) { // emit custom event
  		var event = new CustomEvent(eventName, {detail: target});
  		panel.element.dispatchEvent(event);
  	};
  
  	//initialize the OffCanvas objects
  	var offCanvas = document.getElementsByClassName('js-off-canvas__panel'),
  		transitionSupported = Util.cssSupports('transition');
  	if( offCanvas.length > 0 ) {
  		for( var i = 0; i < offCanvas.length; i++) {
  			(function(i){new OffCanvas(offCanvas[i]);})(i);
  		}
  	}
  }());
  // File#: _1_overscroll-section
  // Usage: codyhouse.co/license
  (function() {
    var OverscrollSection = function(element) {
      this.element = element;
      this.stickyContent = this.element.getElementsByClassName('js-overscroll-section__sticky-content');
      this.scrollContent = this.element.getElementsByClassName('js-overscroll-section__scroll-content');
      this.scrollingFn = false;
      this.scrolling = false;
      this.resetOpacity = false;
      this.disabledClass = 'overscroll-section--disabled';
      initOverscrollSection(this);
    };
  
    function initOverscrollSection(element) {
      // set position of sticky element
      setTop(element);
      // create a new node - to be inserted before the scroll element
      createPrevElement(element);
      // on resize -> reset element top position
      element.element.addEventListener('update-overscroll-section', function(){
        setTop(element);
        setPrevElementTop(element);
      });
      // set initial opacity value
      animateOverscrollSection.bind(element)(); 
      // change opacity of layer
      var observer = new IntersectionObserver(overscrollSectionCallback.bind(element));
      observer.observe(element.prevElement);
    };
  
    function createPrevElement(element) {
      if(element.scrollContent.length == 0) return;
      var newElement = document.createElement("div"); 
      newElement.setAttribute('aria-hidden', 'true');
      element.element.insertBefore(newElement, element.scrollContent[0]);
      element.prevElement =  element.scrollContent[0].previousElementSibling;
      element.prevElement.style.opacity = '0';
      setPrevElementTop(element);
    };
  
    function setPrevElementTop(element) {
      element.prevElementTop = element.prevElement.getBoundingClientRect().top + window.scrollY;
    };
  
    function overscrollSectionCallback(entries) {
      if(entries[0].isIntersecting) {
        if(this.scrollingFn) return; // listener for scroll event already added
        overscrollSectionInitEvent(this);
      } else {
        if(!this.scrollingFn) return; // listener for scroll event already removed
        window.removeEventListener('scroll', this.scrollingFn);
        updateOpacityValue(this, 0);
        this.scrollingFn = false;
      }
    };
  
    function overscrollSectionInitEvent(element) {
      element.scrollingFn = overscrollSectionScrolling.bind(element);
      window.addEventListener('scroll', element.scrollingFn);
    };
  
    function overscrollSectionScrolling() {
      if(this.scrolling) return;
      this.scrolling = true;
      window.requestAnimationFrame(animateOverscrollSection.bind(this));
    };
  
    function animateOverscrollSection() {
      if(this.stickyContent.length == 0) return;
      setPrevElementTop(this);
      if( parseInt(this.stickyContent[0].style.top) != window.innerHeight - this.stickyContent[0].offsetHeight) {
        setTop(this);
      }
      if(this.prevElementTop - window.scrollY < window.innerHeight*2/3) {
        var opacity = Math.easeOutQuart(window.innerHeight*2/3 + window.scrollY - this.prevElementTop, 0, 1, window.innerHeight*2/3);
        if(opacity > 0 ) {
          this.resetOpacity = false;
          updateOpacityValue(this, opacity);
        } else if(!this.resetOpacity) {
          this.resetOpacity = true;
          updateOpacityValue(this, 0);
        } 
      } else {
        updateOpacityValue(this, 0);
      }
      this.scrolling = false;
    };
  
    function updateOpacityValue(element, value) {
      element.element.style.setProperty('--overscroll-section-opacity', value);
    };
  
    function setTop(element) {
      if(element.stickyContent.length == 0) return;
      var translateValue = window.innerHeight - element.stickyContent[0].offsetHeight;
      element.stickyContent[0].style.top = translateValue+'px';
      // check if effect should be disabled
      Util.toggleClass(element.element, element.disabledClass, translateValue > 2);
    };
  
    //initialize the OverscrollSection objects
    var overscrollSections = document.getElementsByClassName('js-overscroll-section');
    var stickySupported = Util.cssSupports('position', 'sticky') || Util.cssSupports('position', '-webkit-sticky'),
      intObservSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
  	if( overscrollSections.length > 0 && stickySupported && !reducedMotion && intObservSupported) {
      var overscrollSectionsArray = [];
  		for( var i = 0; i < overscrollSections.length; i++) {
        (function(i){overscrollSectionsArray.push(new OverscrollSection(overscrollSections[i]));})(i);
      }
      
      var resizingId = false,
        customEvent = new CustomEvent('update-overscroll-section');
  
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 100);
      });
  
      // wait for font to be loaded
      document.fonts.onloadingdone = function (fontFaceSetEvent) {
        doneResizing();
      };
  
      function doneResizing() {
        for( var i = 0; i < overscrollSectionsArray.length; i++) {
          (function(i){overscrollSectionsArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  	}
  }());
  // File#: _1_page-transition
  // Usage: codyhouse.co/license
  (function() {
    var PageTransition = function(opts) {
      if(!('CSS' in window) || !CSS.supports('color', 'var(--color)')) return;
      this.element = document.getElementsByClassName('js-page-trans')[0];
      this.options = Util.extend(PageTransition.defaults , opts);
      this.cachedPages = [];
      this.anchors = false;
      this.clickFunctions = [];
      this.animating = false;
      this.newContent = false;
      this.containerClass = 'js-page-trans__content';
      this.containers = [];
      initSrRegion(this);
      pageTrInit(this);
      initBrowserHistory(this);
    };
  
    function initSrRegion(element) {
      var liveRegion = document.createElement('p');
      Util.setAttributes(liveRegion, {'class': 'sr-only', 'role': 'alert', 'aria-live': 'polite', 'id': 'page-trans-sr-live'});
      element.element.appendChild(liveRegion);
      element.srLive = document.getElementById('page-trans-sr-live');
    };
  
    function pageTrInit(element) { // bind click events
      element.anchors = document.getElementsByClassName('js-page-trans-link');
      for(var i = 0; i < element.anchors.length; i++) {
        (function(i){
          element.clickFunctions[i] = function(event) {
            event.preventDefault();
            element.updateBrowserHistory = true;
            bindClick(element, element.anchors[i].getAttribute('href'));
          };
  
          element.anchors[i].addEventListener('click', element.clickFunctions[i]);
        })(i);
      }
    };
  
    function bindClick(element, link) {
      if(element.animating) return;
      element.animating = true;
      element.link = link; 
      // most of those links will be removed from the page
      unbindClickEvents(element);
      loadPageContent(element); 
      // code that should run before the leaving animation
      if(element.options.beforeLeave) element.options.beforeLeave(element.link);
      // announce to SR new content is being loaded
      element.srLive.textContent = element.options.srLoadingMessage;
      // leaving animation
      if(!element.options.leaveAnimation) return;
      element.containers.push(element.element.getElementsByClassName(element.containerClass)[0]);
      element.options.leaveAnimation(element.containers[0], element.link, function(){
        leavingAnimationComplete(element, true);
      });
    };
  
    function unbindClickEvents(element) {
      for(var i = 0; i < element.anchors.length; i++) {
        element.anchors[i].removeEventListener('click', element.clickFunctions[i]);
      }
    };
  
    function loadPageContent(element) {
      element.newContent = false;
      var pageCache = getCachedPage(element);
      if(pageCache) {
        element.newContent = pageCache;
      } else {
        if(element.options.loadFunction) { // use a custom function to load your data
          element.options.loadFunction(element.link, function(data){
            element.newContent = data;
            element.cachedPages.push({link: element.link, content: element.newContent});
          });
        } else {
          // load page content
          var xmlHttp = new XMLHttpRequest();
          xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
              element.newContent = getContainerHTML(element, xmlHttp.responseText);
              element.cachedPages.push({link: element.link, content: element.newContent});
            }
          };
          xmlHttp.open('GET', element.link);
          xmlHttp.send();
        }
      }
    };
  
    function leavingAnimationComplete(element, triggerProgress) {
      if(element.newContent) {
        // new content has already been created
        triggerEnteringProcess(element);
      } else {
        // new content is not available yet
        if(triggerProgress && element.options.progressAnimation) element.options.progressAnimation(element.link);
        setTimeout(function(){
          leavingAnimationComplete(element, false);
        }, 200);
      }
    };
  
    function getCachedPage(element) {
      var cachedContent = false;
      for(var i = 0; i < element.cachedPages.length; i++) {
        if(element.cachedPages[i].link == element.link) {
          cachedContent = element.cachedPages[i].content;
          break;
        }
      }
      return cachedContent;
    };
  
    function getContainerHTML(element, content) {
      var template = document.createElement('div');
      template.innerHTML = content;
      return template.getElementsByClassName(element.containerClass)[0].outerHTML;
    };
  
    function triggerEnteringProcess(element) {
      if(element.updateBrowserHistory) updateBrowserHistory(element);
      // inject new content
      element.containers[0].insertAdjacentHTML('afterend', element.newContent);
      element.containers = element.element.getElementsByClassName(element.containerClass);
      if(element.options.beforeEnter) element.options.beforeEnter(element.containers[0], element.containers[1], element.link);
      if(!element.options.enterAnimation) return; // entering animation
      element.options.enterAnimation(element.containers[0], element.containers[1], element.link, function(){
        // move focus to new cntent
        Util.moveFocus(element.containers[1]);
        // new content
        var newContent = element.containers[1];
        // remove old content
        element.containers[0].remove();
        if(element.options.afterEnter) element.options.afterEnter(newContent, element.link);
        pageTrInit(element); // bind click event to new anchor elements
        resetPageTransition(element);
        // announce to SR new content is available
        element.srLive.textContent = element.options.srLoadedMessage;
      });
    };
  
    function resetPageTransition(element) {
      // remove old content
      element.newContent = false;
      element.animating = false;
      element.containers = [];
      element.link = false;
    };
  
    function updateBrowserHistory(element) {
      if(window.history.state && window.history.state == element.link) return;
      window.history.pushState({path: element.link},'',element.link);
    };
  
    function initBrowserHistory(element) {
      setTimeout(function() {
        // on load -> replace window history with page url
        window.history.replaceState({path: document.location.href},'',document.location.href);
        window.addEventListener('popstate', function(event) {
          element.updateBrowserHistory = false;
          if(event.state && event.state.path) {
            bindClick(element, event.state.path);
          }
        });
      }, 10);
    };
  
    PageTransition.defaults = {
      beforeLeave: false, // run before the leaving animation is triggered
      leaveAnimation: false,
      progressAnimation: false,
      beforeEnter: false, // run before enterAnimation (after new content has been added to the page)
      enterAnimation: false,
      afterEnter: false,
      loadFunction: false,
      srLoadingMessage: 'New content is being loaded',
      srLoadedMessage: 'New content has been loaded' 
    };
  
    window.PageTransition = PageTransition;
  }());
  // File#: _1_parallax-image
  // Usage: codyhouse.co/license
  (function() {
    var ParallaxImg = function(element, rotationLevel) {
      this.element = element;
      this.figure = this.element.getElementsByClassName('js-parallax-img__assets')[0];
      this.imgs = this.element.getElementsByTagName('img');
      this.maxRotation = rotationLevel || 2; // rotate level
      if(this.maxRotation > 5) this.maxRotation = 5;
      this.scale = 1;
      this.animating = false;
      initParallax(this);
      initParallaxEvents(this);
    };
  
    function initParallax(element) {
      element.count = 0;
      window.requestAnimationFrame(checkImageLoaded.bind(element));
      for(var i = 0; i < element.imgs.length; i++) {(function(i){
        var loaded = false;
        element.imgs[i].addEventListener('load', function(){
          if(loaded) return;
          element.count = element.count + 1;
        });
        if(element.imgs[i].complete && !loaded) {
          loaded = true;
          element.count = element.count + 1;
        }
      })(i);}
    };
  
    function checkImageLoaded() {
      if(this.count >= this.imgs.length) {
        initScale(this);
        if(this.loaded) {
          window.cancelAnimationFrame(this.loaded);
          this.loaded = false;
        }
      } else {
        this.loaded = window.requestAnimationFrame(checkImageLoaded.bind(this));
      }
    };
  
    function initScale(element) {
      var maxImgResize = getMaxScale(element);
      element.scale = maxImgResize/(Math.sin(Math.PI / 2 - element.maxRotation*Math.PI/180));
      element.figure.style.transform = 'scale('+element.scale+')';  
      Util.addClass(element.element, 'parallax-img--loaded');  
    };
  
    function getMaxScale(element) {
      var minWidth = 0;
      var maxWidth = 0;
      for(var i = 0; i < element.imgs.length; i++) {
        var width = element.imgs[i].getBoundingClientRect().width;
        if(width < minWidth || i == 0 ) minWidth = width;
        if(width > maxWidth || i == 0 ) maxWidth = width;
      }
      var scale = Math.ceil(10*maxWidth/minWidth)/10;
      if(scale < 1.1) scale = 1.1;
      return scale;
    }
  
    function initParallaxEvents(element) {
      element.element.addEventListener('mousemove', function(event){
        if(element.animating) return;
        element.animating = true;
        window.requestAnimationFrame(moveImage.bind(element, event));
      });
    };
  
    function moveImage(event, timestamp) {
      var wrapperPosition = this.element.getBoundingClientRect();
      var rotateY = 2*(this.maxRotation/wrapperPosition.width)*(wrapperPosition.left - event.clientX + wrapperPosition.width/2);
      var rotateX = 2*(this.maxRotation/wrapperPosition.height)*(event.clientY - wrapperPosition.top - wrapperPosition.height/2);
  
      if(rotateY > this.maxRotation) rotateY = this.maxRotation;
  		if(rotateY < -1*this.maxRotation) rotateY = -this.maxRotation;
  		if(rotateX > this.maxRotation) rotateX = this.maxRotation;
      if(rotateX < -1*this.maxRotation) rotateX = -this.maxRotation;
      this.figure.style.transform = 'scale('+this.scale+') rotateX('+rotateX+'deg) rotateY('+rotateY+'deg)';
      this.animating = false;
    };
  
    window.ParallaxImg = ParallaxImg;
  
    //initialize the ParallaxImg objects
  	var parallaxImgs = document.getElementsByClassName('js-parallax-img');
  	if( parallaxImgs.length > 0 && Util.cssSupports('transform', 'translateZ(0px)')) {
  		for( var i = 0; i < parallaxImgs.length; i++) {
  			(function(i){
          var rotationLevel = parallaxImgs[i].getAttribute('data-perspective');
          new ParallaxImg(parallaxImgs[i], rotationLevel);
        })(i);
  		}
  	};
  }());
  // File#: _1_password
  // Usage: codyhouse.co/license
  (function() {
  	var Password = function(element) {
  		this.element = element;
  		this.password = this.element.getElementsByClassName('js-password__input')[0];
  		this.visibilityBtn = this.element.getElementsByClassName('js-password__btn')[0];
  		this.visibilityClass = 'password--text-is-visible';
  		this.initPassword();
  	};
  
  	Password.prototype.initPassword = function() {
  		var self = this;
  		//listen to the click on the password btn
  		this.visibilityBtn.addEventListener('click', function(event) {
  			//if password is in focus -> do nothing if user presses Enter
  			if(document.activeElement === self.password) return;
  			event.preventDefault();
  			self.togglePasswordVisibility();
  		});
  	};
  
  	Password.prototype.togglePasswordVisibility = function() {
  		var makeVisible = !Util.hasClass(this.element, this.visibilityClass);
  		//change element class
  		Util.toggleClass(this.element, this.visibilityClass, makeVisible);
  		//change input type
  		(makeVisible) ? this.password.setAttribute('type', 'text') : this.password.setAttribute('type', 'password');
  	};
  	
  	//initialize the Password objects
  	var passwords = document.getElementsByClassName('js-password');
  	if( passwords.length > 0 ) {
  		for( var i = 0; i < passwords.length; i++) {
  			(function(i){new Password(passwords[i]);})(i);
  		}
  	};
  }());
  // File#: _1_percentage-bar
  // Usage: codyhouse.co/license
  (function() {
    var PercentageBar = function(element) {
      this.element = element;
      this.bar = this.element.getElementsByClassName('js-pct-bar__bg');
      this.percentages = this.element.getElementsByClassName('js-pct-bar__value');
      initPercentageBar(this);
    };
  
    function initPercentageBar(bar) {
      if(bar.bar.length < 1) return;
      var content = '';
      for(var i = 0; i < bar.percentages.length; i++) {
        var customClass = bar.percentages[i].getAttribute('data-pct-bar-bg'),
          customStyle = bar.percentages[i].getAttribute('data-pct-bar-style'),
          percentage = bar.percentages[i].textContent;
        
        if(!customStyle) customStyle = '';
        if(!customClass) customClass = '';
        content = content + '<div class="pct-bar__fill js-pct-bar__fill '+customClass+'" style="flex-basis: '+percentage+';'+customStyle+'"></div>';
      }
      bar.bar[0].innerHTML = content;
    }
  
    window.PercentageBar = PercentageBar;
  
    //initialize the PercentageBar objects
    var percentageBar = document.getElementsByClassName('js-pct-bar');
    if( percentageBar.length > 0 ) {
  		for( var i = 0; i < percentageBar.length; i++) {
  			(function(i){new PercentageBar(percentageBar[i]);})(i);
      }
  	}
  }());
  // File#: _1_pie-chart
  // Usage: codyhouse.co/license
  (function() {
    var PieChart = function(opts) {
      this.options = Util.extend(PieChart.defaults , opts);
      this.element = this.options.element;
      this.chartArea = this.element.getElementsByClassName('js-pie-chart__area')[0];
      this.dataValues = this.element.getElementsByClassName('js-pie-chart__value');
      this.chartPaths;
      // used to convert data values to percentages
      this.percentageTot = 0; 
      this.percentageReset = getPercentageMultiplier(this);
      this.percentageStart = []; // store the start angle for each item in the chart
      this.percentageDelta = []; // store the end angle for each item in the chart
      // tooltip element
      this.tooltip = this.element.getElementsByClassName('js-pie-chart__tooltip');
      this.eventIds = [];
      this.hoverId = false;
      this.hovering = false;
      this.selectedIndex = false; // will be used for tooltip 
      this.chartLoaded = false; // used when chart is initially animated
      initPieChart(this);
      initTooltip(this);
    };
  
    function getPercentageMultiplier(chart) {
      var tot = 0;
      for(var i = 0; i < chart.dataValues.length; i++) {
        tot = tot + parseFloat(chart.dataValues[i].textContent);
      }
      return 100/tot;
    };
  
    function initPieChart(chart) {
      createChart(chart);
      animateChart(chart);
      // reset chart on resize (if required)
      resizeChart(chart);
    };
  
    function createChart(chart) {
      setChartSize(chart);
      // create svg element
      createChartSvg(chart);
      // visually hide svg element
      chart.chartArea.setAttribute('aria-hidden', true);
    };
  
    function setChartSize(chart) {
      chart.height = chart.chartArea.clientHeight;
      chart.width = chart.chartArea.clientWidth;
      // donut charts only
      if(chart.options.type == 'donut') {
        chart.donutSize = parseInt(getComputedStyle(chart.element).getPropertyValue('--pie-chart-donut-width'));
        if(chart.donutSize <= 0 || isNaN(chart.donutSize)) chart.donutSize = chart.width/4; 
      }
    };
  
    function createChartSvg(chart) {
      var svg = '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="'+chart.width+'" height="'+chart.height+'" class="pie-chart__svg js-pie-chart__svg"></svg>';
      chart.chartArea.innerHTML = chart.chartArea.innerHTML + svg;
      chart.svg = chart.chartArea.getElementsByClassName('js-pie-chart__svg')[0];
      // create chart content
      getPieSvgCode(chart);
    };
  
    function getPieSvgCode(chart) {
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      gEl.setAttribute('class', 'pie-chart__dataset js-pie-chart__dataset');
      for(var i = 0; i < chart.dataValues.length; i++) {
        var pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        Util.setAttributes(pathEl, {d: getPiePath(chart, i), class: 'pie-chart__data-path pie-chart__data-path--'+(i+1)+' js-pie-chart__data-path js-pie-chart__data-path--'+(i+1), 'data-index': i, 'stroke-linejoin': 'round'});
        var customStyle = chart.dataValues[i].getAttribute('data-pie-chart-style');
        if(customStyle) pathEl.setAttribute('style', customStyle);
        gEl.appendChild(pathEl);
      }
  
      chart.svg.appendChild(gEl);
      chart.chartPaths = chart.svg.querySelectorAll('.js-pie-chart__data-path');
    };
  
    function getPiePath(chart, index) {
      var startAngle = chart.percentageTot*chart.percentageReset*3.6; //convert from percentage to angles
      var dataValue = parseFloat(chart.dataValues[index].textContent);
      // update percentage start
      chart.percentageStart.push(startAngle);
      chart.percentageDelta.push(dataValue*chart.percentageReset*3.6);
      chart.percentageTot = chart.percentageTot + dataValue;
      var endAngle = chart.percentageTot*chart.percentageReset*3.6;
      return getPathCode(chart, startAngle, endAngle);
    };
  
    function getPathCode(chart, startAngle, endAngle) {
      // if we still need to animate the chart -> reset endAngle
      if(!chart.chartLoaded && chart.options.animate && intersectionObserver && ! reducedMotion) {
        endAngle = startAngle;
      }
      if(chart.options.type == 'pie') {
        return getPieArc(chart.width/2, chart.width/2, chart.width/2, startAngle, endAngle);
      } else { //donut
        return getDonutArc(chart.width/2, chart.width/2, chart.width/2, chart.donutSize, startAngle, endAngle);
      }
    };
  
    function initTooltip(chart) {
      if(chart.tooltip.length < 1) return;
      // init mouse events
      chart.eventIds['hover'] = handleEvent.bind(chart);
      chart.chartArea.addEventListener('mouseenter', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mousedown', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mousemove', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mouseleave', chart.eventIds['hover']);
    };
  
    function handleEvent(event) {
  		switch(event.type) {
  			case 'mouseenter':
        case 'mousedown':
  				hoverChart(this, event);
          break;
  			case 'mousemove': 
          var self = this;
  				self.hoverId  = window.requestAnimationFrame 
            ? window.requestAnimationFrame(function(){hoverChart(self, event)})
            : setTimeout(function(){hoverChart(self, event);});
          break;
  			case 'mouseleave':
  				resetTooltip(this);
          break;
  		}
    };
  
    function hoverChart(chart, event) {
      if(chart.hovering) return;
      chart.hovering = true;
      var selectedIndex = getSelectedIndex(event);
      if(selectedIndex !== false && selectedIndex !== chart.selectedIndex) {
        chart.selectedIndex = selectedIndex;
        setTooltipContent(chart);
        placeTooltip(chart);
        Util.removeClass(chart.tooltip[0], 'is-hidden');
      }
      chart.hovering = false;
    };
  
    function resetTooltip(chart) {
      if(chart.hoverId) {
        (window.requestAnimationFrame) ? window.cancelAnimationFrame(chart.hoverId) : clearTimeout(chart.hoverId);
        chart.hoverId = false;
      }
      Util.addClass(chart.tooltip[0], 'is-hidden');
      chart.hovering = false;
      chart.selectedIndex = false;
    };
  
    function placeTooltip(chart) {
      var tooltipRadialPosition = (chart.options.type == 'donut') ? (chart.width - chart.donutSize)/2 : chart.width/4;
      var pathCenter = polarToCartesian(chart.width/2, chart.width/2, tooltipRadialPosition, chart.percentageStart[chart.selectedIndex] + chart.percentageDelta[chart.selectedIndex]/2);
  
      chart.tooltip[0].setAttribute('style', 'left: '+pathCenter.x+'px; top: '+pathCenter.y+'px');
    };
  
    function setTooltipContent(chart) {
      chart.tooltip[0].textContent = chart.dataValues[chart.selectedIndex].textContent;
    };
  
    function getSelectedIndex(event) {
      if(event.target.tagName.toLowerCase() == 'path') {
        return parseInt(event.target.getAttribute('data-index'));
      }
      return false;
    };
  
    function resizeChart(chart) {
      window.addEventListener('resize', function() {
        clearTimeout(chart.eventIds['resize']);
        chart.eventIds['resize'] = setTimeout(doneResizing, 300);
      });
  
      function doneResizing() {
        resetChartResize(chart);
        removeChart(chart);
        createChart(chart);
        initTooltip(chart);
      };
    };
  
    function resetChartResize(chart) {
      chart.hovering = false;
      // reset event listeners
      if( chart.eventIds && chart.eventIds['hover']) {
        chart.chartArea.removeEventListener('mouseenter', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mousedown', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mousemove', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mouseleave', chart.eventIds['hover']);
      }
    };
  
    function removeChart(chart) {
      // on resize -> remove svg and create a new one
      chart.svg.remove();
    };
  
    function animateChart(chart) {
      if(!chart.options.animate || chart.chartLoaded || reducedMotion || !intersectionObserver) return;
      var observer = new IntersectionObserver(chartObserve.bind(chart), {rootMargin: "0px 0px -200px 0px"});
      observer.observe(chart.element);
    };
  
    function chartObserve(entries, observer) { // observe chart position -> start animation when inside viewport
      if(entries[0].isIntersecting) {
        this.chartLoaded = true;
        animatePath(this);
        observer.unobserve(this.element);
      }
    };
  
    function animatePath(chart, type) {
      var currentTime = null,
        duration = 400/chart.dataValues.length;
          
      var animateSinglePath = function(index, timestamp) {
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
  
        var startAngle = chart.percentageStart[index];
        var endAngle =  startAngle + chart.percentageDelta[index]*(progress/duration);
  
        var path = chart.element.getElementsByClassName('js-pie-chart__data-path--'+(index+1))[0];
        var pathCode = getPathCode(chart, startAngle, endAngle);
        path.setAttribute('d', pathCode);
        
        if(progress < duration) {
          window.requestAnimationFrame(function(timestamp) {animateSinglePath(index, timestamp);});
        } else if(index < chart.dataValues.length - 1) {
          currentTime = null;
          window.requestAnimationFrame(function(timestamp) {animateSinglePath(index + 1, timestamp);});
        }
      };
  
      window.requestAnimationFrame(function(timestamp) {animateSinglePath(0, timestamp);});
    };
  
    // util functions - get paths d values
    function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
      var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
    
      return {
        x: centerX + (radius * Math.cos(angleInRadians)),
        y: centerY + (radius * Math.sin(angleInRadians))
      };
    };
    
    function getPieArc(x, y, radius, startAngle, endAngle){
      var start = polarToCartesian(x, y, radius, endAngle);
      var end = polarToCartesian(x, y, radius, startAngle);
  
      var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
  
      var d = [
          "M", start.x, start.y, 
          "A", radius, radius, 0, arcSweep, 0, end.x, end.y,
          "L", x,y,
          "L", start.x, start.y
      ].join(" ");
  
      return d;       
    };
  
    function getDonutArc(x, y, radius, radiusDelta, startAngle, endAngle){
      var s1 = polarToCartesian(x, y, (radius - radiusDelta), endAngle),
        s2 = polarToCartesian(x, y, radius, endAngle),
        s3 = polarToCartesian(x, y, radius, startAngle),
        s4 = polarToCartesian(x, y, (radius - radiusDelta), startAngle);
  
  
      var arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
  
      var d = [
          "M", s1.x, s1.y,
          "L", s2.x, s2.y, 
          "A", radius, radius, 0, arcSweep, 0, s3.x, s3.y, 
          "L", s4.x, s4.y, 
          "A", (radius - radiusDelta), (radius - radiusDelta), 0, arcSweep, 1, s1.x, s1.y
      ].join(" ");
  
      return d;       
    };
  
    PieChart.defaults = {
      element : '',
      type: 'pie', // can be pie or donut
      animate: false
    };
  
    window.PieChart = PieChart;
  
    //initialize the PieChart objects
    var pieCharts = document.getElementsByClassName('js-pie-chart');
    var intersectionObserver = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
    
    if( pieCharts.length > 0 ) {
  		for( var i = 0; i < pieCharts.length; i++) {
  			(function(i){
          var chartType = pieCharts[i].getAttribute('data-pie-chart-type') ? pieCharts[i].getAttribute('data-pie-chart-type') : 'pie';
          var animate = pieCharts[i].getAttribute('data-pie-chart-animation') && pieCharts[i].getAttribute('data-pie-chart-animation') == 'on' ? true : false;
          new PieChart({
            element: pieCharts[i],
            type: chartType,
            animate: animate
          });
        })(i);
      }
  	}
  }());
  // File#: _1_popover
  // Usage: codyhouse.co/license
  (function() {
    var Popover = function(element) {
      this.element = element;
  		this.elementId = this.element.getAttribute('id');
  		this.trigger = document.querySelectorAll('[aria-controls="'+this.elementId+'"]');
  		this.selectedTrigger = false;
      this.popoverVisibleClass = 'popover--is-visible';
      this.selectedTriggerClass = 'popover-control--active';
      this.popoverIsOpen = false;
      // focusable elements
      this.firstFocusable = false;
  		this.lastFocusable = false;
  		// position target - position tooltip relative to a specified element
  		this.positionTarget = getPositionTarget(this);
  		// gap between element and viewport - if there's max-height 
  		this.viewportGap = parseInt(getComputedStyle(this.element).getPropertyValue('--popover-viewport-gap')) || 20;
  		initPopover(this);
  		initPopoverEvents(this);
    };
  
    // public methods
    Popover.prototype.togglePopover = function(bool, moveFocus) {
      togglePopover(this, bool, moveFocus);
    };
  
    Popover.prototype.checkPopoverClick = function(target) {
      checkPopoverClick(this, target);
    };
  
    Popover.prototype.checkPopoverFocus = function() {
      checkPopoverFocus(this);
    };
  
  	// private methods
  	function getPositionTarget(popover) {
  		// position tooltip relative to a specified element - if provided
  		var positionTargetSelector = popover.element.getAttribute('data-position-target');
  		if(!positionTargetSelector) return false;
  		var positionTarget = document.querySelector(positionTargetSelector);
  		return positionTarget;
  	};
  
    function initPopover(popover) {
  		// init aria-labels
  		for(var i = 0; i < popover.trigger.length; i++) {
  			Util.setAttributes(popover.trigger[i], {'aria-expanded': 'false', 'aria-haspopup': 'true'});
  		}
    };
    
    function initPopoverEvents(popover) {
  		for(var i = 0; i < popover.trigger.length; i++) {(function(i){
  			popover.trigger[i].addEventListener('click', function(event){
  				event.preventDefault();
  				// if the popover had been previously opened by another trigger element -> close it first and reopen in the right position
  				if(Util.hasClass(popover.element, popover.popoverVisibleClass) && popover.selectedTrigger !=  popover.trigger[i]) {
  					togglePopover(popover, false, false); // close menu
  				}
  				// toggle popover
  				popover.selectedTrigger = popover.trigger[i];
  				togglePopover(popover, !Util.hasClass(popover.element, popover.popoverVisibleClass), true);
  			});
      })(i);}
      
      // trap focus
      popover.element.addEventListener('keydown', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
          //trap focus inside popover
          trapFocus(popover, event);
        }
      });
  
  		// custom events -> open/close popover
  		popover.element.addEventListener('openPopover', function(event){
  			togglePopover(popover, true);
  		});
  
  		popover.element.addEventListener('closePopover', function(event){
  			togglePopover(popover, false, event.detail);
  		});
    };
    
    function togglePopover(popover, bool, moveFocus) {
  		// toggle popover visibility
  		Util.toggleClass(popover.element, popover.popoverVisibleClass, bool);
  		popover.popoverIsOpen = bool;
  		if(bool) {
        popover.selectedTrigger.setAttribute('aria-expanded', 'true');
        getFocusableElements(popover);
        // move focus
        focusPopover(popover);
  			popover.element.addEventListener("transitionend", function(event) {focusPopover(popover);}, {once: true});
  			// position the popover element
  			positionPopover(popover);
  			// add class to popover trigger
  			Util.addClass(popover.selectedTrigger, popover.selectedTriggerClass);
  		} else if(popover.selectedTrigger) {
  			popover.selectedTrigger.setAttribute('aria-expanded', 'false');
  			if(moveFocus) Util.moveFocus(popover.selectedTrigger);
  			// remove class from menu trigger
  			Util.removeClass(popover.selectedTrigger, popover.selectedTriggerClass);
  			popover.selectedTrigger = false;
  		}
  	};
  	
  	function focusPopover(popover) {
  		if(popover.firstFocusable) {
  			popover.firstFocusable.focus();
  		} else {
  			Util.moveFocus(popover.element);
  		}
  	};
  
    function positionPopover(popover) {
  		// reset popover position
  		resetPopoverStyle(popover);
  		var selectedTriggerPosition = (popover.positionTarget) ? popover.positionTarget.getBoundingClientRect() : popover.selectedTrigger.getBoundingClientRect();
  		
  		var menuOnTop = (window.innerHeight - selectedTriggerPosition.bottom) < selectedTriggerPosition.top;
  			
  		var left = selectedTriggerPosition.left,
  			right = (window.innerWidth - selectedTriggerPosition.right),
  			isRight = (window.innerWidth < selectedTriggerPosition.left + popover.element.offsetWidth);
  
  		var horizontal = isRight ? 'right: '+right+'px;' : 'left: '+left+'px;',
  			vertical = menuOnTop
  				? 'bottom: '+(window.innerHeight - selectedTriggerPosition.top)+'px;'
  				: 'top: '+selectedTriggerPosition.bottom+'px;';
  		// check right position is correct -> otherwise set left to 0
  		if( isRight && (right + popover.element.offsetWidth) > window.innerWidth) horizontal = 'left: '+ parseInt((window.innerWidth - popover.element.offsetWidth)/2)+'px;';
  		// check if popover needs a max-height (user will scroll inside the popover)
  		var maxHeight = menuOnTop ? selectedTriggerPosition.top - popover.viewportGap : window.innerHeight - selectedTriggerPosition.bottom - popover.viewportGap;
  
  		var initialStyle = popover.element.getAttribute('style');
  		if(!initialStyle) initialStyle = '';
  		popover.element.setAttribute('style', initialStyle + horizontal + vertical +'max-height:'+Math.floor(maxHeight)+'px;');
  	};
  	
  	function resetPopoverStyle(popover) {
  		// remove popover inline style before appling new style
  		popover.element.style.maxHeight = '';
  		popover.element.style.top = '';
  		popover.element.style.bottom = '';
  		popover.element.style.left = '';
  		popover.element.style.right = '';
  	};
  
    function checkPopoverClick(popover, target) {
      // close popover when clicking outside it
      if(!popover.popoverIsOpen) return;
      if(!popover.element.contains(target) && !target.closest('[aria-controls="'+popover.elementId+'"]')) togglePopover(popover, false);
    };
  
    function checkPopoverFocus(popover) {
      // on Esc key -> close popover if open and move focus (if focus was inside popover)
      if(!popover.popoverIsOpen) return;
      var popoverParent = document.activeElement.closest('.js-popover');
      togglePopover(popover, false, popoverParent);
    };
    
    function getFocusableElements(popover) {
      //get all focusable elements inside the popover
  		var allFocusable = popover.element.querySelectorAll(focusableElString);
  		getFirstVisible(popover, allFocusable);
  		getLastVisible(popover, allFocusable);
    };
  
    function getFirstVisible(popover, elements) {
  		//get first visible focusable element inside the popover
  		for(var i = 0; i < elements.length; i++) {
  			if( isVisible(elements[i]) ) {
  				popover.firstFocusable = elements[i];
  				break;
  			}
  		}
  	};
  
    function getLastVisible(popover, elements) {
  		//get last visible focusable element inside the popover
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( isVisible(elements[i]) ) {
  				popover.lastFocusable = elements[i];
  				break;
  			}
  		}
    };
  
    function trapFocus(popover, event) {
      if( popover.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of popover
  			event.preventDefault();
  			popover.lastFocusable.focus();
  		}
  		if( popover.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of popover
  			event.preventDefault();
  			popover.firstFocusable.focus();
  		}
    };
    
    function isVisible(element) {
  		// check if element is visible
  		return element.offsetWidth || element.offsetHeight || element.getClientRects().length;
  	};
  
    window.Popover = Popover;
  
    //initialize the Popover objects
    var popovers = document.getElementsByClassName('js-popover');
    // generic focusable elements string selector
  	var focusableElString = '[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary';
  	
  	if( popovers.length > 0 ) {
  		var popoversArray = [];
  		var scrollingContainers = [];
  		for( var i = 0; i < popovers.length; i++) {
  			(function(i){
  				popoversArray.push(new Popover(popovers[i]));
  				var scrollableElement = popovers[i].getAttribute('data-scrollable-element');
  				if(scrollableElement && !scrollingContainers.includes(scrollableElement)) scrollingContainers.push(scrollableElement);
  			})(i);
  		}
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
          // close popover on 'Esc'
  				popoversArray.forEach(function(element){
  					element.checkPopoverFocus();
  				});
  			} 
  		});
  		// close popover when clicking outside it
  		window.addEventListener('click', function(event){
  			popoversArray.forEach(function(element){
  				element.checkPopoverClick(event.target);
  			});
  		});
  		// on resize -> close all popover elements
  		window.addEventListener('resize', function(event){
  			popoversArray.forEach(function(element){
  				element.togglePopover(false, false);
  			});
  		});
  		// on scroll -> close all popover elements
  		window.addEventListener('scroll', function(event){
  			popoversArray.forEach(function(element){
  				if(element.popoverIsOpen) element.togglePopover(false, false);
  			});
  		});
  		// take into account additinal scrollable containers
  		for(var j = 0; j < scrollingContainers.length; j++) {
  			var scrollingContainer = document.querySelector(scrollingContainers[j]);
  			if(scrollingContainer) {
  				scrollingContainer.addEventListener('scroll', function(event){
  					popoversArray.forEach(function(element){
  						if(element.popoverIsOpen) element.togglePopover(false, false);
  					});
  				});
  			}
  		}
  	}
  }());
  // File#: _1_pre-header
  // Usage: codyhouse.co/license
  (function() {
  	var preHeader = document.getElementsByClassName('js-pre-header');
  	if(preHeader.length > 0) {
  		for(var i = 0; i < preHeader.length; i++) {
  			(function(i){ addPreHeaderEvent(preHeader[i]);})(i);
  		}
  
  		function addPreHeaderEvent(element) {
  			var close = element.getElementsByClassName('js-pre-header__close-btn')[0];
  			if(close) {
  				close.addEventListener('click', function(event) {
  					event.preventDefault();
  					Util.addClass(element, 'pre-header--is-hidden');
  				});
  			}
  		}
  	}
  }());
  // File#: _1_product-tour
  // Usage: codyhouse.co/license
  (function() {
    var PTour = function(element, bool) {
      this.element = element;
      this.pin = this.element.getElementsByClassName('js-p-tour__pin');
      this.bg = this.element.getElementsByClassName('js-p-tour__background');
      this.steps = this.element.getElementsByClassName('js-p-tour__step');
      this.targets = [];
      this.targetPositions = [];
      this.showPTour = bool;
      this.visibleStep = 0;
      this.isMobile = false;
      this.resizingId = false;
      this.stepTimeout = false;
      // trigger of the entire tour
      this.tourTriggers = document.getElementsByClassName('js-p-tour-start');
      initPTour(this);
    };
  
    // public methods
    PTour.prototype.show = function() {
      updateLayout(this);
      resetTour(this);
  		showTour(this);
  	};
  
    PTour.prototype.hide = function() {
  		closeTour(this);
  	};
  
    // private methods
    function initPTour(element) {
      // define position functions
      setPositionFn(element);
  
      // collect all targets
      collectTargets(element);
  
      // set layout type
      updateLayout(element);
  
      // detect click on tour element
      element.element.addEventListener('click', function(event) {
        // check if we need to close tour
        var closeBtn = event.target.closest('.js-p-tour__close');
        if(closeBtn) closeTour(element);
  
        // check if this was a next/prev button
        var nextStep = event.target.closest('.js-p-tour__btn-next');
        if(nextStep) updateSteps(element, 'next');
        var prevStep = event.target.closest('.js-p-tour__btn-prev');
        if(prevStep) updateSteps(element, 'prev');
      });
  
      // toggle tour visibility
      element.showPTour ? showTour(element) : closeTour(element);
  
      // on resize -> update layout type
      window.addEventListener('resize', function(event){
        clearTimeout(element.resizingId);
        element.resizingId = setTimeout(function(){
          updateLayout(element);
          if(!element.mobile) showSelectedStep(element);
        }, 200);
      });
  
      // start tour using a trigger button
      if(element.tourTriggers.length > 0) {
        for(var i = 0; i < element.tourTriggers.length; i++) {
          element.tourTriggers[i].addEventListener('click', function(event) {
            updateLayout(element);
            resetTour(element);
  		      showTour(element);
          });
        }
      }
  
      // add loaded class
      Util.addClass(element.element, 'p-tour--loaded');
    };
  
    function setPositionFn(element) {
      element['tooltipBottom'] = tooltipBottom;
      element['tooltipTop'] = tooltipTop;
      element['tooltipLeft'] = tooltipLeft;
      element['tooltipRight'] = tooltipRight;
      element['tooltipBottomLeft'] = tooltipBottomLeft;
      element['tooltipBottomRight'] = tooltipBottomRight;
      element['tooltipTopLeft'] = tooltipTopLeft;
      element['tooltipTopRight'] = tooltipTopRight;
    };
  
    function collectTargets(element) {
      for(var i = 0; i < element.steps.length; i++) {
        element.targets.push(document.querySelector('[data-p-tour-target="'+(i + 1)+'"]'));
        element.targetPositions.push(element.targets[i].getAttribute('data-p-tour-position') || 'center');
      };
    };
  
    function showTour(element) {
      Util.removeClass(element.element, 'p-tour--is-hidden');
      // reveal step
      showSelectedStep(element);
      // show background
      animateBg(element);
    };
  
    function closeTour(element) {
      Util.addClass(element.element, 'p-tour--is-hidden');
      element.element.addEventListener('transitionend', function cb(){
        element.visibleStep = 0;
        element.element.removeEventListener('transitionend', cb);
        updateLayout(element);
        resetTour(element);
      });
    };
  
    function updateSteps(element, direction) {
      // clear timeout
      if(element.stepTimeout) {
        clearTimeout(element.stepTimeout);
        element.stepTimeout = false;
      }
      var newIndex = direction == 'next' ? element.visibleStep + 1 : element.visibleStep - 1;
      if(newIndex < 0) newIndex = element.steps.length - 1;
      if(newIndex >= element.steps.length) newIndex = 0;
      // reset bg class
      Util.removeClass(element.bg[0], 'p-tour__background--animate');
      // hide old step
      hideStep(element, direction, function(){
        // update index
        element.visibleStep = newIndex;
        // show new step
        showSelectedStep(element, direction);
        // trigger bg animation
        animateBg(element);
      });
    };
  
    function hideStep(element, direction, cb) {
      Util.removeClass(element.steps[element.visibleStep], 'p-tour__step--current');
      if(element.isMobile) {
        // small screen animation
        var isNext = (direction == 'next');
        Util.toggleClass(element.steps[element.visibleStep], 'p-tour__step--m-right', !isNext);
        Util.toggleClass(element.steps[element.visibleStep], 'p-tour__step--m-left', isNext);
      } else {
        Util.addClass(element.pin[0], 'p-tour__pin--out');
      }
      if(element.isMobile) cb();
      else {
        element.stepTimeout = setTimeout(cb, 300);
      }
    };
  
    function showSelectedStep(element, direction) {
      // get pin position
      var position = getPinPosition(element); // position = [top, left]
      // update pin position
      setPosition(element.pin[0], position);
      // show pin
      Util.removeClass(element.pin[0], 'p-tour__pin--out');
      // get class position of new step (e.g., p-tour__step--right)
      var classPosition = setTooltipPosition(element, position); 
      // remove all position classes
      Util.removeClass(element.steps[element.visibleStep], 'p-tour__step--top p-tour__step--bottom p-tour__step--left p-tour__step--right p-tour__step--bottom-right p-tour__step--bottom-left p-tour__step--top-right p-tour__step--top-left');
      if(element.isMobile) {
        Util.addClass(element.steps[element.visibleStep], 'p-tour__step--current');
      } else {
        Util.addClass(element.steps[element.visibleStep], 'p-tour__step--current '+classPosition);
      }
      
      if(direction) {
        // mobile animation
        Util.removeClass(element.steps[element.visibleStep], 'p-tour__step--m-left p-tour__step--m-right');
      }
      // move focus to first action button
      var btnAction = element.steps[element.visibleStep].querySelector('button');
      if(btnAction) btnAction.focus();
    };
  
    function animateBg(element) {
      Util.addClass(element.bg[0], 'p-tour__background--animate');
    };
  
    function updateLayout(element) {
      var layout = getComputedStyle(element.element).getPropertyValue('--p-tour-layout').replace(/'/g, '').replace(/"/g, '').trim();
      // on resize -> check tour layout type
      element.isMobile = (layout == 'mobile');
      // init steps
      initStepsPosition(element);
    };
  
    function initStepsPosition(element) {
      if(!element.isMobile) {
        for(var i = 0; i < element.steps.length; i++) Util.removeClass(element.steps[i], 'p-tour__step--m-left p-tour__step--m-right');
      } else {
        for(var i = 0; i < element.steps.length; i++) {
          element.steps[i].style.top = '';
          element.steps[i].style.left = '';
          if(i < element.visibleStep) {
            Util.addClass(element.steps[i], 'p-tour__step--m-left');
            Util.removeClass(element.steps[i], 'p-tour__step--m-right');
          } else if(i > element.visibleStep) {
            Util.addClass(element.steps[i], 'p-tour__step--m-right');
            Util.removeClass(element.steps[i], 'p-tour__step--m-left');
          } else {
            Util.removeClass(element.steps[i], 'p-tour__step--m-right');
            Util.removeClass(element.steps[i], 'p-tour__step--m-left');
          }
        }
      }
    };
  
    function resetTour(element) {
      for(var i = 0; i < element.steps.length; i++) {
        Util.removeClass(element.steps[i], 'p-tour__step--current');
      }
      Util.removeClass(element.bg[0], 'p-tour__background--animate');
    };
  
    function getPinPosition(element) {
      var tourPosition = element.targetPositions[element.visibleStep],
        stepTargetPosition = element.targets[element.visibleStep].getBoundingClientRect();
      var position = [0, 0]; // [top, left]
  
      switch (tourPosition) {
        case 'bottom':
          position[0] = stepTargetPosition.bottom;
          position[1] = stepTargetPosition.left + stepTargetPosition.width/2;
          break;
        case 'top':
          position[0] = stepTargetPosition.top;
          position[1] = stepTargetPosition.left + stepTargetPosition.width/2;
          break;
        case 'left':
          position[0] = stepTargetPosition.top + stepTargetPosition.height/2;
          position[1] = stepTargetPosition.left;
          break;
        case 'right':
          position[0] = stepTargetPosition.top + stepTargetPosition.height/2;
          position[1] = stepTargetPosition.left + stepTargetPosition.width;
          break;
        case 'center':
          position[0] = stepTargetPosition.top + stepTargetPosition.height/2;
          position[1] = stepTargetPosition.left + stepTargetPosition.width/2;
          break;
        case 'bottom-right':
          position[0] = stepTargetPosition.top + stepTargetPosition.height;
          position[1] = stepTargetPosition.left + stepTargetPosition.width;
          break;
        case 'bottom-left':
          position[0] = stepTargetPosition.top + stepTargetPosition.height;
          position[1] = stepTargetPosition.left;
          break;
        case 'top-right':
          position[0] = stepTargetPosition.top;
          position[1] = stepTargetPosition.left + stepTargetPosition.width;
          break;
        case 'top-left':
          position[0] = stepTargetPosition.top;
          position[1] = stepTargetPosition.left;
          break;
      }
      return position;
    };
  
    function setPosition(element, position) {
      // position = [top, left]
      if(position[0] !== false) element.style.top = position[0]+'px';
      if(position[1] !== false) element.style.left = position[1]+'px';
    };
  
    function setTooltipPosition(element, position) {
      if(element.isMobile) return false;
      var layout = element.targetPositions[element.visibleStep];
      if(layout == 'center') layout == 'top';
      var tooltipInfo = getTooltipInfo(element, layout, position);
      setPosition(element.steps[element.visibleStep], tooltipInfo[1]);
      return 'p-tour__step--'+tooltipInfo[0];
    };
  
    function getTooltipInfo(element, layout, position) {
      switch (layout) {
        case 'bottom':
        case 'center':
          var result = checkPosition(element, 'tooltipBottom', 'tooltipTop', 'tooltipLeft', 'tooltipRight', 'tooltipBottomLeft', 'tooltipBottomRight', 'tooltipTopLeft', 'tooltipTopRight', position);
          break;
        case 'top':
          var result = checkPosition(element, 'tooltipTop', 'tooltipBottom', 'tooltipLeft', 'tooltipRight', 'tooltipBottomLeft', 'tooltipBottomRight', 'tooltipTopLeft', 'tooltipTopRight', position);
          break;
        case 'left':
        case 'bottom-left':
        case 'top-left':
          var result = checkPosition(element, 'tooltipLeft', 'tooltipTop', 'tooltipBottom', 'tooltipRight', 'tooltipBottomLeft', 'tooltipBottomRight', 'tooltipTopLeft', 'tooltipTopRight', position);
          break;
        case 'right':
        case 'bottom-right':
        case 'top-right':
          var result = checkPosition(element, 'tooltipRight', 'tooltipLeft', 'tooltipTop', 'tooltipBottom', 'tooltipBottomLeft', 'tooltipBottomRight', 'tooltipTopLeft', 'tooltipTopRight', position);
          break;
      }
      return [result[1], result[0]];
    };
  
    function checkPosition(element, pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8, position) {
      var result = element[pos1](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos2](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos3](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos4](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos5](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos6](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos7](element, position);
      if(result[0]) return [result[1], result[2]];
      result = element[pos8](element, position);
      if(result[0]) return [result[1], result[2]];
      return [[position[0], position[1] - element.steps[element.visibleStep].getBoundingClientRect().width], 'bottom'];
    };
  
    function tooltipBottom(element, position) {
      // check if tooltip can be placed below the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(tooltipBox.height + position[0] > window.innerHeight && position[0] > tooltipBox.height) {
        return [false, false, false]; 
      }
      if(position[1] - tooltipBox.width/2 < 0 && position[1] + tooltipBox.width < window.innerWidth) {
        return [false, false, false]; 
      }
  
      if(position[1] + tooltipBox.width > window.innerWidth && position[1] - tooltipBox.width > 0) {
        return [false, false, false]; 
      }
      return [true, [position[0], position[1] - tooltipBox.width/2], 'bottom'];
    };
  
    function tooltipTop(element, position) {
      // check if tooltip can be placed on top of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if( position[0] < tooltipBox.height && position[0] + tooltipBox.height < window.innerHeight) {
        return [false, false, false]; 
      }
      if(position[1] - tooltipBox.width/2 < 0 && position[1] + tooltipBox.width < window.innerWidth) {
        return [false, false, false]; 
      }
      
      if(position[1] + tooltipBox.width/2 > window.innerWidth && position[1] - tooltipBox.width > 0) {
        return [false, false, false]; 
      }
      return [true, [position[0] - tooltipBox.height, position[1] - tooltipBox.width/2], 'top'];
    };
  
    function tooltipLeft(element, position) {
      // check if tooltip can be placed to the left of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] < tooltipBox.width && position[1] + tooltipBox.width < window.innerWidth) return [false, false, false];
      if(position[0] < tooltipBox.height/2 && position[0] + tooltipBox.height < window.innerHeight) return [false, false, false];
      if(position[0] + tooltipBox.height/2 >  window.innerHeight && position[0] > tooltipBox.height) return [false, false, false];
      return [true, [position[0] - tooltipBox.height/2, position[1] - tooltipBox.width], 'left'];
    };
  
    function tooltipRight(element, position) {
      // check if tooltip can be placed to the right of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] + tooltipBox.width > window.innerWidth && position[1] > tooltipBox.width) return [false, false, false];
      if(position[0] < tooltipBox.height/2 && position[0] + tooltipBox.height < window.innerHeight) return [false, false, false];
      if(position[0] + tooltipBox.height/2 >  window.innerHeight && position[0] > tooltipBox.height) return [false, false, false];
      return [true, [position[0] - tooltipBox.height/2, position[1]], 'right'];
    };
  
    function tooltipBottomLeft(element, position) {
      // check if tooltip can be placed to the bottom-left of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] < tooltipBox.width && position[1] + tooltipBox.width < window.innerWidth) return [false, false, false];
      if(position[0] + tooltipBox.height > window.innerHeight && position[0] > tooltipBox.height) return [false, false, false];
      return [true, [position[0], position[1] - tooltipBox.width], 'bottom-left'];
    };
  
    function tooltipTopLeft(element, position) {
      // check if tooltip can be placed to the top-left of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] < tooltipBox.width && position[1] + tooltipBox.width < window.innerWidth) return [false, false, false];
      if(position[0] < tooltipBox.height && position[0] + tooltipBox.height < window.innerHeight) return [false, false, false];
      return [true, [position[0] - tooltipBox.height, position[1] - tooltipBox.width], 'top-left'];
    };
  
    function tooltipBottomRight(element, position) {
      // check if tooltip can be placed to the bottom-right of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] + tooltipBox.width > window.innerWidth && position[1] > tooltipBox.width) return [false, false, false];
      if(position[0] + tooltipBox.height > window.innerHeight && position[0] > tooltipBox.height) return [false, false, false];
      return [true, [position[0], position[1]], 'bottom-right'];
    };
  
    function tooltipTopRight(element, position) {
      // check if tooltip can be placed to the top-right of the pin
      var tooltipBox = element.steps[element.visibleStep].getBoundingClientRect();
      if(position[1] + tooltipBox.width > window.innerWidth && position[1] > tooltipBox.width) return [false, false, false];
      if(position[0] < tooltipBox.height && position[0] + tooltipBox.height < window.innerHeight) return [false, false, false];
      return [true, [position[0] - tooltipBox.height, position[1]], 'top-right'];
    };
  
    window.PTour = PTour;
  
    //initialize the PTour objects
  	var pTour = document.getElementsByClassName('js-p-tour');
  	if( pTour.length > 0 ) {
  		for( var i = 0; i < pTour.length; i++) {
  			(function(i){new PTour(pTour[i], true);})(i);
  		}
  	};
  }());
  // File#: _1_progress-bar
  // Usage: codyhouse.co/license
  (function() {	
    var ProgressBar = function(element) {
      this.element = element;
      this.fill = this.element.getElementsByClassName('progress-bar__fill')[0];
      this.label = this.element.getElementsByClassName('progress-bar__value');
      this.value = getProgressBarValue(this);
      // before checking if data-animation is set -> check for reduced motion
      updatedProgressBarForReducedMotion(this);
      this.animate = this.element.hasAttribute('data-animation') && this.element.getAttribute('data-animation') == 'on';
      this.animationDuration = this.element.hasAttribute('data-duration') ? this.element.getAttribute('data-duration') : 1000;
      // animation will run only on browsers supporting IntersectionObserver
      this.canAnimate = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
      // this element is used to announce the percentage value to SR
      this.ariaLabel = this.element.getElementsByClassName('js-progress-bar__aria-value');
      // check if we need to update the bar color
      this.changeColor =  Util.hasClass(this.element, 'progress-bar--color-update') && Util.cssSupports('color', 'var(--color-value)');
      if(this.changeColor) {
        this.colorThresholds = getProgressBarColorThresholds(this);
      }
      initProgressBar(this);
      // store id to reset animation
      this.animationId = false;
    }; 
  
    // public function
    ProgressBar.prototype.setProgressBarValue = function(value) {
      setProgressBarValue(this, value);
    };
  
    function getProgressBarValue(progressBar) { // get progress value
      // return (fill width/total width) * 100
      return parseFloat(progressBar.fill.offsetWidth*100/progressBar.element.getElementsByClassName('progress-bar__bg')[0].offsetWidth);
    };
  
    function getProgressBarColorThresholds(progressBar) {
      var thresholds = [];
      var i = 1;
      while (!isNaN(parseInt(getComputedStyle(progressBar.element).getPropertyValue('--progress-bar-color-'+i)))) {
        thresholds.push(parseInt(getComputedStyle(progressBar.element).getPropertyValue('--progress-bar-color-'+i)));
        i = i + 1;
      }
      return thresholds;
    };
  
    function updatedProgressBarForReducedMotion(progressBar) {
      // if reduced motion is supported and set to reduced -> remove animations
      if(osHasReducedMotion) progressBar.element.removeAttribute('data-animation');
    };
  
    function initProgressBar(progressBar) {
      // set initial bar color
      if(progressBar.changeColor) updateProgressBarColor(progressBar, progressBar.value);
      // if data-animation is on -> reset the progress bar and animate when entering the viewport
      if(progressBar.animate && progressBar.canAnimate) animateProgressBar(progressBar);
      // reveal fill and label -> --animate and --color-update variations only
      setTimeout(function(){Util.addClass(progressBar.element, 'progress-bar--init');}, 30);
  
      // dynamically update value of progress bar
      progressBar.element.addEventListener('updateProgress', function(event){
        // cancel request animation frame if it was animating
        if(progressBar.animationId) window.cancelAnimationFrame(progressBar.animationId);
        
        var final = event.detail.value,
          duration = (event.detail.duration) ? event.detail.duration : progressBar.animationDuration;
        var start = getProgressBarValue(progressBar);
        // trigger update animation
        updateProgressBar(progressBar, start, final, duration, function(){
          emitProgressBarEvents(progressBar, 'progressCompleted', progressBar.value+'%');
          // update value of label for SR
          if(progressBar.ariaLabel.length > 0) progressBar.ariaLabel[0].textContent = final+'%';
        });
      });
    };
  
    function animateProgressBar(progressBar) {
      // reset inital values
      setProgressBarValue(progressBar, 0);
      
      // listen for the element to enter the viewport -> start animation
      var observer = new IntersectionObserver(progressBarObserve.bind(progressBar), { threshold: [0, 0.1] });
      observer.observe(progressBar.element);
    };
  
    function progressBarObserve(entries, observer) { // observe progressBar position -> start animation when inside viewport
      var self = this;
      if(entries[0].intersectionRatio.toFixed(1) > 0 && !this.animationTriggered) {
        updateProgressBar(this, 0, this.value, this.animationDuration, function(){
          emitProgressBarEvents(self, 'progressCompleted', self.value+'%');
        });
      }
    };
  
    function updateProgressBar(progressBar, start, to, duration, cb) {
      var change = to - start,
        currentTime = null;
  
      var animateFill = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        var val = parseInt((progress/duration)*change + start);
        // make sure value is in correct range
        if(change > 0 && val > to) val = to;
        if(change < 0 && val < to) val = to;
        if(progress >= duration) val = to;
  
        setProgressBarValue(progressBar, val);
        if(progress < duration) {
          progressBar.animationId = window.requestAnimationFrame(animateFill);
        } else {
          progressBar.animationId = false;
          cb();
        }
      };
      if ( window.requestAnimationFrame && !osHasReducedMotion ) {
        progressBar.animationId = window.requestAnimationFrame(animateFill);
      } else {
        setProgressBarValue(progressBar, to);
        cb();
      }
    };
  
    function setProgressBarValue(progressBar, value) {
      progressBar.fill.style.width = value+'%';
      if(progressBar.label.length > 0 ) progressBar.label[0].textContent = value+'%';
      if(progressBar.changeColor) updateProgressBarColor(progressBar, value);
    };
  
    function updateProgressBarColor(progressBar, value) {
      var className = 'progress-bar--fill-color-'+ progressBar.colorThresholds.length;
      for(var i = progressBar.colorThresholds.length; i > 0; i--) {
        if( !isNaN(progressBar.colorThresholds[i - 1]) && value <= progressBar.colorThresholds[i - 1]) {
          className = 'progress-bar--fill-color-' + i;
        } 
      }
      
      removeProgressBarColorClasses(progressBar);
      Util.addClass(progressBar.element, className);
    };
  
    function removeProgressBarColorClasses(progressBar) {
      var classes = progressBar.element.className.split(" ").filter(function(c) {
        return c.lastIndexOf('progress-bar--fill-color-', 0) !== 0;
      });
      progressBar.element.className = classes.join(" ").trim();
    };
  
    function emitProgressBarEvents(progressBar, eventName, detail) {
      progressBar.element.dispatchEvent(new CustomEvent(eventName, {detail: detail}));
    };
  
    window.ProgressBar = ProgressBar;
  
    //initialize the ProgressBar objects
    var progressBars = document.getElementsByClassName('js-progress-bar');
    var osHasReducedMotion = Util.osHasReducedMotion();
    if( progressBars.length > 0 ) {
  		for( var i = 0; i < progressBars.length; i++) {
  			(function(i){new ProgressBar(progressBars[i]);})(i);
      }
  	}
  }());
  // File#: _1_radial-bar-chart
  // Usage: codyhouse.co/license
  (function() {
    var RadialBar = function(opts) {
      this.options = Util.extend(RadialBar.defaults , opts);
      this.element = this.options.element;
      this.chartArea = this.element.getElementsByClassName('js-radial-bar__area')[0];
      this.percentages = this.element.getElementsByClassName('js-radial-bar__value');
      this.chartDashStroke = [];
      this.tooltip = this.chartArea.getElementsByClassName('js-radial-bar__tooltip');
      this.eventIds = [];
      this.hoverId = false;
      this.hovering = false;
      this.selectedIndex = false; // will be used for tooltip 
      this.chartLoaded = false; // used when chart is initially animated
      initRadialBar(this);
    };
  
    function initRadialBar(chart) {
      createChart(chart);
      animateChart(chart);
      resizeChart(chart);
    };
  
    function createChart(chart) {
      setChartSize(chart);
      getChartVariables(chart); // get radius + gap values
      // create svg element
      createChartSvg(chart);
      // tooltip
      initTooltip(chart);
    };
  
    function setChartSize(chart) {
      chart.height = chart.chartArea.clientHeight;
      chart.width = chart.chartArea.clientWidth;
    };
  
    function getChartVariables(chart) {
      chart.circleGap = parseInt(getComputedStyle(chart.element).getPropertyValue('--radial-bar-gap'));
      if(isNaN(chart.circleGap)) chart.circleGap = 4;
  
      chart.circleStroke = parseInt(getComputedStyle(chart.element).getPropertyValue('--radial-bar-bar-stroke'));
      if(isNaN(chart.circleStroke)) chart.circleStroke = 10;
    };
  
    function createChartSvg(chart) {
      var svg = '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="'+chart.width+'" height="'+chart.height+'" class="radial-bar__svg js-radial-bar__svg"></svg>';
      chart.chartArea.innerHTML = chart.chartArea.innerHTML + svg;
      chart.svg = chart.chartArea.getElementsByClassName('js-radial-bar__svg')[0];
      // create chart content
      getRadialBarCode(chart);
    };
  
    function getRadialBarCode(chart) {
      for(var i = 0; i < chart.percentages.length; i++) {
        // for each percentage value, we'll create: a <g> wrapper + 2 <circle> elements (bg + fill)
        var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
          circleFill = document.createElementNS('http://www.w3.org/2000/svg', 'circle'),
          circleBg = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
  
        var customClass = chart.percentages[i].getAttribute('data-radial-bar-color');
        if(!customClass) customClass = '';
          
        var radius = chart.height/2 - (chart.circleStroke + chart.circleGap)* i - chart.circleStroke;
  
        var circunference = 2*Math.PI*radius,
          percentage = parseInt(chart.percentages[i].textContent);
  
        chart.chartDashStroke.push([circunference*percentage/100, circunference*(100-percentage)/100, circunference]);
  
        Util.setAttributes(circleBg, {cx: chart.height/2, cy: chart.width/2, r: radius, class: 'radial-bar__circle radial-bar__circle__bg', 'data-index': i});
  
        var dashArray = chart.chartDashStroke[i][0]+' '+chart.chartDashStroke[i][1];
        
        if(!chart.chartLoaded && chart.options.animate && intersectionObserver && ! reducedMotion) {
          // if chart has to be animated - start with empty circles
          dashArray = '0 '+2*circunference;
        }
        
        Util.setAttributes(circleFill, {cx: chart.height/2, cy: chart.width/2, r: radius, class: 'radial-bar__circle radial-bar__circle__fill js-radial-bar__circle__fill '+customClass, 'stroke-dasharray': dashArray, 'stroke-dashoffset': circunference/4, 'data-index': i});
  
        gEl.setAttribute('class', 'radial-bar__group');
  
        gEl.appendChild(circleBg);
        gEl.appendChild(circleFill);
        chart.svg.appendChild(gEl);
      }
    };
  
    function initTooltip(chart) {
      if(chart.tooltip.length < 1) return;
      // init mouse events
      chart.eventIds['hover'] = handleEvent.bind(chart);
      chart.chartArea.addEventListener('mouseenter', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mousedown', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mousemove', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mouseleave', chart.eventIds['hover']);
    };
  
    function handleEvent(event) {
      // show tooltip on hover
  		switch(event.type) {
  			case 'mouseenter':
        case 'mousedown':
  				hoverChart(this, event);
          break;
  			case 'mousemove': 
          var self = this;
  				self.hoverId  = window.requestAnimationFrame 
            ? window.requestAnimationFrame(function(){hoverChart(self, event)})
            : setTimeout(function(){hoverChart(self, event);});
          break;
  			case 'mouseleave':
  				resetTooltip(this);
          break;
  		}
    };
  
    function hoverChart(chart, event) {
      if(chart.hovering) return;
      chart.hovering = true;
      var selectedIndex = getSelectedIndex(event);
      if(selectedIndex !== false && selectedIndex !== chart.selectedIndex) {
        chart.selectedIndex = selectedIndex;
        setTooltipContent(chart);
        Util.removeClass(chart.tooltip[0], 'is-hidden');
      } else if(selectedIndex === false) {
        resetTooltip(chart);
      }
      chart.hovering = false;
    };
  
    function resetTooltip(chart) {
      // hide tooltip
      if(chart.hoverId) {
        (window.requestAnimationFrame) ? window.cancelAnimationFrame(chart.hoverId) : clearTimeout(chart.hoverId);
        chart.hoverId = false;
      }
      Util.addClass(chart.tooltip[0], 'is-hidden');
      chart.hovering = false;
      chart.selectedIndex = false;
    };
  
    function setTooltipContent(chart) {
      chart.tooltip[0].textContent = chart.percentages[chart.selectedIndex].textContent;
    };
  
    function getSelectedIndex(event) {
      if(event.target.tagName.toLowerCase() == 'circle') {
        return parseInt(event.target.getAttribute('data-index'));
      }
      return false;
    };
  
    function resizeChart(chart) {
      // reset chart on resize
      window.addEventListener('resize', function() {
        clearTimeout(chart.eventIds['resize']);
        chart.eventIds['resize'] = setTimeout(doneResizing, 300);
      });
  
      function doneResizing() {
        resetChartResize(chart);
        removeChart(chart);
        createChart(chart);
        initTooltip(chart);
      };
    };
  
    function resetChartResize(chart) {
      chart.hovering = false;
      // reset event listeners
      if( chart.eventIds && chart.eventIds['hover']) {
        chart.chartArea.removeEventListener('mouseenter', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mousedown', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mousemove', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mouseleave', chart.eventIds['hover']);
      }
    };
  
    function removeChart(chart) {
      // on resize -> remove svg and create a new one
      chart.svg.remove();
    };
  
    function animateChart(chart) {
      // reveal chart when it enters the viewport
      if(!chart.options.animate || chart.chartLoaded || reducedMotion || !intersectionObserver) return;
      var observer = new IntersectionObserver(chartObserve.bind(chart), {rootMargin: "0px 0px -200px 0px"});
      observer.observe(chart.element);
    };
  
    function chartObserve(entries, observer) { // observe chart position -> start animation when inside viewport
      if(entries[0].isIntersecting) {
        this.chartLoaded = true;
        animatePath(this);
        observer.unobserve(this.element);
      }
    };
  
    function animatePath(chart) {
      var currentTime = null,
        duration = 600;
      var circles = chart.element.getElementsByClassName('js-radial-bar__circle__fill');
          
      var animateSinglePath = function(timestamp) {
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
  
        for(var i = 0; i < chart.percentages.length; i++) {
          var fill = Math.easeOutQuart(progress, 0, chart.chartDashStroke[i][0], duration),
            empty = chart.chartDashStroke[i][2] - fill;
  
          circles[i].setAttribute('stroke-dasharray', fill+' '+empty);
        }
        
        if(progress < duration) {
          window.requestAnimationFrame(animateSinglePath);
        }
      };
  
      window.requestAnimationFrame(animateSinglePath);
    };
  
    RadialBar.defaults = {
      element : '',
      animate: false
    };
  
    window.RadialBar = RadialBar;
  
    // initialize the RadialBar objects
    var radialBar = document.getElementsByClassName('js-radial-bar');
    var intersectionObserver = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
  
    if( radialBar.length > 0 ) {
  		for( var i = 0; i < radialBar.length; i++) {
  			(function(i){
          var animate = radialBar[i].getAttribute('data-radial-bar-animation') && radialBar[i].getAttribute('data-radial-bar-animation') == 'on' ? true : false;
          new RadialBar({element: radialBar[i], animate: animate});
        })(i);
      }
  	}
  }());
  // File#: _1_rating
  // Usage: codyhouse.co/license
  (function() {
  	var Rating = function(element) {
  		this.element = element;
  		this.icons = this.element.getElementsByClassName('js-rating__control')[0];
  		this.iconCode = this.icons.children[0].parentNode.innerHTML;
  		this.initialRating = [];
  		this.initialRatingElement = this.element.getElementsByClassName('js-rating__value')[0];
  		this.ratingItems;
  		this.selectedRatingItem;
      this.readOnly = Util.hasClass(this.element, 'js-rating--read-only');
  		this.ratingMaxValue = 5;
  		this.getInitialRating();
  		this.initRatingHtml();
  	};
  
  	Rating.prototype.getInitialRating = function() {
  		// get the rating of the product
  		if(!this.initialRatingElement || !this.readOnly) {
  			this.initialRating = [0, false];
  			return;
  		}
  
  		var initialValue = Number(this.initialRatingElement.textContent);
  		if(isNaN(initialValue)) {
  			this.initialRating = [0, false];
  			return;
  		}
  
  		var floorNumber = Math.floor(initialValue);
  		this.initialRating[0] = (floorNumber < initialValue) ? floorNumber + 1 : floorNumber;
  		this.initialRating[1] = (floorNumber < initialValue) ? Math.round((initialValue - floorNumber)*100) : false;
  	};
  
  	Rating.prototype.initRatingHtml = function() {
  		//create the star elements
  		var iconsList = this.readOnly ? '<ul>' : '<ul role="radiogroup">';
  		
  		//if initial rating value is zero -> add a 'zero' item 
  		if(this.initialRating[0] == 0 && !this.initialRating[1]) {
  			iconsList = iconsList+ '<li class="rating__item--zero rating__item--checked"></li>';
  		}
  
  		// create the stars list 
  		for(var i = 0; i < this.ratingMaxValue; i++) { 
  			iconsList = iconsList + this.getStarHtml(i);
  		}
  		iconsList = iconsList + '</ul>';
  
  		// --default variation only - improve SR accessibility including a legend element 
  		if(!this.readOnly) {
  			var labelElement = this.element.getElementsByTagName('label');
  			if(labelElement.length > 0) {
  				var legendElement = '<legend class="'+labelElement[0].getAttribute('class')+'">'+labelElement[0].textContent+'</legend>';
  				iconsList = '<fieldset>'+legendElement+iconsList+'</fieldset>';
  				Util.addClass(labelElement[0], 'is-hidden');
  			}
  		}
  
  		this.icons.innerHTML = iconsList;
  		
  		//init object properties
  		this.ratingItems = this.icons.getElementsByClassName('js-rating__item');
  		this.selectedRatingItem = this.icons.getElementsByClassName('rating__item--checked')[0];
  
  		//show the stars
  		Util.removeClass(this.icons, 'rating__control--is-hidden');
  
  		//event listener
  		!this.readOnly && this.initRatingEvents();// rating vote enabled
  	};
  
  	Rating.prototype.getStarHtml = function(index) {
  		var listItem = '';
  		var checked = (index+1 == this.initialRating[0]) ? true : false,
  			itemClass = checked ? ' rating__item--checked' : '',
  			tabIndex = (checked || (this.initialRating[0] == 0 && !this.initialRating[1] && index == 0) ) ? 0 : -1,
  			showHalf = checked && this.initialRating[1] ? true : false,
  			iconWidth = showHalf ? ' rating__item--half': '';
  		if(!this.readOnly) {
  			listItem = '<li class="js-rating__item'+itemClass+iconWidth+'" role="radio" aria-label="'+(index+1)+'" aria-checked="'+checked+'" tabindex="'+tabIndex+'"><div class="rating__icon">'+this.iconCode+'</div></li>';
  		} else {
  			var starInner = showHalf ? '<div class="rating__icon">'+this.iconCode+'</div><div class="rating__icon rating__icon--inactive">'+this.iconCode+'</div>': '<div class="rating__icon">'+this.iconCode+'</div>';
  			listItem = '<li class="js-rating__item'+itemClass+iconWidth+'">'+starInner+'</li>';
  		}
  		return listItem;
  	};
  
  	Rating.prototype.initRatingEvents = function() {
  		var self = this;
  
  		//click on a star
  		this.icons.addEventListener('click', function(event){
  			var trigger = event.target.closest('.js-rating__item');
  			self.resetSelectedIcon(trigger);
  		});
  
  		//keyboard navigation -> select new star
  		this.icons.addEventListener('keydown', function(event){
  			if( event.keyCode && (event.keyCode == 39 || event.keyCode == 40 ) || event.key && (event.key.toLowerCase() == 'arrowright' || event.key.toLowerCase() == 'arrowdown') ) {
  				self.selectNewIcon('next'); //select next star on arrow right/down
  			} else if(event.keyCode && (event.keyCode == 37 || event.keyCode == 38 ) || event.key && (event.key.toLowerCase() == 'arrowleft' || event.key.toLowerCase() == 'arrowup')) {
  				self.selectNewIcon('prev'); //select prev star on arrow left/up
  			} else if(event.keyCode && event.keyCode == 32 || event.key && event.key == ' ') {
  				self.selectFocusIcon(); // select focused star on Space
  			}
  		});
  	};
  
  	Rating.prototype.selectNewIcon = function(direction) {
  		var index = Util.getIndexInArray(this.ratingItems, this.selectedRatingItem);
  		index = (direction == 'next') ? index + 1 : index - 1;
  		if(index < 0) index = this.ratingItems.length - 1;
  		if(index >= this.ratingItems.length) index = 0;	
  		this.resetSelectedIcon(this.ratingItems[index]);
  		this.ratingItems[index].focus();
  	};
  
  	Rating.prototype.selectFocusIcon = function(direction) {
  		this.resetSelectedIcon(document.activeElement);
  	};
  
  	Rating.prototype.resetSelectedIcon = function(trigger) {
  		if(!trigger) return;
  		Util.removeClass(this.selectedRatingItem, 'rating__item--checked');
  		Util.setAttributes(this.selectedRatingItem, {'aria-checked': false, 'tabindex': -1});
  		Util.addClass(trigger, 'rating__item--checked');
  		Util.setAttributes(trigger, {'aria-checked': true, 'tabindex': 0});
  		this.selectedRatingItem = trigger; 
  		// update select input value
  		var select = this.element.getElementsByTagName('select');
  		if(select.length > 0) {
  			select[0].value = trigger.getAttribute('aria-label');
  		}
  	};
  	
  	//initialize the Rating objects
  	var ratings = document.getElementsByClassName('js-rating');
  	if( ratings.length > 0 ) {
  		for( var i = 0; i < ratings.length; i++) {
  			(function(i){new Rating(ratings[i]);})(i);
  		}
  	};
  }());
  // File#: _1_read-more
  // Usage: codyhouse.co/license
  (function() {
    var ReadMore = function(element) {
      this.element = element;
      this.moreContent = this.element.getElementsByClassName('js-read-more__content');
      this.count = this.element.getAttribute('data-characters') || 200;
      this.counting = 0;
      this.btnClasses = this.element.getAttribute('data-btn-class');
      this.ellipsis = this.element.getAttribute('data-ellipsis') && this.element.getAttribute('data-ellipsis') == 'off' ? false : true;
      this.btnShowLabel = 'Read more';
      this.btnHideLabel = 'Read less';
      this.toggleOff = this.element.getAttribute('data-toggle') && this.element.getAttribute('data-toggle') == 'off' ? false : true;
      if( this.moreContent.length == 0 ) splitReadMore(this);
      setBtnLabels(this);
      initReadMore(this);
    };
  
    function splitReadMore(readMore) { 
      splitChildren(readMore.element, readMore); // iterate through children and hide content
    };
  
    function splitChildren(parent, readMore) {
      if(readMore.counting >= readMore.count) {
        Util.addClass(parent, 'js-read-more__content');
        return parent.outerHTML;
      }
      var children = parent.childNodes;
      var content = '';
      for(var i = 0; i < children.length; i++) {
        if (children[i].nodeType == Node.TEXT_NODE) {
          content = content + wrapText(children[i], readMore);
        } else {
          content = content + splitChildren(children[i], readMore);
        }
      }
      parent.innerHTML = content;
      return parent.outerHTML;
    };
  
    function wrapText(element, readMore) {
      var content = element.textContent;
      if(content.replace(/\s/g,'').length == 0) return '';// check if content is empty
      if(readMore.counting >= readMore.count) {
        return '<span class="js-read-more__content">' + content + '</span>';
      }
      if(readMore.counting + content.length < readMore.count) {
        readMore.counting = readMore.counting + content.length;
        return content;
      }
      var firstContent = content.substr(0, readMore.count - readMore.counting);
      firstContent = firstContent.substr(0, Math.min(firstContent.length, firstContent.lastIndexOf(" ")));
      var secondContent = content.substr(firstContent.length, content.length);
      readMore.counting = readMore.count;
      return firstContent + '<span class="js-read-more__content">' + secondContent + '</span>';
    };
  
    function setBtnLabels(readMore) { // set custom labels for read More/Less btns
      var btnLabels = readMore.element.getAttribute('data-btn-labels');
      if(btnLabels) {
        var labelsArray = btnLabels.split(',');
        readMore.btnShowLabel = labelsArray[0].trim();
        readMore.btnHideLabel = labelsArray[1].trim();
      }
    };
  
    function initReadMore(readMore) { // add read more/read less buttons to the markup
      readMore.moreContent = readMore.element.getElementsByClassName('js-read-more__content');
      if( readMore.moreContent.length == 0 ) {
        Util.addClass(readMore.element, 'read-more--loaded');
        return;
      }
      var btnShow = ' <button class="js-read-more__btn '+readMore.btnClasses+'">'+readMore.btnShowLabel+'</button>';
      var btnHide = ' <button class="js-read-more__btn is-hidden '+readMore.btnClasses+'">'+readMore.btnHideLabel+'</button>';
      if(readMore.ellipsis) {
        btnShow = '<span class="js-read-more__ellipsis" aria-hidden="true">...</span>'+ btnShow;
      }
  
      readMore.moreContent[readMore.moreContent.length - 1].insertAdjacentHTML('afterend', btnHide);
      readMore.moreContent[0].insertAdjacentHTML('afterend', btnShow);
      resetAppearance(readMore);
      initEvents(readMore);
    };
  
    function resetAppearance(readMore) { // hide part of the content
      for(var i = 0; i < readMore.moreContent.length; i++) Util.addClass(readMore.moreContent[i], 'is-hidden');
      Util.addClass(readMore.element, 'read-more--loaded'); // show entire component
    };
  
    function initEvents(readMore) { // listen to the click on the read more/less btn
      readMore.btnToggle = readMore.element.getElementsByClassName('js-read-more__btn');
      readMore.ellipsis = readMore.element.getElementsByClassName('js-read-more__ellipsis');
  
      readMore.btnToggle[0].addEventListener('click', function(event){
        event.preventDefault();
        updateVisibility(readMore, true);
      });
      readMore.btnToggle[1].addEventListener('click', function(event){
        event.preventDefault();
        updateVisibility(readMore, false);
      });
    };
  
    function updateVisibility(readMore, visibile) {
      for(var i = 0; i < readMore.moreContent.length; i++) Util.toggleClass(readMore.moreContent[i], 'is-hidden', !visibile);
      // reset btns appearance
      Util.toggleClass(readMore.btnToggle[0], 'is-hidden', visibile);
      Util.toggleClass(readMore.btnToggle[1], 'is-hidden', !visibile);
      if(readMore.ellipsis.length > 0 ) Util.toggleClass(readMore.ellipsis[0], 'is-hidden', visibile);
      if(!readMore.toggleOff) Util.addClass(readMore.btn, 'is-hidden');
      // move focus
      if(visibile) {
        var targetTabIndex = readMore.moreContent[0].getAttribute('tabindex');
        Util.moveFocus(readMore.moreContent[0]);
        resetFocusTarget(readMore.moreContent[0], targetTabIndex);
      } else {
        Util.moveFocus(readMore.btnToggle[0]);
      }
    };
  
    function resetFocusTarget(target, tabindex) {
      if( parseInt(target.getAttribute('tabindex')) < 0) {
  			target.style.outline = 'none';
  			!tabindex && target.removeAttribute('tabindex');
  		}
    };
  
    //initialize the ReadMore objects
  	var readMore = document.getElementsByClassName('js-read-more');
  	if( readMore.length > 0 ) {
  		for( var i = 0; i < readMore.length; i++) {
  			(function(i){new ReadMore(readMore[i]);})(i);
  		}
  	};
  }());
  // File#: _1_reading-progressbar
  // Usage: codyhouse.co/license
  (function() {
    var readingIndicator = document.getElementsByClassName('js-reading-progressbar')[0],
  		readingIndicatorContent = document.getElementsByClassName('js-reading-content')[0];
    
    if( readingIndicator && readingIndicatorContent) {
      var progressInfo = [],
        progressEvent = false,
        progressFallback = readingIndicator.getElementsByClassName('js-reading-progressbar__fallback')[0],
        progressIsSupported = 'value' in readingIndicator;
  
      var boundingClientRect = readingIndicatorContent.getBoundingClientRect();
  
      progressInfo['height'] = readingIndicatorContent.offsetHeight;
      progressInfo['top'] = boundingClientRect.top;
      progressInfo['bottom'] = boundingClientRect.bottom;
      progressInfo['window'] = window.innerHeight;
      progressInfo['class'] = 'reading-progressbar--is-active';
      progressInfo['hideClass'] = 'reading-progressbar--is-out';
      
      //init indicator
      setProgressIndicator();
      // wait for font to be loaded - reset progress bar
      if(document.fonts) {
        document.fonts.ready.then(function() {
          triggerReset();
        });
      }
      // listen to window resize - update progress
      window.addEventListener('resize', function(event){
        triggerReset();
      });
  
      //listen to the window scroll event - update progress
      window.addEventListener('scroll', function(event){
        if(progressEvent) return;
        progressEvent = true;
        (!window.requestAnimationFrame) ? setTimeout(function(){setProgressIndicator();}, 250) : window.requestAnimationFrame(setProgressIndicator);
      });
      
      function setProgressIndicator() {
        var boundingClientRect = readingIndicatorContent.getBoundingClientRect();
        progressInfo['top'] = boundingClientRect.top;
        progressInfo['bottom'] = boundingClientRect.bottom;
  
        if(progressInfo['height'] <= progressInfo['window']) {
          // short content - hide progress indicator
          Util.removeClass(readingIndicator, progressInfo['class']);
          progressEvent = false;
          return;
        }
        // get new progress and update element
        Util.addClass(readingIndicator, progressInfo['class']);
        var value = (progressInfo['top'] >= 0) ? 0 : 100*(0 - progressInfo['top'])/(progressInfo['height'] - progressInfo['window']);
        readingIndicator.setAttribute('value', value);
        if(!progressIsSupported && progressFallback) progressFallback.style.width = value+'%';
        // hide progress bar when target is outside the viewport
        Util.toggleClass(readingIndicator, progressInfo['hideClass'], progressInfo['bottom'] <= 0);
        progressEvent = false;
      };
  
      function triggerReset() {
        if(progressEvent) return;
        progressEvent = true;
        (!window.requestAnimationFrame) ? setTimeout(function(){resetProgressIndicator();}, 250) : window.requestAnimationFrame(resetProgressIndicator);
      };
  
      function resetProgressIndicator() {
        progressInfo['height'] = readingIndicatorContent.offsetHeight;
        progressInfo['window'] = window.innerHeight;
        setProgressIndicator();
      };
    }
  }());
  // File#: _1_repeater
  // Usage: codyhouse.co/license
  (function() {
    var Repeater = function(element) {
      this.element = element;
      this.blockWrapper = this.element.getElementsByClassName('js-repeater__list');
      if(this.blockWrapper.length < 1) return;
      this.blocks = false;
      getBlocksList(this);
      this.firstBlock = false;
      this.addNew = this.element.getElementsByClassName('js-repeater__add');
      this.cloneClass = this.element.getAttribute('data-repeater-class');
      this.inputName = this.element.getAttribute('data-repeater-input-name');
      initRepeater(this);
    };
  
    function initRepeater(element) {
      if(element.addNew.length < 1 || element.blocks.length < 1 || element.blockWrapper.length < 1 ) return;
      element.firstBlock = element.blocks[0].cloneNode(true);
      
      // detect click on a Remove button
      element.element.addEventListener('click', function(event) {
        var deleteBtn = event.target.closest('.js-repeater__remove');
        if(deleteBtn) {
          event.preventDefault();
          removeBlock(element, deleteBtn);
        }
      });
  
      // detect click on Add button
      element.addNew[0].addEventListener('click', function(event) {
        event.preventDefault();
        addBlock(element);
      });
    };
  
    function addBlock(element) {
      if(element.blocks.length > 0) {
        var clone = element.blocks[element.blocks.length - 1].cloneNode(true),
          nameToReplace = element.inputName.replace('[n]', '['+(element.blocks.length - 1)+']'),
          newName = element.inputName.replace('[n]', '['+element.blocks.length+']');
      } else {
        var clone =  element.firstBlock.cloneNode(true),
        nameToReplace = element.inputName.replace('[n]', '[0]'),
        newName = element.inputName.replace('[n]', '[0]');
      }
      
      if(element.cloneClass) Util.addClass(clone, element.cloneClass);
      // modify name/for/id attributes
      updateBlockAttrs(clone, nameToReplace, newName, true);
  
      element.blockWrapper[0].appendChild(clone);
      // update blocks list
      getBlocksList(element)
    };
  
    function removeBlock(element, trigger) {
      var block = trigger.closest('.js-repeater__item');
      if(block) {
        var index = Util.getIndexInArray(element.blocks, block);
        block.remove();
        // update blocks list
        getBlocksList(element);
        // need to reset all blocks after that -> name/for/id values
        for(var i = index; i < element.blocks.length; i++) {
          updateBlockAttrs(element.blocks[i], element.inputName.replace('[n]', '['+(i+1)+']'), element.inputName.replace('[n]', '['+i+']'));
        }
      }
    };
  
    function updateBlockAttrs(block, nameToReplace, newName, reset) {
      var nameElements = block.querySelectorAll('[name^="'+nameToReplace+'"]'),
        forElements = block.querySelectorAll('[for^="'+nameToReplace+'"]'),
        idElements = block.querySelectorAll('[id^="'+nameToReplace+'"]');
  
      for(var i = 0; i < nameElements.length; i++) {
        var nameAttr = nameElements[i].getAttribute('name');
        nameElements[i].setAttribute('name', nameAttr.replace(nameToReplace, newName));
        if(reset && nameElements[i].value) nameElements[i].value = '';
      }
  
      for(var i = 0; i < forElements.length; i++) {
        var forAttr = forElements[i].getAttribute('for');
        forElements[i].setAttribute('for', forAttr.replace(nameToReplace, newName));
      }
  
      for(var i = 0; i < idElements.length; i++) {
        var idAttr = idElements[i].getAttribute('id');
        idElements[i].setAttribute('id', idAttr.replace(nameToReplace, newName));
      }
    };
  
    function getBlocksList(element) {
      element.blocks = Util.getChildrenByClassName(element.blockWrapper[0], 'js-repeater__item');
    };
  
    //initialize the Repeater objects
  	var repeater = document.getElementsByClassName('js-repeater');
  	if( repeater.length > 0 ) {
  		for( var i = 0; i < repeater.length; i++) {
  			(function(i){new Repeater(repeater[i]);})(i);
  		}
  	};
  }());
  // File#: _1_responsive-sidebar
  // Usage: codyhouse.co/license
  (function() {
    var Sidebar = function(element) {
  		this.element = element;
  		this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
  		this.firstFocusable = null;
  		this.lastFocusable = null;
  		this.selectedTrigger = null;
      this.showClass = "sidebar--is-visible";
      this.staticClass = "sidebar--static";
      this.customStaticClass = "";
      this.readyClass = "sidebar--loaded";
      this.contentReadyClass = "sidebar-loaded:show";
      this.layout = false; // this will be static or mobile
      this.preventScrollEl = getPreventScrollEl(this);
      getCustomStaticClass(this); // custom classes for static version
      initSidebar(this);
    };
  
    function getPreventScrollEl(element) {
  		var scrollEl = false;
  		var querySelector = element.element.getAttribute('data-sidebar-prevent-scroll');
  		if(querySelector) scrollEl = document.querySelector(querySelector);
  		return scrollEl;
  	};
  
    function getCustomStaticClass(element) {
      var customClasses = element.element.getAttribute('data-static-class');
      if(customClasses) element.customStaticClass = ' '+customClasses;
    };
    
    function initSidebar(sidebar) {
      initSidebarResize(sidebar); // handle changes in layout -> mobile to static and viceversa
      
  		if ( sidebar.triggers ) { // open sidebar when clicking on trigger buttons - mobile layout only
  			for(var i = 0; i < sidebar.triggers.length; i++) {
  				sidebar.triggers[i].addEventListener('click', function(event) {
  					event.preventDefault();
            toggleSidebar(sidebar, event.target);
  				});
  			}
  		}
  
      // use the 'openSidebar' event to trigger the sidebar
      sidebar.element.addEventListener('openSidebar', function(event) {
        toggleSidebar(sidebar, event.detail);
      });
    };
  
    function toggleSidebar(sidebar, target) {
      if(Util.hasClass(sidebar.element, sidebar.showClass)) {
        sidebar.selectedTrigger = target;
        closeSidebar(sidebar);
        return;
      }
      sidebar.selectedTrigger = target;
      showSidebar(sidebar);
      initSidebarEvents(sidebar);
    };
  
    function showSidebar(sidebar) { // mobile layout only
  		Util.addClass(sidebar.element, sidebar.showClass);
  		getFocusableElements(sidebar);
  		Util.moveFocus(sidebar.element);
      // change the overflow of the preventScrollEl
  		if(sidebar.preventScrollEl) sidebar.preventScrollEl.style.overflow = 'hidden';
    };
  
    function closeSidebar(sidebar) { // mobile layout only
  		Util.removeClass(sidebar.element, sidebar.showClass);
  		sidebar.firstFocusable = null;
  		sidebar.lastFocusable = null;
      if(sidebar.selectedTrigger) sidebar.selectedTrigger.focus();
      sidebar.element.removeAttribute('tabindex');
  		//remove listeners
  		cancelSidebarEvents(sidebar);
      // change the overflow of the preventScrollEl
  		if(sidebar.preventScrollEl) sidebar.preventScrollEl.style.overflow = '';
  	};
  
    function initSidebarEvents(sidebar) { // mobile layout only
      //add event listeners
  		sidebar.element.addEventListener('keydown', handleEvent.bind(sidebar));
  		sidebar.element.addEventListener('click', handleEvent.bind(sidebar));
    };
  
    function cancelSidebarEvents(sidebar) { // mobile layout only
      //remove event listeners
  		sidebar.element.removeEventListener('keydown', handleEvent.bind(sidebar));
  		sidebar.element.removeEventListener('click', handleEvent.bind(sidebar));
    };
  
    function handleEvent(event) { // mobile layout only
      switch(event.type) {
        case 'click': {
          initClick(this, event);
        }
        case 'keydown': {
          initKeyDown(this, event);
        }
      }
    };
  
    function initKeyDown(sidebar, event) { // mobile layout only
      if( event.keyCode && event.keyCode == 27 || event.key && event.key == 'Escape' ) {
        //close sidebar window on esc
        closeSidebar(sidebar);
      } else if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
        //trap focus inside sidebar
        trapFocus(sidebar, event);
      }
    };
  
    function initClick(sidebar, event) { // mobile layout only
      //close sidebar when clicking on close button or sidebar bg layer 
  		if( !event.target.closest('.js-sidebar__close-btn') && !Util.hasClass(event.target, 'js-sidebar') ) return;
  		event.preventDefault();
  		closeSidebar(sidebar);
    };
  
    function trapFocus(sidebar, event) { // mobile layout only
      if( sidebar.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of sidebar
  			event.preventDefault();
  			sidebar.lastFocusable.focus();
  		}
  		if( sidebar.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of sidebar
  			event.preventDefault();
  			sidebar.firstFocusable.focus();
  		}
    };
  
    function initSidebarResize(sidebar) {
      // custom event emitted when window is resized - detect only if the sidebar--static@{breakpoint} class was added
      var beforeContent = getComputedStyle(sidebar.element, ':before').getPropertyValue('content');
      if(beforeContent && beforeContent !='' && beforeContent !='none') {
        checkSidebarLayout(sidebar);
  
        sidebar.element.addEventListener('update-sidebar', function(event){
          checkSidebarLayout(sidebar);
        });
      } 
      // check if there a main element to show
      var mainContent = document.getElementsByClassName(sidebar.contentReadyClass);
      if(mainContent.length > 0) Util.removeClass(mainContent[0], sidebar.contentReadyClass);
      Util.addClass(sidebar.element, sidebar.readyClass);
    };
  
    function checkSidebarLayout(sidebar) {
      var layout = getComputedStyle(sidebar.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      if(layout == sidebar.layout) return;
      sidebar.layout = layout;
      if(layout != 'static') Util.addClass(sidebar.element, 'is-hidden');
      Util.toggleClass(sidebar.element, sidebar.staticClass + sidebar.customStaticClass, layout == 'static');
      if(layout != 'static') setTimeout(function(){Util.removeClass(sidebar.element, 'is-hidden')});
      // reset element role 
      (layout == 'static') ? sidebar.element.removeAttribute('role', 'alertdialog') :  sidebar.element.setAttribute('role', 'alertdialog');
      // reset mobile behaviour
      if(layout == 'static' && Util.hasClass(sidebar.element, sidebar.showClass)) closeSidebar(sidebar);
    };
  
    function getFocusableElements(sidebar) {
      //get all focusable elements inside the drawer
  		var allFocusable = sidebar.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(sidebar, allFocusable);
  		getLastVisible(sidebar, allFocusable);
    };
  
    function getFirstVisible(sidebar, elements) {
  		//get first visible focusable element inside the sidebar
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				sidebar.firstFocusable = elements[i];
  				return true;
  			}
  		}
  	};
  
  	function getLastVisible(sidebar, elements) {
  		//get last visible focusable element inside the sidebar
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				sidebar.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    window.Sidebar = Sidebar;
  
    //initialize the Sidebar objects
  	var sidebar = document.getElementsByClassName('js-sidebar');
  	if( sidebar.length > 0 ) {
  		for( var i = 0; i < sidebar.length; i++) {
  			(function(i){new Sidebar(sidebar[i]);})(i);
      }
      // switch from mobile to static layout
      var customEvent = new CustomEvent('update-sidebar');
      window.addEventListener('resize', function(event){
        (!window.requestAnimationFrame) ? setTimeout(function(){resetLayout();}, 250) : window.requestAnimationFrame(resetLayout);
      });
  
      (window.requestAnimationFrame) // init sidebar layout
        ? window.requestAnimationFrame(resetLayout)
        : resetLayout();
  
      function resetLayout() {
        for( var i = 0; i < sidebar.length; i++) {
          (function(i){sidebar[i].dispatchEvent(customEvent)})(i);
        };
      };
  	}
  }());
  // File#: _1_reveal-effects
  // Usage: codyhouse.co/license
  (function() {
  	var fxElements = document.getElementsByClassName('reveal-fx');
  	var intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  	if(fxElements.length > 0) {
  		// deactivate effect if Reduced Motion is enabled
  		if (Util.osHasReducedMotion() || !intersectionObserverSupported) {
  			fxRemoveClasses();
  			return;
  		}
  		//on small devices, do not animate elements -> reveal all
  		if( fxDisabled(fxElements[0]) ) {
  			fxRevealAll();
  			return;
  		}
  
  		var fxRevealDelta = 120; // amount (in pixel) the element needs to enter the viewport to be revealed - if not custom value (data-reveal-fx-delta)
  		
  		var viewportHeight = window.innerHeight,
  			fxChecking = false,
  			fxRevealedItems = [],
  			fxElementDelays = fxGetDelays(), //elements animation delay
  			fxElementDeltas = fxGetDeltas(); // amount (in px) the element needs enter the viewport to be revealed (default value is fxRevealDelta) 
  		
  		
  		// add event listeners
  		window.addEventListener('load', fxReveal);
  		window.addEventListener('resize', fxResize);
  		window.addEventListener('restartAll', fxRestart);
  
  		// observe reveal elements
  		var observer = [];
  		initObserver();
  
  		function initObserver() {
  			for(var i = 0; i < fxElements.length; i++) {
  				observer[i] = new IntersectionObserver(
  					function(entries, observer) { 
  						if(entries[0].isIntersecting) {
  							fxRevealItemObserver(entries[0].target);
  							observer.unobserve(entries[0].target);
  						}
  					}, 
  					{rootMargin: "0px 0px -"+fxElementDeltas[i]+"px 0px"}
  				);
  	
  				observer[i].observe(fxElements[i]);
  			}
  		};
  
  		function fxRevealAll() { // reveal all elements - small devices
  			for(var i = 0; i < fxElements.length; i++) {
  				Util.addClass(fxElements[i], 'reveal-fx--is-visible');
  			}
  		};
  
  		function fxResize() { // on resize - check new window height and reveal visible elements
  			if(fxChecking) return;
  			fxChecking = true;
  			(!window.requestAnimationFrame) ? setTimeout(function(){fxReset();}, 250) : window.requestAnimationFrame(fxReset);
  		};
  
  		function fxReset() {
  			viewportHeight = window.innerHeight;
  			fxReveal();
  		};
  
  		function fxReveal() { // reveal visible elements
  			for(var i = 0; i < fxElements.length; i++) {(function(i){
  				if(fxRevealedItems.indexOf(i) != -1 ) return; //element has already been revelead
  				if(fxElementIsVisible(fxElements[i], i)) {
  					fxRevealItem(i);
  					fxRevealedItems.push(i);
  				}})(i); 
  			}
  			fxResetEvents(); 
  			fxChecking = false;
  		};
  
  		function fxRevealItem(index) {
  			if(fxElementDelays[index] && fxElementDelays[index] != 0) {
  				// wait before revealing element if a delay was added
  				setTimeout(function(){
  					Util.addClass(fxElements[index], 'reveal-fx--is-visible');
  				}, fxElementDelays[index]);
  			} else {
  				Util.addClass(fxElements[index], 'reveal-fx--is-visible');
  			}
  		};
  
  		function fxRevealItemObserver(item) {
  			var index = Util.getIndexInArray(fxElements, item);
  			if(fxRevealedItems.indexOf(index) != -1 ) return; //element has already been revelead
  			fxRevealItem(index);
  			fxRevealedItems.push(index);
  			fxResetEvents(); 
  			fxChecking = false;
  		};
  
  		function fxGetDelays() { // get anmation delays
  			var delays = [];
  			for(var i = 0; i < fxElements.length; i++) {
  				delays.push( fxElements[i].getAttribute('data-reveal-fx-delay') ? parseInt(fxElements[i].getAttribute('data-reveal-fx-delay')) : 0);
  			}
  			return delays;
  		};
  
  		function fxGetDeltas() { // get reveal delta
  			var deltas = [];
  			for(var i = 0; i < fxElements.length; i++) {
  				deltas.push( fxElements[i].getAttribute('data-reveal-fx-delta') ? parseInt(fxElements[i].getAttribute('data-reveal-fx-delta')) : fxRevealDelta);
  			}
  			return deltas;
  		};
  
  		function fxDisabled(element) { // check if elements need to be animated - no animation on small devices
  			return !(window.getComputedStyle(element, '::before').getPropertyValue('content').replace(/'|"/g, "") == 'reveal-fx');
  		};
  
  		function fxElementIsVisible(element, i) { // element is inside viewport
  			return (fxGetElementPosition(element) <= viewportHeight - fxElementDeltas[i]);
  		};
  
  		function fxGetElementPosition(element) { // get top position of element
  			return element.getBoundingClientRect().top;
  		};
  
  		function fxResetEvents() { 
  			if(fxElements.length > fxRevealedItems.length) return;
  			// remove event listeners if all elements have been revealed
  			window.removeEventListener('load', fxReveal);
  			window.removeEventListener('resize', fxResize);
  		};
  
  		function fxRemoveClasses() {
  			// Reduced Motion on or Intersection Observer not supported
  			while(fxElements[0]) {
  				// remove all classes starting with 'reveal-fx--'
  				var classes = fxElements[0].getAttribute('class').split(" ").filter(function(c) {
  					return c.lastIndexOf('reveal-fx--', 0) !== 0;
  				});
  				fxElements[0].setAttribute('class', classes.join(" ").trim());
  				Util.removeClass(fxElements[0], 'reveal-fx');
  			}
  		};
  
  		function fxRestart() {
        // restart the reveal effect -> hide all elements and re-init the observer
        if (Util.osHasReducedMotion() || !intersectionObserverSupported || fxDisabled(fxElements[0])) {
          return;
        }
        // check if we need to add the event listensers back
        if(fxElements.length <= fxRevealedItems.length) {
          window.addEventListener('load', fxReveal);
          window.addEventListener('resize', fxResize);
        }
        // remove observer and reset the observer array
        for(var i = 0; i < observer.length; i++) {
          if(observer[i]) observer[i].disconnect();
        }
        observer = [];
        // remove visible class
        for(var i = 0; i < fxElements.length; i++) {
          Util.removeClass(fxElements[i], 'reveal-fx--is-visible');
        }
        // reset fxRevealedItems array
        fxRevealedItems = [];
        // restart observer
        initObserver();
      };
  	}
  }());
  // File#: _1_revealing-section
  // Usage: codyhouse.co/license
  (function() {
    var RevealingSection = function(element) {
      this.element = element;
      this.scrollingFn = false;
      this.scrolling = false;
      this.resetOpacity = false;
      initRevealingSection(this);
    };
  
    function initRevealingSection(element) {
      // set position of sticky element
      setBottom(element);
      // create a new node - to be inserted before the sticky element
      createPrevElement(element);
      // on resize -> reset element bottom position
      element.element.addEventListener('update-reveal-section', function(){
        setBottom(element);
        setPrevElementTop(element);
      });
      animateRevealingSection.bind(element)(); // set initial status
      // change opacity of layer
      var observer = new IntersectionObserver(revealingSectionCallback.bind(element));
  		observer.observe(element.prevElement);
    };
  
    function createPrevElement(element) {
      var newElement = document.createElement("div"); 
      newElement.setAttribute('aria-hidden', 'true');
      element.element.parentElement.insertBefore(newElement, element.element);
      element.prevElement =  element.element.previousElementSibling;
      element.prevElement.style.opacity = '0';
      element.prevElement.style.height = '1px';
      setPrevElementTop(element);
    };
  
    function setPrevElementTop(element) {
      element.prevElementTop = element.prevElement.getBoundingClientRect().top + window.scrollY;
    };
  
    function revealingSectionCallback(entries, observer) {
  		if(entries[0].isIntersecting) {
        if(this.scrollingFn) return; // listener for scroll event already added
        revealingSectionInitEvent(this);
      } else {
        if(!this.scrollingFn) return; // listener for scroll event already removed
        window.removeEventListener('scroll', this.scrollingFn);
        updateOpacityValue(this, 0);
        this.scrollingFn = false;
      }
    };
    
    function revealingSectionInitEvent(element) {
      element.scrollingFn = revealingSectionScrolling.bind(element);
      window.addEventListener('scroll', element.scrollingFn);
    };
  
    function revealingSectionScrolling() {
      if(this.scrolling) return;
      this.scrolling = true;
      window.requestAnimationFrame(animateRevealingSection.bind(this));
    };
  
    function animateRevealingSection() {
      if(this.prevElementTop - window.scrollY < window.innerHeight) {
        var opacity = (1 - (window.innerHeight + window.scrollY - this.prevElementTop)/window.innerHeight).toFixed(2);
        if(opacity > 0 ) {
          this.resetOpacity = false;
          updateOpacityValue(this, opacity);
        } else if(!this.resetOpacity) {
          this.resetOpacity = true;
          updateOpacityValue(this, 0);
        } 
      }
      this.scrolling = false;
    };
  
    function updateOpacityValue(element, value) {
      element.element.style.setProperty('--reavealing-section-overlay-opacity', value);
    };
  
    function setBottom(element) {
      var translateValue = window.innerHeight - element.element.offsetHeight;
      if(translateValue > 0) translateValue = 0;
      element.element.style.bottom = ''+translateValue+'px';
    };
  
    //initialize the Revealing Section objects
    var revealingSection = document.getElementsByClassName('js-revealing-section');
    var stickySupported = Util.cssSupports('position', 'sticky') || Util.cssSupports('position', '-webkit-sticky');
  	if( revealingSection.length > 0 && stickySupported) {
      var revealingSectionArray = [];
  		for( var i = 0; i < revealingSection.length; i++) {
        (function(i){revealingSectionArray.push(new RevealingSection(revealingSection[i]));})(i);
      }
      
      var resizingId = false,
        customEvent = new CustomEvent('update-reveal-section');
  
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 100);
      });
  
      // wait for font to be loaded
      if(document.fonts) {
        document.fonts.onloadingdone = function (fontFaceSetEvent) {
          doneResizing();
        };
      }
  
      function doneResizing() {
        for( var i = 0; i < revealingSectionArray.length; i++) {
          (function(i){revealingSectionArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  	}
  }());
  // File#: _1_row-table
  // Usage: codyhouse.co/license
  (function() {
  	var RowTable = function(element) {
      this.element = element;
      this.headerRows = this.element.getElementsByTagName('thead')[0].getElementsByTagName('th');
      this.tableRows = this.element.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
      this.collapsedLayoutClass = 'row-table--collapsed';
      this.mainRowCellClass = 'row-table__th-inner';
      initTable(this);
    };
  
    function initTable(table) {
      checkTableLayour(table); // switch from a collapsed to an expanded layout
  
      // create additional table content
      addTableContent(table);
  
      // custom event emitted when window is resized
      table.element.addEventListener('update-row-table', function(event){
        checkTableLayour(table);
      });
  
      // mobile version - listent to click/key enter on the row -> expand it
      table.element.addEventListener('click', function(event){
        revealRowDetails(table, event);
      });
      table.element.addEventListener('keydown', function(event){
        if(event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {
          revealRowDetails(table, event);
        }
      });
    };
  
    function checkTableLayour(table) {
      var layout = getComputedStyle(table.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(table.element, table.collapsedLayoutClass, layout == 'expanded');
    };
  
    function addTableContent(table) {
      // for the expanded version, add a ul with list of details for each table row
      for(var i = 0; i < table.tableRows.length; i++) {
        var content = '';
        var cells = table.tableRows[i].getElementsByClassName('row-table__cell');
        for(var j = 0; j < cells.length; j++) {
          if(j == 0 ) {
            Util.addClass(cells[j], 'js-'+table.mainRowCellClass);
            var cellLabel = cells[j].getElementsByClassName('row-table__th-inner');
            if(cellLabel.length > 0 ) cellLabel[0].innerHTML = cellLabel[0].innerHTML + '<i class="row-table__th-icon" aria-hidden="true"></i>'
          } else {
            content = content + '<li class="row-table__item"><span class="row-table__label">'+table.headerRows[j].innerHTML+':</span><span>'+cells[j].innerHTML+'</span></li>';
          }
        }
        content = '<ul class="row-table__list" aria-hidden="true">'+content+'</ul>';
        cells[0].innerHTML = '<input type="text" class="row-table__input" aria-hidden="true">'+cells[0].innerHTML + content;
      }
    };
  
    function revealRowDetails(table, event) {
      if(!event.target.closest('.js-'+table.mainRowCellClass) || event.target.closest('.row-table__list')) return;
      var row = event.target.closest('.js-'+table.mainRowCellClass);
      Util.toggleClass(row, 'row-table__cell--show-list', !Util.hasClass(row, 'row-table__cell--show-list'));
    };
  
    //initialize the RowTable objects
  	var rowTables = document.getElementsByClassName('js-row-table');
  	if( rowTables.length > 0 ) {
      var j = 0,
      rowTablesArray = [];
  		for( var i = 0; i < rowTables.length; i++) {
        var beforeContent = getComputedStyle(rowTables[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){rowTablesArray.push(new RowTable(rowTables[i]));})(i);
          j = j + 1;
        }
      }
      
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-row-table');
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < rowTablesArray.length; i++) {
            (function(i){rowTablesArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  
        (window.requestAnimationFrame) // init table layout
          ? window.requestAnimationFrame(doneResizing)
          : doneResizing();
      }
  	}
  }());
  // File#: _1_scrolling-animations
  // Usage: codyhouse.co/license
  (function() {
    var ScrollFx = function(element, scrollableSelector) {
      this.element = element;
      this.options = [];
      this.boundingRect = this.element.getBoundingClientRect();
      this.windowHeight = window.innerHeight;
      this.scrollingFx = [];
      this.animating = [];
      this.deltaScrolling = [];
      this.observer = [];
      this.scrollableSelector = scrollableSelector; // if the scrollable element is not the window 
      this.scrollableElement = false;
      initScrollFx(this);
      // ToDo - option to pass two selectors to target the element start and stop animation scrolling values -> to be used for sticky/fixed elements
    };
  
    function initScrollFx(element) {
      // do not animate if reduced motion is on
      if(Util.osHasReducedMotion()) return;
      // get scrollable element
      setScrollableElement(element);
      // get animation params
      var animation = element.element.getAttribute('data-scroll-fx');
      if(animation) {
        element.options.push(extractAnimation(animation));
      } else {
        getAnimations(element, 1);
      }
      // set Intersection Observer
      initObserver(element);
      // update params on resize
      initResize(element);
    };
  
    function setScrollableElement(element) {
      if(element.scrollableSelector) element.scrollableElement = document.querySelector(element.scrollableSelector);
    };
  
    function initObserver(element) {
      for(var i = 0; i < element.options.length; i++) {
        (function(i){
          element.scrollingFx[i] = false;
          element.deltaScrolling[i] = getDeltaScrolling(element, i);
          element.animating[i] = false;
  
          element.observer[i] = new IntersectionObserver(
            function(entries, observer) { 
              scrollFxCallback(element, i, entries, observer);
            },
            {
              rootMargin: (element.options[i][5] -100)+"% 0px "+(0 - element.options[i][4])+"% 0px"
            }
          );
      
          element.observer[i].observe(element.element);
  
          // set initial value
          setTimeout(function(){
            animateScrollFx.bind(element, i)();
          })
        })(i);
      }
    };
  
    function scrollFxCallback(element, index, entries, observer) {
  		if(entries[0].isIntersecting) {
        if(element.scrollingFx[index]) return; // listener for scroll event already added
        // reset delta
        resetDeltaBeforeAnim(element, index);
        triggerAnimateScrollFx(element, index);
      } else {
        if(!element.scrollingFx[index]) return; // listener for scroll event already removed
        window.removeEventListener('scroll', element.scrollingFx[index]);
        element.scrollingFx[index] = false;
      }
    };
  
    function triggerAnimateScrollFx(element, index) {
      element.scrollingFx[index] = animateScrollFx.bind(element, index);
      (element.scrollableElement)
        ? element.scrollableElement.addEventListener('scroll', element.scrollingFx[index])
        : window.addEventListener('scroll', element.scrollingFx[index]);
    };
  
    function animateScrollFx(index) {
      // if window scroll is outside the proper range -> return
      if(getScrollY(this) < this.deltaScrolling[index][0]) {
        setCSSProperty(this, index, this.options[index][1]);
        return;
      }
      if(getScrollY(this) > this.deltaScrolling[index][1]) {
        setCSSProperty(this, index, this.options[index][2]);
        return;
      }
      if(this.animating[index]) return;
      this.animating[index] = true;
      window.requestAnimationFrame(updatePropertyScroll.bind(this, index));
    };
  
    function updatePropertyScroll(index) { // get value
      // check if this is a theme value or a css property
      if(isNaN(this.options[index][1])) {
        // this is a theme value to update
        (getScrollY(this) >= this.deltaScrolling[index][1]) 
          ? setCSSProperty(this, index, this.options[index][2])
          : setCSSProperty(this, index, this.options[index][1]);
      } else {
        // this is a CSS property
        var value = this.options[index][1] + (this.options[index][2] - this.options[index][1])*(getScrollY(this) - this.deltaScrolling[index][0])/(this.deltaScrolling[index][1] - this.deltaScrolling[index][0]);
        // update css property
        setCSSProperty(this, index, value);
      }
      
      this.animating[index] = false;
    };
  
    function setCSSProperty(element, index, value) {
      if(isNaN(value)) {
        // this is a theme value that needs to be updated
        setThemeValue(element, value);
        return;
      }
      if(element.options[index][0] == '--scroll-fx-skew' || element.options[index][0] == '--scroll-fx-scale') {
        // set 2 different CSS properties for the transformation on both x and y axis
        element.element.style.setProperty(element.options[index][0]+'-x', value+element.options[index][3]);
        element.element.style.setProperty(element.options[index][0]+'-y', value+element.options[index][3]);
      } else {
        // set single CSS property
        element.element.style.setProperty(element.options[index][0], value+element.options[index][3]);
      }
    };
  
    function setThemeValue(element, value) {
      // if value is different from the theme in use -> update it
      if(element.element.getAttribute('data-theme') != value) {
        Util.addClass(element.element, 'scroll-fx--theme-transition');
        element.element.offsetWidth;
        element.element.setAttribute('data-theme', value);
        element.element.addEventListener('transitionend', function cb(){
          element.element.removeEventListener('transitionend', cb);
          Util.removeClass(element.element, 'scroll-fx--theme-transition');
        });
      }
    };
  
    function getAnimations(element, index) {
      var option = element.element.getAttribute('data-scroll-fx-'+index);
      if(option) {
        // multiple animations for the same element - iterate through them
        element.options.push(extractAnimation(option));
        getAnimations(element, index+1);
      } 
      return;
    };
  
    function extractAnimation(option) {
      var array = option.split(',').map(function(item) {
        return item.trim();
      });
      var propertyOptions = getPropertyValues(array[1], array[2]);
      var animation = [getPropertyLabel(array[0]), propertyOptions[0], propertyOptions[1], propertyOptions[2], parseInt(array[3]), parseInt(array[4])];
      return animation;
    };
  
    function getPropertyLabel(property) {
      var propertyCss = '--scroll-fx-';
      for(var i = 0; i < property.length; i++) {
        propertyCss = (property[i] == property[i].toUpperCase())
          ? propertyCss + '-'+property[i].toLowerCase()
          : propertyCss +property[i];
      }
      if(propertyCss == '--scroll-fx-rotate') {
        propertyCss = '--scroll-fx-rotate-z';
      } else if(propertyCss == '--scroll-fx-translate') {
        propertyCss = '--scroll-fx-translate-x';
      }
      return propertyCss;
    };
  
    function getPropertyValues(val1, val2) {
      var nbVal1 = parseFloat(val1), 
        nbVal2 = parseFloat(val2),
        unit = val1.replace(nbVal1, '');
      if(isNaN(nbVal1)) {
        // property is a theme value
        nbVal1 = val1;
        nbVal2 = val2;
        unit = '';
      }
      return [nbVal1, nbVal2, unit];
    };
  
    function getDeltaScrolling(element, index) {
      // this retrieve the max and min scroll value that should trigger the animation
      var topDelta = getScrollY(element) - (element.windowHeight - (element.windowHeight + element.boundingRect.height)*element.options[index][4]/100) + element.boundingRect.top,
        bottomDelta = getScrollY(element) - (element.windowHeight - (element.windowHeight + element.boundingRect.height)*element.options[index][5]/100) + element.boundingRect.top;
      return [topDelta, bottomDelta];
    };
  
    function initResize(element) {
      var resizingId = false;
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(resetResize.bind(element), 500);
      });
      // emit custom event -> elements have been initialized
      var event = new CustomEvent('scrollFxReady');
  		element.element.dispatchEvent(event);
    };
  
    function resetResize() {
      // on resize -> make sure to update all scrolling delta values
      this.boundingRect = this.element.getBoundingClientRect();
      this.windowHeight = window.innerHeight;
      for(var i = 0; i < this.deltaScrolling.length; i++) {
        this.deltaScrolling[i] = getDeltaScrolling(this, i);
        animateScrollFx.bind(this, i)();
      }
      // emit custom event -> elements have been resized
      var event = new CustomEvent('scrollFxResized');
  		this.element.dispatchEvent(event);
    };
  
    function resetDeltaBeforeAnim(element, index) {
      element.boundingRect = element.element.getBoundingClientRect();
      element.windowHeight = window.innerHeight;
      element.deltaScrolling[index] = getDeltaScrolling(element, index);
    };
  
    function getScrollY(element) {
      if(!element.scrollableElement) return window.scrollY;
      return element.scrollableElement.scrollTop;
    }
  
    window.ScrollFx = ScrollFx;
  
    var scrollFx = document.getElementsByClassName('js-scroll-fx');
    for(var i = 0; i < scrollFx.length; i++) {
      (function(i){
        var scrollableElement = scrollFx[i].getAttribute('data-scrollable-element');
        new ScrollFx(scrollFx[i], scrollableElement);
      })(i);
    }
  }());
  // File#: _1_side-navigation-v2
  // Usage: codyhouse.co/license
  (function() {
    var SideNav2 = function(element) {
      this.element = element;
      this.controller = this.element.getElementsByClassName('js-sidenav-v2__control');
      this.staticLayoutClass = 'sidenav-v2--static';
      this.expandedClass = 'sidenav-v2--expanded';
      this.isStatic = Util.hasClass(this.element, this.staticLayoutClass);
      this.layout = 'static';
      this.customStatic = this.element.getAttribute('data-static-class');
      this.sideNavItems = this.element.getElementsByClassName('js-sidenav-v2__link');
      initSideNav2(this);
    };
  
    function initSideNav2(element) {
      checkNavLayour(element);
  
      // custom event emitted when window is resized
      element.element.addEventListener('update-side-nav-v2', function(event){
        checkNavLayour(element);
      });
  
      // collapsed version only (mobile)
      initCollapsedVersion(element);
    };
  
    function initCollapsedVersion(element) { // collapsed version only (mobile)
      if(element.controller.length < 1) return;
      
      // toggle nav visibility
      element.controller[0].addEventListener('click', function(event){
        var isOpen = Util.hasClass(element.element, element.expandedClass);
        toggleSideNav(element, isOpen);
      });
  
      // close expanded version on esc
      element.element.addEventListener('keydown', function(event){
        if(element.layout == 'static') return;
        if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape') ) {
          toggleSideNav(element, true);
          element.controller[0].focus();
        }
      });
    };
  
    function toggleSideNav(element, bool) {
      Util.toggleClass(element.element, element.expandedClass, !bool);
      bool ? element.controller[0].removeAttribute('aria-expanded') : element.controller[0].setAttribute('aria-expanded', 'true');
      if(!bool && element.sideNavItems.length > 0) {
        element.sideNavItems[0].focus();
      }
    };
  
    function checkNavLayour(element) {
      if(element.isStatic) return;
      element.layout = getComputedStyle(element.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(element.element, element.staticLayoutClass, element.layout == 'static');
      if(element.customStatic) Util.toggleClass(element.element, element.customStatic, element.layout == 'static');
    };
  
    //initialize the SideNav2 objects
  	var sideNav = document.getElementsByClassName('js-sidenav-v2');
  	if( sideNav.length > 0 ) {
      var sideNavArray = [];
  		for( var i = 0; i < sideNav.length; i++) {
        (function(i){sideNavArray.push(new SideNav2(sideNav[i]));})(i);
      }
  
      var resizingId = false,
        customEvent = new CustomEvent('update-side-nav-v2');
      window.addEventListener('resize', function(event){
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 300);
      });
  
      function doneResizing() {
        for( var i = 0; i < sideNavArray.length; i++) {
          (function(i){sideNavArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  
      (window.requestAnimationFrame) // init side nav layout
        ? window.requestAnimationFrame(doneResizing)
        : doneResizing();
  	}
  }());
  // File#: _1_side-navigation
  // Usage: codyhouse.co/license
  (function() {
    function initSideNav(nav) {
      nav.addEventListener('click', function(event){
        var btn = event.target.closest('.js-sidenav__sublist-control');
        if(!btn) return;
        var listItem = btn.parentElement,
          bool = Util.hasClass(listItem, 'sidenav__item--expanded');
        btn.setAttribute('aria-expanded', !bool);
        Util.toggleClass(listItem, 'sidenav__item--expanded', !bool);
      });
    };
  
  	var sideNavs = document.getElementsByClassName('js-sidenav');
  	if( sideNavs.length > 0 ) {
  		for( var i = 0; i < sideNavs.length; i++) {
        (function(i){initSideNav(sideNavs[i]);})(i);
  		}
  	}
  }());
  // File#: _1_skip-link
  // Usage: codyhouse.co/license
  (function() {
    function initSkipLinkEvents(skipLink) {
      // toggle class skip-link--focus if link is in focus/loses focus
      skipLink.addEventListener('focusin', function(){
        Util.addClass(skipLink, 'skip-link--focus');
      });
      skipLink.addEventListener('focusout', function(){
        Util.removeClass(skipLink, 'skip-link--focus');
      });
    };
  
    var skipLinks = document.getElementsByClassName('skip-link');
  	if( skipLinks.length > 0 ) {
  		for( var i = 0; i < skipLinks.length; i++) {
  			initSkipLinkEvents(skipLinks[i]);
  		}
    }
  }());
  // File#: _1_slider
  // Usage: codyhouse.co/license
  (function() {
  	var Slider = function(element) {
  		this.element = element;
  		this.rangeWrapper = this.element.getElementsByClassName('slider__range');
  		this.rangeInput = this.element.getElementsByClassName('slider__input');
  		this.value = this.element.getElementsByClassName('js-slider__value'); 
  		this.floatingValue = this.element.getElementsByClassName('js-slider__value--floating'); 
  		this.rangeMin = this.rangeInput[0].getAttribute('min');
  		this.rangeMax = this.rangeInput[0].getAttribute('max');
  		this.sliderWidth = window.getComputedStyle(this.element.getElementsByClassName('slider__range')[0]).getPropertyValue('width');
  		this.thumbWidth = getComputedStyle(this.element).getPropertyValue('--slide-thumb-size');
  		this.isInputVar = (this.value[0].tagName.toLowerCase() == 'input');
  		this.isFloatingVar = this.floatingValue.length > 0;
  		if(this.isFloatingVar) {
  			this.floatingValueLeft = window.getComputedStyle(this.floatingValue[0]).getPropertyValue('left');
  		}
  		initSlider(this);
  	};
  
  	function initSlider(slider) {
  		updateLabelValues(slider);// update label/input value so that it is the same as the input range
  		updateLabelPosition(slider, false); // update label position if floating variation
  		updateRangeColor(slider, false); // update range bg color
  		checkRangeSupported(slider); // hide label/input value if input range is not supported
  		
  		// listen to change in the input range
  		for(var i = 0; i < slider.rangeInput.length; i++) {
  			(function(i){
  				slider.rangeInput[i].addEventListener('input', function(event){
  					updateSlider(slider, i);
  				});
  				slider.rangeInput[i].addEventListener('change', function(event){ // fix issue on IE where input event is not emitted
  					updateSlider(slider, i);
  				});
  			})(i);
  		}
  
  		// if there's an input text, listen for changes in value, validate it and then update slider
  		if(slider.isInputVar) {
  			for(var i = 0; i < slider.value.length; i++) {
  				(function(i){
  					slider.value[i].addEventListener('change', function(event){
  						updateRange(slider, i);
  					});
  				})(i);
  			}
  		}
  
  		// native <input> element has been updated (e.g., form reset) -> update custom appearance
  		slider.element.addEventListener('slider-updated', function(event){
  			for(var i = 0; i < slider.value.length; i++) {updateSlider(slider, i);}
  		});
  
  		// custom events - emitted if slider has allows for multi-values
  		slider.element.addEventListener('inputRangeLimit', function(event){
  			updateLabelValues(slider);
  			updateLabelPosition(slider, event.detail);
  		});
  	};
  
  	function updateSlider(slider, index) {
  		updateLabelValues(slider);
  		updateLabelPosition(slider, index);
  		updateRangeColor(slider, index);
  	};
  
  	function updateLabelValues(slider) {
  		for(var i = 0; i < slider.rangeInput.length; i++) {
  			slider.isInputVar ? slider.value[i].value = slider.rangeInput[i].value : slider.value[i].textContent = slider.rangeInput[i].value;
  		}
  	};
  
  	function updateLabelPosition(slider, index) {
  		if(!slider.isFloatingVar) return;
  		var i = index ? index : 0,
  			j = index ? index + 1: slider.rangeInput.length;
  		for(var k = i; k < j; k++) {
  			var percentage = (slider.rangeInput[k].value - slider.rangeMin)/(slider.rangeMax - slider.rangeMin);
  			slider.floatingValue[k].style.left = 'calc(0.5 * '+slider.floatingValueLeft+' + '+percentage+' * ( '+slider.sliderWidth+' - '+slider.floatingValueLeft+' ))';
  		}
  	};
  
  	function updateRangeColor(slider, index) {
  		if(slider.rangeInput.length > 1) {slider.element.dispatchEvent(new CustomEvent('updateRange', {detail: index}));return;}
  		var percentage = parseInt((slider.rangeInput[0].value - slider.rangeMin)/(slider.rangeMax - slider.rangeMin)*100),
  			fill = 'calc('+percentage+'*('+slider.sliderWidth+' - 0.5*'+slider.thumbWidth+')/100)',
  			empty = 'calc('+slider.sliderWidth+' - '+percentage+'*('+slider.sliderWidth+' - 0.5*'+slider.thumbWidth+')/100)';
  
  		slider.rangeWrapper[0].style.setProperty('--slider-fill-value', fill);
  		slider.rangeWrapper[0].style.setProperty('--slider-empty-value', empty);
  	};
  
  	function updateRange(slider, index) {
  		var newValue = parseFloat(slider.value[index].value);
  		if(isNaN(newValue)) {
  			slider.value[index].value = slider.rangeInput[index].value;
  			return;
  		} else {
  			if(newValue < slider.rangeMin) newValue = slider.rangeMin;
  			if(newValue > slider.rangeMax) newValue = slider.rangeMax;
  			slider.rangeInput[index].value = newValue;
  			var inputEvent = new Event('change');
  			slider.rangeInput[index].dispatchEvent(inputEvent);
  		}
  	};
  
  	function checkRangeSupported(slider) {
  		var input = document.createElement("input");
  		input.setAttribute("type", "range");
  		Util.toggleClass(slider.element, 'slider--range-not-supported', input.type !== "range");
  	};
  
  	//initialize the Slider objects
  	var sliders = document.getElementsByClassName('js-slider');
  	if( sliders.length > 0 ) {
  		for( var i = 0; i < sliders.length; i++) {
  			(function(i){new Slider(sliders[i]);})(i);
  		}
  	}
  }());
  // File#: _1_sliding-panels
  // Usage: codyhouse.co/license
  (function() {
    var SlidingPanels = function(element) {
      this.element = element;
      this.itemsList = this.element.getElementsByClassName('js-s-panels__projects-list');
      this.items = this.itemsList[0].getElementsByClassName('js-s-panels__project-preview');
      this.navigationToggle = this.element.getElementsByClassName('js-s-panels__nav-control');
      this.navigation = this.element.getElementsByClassName('js-s-panels__nav-wrapper');
      this.transitionLayer = this.element.getElementsByClassName('js-s-panels__overlay-layer');
      this.selectedSection = false; // will be used to store the visible project content section
      this.animating = false;
      // aria labels for the navigationToggle button
      this.toggleAriaLabels = ['Toggle navigation', 'Close Project'];
      initSlidingPanels(this);
    };
  
    function initSlidingPanels(element) {
      // detect click on toggle menu
      if(element.navigationToggle.length > 0 && element.navigation.length > 0) {
        element.navigationToggle[0].addEventListener('click', function(event) {
          if(element.animating) return;
          
          // if project is open -> close project
          if(closeProjectIfVisible(element)) return;
          
          // toggle navigation
          var openNav = Util.hasClass(element.navigation[0], 'is-hidden');
          toggleNavigation(element, openNav);
        });
      }
  
      // open project
      element.element.addEventListener('click', function(event) {
        if(element.animating) return;
  
        var link = event.target.closest('.js-s-panels__project-control');
        if(!link) return;
        event.preventDefault();
        openProject(element, event.target.closest('.js-s-panels__project-preview'), link.getAttribute('href').replace('#', ''));
      });
    };
  
    // check if there's a visible project to close and close it
    function closeProjectIfVisible(element) {
      var visibleProject = element.element.getElementsByClassName('s-panels__project-preview--selected');
      if(visibleProject.length > 0) {
        element.animating = true;
        closeProject(element);
        return true;
      }
  
      return false;
    };
  
    function toggleNavigation(element, openNavigation) {
      element.animating = true;
      if(openNavigation) Util.removeClass(element.navigation[0], 'is-hidden');
      slideProjects(element, openNavigation, false, function(){
        element.animating = false;
        if(!openNavigation) Util.addClass(element.navigation[0], 'is-hidden');
      });
      Util.toggleClass(element.navigationToggle[0], 's-panels__nav-control--arrow-down', openNavigation);
    };
  
    function openProject(element, project, id) {
      element.animating = true;
      var projectIndex = Util.getIndexInArray(element.items, project);
      // hide navigation
      Util.removeClass(element.itemsList[0], 'bg-opacity-0');
      // expand selected projects
      Util.addClass(project, 's-panels__project-preview--selected');
      // hide remaining projects
      slideProjects(element, true, projectIndex, function() {
        // reveal section content
        element.selectedSection = document.getElementById(id);
        if(element.selectedSection) Util.removeClass(element.selectedSection, 'is-hidden');
        element.animating = false;
        // trigger a custom event - this can be used to init the project content (if required)
  		  element.element.dispatchEvent(new CustomEvent('slidingPanelOpen', {detail: projectIndex}));
      });
      // modify toggle button appearance
      Util.addClass(element.navigationToggle[0], 's-panels__nav-control--close');
      // modify toggle button aria-label
      element.navigationToggle[0].setAttribute('aria-label', element.toggleAriaLabels[1]);
    };
  
    function closeProject(element) {
      // remove transitions from projects
      toggleTransitionProjects(element, true);
      // hide navigation
      Util.removeClass(element.itemsList[0], 'bg-opacity-0');
      // reveal transition layer
      Util.addClass(element.transitionLayer[0], 's-panels__overlay-layer--visible');
      // wait for end of transition layer effect
      element.transitionLayer[0].addEventListener('transitionend', function cb(event) {
        if(event.propertyName != 'opacity') return;
        element.transitionLayer[0].removeEventListener('transitionend', cb);
        // update projects classes
        resetProjects(element);
  
        setTimeout(function(){
          // hide transition layer
          Util.removeClass(element.transitionLayer[0], 's-panels__overlay-layer--visible');
          // reveal projects
          slideProjects(element, false, false, function() {
            Util.addClass(element.itemsList[0], 'bg-opacity-0');
            element.animating = false;
          });
        }, 200);
      });
  
      // modify toggle button appearance
      Util.removeClass(element.navigationToggle[0], 's-panels__nav-control--close');
      // modify toggle button aria-label
      element.navigationToggle[0].setAttribute('aria-label', element.toggleAriaLabels[0]);
    };
  
    function slideProjects(element, openNav, exclude, cb) {
      // projects will slide out in a random order
      var randomList = getRandomList(element.items.length, exclude);
      for(var i = 0; i < randomList.length; i++) {(function(i){
        setTimeout(function(){
          Util.toggleClass(element.items[randomList[i]], 's-panels__project-preview--hide', openNav);
          toggleProjectAccessibility(element.items[randomList[i]], openNav);
          if(cb && i == randomList.length - 1) {
            // last item to be animated -> execute callback function at the end of the animation
            element.items[randomList[i]].addEventListener('transitionend', function cbt() {
              if(event.propertyName != 'transform') return;
              if(cb) cb();
              element.items[randomList[i]].removeEventListener('transitionend', cbt);
            });
          }
        }, i*100);
      })(i);}
    };
  
    function toggleTransitionProjects(element, bool) {
      // remove transitions from project elements
      for(var i = 0; i < element.items.length; i++) {
        Util.toggleClass(element.items[i], 's-panels__project-preview--no-transition', bool);
      }
    };
  
    function resetProjects(element) {
      // reset projects classes -> remove selected/no-transition class + add hide class
      for(var i = 0; i < element.items.length; i++) {
        Util.removeClass(element.items[i], 's-panels__project-preview--selected s-panels__project-preview--no-transition');
        Util.addClass(element.items[i], 's-panels__project-preview--hide');
      }
  
      // hide project content
      if(element.selectedSection) Util.addClass(element.selectedSection, 'is-hidden');
      element.selectedSection = false;
    };
  
    function getRandomList(maxVal, exclude) {
      // get list of random integer from 0 to (maxVal - 1) excluding (exclude) if defined
      var uniqueRandoms = [];
      var randomArray = [];
      
      function makeUniqueRandom() {
        // refill the array if needed
        if (!uniqueRandoms.length) {
          for (var i = 0; i < maxVal; i++) {
            if(exclude === false || i != exclude) uniqueRandoms.push(i);
          }
        }
        var index = Math.floor(Math.random() * uniqueRandoms.length);
        var val = uniqueRandoms[index];
        // now remove that value from the array
        uniqueRandoms.splice(index, 1);
        return val;
      }
  
      for(var j = 0; j < maxVal; j++) {
        randomArray.push(makeUniqueRandom());
      }
  
      return randomArray;
    };
  
    function toggleProjectAccessibility(project, bool) {
      bool ? project.setAttribute('aria-hidden', 'true') : project.removeAttribute('aria-hidden');
      var link = project.getElementsByClassName('js-s-panels__project-control');
      if(link.length > 0) {
        bool ? link[0].setAttribute('tabindex', '-1') : link[0].removeAttribute('tabindex');
      }
    };
  
    //initialize the SlidingPanels objects
  	var slidingPanels = document.getElementsByClassName('js-s-panels');
  	if( slidingPanels.length > 0 ) {
  		for( var i = 0; i < slidingPanels.length; i++) {
  			(function(i){new SlidingPanels(slidingPanels[i]);})(i);
  		}
  	}
  }());
  // File#: _1_smooth-scrolling
  // Usage: codyhouse.co/license
  (function() {
  	var SmoothScroll = function(element) {
  		if(!('CSS' in window) || !CSS.supports('color', 'var(--color-var)')) return;
  		this.element = element;
  		this.scrollDuration = parseInt(this.element.getAttribute('data-duration')) || 300;
  		this.dataElementY = this.element.getAttribute('data-scrollable-element-y') || this.element.getAttribute('data-scrollable-element') || this.element.getAttribute('data-element');
  		this.scrollElementY = this.dataElementY ? document.querySelector(this.dataElementY) : window;
  		this.dataElementX = this.element.getAttribute('data-scrollable-element-x');
  		this.scrollElementX = this.dataElementY ? document.querySelector(this.dataElementX) : window;
  		this.initScroll();
  	};
  
  	SmoothScroll.prototype.initScroll = function() {
  		var self = this;
  
  		//detect click on link
  		this.element.addEventListener('click', function(event){
  			event.preventDefault();
  			var targetId = event.target.closest('.js-smooth-scroll').getAttribute('href').replace('#', ''),
  				target = document.getElementById(targetId),
  				targetTabIndex = target.getAttribute('tabindex'),
  				windowScrollTop = self.scrollElementY.scrollTop || document.documentElement.scrollTop;
  
  			// scroll vertically
  			if(!self.dataElementY) windowScrollTop = window.scrollY || document.documentElement.scrollTop;
  
  			var scrollElementY = self.dataElementY ? self.scrollElementY : false;
  
  			var fixedHeight = self.getFixedElementHeight(); // check if there's a fixed element on the page
  			Util.scrollTo(target.getBoundingClientRect().top + windowScrollTop - fixedHeight, self.scrollDuration, function() {
  				// scroll horizontally
  				self.scrollHorizontally(target, fixedHeight);
  				//move the focus to the target element - don't break keyboard navigation
  				Util.moveFocus(target);
  				history.pushState(false, false, '#'+targetId);
  				self.resetTarget(target, targetTabIndex);
  			}, scrollElementY);
  		});
  	};
  
  	SmoothScroll.prototype.scrollHorizontally = function(target, delta) {
      var scrollEl = this.dataElementX ? this.scrollElementX : false;
      var windowScrollLeft = this.scrollElementX ? this.scrollElementX.scrollLeft : document.documentElement.scrollLeft;
      var final = target.getBoundingClientRect().left + windowScrollLeft - delta,
        duration = this.scrollDuration;
  
      var element = scrollEl || window;
      var start = element.scrollLeft || document.documentElement.scrollLeft,
        currentTime = null;
  
      if(!scrollEl) start = window.scrollX || document.documentElement.scrollLeft;
  		// return if there's no need to scroll
      if(Math.abs(start - final) < 5) return;
          
      var animateScroll = function(timestamp){
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        var val = Math.easeInOutQuad(progress, start, final-start, duration);
        element.scrollTo({
  				left: val,
  			});
        if(progress < duration) {
          window.requestAnimationFrame(animateScroll);
        }
      };
  
      window.requestAnimationFrame(animateScroll);
    };
  
  	SmoothScroll.prototype.resetTarget = function(target, tabindex) {
  		if( parseInt(target.getAttribute('tabindex')) < 0) {
  			target.style.outline = 'none';
  			!tabindex && target.removeAttribute('tabindex');
  		}	
  	};
  
  	SmoothScroll.prototype.getFixedElementHeight = function() {
  		var scrollElementY = this.dataElementY ? this.scrollElementY : document.documentElement;
      var fixedElementDelta = parseInt(getComputedStyle(scrollElementY).getPropertyValue('scroll-padding'));
  		if(isNaN(fixedElementDelta) ) { // scroll-padding not supported
  			fixedElementDelta = 0;
  			var fixedElement = document.querySelector(this.element.getAttribute('data-fixed-element'));
  			if(fixedElement) fixedElementDelta = parseInt(fixedElement.getBoundingClientRect().height);
  		}
  		return fixedElementDelta;
  	};
  	
  	//initialize the Smooth Scroll objects
  	var smoothScrollLinks = document.getElementsByClassName('js-smooth-scroll');
  	if( smoothScrollLinks.length > 0 && !Util.cssSupports('scroll-behavior', 'smooth') && window.requestAnimationFrame) {
  		// you need javascript only if css scroll-behavior is not supported
  		for( var i = 0; i < smoothScrollLinks.length; i++) {
  			(function(i){new SmoothScroll(smoothScrollLinks[i]);})(i);
  		}
  	}
  }());
  // File#: _1_social-sharing
  // Usage: codyhouse.co/license
  (function() {
    function initSocialShare(button) {
      button.addEventListener('click', function(event){
        event.preventDefault();
        var social = button.getAttribute('data-social');
        var url = getSocialUrl(button, social);
        (social == 'mail')
          ? window.location.href = url
          : window.open(url, social+'-share-dialog', 'width=626,height=436');
      });
    };
  
    function getSocialUrl(button, social) {
      var params = getSocialParams(social);
      var newUrl = '';
      for(var i = 0; i < params.length; i++) {
        var paramValue = button.getAttribute('data-'+params[i]);
        if(params[i] == 'hashtags') paramValue = encodeURI(paramValue.replace(/\#| /g, ''));
        if(paramValue) {
          (social == 'facebook') 
            ? newUrl = newUrl + 'u='+encodeURIComponent(paramValue)+'&'
            : newUrl = newUrl + params[i]+'='+encodeURIComponent(paramValue)+'&';
        }
      }
      if(social == 'linkedin') newUrl = 'mini=true&'+newUrl;
      return button.getAttribute('href')+'?'+newUrl;
    };
  
    function getSocialParams(social) {
      var params = [];
      switch (social) {
        case 'twitter':
          params = ['text', 'hashtags'];
          break;
        case 'facebook':
        case 'linkedin':
          params = ['url'];
          break;
        case 'pinterest':
          params = ['url', 'media', 'description'];
          break;
        case 'mail':
          params = ['subject', 'body'];
          break;
      }
      return params;
    };
  
    var socialShare = document.getElementsByClassName('js-social-share');
    if(socialShare.length > 0) {
      for( var i = 0; i < socialShare.length; i++) {
        (function(i){initSocialShare(socialShare[i])})(i);
      }
    }
  }());
  // File#: _1_stacking-cards
  // Usage: codyhouse.co/license
  (function() {
    var StackCards = function(element) {
      this.element = element;
      this.items = this.element.getElementsByClassName('js-stack-cards__item');
      this.scrollingFn = false;
      this.scrolling = false;
      initStackCardsEffect(this); 
      initStackCardsResize(this); 
    };
  
    function initStackCardsEffect(element) { // use Intersection Observer to trigger animation
      setStackCards(element); // store cards CSS properties
  		var observer = new IntersectionObserver(stackCardsCallback.bind(element), { threshold: [0, 1] });
  		observer.observe(element.element);
    };
  
    function initStackCardsResize(element) { // detect resize to reset gallery
      element.element.addEventListener('resize-stack-cards', function(){
        setStackCards(element);
        animateStackCards.bind(element);
      });
    };
    
    function stackCardsCallback(entries) { // Intersection Observer callback
      if(entries[0].isIntersecting) {
        if(this.scrollingFn) return; // listener for scroll event already added
        stackCardsInitEvent(this);
      } else {
        if(!this.scrollingFn) return; // listener for scroll event already removed
        window.removeEventListener('scroll', this.scrollingFn);
        this.scrollingFn = false;
      }
    };
    
    function stackCardsInitEvent(element) {
      element.scrollingFn = stackCardsScrolling.bind(element);
      window.addEventListener('scroll', element.scrollingFn);
    };
  
    function stackCardsScrolling() {
      if(this.scrolling) return;
      this.scrolling = true;
      window.requestAnimationFrame(animateStackCards.bind(this));
    };
  
    function setStackCards(element) {
      // store wrapper properties
      element.marginY = getComputedStyle(element.element).getPropertyValue('--stack-cards-gap');
      getIntegerFromProperty(element); // convert element.marginY to integer (px value)
      element.elementHeight = element.element.offsetHeight;
  
      // store card properties
      var cardStyle = getComputedStyle(element.items[0]);
      element.cardTop = Math.floor(parseFloat(cardStyle.getPropertyValue('top')));
      element.cardHeight = Math.floor(parseFloat(cardStyle.getPropertyValue('height')));
  
      // store window property
      element.windowHeight = window.innerHeight;
  
      // reset margin + translate values
      if(isNaN(element.marginY)) {
        element.element.style.paddingBottom = '0px';
      } else {
        element.element.style.paddingBottom = (element.marginY*(element.items.length - 1))+'px';
      }
  
      for(var i = 0; i < element.items.length; i++) {
        if(isNaN(element.marginY)) {
          element.items[i].style.transform = 'none;';
        } else {
          element.items[i].style.transform = 'translateY('+element.marginY*i+'px)';
        }
      }
    };
  
    function getIntegerFromProperty(element) {
      var node = document.createElement('div');
      node.setAttribute('style', 'opacity:0; visbility: hidden;position: absolute; height:'+element.marginY);
      element.element.appendChild(node);
      element.marginY = parseInt(getComputedStyle(node).getPropertyValue('height'));
      element.element.removeChild(node);
    };
  
    function animateStackCards() {
      if(isNaN(this.marginY)) { // --stack-cards-gap not defined - do not trigger the effect
        this.scrolling = false;
        return; 
      }
  
      var top = this.element.getBoundingClientRect().top;
  
      if( this.cardTop - top + this.element.windowHeight - this.elementHeight - this.cardHeight + this.marginY + this.marginY*this.items.length > 0) { 
        this.scrolling = false;
        return;
      }
  
      for(var i = 0; i < this.items.length; i++) { // use only scale
        var scrolling = this.cardTop - top - i*(this.cardHeight+this.marginY);
        if(scrolling > 0) {  
          var scaling = i == this.items.length - 1 ? 1 : (this.cardHeight - scrolling*0.05)/this.cardHeight;
          this.items[i].style.transform = 'translateY('+this.marginY*i+'px) scale('+scaling+')';
        } else {
          this.items[i].style.transform = 'translateY('+this.marginY*i+'px)';
        }
      }
  
      this.scrolling = false;
    };
  
    // initialize StackCards object
    var stackCards = document.getElementsByClassName('js-stack-cards'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
      
  	if(stackCards.length > 0 && intersectionObserverSupported && !reducedMotion) { 
      var stackCardsArray = [];
  		for(var i = 0; i < stackCards.length; i++) {
  			(function(i){
          stackCardsArray.push(new StackCards(stackCards[i]));
        })(i);
      }
      
      var resizingId = false,
        customEvent = new CustomEvent('resize-stack-cards');
      
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 500);
      });
  
      function doneResizing() {
        for( var i = 0; i < stackCardsArray.length; i++) {
          (function(i){stackCardsArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  	}
  }());
  // File#: _1_sticky-banner
  // Usage: codyhouse.co/license
  (function() {
    var StickyBanner = function(element) {
      this.element = element;
      this.offsetIn = 0;
      this.offsetOut = 0;
      this.targetIn = this.element.getAttribute('data-target-in') ? document.querySelector(this.element.getAttribute('data-target-in')) : false;
      this.targetOut = this.element.getAttribute('data-target-out') ? document.querySelector(this.element.getAttribute('data-target-out')) : false;
      this.reset = 0;
      // check if the window is the scrollable element
      this.dataElement = this.element.getAttribute('data-element');
      this.scrollElement = this.dataElement ? document.querySelector(this.dataElement) : window;
      this.scrollingId = false;
      getBannerOffsets(this);
      initBanner(this);
    };
  
    function getBannerOffsets(element) { // get offset in and offset out values
      // update offsetIn
      element.offsetIn = 0;
      var windowTop = getScrollTop(element);
  
      if(element.targetIn) {
        var boundingClientRect = element.targetIn.getBoundingClientRect();
        element.offsetIn = boundingClientRect.top + windowTop + boundingClientRect.height;
      }
      var dataOffsetIn = element.element.getAttribute('data-offset-in');
      if(dataOffsetIn) {
        element.offsetIn = element.offsetIn + parseInt(dataOffsetIn);
      }
      // update offsetOut
      element.offsetOut = 0;
      if(element.targetOut) {
        var boundingClientRect = element.targetOut.getBoundingClientRect();
        element.offsetOut = boundingClientRect.top + windowTop - window.innerHeight;
      }
      var dataOffsetOut = element.element.getAttribute('data-offset-out');
      if(dataOffsetOut) {
        element.offsetOut = element.offsetOut + parseInt(dataOffsetOut);
      }
    };
  
    function initBanner(element) {
      resetBannerVisibility(element);
  
      element.element.addEventListener('resize-banner', function(){
        getBannerOffsets(element);
        resetBannerVisibility(element);
      });
  
      element.element.addEventListener('scroll-banner', function(){
        if(element.reset < 10) {
          getBannerOffsets(element);
          element.reset = element.reset + 1;
        }
        resetBannerVisibility(element);
      });
  
      if(element.dataElement && element.scrollElement) {
        // the scrollable element is different from the window - detect the scrolling
        element.scrollElement.addEventListener('scroll', function(event){
          if(element.scrollingId) return;
          element.scrollingId = true;
          window.requestAnimationFrame(function(){
            element.element.dispatchEvent(new CustomEvent('scroll-banner'));
            element.scrollingId = false;
          })
        });
      }
    };
  
    function resetBannerVisibility(element) {
      var scrollTop = getScrollTop(element),
        topTarget = false,
        bottomTarget = false;
      if(element.offsetIn < scrollTop) {
        topTarget = true;
      }
      if(element.offsetOut == 0 || scrollTop < element.offsetOut) {
        bottomTarget = true;
      }
  
      Util.toggleClass(element.element, 'sticky-banner--visible', bottomTarget && topTarget);
    };
  
    function getScrollTop(element) {
      // the scrollable element could be different from the window element
      var windowTop = element.scrollElement.scrollTop || document.documentElement.scrollTop;
      if(!element.dataElement) windowTop = window.scrollY || document.documentElement.scrollTop;
      return windowTop;
    };
  
    //initialize the Sticky Banner objects
  	var stckyBanner = document.getElementsByClassName('js-sticky-banner');
  	if( stckyBanner.length > 0 ) {
  		for( var i = 0; i < stckyBanner.length; i++) {
  			(function(i){new StickyBanner(stckyBanner[i]);})(i);
      }
      
      // init scroll/resize
      var resizingId = false,
        scrollingId = false,
        resizeEvent = new CustomEvent('resize-banner'),
        scrollEvent = new CustomEvent('scroll-banner');
      
      window.addEventListener('resize', function(event){
        clearTimeout(resizingId);
        resizingId = setTimeout(function(){
          doneResizing(resizeEvent);
        }, 300);
      });
  
      window.addEventListener('scroll', function(event){
        if(scrollingId) return;
        scrollingId = true;
        window.requestAnimationFrame 
          ? window.requestAnimationFrame(function(){
            doneResizing(scrollEvent);
            scrollingId = false;
          })
          : setTimeout(function(){
            doneResizing(scrollEvent);
            scrollingId = false;
          }, 200);
  
        resizingId = setTimeout(function(){
          doneResizing(resizeEvent);
        }, 300);
      });
  
      function doneResizing(event) {
        for( var i = 0; i < stckyBanner.length; i++) {
          (function(i){stckyBanner[i].dispatchEvent(event)})(i);
        };
      };
  	}
  }());
  // File#: _1_sticky-hero
  // Usage: codyhouse.co/license
  (function() {
  	var StickyBackground = function(element) {
  		this.element = element;
  		this.scrollingElement = this.element.getElementsByClassName('sticky-hero__content')[0];
  		this.nextElement = this.element.nextElementSibling;
  		this.scrollingTreshold = 0;
  		this.nextTreshold = 0;
  		initStickyEffect(this);
  	};
  
  	function initStickyEffect(element) {
  		var observer = new IntersectionObserver(stickyCallback.bind(element), { threshold: [0, 0.1, 1] });
  		observer.observe(element.scrollingElement);
  		if(element.nextElement) observer.observe(element.nextElement);
  	};
  
  	function stickyCallback(entries, observer) {
  		var threshold = entries[0].intersectionRatio.toFixed(1);
  		(entries[0].target ==  this.scrollingElement)
  			? this.scrollingTreshold = threshold
  			: this.nextTreshold = threshold;
  
  		Util.toggleClass(this.element, 'sticky-hero--media-is-fixed', (this.nextTreshold > 0 || this.scrollingTreshold > 0));
  	};
  
  
  	var stickyBackground = document.getElementsByClassName('js-sticky-hero'),
  		intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  	if(stickyBackground.length > 0 && intersectionObserverSupported) { // if IntersectionObserver is not supported, animations won't be triggeres
  		for(var i = 0; i < stickyBackground.length; i++) {
  			(function(i){ // if animations are enabled -> init the StickyBackground object
          if( Util.hasClass(stickyBackground[i], 'sticky-hero--overlay-layer') || Util.hasClass(stickyBackground[i], 'sticky-hero--scale')) new StickyBackground(stickyBackground[i]);
        })(i);
  		}
  	}
  }());
  // File#: _1_swipe-content
  (function() {
  	var SwipeContent = function(element) {
  		this.element = element;
  		this.delta = [false, false];
  		this.dragging = false;
  		this.intervalId = false;
  		initSwipeContent(this);
  	};
  
  	function initSwipeContent(content) {
  		content.element.addEventListener('mousedown', handleEvent.bind(content));
  		content.element.addEventListener('touchstart', handleEvent.bind(content));
  	};
  
  	function initDragging(content) {
  		//add event listeners
  		content.element.addEventListener('mousemove', handleEvent.bind(content));
  		content.element.addEventListener('touchmove', handleEvent.bind(content));
  		content.element.addEventListener('mouseup', handleEvent.bind(content));
  		content.element.addEventListener('mouseleave', handleEvent.bind(content));
  		content.element.addEventListener('touchend', handleEvent.bind(content));
  	};
  
  	function cancelDragging(content) {
  		//remove event listeners
  		if(content.intervalId) {
  			(!window.requestAnimationFrame) ? clearInterval(content.intervalId) : window.cancelAnimationFrame(content.intervalId);
  			content.intervalId = false;
  		}
  		content.element.removeEventListener('mousemove', handleEvent.bind(content));
  		content.element.removeEventListener('touchmove', handleEvent.bind(content));
  		content.element.removeEventListener('mouseup', handleEvent.bind(content));
  		content.element.removeEventListener('mouseleave', handleEvent.bind(content));
  		content.element.removeEventListener('touchend', handleEvent.bind(content));
  	};
  
  	function handleEvent(event) {
  		switch(event.type) {
  			case 'mousedown':
  			case 'touchstart':
  				startDrag(this, event);
  				break;
  			case 'mousemove':
  			case 'touchmove':
  				drag(this, event);
  				break;
  			case 'mouseup':
  			case 'mouseleave':
  			case 'touchend':
  				endDrag(this, event);
  				break;
  		}
  	};
  
  	function startDrag(content, event) {
  		content.dragging = true;
  		// listen to drag movements
  		initDragging(content);
  		content.delta = [parseInt(unify(event).clientX), parseInt(unify(event).clientY)];
  		// emit drag start event
  		emitSwipeEvents(content, 'dragStart', content.delta, event.target);
  	};
  
  	function endDrag(content, event) {
  		cancelDragging(content);
  		// credits: https://css-tricks.com/simple-swipe-with-vanilla-javascript/
  		var dx = parseInt(unify(event).clientX), 
  	    dy = parseInt(unify(event).clientY);
  	  
  	  // check if there was a left/right swipe
  		if(content.delta && (content.delta[0] || content.delta[0] === 0)) {
  	    var s = getSign(dx - content.delta[0]);
  			
  			if(Math.abs(dx - content.delta[0]) > 30) {
  				(s < 0) ? emitSwipeEvents(content, 'swipeLeft', [dx, dy]) : emitSwipeEvents(content, 'swipeRight', [dx, dy]);	
  			}
  	    
  	    content.delta[0] = false;
  	  }
  		// check if there was a top/bottom swipe
  	  if(content.delta && (content.delta[1] || content.delta[1] === 0)) {
  	  	var y = getSign(dy - content.delta[1]);
  
  	  	if(Math.abs(dy - content.delta[1]) > 30) {
  	    	(y < 0) ? emitSwipeEvents(content, 'swipeUp', [dx, dy]) : emitSwipeEvents(content, 'swipeDown', [dx, dy]);
  	    }
  
  	    content.delta[1] = false;
  	  }
  		// emit drag end event
  	  emitSwipeEvents(content, 'dragEnd', [dx, dy]);
  	  content.dragging = false;
  	};
  
  	function drag(content, event) {
  		if(!content.dragging) return;
  		// emit dragging event with coordinates
  		(!window.requestAnimationFrame) 
  			? content.intervalId = setTimeout(function(){emitDrag.bind(content, event);}, 250) 
  			: content.intervalId = window.requestAnimationFrame(emitDrag.bind(content, event));
  	};
  
  	function emitDrag(event) {
  		emitSwipeEvents(this, 'dragging', [parseInt(unify(event).clientX), parseInt(unify(event).clientY)]);
  	};
  
  	function unify(event) { 
  		// unify mouse and touch events
  		return event.changedTouches ? event.changedTouches[0] : event; 
  	};
  
  	function emitSwipeEvents(content, eventName, detail, el) {
  		var trigger = false;
  		if(el) trigger = el;
  		// emit event with coordinates
  		var event = new CustomEvent(eventName, {detail: {x: detail[0], y: detail[1], origin: trigger}});
  		content.element.dispatchEvent(event);
  	};
  
  	function getSign(x) {
  		if(!Math.sign) {
  			return ((x > 0) - (x < 0)) || +x;
  		} else {
  			return Math.sign(x);
  		}
  	};
  
  	window.SwipeContent = SwipeContent;
  	
  	//initialize the SwipeContent objects
  	var swipe = document.getElementsByClassName('js-swipe-content');
  	if( swipe.length > 0 ) {
  		for( var i = 0; i < swipe.length; i++) {
  			(function(i){new SwipeContent(swipe[i]);})(i);
  		}
  	}
  }());
  // File#: _1_switch-icon
  // Usage: codyhouse.co/license
  (function() {
  	var switchIcons = document.getElementsByClassName('js-switch-icon');
  	if( switchIcons.length > 0 ) {
  		for(var i = 0; i < switchIcons.length; i++) {(function(i){
  			if( !Util.hasClass(switchIcons[i], 'switch-icon--hover') ) initswitchIcons(switchIcons[i]);
  		})(i);}
  
  		function initswitchIcons(btn) {
  			btn.addEventListener('click', function(event){	
  				event.preventDefault();
  				var status = !Util.hasClass(btn, 'switch-icon--state-b');
  				Util.toggleClass(btn, 'switch-icon--state-b', status);
  				// emit custom event
  				var event = new CustomEvent('switch-icon-clicked', {detail: status});
  				btn.dispatchEvent(event);
  			});
  		};
  	}
  }());
  // File#: _1_table
  // Usage: codyhouse.co/license
  (function() {
    function initTable(table) {
      checkTableLayour(table); // switch from a collapsed to an expanded layout
      Util.addClass(table, 'table--loaded'); // show table
  
      // custom event emitted when window is resized
      table.addEventListener('update-table', function(event){
        checkTableLayour(table);
      });
    };
  
    function checkTableLayour(table) {
      var layout = getComputedStyle(table, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(table, tableExpandedLayoutClass, layout != 'collapsed');
    };
  
    var tables = document.getElementsByClassName('js-table'),
      tableExpandedLayoutClass = 'table--expanded';
    if( tables.length > 0 ) {
      var j = 0;
      for( var i = 0; i < tables.length; i++) {
        var beforeContent = getComputedStyle(tables[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){initTable(tables[i]);})(i);
          j = j + 1;
        } else {
          Util.addClass(tables[i], 'table--loaded');
        }
      }
      
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-table');
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < tables.length; i++) {
            (function(i){tables[i].dispatchEvent(customEvent)})(i);
          };
        };
  
        (window.requestAnimationFrame) // init table layout
          ? window.requestAnimationFrame(doneResizing)
          : doneResizing();
      }
    }
  }());
  // File#: _1_tabs
  // Usage: codyhouse.co/license
  (function() {
  	var Tab = function(element) {
  		this.element = element;
  		this.tabList = this.element.getElementsByClassName('js-tabs__controls')[0];
  		this.listItems = this.tabList.getElementsByTagName('li');
  		this.triggers = this.tabList.getElementsByTagName('a');
  		this.panelsList = this.element.getElementsByClassName('js-tabs__panels')[0];
  		this.panels = Util.getChildrenByClassName(this.panelsList, 'js-tabs__panel');
  		this.hideClass = 'is-hidden';
  		this.customShowClass = this.element.getAttribute('data-show-panel-class') ? this.element.getAttribute('data-show-panel-class') : false;
  		this.layout = this.element.getAttribute('data-tabs-layout') ? this.element.getAttribute('data-tabs-layout') : 'horizontal';
  		// deep linking options
  		this.deepLinkOn = this.element.getAttribute('data-deep-link') == 'on';
  		// init tabs
  		this.initTab();
  	};
  
  	Tab.prototype.initTab = function() {
  		//set initial aria attributes
  		this.tabList.setAttribute('role', 'tablist');
  		for( var i = 0; i < this.triggers.length; i++) {
  			var bool = (i == 0),
  				panelId = this.panels[i].getAttribute('id');
  			this.listItems[i].setAttribute('role', 'presentation');
  			Util.setAttributes(this.triggers[i], {'role': 'tab', 'aria-selected': bool, 'aria-controls': panelId, 'id': 'tab-'+panelId});
  			Util.addClass(this.triggers[i], 'js-tabs__trigger'); 
  			Util.setAttributes(this.panels[i], {'role': 'tabpanel', 'aria-labelledby': 'tab-'+panelId});
  			Util.toggleClass(this.panels[i], this.hideClass, !bool);
  
  			if(!bool) this.triggers[i].setAttribute('tabindex', '-1'); 
  		}
  
  		//listen for Tab events
  		this.initTabEvents();
  
  		// check deep linking option
  		this.initDeepLink();
  	};
  
  	Tab.prototype.initTabEvents = function() {
  		var self = this;
  		//click on a new tab -> select content
  		this.tabList.addEventListener('click', function(event) {
  			if( event.target.closest('.js-tabs__trigger') ) self.triggerTab(event.target.closest('.js-tabs__trigger'), event);
  		});
  		//arrow keys to navigate through tabs 
  		this.tabList.addEventListener('keydown', function(event) {
  			;
  			if( !event.target.closest('.js-tabs__trigger') ) return;
  			if( tabNavigateNext(event, self.layout) ) {
  				event.preventDefault();
  				self.selectNewTab('next');
  			} else if( tabNavigatePrev(event, self.layout) ) {
  				event.preventDefault();
  				self.selectNewTab('prev');
  			}
  		});
  	};
  
  	Tab.prototype.selectNewTab = function(direction) {
  		var selectedTab = this.tabList.querySelector('[aria-selected="true"]'),
  			index = Util.getIndexInArray(this.triggers, selectedTab);
  		index = (direction == 'next') ? index + 1 : index - 1;
  		//make sure index is in the correct interval 
  		//-> from last element go to first using the right arrow, from first element go to last using the left arrow
  		if(index < 0) index = this.listItems.length - 1;
  		if(index >= this.listItems.length) index = 0;	
  		this.triggerTab(this.triggers[index]);
  		this.triggers[index].focus();
  	};
  
  	Tab.prototype.triggerTab = function(tabTrigger, event) {
  		var self = this;
  		event && event.preventDefault();	
  		var index = Util.getIndexInArray(this.triggers, tabTrigger);
  		//no need to do anything if tab was already selected
  		if(this.triggers[index].getAttribute('aria-selected') == 'true') return;
  		
  		for( var i = 0; i < this.triggers.length; i++) {
  			var bool = (i == index);
  			Util.toggleClass(this.panels[i], this.hideClass, !bool);
  			if(this.customShowClass) Util.toggleClass(this.panels[i], this.customShowClass, bool);
  			this.triggers[i].setAttribute('aria-selected', bool);
  			bool ? this.triggers[i].setAttribute('tabindex', '0') : this.triggers[i].setAttribute('tabindex', '-1');
  		}
  
  		// update url if deepLink is on
  		if(this.deepLinkOn) {
  			history.replaceState(null, '', '#'+tabTrigger.getAttribute('aria-controls'));
  		}
  	};
  
  	Tab.prototype.initDeepLink = function() {
  		if(!this.deepLinkOn) return;
  		var hash = window.location.hash.substr(1);
  		var self = this;
  		if(!hash || hash == '') return;
  		for(var i = 0; i < this.panels.length; i++) {
  			if(this.panels[i].getAttribute('id') == hash) {
  				this.triggerTab(this.triggers[i], false);
  				setTimeout(function(){self.panels[i].scrollIntoView(true);});
  				break;
  			}
  		};
  	};
  
  	function tabNavigateNext(event, layout) {
  		if(layout == 'horizontal' && (event.keyCode && event.keyCode == 39 || event.key && event.key == 'ArrowRight')) {return true;}
  		else if(layout == 'vertical' && (event.keyCode && event.keyCode == 40 || event.key && event.key == 'ArrowDown')) {return true;}
  		else {return false;}
  	};
  
  	function tabNavigatePrev(event, layout) {
  		if(layout == 'horizontal' && (event.keyCode && event.keyCode == 37 || event.key && event.key == 'ArrowLeft')) {return true;}
  		else if(layout == 'vertical' && (event.keyCode && event.keyCode == 38 || event.key && event.key == 'ArrowUp')) {return true;}
  		else {return false;}
  	};
  	
  	//initialize the Tab objects
  	var tabs = document.getElementsByClassName('js-tabs');
  	if( tabs.length > 0 ) {
  		for( var i = 0; i < tabs.length; i++) {
  			(function(i){new Tab(tabs[i]);})(i);
  		}
  	}
  }());
  // File#: _1_ticker
  // Usage: codyhouse.co/license
  (function() {
    var Ticker = function(element) {
      this.element = element;
      this.list = this.element.getElementsByTagName('ul')[0];
      this.items = this.list.children;
      this.paused = false;
      // clones info
      this.clones = this.list.innerHTML;
      this.clonesNumber = 1;
      this.itemsLength = this.items.length;
      // animation duration
      this.animationDuration = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--ticker-animation-duration'));
      initTicker(this);
    };
  
    function initTicker(ticker) {
      // clone ticker children
      setTickerWidth(ticker);
      cloneItems(ticker);
      initAnimation(ticker);
  
      // resize/font loaded event
      ticker.element.addEventListener('update-ticker', function(event){
        setTickerWidth(ticker);
        cloneItems(ticker);
      });
  
      // click on control button events
      ticker.element.addEventListener('anim-ticker', function(event){
        ticker.paused = false;
        Util.removeClass(ticker.element, 'ticker--paused');
      });
  
      ticker.element.addEventListener('pause-ticker', function(event){
        ticker.paused = true;
        Util.addClass(ticker.element, 'ticker--paused');
      });
  
      // all set
      Util.addClass(ticker.element, 'ticker--loaded');
    };
  
    function setTickerWidth(ticker) {
      var width = 0;
      for(var i = 0; i < ticker.itemsLength; i++) {
        width = width + getItemWidth(ticker.items[i]);
      }
      // check if we need to update the number of clones
      if(width < window.innerWidth) {
        ticker.clonesNumber = Math.ceil(window.innerWidth/width) * 2 - 1;
      } else {
        ticker.clonesNumber = 1;
      }
  
      // update list width
      ticker.list.style.width = ((ticker.clonesNumber + 1)*width)+'px';
    };
  
    function getItemWidth(item) {
      var style = window.getComputedStyle(item);
      return parseFloat(style.marginRight) + parseFloat(style.marginLeft) + item.offsetWidth;
    };
  
    function cloneItems(ticker) {
      ticker.list.innerHTML = ticker.clones;
      for(var i = 0; i < ticker.clonesNumber; i++) {
        ticker.list.insertAdjacentHTML('beforeend', ticker.clones);
      }
      // update animation duration
      ticker.element.style.setProperty('--ticker-animation-duration', ticker.animationDuration*(ticker.clonesNumber+1)+'s');
    };
  
    function initAnimation(ticker) {
      // init observer - animate ticker only when in viewport
      var observer = new IntersectionObserver(tickerObserve.bind(ticker));
      observer.observe(ticker.element);
      
    };
  
    function tickerObserve(entries) {
      if(entries[0].isIntersecting) {
        if(!this.paused) Util.addClass(this.element, 'ticker--animate');
      } else {
        Util.removeClass(this.element, 'ticker--animate');
      }
    };
  
    function initTickerController(controller) {
      // play/pause btn controller
      var tickerContainer = document.getElementById(controller.getAttribute('aria-controls'));
      if(!tickerContainer) return;
      var tickerList = tickerContainer.getElementsByClassName('js-ticker');
      if(tickerList.length < 1) tickerList = [tickerContainer];
      // detect click
      controller.addEventListener('click', function(event){
        var playAnimation = controller.getAttribute('aria-pressed') == 'true';
        var animEvent = playAnimation ? 'anim-ticker' : 'pause-ticker';
        playAnimation ? controller.setAttribute('aria-pressed', 'false') : controller.setAttribute('aria-pressed', 'true');
        for(var i = 0; i < tickerList.length; i++) {
          tickerList[i].dispatchEvent(new CustomEvent(animEvent));
        }
      });
    };
  
    //initialize the Ticker objects
    var tickers = document.getElementsByClassName('js-ticker'),
      requestAnimationFrameSupported = window.requestAnimationFrame,
      reducedMotion = Util.osHasReducedMotion(),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  
  	if( tickers.length > 0 ) {
      var tickersArray = [];
  		for( var i = 0; i < tickers.length; i++) {
        if(!requestAnimationFrameSupported || reducedMotion || !intersectionObserverSupported) {
          // animation is off if requestAnimationFrame/IntersectionObserver is not supported or reduced motion is on
          Util.addClass(tickers[i], 'ticker--anim-off');
        } else {(function(i){tickersArray.push(new Ticker(tickers[i]));})(i);}
      }
  
      if(tickersArray.length > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-ticker');
        
        // on resize -> update ticker width 
        window.addEventListener('resize', function() {
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 500);
        });
  
        // wait for font to be loaded -> update ticker width
        if(document.fonts) {
          document.fonts.onloadingdone = function (fontFaceSetEvent) {
            doneResizing();
          };
        }
  
        function doneResizing() {
          for( var i = 0; i < tickersArray.length; i++) {
            (function(i){tickersArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  
        // ticker play/pause buttons
        var tickerControl = document.getElementsByClassName('js-ticker-control');
        if(tickerControl.length > 0) {
          for( var i = 0; i < tickerControl.length; i++) {
            if(!requestAnimationFrameSupported || reducedMotion || !intersectionObserverSupported) {
              Util.addClass(tickerControl[i], 'is-hidden');
            } else {
              (function(i){initTickerController(tickerControl[i]);})(i);
            } 
          }
        }
      };
    }
  }());
  // File#: _1_tilted-img-slideshow
  // Usage: codyhouse.co/license
  (function() {
    var TiltedSlideshow = function(element) {
      this.element = element;
      this.list = this.element.getElementsByClassName('js-tilted-slideshow__list')[0];
      this.images = this.list.getElementsByClassName('js-tilted-slideshow__item');
      this.selectedIndex = 0;
      this.animating = false;
      // classes
      this.orderClasses = ['tilted-slideshow__item--top', 'tilted-slideshow__item--middle', 'tilted-slideshow__item--bottom'];
      this.moveClasses = ['tilted-slideshow__item--move-out', 'tilted-slideshow__item--move-in'];
      this.interactedClass = 'tilted-slideshow--interacted';
      initTiltedSlideshow(this);
    };
  
    function initTiltedSlideshow(slideshow) {
      if(!animateImgs) removeTransitions(slideshow);
      
      slideshow.list.addEventListener('click', function(event) {
        Util.addClass(slideshow.element, slideshow.interactedClass);
        animateImgs ? animateImages(slideshow) : switchImages(slideshow);
      });
    };
  
    function removeTransitions(slideshow) {
      // if reduced motion is on or css variables are not supported -> do not animate images
      for(var i = 0; i < slideshow.images.length; i++) {
        slideshow.images[i].style.transition = 'none';
      }
    };
  
    function switchImages(slideshow) {
      // if reduced motion is on or css variables are not supported -> switch images without animation
      resetOrderClasses(slideshow);
      resetSelectedIndex(slideshow);
    };
  
    function resetSelectedIndex(slideshow) {
      // update the index of the top image
      slideshow.selectedIndex = resetIndex(slideshow, slideshow.selectedIndex + 1);
    };
  
    function resetIndex(slideshow, index) {
      // make sure index is < 3
      if(index >= slideshow.images.length) index = index - slideshow.images.length;
      return index;
    };
  
    function resetOrderClasses(slideshow) {
      // update the orderClasses for each images
      if(!animateImgs) {
        // top image -> remove top class and add bottom class
        Util.addClass(slideshow.images[slideshow.selectedIndex], slideshow.orderClasses[2]);
        Util.removeClass(slideshow.images[slideshow.selectedIndex], slideshow.orderClasses[0]);
      }
  
      // middle image -> remove middle class and add top class
      var middleImage = slideshow.images[resetIndex(slideshow, slideshow.selectedIndex + 1)];
      Util.addClass(middleImage, slideshow.orderClasses[0]);
      Util.removeClass(middleImage, slideshow.orderClasses[1]);
  
      // bottom image -> remove bottom class and add middle class
      var bottomImage = slideshow.images[resetIndex(slideshow, slideshow.selectedIndex + 2)];
      Util.addClass(bottomImage, slideshow.orderClasses[1]);
      Util.removeClass(bottomImage, slideshow.orderClasses[2]);
    };
  
    function animateImages(slideshow) {
      if(slideshow.animating) return;
      slideshow.animating = true;
  
      // reset order classes for middle/bottom images
      resetOrderClasses(slideshow);
      
      // animate top image
      var topImage = slideshow.images[slideshow.selectedIndex];
      // remove top class and add move out class
      Util.removeClass(topImage, slideshow.orderClasses[0]);
      Util.addClass(topImage, slideshow.moveClasses[0]);
      
      topImage.addEventListener('transitionend', function cb(event) {
        // remove transition
  			topImage.style.transition = 'none';
  			topImage.removeEventListener("transitionend", cb);
        
        setTimeout(function(){
          // add bottom + move-in class, remove move-out class
          Util.removeClass(topImage, slideshow.moveClasses[0]);
          Util.addClass(topImage, slideshow.moveClasses[1]+' '+ slideshow.orderClasses[2]);
          setTimeout(function(){
            topImage.style.transition = '';
            // remove move-in class
            Util.removeClass(topImage, slideshow.moveClasses[1]);
            topImage.addEventListener('transitionend', function cbn(event) {
              // reset animating property and selectedIndex index
              resetSelectedIndex(slideshow);
              slideshow.animating = false;
              topImage.removeEventListener("transitionend", cbn);
            });
          }, 10);
        }, 10);
  		});
    };
  
    var tiltedSlideshow = document.getElementsByClassName('js-tilted-slideshow'),
      animateImgs = !Util.osHasReducedMotion() && ('CSS' in window) && CSS.supports('color', 'var(--color-var)');
    if(tiltedSlideshow.length > 0) {
      for(var i = 0; i < tiltedSlideshow.length; i++) {
        new TiltedSlideshow(tiltedSlideshow[i]);
      }
    }
  }());
  // File#: _1_toast
  // Usage: codyhouse.co/license
  (function() {
    var Toasts = function() {
      this.toastsEl = document.getElementsByClassName('js-toast');
      this.toastsId = getRandomInt(0, 1000);
      this.index = 0;
      this.closingToast = false;
      initToasts(this);
    };
  
    // public method to initialize new toast elements
    Toasts.prototype.initToast = function(element) {
  		initSingleToast(this, element);
  	};
  
    function initToasts(obj) {
      // create a wrapper element for each toast variation
      createWrapper(obj, 'top-right');
      createWrapper(obj, 'top-left');
      createWrapper(obj, 'top-center');
      createWrapper(obj, 'bottom-right');
      createWrapper(obj, 'bottom-left');
      createWrapper(obj, 'bottom-center');
  
      // init single toast element
      for(var i = 0; i < obj.toastsEl.length; i++) {
        initSingleToast(obj, obj.toastsEl[i]);
      }
  
      // listen for dynamic toast creation
      window.addEventListener('newToast', function(event) {
        initSingleToast(obj, event.detail);
      });
    };
  
    function getRandomInt(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min) + min); 
    };
  
    function createWrapper(obj, position) {
      var classes = 'top-0 left-0 flex-column';
      if(position == 'top-right') classes = 'top-0 right-0 flex-column';
      if(position == 'top-center') classes = 'top-0 left-50% -translate-x-50% flex-column items-center';
      if(position == 'bottom-right') classes = 'bottom-0 right-0 flex-column-reverse';
      if(position == 'bottom-left') classes = 'bottom-0 left-0 flex-column-reverse';
      if(position == 'bottom-center') classes = 'bottom-0 left-50% -translate-x-50% flex-column-reverse items-center';
  
      var div = '<div class="toast-wrapper position-fixed flex '+classes+'" id="toast-wrapper-'+position+'"></div>';
      document.body.insertAdjacentHTML('beforeend', div);
      obj[position] = document.getElementById('toast-wrapper-'+position);
    };
  
    function initSingleToast(obj, toast) {
      var id = 'toast-'+obj.toastsId+'-'+obj.index;
      obj.index = obj.index + 1;
      // store toast info in the Toasts obj
      obj[id] = {};
      obj[id]['interval'] = toast.getAttribute('data-toast-interval') || 5000,
      obj[id]['intervalId'] = false;
      obj[id]['closing'] = false;
      // get position type
      var classes = toast.getAttribute('class');
      obj[id]['position'] = 'top-right';
      if(classes.indexOf('toast--top-left') > -1) obj[id]['position'] = 'top-left';
      if(classes.indexOf('toast--top-center') > -1) obj[id]['position'] = 'top-center';
      if(classes.indexOf('toast--bottom-right') > -1) obj[id]['position'] = 'bottom-right';
      if(classes.indexOf('toast--bottom-left') > -1) obj[id]['position'] = 'bottom-left'; 
      if(classes.indexOf('toast--bottom-center') > -1) obj[id]['position'] = 'bottom-center';
  
      // listen for custom open event
      toast.addEventListener('openToast', function() {
        if(!Util.hasClass(toast, 'toast--hidden') || obj[id]['closing']) return;
        openToast(obj, toast, id);
      });
  
      // close toast
      toast.addEventListener('click', function(event){
        if(event.target.closest('.js-toast__close-btn')) {
          obj.closingToast = true;
          closeToast(obj, toast, id);
        }
      });
    };
  
    function openToast(obj, toast, id) {
      if(obj[id]['intervalId']) {
        clearInterval(obj[id]['intervalId']);
        obj[id]['intervalId'] = false;
      }
      // place toast - insert in the proper container
      var fragment = document.createDocumentFragment();
      fragment.appendChild(toast);
      obj[obj[id]['position']].appendChild(fragment);
  
      // change position
      toast.style.position = 'static';
  
      // show toast
      setTimeout(function() {
        Util.removeClass(toast, 'toast--hidden');
      });
      
      // automatically close after a time interval
      if(obj[id]['interval'] && parseInt(obj[id]['interval']) > 0) {
        setToastInterval(obj, toast, id, obj[id]['interval']);
      }
    };
  
    function setToastInterval(obj, toast, id, interval) {
      obj[id]['intervalId'] = setTimeout(function(){
        if(obj.closingToast) return setToastInterval(obj, toast, id, 1000);
        closeToast(obj, toast, id);
      }, interval);
    };
  
    function closeToast(obj, toast, id) {
      obj[id]['closing'] = true;
      Util.addClass(toast, 'toast--hidden');
      // clear timeout
      if(obj[id]['intervalId']) clearTimeout(obj[id]['intervalId']);
      // remove toast and animate siblings
      closeToastAnimation(obj, toast, id);    
    };
  
    function closeToastAnimation(obj, toast, id) {
      // get all next elements 
      var siblings = getToastNextSiblings(toast);
      // get translate value (could be positive or negative based on position)
      var toastStyle = window.getComputedStyle(toast),
        margin = parseInt(toastStyle.getPropertyValue('margin-top')) || parseInt(toastStyle.getPropertyValue('margin-bottom'));
      // translate next elements if any
      var translate = toast.offsetHeight + margin;
      if(obj[id]['position'].indexOf('top') > -1) {
        translate = '-'+translate
      }
      for(var i = 0; i < siblings.length; i++) {
        siblings[i].style.transform = 'translateY('+translate+'px)';
      }
      // remove toast and reset translate
      toast.addEventListener('transitionend', function cb(event){
        if(event.propertyName != 'opacity') return;
        toast.removeEventListener('transitionend', cb);
        removeToast(toast, siblings, obj, id);
        obj.closingToast = false;
      });
    };
  
    function getToastNextSiblings(toast) {
      var array = [];
      var nextSibling = toast.nextElementSibling;
      if(nextSibling) {
        array.push(nextSibling);
        var nextSiblingsIterate = getToastNextSiblings(nextSibling);
        Array.prototype.push.apply(array, nextSiblingsIterate);
      }
      return array;
    };
  
    function removeToast(toast, siblings, obj, id) {
      // reset position
      toast.style.position = '';
  
      // move toast back to body
      var fragment = document.createDocumentFragment();
      fragment.appendChild(toast);
      document.body.appendChild(fragment); 
  
      // reset siblings translate
      for(var i = 0; i < siblings.length; i++) {
        (function(i){
          // set transition to none
          siblings[i].style.transition = 'none';
          siblings[i].style.transform = '';
          setTimeout(function() {siblings[i].style.transition = '';}, 10);
        })(i);
      }
  
      // reset closing status
      obj[id]['closing'] = false;
    };
  
    window.Toasts = Toasts;
  
  	//initialize the Toasts objects
  	var toasts = document.getElementsByClassName('js-toast');
  	if( toasts.length > 0 ) {
  		new Toasts();
  	}
  }());
  // File#: _1_tooltip
  // Usage: codyhouse.co/license
  (function() {
  	var Tooltip = function(element) {
  		this.element = element;
  		this.tooltip = false;
  		this.tooltipIntervalId = false;
  		this.tooltipContent = this.element.getAttribute('title');
  		this.tooltipPosition = (this.element.getAttribute('data-tooltip-position')) ? this.element.getAttribute('data-tooltip-position') : 'top';
  		this.tooltipClasses = (this.element.getAttribute('data-tooltip-class')) ? this.element.getAttribute('data-tooltip-class') : false;
  		this.tooltipId = 'js-tooltip-element'; // id of the tooltip element -> trigger will have the same aria-describedby attr
  		// there are cases where you only need the aria-label -> SR do not need to read the tooltip content (e.g., footnotes)
  		this.tooltipDescription = (this.element.getAttribute('data-tooltip-describedby') && this.element.getAttribute('data-tooltip-describedby') == 'false') ? false : true; 
  
  		this.tooltipDelay = 300; // show tooltip after a delay (in ms)
  		this.tooltipDelta = 10; // distance beetwen tooltip and trigger element (in px)
  		this.tooltipTriggerHover = false;
  		// tooltp sticky option
  		this.tooltipSticky = (this.tooltipClasses && this.tooltipClasses.indexOf('tooltip--sticky') > -1);
  		this.tooltipHover = false;
  		if(this.tooltipSticky) {
  			this.tooltipHoverInterval = false;
  		}
  		// tooltip triangle - css variable to control its position
  		this.tooltipTriangleVar = '--tooltip-triangle-translate';
  		resetTooltipContent(this);
  		initTooltip(this);
  	};
  
  	function resetTooltipContent(tooltip) {
  		var htmlContent = tooltip.element.getAttribute('data-tooltip-title');
  		if(htmlContent) {
  			tooltip.tooltipContent = htmlContent;
  		}
  	};
  
  	function initTooltip(tooltipObj) {
  		// reset trigger element
  		tooltipObj.element.removeAttribute('title');
  		tooltipObj.element.setAttribute('tabindex', '0');
  		// add event listeners
  		tooltipObj.element.addEventListener('mouseenter', handleEvent.bind(tooltipObj));
  		tooltipObj.element.addEventListener('focus', handleEvent.bind(tooltipObj));
  	};
  
  	function removeTooltipEvents(tooltipObj) {
  		// remove event listeners
  		tooltipObj.element.removeEventListener('mouseleave',  handleEvent.bind(tooltipObj));
  		tooltipObj.element.removeEventListener('blur',  handleEvent.bind(tooltipObj));
  	};
  
  	function handleEvent(event) {
  		// handle events
  		switch(event.type) {
  			case 'mouseenter':
  			case 'focus':
  				showTooltip(this, event);
  				break;
  			case 'mouseleave':
  			case 'blur':
  				checkTooltip(this);
  				break;
  			case 'newContent':
  				changeTooltipContent(this, event);
  				break;
  		}
  	};
  
  	function showTooltip(tooltipObj, event) {
  		// tooltip has already been triggered
  		if(tooltipObj.tooltipIntervalId) return;
  		tooltipObj.tooltipTriggerHover = true;
  		// listen to close events
  		tooltipObj.element.addEventListener('mouseleave', handleEvent.bind(tooltipObj));
  		tooltipObj.element.addEventListener('blur', handleEvent.bind(tooltipObj));
  		// custom event to reset tooltip content
  		tooltipObj.element.addEventListener('newContent', handleEvent.bind(tooltipObj));
  
  		// show tooltip with a delay
  		tooltipObj.tooltipIntervalId = setTimeout(function(){
  			createTooltip(tooltipObj);
  		}, tooltipObj.tooltipDelay);
  	};
  
  	function createTooltip(tooltipObj) {
  		tooltipObj.tooltip = document.getElementById(tooltipObj.tooltipId);
  		
  		if( !tooltipObj.tooltip ) { // tooltip element does not yet exist
  			tooltipObj.tooltip = document.createElement('div');
  			document.body.appendChild(tooltipObj.tooltip);
  		} 
  
  		// remove data-reset attribute that is used when updating tooltip content (newContent custom event)
  		tooltipObj.tooltip.removeAttribute('data-reset');
  		
  		// reset tooltip content/position
  		Util.setAttributes(tooltipObj.tooltip, {'id': tooltipObj.tooltipId, 'class': 'tooltip tooltip--is-hidden js-tooltip', 'role': 'tooltip'});
  		tooltipObj.tooltip.innerHTML = tooltipObj.tooltipContent;
  		if(tooltipObj.tooltipDescription) tooltipObj.element.setAttribute('aria-describedby', tooltipObj.tooltipId);
  		if(tooltipObj.tooltipClasses) Util.addClass(tooltipObj.tooltip, tooltipObj.tooltipClasses);
  		if(tooltipObj.tooltipSticky) Util.addClass(tooltipObj.tooltip, 'tooltip--sticky');
  		placeTooltip(tooltipObj);
  		Util.removeClass(tooltipObj.tooltip, 'tooltip--is-hidden');
  
  		// if tooltip is sticky, listen to mouse events
  		if(!tooltipObj.tooltipSticky) return;
  		tooltipObj.tooltip.addEventListener('mouseenter', function cb(){
  			tooltipObj.tooltipHover = true;
  			if(tooltipObj.tooltipHoverInterval) {
  				clearInterval(tooltipObj.tooltipHoverInterval);
  				tooltipObj.tooltipHoverInterval = false;
  			}
  			tooltipObj.tooltip.removeEventListener('mouseenter', cb);
  			tooltipLeaveEvent(tooltipObj);
  		});
  	};
  
  	function tooltipLeaveEvent(tooltipObj) {
  		tooltipObj.tooltip.addEventListener('mouseleave', function cb(){
  			tooltipObj.tooltipHover = false;
  			tooltipObj.tooltip.removeEventListener('mouseleave', cb);
  			hideTooltip(tooltipObj);
  		});
  	};
  
  	function placeTooltip(tooltipObj) {
  		// set top and left position of the tooltip according to the data-tooltip-position attr of the trigger
  		var dimention = [tooltipObj.tooltip.offsetHeight, tooltipObj.tooltip.offsetWidth],
  			positionTrigger = tooltipObj.element.getBoundingClientRect(),
  			position = [],
  			scrollY = window.scrollY || window.pageYOffset;
  		
  		position['top'] = [ (positionTrigger.top - dimention[0] - tooltipObj.tooltipDelta + scrollY), (positionTrigger.right/2 + positionTrigger.left/2 - dimention[1]/2)];
  		position['bottom'] = [ (positionTrigger.bottom + tooltipObj.tooltipDelta + scrollY), (positionTrigger.right/2 + positionTrigger.left/2 - dimention[1]/2)];
  		position['left'] = [(positionTrigger.top/2 + positionTrigger.bottom/2 - dimention[0]/2 + scrollY), positionTrigger.left - dimention[1] - tooltipObj.tooltipDelta];
  		position['right'] = [(positionTrigger.top/2 + positionTrigger.bottom/2 - dimention[0]/2 + scrollY), positionTrigger.right + tooltipObj.tooltipDelta];
  		
  		var direction = tooltipObj.tooltipPosition;
  		if( direction == 'top' && position['top'][0] < scrollY) direction = 'bottom';
  		else if( direction == 'bottom' && position['bottom'][0] + tooltipObj.tooltipDelta + dimention[0] > scrollY + window.innerHeight) direction = 'top';
  		else if( direction == 'left' && position['left'][1] < 0 )  direction = 'right';
  		else if( direction == 'right' && position['right'][1] + dimention[1] > window.innerWidth ) direction = 'left';
  
  		// reset tooltip triangle translate value
  		tooltipObj.tooltip.style.setProperty(tooltipObj.tooltipTriangleVar, '0px');
  		
  		if(direction == 'top' || direction == 'bottom') {
  			var deltaMarg = 5;
  			if(position[direction][1] < 0 ) {
  				position[direction][1] = deltaMarg;
  				// make sure triangle is at the center of the tooltip trigger
  				tooltipObj.tooltip.style.setProperty(tooltipObj.tooltipTriangleVar, (positionTrigger.left + 0.5*positionTrigger.width - 0.5*dimention[1] - deltaMarg)+'px');
  			}
  			if(position[direction][1] + dimention[1] > window.innerWidth ) {
  				position[direction][1] = window.innerWidth - dimention[1] - deltaMarg;
  				// make sure triangle is at the center of the tooltip trigger
  				tooltipObj.tooltip.style.setProperty(tooltipObj.tooltipTriangleVar, (0.5*dimention[1] - (window.innerWidth - positionTrigger.right) - 0.5*positionTrigger.width + deltaMarg)+'px');
  			}
  		}
  		tooltipObj.tooltip.style.top = position[direction][0]+'px';
  		tooltipObj.tooltip.style.left = position[direction][1]+'px';
  		Util.addClass(tooltipObj.tooltip, 'tooltip--'+direction);
  	};
  
  	function checkTooltip(tooltipObj) {
  		tooltipObj.tooltipTriggerHover = false;
  		if(!tooltipObj.tooltipSticky) hideTooltip(tooltipObj);
  		else {
  			if(tooltipObj.tooltipHover) return;
  			if(tooltipObj.tooltipHoverInterval) return;
  			tooltipObj.tooltipHoverInterval = setTimeout(function(){
  				hideTooltip(tooltipObj); 
  				tooltipObj.tooltipHoverInterval = false;
  			}, 300);
  		}
  	};
  
  	function hideTooltip(tooltipObj) {
  		if(tooltipObj.tooltipHover || tooltipObj.tooltipTriggerHover) return;
  		clearInterval(tooltipObj.tooltipIntervalId);
  		if(tooltipObj.tooltipHoverInterval) {
  			clearInterval(tooltipObj.tooltipHoverInterval);
  			tooltipObj.tooltipHoverInterval = false;
  		}
  		tooltipObj.tooltipIntervalId = false;
  		if(!tooltipObj.tooltip) return;
  		// hide tooltip
  		removeTooltip(tooltipObj);
  		// remove events
  		removeTooltipEvents(tooltipObj);
  	};
  
  	function removeTooltip(tooltipObj) {
  		if(tooltipObj.tooltipContent == tooltipObj.tooltip.innerHTML || tooltipObj.tooltip.getAttribute('data-reset') == 'on') {
  			Util.addClass(tooltipObj.tooltip, 'tooltip--is-hidden');
  			tooltipObj.tooltip.removeAttribute('data-reset');
  		}
  		if(tooltipObj.tooltipDescription) tooltipObj.element.removeAttribute('aria-describedby');
  	};
  
  	function changeTooltipContent(tooltipObj, event) {
  		if(tooltipObj.tooltip && tooltipObj.tooltipTriggerHover && event.detail) {
  			tooltipObj.tooltip.innerHTML = event.detail;
  			tooltipObj.tooltip.setAttribute('data-reset', 'on');
  			placeTooltip(tooltipObj);
  		}
  	};
  
  	window.Tooltip = Tooltip;
  
  	//initialize the Tooltip objects
  	var tooltips = document.getElementsByClassName('js-tooltip-trigger');
  	if( tooltips.length > 0 ) {
  		for( var i = 0; i < tooltips.length; i++) {
  			(function(i){new Tooltip(tooltips[i]);})(i);
  		}
  	}
  }());
  // File#: _1_tree
  // Usage: codyhouse.co/license
  (function() {
    var Tree = function(element) {
      this.element = element;
      this.contentEditable = treeIsEditable(this);
      initTree(this);
    };
  
    function treeIsEditable(element) {
      var editableAttr = element.element.getAttribute('data-tree-content-editable');
      return editableAttr && editableAttr == 'true';
    };
  
    function initTree(element) {
      element.element.addEventListener('click', function(event){
        var control = event.target.closest('.js-tree__node-control');
        if(control) {
          var node = control.closest('.tree__node');
          if(node) Util.toggleClass(node, 'tree__node--expanded', !Util.hasClass(node, 'tree__node--expanded'));
        } else if(element.contentEditable) {
          selectItem(element, event.target);
        }
      });
  
      if(element.contentEditable) initContentEditable(element);
  
      // keyboard navigation
      initKeyboardNav(element);
    };
  
    function selectItem(element, target) {
      var item = target.closest('.tree__item');
      if(item) {
        var selectedItem = element.element.getElementsByClassName('tree__item--selected');
        if(selectedItem.length > 0) Util.removeClass(selectedItem[0], 'tree__item--selected');
        Util.addClass(item, 'tree__item--selected');
      }
    };
  
    function initContentEditable(element) {
      element.element.addEventListener('dblclick', function(event){
        // make label editable on double-click
        var label = event.target.closest('.tree__label');
        if(label) resetEditing(element, label, true);
      });
  
      element.element.addEventListener('focusout', function(event){
        // if label loses focus -> remove the contenteditable attribute
        var editingLabel = event.target.closest('.tree__label[contenteditable="true"]');
        if(editingLabel) resetEditing(element, editingLabel, false);
      });
    };
  
    function initKeyboardNav(element) {
      element.element.addEventListener('keydown', function(event) {
        var focusedNode = document.activeElement.closest('.tree__node');
        if(!focusedNode) return;
        var isGroupNode = focusedNode.querySelector('.tree__nodes'),
          nodeIsEditing = event.target.closest('.tree__label[contenteditable="true"]');
        
        if((event.key && event.key.toLowerCase() === "arrowright") || (event.keyCode && event.keyCode === "39")) {
          if(!isGroupNode || nodeIsEditing) return;
          event.preventDefault();
          // if this is a group -> open it
          Util.addClass(focusedNode, 'tree__node--expanded');
        } else if ((event.key && event.key.toLowerCase() === "arrowleft") || (event.keyCode && event.keyCode === "37")) {
          if(!isGroupNode || nodeIsEditing) return;
          event.preventDefault();
          // if this is a group -> close it
          Util.removeClass(focusedNode, 'tree__node--expanded');
        } else if ((event.key && event.key.toLowerCase() === "arrowdown") || (event.keyCode && event.keyCode === "40")) {
          event.preventDefault();
          var nextNode = getNextNode(focusedNode, isGroupNode);
          moveTreeFocused(element, nextNode);
        } else if ((event.key && event.key.toLowerCase() === "arrowup") || (event.keyCode && event.keyCode === "38")) {
          event.preventDefault();
          var prevNode = getPrevNode(focusedNode);
          moveTreeFocused(element, prevNode);
  			} else if ( element.contentEditable && (event.key && event.key.toLowerCase() === "enter") || (event.keyCode && event.keyCode === "13")) {
          // user pressed the Enter key - only for content editable 
          var editingLabel = event.target.closest('.tree__label[contenteditable="true"]'),
            labelToEdit = event.target.closest('.tree__label');
          if(editingLabel) { // label was being edited
            event.preventDefault();
            resetEditing(element, editingLabel, false);
          } else if(labelToEdit) { // lable was in focus -> allow editing
            event.preventDefault();
            resetEditing(element, labelToEdit, true);
          } 
        } else if ( element.contentEditable && (event.key && event.key.toLowerCase() === "escape") || (event.keyCode && event.keyCode === "27")) {
          // if user was editing an element -> resetEditing
          var editingLabel = event.target.closest('.tree__label[contenteditable="true"]');
          if(editingLabel) { // label was being edited
            event.preventDefault();
            resetEditing(element, editingLabel, false);
          }
        }
      });
    };
  
    function getPrevNode(node) {
      var prevSibling = node.previousElementSibling;
      if(!prevSibling) {
        // get parent
        var parent = node.parentElement;
        if(!parent) return false;
        return parent.closest('.tree__node');
      } else if(prevSibling.classList.contains('tree__node--expanded')) {
        return getLastChild(prevSibling);
      } else {
        return prevSibling;
      }
    };
  
    function getLastChild(node) { // recursive function used to grab the prev element to select
      var children = Util.getChildrenByClassName(node.querySelector('.tree__nodes'), 'tree__node');
      if(children.length > 0) {
        var lastChild = children[children.length - 1];
        console.log(lastChild);
        if(lastChild.classList.contains('tree__node--expanded')) {
          return getLastChild(lastChild);
        } else {
          return lastChild;
        }
      } else {
        return node;
      }
    };
  
    function getNextNode(node, isGroupNode) {
      var nextSibling = false;
      if(isGroupNode && Util.hasClass(node, 'tree__node--expanded')) {
        // expanded group -> take children if any
        var children = node.getElementsByClassName('tree__node');
        if(children.length > 0) {
          nextSibling = children[0];
        } else {
          nextSibling = node.nextElementSibling;
        }
      } else {
        nextSibling = node.nextElementSibling;
      }
      return getNotFalseNextElement(node, nextSibling);
    };
  
    function getNotFalseNextElement(node, nextSibling) { // recursive function used to grab the next element to select
      if(nextSibling) return nextSibling;
      // element does not have siblings to return -> get parent and check for next not false sibling
      var parent = node.parentElement;
      if(!parent) return false;
      var parentItem = parent.closest('.tree__node');
      if(parentItem) return getNotFalseNextElement(parentItem, parentItem.nextElementSibling);
      else return false;
    };
  
    function moveTreeFocused(element, node) { // new node has been selected using the keyboard (up/down arrows)
      if(!node) return;
      var isGroupNode = node.querySelector('.tree__nodes');
      // move focus to anchor/button or to span (content-editable variation)
      var focusEl;
      if(element.contentEditable) {
        focusEl = node.querySelector('.tree__label');
      } else {
        focusEl = isGroupNode ? node.querySelector('.js-tree__node-control') : node.querySelector('a');
      }
      if(focusEl) focusEl.focus();
      // content-editable -> move also the selected class
      if(element.contentEditable) selectItem(element, focusEl);
    };
  
    function resetEditing(element, label, bool) {
      if(!label) return;
      Util.toggleClass(label.closest('.tree__item'), 'tree__item--editing', bool);
      if(bool) { // make label editable
        label.setAttribute('contenteditable', 'true');
        selectText(label);
      } else { // label not editable
        label.removeAttribute('contenteditable');
        // emit custom event to keep track of the updated labels
  		  element.element.dispatchEvent(new CustomEvent('labelEdited', {detail: label}));
      }
    };
  
    function selectText(element) {
      // when label is being editied -> select all its text
      if (document.body.createTextRange) {
        var range = document.body.createTextRange();
        range.moveToElementText(element);
        range.select();
      } else if (window.getSelection) {
        var selection = window.getSelection();        
        var range = document.createRange();
        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);
      }
    };
  
    //initialize the Tree objects
    var trees = document.getElementsByClassName('js-tree');
  	if( trees.length > 0) {
  		for( var i = 0; i < trees.length; i++) {
        new Tree(trees[i]);
      }
  	}
  }());
  // File#: _1_vertical-timeline
  // Usage: codyhouse.co/license
  (function() {
  	var VTimeline = function(element) {
      this.element = element;
      this.sections = this.element.getElementsByClassName('js-v-timeline__section');
      this.animate = this.element.getAttribute('data-animation') && this.element.getAttribute('data-animation') == 'on' ? true : false;
      this.animationClass = 'v-timeline__section--animate';
      this.animationDelta = '-150px';
      initVTimeline(this);
    };
  
    function initVTimeline(element) {
      if(!element.animate) return;
      for(var i = 0; i < element.sections.length; i++) {
        var observer = new IntersectionObserver(vTimelineCallback.bind(element, i),
        {rootMargin: "0px 0px "+element.animationDelta+" 0px"});
  		  observer.observe(element.sections[i]);
      }
    };
  
    function vTimelineCallback(index, entries, observer) {
      if(entries[0].isIntersecting) {
        Util.addClass(this.sections[index], this.animationClass);
        observer.unobserve(this.sections[index]);
      } 
    };
  
    //initialize the VTimeline objects
    var timelines = document.querySelectorAll('.js-v-timeline'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
  	if( timelines.length > 0) {
  		for( var i = 0; i < timelines.length; i++) {
        if(intersectionObserverSupported && !reducedMotion) (function(i){new VTimeline(timelines[i]);})(i);
        else timelines[i].removeAttribute('data-animation');
  		}
  	}
  }());
  // File#: _2_adv-custom-select
  // Usage: codyhouse.co/license
  (function() {
    var AdvSelect = function(element) {
      this.element = element;
      this.select = this.element.getElementsByTagName('select')[0];
      this.optGroups = this.select.getElementsByTagName('optgroup');
      this.options = this.select.getElementsByTagName('option');
      this.optionData = getOptionsData(this);
      this.selectId = this.select.getAttribute('id');
      this.selectLabel = document.querySelector('[for='+this.selectId+']')
      this.trigger = this.element.getElementsByClassName('js-adv-select__control')[0];
      this.triggerLabel = this.trigger.getElementsByClassName('js-adv-select__value')[0];
      this.dropdown = document.getElementById(this.trigger.getAttribute('aria-controls'));
  
      initAdvSelect(this); // init markup
      initAdvSelectEvents(this); // init event listeners
    };
  
    function getOptionsData(select) {
      var obj = [],
        dataset = select.options[0].dataset;
  
      function camelCaseToDash( myStr ) {
        return myStr.replace( /([a-z])([A-Z])/g, '$1-$2' ).toLowerCase();
      }
      for (var prop in dataset) {
        if (Object.prototype.hasOwnProperty.call(dataset, prop)) {
          // obj[prop] = select.dataset[prop];
          obj.push(camelCaseToDash(prop));
        }
      }
      return obj;
    };
  
    function initAdvSelect(select) {
      // create custom structure
      createAdvStructure(select);
      // update trigger label
      updateTriggerLabel(select);
      // hide native select and show custom structure
      Util.addClass(select.select, 'is-hidden');
      Util.removeClass(select.trigger, 'is-hidden');
      Util.removeClass(select.dropdown, 'is-hidden');
    };
  
    function initAdvSelectEvents(select) {
      if(select.selectLabel) {
        // move focus to custom trigger when clicking on <select> label
        select.selectLabel.addEventListener('click', function(){
          select.trigger.focus();
        });
      }
  
      // option is selected in dropdown
      select.dropdown.addEventListener('click', function(event){
        triggerSelection(select, event.target);
      });
  
      // keyboard navigation
      select.dropdown.addEventListener('keydown', function(event){
        if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
          keyboardCustomSelect(select, 'prev', event);
        } else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
          keyboardCustomSelect(select, 'next', event);
        } else if(event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {
          triggerSelection(select, document.activeElement);
        }
      });
    };
  
    function createAdvStructure(select) {
      // store optgroup and option structure
      var optgroup = select.dropdown.querySelector('[role="group"]'),
        option = select.dropdown.querySelector('[role="option"]'),
        optgroupClone = false,
        optgroupLabel = false,
        optionClone = false;
      if(optgroup) {
        optgroupClone = optgroup.cloneNode();
        optgroupLabel = document.getElementById(optgroupClone.getAttribute('describedby'));
      }
      if(option) optionClone = option.cloneNode(true);
  
      var dropdownCode = '';
  
      if(select.optGroups.length > 0) {
        for(var i = 0; i < select.optGroups.length; i++) {
          dropdownCode = dropdownCode + getOptGroupCode(select, select.optGroups[i], optgroupClone, optionClone, optgroupLabel, i);
        }
      } else {
        for(var i = 0; i < select.options.length; i++) {
          dropdownCode = dropdownCode + getOptionCode(select, select.options[i], optionClone);
        }
      }
  
      select.dropdown.innerHTML = dropdownCode;
    };
  
    function getOptGroupCode(select, optGroup, optGroupClone, optionClone, optgroupLabel, index) {
      if(!optGroupClone || !optionClone) return '';
      var code = '';
      var options = optGroup.getElementsByTagName('option');
      for(var i = 0; i < options.length; i++) {
        code = code + getOptionCode(select, options[i], optionClone);
      }
      if(optgroupLabel) {
        var label = optgroupLabel.cloneNode(true);
        var id = label.getAttribute('id') + '-'+index;
        label.setAttribute('id', id);
        optGroupClone.setAttribute('describedby', id);
        code = label.outerHTML.replace('{optgroup-label}', optGroup.getAttribute('label')) + code;
      } 
      optGroupClone.innerHTML = code;
      return optGroupClone.outerHTML;
    };
  
    function getOptionCode(select, option, optionClone) {
      optionClone.setAttribute('data-value', option.value);
      if(option.selected) {
        optionClone.setAttribute('aria-selected', 'true');
        optionClone.setAttribute('tabindex', '0');
      } else {
        optionClone.removeAttribute('aria-selected');
        optionClone.removeAttribute('tabindex');
      }
      var optionHtml = optionClone.outerHTML;
      optionHtml = optionHtml.replace('{option-label}', option.text);
      for(var i = 0; i < select.optionData.length; i++) {
        optionHtml = optionHtml.replace('{'+select.optionData[i]+'}', option.getAttribute('data-'+select.optionData[i]));
      }
      return optionHtml;
    };
  
    function updateTriggerLabel(select) {
      // select.triggerLabel.textContent = select.options[select.select.selectedIndex].text;
      select.triggerLabel.innerHTML = select.dropdown.querySelector('[aria-selected="true"]').innerHTML;
    };
  
    function triggerSelection(select, target) {
      var option = target.closest('[role="option"]');
      if(!option) return;
      selectOption(select, option);
    };
  
    function selectOption(select, option) {
      if(option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') == 'true') {
        // selecting the same option
      } else { 
        var selectedOption = select.dropdown.querySelector('[aria-selected="true"]');
        if(selectedOption) {
          selectedOption.removeAttribute('aria-selected');
          selectedOption.removeAttribute('tabindex');
        }
        option.setAttribute('aria-selected', 'true');
        option.setAttribute('tabindex', '0');
        // new option has been selected -> update native <select> element and trigger label
        updateNativeSelect(select, option.getAttribute('data-value'));
        updateTriggerLabel(select);
      }
      // move focus back to trigger
      setTimeout(function(){
        select.trigger.click();
      });
    };
  
    function updateNativeSelect(select, selectedValue) {
      var selectedOption = select.select.querySelector('[value="'+selectedValue+'"');
      select.select.selectedIndex = Util.getIndexInArray(select.options, selectedOption);
      select.select.dispatchEvent(new CustomEvent('change', {bubbles: true})); // trigger change event
    };
  
    function keyboardCustomSelect(select, direction) {
      var selectedOption = select.select.querySelector('[value="'+document.activeElement.getAttribute('data-value')+'"]');
      if(!selectedOption) return;
      var index = Util.getIndexInArray(select.options, selectedOption);
      
      index = direction == 'next' ? index + 1 : index - 1;
      if(index < 0) return;
      if(index >= select.options.length) return;
      
      var dropdownOption = select.dropdown.querySelector('[data-value="'+select.options[index].getAttribute('value')+'"]');
      if(dropdownOption) Util.moveFocus(dropdownOption);
    };
  
    //initialize the AdvSelect objects
    var advSelect = document.getElementsByClassName('js-adv-select');
    if( advSelect.length > 0 ) {
      for( var i = 0; i < advSelect.length; i++) {
        (function(i){new AdvSelect(advSelect[i]);})(i);
      }
    }
  }());
  // File#: _2_anim-card
  // Usage: codyhouse.co/license
  (function() {
    var AnimCards = function(element) {
      this.element = element;
      this.list = this.element.getElementsByTagName('ul')[0];
      this.cards = this.list.children;
      this.reverseDirection = Util.hasClass(this.element, 'anim-cards--reverse');
      this.translate = 0; // store container translate value
      this.animationId = false;
      this.animating = false;
      this.paused = false;
      // change speed of animation  
      this.animationSpeed = 1; // > 1 to increse speed, < 1 to reduce; always > 0
      initAnimCardsEvents(this);
    };
  
    function initAnimCardsEvents(cards) {
      // init observer
      var observer = new IntersectionObserver(animCardsObserve.bind(cards));
      observer.observe(cards.element);
  
      cards.element.addEventListener('update-card-width', function(event){ // reset animation on resize
        if(cards.animating) {
          cancelPrevAnimation(cards);
          if(!cards.paused) initAnimCards(cards);
        }
      });
  
      // play/pause button
      cards.element.addEventListener('anim-cards', function(event) {
        playCards(cards);
      });
      cards.element.addEventListener('pause-cards', function(event) {
        pauseCards(cards);
      });
  
      // pause on hover
      var pauseHover = cards.element.getAttribute('data-anim-cards-pause-hover');
      if(pauseHover && pauseHover == 'on') {
        cards.element.addEventListener('mouseenter', function(){
          pauseCards(cards);
        });
  
        cards.element.addEventListener('mouseleave', function(){
          playCards(cards);
        });
      }
    };
  
    function pauseCards(cards) { // pause cards - play/pause button or mouseenter
      cards.paused = true;
      if(cards.animating) {
        cancelPrevAnimation(cards);
        cards.timestamp = false;
      }
    };
  
    function playCards(cards) { // play cards - play/pause button or mouseleave
      cards.paused = false;
      if(cards.animating) initAnimCards(cards);
    };
  
    function animCardsObserve(entries) {
      if(entries[0].isIntersecting) {
        this.animating = true;
        if(!this.paused) initAnimCards(this); // init animation
      } else {
        this.animating = false;
        cancelPrevAnimation(this);
      }
    };
  
    function initAnimCards(cards) {
      if(cards.paused) return;
      cards.cardWidth = getAnimCardsWidth(cards);
      cards.animationId = window.requestAnimationFrame(triggerAnimCards.bind(cards));
    };
  
    function triggerAnimCards(timestamp) {
      cancelPrevAnimation(this);
      if(!this.timestamp) this.timestamp = timestamp;
      var translateIncrease = (this.timestamp - timestamp)*0.06*this.animationSpeed;
      this.timestamp = timestamp;
      updateAnimCardsTranslate(this, translateIncrease);
      updateAnimCardsList(this);
      setTranslate(this);
      this.animationId = window.requestAnimationFrame(triggerAnimCards.bind(this));
    };
  
    function updateAnimCardsTranslate(cards, translate) {
      cards.translate = cards.reverseDirection ? cards.translate - translate : cards.translate + translate;
      cards.translate = Math.round(Math.abs(cards.translate));
      if(!cards.reverseDirection) cards.translate = cards.translate*-1;
    };
  
    function updateAnimCardsList(cards) {
      if(Math.abs(cards.translate) <= cards.cardWidth) return;
      // need to remove first item from the list and append it to the end of list
      cards.translate = Math.abs(cards.translate) - cards.cardWidth;
      if(!cards.reverseDirection) cards.translate = cards.translate*-1;
      var clone = cards.cards[0].cloneNode(true);
      cards.list.removeChild(cards.cards[0]);
      cards.list.appendChild(clone);
    };
  
    function setTranslate(cards) {
      cards.list.style.transform = 'translateX('+cards.translate+'px)';
      cards.list.style.msTransform = 'translateX('+cards.translate+'px)';
    };
  
    function getAnimCardsWidth(cards) {
      return parseFloat(window.getComputedStyle(cards.cards[0]).marginRight) + cards.cards[0].offsetWidth;
    };
  
    function cancelPrevAnimation(cards) {
      if(cards.animationId) {
        window.cancelAnimationFrame(cards.animationId);
        cards.animationId = false;
      }
    };
  
    function initAnimCardsController(controller) {
      // play/pause btn controller
      var cardsContainer = document.getElementById(controller.getAttribute('aria-controls'));
      if(!cardsContainer) return;
      var cardsList = cardsContainer.getElementsByClassName('js-anim-cards');
      if(cardsList.length < 1) return;
  
      // detect click
      controller.addEventListener('click', function(event){
        var playAnimation = controller.getAttribute('aria-pressed') == 'true';
        var animEvent = playAnimation ? 'anim-cards' : 'pause-cards';
        playAnimation ? controller.setAttribute('aria-pressed', 'false') : controller.setAttribute('aria-pressed', 'true');
        for(var i = 0; i < cardsList.length; i++) {
          cardsList[i].dispatchEvent(new CustomEvent(animEvent));
        }
      });
    };
  
    //initialize the AnimCards objects
    var animCards = document.getElementsByClassName('js-anim-cards'),
      requestAnimationFrameSupported = window.requestAnimationFrame,
      reducedMotion = Util.osHasReducedMotion(),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  
  	if( animCards.length > 0 ) {
      var animCardsArray = [];
  		for( var i = 0; i < animCards.length; i++) {
        if(!requestAnimationFrameSupported || reducedMotion || !intersectionObserverSupported) {
          // animation is off if requestAnimationFrame/IntersectionObserver is not supported or reduced motion is on
          Util.addClass(animCards[i], 'anim-cards--anim-off');
        } else {(function(i){animCardsArray.push(new AnimCards(animCards[i]));})(i);}
      }
  
      if(animCardsArray.length > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-card-width');
        
        window.addEventListener('resize', function() {
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 500);
        });
  
        function doneResizing() {
          for( var i = 0; i < animCardsArray.length; i++) {
            (function(i){animCardsArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
      };
  
      // check play/pause buttons
      var animCardsControl = document.getElementsByClassName('js-anim-cards-control');
      if(animCardsControl.length > 0) {
        for( var i = 0; i < animCardsControl.length; i++) {
          if(!requestAnimationFrameSupported || reducedMotion || !intersectionObserverSupported) {
            Util.addClass(animCardsControl[i], 'is-hidden');
          } else {
            (function(i){initAnimCardsController(animCardsControl[i]);})(i);
          } 
        }
      }
    }
  }());
  // File#: _2_autocomplete
  // Usage: codyhouse.co/license
  (function() {
    var Autocomplete = function(opts) {
      if(!('CSS' in window) || !CSS.supports('color', 'var(--color-var)')) return;
      this.options = Util.extend(Autocomplete.defaults, opts);
      this.element = this.options.element;
      this.input = this.element.getElementsByClassName('js-autocomplete__input')[0];
      this.results = this.element.getElementsByClassName('js-autocomplete__results')[0];
      this.resultsList = this.results.getElementsByClassName('js-autocomplete__list')[0];
      this.ariaResult = this.element.getElementsByClassName('js-autocomplete__aria-results');
      this.resultClassName = this.element.getElementsByClassName('js-autocomplete__item').length > 0 ? 'js-autocomplete__item' : 'js-autocomplete__result';
      // store search info
      this.inputVal = '';
      this.typeId = false;
      this.searching = false;
      this.searchingClass = this.element.getAttribute('data-autocomplete-searching-class') || 'autocomplete--searching';
      // dropdown reveal class
      this.dropdownActiveClass =  this.element.getAttribute('data-autocomplete-dropdown-visible-class') || this.element.getAttribute('data-dropdown-active-class');
      // truncate dropdown
      this.truncateDropdown = this.element.getAttribute('data-autocomplete-dropdown-truncate') && this.element.getAttribute('data-autocomplete-dropdown-truncate') == 'on' ? true : false;
      initAutocomplete(this);
      this.autocompleteClosed = false; // fix issue when selecting an option from the list
    };
  
    function initAutocomplete(element) {
      initAutocompleteAria(element); // set aria attributes for SR and keyboard users
      initAutocompleteTemplates(element);
      initAutocompleteEvents(element);
    };
  
    function initAutocompleteAria(element) {
      // set aria attributes for input element
      Util.setAttributes(element.input, {'role': 'combobox', 'aria-autocomplete': 'list'});
      var listId = element.resultsList.getAttribute('id');
      if(listId) element.input.setAttribute('aria-owns', listId);
      // set aria attributes for autocomplete list
      element.resultsList.setAttribute('role', 'list');
    };
  
    function initAutocompleteTemplates(element) {
      element.templateItems = element.resultsList.querySelectorAll('.'+element.resultClassName+'[data-autocomplete-template]');
      if(element.templateItems.length < 1) element.templateItems = element.resultsList.querySelectorAll('.'+element.resultClassName);
      element.templates = [];
      for(var i = 0; i < element.templateItems.length; i++) {
        element.templates[i] = element.templateItems[i].getAttribute('data-autocomplete-template');
      }
    };
  
    function initAutocompleteEvents(element) {
      // input - keyboard navigation 
      element.input.addEventListener('keyup', function(event){
        handleInputTyped(element, event);
      });
  
      // if input type="search" -> detect when clicking on 'x' to clear input
      element.input.addEventListener('search', function(event){
        updateSearch(element);
      });
  
      // make sure dropdown is open on click
      element.input.addEventListener('click', function(event){
        updateSearch(element, true);
      });
  
      element.input.addEventListener('focus', function(event){
        if(element.autocompleteClosed) {
          element.autocompleteClosed = false;
          return;
        }
        updateSearch(element, true);
      });
  
      // input loses focus -> close menu
      element.input.addEventListener('blur', function(event){
        checkFocusLost(element, event);
      });
  
      // results list - keyboard navigation 
      element.resultsList.addEventListener('keydown', function(event){
        navigateList(element, event);
      });
  
      // results list loses focus -> close menu
      element.resultsList.addEventListener('focusout', function(event){
        checkFocusLost(element, event);
      });
  
      // close on esc
      window.addEventListener('keyup', function(event){
        if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
          toggleOptionsList(element, false);
        } else if(event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') { // on Enter - select result if focus is within results list
          selectResult(element, document.activeElement.closest('.'+element.resultClassName), event);
        }
      });
  
      // select element from list
      element.resultsList.addEventListener('click', function(event){
        selectResult(element, event.target.closest('.'+element.resultClassName), event);
      });
    };
  
    function checkFocusLost(element, event) {
      if(element.element.contains(event.relatedTarget)) return;
      toggleOptionsList(element, false);
    };
  
    function handleInputTyped(element, event) {
      if(event.key.toLowerCase() == 'arrowdown' || event.keyCode == '40') {
        moveFocusToList(element);
      } else {
        updateSearch(element);
      }
    };
  
    function moveFocusToList(element) {
      if(!Util.hasClass(element.element, element.dropdownActiveClass)) return;
      resetSearch(element); // clearTimeout
      // make sure first element is focusable
      var index = 0;
      if(!elementListIsFocusable(element.resultsItems[index])) {
        index = getElementFocusbleIndex(element, index, true);
      }
      getListFocusableEl(element.resultsItems[index]).focus();
    };
  
    function updateSearch(element, bool) {
      var inputValue = element.input.value;
      if(inputValue == element.inputVal && !bool) return; // input value did not change
      element.inputVal = inputValue;
      if(element.typeId) clearInterval(element.typeId); // clearTimeout
      if(element.inputVal.length < element.options.characters) { // not enough characters to start searching
        toggleOptionsList(element, false);
        return;
      }
      if(bool) { // on focus -> update result list without waiting for the debounce
        updateResultsList(element, 'focus');
        return;
      }
      element.typeId = setTimeout(function(){
        updateResultsList(element, 'type');
      }, element.options.debounce);
    };
  
    function toggleOptionsList(element, bool) {
      // toggle visibility of options list
      if(bool) {
        if(Util.hasClass(element.element, element.dropdownActiveClass)) return;
        Util.addClass(element.element, element.dropdownActiveClass);
        element.input.setAttribute('aria-expanded', true);
        truncateAutocompleteList(element);
      } else {
        if(!Util.hasClass(element.element, element.dropdownActiveClass)) return;
        if(element.resultsList.contains(document.activeElement)) {
          element.autocompleteClosed = true;
          element.input.focus();
        }
        Util.removeClass(element.element, element.dropdownActiveClass);
        element.input.removeAttribute('aria-expanded');
        resetSearch(element); // clearTimeout
      }
    };
  
    function truncateAutocompleteList(element) {
      if(!element.truncateDropdown) return;
      // reset max height
      element.resultsList.style.maxHeight = '';
      // check available space 
      var spaceBelow = (window.innerHeight - element.input.getBoundingClientRect().bottom - 10),
        maxHeight = parseInt(getComputedStyle(element.resultsList).maxHeight);
  
      (maxHeight > spaceBelow) 
        ? element.resultsList.style.maxHeight = spaceBelow+'px' 
        : element.resultsList.style.maxHeight = '';
    };
  
    function updateResultsList(element, eventType) {
      if(element.searching) return;
      element.searching = true;
      Util.addClass(element.element, element.searchingClass); // show loader
      element.options.searchData(element.inputVal, function(data){
        // data = custom results
        populateResults(element, data);
        Util.removeClass(element.element, element.searchingClass);
        toggleOptionsList(element, true);
        updateAriaRegion(element);
        element.searching = false;
      }, eventType);
    };
  
    function updateAriaRegion(element) {
      element.resultsItems = element.resultsList.querySelectorAll('.'+element.resultClassName+'[tabindex="-1"]');
      if(element.ariaResult.length == 0) return;
      element.ariaResult[0].textContent = element.resultsItems.length;
    };
  
    function resetSearch(element) {
      if(element.typeId) clearInterval(element.typeId);
      element.typeId = false;
    };
  
    function navigateList(element, event) {
      var downArrow = (event.key.toLowerCase() == 'arrowdown' || event.keyCode == '40'),
        upArrow = (event.key.toLowerCase() == 'arrowup' || event.keyCode == '38');
      if(!downArrow && !upArrow) return;
      event.preventDefault();
      var selectedElement = document.activeElement.closest('.'+element.resultClassName) || document.activeElement;
      var index = Util.getIndexInArray(element.resultsItems, selectedElement);
      var newIndex = getElementFocusbleIndex(element, index, downArrow);
      getListFocusableEl(element.resultsItems[newIndex]).focus();
    };
  
    function getElementFocusbleIndex(element, index, nextItem) {
      var newIndex = nextItem ? index + 1 : index - 1;
      if(newIndex < 0) newIndex = element.resultsItems.length - 1;
      if(newIndex >= element.resultsItems.length) newIndex = 0;
      // check if element can be focused
      if(!elementListIsFocusable(element.resultsItems[newIndex])) {
        // skip this element
        return getElementFocusbleIndex(element, newIndex, nextItem);
      }
      return newIndex;
    };
  
    function elementListIsFocusable(item) {
      var role = item.getAttribute('role');
      if(role && role == 'presentation') {
        // skip this element
        return false;
      }
      return true;
    };
  
    function getListFocusableEl(item) {
      var newFocus = item,
        focusable = newFocus.querySelectorAll('button:not([disabled]), [href]');
      if(focusable.length > 0 ) newFocus = focusable[0];
      return newFocus;
    };
  
    function selectResult(element, result, event) {
      if(!result) return;
      if(element.options.onClick) {
        element.options.onClick(result, element, event, function(){
          toggleOptionsList(element, false);
        });
      } else {
        element.input.value = getResultContent(result);
        toggleOptionsList(element, false);
      }
      element.inputVal = element.input.value;
    };
  
    function getResultContent(result) { // get text content of selected item
      var labelElement = result.querySelector('[data-autocomplete-label]');
      return labelElement ? labelElement.textContent : result.textContent;
    };
  
    function populateResults(element, data) {
      var innerHtml = '';
  
      for(var i = 0; i < data.length; i++) {
        innerHtml = innerHtml + getItemHtml(element, data[i]);
      }
      element.resultsList.innerHTML = innerHtml;
    };
  
    function getItemHtml(element, data) {
      var clone = getClone(element, data);
      Util.removeClass(clone, 'is-hidden');
      clone.setAttribute('tabindex', '-1');
      for(var key in data) {
        if (data.hasOwnProperty(key)) {
          if(key == 'label') setLabel(clone, data[key]);
          else if(key == 'class') setClass(clone, data[key]);
          else if(key == 'url') setUrl(clone, data[key]);
          else if(key == 'src') setSrc(clone, data[key]);
          else setKey(clone, key, data[key]);
        }
      }
      return clone.outerHTML;
    };
  
    function getClone(element, data) {
      var item = false;
      if(element.templateItems.length == 1 || !data['template']) item = element.templateItems[0];
      else {
        for(var i = 0; i < element.templateItems.length; i++) {
          if(data['template'] == element.templates[i]) {
            item = element.templateItems[i];
          }
        }
        if(!item) item = element.templateItems[0];
      }
      return item.cloneNode(true);
    };
  
    function setLabel(clone, label) {
      var labelElement = clone.querySelector('[data-autocomplete-label]');
      labelElement 
        ? labelElement.textContent = label
        : clone.textContent = label;
    };
  
    function setClass(clone, classList) {
      Util.addClass(clone, classList);
    };
  
    function setUrl(clone, url) {
      var linkElement = clone.querySelector('[data-autocomplete-url]');
      if(linkElement) linkElement.setAttribute('href', url);
    };
  
    function setSrc(clone, src) {
      var imgElement = clone.querySelector('[data-autocomplete-src]');
      if(imgElement) imgElement.setAttribute('src', src);
    };
  
    function setKey(clone, key, value) {
      var subElement = clone.querySelector('[data-autocomplete-'+key+']');
      if(subElement) {
        if(subElement.hasAttribute('data-autocomplete-html')) subElement.innerHTML = value;
        else subElement.textContent = value;
      }
    };
  
    Autocomplete.defaults = {
      element : '',
      debounce: 200,
      characters: 2,
      searchData: false, // function used to return results
      onClick: false // function executed when selecting an item in the list; arguments (result, obj) -> selected <li> item + Autocompletr obj reference
    };
  
    window.Autocomplete = Autocomplete;
  }());
  // File#: _2_carousel
  // Usage: codyhouse.co/license
  (function() {
    var Carousel = function(opts) {
      this.options = Util.extend(Carousel.defaults , opts);
      this.element = this.options.element;
      this.listWrapper = this.element.getElementsByClassName('carousel__wrapper')[0];
      this.list = this.element.getElementsByClassName('carousel__list')[0];
      this.items = this.element.getElementsByClassName('carousel__item');
      this.initItems = []; // store only the original elements - will need this for cloning
      this.itemsNb = this.items.length; //original number of items
      this.visibItemsNb = 1; // tot number of visible items
      this.itemsWidth = 1; // this will be updated with the right width of items
      this.itemOriginalWidth = false; // store the initial width to use it on resize
      this.selectedItem = 0; // index of first visible item 
      this.translateContainer = 0; // this will be the amount the container has to be translated each time a new group has to be shown (negative)
      this.containerWidth = 0; // this will be used to store the total width of the carousel (including the overflowing part)
      this.ariaLive = false;
      // navigation
      this.controls = this.element.getElementsByClassName('js-carousel__control');
      this.animating = false;
      // autoplay
      this.autoplayId = false;
      this.autoplayPaused = false;
      //drag
      this.dragStart = false;
      // resize
      this.resizeId = false;
      // used to re-initialize js
      this.cloneList = [];
      // store items min-width
      this.itemAutoSize = false;
      // store translate value (loop = off)
      this.totTranslate = 0;
      // modify loop option if navigation is on
      if(this.options.nav) this.options.loop = false;
      // store counter elements (if present)
      this.counter = this.element.getElementsByClassName('js-carousel__counter');
      this.counterTor = this.element.getElementsByClassName('js-carousel__counter-tot');
      initCarouselLayout(this); // get number visible items + width items
      setItemsWidth(this, true); 
      insertBefore(this, this.visibItemsNb); // insert clones before visible elements
      updateCarouselClones(this); // insert clones after visible elements
      resetItemsTabIndex(this); // make sure not visible items are not focusable
      initAriaLive(this); // set aria-live region for SR
      initCarouselEvents(this); // listen to events
      initCarouselCounter(this);
      Util.addClass(this.element, 'carousel--loaded');
    };
    
    //public carousel functions
    Carousel.prototype.showNext = function() {
      showNextItems(this);
    };
  
    Carousel.prototype.showPrev = function() {
      showPrevItems(this);
    };
  
    Carousel.prototype.startAutoplay = function() {
      startAutoplay(this);
    };
  
    Carousel.prototype.pauseAutoplay = function() {
      pauseAutoplay(this);
    };
    
    //private carousel functions
    function initCarouselLayout(carousel) {
      // evaluate size of single elements + number of visible elements
      var itemStyle = window.getComputedStyle(carousel.items[0]),
        containerStyle = window.getComputedStyle(carousel.listWrapper),
        itemWidth = parseFloat(itemStyle.getPropertyValue('width')),
        itemMargin = parseFloat(itemStyle.getPropertyValue('margin-right')),
        containerPadding = parseFloat(containerStyle.getPropertyValue('padding-left')),
        containerWidth = parseFloat(containerStyle.getPropertyValue('width'));
  
      if(!carousel.itemAutoSize) {
        carousel.itemAutoSize = itemWidth;
      }
  
      // if carousel.listWrapper is hidden -> make sure to retrieve the proper width
      containerWidth = getCarouselWidth(carousel, containerWidth);
  
      if( !carousel.itemOriginalWidth) { // on resize -> use initial width of items to recalculate 
        carousel.itemOriginalWidth = itemWidth;
      } else {
        itemWidth = carousel.itemOriginalWidth;
      }
  
      if(carousel.itemAutoSize) {
        carousel.itemOriginalWidth = parseInt(carousel.itemAutoSize);
        itemWidth = carousel.itemOriginalWidth;
      }
      // make sure itemWidth is smaller than container width
      if(containerWidth < itemWidth) {
        carousel.itemOriginalWidth = containerWidth
        itemWidth = carousel.itemOriginalWidth;
      }
      // get proper width of elements
      carousel.visibItemsNb = parseInt((containerWidth - 2*containerPadding + itemMargin)/(itemWidth+itemMargin));
      carousel.itemsWidth = parseFloat( (((containerWidth - 2*containerPadding + itemMargin)/carousel.visibItemsNb) - itemMargin).toFixed(1));
      carousel.containerWidth = (carousel.itemsWidth+itemMargin)* carousel.items.length;
      carousel.translateContainer = 0 - ((carousel.itemsWidth+itemMargin)* carousel.visibItemsNb);
      // flexbox fallback
      if(!flexSupported) carousel.list.style.width = (carousel.itemsWidth + itemMargin)*carousel.visibItemsNb*3+'px';
      
      // this is used when loop == off
      carousel.totTranslate = 0 - carousel.selectedItem*(carousel.itemsWidth+itemMargin);
      if(carousel.items.length <= carousel.visibItemsNb) carousel.totTranslate = 0;
  
      centerItems(carousel); // center items if carousel.items.length < visibItemsNb
      alignControls(carousel); // check if controls need to be aligned to a different element
    };
  
    function setItemsWidth(carousel, bool) {
      for(var i = 0; i < carousel.items.length; i++) {
        carousel.items[i].style.width = carousel.itemsWidth+"px";
        if(bool) carousel.initItems.push(carousel.items[i]);
      }
    };
  
    function updateCarouselClones(carousel) { 
      if(!carousel.options.loop) return;
      // take care of clones after visible items (needs to run after the update of clones before visible items)
      if(carousel.items.length < carousel.visibItemsNb*3) {
        insertAfter(carousel, carousel.visibItemsNb*3 - carousel.items.length, carousel.items.length - carousel.visibItemsNb*2);
      } else if(carousel.items.length > carousel.visibItemsNb*3 ) {
        removeClones(carousel, carousel.visibItemsNb*3, carousel.items.length - carousel.visibItemsNb*3);
      }
      // set proper translate value for the container
      setTranslate(carousel, 'translateX('+carousel.translateContainer+'px)');
    };
  
    function initCarouselEvents(carousel) {
      // listen for click on previous/next arrow
      // dots navigation
      if(carousel.options.nav) {
        carouselCreateNavigation(carousel);
        carouselInitNavigationEvents(carousel);
      }
  
      if(carousel.controls.length > 0) {
        carousel.controls[0].addEventListener('click', function(event){
          event.preventDefault();
          showPrevItems(carousel);
          updateAriaLive(carousel);
        });
        carousel.controls[1].addEventListener('click', function(event){
          event.preventDefault();
          showNextItems(carousel);
          updateAriaLive(carousel);
        });
  
        // update arrow visility -> loop == off only
        resetCarouselControls(carousel);
        // emit custom event - items visible
        emitCarouselActiveItemsEvent(carousel)
      }
      // autoplay
      if(carousel.options.autoplay) {
        startAutoplay(carousel);
        // pause autoplay if user is interacting with the carousel
        if(!carousel.options.autoplayOnHover) {
          carousel.element.addEventListener('mouseenter', function(event){
            pauseAutoplay(carousel);
            carousel.autoplayPaused = true;
          });
          carousel.element.addEventListener('mouseleave', function(event){
            carousel.autoplayPaused = false;
            startAutoplay(carousel);
          });
        }
        if(!carousel.options.autoplayOnFocus) {
          carousel.element.addEventListener('focusin', function(event){
            pauseAutoplay(carousel);
            carousel.autoplayPaused = true;
          });
        
          carousel.element.addEventListener('focusout', function(event){
            carousel.autoplayPaused = false;
            startAutoplay(carousel);
          });
        }
      }
      // drag events
      if(carousel.options.drag && window.requestAnimationFrame) {
        //init dragging
        new SwipeContent(carousel.element);
        carousel.element.addEventListener('dragStart', function(event){
          if(event.detail.origin && event.detail.origin.closest('.js-carousel__control')) return;
          if(event.detail.origin && event.detail.origin.closest('.js-carousel__navigation')) return;
          if(event.detail.origin && !event.detail.origin.closest('.carousel__wrapper')) return;
          Util.addClass(carousel.element, 'carousel--is-dragging');
          pauseAutoplay(carousel);
          carousel.dragStart = event.detail.x;
          animateDragEnd(carousel);
        });
        carousel.element.addEventListener('dragging', function(event){
          if(!carousel.dragStart) return;
          if(carousel.animating || Math.abs(event.detail.x - carousel.dragStart) < 10) return;
          var translate = event.detail.x - carousel.dragStart + carousel.translateContainer;
          if(!carousel.options.loop) {
            translate = event.detail.x - carousel.dragStart + carousel.totTranslate; 
          }
          setTranslate(carousel, 'translateX('+translate+'px)');
        });
      }
      // reset on resize
      window.addEventListener('resize', function(event){
        pauseAutoplay(carousel);
        clearTimeout(carousel.resizeId);
        carousel.resizeId = setTimeout(function(){
          resetCarouselResize(carousel);
          // reset dots navigation
          resetDotsNavigation(carousel);
          resetCarouselControls(carousel);
          setCounterItem(carousel);
          startAutoplay(carousel);
          centerItems(carousel); // center items if carousel.items.length < visibItemsNb
          alignControls(carousel);
          // emit custom event - items visible
          emitCarouselActiveItemsEvent(carousel)
        }, 250)
      });
      // keyboard navigation
      carousel.element.addEventListener('keydown', function(event){
  			if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
  				carousel.showNext();
  			} else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
  				carousel.showPrev();
  			}
  		});
    };
  
    function showPrevItems(carousel) {
      if(carousel.animating) return;
      carousel.animating = true;
      carousel.selectedItem = getIndex(carousel, carousel.selectedItem - carousel.visibItemsNb);
      animateList(carousel, '0', 'prev');
    };
  
    function showNextItems(carousel) {
      if(carousel.animating) return;
      carousel.animating = true;
      carousel.selectedItem = getIndex(carousel, carousel.selectedItem + carousel.visibItemsNb);
      animateList(carousel, carousel.translateContainer*2+'px', 'next');
    };
  
    function animateDragEnd(carousel) { // end-of-dragging animation
      carousel.element.addEventListener('dragEnd', function cb(event){
        carousel.element.removeEventListener('dragEnd', cb);
        Util.removeClass(carousel.element, 'carousel--is-dragging');
        if(event.detail.x - carousel.dragStart < -40) {
          carousel.animating = false;
          showNextItems(carousel);
        } else if(event.detail.x - carousel.dragStart > 40) {
          carousel.animating = false;
          showPrevItems(carousel);
        } else if(event.detail.x - carousel.dragStart == 0) { // this is just a click -> no dragging
          return;
        } else { // not dragged enought -> do not update carousel, just reset
          carousel.animating = true;
          animateList(carousel, carousel.translateContainer+'px', false);
        }
        carousel.dragStart = false;
      });
    };
  
    function animateList(carousel, translate, direction) { // takes care of changing visible items
      pauseAutoplay(carousel);
      Util.addClass(carousel.list, 'carousel__list--animating');
      var initTranslate = carousel.totTranslate;
      if(!carousel.options.loop) {
        translate = noLoopTranslateValue(carousel, direction);
      }
      setTimeout(function() {setTranslate(carousel, 'translateX('+translate+')');});
      if(transitionSupported) {
        carousel.list.addEventListener('transitionend', function cb(event){
          if(event.propertyName && event.propertyName != 'transform') return;
          Util.removeClass(carousel.list, 'carousel__list--animating');
          carousel.list.removeEventListener('transitionend', cb);
          animateListCb(carousel, direction);
        });
      } else {
        animateListCb(carousel, direction);
      }
      if(!carousel.options.loop && (initTranslate == carousel.totTranslate)) {
        // translate value was not updated -> trigger transitionend event to restart carousel
        carousel.list.dispatchEvent(new CustomEvent('transitionend'));
      }
      resetCarouselControls(carousel);
      setCounterItem(carousel);
      // emit custom event - items visible
      emitCarouselActiveItemsEvent(carousel)
    };
  
    function noLoopTranslateValue(carousel, direction) {
      var translate = carousel.totTranslate;
      if(direction == 'next') {
        translate = carousel.totTranslate + carousel.translateContainer;
      } else if(direction == 'prev') {
        translate = carousel.totTranslate - carousel.translateContainer;
      } else if(direction == 'click') {
        translate = carousel.selectedDotIndex*carousel.translateContainer;
      }
      if(translate > 0)  {
        translate = 0;
        carousel.selectedItem = 0;
      }
      if(translate < - carousel.translateContainer - carousel.containerWidth) {
        translate = - carousel.translateContainer - carousel.containerWidth;
        carousel.selectedItem = carousel.items.length - carousel.visibItemsNb;
      }
      if(carousel.visibItemsNb > carousel.items.length) translate = 0;
      carousel.totTranslate = translate;
      return translate + 'px';
    };
  
    function animateListCb(carousel, direction) { // reset actions after carousel has been updated
      if(direction) updateClones(carousel, direction);
      carousel.animating = false;
      // reset autoplay
      startAutoplay(carousel);
      // reset tab index
      resetItemsTabIndex(carousel);
    };
  
    function updateClones(carousel, direction) {
      if(!carousel.options.loop) return;
      // at the end of each animation, we need to update the clones before and after the visible items
      var index = (direction == 'next') ? 0 : carousel.items.length - carousel.visibItemsNb;
      // remove clones you do not need anymore
      removeClones(carousel, index, false);
      // add new clones 
      (direction == 'next') ? insertAfter(carousel, carousel.visibItemsNb, 0) : insertBefore(carousel, carousel.visibItemsNb);
      //reset transform
      setTranslate(carousel, 'translateX('+carousel.translateContainer+'px)');
    };
  
    function insertBefore(carousel, nb, delta) {
      if(!carousel.options.loop) return;
      var clones = document.createDocumentFragment();
      var start = 0;
      if(delta) start = delta;
      for(var i = start; i < nb; i++) {
        var index = getIndex(carousel, carousel.selectedItem - i - 1),
          clone = carousel.initItems[index].cloneNode(true);
        Util.addClass(clone, 'js-clone');
        clones.insertBefore(clone, clones.firstChild);
      }
      carousel.list.insertBefore(clones, carousel.list.firstChild);
      emitCarouselUpdateEvent(carousel);
    };
  
    function insertAfter(carousel, nb, init) {
      if(!carousel.options.loop) return;
      var clones = document.createDocumentFragment();
      for(var i = init; i < nb + init; i++) {
        var index = getIndex(carousel, carousel.selectedItem + carousel.visibItemsNb + i),
          clone = carousel.initItems[index].cloneNode(true);
        Util.addClass(clone, 'js-clone');
        clones.appendChild(clone);
      }
      carousel.list.appendChild(clones);
      emitCarouselUpdateEvent(carousel);
    };
  
    function removeClones(carousel, index, bool) {
      if(!carousel.options.loop) return;
      if( !bool) {
        bool = carousel.visibItemsNb;
      }
      for(var i = 0; i < bool; i++) {
        if(carousel.items[index]) carousel.list.removeChild(carousel.items[index]);
      }
    };
  
    function resetCarouselResize(carousel) { // reset carousel on resize
      var visibleItems = carousel.visibItemsNb;
      // get new items min-width value
      resetItemAutoSize(carousel);
      initCarouselLayout(carousel); 
      setItemsWidth(carousel, false);
      resetItemsWidth(carousel); // update the array of original items -> array used to create clones
      if(carousel.options.loop) {
        if(visibleItems > carousel.visibItemsNb) {
          removeClones(carousel, 0, visibleItems - carousel.visibItemsNb);
        } else if(visibleItems < carousel.visibItemsNb) {
          insertBefore(carousel, carousel.visibItemsNb, visibleItems);
        }
        updateCarouselClones(carousel); // this will take care of translate + after elements
      } else {
        // reset default translate to a multiple value of (itemWidth + margin)
        var translate = noLoopTranslateValue(carousel);
        setTranslate(carousel, 'translateX('+translate+')');
      }
      resetItemsTabIndex(carousel); // reset focusable elements
    };
  
    function resetItemAutoSize(carousel) {
      if(!cssPropertiesSupported) return;
      // remove inline style
      carousel.items[0].removeAttribute('style');
      // get original item width 
      carousel.itemAutoSize = getComputedStyle(carousel.items[0]).getPropertyValue('width');
    };
  
    function resetItemsWidth(carousel) {
      for(var i = 0; i < carousel.initItems.length; i++) {
        carousel.initItems[i].style.width = carousel.itemsWidth+"px";
      }
    };
  
    function resetItemsTabIndex(carousel) {
      var carouselActive = carousel.items.length > carousel.visibItemsNb;
      var j = carousel.items.length;
      for(var i = 0; i < carousel.items.length; i++) {
        if(carousel.options.loop) {
          if(i < carousel.visibItemsNb || i >= 2*carousel.visibItemsNb ) {
            carousel.items[i].setAttribute('tabindex', '-1');
          } else {
            if(i < j) j = i;
            carousel.items[i].removeAttribute('tabindex');
          }
        } else {
          if( (i < carousel.selectedItem || i >= carousel.selectedItem + carousel.visibItemsNb) && carouselActive) {
            carousel.items[i].setAttribute('tabindex', '-1');
          } else {
            if(i < j) j = i;
            carousel.items[i].removeAttribute('tabindex');
          }
        }
      }
      resetVisibilityOverflowItems(carousel, j);
    };
  
    function startAutoplay(carousel) {
      if(carousel.options.autoplay && !carousel.autoplayId && !carousel.autoplayPaused) {
        carousel.autoplayId = setInterval(function(){
          showNextItems(carousel);
        }, carousel.options.autoplayInterval);
      }
    };
  
    function pauseAutoplay(carousel) {
      if(carousel.options.autoplay) {
        clearInterval(carousel.autoplayId);
        carousel.autoplayId = false;
      }
    };
  
    function initAriaLive(carousel) { // create an aria-live region for SR
      if(!carousel.options.ariaLive) return;
      // create an element that will be used to announce the new visible slide to SR
      var srLiveArea = document.createElement('div');
      Util.setAttributes(srLiveArea, {'class': 'sr-only js-carousel__aria-live', 'aria-live': 'polite', 'aria-atomic': 'true'});
      carousel.element.appendChild(srLiveArea);
      carousel.ariaLive = srLiveArea;
    };
  
    function updateAriaLive(carousel) { // announce to SR which items are now visible
      if(!carousel.options.ariaLive) return;
      carousel.ariaLive.innerHTML = 'Item '+(carousel.selectedItem + 1)+' selected. '+carousel.visibItemsNb+' items of '+carousel.initItems.length+' visible';
    };
  
    function getIndex(carousel, index) {
      if(index < 0) index = getPositiveValue(index, carousel.itemsNb);
      if(index >= carousel.itemsNb) index = index % carousel.itemsNb;
      return index;
    };
  
    function getPositiveValue(value, add) {
      value = value + add;
      if(value > 0) return value;
      else return getPositiveValue(value, add);
    };
  
    function setTranslate(carousel, translate) {
      carousel.list.style.transform = translate;
      carousel.list.style.msTransform = translate;
    };
  
    function getCarouselWidth(carousel, computedWidth) { // retrieve carousel width if carousel is initially hidden
      var closestHidden = carousel.listWrapper.closest('.sr-only');
      if(closestHidden) { // carousel is inside an .sr-only (visually hidden) element
        Util.removeClass(closestHidden, 'sr-only');
        computedWidth = carousel.listWrapper.offsetWidth;
        Util.addClass(closestHidden, 'sr-only');
      } else if(isNaN(computedWidth)){
        computedWidth = getHiddenParentWidth(carousel.element, carousel);
      }
      return computedWidth;
    };
  
    function getHiddenParentWidth(element, carousel) {
      var parent = element.parentElement;
      if(parent.tagName.toLowerCase() == 'html') return 0;
      var style = window.getComputedStyle(parent);
      if(style.display == 'none' || style.visibility == 'hidden') {
        parent.setAttribute('style', 'display: block!important; visibility: visible!important;');
        var computedWidth = carousel.listWrapper.offsetWidth;
        parent.style.display = '';
        parent.style.visibility = '';
        return computedWidth;
      } else {
        return getHiddenParentWidth(parent, carousel);
      }
    };
  
    function resetCarouselControls(carousel) {
      if(carousel.options.loop) return;
      // update arrows status
      if(carousel.controls.length > 0) {
        (carousel.totTranslate == 0) 
          ? carousel.controls[0].setAttribute('disabled', true) 
          : carousel.controls[0].removeAttribute('disabled');
        (carousel.totTranslate == (- carousel.translateContainer - carousel.containerWidth) || carousel.items.length <= carousel.visibItemsNb) 
          ? carousel.controls[1].setAttribute('disabled', true) 
          : carousel.controls[1].removeAttribute('disabled');
      }
      // update carousel dots
      if(carousel.options.nav) {
        var selectedDot = carousel.navigation.getElementsByClassName(carousel.options.navigationItemClass+'--selected');
        if(selectedDot.length > 0) Util.removeClass(selectedDot[0], carousel.options.navigationItemClass+'--selected');
  
        var newSelectedIndex = getSelectedDot(carousel);
        if(carousel.totTranslate == (- carousel.translateContainer - carousel.containerWidth)) {
          newSelectedIndex = carousel.navDots.length - 1;
        }
        Util.addClass(carousel.navDots[newSelectedIndex], carousel.options.navigationItemClass+'--selected');
      }
  
      (carousel.totTranslate == 0 && (carousel.totTranslate == (- carousel.translateContainer - carousel.containerWidth) || carousel.items.length <= carousel.visibItemsNb))
          ? Util.addClass(carousel.element, 'carousel--hide-controls')
          : Util.removeClass(carousel.element, 'carousel--hide-controls');
    };
  
    function emitCarouselUpdateEvent(carousel) {
      carousel.cloneList = [];
      var clones = carousel.element.querySelectorAll('.js-clone');
      for(var i = 0; i < clones.length; i++) {
        Util.removeClass(clones[i], 'js-clone');
        carousel.cloneList.push(clones[i]);
      }
      emitCarouselEvents(carousel, 'carousel-updated', carousel.cloneList);
    };
  
    function carouselCreateNavigation(carousel) {
      if(carousel.element.getElementsByClassName('js-carousel__navigation').length > 0) return;
    
      var navigation = document.createElement('ol'),
        navChildren = '';
  
      var navClasses = carousel.options.navigationClass+' js-carousel__navigation';
      if(carousel.items.length <= carousel.visibItemsNb) {
        navClasses = navClasses + ' is-hidden';
      }
      navigation.setAttribute('class', navClasses);
  
      var dotsNr = Math.ceil(carousel.items.length/carousel.visibItemsNb),
        selectedDot = getSelectedDot(carousel),
        indexClass = carousel.options.navigationPagination ? '' : 'sr-only'
      for(var i = 0; i < dotsNr; i++) {
        var className = (i == selectedDot) ? 'class="'+carousel.options.navigationItemClass+' '+carousel.options.navigationItemClass+'--selected js-carousel__nav-item"' :  'class="'+carousel.options.navigationItemClass+' js-carousel__nav-item"';
        navChildren = navChildren + '<li '+className+'><button class="reset js-tab-focus" style="outline: none;"><span class="'+indexClass+'">'+ (i+1) + '</span></button></li>';
      }
      navigation.innerHTML = navChildren;
      carousel.element.appendChild(navigation);
    };
  
    function carouselInitNavigationEvents(carousel) {
      carousel.navigation = carousel.element.getElementsByClassName('js-carousel__navigation')[0];
      carousel.navDots = carousel.element.getElementsByClassName('js-carousel__nav-item');
      carousel.navIdEvent = carouselNavigationClick.bind(carousel);
      carousel.navigation.addEventListener('click', carousel.navIdEvent);
    };
  
    function carouselRemoveNavigation(carousel) {
      if(carousel.navigation) carousel.element.removeChild(carousel.navigation);
      if(carousel.navIdEvent) carousel.navigation.removeEventListener('click', carousel.navIdEvent);
    };
  
    function resetDotsNavigation(carousel) {
      if(!carousel.options.nav) return;
      carouselRemoveNavigation(carousel);
      carouselCreateNavigation(carousel);
      carouselInitNavigationEvents(carousel);
    };
  
    function carouselNavigationClick(event) {
      var dot = event.target.closest('.js-carousel__nav-item');
      if(!dot) return;
      if(this.animating) return;
      this.animating = true;
      var index = Util.getIndexInArray(this.navDots, dot);
      this.selectedDotIndex = index;
      this.selectedItem = index*this.visibItemsNb;
      animateList(this, false, 'click');
    };
  
    function getSelectedDot(carousel) {
      return Math.ceil(carousel.selectedItem/carousel.visibItemsNb);
    };
  
    function initCarouselCounter(carousel) {
      if(carousel.counterTor.length > 0) carousel.counterTor[0].textContent = carousel.itemsNb;
      setCounterItem(carousel);
    };
  
    function setCounterItem(carousel) {
      if(carousel.counter.length == 0) return;
      var totalItems = carousel.selectedItem + carousel.visibItemsNb;
      if(totalItems > carousel.items.length) totalItems = carousel.items.length;
      carousel.counter[0].textContent = totalItems;
    };
  
    function centerItems(carousel) {
      if(!carousel.options.justifyContent) return;
      Util.toggleClass(carousel.list, 'justify-center', carousel.items.length < carousel.visibItemsNb);
    };
  
    function alignControls(carousel) {
      if(carousel.controls.length < 1 || !carousel.options.alignControls) return;
      if(!carousel.controlsAlignEl) {
        carousel.controlsAlignEl = carousel.element.querySelector(carousel.options.alignControls);
      }
      if(!carousel.controlsAlignEl) return;
      var translate = (carousel.element.offsetHeight - carousel.controlsAlignEl.offsetHeight);
      for(var i = 0; i < carousel.controls.length; i++) {
        carousel.controls[i].style.marginBottom = translate + 'px';
      }
    };
  
    function emitCarouselActiveItemsEvent(carousel) {
      emitCarouselEvents(carousel, 'carousel-active-items', {firstSelectedItem: carousel.selectedItem, visibleItemsNb: carousel.visibItemsNb});
    };
  
    function emitCarouselEvents(carousel, eventName, eventDetail) {
      var event = new CustomEvent(eventName, {detail: eventDetail});
      carousel.element.dispatchEvent(event);
    };
  
    function resetVisibilityOverflowItems(carousel, j) {
      if(!carousel.options.overflowItems) return;
      var itemWidth = carousel.containerWidth/carousel.items.length,
        delta = (window.innerWidth - itemWidth*carousel.visibItemsNb)/2,
        overflowItems = Math.ceil(delta/itemWidth);
  
      for(var i = 0; i < overflowItems; i++) {
        var indexPrev = j - 1 - i; // prev element
        if(indexPrev >= 0 ) carousel.items[indexPrev].removeAttribute('tabindex');
        var indexNext = j + carousel.visibItemsNb + i; // next element
        if(indexNext < carousel.items.length) carousel.items[indexNext].removeAttribute('tabindex');
      }
    };
  
    Carousel.defaults = {
      element : '',
      autoplay : false,
      autoplayOnHover: false,
  		autoplayOnFocus: false,
      autoplayInterval: 5000,
      loop: true,
      nav: false,
      navigationItemClass: 'carousel__nav-item',
      navigationClass: 'carousel__navigation',
      navigationPagination: false,
      drag: false,
      justifyContent: false,
      alignControls: false,
      overflowItems: false
    };
  
    window.Carousel = Carousel;
  
    //initialize the Carousel objects
    var carousels = document.getElementsByClassName('js-carousel'),
      flexSupported = Util.cssSupports('align-items', 'stretch'),
      transitionSupported = Util.cssSupports('transition'),
      cssPropertiesSupported = ('CSS' in window && CSS.supports('color', 'var(--color-var)'));
  
    if( carousels.length > 0) {
      for( var i = 0; i < carousels.length; i++) {
        (function(i){
          var autoplay = (carousels[i].getAttribute('data-autoplay') && carousels[i].getAttribute('data-autoplay') == 'on') ? true : false,
            autoplayInterval = (carousels[i].getAttribute('data-autoplay-interval')) ? carousels[i].getAttribute('data-autoplay-interval') : 5000,
            autoplayOnHover = (carousels[i].getAttribute('data-autoplay-hover') && carousels[i].getAttribute('data-autoplay-hover') == 'on') ? true : false,
  					autoplayOnFocus = (carousels[i].getAttribute('data-autoplay-focus') && carousels[i].getAttribute('data-autoplay-focus') == 'on') ? true : false,
            drag = (carousels[i].getAttribute('data-drag') && carousels[i].getAttribute('data-drag') == 'on') ? true : false,
            loop = (carousels[i].getAttribute('data-loop') && carousels[i].getAttribute('data-loop') == 'off') ? false : true,
            nav = (carousels[i].getAttribute('data-navigation') && carousels[i].getAttribute('data-navigation') == 'on') ? true : false,
            navigationItemClass = carousels[i].getAttribute('data-navigation-item-class') ? carousels[i].getAttribute('data-navigation-item-class') : 'carousel__nav-item',
            navigationClass = carousels[i].getAttribute('data-navigation-class') ? carousels[i].getAttribute('data-navigation-class') : 'carousel__navigation',
            navigationPagination = (carousels[i].getAttribute('data-navigation-pagination') && carousels[i].getAttribute('data-navigation-pagination') == 'on') ? true : false,
            overflowItems = (carousels[i].getAttribute('data-overflow-items') && carousels[i].getAttribute('data-overflow-items') == 'on') ? true : false,
            alignControls = carousels[i].getAttribute('data-align-controls') ? carousels[i].getAttribute('data-align-controls') : false,
            justifyContent = (carousels[i].getAttribute('data-justify-content') && carousels[i].getAttribute('data-justify-content') == 'on') ? true : false;
          new Carousel({element: carousels[i], autoplay : autoplay, autoplayOnHover: autoplayOnHover, autoplayOnFocus: autoplayOnFocus,autoplayInterval : autoplayInterval, drag: drag, ariaLive: true, loop: loop, nav: nav, navigationItemClass: navigationItemClass, navigationPagination: navigationPagination, navigationClass: navigationClass, overflowItems: overflowItems, justifyContent: justifyContent, alignControls: alignControls});
        })(i);
      }
    };
  }());
  // File#: _2_chart
  // Usage: codyhouse.co/license
  (function() {
    var Chart = function(opts) {
      this.options = Util.extend(Chart.defaults , opts);
      this.element = this.options.element.getElementsByClassName('js-chart__area')[0];
      this.svgPadding = this.options.padding;
      this.topDelta = this.svgPadding;
      this.bottomDelta = 0;
      this.leftDelta = 0;
      this.rightDelta = 0;
      this.legendHeight = 0;
      this.yChartMaxWidth = 0;
      this.yAxisHeight = 0;
      this.xAxisWidth = 0;
      this.yAxisInterval = []; // used to store min and max value on y axis
      this.xAxisInterval = []; // used to store min and max value on x axis
      this.datasetScaled = []; // used to store set data converted to chart coordinates
      this.datasetScaledFlat = []; // used to store set data converted to chart coordinates for animation
      this.datasetAreaScaled = []; // used to store set data (area part) converted to chart coordinates
      this.datasetAreaScaledFlat = []; // used to store set data (area part)  converted to chart coordinates for animation
      // columns chart - store if x axis label where rotated
      this.xAxisLabelRotation = false;
      // tooltip
      this.interLine = false;
      this.markers = false;
      this.tooltipOn = this.options.tooltip && this.options.tooltip.enabled;
      this.tooltipClasses = (this.tooltipOn && this.options.tooltip.classes) ? this.options.tooltip.classes : '';
      this.tooltipPosition = (this.tooltipOn && this.options.tooltip.position) ? this.options.tooltip.position : false;
      this.tooltipDelta = 10;
      this.selectedMarker = false;
      this.selectedMarkerClass = 'chart__marker--selected';
      this.selectedBarClass = 'chart__data-bar--selected';
      this.hoverId = false;
      this.hovering = false;
      // events id
      this.eventIds = []; // will use to store event ids
      // accessibility
      this.categories = this.options.element.getElementsByClassName('js-chart__category');
      this.loaded = false;
      // init chart
      initChartInfo(this);
      initChart(this);
      // if externalDate == true
      initExternalData(this);
    };
  
    function initChartInfo(chart) {
      // we may need to store store some initial config details before setting up the chart
      if(chart.options.type == 'column') {
        setChartColumnSize(chart);
      }
    };
  
    function initChart(chart) {
      if(chart.options.datasets.length == 0) return; // no data where provided
      if(!intObservSupported) chart.options.animate = false; // do not animate if intersectionObserver is not supported
      // init event ids variables
      intEventIds(chart);
      setChartSize(chart);
      createChartSvg(chart);
      createSrTables(chart); // chart accessibility
      animateChart(chart); // if animate option is true
      resizeChart(chart);
      chart.loaded = true;
    };
  
    function intEventIds(chart) {
      chart.eventIds['resize'] = false;
    };
  
    function setChartSize(chart) {
      chart.height = chart.element.clientHeight;
      chart.width = chart.element.clientWidth;
    };
  
    function createChartSvg(chart) {
      var svg = '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="'+chart.width+'" height="'+chart.height+'" class="chart__svg js-chart__svg"></svg>';
      chart.element.innerHTML = svg;
      chart.svg = chart.element.getElementsByClassName('js-chart__svg')[0];
  
      // create chart content
      switch (chart.options.type) {
        case 'pie':
          getPieSvgCode(chart);
          break;
        case 'doughnut':
          getDoughnutSvgCode(chart);
          break;
        case 'column':
          getColumnSvgCode(chart);
          break;
        default:
          getLinearSvgCode(chart);
      }
    };
  
    function getLinearSvgCode(chart) { // svg for linear + area charts
      setYAxis(chart);
      setXAxis(chart);
      updateChartWidth(chart);
      placexAxisLabels(chart);
      placeyAxisLabels(chart);
      setChartDatasets(chart);
      initTooltips(chart);
    };
  
    function getColumnSvgCode(chart) { // svg for column charts
      setYAxis(chart);
      setXAxis(chart);
      updateChartWidth(chart);
      placexAxisLabels(chart);
      placeyAxisLabels(chart);
      resetColumnChart(chart);
      setColumnChartDatasets(chart);
      initTooltips(chart);
    };
  
    function setXAxis(chart) {
      // set legend of axis if available
      if( chart.options.xAxis && chart.options.xAxis.legend) {
        var textLegend = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        textLegend.textContent = chart.options.xAxis.legend;
        Util.setAttributes(textLegend, {class: 'chart__axis-legend chart__axis-legend--x js-chart__axis-legend--x'});
        chart.svg.appendChild(textLegend);
  
        var xLegend = chart.element.getElementsByClassName('js-chart__axis-legend--x')[0];
  
        if(isVisible(xLegend)) {
          var size = xLegend.getBBox(),
            xPosition = chart.width/2 - size.width/2,
            yPosition = chart.height - chart.bottomDelta;
  
          Util.setAttributes(xLegend, {x: xPosition, y: yPosition});
          chart.bottomDelta = chart.bottomDelta + size.height +chart.svgPadding;
        }
      }
  
      // get interval and create scale
      var xLabels;
      if(chart.options.xAxis && chart.options.xAxis.labels && chart.options.xAxis.labels.length > 1) {
        xLabels = chart.options.xAxis.labels;
        chart.xAxisInterval = [0, chart.options.xAxis.labels.length - 1];
      } else {
        xLabels = getChartXLabels(chart); // this function is used to set chart.xAxisInterval as well
      }
      // modify axis labels
      if(chart.options.xAxis && chart.options.xAxis.labelModifier) {
        xLabels = modifyAxisLabel(xLabels, chart.options.xAxis.labelModifier);
      } 
  
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      Util.setAttributes(gEl, {class: 'chart__axis-labels chart__axis-labels--x js-chart__axis-labels--x'});
  
      for(var i = 0; i < xLabels.length; i++) {
        var textEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        var labelClasses = (chart.options.xAxis && chart.options.xAxis.labels) ? 'chart__axis-label chart__axis-label--x js-chart__axis-label' : 'is-hidden js-chart__axis-label';
        Util.setAttributes(textEl, {class: labelClasses, 'alignment-baseline': 'middle'});
        textEl.textContent = xLabels[i];
        gEl.appendChild(textEl);
      }
      
      if(chart.options.xAxis && chart.options.xAxis.line) {
        var lineEl = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        Util.setAttributes(lineEl, {class: 'chart__axis chart__axis--x js-chart__axis--x', 'stroke-linecap': 'square'});
        gEl.appendChild(lineEl);
      }
  
      var ticksLength = xLabels.length;
      if(chart.options.type == 'column') ticksLength = ticksLength + 1;
      
      for(var i = 0; i < ticksLength; i++) {
        var tickEl = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        var classTicks = (chart.options.xAxis && chart.options.xAxis.ticks) ? 'chart__tick chart__tick-x js-chart__tick-x' : 'js-chart__tick-x';
        Util.setAttributes(tickEl, {class: classTicks, 'stroke-linecap': 'square'});
        gEl.appendChild(tickEl);
      }
  
      chart.svg.appendChild(gEl);
    };
  
    function setYAxis(chart) {
      // set legend of axis if available
      if( chart.options.yAxis && chart.options.yAxis.legend) {
        var textLegend = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        textLegend.textContent = chart.options.yAxis.legend;
        textLegend.setAttribute('class', 'chart__axis-legend chart__axis-legend--y js-chart__axis-legend--y');
        chart.svg.appendChild(textLegend);
  
        var yLegend = chart.element.getElementsByClassName('js-chart__axis-legend--y')[0];
        if(isVisible(yLegend)) {
          var height = yLegend.getBBox().height,
            xPosition = chart.leftDelta + height/2,
            yPosition = chart.topDelta;
      
          Util.setAttributes(yLegend, {x: xPosition, y: yPosition});
          chart.leftDelta = chart.leftDelta + height + chart.svgPadding;
        }
      }
      // get interval and create scale
      var yLabels;
      if(chart.options.yAxis && chart.options.yAxis.labels && chart.options.yAxis.labels.length > 1) {
        yLabels = chart.options.yAxis.labels;
        chart.yAxisInterval = [0, chart.options.yAxis.labels.length - 1];
      } else {
        yLabels = getChartYLabels(chart); // this function is used to set chart.yAxisInterval as well
      }
  
      // modify axis labels
      if(chart.options.yAxis && chart.options.yAxis.labelModifier) {
        yLabels = modifyAxisLabel(yLabels, chart.options.yAxis.labelModifier);
      } 
  
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      Util.setAttributes(gEl, {class: 'chart__axis-labels chart__axis-labels--y js-chart__axis-labels--y'});
  
      for(var i = yLabels.length - 1; i >= 0; i--) {
        var textEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        var labelClasses = (chart.options.yAxis && chart.options.yAxis.labels) ? 'chart__axis-label chart__axis-label--y js-chart__axis-label' : 'is-hidden js-chart__axis-label';
        Util.setAttributes(textEl, {class: labelClasses, 'alignment-baseline': 'middle'});
        textEl.textContent = yLabels[i];
        gEl.appendChild(textEl);
      }
  
      if(chart.options.yAxis && chart.options.yAxis.line) {
        var lineEl = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        Util.setAttributes(lineEl, {class: 'chart__axis chart__axis--y js-chart__axis--y', 'stroke-linecap': 'square'});
        gEl.appendChild(lineEl);
      }
  
      var hideGuides = chart.options.xAxis && chart.options.xAxis.hasOwnProperty('guides') && !chart.options.xAxis.guides;
      for(var i = 1; i < yLabels.length; i++ ) {
        var rectEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
        Util.setAttributes(rectEl, {class: 'chart__guides js-chart__guides'});
        if(hideGuides) {
          Util.setAttributes(rectEl, {class: 'chart__guides js-chart__guides opacity-0'});
        }
        gEl.appendChild(rectEl);
      }
      chart.svg.appendChild(gEl);
    };
  
    function updateChartWidth(chart) {
      var labels = chart.element.getElementsByClassName('js-chart__axis-labels--y')[0].querySelectorAll('.js-chart__axis-label');
  
      if(isVisible(labels[0])) {
        chart.yChartMaxWidth = getLabelMaxSize(labels, 'width');
        chart.leftDelta = chart.leftDelta + chart.svgPadding + chart.yChartMaxWidth + chart.svgPadding;
      } else {
        chart.leftDelta = chart.leftDelta + chart.svgPadding;
      }
  
      var xLabels = chart.element.getElementsByClassName('js-chart__axis-labels--x')[0].querySelectorAll('.js-chart__axis-label');
      if(isVisible(xLabels[0]) && !isVisible(labels[0])) {
        chart.leftDelta = chart.leftDelta + xLabels[0].getBBox().width*0.5;
      }
    };
  
    function placeyAxisLabels(chart) {
      var labels = chart.element.getElementsByClassName('js-chart__axis-labels--y')[0].querySelectorAll('.js-chart__axis-label');
  
      var labelsVisible = isVisible(labels[0]);
      var height = 0;
      if(labelsVisible) height = labels[0].getBBox().height*0.5;
      
      // update topDelta and set chart height
      chart.topDelta = chart.topDelta + height + chart.svgPadding;
      chart.yAxisHeight = chart.height - chart.topDelta - chart.bottomDelta;
  
      var yDelta = chart.yAxisHeight/(labels.length - 1);
  
      var gridRect = chart.element.getElementsByClassName('js-chart__guides'),
        dasharray = ""+chart.xAxisWidth+" "+(2*(chart.xAxisWidth + yDelta))+"";
  
      for(var i = 0; i < labels.length; i++) {
        var labelWidth = 0;
        if(labelsVisible) labelWidth = labels[i].getBBox().width;
        // chart.leftDelta has already been updated in updateChartWidth() function
        Util.setAttributes(labels[i], {x: chart.leftDelta - labelWidth - 2*chart.svgPadding, y: chart.topDelta + yDelta*i });
        // place grid rectangles
        if(gridRect[i]) Util.setAttributes(gridRect[i], {x: chart.leftDelta, y: chart.topDelta + yDelta*i, height: yDelta, width: chart.xAxisWidth, 'stroke-dasharray': dasharray});
      }
  
      // place the y axis
      var yAxis = chart.element.getElementsByClassName('js-chart__axis--y');
      if(yAxis.length > 0) {
        Util.setAttributes(yAxis[0], {x1: chart.leftDelta, x2: chart.leftDelta, y1: chart.topDelta, y2: chart.topDelta + chart.yAxisHeight})
      }
      // center y axis label
      var yLegend = chart.element.getElementsByClassName('js-chart__axis-legend--y');
      if(yLegend.length > 0 && isVisible(yLegend[0]) ) {
        var position = yLegend[0].getBBox(),
          height = position.height,
          yPosition = position.y + 0.5*(chart.yAxisHeight + position.width),
          xPosition = position.x + height/4;
        
        Util.setAttributes(yLegend[0], {y: yPosition, x: xPosition, transform: 'rotate(-90 '+(position.x + height)+' '+(yPosition + height/2)+')'});
      }
    };
  
    function placexAxisLabels(chart) {
      var labels = chart.element.getElementsByClassName('js-chart__axis-labels--x')[0].querySelectorAll('.js-chart__axis-label');
      var ticks = chart.element.getElementsByClassName('js-chart__tick-x');
  
      // increase rightDelta value
      var labelWidth = 0,
        labelsVisible = isVisible(labels[labels.length - 1]);
      if(labelsVisible) labelWidth = labels[labels.length - 1].getBBox().width;
      if(chart.options.type != 'column') {
        chart.rightDelta = chart.rightDelta + labelWidth*0.5 + chart.svgPadding;
      } else {
        chart.rightDelta = chart.rightDelta + 4;
      }
      chart.xAxisWidth = chart.width - chart.leftDelta - chart.rightDelta;
      
  
      var maxHeight = getLabelMaxSize(labels, 'height'),
        maxWidth = getLabelMaxSize(labels, 'width'),
        xDelta = chart.xAxisWidth/(labels.length - 1);
  
      if(chart.options.type == 'column') xDelta = chart.xAxisWidth/labels.length;
  
      var totWidth = 0,
        height = 0;
      if(labelsVisible)  height = labels[0].getBBox().height;
  
      for(var i = 0; i < labels.length; i++) {
        var width = 0;
        if(labelsVisible) width = labels[i].getBBox().width;
        // label
        Util.setAttributes(labels[i], {y: chart.height - chart.bottomDelta - height/2, x: chart.leftDelta + xDelta*i - width/2});
        // tick
        Util.setAttributes(ticks[i], {y1: chart.height - chart.bottomDelta - maxHeight - chart.svgPadding, y2: chart.height - chart.bottomDelta - maxHeight - chart.svgPadding + 5, x1: chart.leftDelta + xDelta*i, x2: chart.leftDelta + xDelta*i});
        totWidth = totWidth + width + 4;
      }
      // for columns chart -> there's an additional tick element
      if(chart.options.type == 'column' && ticks[labels.length]) {
        Util.setAttributes(ticks[labels.length], {y1: chart.height - chart.bottomDelta - maxHeight - chart.svgPadding, y2: chart.height - chart.bottomDelta - maxHeight - chart.svgPadding + 5, x1: chart.leftDelta + xDelta*labels.length, x2: chart.leftDelta + xDelta*labels.length});
      }
      //check if we need to rotate chart label -> not enough space
      if(totWidth >= chart.xAxisWidth) {
        chart.xAxisLabelRotation = true;
        rotatexAxisLabels(chart, labels, ticks, maxWidth - maxHeight);
        maxHeight = maxWidth;
      } else {
        chart.xAxisLabelRotation = false;
      }
  
      chart.bottomDelta = chart.bottomDelta + chart.svgPadding + maxHeight;
  
      // place the x axis
      var xAxis = chart.element.getElementsByClassName('js-chart__axis--x');
      if(xAxis.length > 0) {
        Util.setAttributes(xAxis[0], {x1: chart.leftDelta, x2: chart.width - chart.rightDelta, y1: chart.height - chart.bottomDelta, y2: chart.height - chart.bottomDelta})
      }
  
      // center x-axis label
      var xLegend = chart.element.getElementsByClassName('js-chart__axis-legend--x');
      if(xLegend.length > 0 && isVisible(xLegend[0])) {
        xLegend[0].setAttribute('x', chart.leftDelta + 0.5*(chart.xAxisWidth - xLegend[0].getBBox().width));
      }
    };
  
    function rotatexAxisLabels(chart, labels, ticks, delta) {
      // there's not enough horiziontal space -> we need to rotate the x axis labels
      for(var i = 0; i < labels.length; i++) {
        var dimensions = labels[i].getBBox(),
          xCenter = parseFloat(labels[i].getAttribute('x')) + dimensions.width/2,
          yCenter = parseFloat(labels[i].getAttribute('y'))  - delta;
  
        Util.setAttributes(labels[i], {y: parseFloat(labels[i].getAttribute('y')) - delta, transform: 'rotate(-45 '+xCenter+' '+yCenter+')'});
  
        ticks[i].setAttribute('transform', 'translate(0 -'+delta+')');
      }
      if(ticks[labels.length]) ticks[labels.length].setAttribute('transform', 'translate(0 -'+delta+')');
    };
  
    function setChartDatasets(chart) {
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      gEl.setAttribute('class', 'chart__dataset js-chart__dataset');
      chart.datasetScaled = [];
      for(var i = 0; i < chart.options.datasets.length; i++) {
        var gSet = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        gSet.setAttribute('class', 'chart__set chart__set--'+(i+1)+' js-chart__set');
        chart.datasetScaled[i] = JSON.parse(JSON.stringify(chart.options.datasets[i].data));
        chart.datasetScaled[i] = getChartData(chart, chart.datasetScaled[i]);
        chart.datasetScaledFlat[i] = JSON.parse(JSON.stringify(chart.datasetScaled[i]));
        if(chart.options.type == 'area') {
          chart.datasetAreaScaled[i] = getAreaPointsFromLine(chart, chart.datasetScaled[i]);
          chart.datasetAreaScaledFlat[i] = JSON.parse(JSON.stringify(chart.datasetAreaScaled[i]));
        }
        if(!chart.loaded && chart.options.animate) {
          flatDatasets(chart, i);
        }
        gSet.appendChild(getPath(chart, chart.datasetScaledFlat[i], chart.datasetAreaScaledFlat[i], i));
        gSet.appendChild(getMarkers(chart, chart.datasetScaled[i], i));
        gEl.appendChild(gSet);
      }
      
      chart.svg.appendChild(gEl);
    };
  
    function getChartData(chart, data) {
      var multiSet = data[0].length > 1;
      var points = multiSet ? data : addXData(data); // addXData is used for one-dimension dataset; e.g. [2, 4, 6] rather than [[2, 4], [4, 7]]
      
      // xOffsetChart used for column chart type onlymodified
      var xOffsetChart = chart.xAxisWidth/(points.length-1) - chart.xAxisWidth/points.length;
      // now modify the points to coordinate relative to the svg 
      for(var i = 0; i < points.length; i++) {
        var xNewCoordinate = chart.leftDelta + chart.xAxisWidth*(points[i][0] - chart.xAxisInterval[0])/(chart.xAxisInterval[1] - chart.xAxisInterval[0]),
          yNewCoordinate = chart.height - chart.bottomDelta - chart.yAxisHeight*(points[i][1] - chart.yAxisInterval[0])/(chart.yAxisInterval[1] - chart.yAxisInterval[0]);
        if(chart.options.type == 'column') {
          xNewCoordinate = xNewCoordinate - i*xOffsetChart;
        }
        points[i] = [xNewCoordinate, yNewCoordinate];
      }
      return points;
    };
  
    function getPath(chart, points, areaPoints, index) {
      var pathCode = chart.options.smooth ? getSmoothLine(points, false) : getStraightLine(points);
      
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
        pathL = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        
      Util.setAttributes(pathL, {d: pathCode, class: 'chart__data-line chart__data-line--'+(index+1)+' js-chart__data-line--'+(index+1)});
  
      if(chart.options.type == 'area') {
        var areaCode = chart.options.smooth ? getSmoothLine(areaPoints, true) : getStraightLine(areaPoints);
        var pathA = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        Util.setAttributes(pathA, {d: areaCode, class: 'chart__data-fill chart__data-fill--'+(index+1)+' js-chart__data-fill--'+(index+1)});
        gEl.appendChild(pathA);
      }
     
      gEl.appendChild(pathL);
      return gEl;
    };
  
    function getStraightLine(points) {
      var dCode = '';
      for(var i = 0; i < points.length; i++) {
        dCode = (i == 0) ? 'M '+points[0][0]+','+points[0][1] : dCode+ ' L '+points[i][0]+','+points[i][1];
      }
      return dCode;
    };
  
    function flatDatasets(chart, index) {
      var bottomY = getBottomFlatDatasets(chart);
      for(var i = 0; i < chart.datasetScaledFlat[index].length; i++) {
        chart.datasetScaledFlat[index][i] = [chart.datasetScaled[index][i][0], bottomY];
      }
      if(chart.options.type == 'area') {
        chart.datasetAreaScaledFlat[index] = getAreaPointsFromLine(chart, chart.datasetScaledFlat[index]);
      }
    };
  
    // https://medium.com/@francoisromain/smooth-a-svg-path-with-cubic-bezier-curves-e37b49d46c74
    function getSmoothLine(points, bool) {
      var dCode = '';
      var maxVal = points.length;
      var pointsLoop = JSON.parse(JSON.stringify(points));
      if(bool) {
        maxVal = maxVal - 3;
        pointsLoop.splice(-3, 3);
      }
      for(var i = 0; i < maxVal; i++) {
        if(i == 0) dCode = 'M '+points[0][0]+','+points[0][1];
        else dCode = dCode + ' '+bezierCommand(points[i], i, pointsLoop);
      }
      if(bool) {
        for(var j = maxVal; j < points.length; j++) {
          dCode = dCode + ' L '+points[j][0]+','+points[j][1];
        }
      }
      return dCode;
    };  
    
    function pathLine(pointA, pointB) {
      var lengthX = pointB[0] - pointA[0];
      var lengthY = pointB[1] - pointA[1];
  
      return {
        length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
        angle: Math.atan2(lengthY, lengthX)
      };
    };
  
    function pathControlPoint(current, previous, next, reverse) {
      var p = previous || current;
      var n = next || current;
      var smoothing = 0.2;
      var o = pathLine(p, n);
  
      var angle = o.angle + (reverse ? Math.PI : 0);
      var length = o.length * smoothing;
  
      var x = current[0] + Math.cos(angle) * length;
      var y = current[1] + Math.sin(angle) * length;
      return [x, y];
    };
  
    function bezierCommand(point, i, a) {
      var cps =  pathControlPoint(a[i - 1], a[i - 2], point);
      var cpe = pathControlPoint(point, a[i - 1], a[i + 1], true);
      return "C "+cps[0]+','+cps[1]+' '+cpe[0]+','+cpe[1]+' '+point[0]+','+point[1];
    };
  
    function getAreaPointsFromLine(chart, array) {
      var points = JSON.parse(JSON.stringify(array)),
        firstPoint = points[0],
        lastPoint = points[points.length -1];
  
      var boottomY = getBottomFlatDatasets(chart); 
      points.push([lastPoint[0], boottomY]);
      points.push([chart.leftDelta, boottomY]);
      points.push([chart.leftDelta, firstPoint[1]]);
      return points;
    };
  
    function getBottomFlatDatasets(chart) {
      var bottom = chart.height - chart.bottomDelta;
      if(chart.options.fillOrigin ) {
        bottom = chart.height - chart.bottomDelta - chart.yAxisHeight*(0 - chart.yAxisInterval[0])/(chart.yAxisInterval[1] - chart.yAxisInterval[0]);
      }
      if(chart.options.type && chart.options.type == 'column') {
        bottom = chart.yZero; 
      }
      return bottom;
    };
  
    function getMarkers(chart, points, index) {
      // see if we need to show tooltips 
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      var xOffset = 0;
      if(chart.options.type == 'column') {
        xOffset = 0.5*chart.xAxisWidth/points.length;
      }
      for(var i = 0; i < points.length; i++) {
        var marker = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        Util.setAttributes(marker, {class: 'chart__marker js-chart__marker chart__marker--'+(index+1), cx: points[i][0] + xOffset, cy: points[i][1], r: 2, 'data-set': index, 'data-index': i});
        gEl.appendChild(marker);
      }
      return gEl;
    };
  
    function addXData(data) {
      var multiData = [];
      for(var i = 0; i < data.length; i++) {
        multiData.push([i, data[i]]);
      }
      return multiData;
    };
  
    function createSrTables(chart) {
      // create a table element for accessibility reasons
      var table = '<div class="chart__sr-table sr-only">';
      for(var i = 0; i < chart.options.datasets.length; i++) {
        table = table + createDataTable(chart, i);
      }
      table = table + '</div>';
      chart.element.insertAdjacentHTML('afterend', table);
    };
  
    function createDataTable(chart, index) {
      var tableTitle = (chart.categories.length > index ) ? 'aria-label="'+chart.categories.length[index].textContent+'"': '';
      var table = '<table '+tableTitle+'><thead><tr>';
      table = (chart.options.xAxis && chart.options.xAxis.legend) 
        ? table + '<th scope="col">'+chart.options.xAxis.legend+'</th>'
        : table + '<th scope="col"></th>';
        
      table = (chart.options.yAxis && chart.options.yAxis.legend) 
        ? table + '<th scope="col">'+chart.options.yAxis.legend+'</th>'
        : table + '<th scope="col"></th>';
  
      table = table + '</thead><tbody>';
      var multiset = chart.options.datasets[index].data[0].length > 1,
        xAxisLabels = chart.options.xAxis && chart.options.xAxis.labels && chart.options.xAxis.labels.length > 1;
      for(var i = 0; i < chart.options.datasets[index].data.length; i++) {
        table = table + '<tr>';
        if(multiset) {
          table = table + '<td role="cell">'+chart.options.datasets[index].data[i][0]+'</td><td role="cell">'+chart.options.datasets[index].data[i][1]+'</td>';
        } else {
          var xValue = xAxisLabels ? chart.options.xAxis.labels[i]: (i + 1);
          table = table + '<td role="cell">'+xValue+'</td><td role="cell">'+chart.options.datasets[index].data[i]+'</td>';
        }
        table = table + '</tr>';
      }
      table = table + '</tbody></table>';
      return table;
    }
  
    function getChartYLabels(chart) {
      var labels = [],
        intervals = 0;
      if(chart.options.yAxis && chart.options.yAxis.range && chart.options.yAxis.step) {
        intervals = Math.ceil((chart.options.yAxis.range[1] - chart.options.yAxis.range[0])/chart.options.yAxis.step);
        for(var i = 0; i <= intervals; i++) {
          labels.push(chart.options.yAxis.range[0] + chart.options.yAxis.step*i);
        }
        chart.yAxisInterval = [chart.options.yAxis.range[0], chart.options.yAxis.range[1]];
      } else {
        var columnChartStacked = (chart.options.type && chart.options.type == 'column' && chart.options.stacked);
        if(columnChartStacked) setDatasetsSum(chart);
        var min = columnChartStacked ? getColStackedMinDataValue(chart) : getMinDataValue(chart, true);
        var max = columnChartStacked ? getColStackedMaxDataValue(chart) : getMaxDataValue(chart, true);
        var niceScale = new NiceScale(min, max, 5);
        var intervals = Math.ceil((niceScale.getNiceUpperBound() - niceScale.getNiceLowerBound()) /niceScale.getTickSpacing());
  
        for(var i = 0; i <= intervals; i++) {
          labels.push(niceScale.getNiceLowerBound() + niceScale.getTickSpacing()*i);
        }
        chart.yAxisInterval = [niceScale.getNiceLowerBound(), niceScale.getNiceUpperBound()];
      }
      return labels;
    };
  
    function getChartXLabels(chart) {
      var labels = [],
        intervals = 0;
      if(chart.options.xAxis && chart.options.xAxis.range && chart.options.xAxis.step) {
        intervals = Math.ceil((chart.options.xAxis.range[1] - chart.options.xAxis.range[0])/chart.options.xAxis.step);
        for(var i = 0; i <= intervals; i++) {
          labels.push(chart.options.xAxis.range[0] + chart.options.xAxis.step*i);
        }
        chart.xAxisInterval = [chart.options.xAxis.range[0], chart.options.xAxis.range[1]];
      } else if(!chart.options.datasets[0].data[0].length || chart.options.datasets[0].data[0].length < 2) {
        // data sets are passed with a single value (y axis only)
        chart.xAxisInterval = [0, chart.options.datasets[0].data.length - 1];
        for(var i = 0; i < chart.options.datasets[0].data.length; i++) {
          labels.push(i);
        }
      } else {
        var min = getMinDataValue(chart, false);
        var max = getMaxDataValue(chart, false);
        var niceScale = new NiceScale(min, max, 5);
        var intervals = Math.ceil((niceScale.getNiceUpperBound() - niceScale.getNiceLowerBound()) /niceScale.getTickSpacing());
  
        for(var i = 0; i <= intervals; i++) {
          labels.push(niceScale.getNiceLowerBound() + niceScale.getTickSpacing()*i);
        }
        chart.xAxisInterval = [niceScale.getNiceLowerBound(), niceScale.getNiceUpperBound()];
      }
      return labels;
    };
  
    function modifyAxisLabel(labels, fnModifier) {
      for(var i = 0; i < labels.length; i++) {
        labels[i] = fnModifier(labels[i]);
      }
  
      return labels;
    };
  
    function getLabelMaxSize(labels, dimesion) {
      if(!isVisible(labels[0])) return 0;
      var size = 0;
      for(var i = 0; i < labels.length; i++) {
        var labelSize = labels[i].getBBox()[dimesion];
        if(labelSize > size) size = labelSize;
      };  
      return size;
    };
  
    function getMinDataValue(chart, bool) { // bool = true for y axis
      var minArray = [];
      for(var i = 0; i < chart.options.datasets.length; i++) {
        minArray.push(getMin(chart.options.datasets[i].data, bool));
      }
      return Math.min.apply(null, minArray);
    };
  
    function getMaxDataValue(chart, bool) { // bool = true for y axis
      var maxArray = [];
      for(var i = 0; i < chart.options.datasets.length; i++) {
        maxArray.push(getMax(chart.options.datasets[i].data, bool));
      }
      return Math.max.apply(null, maxArray);
    };
  
    function setDatasetsSum(chart) {
      // sum all datasets -> this is used for column and bar charts
      chart.datasetsSum = [];
      for(var i = 0; i < chart.options.datasets.length; i++) {
        for(var j = 0; j < chart.options.datasets[i].data.length; j++) {
          chart.datasetsSum[j] = (i == 0) ? chart.options.datasets[i].data[j] : chart.datasetsSum[j] + chart.options.datasets[i].data[j];
        }
      } 
    };
  
    function getColStackedMinDataValue(chart) {
      var min = Math.min.apply(null, chart.datasetsSum);
      if(min > 0) min = 0;
      return min;
    };
  
    function getColStackedMaxDataValue(chart) {
      var max = Math.max.apply(null, chart.datasetsSum);
      if(max < 0) max = 0;
      return max;
    };
  
    function getMin(array, bool) {
      var min;
      var multiSet = array[0].length > 1;
      for(var i = 0; i < array.length; i++) {
        var value;
        if(multiSet) {
          value = bool ? array[i][1] : array[i][0];
        } else {
          value = array[i];
        }
        if(i == 0) {min = value;}
        else if(value < min) {min = value;}
      }
      return min;
    };
  
    function getMax(array, bool) {
      var max;
      var multiSet = array[0].length > 1;
      for(var i = 0; i < array.length; i++) {
        var value;
        if(multiSet) {
          value = bool ? array[i][1] : array[i][0];
        } else {
          value = array[i];
        }
        if(i == 0) {max = value;}
        else if(value > max) {max = value;}
      }
      return max;
    };
  
    // https://gist.github.com/igodorogea/4f42a95ea31414c3a755a8b202676dfd
    function NiceScale (lowerBound, upperBound, _maxTicks) {
      var maxTicks = _maxTicks || 10;
      var tickSpacing;
      var range;
      var niceLowerBound;
      var niceUpperBound;
    
      calculate();
    
      this.setMaxTicks = function (_maxTicks) {
        maxTicks = _maxTicks;
        calculate();
      };
    
      this.getNiceUpperBound = function() {
        return niceUpperBound;
      };
    
      this.getNiceLowerBound = function() {
        return niceLowerBound;
      };
    
      this.getTickSpacing = function() {
        return tickSpacing;
      };
    
      function setMinMaxPoints (min, max) {
        lowerBound = min;
        upperBound = max;
        calculate();
      }
    
      function calculate () {
        range = niceNum(upperBound - lowerBound, false);
        tickSpacing = niceNum(range / (maxTicks - 1), true);
        niceLowerBound = Math.floor(lowerBound / tickSpacing) * tickSpacing;
        niceUpperBound = Math.ceil(upperBound / tickSpacing) * tickSpacing;
      }
    
      function niceNum (range, round) {
        // var exponent = Math.floor(Math.log10(range));
        var exponent = Math.floor(Math.log(range) * Math.LOG10E);
        var fraction = range / Math.pow(10, exponent);
        var niceFraction;
    
        if (round) {
          if (fraction < 1.5) niceFraction = 1;
          else if (fraction < 3) niceFraction = 2;
          else if (fraction < 7) niceFraction = 5;
          else niceFraction = 10;
        } else {
          if (fraction <= 1) niceFraction = 1;
          else if (fraction <= 2) niceFraction = 2;
          else if (fraction <= 5) niceFraction = 5;
          else niceFraction = 10;
        }
    
        return niceFraction * Math.pow(10, exponent);
      }
    };
  
    function initTooltips(chart) {
      if(!intObservSupported) return;
  
      chart.markers = [];
      chart.bars = []; // this is for column/bar charts only
      var chartSets = chart.element.getElementsByClassName('js-chart__set');
      for(var i = 0; i < chartSets.length; i++) {
        chart.markers[i] = chartSets[i].querySelectorAll('.js-chart__marker');
        if(chart.options.type && chart.options.type == 'column') {
          chart.bars[i] = chartSets[i].querySelectorAll('.js-chart__data-bar');
        }
      }
      
      // create tooltip line
      if(chart.options.yIndicator) {
        var tooltipLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        Util.setAttributes(tooltipLine, {x1: 0, y1: chart.topDelta, x2: 0, y2: chart.topDelta + chart.yAxisHeight, transform: 'translate('+chart.leftDelta+' '+chart.topDelta+')', class: 'chart__y-indicator js-chart__y-indicator is-hidden'});
        chart.svg.insertBefore(tooltipLine, chart.element.getElementsByClassName('js-chart__dataset')[0]);
        chart.interLine = chart.element.getElementsByClassName('js-chart__y-indicator')[0];
      }
      
      // create tooltip
      if(chart.tooltipOn) {
        var tooltip = document.createElement('div');
        tooltip.setAttribute('class', 'chart__tooltip js-chart__tooltip is-hidden '+chart.tooltipClasses);
        chart.element.appendChild(tooltip);
        chart.tooltip = chart.element.getElementsByClassName('js-chart__tooltip')[0];
      }
      initChartHover(chart);
    };
  
    function initChartHover(chart) {
      if(!chart.options.yIndicator && !chart.tooltipOn) return;
      // init hover effect
      chart.chartArea = chart.element.getElementsByClassName('js-chart__axis-labels--y')[0];
      chart.eventIds['hover'] = handleEvent.bind(chart);
      chart.chartArea.addEventListener('mouseenter', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mousemove', chart.eventIds['hover']);
      chart.chartArea.addEventListener('mouseleave', chart.eventIds['hover']);
      if(!SwipeContent) return;
      new SwipeContent(chart.element);
      chart.element.addEventListener('dragStart', chart.eventIds['hover']);
      chart.element.addEventListener('dragging', chart.eventIds['hover']);
      chart.element.addEventListener('dragEnd', chart.eventIds['hover']);
    };
  
    function hoverChart(chart, event) {
      if(chart.hovering) return;
      if(!chart.options.yIndicator && !chart.tooltipOn) return;
      chart.hovering = true;
      var selectedMarker = getSelectedMarker(chart, event);
      if(selectedMarker === false) return;
      if(selectedMarker !== chart.selectedMarker) {
        resetMarkers(chart, false);
        resetBars(chart, false);
  
        chart.selectedMarker = selectedMarker;
        resetMarkers(chart, true);
        resetBars(chart, true);
        var markerSize = chart.markers[0][chart.selectedMarker].getBBox();
        
        if(chart.options.yIndicator) {
          Util.removeClass(chart.interLine, 'is-hidden');
          chart.interLine.setAttribute('transform', 'translate('+(markerSize.x + markerSize.width/2)+' 0)');
        }
        
        if(chart.tooltipOn) {
          Util.removeClass(chart.tooltip, 'is-hidden');
          setTooltipHTML(chart);
          placeTooltip(chart);
        }
      }
      updateExternalData(chart);
      chart.hovering = false;
    };
  
    function getSelectedMarker(chart, event) {
      if(chart.markers[0].length < 1) return false;
      var clientX = event.detail.x ? event.detail.x : event.clientX;
      var xposition =  clientX - chart.svg.getBoundingClientRect().left;
      var marker = 0,
        deltaX = Math.abs(chart.markers[0][0].getBBox().x - xposition);
      for(var i = 1; i < chart.markers[0].length; i++) {
        var newDeltaX = Math.abs(chart.markers[0][i].getBBox().x - xposition);
        if(newDeltaX < deltaX) {
          deltaX = newDeltaX;
          marker = i;
        }
      }
      return marker;
    };
  
    function resetTooltip(chart) {
      if(chart.hoverId) {
        (window.requestAnimationFrame) ? window.cancelAnimationFrame(chart.hoverId) : clearTimeout(chart.hoverId);
        chart.hoverId = false;
      }
      if(chart.tooltipOn) Util.addClass(chart.tooltip, 'is-hidden');
      if(chart.options.yIndicator)Util.addClass(chart.interLine, 'is-hidden');
      resetMarkers(chart, false);
      resetBars(chart, false);
      chart.selectedMarker = false;
      resetExternalData(chart);
      chart.hovering = false;
    };
  
    function resetMarkers(chart, bool) {
      for(var i = 0; i < chart.markers.length; i++) {
        if(chart.markers[i] && chart.markers[i][chart.selectedMarker]) Util.toggleClass(chart.markers[i][chart.selectedMarker], chart.selectedMarkerClass, bool);
      }
    };
  
    function resetBars(chart, bool) {
      // for column/bar chart -> change opacity on hover
      if(!chart.options.type || chart.options.type != 'column') return;
      for(var i = 0; i < chart.bars.length; i++) {
        if(chart.bars[i] && chart.bars[i][chart.selectedMarker]) Util.toggleClass(chart.bars[i][chart.selectedMarker], chart.selectedBarClass, bool);
      }
    };
  
    function setTooltipHTML(chart) {
      var selectedMarker = chart.markers[0][chart.selectedMarker];
      chart.tooltip.innerHTML = getTooltipHTML(chart, selectedMarker.getAttribute('data-index'), selectedMarker.getAttribute('data-set'));
    };
  
    function getTooltipHTML(chart, index, setIndex) {
      var htmlContent = '';
      if(chart.options.tooltip.customHTML) {
        htmlContent = chart.options.tooltip.customHTML(index, chart.options, setIndex);
      } else {
        var multiVal = chart.options.datasets[setIndex].data[index].length > 1;
        if(chart.options.xAxis && chart.options.xAxis.labels && chart.options.xAxis.labels.length > 1) {
          htmlContent = chart.options.xAxis.labels[index] +' - ';
        } else if(multiVal) {
          htmlContent = chart.options.datasets[setIndex].data[index][0] +' - ';
        }
        htmlContent = (multiVal) 
          ? htmlContent + chart.options.datasets[setIndex].data[index][1] 
          : htmlContent + chart.options.datasets[setIndex].data[index];
      }   
      return htmlContent;
    };
  
    function placeTooltip(chart) {
      var selectedMarker = chart.markers[0][chart.selectedMarker];
      var markerPosition = selectedMarker.getBoundingClientRect();
      var markerPositionSVG = selectedMarker.getBBox();
      var svgPosition = chart.svg.getBoundingClientRect();
  
      if(chart.options.type == 'column') {
        tooltipPositionColumnChart(chart, selectedMarker, markerPosition, markerPositionSVG);
      } else {
        tooltipPositionChart(chart, markerPosition, markerPositionSVG, svgPosition.left, svgPosition.width);
      }
    };
  
    function tooltipPositionChart(chart, markerPosition, markerPositionSVG, svgPositionLeft, svgPositionWidth) {
      // set top/left/transform of the tooltip for line/area charts
      // horizontal position
      if(markerPosition.left - svgPositionLeft <= svgPositionWidth/2) {
        chart.tooltip.style.left = (markerPositionSVG.x + markerPositionSVG.width + 2)+'px';
        chart.tooltip.style.right = 'auto';
        chart.tooltip.style.transform = 'translateY(-100%)';
      } else {
        chart.tooltip.style.left = 'auto';
        chart.tooltip.style.right = (svgPositionWidth - markerPositionSVG.x + 2)+'px';
        chart.tooltip.style.transform = 'translateY(-100%)'; 
      }
      // vertical position
      if(!chart.tooltipPosition) {
        chart.tooltip.style.top = markerPositionSVG.y +'px';
      } else if(chart.tooltipPosition == 'top') {
        chart.tooltip.style.top = (chart.topDelta + chart.tooltip.getBoundingClientRect().height + 5) +'px';
        chart.tooltip.style.bottom = 'auto';
      } else {
        chart.tooltip.style.top = 'auto';
        chart.tooltip.style.bottom = (chart.bottomDelta + 5)+'px';
        chart.tooltip.style.transform = ''; 
      }
    };
  
    function tooltipPositionColumnChart(chart, marker, markerPosition, markerPositionSVG) {
      // set top/left/transform of the tooltip for column charts
      chart.tooltip.style.left = (markerPositionSVG.x + markerPosition.width/2)+'px';
      chart.tooltip.style.right = 'auto';
      chart.tooltip.style.transform = 'translateX(-50%) translateY(-100%)';
      if(!chart.tooltipPosition) {
        if(parseInt(marker.getAttribute('cy')) > chart.yZero) {
          // negative value -> move tooltip below the bar
          chart.tooltip.style.top = (markerPositionSVG.y + markerPositionSVG.height + 6) +'px';
          chart.tooltip.style.transform = 'translateX(-50%)';
        } else {
          chart.tooltip.style.top = (markerPositionSVG.y - 6) +'px';
        }
      } else if(chart.tooltipPosition == 'top') {
        chart.tooltip.style.top = (chart.topDelta + chart.tooltip.getBoundingClientRect().height + 5) +'px';
        chart.tooltip.style.bottom = 'auto';
      } else {
        chart.tooltip.style.bottom = (chart.bottomDelta + 5)+'px';
        chart.tooltip.style.top = 'auto';
        chart.tooltip.style.transform = 'translateX(-50%)';
      }
    };
  
    function animateChart(chart) {
      if(!chart.options.animate) return;
      var observer = new IntersectionObserver(chartObserve.bind(chart), {rootMargin: "0px 0px -200px 0px"});
      observer.observe(chart.element);
    };
  
    function chartObserve(entries, observer) { // observe chart position -> start animation when inside viewport
      if(entries[0].isIntersecting) {
        triggerChartAnimation(this);
        observer.unobserve(this.element);
      }
    };
  
    function triggerChartAnimation(chart) {
      if(chart.options.type == 'line' || chart.options.type == 'area') {
        animatePath(chart, 'line');
        if(chart.options.type == 'area') animatePath(chart, 'fill');
      } else if(chart.options.type == 'column') {
        animateRectPath(chart, 'column');
      }
    };
  
    function animatePath(chart, type) {
      var currentTime = null,
        duration = 600;
  
      var startArray = chart.datasetScaledFlat,
        finalArray = chart.datasetScaled;
  
      if(type == 'fill') {
        startArray = chart.datasetAreaScaledFlat;
        finalArray = chart.datasetAreaScaled;
      }
          
      var animateSinglePath = function(timestamp){
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        for(var i = 0; i < finalArray.length; i++) {
          var points = [];
          var path = chart.element.getElementsByClassName('js-chart__data-'+type+'--'+(i+1))[0];
          for(var j = 0; j < finalArray[i].length; j++) {
            var val = Math.easeOutQuart(progress, startArray[i][j][1], finalArray[i][j][1]-startArray[i][j][1], duration);
            points[j] = [finalArray[i][j][0], val];
          }
          // get path and animate
          var pathCode = chart.options.smooth ? getSmoothLine(points, type == 'fill') : getStraightLine(points);
          path.setAttribute('d', pathCode);
        }
        if(progress < duration) {
          window.requestAnimationFrame(animateSinglePath);
        }
      };
  
      window.requestAnimationFrame(animateSinglePath);
    };
  
    function resizeChart(chart) {
      window.addEventListener('resize', function() {
        clearTimeout(chart.eventIds['resize']);
        chart.eventIds['resize'] = setTimeout(doneResizing, 300);
      });
  
      function doneResizing() {
        resetChartResize(chart);
        initChart(chart);
      };
    };
  
    function resetChartResize(chart) {
      chart.topDelta = 0;
      chart.bottomDelta = 0;
      chart.leftDelta = 0;
      chart.rightDelta = 0;
      chart.dragging = false;
      // reset event listeners
      if( chart.eventIds && chart.eventIds['hover']) {
        chart.chartArea.removeEventListener('mouseenter', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mousemove', chart.eventIds['hover']);
        chart.chartArea.removeEventListener('mouseleave', chart.eventIds['hover']);
        chart.element.removeEventListener('dragStart', chart.eventIds['hover']);
        chart.element.removeEventListener('dragging', chart.eventIds['hover']);
        chart.element.removeEventListener('dragEnd', chart.eventIds['hover']);
      }
    };
  
    function handleEvent(event) {
  		switch(event.type) {
  			case 'mouseenter':
  				hoverChart(this, event);
          break;
  			case 'mousemove':
        case 'dragging':   
          var self = this;
  				self.hoverId  = window.requestAnimationFrame 
            ? window.requestAnimationFrame(function(){hoverChart(self, event)})
            : setTimeout(function(){hoverChart(self, event);});
          break;
  			case 'mouseleave':
        case 'dragEnd':
  				resetTooltip(this);
          break;
  		}
    };
  
    function isVisible(item) {
      return (item && item.getClientRects().length > 0);
    };
  
    function initExternalData(chart) {
      if(!chart.options.externalData) return;
      var chartId = chart.options.element.getAttribute('id');
      if(!chartId) return;
      chart.extDataX = [];
      chart.extDataXInit = [];
      chart.extDataY = [];
      chart.extDataYInit = [];
      if(chart.options.datasets.length > 1) {
        for(var i = 0; i < chart.options.datasets.length; i++) {
          chart.extDataX[i] = document.querySelectorAll('.js-ext-chart-data-x--'+(i+1)+'[data-chart="'+chartId+'"]');
          chart.extDataY[i] = document.querySelectorAll('.js-ext-chart-data-y--'+(i+1)+'[data-chart="'+chartId+'"]');
        }
      } else {
        chart.extDataX[0] = document.querySelectorAll('.js-ext-chart-data-x[data-chart="'+chartId+'"]');
        chart.extDataY[0] = document.querySelectorAll('.js-ext-chart-data-y[data-chart="'+chartId+'"]');
      }
      // store initial HTML contentent
      storeExternalDataContent(chart, chart.extDataX, chart.extDataXInit);
      storeExternalDataContent(chart, chart.extDataY, chart.extDataYInit);
    };
  
    function storeExternalDataContent(chart, elements, array) {
      for(var i = 0; i < elements.length; i++) {
        array[i] = [];
        if(elements[i][0]) array[i][0] = elements[i][0].innerHTML;
      }
    };
  
    function updateExternalData(chart) {
      if(!chart.extDataX || !chart.extDataY) return;
      var marker = chart.markers[0][chart.selectedMarker];
      if(!marker) return;
      var dataIndex = marker.getAttribute('data-index');
      var multiVal = chart.options.datasets[0].data[0].length > 1;
      for(var i = 0; i < chart.options.datasets.length; i++) {
        updateExternalDataX(chart, dataIndex, i, multiVal);
        updateExternalDataY(chart, dataIndex, i, multiVal);
      }
    };
  
    function updateExternalDataX(chart, dataIndex, setIndex, multiVal) {
      if( !chart.extDataX[setIndex] || !chart.extDataX[setIndex][0]) return;
      var value = '';
      if(chart.options.externalData.customXHTML) {
        value = chart.options.externalData.customXHTML(dataIndex, chart.options, setIndex);
      } else {
        if(chart.options.xAxis && chart.options.xAxis.labels && chart.options.xAxis.labels.length > 1) {
          value = chart.options.xAxis.labels[dataIndex];
        } else if(multiVal) {
          htmlContent = chart.options.datasets[setIndex].data[dataIndex][0];
        }
      }
      chart.extDataX[setIndex][0].innerHTML = value;
    };
  
    function updateExternalDataY(chart, dataIndex, setIndex, multiVal) {
      if( !chart.extDataY[setIndex] || !chart.extDataY[setIndex][0]) return;
      var value = '';
      if(chart.options.externalData.customYHTML) {
        value = chart.options.externalData.customYHTML(dataIndex, chart.options, setIndex);
      } else {
        if(multiVal) {
          value = chart.options.datasets[setIndex].data[dataIndex][1];
        } else {
          value = chart.options.datasets[setIndex].data[dataIndex];
        }
      }
      chart.extDataY[setIndex][0].innerHTML = value;
    };
  
    function resetExternalData(chart) {
      if(!chart.options.externalData) return;
      for(var i = 0; i < chart.options.datasets.length; i++) {
        if(chart.extDataX[i][0]) chart.extDataX[i][0].innerHTML = chart.extDataXInit[i][0];
        if(chart.extDataY[i][0]) chart.extDataY[i][0].innerHTML = chart.extDataYInit[i][0];
      }
    };
  
    function setChartColumnSize(chart) {
      chart.columnWidthPerc = 100;
      chart.columnGap = 0;
      if(chart.options.column && chart.options.column.width) {
        chart.columnWidthPerc = parseInt(chart.options.column.width);
      }
      if(chart.options.column && chart.options.column.gap) {
        chart.columnGap = parseInt(chart.options.column.gap);
      } 
    };
  
    function resetColumnChart(chart) {
      var labels = chart.element.getElementsByClassName('js-chart__axis-labels--x')[0].querySelectorAll('.js-chart__axis-label'),
        labelsVisible = isVisible(labels[labels.length - 1]),
        xDelta = chart.xAxisWidth/labels.length;
      
      // translate x axis labels
      if(labelsVisible) {
        moveXAxisLabels(chart, labels, 0.5*xDelta);
      }
      // set column width + separation gap between columns
      var columnsSpace = xDelta*chart.columnWidthPerc/100;
      if(chart.options.stacked) {
        chart.columnWidth = columnsSpace;
      } else {
        chart.columnWidth = (columnsSpace - chart.columnGap*(chart.options.datasets.length - 1) )/chart.options.datasets.length;
      }
  
      chart.columnDelta = (xDelta - columnsSpace)/2;
    };
  
    function moveXAxisLabels(chart, labels, delta) { 
      // this applies to column charts only
      // translate the xlabels to center them 
      if(chart.xAxisLabelRotation) return; // labels were rotated - no need to translate
      for(var i = 0; i < labels.length; i++) {
        Util.setAttributes(labels[i], {x: labels[i].getBBox().x + delta});
      }
    };
  
    function setColumnChartDatasets(chart) {
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
      gEl.setAttribute('class', 'chart__dataset js-chart__dataset');
      chart.datasetScaled = [];
  
      setColumnChartYZero(chart);
      
      for(var i = 0; i < chart.options.datasets.length; i++) {
        var gSet = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        gSet.setAttribute('class', 'chart__set chart__set--'+(i+1)+' js-chart__set');
        chart.datasetScaled[i] = JSON.parse(JSON.stringify(chart.options.datasets[i].data));
        chart.datasetScaled[i] = getChartData(chart, chart.datasetScaled[i]);
        chart.datasetScaledFlat[i] = JSON.parse(JSON.stringify(chart.datasetScaled[i]));
        if(!chart.loaded && chart.options.animate) {
          flatDatasets(chart, i);
        }
        gSet.appendChild(getSvgColumns(chart, chart.datasetScaledFlat[i], i));
        gEl.appendChild(gSet);
        gSet.appendChild(getMarkers(chart, chart.datasetScaled[i], i));
      }
      
      chart.svg.appendChild(gEl);
    };
  
    function setColumnChartYZero(chart) {
      // if there are negative values -> make sre columns start from zero
      chart.yZero = chart.height - chart.bottomDelta;
      if(chart.yAxisInterval[0] < 0) {
        chart.yZero = chart.height - chart.bottomDelta + chart.yAxisHeight*(chart.yAxisInterval[0])/(chart.yAxisInterval[1] - chart.yAxisInterval[0]);
      }
    };
  
    function getSvgColumns(chart, dataset, index) {
      var gEl = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  
      for(var i = 0; i < dataset.length; i++) {
        var pathL = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        var points = getColumnPoints(chart, dataset[i], index, i, chart.datasetScaledFlat);
        var lineType =  chart.options.column && chart.options.column.radius ? 'round' : 'square';
        if(lineType == 'round' && chart.options.stacked && index < chart.options.datasets.length - 1) lineType = 'square';
        var dPath = (lineType == 'round') ? getRoundedColumnRect(chart, points) : getStraightLine(points);
        Util.setAttributes(pathL, {d: dPath, class: 'chart__data-bar chart__data-bar--'+(index+1)+' js-chart__data-bar js-chart__data-bar--'+(index+1)});
        gEl.appendChild(pathL);
      }
      return gEl;
    };
  
    function getColumnPoints(chart, point, index, pointIndex, dataSetsAll) {
      var xOffset = chart.columnDelta + index*(chart.columnWidth + chart.columnGap),
        yOffset = 0;
  
      if(chart.options.stacked) {
        xOffset = chart.columnDelta;
        yOffset = getyOffsetColChart(chart, dataSetsAll, index, pointIndex);
      }
  
      return [ 
        [point[0] + xOffset, chart.yZero - yOffset],
        [point[0] + xOffset, point[1] - yOffset], 
        [point[0] + xOffset + chart.columnWidth, point[1] - yOffset],
        [point[0] + xOffset + chart.columnWidth, chart.yZero - yOffset]
      ];
    };
  
    function getyOffsetColChart(chart, dataSetsAll, index, pointIndex) {
      var offset = 0;
      for(var i = 0; i < index; i++) {
        if(dataSetsAll[i] && dataSetsAll[i][pointIndex]) offset = offset + (chart.height - chart.bottomDelta - dataSetsAll[i][pointIndex][1]);
      }
      return offset;
    };
  
    function getRoundedColumnRect(chart, points) {
      var radius = parseInt(chart.options.column.radius);
      var arcType = '0,0,1',
        deltaArc1 = '-',
        deltaArc2 = ',',
        rectHeight = points[1][1] + radius;
      if(chart.yAxisInterval[0] < 0 && points[1][1] > chart.yZero) {
        arcType = '0,0,0';
        deltaArc1 = ',';
        deltaArc2 = '-';
        rectHeight = points[1][1] - radius;
      }
      var dpath = 'M '+points[0][0]+' '+points[0][1];
      dpath = dpath + ' V '+rectHeight;
      dpath = dpath + ' a '+radius+','+radius+','+arcType+','+radius+deltaArc1+radius;
      dpath = dpath + ' H '+(points[2][0] - radius);
      dpath = dpath + ' a '+radius+','+radius+','+arcType+','+radius+deltaArc2+radius;
      dpath = dpath + ' V '+points[3][1];
      return dpath;
    };
  
    function animateRectPath(chart, type) {
      var currentTime = null,
        duration = 600;
  
      var startArray = chart.datasetScaledFlat,
        finalArray = chart.datasetScaled;
          
      var animateSingleRectPath = function(timestamp){
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        var multiSetPoint = [];
        for(var i = 0; i < finalArray.length; i++) {
          // multi sets
          var points = [];
          var paths = chart.element.getElementsByClassName('js-chart__data-bar--'+(i+1));
          var rectLine = chart.options.column && chart.options.column.radius ? 'round' : 'square';
          if(chart.options.stacked && rectLine == 'round' && i < finalArray.length - 1) rectLine = 'square'; 
          for(var j = 0; j < finalArray[i].length; j++) {
            var val = Math.easeOutQuart(progress, startArray[i][j][1], finalArray[i][j][1]-startArray[i][j][1], duration);
            points[j] = [finalArray[i][j][0], val];
            // get path and animate
            var rectPoints = getColumnPoints(chart, points[j], i, j, multiSetPoint);
            var dPath = (rectLine == 'round') ? getRoundedColumnRect(chart, rectPoints) : getStraightLine(rectPoints);
            paths[j].setAttribute('d', dPath);
          }
  
          multiSetPoint[i] = points;
        }
        if(progress < duration) {
          window.requestAnimationFrame(animateSingleRectPath);
        }
      };
  
      window.requestAnimationFrame(animateSingleRectPath);
    };
  
    function getPieSvgCode(chart) {
  
    };
  
    function getDoughnutSvgCode(chart) {
  
    };
  
    Chart.defaults = {
      element : '',
      type: 'line', // can be line, area, bar
      xAxis: {},
      yAxis: {},
      datasets: [],
      tooltip: {
        enabled: false,
        classes: false,
        customHTM: false
      },
      yIndicator: true,
      padding: 10
    };
  
    window.Chart = Chart;
  
    var intObservSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
  }());
  // File#: _2_checkout-v2
  // Usage: codyhouse.co/license
  (function() {
    // update billing info visibility
    var billingCheckBox = document.getElementsByClassName('js-billing-checkbox');
    if(billingCheckBox.length > 0) {
      var billingInfo = document.getElementsByClassName('js-billing-info');
      if(billingInfo.length == 0) return;
      resetBillingInfo(billingCheckBox[0], billingInfo[0]);
      
      billingCheckBox[0].addEventListener('change', function(){
        resetBillingInfo(billingCheckBox[0], billingInfo[0]);
      });
    }
  
    function resetBillingInfo(input, content) {
      Util.toggleClass(content, 'is-visible', !input.checked);
    };
  }());
  // File#: _2_checkout
  // Usage: codyhouse.co/license
  (function() {
    // update billing info visibility
    var billingCheckBox = document.getElementsByClassName('js-billing-checkbox');
    if(billingCheckBox.length > 0) {
      var billingInfo = document.getElementsByClassName('js-billing-info');
      if(billingInfo.length == 0) return;
      resetBillingInfo(billingCheckBox[0], billingInfo[0]);
      
      billingCheckBox[0].addEventListener('change', function(){
        resetBillingInfo(billingCheckBox[0], billingInfo[0]);
      });
    }
  
    function resetBillingInfo(input, content) {
      Util.toggleClass(content, 'is-visible', !input.checked);
    };
  }());
  // File#: _2_comments
  // Usage: codyhouse.co/license
  (function() {
    function initVote(element) {
      var voteCounter = element.getElementsByClassName('js-comments__vote-label');
      element.addEventListener('click', function(){
        var pressed = element.getAttribute('aria-pressed') == 'true';
        element.setAttribute('aria-pressed', !pressed);
        Util.toggleClass(element, 'comments__vote-btn--pressed', !pressed);
        resetCounter(voteCounter, pressed);
        emitKeypressEvents(element, voteCounter, pressed);
      });
    };
  
    function resetCounter(voteCounter, pressed) { // update counter value (if present)
      if(voteCounter.length == 0) return;
      var count = parseInt(voteCounter[0].textContent);
      voteCounter[0].textContent = pressed ? count - 1 : count + 1;
    };
  
    function emitKeypressEvents(element, label, pressed) { // emit custom event when vote is updated
      var count = (label.length == 0) ? false : parseInt(label[0].textContent);
      var event = new CustomEvent('newVote', {detail: {count: count, upVote: !pressed}});
  		element.dispatchEvent(event);
    };
  
    var voteCounting = document.getElementsByClassName('js-comments__vote-btn');
    if( voteCounting.length > 0 ) {
  		for( var i = 0; i < voteCounting.length; i++) {
  			(function(i){initVote(voteCounting[i]);})(i);
  		}
  	}
  }());
  // File#: _2_content-rating
  // Usage: codyhouse.co/license
  (function() {
    function initRateCont(element) {
      var commentSection = element.getElementsByClassName('js-rate-cont__comment');
      if(commentSection.length == 0) return;
      element.addEventListener('change', function() {
        // show comment input if user selects one of the radio btns
        showComment(commentSection[0]);
      });
    };
  
    function showComment(comment) {
      if(!Util.hasClass(comment, 'is-hidden')) return;
      // reveal comment section
      Util.removeClass(comment, 'is-hidden');
      var initHeight = 0,
  			finalHeight = comment.offsetHeight;
      if(window.requestAnimationFrame && !reducedMotion) {
        Util.setHeight(initHeight, finalHeight, comment, 200, function(){
          // move focus to textarea
          var textArea = comment.querySelector('textarea');
          if(textArea) textArea.focus();
          // remove inline style
          comment.style.height = '';
        }, 'easeInOutQuad');
      }
    };
  
    var rateCont = document.getElementsByClassName('js-rate-cont'),
      reducedMotion = Util.osHasReducedMotion();
    if( rateCont.length > 0 ) {
  		for( var i = 0; i < rateCont.length; i++) {
  			(function(i){initRateCont(rateCont[i]);})(i);
  		}
  	}
  }());
  // File#: _2_copy-to-clip
  // Usage: codyhouse.co/license
  (function() {
    var CopyClipboard = function() {
      this.copyTargetClass = 'js-copy-to-clip';
      this.copyStatusClass = 'copy-to-clip--copied';
      this.resetDelay = 2000; // delay for removing the copy-to-clip--copied class
      initCopyToClipboard(this);
    };
  
    function initCopyToClipboard(element) {
      document.addEventListener('click', function(event) {
        var target = event.target.closest('.'+element.copyTargetClass);
        if(!target) return;
        copyContentToClipboard(element, target);
      });
    };
  
    function copyContentToClipboard(element, target) {
      // copy to clipboard
      navigator.clipboard.writeText(getContentToCopy(target)).then(function() { // content successfully copied
        // add success class to target
        Util.addClass(target, element.copyStatusClass);
  
        setTimeout(function(){ // remove success class from target
          Util.removeClass(target, element.copyStatusClass);
        }, element.resetDelay);
        
        // change tooltip content
        var newTitle = target.getAttribute('data-success-title');
        if(newTitle && newTitle != '') target.dispatchEvent(new CustomEvent("newContent", {detail: newTitle}));
        
        // dispatch success event
        target.dispatchEvent(new CustomEvent("contentCopied"));
      }, function() { // error while copying the code
        // dispatch error event
        target.dispatchEvent(new CustomEvent("contentNotCopied"));
      });
    };
  
    function getContentToCopy(target) {
      var content = target.innerText;
      var ariaControls = document.getElementById(target.getAttribute('aria-controls')),
        defaultText = target.getAttribute('data-clipboard-content');
      if(ariaControls) {
        content = ariaControls.innerText;
      } else if(defaultText && defaultText != '') {
        content = defaultText;
      }
      return content;
    };
  
    window.CopyClipboard = CopyClipboard;
  
    var copyToClipboard = document.getElementsByClassName('js-copy-to-clip');
    if(copyToClipboard.length > 0) {
      new CopyClipboard();
    } 
  }());
  // File#: _2_date-range
  // Usage: codyhouse.co/license
  (function() {
    var DateRange = function(opts) {
      this.options = Util.extend(DatePicker.defaults , opts);
      this.element = this.options.element;
      this.inputStart = this.element.getElementsByClassName('js-date-range__text--start')[0]; // visible to SR only
      this.inputEnd = this.element.getElementsByClassName('js-date-range__text--end')[0]; // visible to SR only
      this.trigger = this.element.getElementsByClassName('js-date-range__trigger')[0];
      this.triggerLabel = this.trigger.getAttribute('aria-label');
      this.datePicker = this.element.getElementsByClassName('js-date-picker')[0];
      this.body = this.datePicker.getElementsByClassName('js-date-picker__dates')[0];
      this.navigation = this.datePicker.getElementsByClassName('js-date-picker__month-nav')[0];
      this.heading = this.datePicker.getElementsByClassName('js-date-picker__month-label')[0];
      this.pickerVisible = false;
      // date format
      this.dateIndexes = getDateIndexes(this); // store indexes of date parts (d, m, y)
      // selected date (star/end)
      this.dateSelected = [];
      this.selectedDay = [];
      this.selectedMonth = [];
      this.selectedYear = [];
      // which date needs to be selected
      this.dateToSelect = 0; // o or start date, 1 for end date
      // focus trap
      this.firstFocusable = false;
      this.lastFocusable = false;
      // trigger btn - start/end values
      this.dateValueStartEl = this.element.getElementsByClassName('js-date-range__value--start');
      this.dateValueEndEl = this.element.getElementsByClassName('js-date-range__value--end');
      if(this.dateValueStartEl.length > 0) {
        this.dateValueStartElLabel = this.dateValueStartEl[0].textContent; // initial input value
      }
      if(this.dateValueEndEl.length > 0) {
        this.dateValueEndElLabel = this.dateValueEndEl[0].textContent; // initial input value
      }
      // trigger btn - label
      this.triggerLabelWrapper = this.trigger.getElementsByClassName('js-date-range__trigger-label');
      // custom classes
      this.selectedStartClass= 'date-picker__date--selected js-date-picker__date--range-start'; // does not include the class to remove borders
      this.selectedEndClass= 'date-picker__date--selected date-picker__date--range-end js-date-picker__date--range-end';
      this.inBetweenClass = 'date-picker__date--range';
      this.mouseMoving = false;
      // predefined options - if there's a select element with a list of predefined options
      this.predefOptions = this.element.previousElementSibling;
      initCalendarAria(this);
      resetCalendar(this);
      resetTriggerLabel(this, true);
      initCalendarEvents(this);
  
      // place picker according to available space
      placeCalendar(this);
  
      // predefined options
      initPredefinedOptions(this);
    };
  
    function initCalendarAria(datePicker) {
      // make input elements accessible
      resetInputVisibility(datePicker.inputStart);
      resetInputVisibility(datePicker.inputEnd);
      // create a live region used to announce new month selection to SR + new date selection
      var srLiveReagion = document.createElement('div');
      srLiveReagion.setAttribute('aria-live', 'polite');
      Util.addClass(srLiveReagion, 'sr-only js-date-range__sr-live');
      datePicker.element.appendChild(srLiveReagion);
      datePicker.srLiveReagionM = datePicker.element.getElementsByClassName('js-date-range__sr-live')[0];
    };
  
    function resetInputVisibility(input) {
      // make sure input elements are accessible to SR but not tabbable
      input.setAttribute('tabindex', '-1');
      var wrapper = input.closest('.js-date-range__input');
      if(wrapper) {
        Util.addClass(wrapper, 'sr-only');
        wrapper.style.display = 'block';
      }
    };
  
    function initCalendarEvents(datePicker) {
      if(datePicker.trigger) {
        datePicker.trigger.addEventListener('click', function(event){ // open calendar when clicking on calendar button
          event.preventDefault();
          datePicker.pickerVisible = false;
          toggleCalendar(datePicker);
          datePicker.trigger.setAttribute('aria-expanded', 'true');
        });
      }
      // navigate using month nav
      datePicker.navigation.addEventListener('click', function(event){
        event.preventDefault();
        var btn = event.target.closest('.js-date-picker__month-nav-btn');
        if(btn) {
          Util.hasClass(btn, 'js-date-picker__month-nav-btn--prev') ? showPrev(datePicker, true) : showNext(datePicker, true);
        }
      });
  
      // hide calendar
      window.addEventListener('keydown', function(event){ // close calendar on esc
        if(event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape') {
          if(!datePicker.pickerVisible) return;
          if(document.activeElement. closest('.js-date-picker')) {
            datePicker.trigger.focus(); //if focus is inside the calendar -> move the focus to the input element 
          } 
          hideCalendar(datePicker);
        }
      });
      window.addEventListener('click', function(event){
        if(!event.target.closest('.js-date-picker') && !event.target.closest('.js-date-range__trigger') && datePicker.pickerVisible) {
          hideCalendar(datePicker);
        }
      });
  
      // navigate through days of calendar
      datePicker.body.addEventListener('keydown', function(event){
        var day = datePicker.currentDay;
        if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
          day = day + 7;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
          day = day + 1;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
          day = day - 1;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
          day = day - 7;
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 35 || event.key && event.key.toLowerCase() == 'end') { // move focus to last day of week
          event.preventDefault();
          day = day + 6 - getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, day);
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 36 || event.key && event.key.toLowerCase() == 'home') { // move focus to first day of week
          event.preventDefault();
          day = day - getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, day);
          resetDayValue(day, datePicker);
        } else if(event.keyCode && event.keyCode == 34 || event.key && event.key.toLowerCase() == 'pagedown') {
          event.preventDefault();
          showNext(datePicker); // show next month
          keyNavigationInBetween(datePicker);
        } else if(event.keyCode && event.keyCode == 33 || event.key && event.key.toLowerCase() == 'pageup') {
          event.preventDefault();
          showPrev(datePicker); // show prev month
          keyNavigationInBetween(datePicker);
        }
      });
  
      // trap focus inside calendar
      datePicker.datePicker.addEventListener('keydown', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
          //trap focus inside modal
          trapFocus(event, datePicker);
        }
      });
  
      // select a date inside the date picker
      datePicker.body.addEventListener('click', function(event){
        event.preventDefault();
        var day = event.target.closest('button');
        if(day) {
          if(datePicker.dateToSelect == 1 && dateIsBeforeStart(datePicker, day)) {
            // if this is end date -> make sure it is after start date, otherwise use as start date
            datePicker.dateToSelect = 0;
          }
          datePicker.dateSelected[datePicker.dateToSelect] = true;
          datePicker.selectedDay[datePicker.dateToSelect] = parseInt(day.innerText);
          datePicker.selectedMonth[datePicker.dateToSelect] = datePicker.currentMonth;
          datePicker.selectedYear[datePicker.dateToSelect] = datePicker.currentYear;
  
          if(datePicker.dateToSelect == 0) {
            setInputStartValue(datePicker);
            datePicker.dateToSelect = 1;
            startDateSelected(datePicker, day);
          } else {
            setInputEndValue(datePicker);
            datePicker.dateToSelect = 0;
            // close date picker
            hideCalendar(datePicker);
          }
          resetLabelCalendarTrigger(datePicker);
          resetLabelCalendarValue(datePicker);
          resetAriaLive(datePicker);
        }
      });
  
      // on mouse move, highlight the elements between start and end date
      datePicker.body.addEventListener('mousemove', function(event){
        var button = event.target.closest('.js-date-picker__date');
        if(!button || !datePicker.dateSelected[0] || datePicker.dateSelected[1]) return;
        showInBetweenElements(datePicker, button);
      });
  
      datePicker.body.addEventListener('mouseleave', function(event){
        if(!datePicker.dateSelected[1]) {
          // end date has not been selected -> remove the inBetween classes
          removeInBetweenClass(datePicker);
          resetStarDateAppearance(datePicker);
        }
      });
  
      // input events - for SR only
      datePicker.inputStart.addEventListener('focusout', function(event){
        resetCalendarFromInput(datePicker, datePicker.inputStart);
      });
      datePicker.inputEnd.addEventListener('focusout', function(event){
        resetCalendarFromInput(datePicker, datePicker.inputEnd);
      });
    };
  
    function dateIsBeforeStart(datePicker, day) { // do not allow end date < start date
      var selectedDate = [datePicker.currentYear, datePicker.currentMonth, parseInt(day.textContent)],
        startDate = [datePicker.selectedYear[0], datePicker.selectedMonth[0], datePicker.selectedDay[0]];
      return isPast(selectedDate, startDate);
    };
  
    function startDateSelected(datePicker, day) { // new start date has been selected
      datePicker.dateSelected[1] = false;
      datePicker.selectedDay[1] = false;
      datePicker.selectedMonth[1] = false;
      datePicker.selectedYear[1] = false;
      // reset input
      datePicker.inputEnd.value = '';
      // remove class from selected element -> if there was one
      var startDate = datePicker.element.getElementsByClassName('js-date-picker__date--range-start');
      if(startDate.length > 0) {
        Util.removeClass(startDate[0], datePicker.selectedStartClass + ' date-picker__date--range-start');
      }
      var endDate = datePicker.element.getElementsByClassName('js-date-picker__date--range-end');
      if(endDate.length > 0) {
        Util.removeClass(endDate[0], datePicker.selectedEndClass);
      }
      removeInBetweenClass(datePicker);
      // add classes to selected date
      Util.addClass(day, datePicker.selectedStartClass);
    };
  
    function resetCalendarFromInput(datePicker, input) {
      // reset calendar when input field is updated (SR only)
      var inputDate = getDateFromInput(datePicker, input.value);
      if(!inputDate) {
        input.value = '';
        return;
      }
      if (isNaN(new Date(inputDate).getTime())) {
        input.value = '';
        return;
      }
      resetCalendar(datePicker);
    };
  
    function resetCalendar(datePicker) {
      // new date has been selected -> reset calendar appearance
      resetSingleDate(datePicker, 0);
      resetSingleDate(datePicker, 1);
      // reset aria
      resetLabelCalendarTrigger(datePicker);
      resetLabelCalendarValue(datePicker);
      resetAriaLive(datePicker);
    };
  
    function resetSingleDate(datePicker, index) {
      // set current date + selected date (index == 0 ? startDate : endDate)
      var currentDate = false,
        selectedDate = (index == 0 ) ? datePicker.inputStart.value : datePicker.inputEnd.value;
  
      datePicker.dateSelected[index] = false;
      if( selectedDate != '') {
        var date = getDateFromInput(datePicker, selectedDate);
        datePicker.dateSelected[index] = true;
        currentDate = date;
      } 
      if( index == 0 ) {
        datePicker.currentDay = getCurrentDay(currentDate);
        datePicker.currentMonth = getCurrentMonth(currentDate); 
        datePicker.currentYear = getCurrentYear(currentDate); 
      }
      
      datePicker.selectedDay[index] = datePicker.dateSelected[index] ? getCurrentDay(currentDate) : false;
      datePicker.selectedMonth[index] = datePicker.dateSelected[index] ? getCurrentMonth(currentDate) : false;
      datePicker.selectedYear[index] = datePicker.dateSelected[index] ? getCurrentYear(currentDate) : false;
    };
  
    function getCurrentDay(date) {
      return (date) 
        ? getDayFromDate(date)
        : new Date().getDate();
    };
  
    function getCurrentMonth(date) {
      return (date) 
        ? getMonthFromDate(date)
        : new Date().getMonth();
    };
  
    function getCurrentYear(date) {
      return (date) 
        ? getYearFromDate(date)
        : new Date().getFullYear();
    };
  
    function getDayFromDate(date) {
      var day = parseInt(date.split('-')[2]);
      return isNaN(day) ? getCurrentDay(false) : day;
    };
  
    function getMonthFromDate(date) {
      var month = parseInt(date.split('-')[1]) - 1;
      return isNaN(month) ? getCurrentMonth(false) : month;
    };
  
    function getYearFromDate(date) {
      var year = parseInt(date.split('-')[0]);
      return isNaN(year) ? getCurrentYear(false) : year;
    };
  
    function showNext(datePicker, bool) {
      // show next month
      datePicker.currentYear = (datePicker.currentMonth === 11) ? datePicker.currentYear + 1 : datePicker.currentYear;
      datePicker.currentMonth = (datePicker.currentMonth + 1) % 12;
      datePicker.currentDay = checkDayInMonth(datePicker);
      showCalendar(datePicker, bool);
      datePicker.srLiveReagionM.textContent = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
    };
  
    function showPrev(datePicker, bool) {
      // show prev month
      datePicker.currentYear = (datePicker.currentMonth === 0) ? datePicker.currentYear - 1 : datePicker.currentYear;
      datePicker.currentMonth = (datePicker.currentMonth === 0) ? 11 : datePicker.currentMonth - 1;
      datePicker.currentDay = checkDayInMonth(datePicker);
      showCalendar(datePicker, bool);
      datePicker.srLiveReagionM.textContent = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
    };
  
    function checkDayInMonth(datePicker) {
      return (datePicker.currentDay > daysInMonth(datePicker.currentYear, datePicker.currentMonth)) ? 1 : datePicker.currentDay;
    };
  
    function daysInMonth(year, month) {
      return 32 - new Date(year, month, 32).getDate();
    };
  
    function showCalendar(datePicker, bool) {
      // show calendar element
      var firstDay = getDayOfWeek(datePicker.currentYear, datePicker.currentMonth, '01');
      datePicker.body.innerHTML = '';
      datePicker.heading.innerHTML = datePicker.options.months[datePicker.currentMonth] + ' ' + datePicker.currentYear;
  
      // creating all cells
      var date = 1,
        calendar = '';
      for (var i = 0; i < 6; i++) {
        for (var j = 0; j < 7; j++) {
          if (i === 0 && j < firstDay) {
            calendar = calendar + '<li></li>';
          } else if (date > daysInMonth(datePicker.currentYear, datePicker.currentMonth)) {
            break;
          } else {
            var classListDate = '',
              tabindexValue = '-1';
            if (date === datePicker.currentDay) {
              tabindexValue = '0';
            } 
            if(!datePicker.dateSelected[0] && !datePicker.dateSelected[1] && getCurrentMonth() == datePicker.currentMonth && getCurrentYear() == datePicker.currentYear && date == getCurrentDay()){
              classListDate = classListDate+' date-picker__date--today'
            }
            if (datePicker.dateSelected[0] && date === datePicker.selectedDay[0] && datePicker.currentYear === datePicker.selectedYear[0] && datePicker.currentMonth === datePicker.selectedMonth[0]) {
              classListDate = classListDate+'  '+datePicker.selectedStartClass;
            }
            if (datePicker.dateSelected[1] && date === datePicker.selectedDay[1] && datePicker.currentYear === datePicker.selectedYear[1] && datePicker.currentMonth === datePicker.selectedMonth[1]) {
              classListDate = classListDate+'  '+datePicker.selectedEndClass;
            }
            calendar = calendar + '<li><button class="date-picker__date'+classListDate+' js-date-picker__date" tabindex="'+tabindexValue+'">'+date+'</button></li>';
            date++;
          }
        }
      }
      datePicker.body.innerHTML = calendar; // appending days into calendar body
      
      // show calendar
      if(!datePicker.pickerVisible) Util.addClass(datePicker.datePicker, 'date-picker--is-visible');
      datePicker.pickerVisible = true;
  
      //  if bool is false, move focus to calendar day
      if(!bool) datePicker.body.querySelector('button[tabindex="0"]').focus();
  
      // store first/last focusable elements
      getFocusableElements(datePicker);
      // set inBetween elements
      if(datePicker.dateSelected[1]) {
        var endDate = datePicker.element.getElementsByClassName('js-date-picker__date--range-end');
        if(endDate.length > 0) {
          resetInBetweenElements(datePicker, endDate[0]);
        } else if(monthIsBetween(datePicker)) {
          // end date has been set but it is in another month
          // if we are in a previous month -- reset in between days
          var dates = datePicker.element.getElementsByClassName('js-date-picker__date');
          resetInBetweenElements(datePicker, dates[dates.length - 1]);
        }
      }
      // reset trigger label
      resetTriggerLabel(datePicker, true);
    };
  
    function resetTriggerLabel(datePicker, bool) {
      if(datePicker.triggerLabelWrapper.length < 1) return;
      if(datePicker.triggerLabelWrapper[0].children.length < 2) return;
  
      if(bool) {
        Util.addClass(datePicker.triggerLabelWrapper[0].children[0], 'is-hidden');
        Util.removeClass(datePicker.triggerLabelWrapper[0].children[1], 'is-hidden');
        // place calendar
        placeCalendar(datePicker);
      } else if( !datePicker.dateSelected[0] && !datePicker.dateSelected[1]) {
        Util.addClass(datePicker.triggerLabelWrapper[0].children[1], 'is-hidden');
        Util.removeClass(datePicker.triggerLabelWrapper[0].children[0], 'is-hidden');
      }
    };
  
    function hideCalendar(datePicker) {
      Util.removeClass(datePicker.datePicker, 'date-picker--is-visible');
      datePicker.pickerVisible = false;
  
      // reset first/last focusable
      datePicker.firstFocusable = false;
      datePicker.lastFocusable = false;
  
      // reset trigger aria-expanded attribute
      if(datePicker.trigger) datePicker.trigger.setAttribute('aria-expanded', 'false');
  
      // update focus if required
      if(document.activeElement.closest('.js-date-picker')) datePicker.trigger.focus();
  
      // reset trigger label
      resetTriggerLabel(datePicker, false);
    };
  
    function toggleCalendar(datePicker, bool) {
      if(!datePicker.pickerVisible) {
        resetCalendar(datePicker);
        showCalendar(datePicker, bool);
      } else {
        hideCalendar(datePicker);
      }
    };
  
    function getDayOfWeek(year, month, day) {
      var weekDay = (new Date(year, month, day)).getDay() - 1;
      if(weekDay < 0) weekDay = 6;
      return weekDay;
    };
  
    function getDateIndexes(datePicker) {
      var dateFormat = datePicker.options.dateFormat.toLowerCase().replace(/-/g, '');
      return [dateFormat.indexOf('d'), dateFormat.indexOf('m'), dateFormat.indexOf('y')];
    };
  
    function setInputStartValue(datePicker) {
      datePicker.inputStart.value = getDateForInput(datePicker, 0);
    };
  
    function setInputEndValue(datePicker) {
      datePicker.inputEnd.value = getDateForInput(datePicker, 1);
    };
  
    function getDateForInput(datePicker, index) {
      // index is 0 for start date, 1 for end date
      var dateArray = [];
      dateArray[datePicker.dateIndexes[0]] = getReadableDate(datePicker.selectedDay[index]);
      dateArray[datePicker.dateIndexes[1]] = getReadableDate(datePicker.selectedMonth[index]+1);
      dateArray[datePicker.dateIndexes[2]] = datePicker.selectedYear[index];
      return dateArray[0]+datePicker.options.dateSeparator+dateArray[1]+datePicker.options.dateSeparator+dateArray[2];
    };
  
    function getDateFromInput(datePicker, input) {
      var dateArray = input.split(datePicker.options.dateSeparator);
      if(dateArray.length < 3) return false;
      return dateArray[datePicker.dateIndexes[2]]+'-'+dateArray[datePicker.dateIndexes[1]]+'-'+dateArray[datePicker.dateIndexes[0]];
    };
  
    function getReadableDate(date) {
      return (date < 10) ? '0'+date : date;
    };
  
    function resetDayValue(day, datePicker) {
      var totDays = daysInMonth(datePicker.currentYear, datePicker.currentMonth);
      if( day > totDays) {
        datePicker.currentDay = day - totDays;
        showNext(datePicker, false);
        keyNavigationInBetween(datePicker);
      } else if(day < 1) {
        var newMonth = datePicker.currentMonth == 0 ? 11 : datePicker.currentMonth - 1;
        datePicker.currentDay = daysInMonth(datePicker.currentYear, newMonth) + day;
        showPrev(datePicker, false);
        keyNavigationInBetween(datePicker);
      } else {
        datePicker.currentDay = day;
        datePicker.body.querySelector('button[tabindex="0"]').setAttribute('tabindex', '-1');
        // set new tabindex to selected item
        var buttons = datePicker.body.getElementsByTagName("button");
        for (var i = 0; i < buttons.length; i++) {
          if (buttons[i].textContent == datePicker.currentDay) {
            buttons[i].setAttribute('tabindex', '0');
            buttons[i].focus();
            break;
          }
        }
        getFocusableElements(datePicker); // update first focusable/last focusable element
        // reset inBetween dates
        keyNavigationInBetween(datePicker);
      }
    };
  
    function getFocusableElements(datePicker) {
      var allFocusable = datePicker.datePicker.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
      getFirstFocusable(allFocusable, datePicker);
      getLastFocusable(allFocusable, datePicker);
    };
  
    function getFirstFocusable(elements, datePicker) {
      for(var i = 0; i < elements.length; i++) {
  			if( (elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length) &&  elements[i].getAttribute('tabindex') != '-1') {
  				datePicker.firstFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function getLastFocusable(elements, datePicker) {
      //get last visible focusable element inside the modal
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( (elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length) &&  elements[i].getAttribute('tabindex') != '-1' ) {
  				datePicker.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function trapFocus(event, datePicker) {
      if( datePicker.firstFocusable == document.activeElement && event.shiftKey) {
  			//on Shift+Tab -> focus last focusable element when focus moves out of calendar
  			event.preventDefault();
  			datePicker.lastFocusable.focus();
  		}
  		if( datePicker.lastFocusable == document.activeElement && !event.shiftKey) {
  			//on Tab -> focus first focusable element when focus moves out of calendar
  			event.preventDefault();
  			datePicker.firstFocusable.focus();
  		}
    };
  
    function resetLabelCalendarTrigger(datePicker) {
      // for SR only - update trigger aria-label to include selected dates
      if(!datePicker.trigger) return;
      var label = '';
      if(datePicker.selectedYear[0] && datePicker.selectedMonth[0] && datePicker.selectedDay[0]) {
        label = label + ', start date selected is '+ new Date(datePicker.selectedYear[0], datePicker.selectedMonth[0], datePicker.selectedDay[0]).toDateString();
      }
      if(datePicker.selectedYear[1] && datePicker.selectedMonth[1] && datePicker.selectedDay[1]) {
        label = label + ', end date selected is '+ new Date(datePicker.selectedYear[1], datePicker.selectedMonth[1], datePicker.selectedDay[1]).toDateString();
      }
  
      datePicker.trigger.setAttribute('aria-label', datePicker.triggerLabel+label);
    };
    
    function resetLabelCalendarValue(datePicker) {
      // trigger visible label - update value with selected dates
      if(datePicker.dateValueStartEl.length > 0) {
        resetLabel(datePicker, 0, datePicker.dateValueStartEl[0], datePicker.dateValueStartElLabel);
      }
      if(datePicker.dateValueEndEl.length > 0) {
        resetLabel(datePicker, 1, datePicker.dateValueEndEl[0], datePicker.dateValueEndElLabel);
      }
    };
  
    function resetLabel(datePicker, index, input, initialLabel) {
      (datePicker.selectedYear[index] && datePicker.selectedMonth[index] !== false && datePicker.selectedDay[index]) 
        ? input.textContent = getDateForInput(datePicker, index)
        : input.textContent = initialLabel;
    };
  
    function resetAriaLive(datePicker) { 
      // SR only - update an aria live region to announce the date that has just been selected
      var content = false;
      if(datePicker.dateSelected[0] && !datePicker.dateSelected[1]) {
        // end date has been selected -> notify users
        content = 'Start date selected is '+ new Date(datePicker.selectedYear[0], datePicker.selectedMonth[0], datePicker.selectedDay[0]).toDateString()+', select end date';
      }
      if(content) datePicker.srLiveReagionM.textContent = content;
    };
  
    function showInBetweenElements(datePicker, button) {
      // this function is used to add style to elements when the start date has been selected, and user is moving to select end date
      if(datePicker.mouseMoving) return;
      datePicker.mouseMoving = true;
      window.requestAnimationFrame(function(){
        removeInBetweenClass(datePicker);
        resetInBetweenElements(datePicker, button);
        resetStarDateAppearance(datePicker);
        datePicker.mouseMoving = false;
      });
    };
  
    function resetInBetweenElements(datePicker, endDate) {
      if(!endDate) return;
      // check if date is older than the start date -> do not add the --range class
      if(isPast([datePicker.currentYear, datePicker.currentMonth, parseInt(endDate.textContent)], [datePicker.selectedYear[0], datePicker.selectedMonth[0], datePicker.selectedDay[0]])) return
      if(Util.hasClass(endDate, 'js-date-picker__date--range-start')) {
        Util.addClass(endDate, 'date-picker__date--range-start');
        return;
      } else if(!Util.hasClass(endDate, 'js-date-picker__date--range-end')) {
        Util.addClass(endDate, datePicker.inBetweenClass);
      }
      var prevDay = endDate.closest('li').previousElementSibling;
      if(!prevDay) return;
      var date = prevDay.querySelector('button');
      if(!date) return;
      resetInBetweenElements(datePicker, date);
    };
  
    function removeInBetweenClass(datePicker) {
      var inBetweenDates = datePicker.element.getElementsByClassName(datePicker.inBetweenClass);
      while(inBetweenDates[0]) {
        Util.removeClass(inBetweenDates[0], datePicker.inBetweenClass);
      }
    };
  
    function monthIsBetween(datePicker) {
      var beforeEndDate = false;
      var afterStartDate = false;
      // check before end date
      if(datePicker.currentYear < datePicker.selectedYear[1]) {
        beforeEndDate = true;
      } else if(datePicker.currentYear == datePicker.selectedYear[1] && datePicker.currentMonth <= datePicker.selectedMonth[1]) {
        beforeEndDate = true;
      }
      // check after start date
      if(datePicker.currentYear > datePicker.selectedYear[0]) {
        afterStartDate = true;
      } else if(datePicker.currentYear == datePicker.selectedYear[0] && datePicker.currentMonth >= datePicker.selectedMonth[0]) {
        afterStartDate = true;
      }
      return beforeEndDate && afterStartDate;
    };
  
    function isPast(date, now) {
      // date < now
      var newdate = new Date(date[0], date[1], date[2]),
        nowDate = new Date(now[0], now[1], now[2]);
      return newdate < nowDate;
    };
  
    function keyNavigationInBetween(datePicker) {
      if(datePicker.dateSelected[0] && !datePicker.dateSelected[1]) showInBetweenElements(datePicker, datePicker.element.querySelector('.js-date-picker__date[tabindex="0"]'));
    };
  
    function resetStarDateAppearance(datePicker) {
      // the start date apperance is modified when there are --range elements (e.g., remove corners)
      if(!datePicker.dateSelected[0]) return;
      var inBetweenDates = datePicker.datePicker.getElementsByClassName(datePicker.inBetweenClass);
      if(inBetweenDates.length == 0) {
        var startDate = datePicker.datePicker.getElementsByClassName('date-picker__date--range-start');
        if(startDate.length > 0) Util.removeClass(startDate[0], 'date-picker__date--range-start');
      }
    };
  
    function initPredefinedOptions(datePicker) {
      if(!datePicker.predefOptions || !Util.hasClass(datePicker.predefOptions, 'js-date-range-select')) return;
      
      var select = datePicker.predefOptions.querySelector('select');
      if(!select) return;
  
      // check initial value and toggle date range
      if(select.options[select.selectedIndex].value == 'custom') Util.removeClass(datePicker.element, 'is-hidden');
  
      select.addEventListener('change', function(event) {
        if(select.options[select.selectedIndex].value == 'custom') {
          // reveal date picker
          Util.removeClass(datePicker.element, 'is-hidden');
          placeCalendar(datePicker);
          datePicker.trigger.focus();
        } else {
          Util.addClass(datePicker.element, 'is-hidden');
        }
      });
    };
  
    function placeCalendar(datePicker) {
      // reset position
      datePicker.datePicker.style.left = '0px';
      datePicker.datePicker.style.right = 'auto';
      
      //check if you need to modify the calendar postion
      var pickerBoundingRect = datePicker.datePicker.getBoundingClientRect();
  
      if(pickerBoundingRect.right > window.innerWidth) {
        datePicker.datePicker.style.left = 'auto';
        datePicker.datePicker.style.right = '0px';
      }
    };
  
    DateRange.defaults = {
      element : '',
      months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      dateFormat: 'd-m-y',
      dateSeparator: '/'
    };
  
    window.DateRange = DateRange;
  
    var dateRange = document.getElementsByClassName('js-date-range');
    if( dateRange.length > 0 ) {
  		for( var i = 0; i < dateRange.length; i++) {(function(i){
        var opts = {element: dateRange[i]};
        if(dateRange[i].getAttribute('data-date-format')) {
          opts.dateFormat = dateRange[i].getAttribute('data-date-format');
        }
        if(dateRange[i].getAttribute('data-date-separator')) {
          opts.dateSeparator = dateRange[i].getAttribute('data-date-separator');
        }
        if(dateRange[i].getAttribute('data-months')) {
          opts.months = dateRange[i].getAttribute('data-months').split(',').map(function(item) {return item.trim();});
        }
        new DateRange(opts);
      })(i);}
  	}
  }());
  // File#: _2_drag-drop-file
  // Usage: codyhouse.co/license
  (function() {
    var Ddf = function(opts) {
      this.options = Util.extend(Ddf.defaults , opts);
      this.element = this.options.element;
      this.area = this.element.getElementsByClassName('js-ddf__area');
      this.input = this.element.getElementsByClassName('js-ddf__input');
      this.label = this.element.getElementsByClassName('js-ddf__label');
      this.labelEnd = this.element.getElementsByClassName('js-ddf__files-counter');
      this.labelEndMessage = this.labelEnd.length > 0 ? this.labelEnd[0].innerHTML.split('%') : false;
      this.droppedFiles = [];
      this.lastDroppedFiles = [];
      this.options.acceptFile = [];
      this.progress = false;
      this.progressObj = [];
      this.progressCompleteClass = 'ddf__progress--complete';
      initDndMessageResponse(this);
      initProgress(this, 0, 1, false);
      initDdf(this);
    };
  
    function initDndMessageResponse(element) { 
      // use this function to initilise the response of the Ddf when files are dropped (e.g., show list of files, update label message, show loader)
      if(element.options.showFiles) {
        element.filesList = element.element.getElementsByClassName('js-ddf__list');
        if(element.filesList.length == 0) return;
        element.fileItems = element.filesList[0].getElementsByClassName('js-ddf__item');
        if(element.fileItems.length > 0) Util.addClass(element.fileItems[0], 'is-hidden');+
        // listen for click on remove file action
        initRemoveFile(element);
      } else { // do not show list of files
        if(element.label.length == 0) return;
        if(element.options.upload) element.progress = element.element.getElementsByClassName('js-ddf__progress');
      }
    };
  
    function initDdf(element) {
      if(element.input.length > 0 ) { // store accepted file format
        var accept = element.input[0].getAttribute('accept');
        if(accept) element.options.acceptFile = accept.split(',').map(function(element){ return element.trim();})
      }
  
      initDndInput(element);
      initDndArea(element);
    };
  
    function initDndInput(element) { // listen to changes in the input file element
      if(element.input.length == 0 ) return;
      element.input[0].addEventListener('change', function(event){
        if(element.input[0].value == '') return; 
        storeDroppedFiles(element, element.input[0].files);
        element.input[0].value = '';
        updateDndArea(element);
      });
    };
  
    function initDndArea(element) { //drag event listeners
      element.element.addEventListener('dragenter', handleEvent.bind(element));
      element.element.addEventListener('dragover', handleEvent.bind(element));
      element.element.addEventListener('dragleave', handleEvent.bind(element));
      element.element.addEventListener('drop', handleEvent.bind(element));
    };
  
    function handleEvent(event) {
      switch(event.type) {
        case 'dragenter': 
        case 'dragover':
          preventDefaults(event);
          Util.addClass(this.area[0], 'ddf__area--file-hover');
          break;
        case 'dragleave':
          preventDefaults(event);
          Util.removeClass(this.area[0], 'ddf__area--file-hover');
          break;
        case 'drop':
          preventDefaults(event);
          storeDroppedFiles(this, event.dataTransfer.files);
          updateDndArea(this);
          break;
      }
    };
  
    function storeDroppedFiles(element, fileData) { // check files size/format/number
      element.lastDroppedFiles = [];
      if(element.options.replaceFiles) element.droppedFiles = [];
      Array.prototype.push.apply(element.lastDroppedFiles, fileData);
      filterUploadedFiles(element); // remove files that do not respect format/size
      element.droppedFiles = element.droppedFiles.concat(element.lastDroppedFiles);
      if(element.options.maxFiles) filterMaxFiles(element); // check max number of files
    };
  
    function updateDndArea(element) { // update UI + emit events
      if(element.options.showFiles) updateDndList(element);
      else {
        updateDndAreaMessage(element);
        Util.addClass(element.area[0], 'ddf__area--file-dropped');
      }
      Util.removeClass(element.area[0], 'ddf__area--file-hover');
      emitCustomEvents(element, 'filesUploaded', false);
    };
  
    function preventDefaults(event) {
      event.preventDefault();
      event.stopPropagation();
    };
  
    function filterUploadedFiles(element) {
      // check max weight
      if(element.options.maxSize) filterMaxWeight(element);
      // check file format
      if(element.options.acceptFile.length > 0) filterAcceptFile(element);
    };
  
    function filterMaxWeight(element) { // filter files by size
      var rejected = [];
      for(var i = element.lastDroppedFiles.length - 1; i >= 0; i--) {
        if(element.lastDroppedFiles[i].size > element.options.maxSize*1000) {
          var rejectedFile = element.lastDroppedFiles.splice(i, 1);
          rejected.push(rejectedFile[0].name);
        }
      }
      if(rejected.length > 0) {
        emitCustomEvents(element, 'rejectedWeight', rejected);
      }
    };
  
    function filterAcceptFile(element) { // filter files by format
      var rejected = [];
      for(var i = element.lastDroppedFiles.length - 1; i >= 0; i--) {
        if( !formatInList(element, i) ) {
          var rejectedFile = element.lastDroppedFiles.splice(i, 1);
          rejected.push(rejectedFile[0].name);
        }
      }
  
      if(rejected.length > 0) {
        emitCustomEvents(element, 'rejectedFormat', rejected);
      }
    };
  
    function formatInList(element, index) {
      var formatArray = element.lastDroppedFiles[index].type.split('/'),
        type = formatArray[0]+'/*',
        extension = formatArray.length > 1 ? formatArray[1]: false;
  
      var accepted = false;
      for(var i = 0; i < element.options.acceptFile.length; i++) {
        if(element.lastDroppedFiles[index].type == element.options.acceptFile[i] || type == element.options.acceptFile[i] || (extension && extension == element.options.acceptFile[i]) ) {
          accepted = true;
          break;
        }
  
        if(extension && extensionInList(extension, element.options.acceptFile[i])) { // extension could be list of format; e.g. for the svg it is svg+xml
          accepted = true;
          break;
        }
      }
      return accepted;
    };
  
    function extensionInList(extensionList, extension) {
      // extension could be .svg, .pdf, ..
      // extensionList could be png, svg+xml, ...
      if('.'+extensionList  == extension) return true;
      var accepted = false;
      var extensionListArray = extensionList.split('+');
      for(var i = 0; i < extensionListArray.length; i++) {
        if('.'+extensionListArray[i] == extension) {
          accepted = true;
          break;
        }
      }
      return accepted;
    }
  
    function filterMaxFiles(element) { // check number of uploaded files
      if(element.options.maxFiles >= element.droppedFiles.length) return; 
      var rejected = [];
      while (element.droppedFiles.length > element.options.maxFiles) {
        var rejectedFile = element.droppedFiles.pop();
        element.lastDroppedFiles.pop();
        rejected.push(rejectedFile.name);
      }
  
      if(rejected.length > 0) {
        emitCustomEvents(element, 'rejectedNumber', rejected);
      }
    };
  
    function updateDndAreaMessage(element) {
      if(element.progress && element.progress[0]) { // reset progress bar 
        element.progressObj[0].setProgressBarValue(0);
        Util.toggleClass(element.progress[0], 'is-hidden', element.droppedFiles.length == 0);
        Util.removeClass(element.progress[0], element.progressCompleteClass);
      }
  
      if(element.droppedFiles.length > 0 && element.labelEndMessage) {
        var finalMessage = element.labelEnd.innerHTML;
        if(element.labelEndMessage.length > 3) {
          finalMessage = element.droppedFiles.length > 1 
            ? element.labelEndMessage[0] + element.labelEndMessage[2] + element.labelEndMessage[3]
            : element.labelEndMessage[0] + element.labelEndMessage[1] + element.labelEndMessage[3];
        }
        element.labelEnd[0].innerHTML = finalMessage.replace('{n}', element.droppedFiles.length);
      }
    };
  
    function updateDndList(element) {
      // create new list of files to be appended
      if(!element.fileItems || element.fileItems.length == 0) return
      var clone = element.fileItems[0].cloneNode(true),
        string = '';
      Util.removeClass(clone, 'is-hidden');
      for(var i = 0; i < element.lastDroppedFiles.length; i++) {
        clone.getElementsByClassName('js-ddf__file-name')[0].textContent = element.lastDroppedFiles[i].name;
        string = clone.outerHTML + string;
      }
  
      if(element.options.replaceFiles) { // replace all files in list with new files
        string = element.fileItems[0].outerHTML + string;
        element.filesList[0].innerHTML = string;
      } else {
        element.fileItems[0].insertAdjacentHTML('afterend', string);
      }
  
      if(element.options.upload) storeMultipleProgress(element);
  
      Util.toggleClass(element.filesList[0], 'is-hidden', element.droppedFiles.length == 0);
    };
  
    function initRemoveFile(element) { // if list of files is visible - option to remove file from list
      element.filesList[0].addEventListener('click', function(event){
        if(!event.target.closest('.js-ddf__remove-btn')) return;
        event.preventDefault();
        var item = event.target.closest('.js-ddf__item'),
          index = Util.getIndexInArray(element.filesList[0].getElementsByClassName('js-ddf__item'), item);
        
        var removedFile = element.droppedFiles.splice(element.droppedFiles.length - index, 1);
        if(element.progress && element.progress.length > element.droppedFiles.length - index) {
          element.progress.splice();
        }
        // check if we need to remove items form the lastDroppedFiles array
        var lastDroppedIndex = element.lastDroppedFiles.length - index;
        if(lastDroppedIndex >= 0 && lastDroppedIndex < element.lastDroppedFiles.length - 1) {
          element.lastDroppedFiles.splice(element.lastDroppedFiles.length - index, 1);
        }
        item.remove();
        emitCustomEvents(element, 'fileRemoved', removedFile);
      });
  
    };
  
    function storeMultipleProgress(element) { // handle progress bar elements
      element.progress = [];
      var delta = element.droppedFiles.length - element.lastDroppedFiles.length;
      for(var i = 0; i < element.lastDroppedFiles.length; i++) {
        element.progress[i] = element.fileItems[element.droppedFiles.length - delta - i].getElementsByClassName('js-ddf__progress')[0];
      }
      initProgress(element, 0, element.lastDroppedFiles.length, true);
    };
  
    function initProgress(element, start, end, bool) {
      element.progressObj = [];
      if(!element.progress || element.progress.length == 0) return;
      for(var i = start; i < end; i++) {(function(i){
        element.progressObj.push(new CProgressBar(element.progress[i]));
        if(bool) Util.removeClass(element.progress[i], 'is-hidden');
        // listen for 100% progress
        element.progress[i].addEventListener('updateProgress', function(event){
          if(event.detail.value == 100 ) Util.addClass(element.progress[i], element.progressCompleteClass);
        });
      })(i);}
    };
  
    function emitCustomEvents(element, eventName, detail) {
  		var event = new CustomEvent(eventName, {detail: detail});
  		element.element.dispatchEvent(event);
    };
    
    Ddf.defaults = {
      element : '',
      maxFiles: false, // max number of files
      maxSize: false, // max weight - set in kb
      showFiles: false, // show list of selected files
      replaceFiles: true, // when new files are loaded -> they replace the old ones
      upload: false // show progress bar for the upload process
    };
  
    window.Ddf = Ddf;
  }());
  // File#: _2_draggable-img-gallery
  // Usage: codyhouse.co/license
  (function() {
    var DragGallery = function(element) {
      this.element = element;
      this.list = this.element.getElementsByTagName('ul')[0];
      this.imgs = this.list.children;
      this.gestureHint = this.element.getElementsByClassName('drag-gallery__gesture-hint');// drag gesture hint
      this.galleryWidth = getGalleryWidth(this); 
      this.translate = 0; // store container translate value
      this.dragStart = false; // start dragging position
      // drag momentum option
      this.dragMStart = false;
      this.dragTimeMStart = false;
      this.dragTimeMEnd = false;
      this.dragMSpeed = false;
      this.dragAnimId = false;
      initDragGalleryEvents(this); 
    };
  
    function initDragGalleryEvents(gallery) {
      initDragging(gallery); // init dragging
  
      gallery.element.addEventListener('update-gallery-width', function(event){ // window resize
        gallery.galleryWidth = getGalleryWidth(gallery); 
        // reset translate value if not acceptable
        checkTranslateValue(gallery);
        setTranslate(gallery);
      });
       
      if(intersectionObsSupported) initOpacityAnim(gallery); // init image animation
  
      if(!reducedMotion && gallery.gestureHint.length > 0) initHintGesture(gallery); // init hint gesture element animation
  
      initKeyBoardNav(gallery);
    };
  
    function getGalleryWidth(gallery) {
      return gallery.list.scrollWidth - gallery.list.offsetWidth;
    };
  
    function initDragging(gallery) { // gallery drag
      new SwipeContent(gallery.element);
      gallery.element.addEventListener('dragStart', function(event){
        window.cancelAnimationFrame(gallery.dragAnimId);
        Util.addClass(gallery.element, 'drag-gallery--is-dragging'); 
        gallery.dragStart = event.detail.x;
        gallery.dragMStart = event.detail.x;
        gallery.dragTimeMStart = new Date().getTime();
        gallery.dragTimeMEnd = false;
        gallery.dragMSpeed = false;
        initDragEnd(gallery);
      });
  
      gallery.element.addEventListener('dragging', function(event){
        if(!gallery.dragStart) return;
        if(Math.abs(event.detail.x - gallery.dragStart) < 5) return;
        gallery.translate = Math.round(event.detail.x - gallery.dragStart + gallery.translate);
        gallery.dragStart = event.detail.x;
        checkTranslateValue(gallery);
        setTranslate(gallery);
      });
    };
  
    function initDragEnd(gallery) {
      gallery.element.addEventListener('dragEnd', function cb(event){
        gallery.element.removeEventListener('dragEnd', cb);
        Util.removeClass(gallery.element, 'drag-gallery--is-dragging');
        initMomentumDrag(gallery); // drag momentum
        gallery.dragStart = false;
      });
    };
  
    function initKeyBoardNav(gallery) {
      gallery.element.setAttribute('tabindex', 0);
      // navigate gallery using right/left arrows
      gallery.element.addEventListener('keyup', function(event){
        if( event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright' ) {
          keyboardNav(gallery, 'right');
        } else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
          keyboardNav(gallery, 'left');
        }
      });
    };
  
    function keyboardNav(gallery, direction) {
      var delta = parseFloat(window.getComputedStyle(gallery.imgs[0]).marginRight) + gallery.imgs[0].offsetWidth;
      gallery.translate = (direction == 'right') ? gallery.translate - delta : gallery.translate + delta;
      checkTranslateValue(gallery);
      setTranslate(gallery);
    };
  
    function checkTranslateValue(gallery) { // make sure translate is in the right interval
      if(gallery.translate > 0) {
        gallery.translate = 0;
        gallery.dragMSpeed = 0;
      }
      if(Math.abs(gallery.translate) > gallery.galleryWidth) {
        gallery.translate = gallery.galleryWidth*-1;
        gallery.dragMSpeed = 0;
      }
    };
  
    function setTranslate(gallery) {
      gallery.list.style.transform = 'translateX('+gallery.translate+'px)';
      gallery.list.style.msTransform = 'translateX('+gallery.translate+'px)';
    };
  
    function initOpacityAnim(gallery) { // animate img opacities on drag
      for(var i = 0; i < gallery.imgs.length; i++) {
        var observer = new IntersectionObserver(opacityCallback.bind(gallery.imgs[i]), { threshold: [0, 0.1] });
  		  observer.observe(gallery.imgs[i]);
      }
    };
  
    function opacityCallback(entries, observer) { // reveal images when they enter the viewport
      var threshold = entries[0].intersectionRatio.toFixed(1);
  		if(threshold > 0) {
        Util.addClass(this, 'drag-gallery__item--visible');
        observer.unobserve(this);
      }
    };
  
    function initMomentumDrag(gallery) {
      // momentum effect when drag is over
      if(reducedMotion) return;
      var timeNow = new Date().getTime();
      gallery.dragMSpeed = 0.95*(gallery.dragStart - gallery.dragMStart)/(timeNow - gallery.dragTimeMStart);
  
      var currentTime = false;
  
      function animMomentumDrag(timestamp) {
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        currentTime = timestamp;
        if(Math.abs(gallery.dragMSpeed) < 0.01) {
          gallery.dragAnimId = false;
          return;
        } else {
          gallery.translate = Math.round(gallery.translate + (gallery.dragMSpeed*progress));
          checkTranslateValue(gallery);
          setTranslate(gallery);
          gallery.dragMSpeed = gallery.dragMSpeed*0.95;
          gallery.dragAnimId = window.requestAnimationFrame(animMomentumDrag);
        }
      };
  
      gallery.dragAnimId = window.requestAnimationFrame(animMomentumDrag);
    };
  
    function initHintGesture(gallery) { // show user a hint about gallery dragging
      var observer = new IntersectionObserver(hintGestureCallback.bind(gallery.gestureHint[0]), { threshold: [0, 1] });
  		observer.observe(gallery.gestureHint[0]);
    };
  
    function hintGestureCallback(entries, observer) {
      var threshold = entries[0].intersectionRatio.toFixed(1);
  		if(threshold > 0) {
        Util.addClass(this, 'drag-gallery__gesture-hint--animate');
        observer.unobserve(this);
      }
    };
  
    //initialize the DragGallery objects
    var dragGallery = document.getElementsByClassName('js-drag-gallery'),
      intersectionObsSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
  
    if( dragGallery.length > 0 ) {
      var dragGalleryArray = [];
      for( var i = 0; i < dragGallery.length; i++) {
        (function(i){ 
          if(!intersectionObsSupported || reducedMotion) Util.addClass(dragGallery[i], 'drag-gallery--anim-off');
          dragGalleryArray.push(new DragGallery(dragGallery[i]));
        })(i);
      }
  
      // resize event
      var resizingId = false,
        customEvent = new CustomEvent('update-gallery-width');
      
      window.addEventListener('resize', function() {
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 500);
      });
  
      function doneResizing() {
        for( var i = 0; i < dragGalleryArray.length; i++) {
          (function(i){dragGalleryArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
    }
  }());
  // File#: _2_drawer-navigation
  // Usage: codyhouse.co/license
  (function() {
    function initDrNavControl(element) {
      var circle = element.getElementsByTagName('circle');
      if(circle.length > 0) {
        // set svg attributes to create fill-in animation on click
        initCircleAttributes(element, circle[0]);
      }
  
      var drawerId = element.getAttribute('aria-controls'),
        drawer = document.getElementById(drawerId);
      if(drawer) {
        // when the drawer is closed without click (e.g., user presses 'Esc') -> reset trigger status
        drawer.addEventListener('drawerIsClose', function(event){ 
          if(!event.detail || (event.detail && !event.detail.closest('.js-dr-nav-control[aria-controls="'+drawerId+'"]')) ) resetTrigger(element);
        });
      }
    };
  
    function initCircleAttributes(element, circle) {
      // set circle stroke-dashoffset/stroke-dasharray values
      var circumference = (2*Math.PI*circle.getAttribute('r')).toFixed(2);
      circle.setAttribute('stroke-dashoffset', circumference);
      circle.setAttribute('stroke-dasharray', circumference);
      Util.addClass(element, 'dr-nav-control--ready-to-animate');
    };
  
    function resetTrigger(element) {
      Util.removeClass(element, 'anim-menu-btn--state-b'); 
    };
  
    var drNavControl = document.getElementsByClassName('js-dr-nav-control');
    if(drNavControl.length > 0) initDrNavControl(drNavControl[0]);
  }());
  // File#: _2_dropdown
  // Usage: codyhouse.co/license
  (function() {
  	var Dropdown = function(element) {
  		this.element = element;
  		this.trigger = this.element.getElementsByClassName('js-dropdown__trigger')[0];
  		this.dropdown = this.element.getElementsByClassName('js-dropdown__menu')[0];
  		this.triggerFocus = false;
  		this.dropdownFocus = false;
  		this.hideInterval = false;
  		// sublevels
  		this.dropdownSubElements = this.element.getElementsByClassName('js-dropdown__sub-wrapper');
  		this.prevFocus = false; // store element that was in focus before focus changed
  		this.addDropdownEvents();
  	};
  	
  	Dropdown.prototype.addDropdownEvents = function(){
  		//place dropdown
  		var self = this;
  		this.placeElement();
  		this.element.addEventListener('placeDropdown', function(event){
  			self.placeElement();
  		});
  		// init dropdown
  		this.initElementEvents(this.trigger, this.triggerFocus); // this is used to trigger the primary dropdown
  		this.initElementEvents(this.dropdown, this.dropdownFocus); // this is used to trigger the primary dropdown
  		// init sublevels
  		this.initSublevels(); // if there are additional sublevels -> bind hover/focus events
  	};
  
  	Dropdown.prototype.placeElement = function() {
  		// remove inline style first
  		this.dropdown.removeAttribute('style');
  		// check dropdown position
  		var triggerPosition = this.trigger.getBoundingClientRect(),
  			isRight = (window.innerWidth < triggerPosition.left + parseInt(getComputedStyle(this.dropdown).getPropertyValue('width')));
  
  		var xPosition = isRight ? 'right: 0px; left: auto;' : 'left: 0px; right: auto;';
  		this.dropdown.setAttribute('style', xPosition);
  	};
  
  	Dropdown.prototype.initElementEvents = function(element, bool) {
  		var self = this;
  		element.addEventListener('mouseenter', function(){
  			bool = true;
  			self.showDropdown();
  		});
  		element.addEventListener('focus', function(){
  			self.showDropdown();
  		});
  		element.addEventListener('mouseleave', function(){
  			bool = false;
  			self.hideDropdown();
  		});
  		element.addEventListener('focusout', function(){
  			self.hideDropdown();
  		});
  	};
  
  	Dropdown.prototype.showDropdown = function(){
  		if(this.hideInterval) clearInterval(this.hideInterval);
  		// remove style attribute
  		this.dropdown.removeAttribute('style');
  		this.placeElement();
  		this.showLevel(this.dropdown, true);
  	};
  
  	Dropdown.prototype.hideDropdown = function(){
  		var self = this;
  		if(this.hideInterval) clearInterval(this.hideInterval);
  		this.hideInterval = setTimeout(function(){
  			var dropDownFocus = document.activeElement.closest('.js-dropdown'),
  				inFocus = dropDownFocus && (dropDownFocus == self.element);
  			// if not in focus and not hover -> hide
  			if(!self.triggerFocus && !self.dropdownFocus && !inFocus) {
  				self.hideLevel(self.dropdown, true);
  				// make sure to hide sub/dropdown
  				self.hideSubLevels();
  				self.prevFocus = false;
  			}
  		}, 300);
  	};
  
  	Dropdown.prototype.initSublevels = function(){
  		var self = this;
  		var dropdownMenu = this.element.getElementsByClassName('js-dropdown__menu');
  		for(var i = 0; i < dropdownMenu.length; i++) {
  			var listItems = dropdownMenu[i].children;
  			// bind hover
  	    new menuAim({
  	      menu: dropdownMenu[i],
  	      activate: function(row) {
  	      	var subList = row.getElementsByClassName('js-dropdown__menu')[0];
  	      	if(!subList) return;
  	      	Util.addClass(row.querySelector('a'), 'dropdown__item--hover');
  	      	self.showLevel(subList);
  	      },
  	      deactivate: function(row) {
  	      	var subList = row.getElementsByClassName('dropdown__menu')[0];
  	      	if(!subList) return;
  	      	Util.removeClass(row.querySelector('a'), 'dropdown__item--hover');
  	      	self.hideLevel(subList);
  	      },
  	      submenuSelector: '.js-dropdown__sub-wrapper',
  	    });
  		}
  		// store focus element before change in focus
  		this.element.addEventListener('keydown', function(event) { 
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  				self.prevFocus = document.activeElement;
  			}
  		});
  		// make sure that sublevel are visible when their items are in focus
  		this.element.addEventListener('keyup', function(event) {
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  				// focus has been moved -> make sure the proper classes are added to subnavigation
  				var focusElement = document.activeElement,
  					focusElementParent = focusElement.closest('.js-dropdown__menu'),
  					focusElementSibling = focusElement.nextElementSibling;
  
  				// if item in focus is inside submenu -> make sure it is visible
  				if(focusElementParent && !Util.hasClass(focusElementParent, 'dropdown__menu--is-visible')) {
  					self.showLevel(focusElementParent);
  				}
  				// if item in focus triggers a submenu -> make sure it is visible
  				if(focusElementSibling && !Util.hasClass(focusElementSibling, 'dropdown__menu--is-visible')) {
  					self.showLevel(focusElementSibling);
  				}
  
  				// check previous element in focus -> hide sublevel if required 
  				if( !self.prevFocus) return;
  				var prevFocusElementParent = self.prevFocus.closest('.js-dropdown__menu'),
  					prevFocusElementSibling = self.prevFocus.nextElementSibling;
  				
  				if( !prevFocusElementParent ) return;
  				
  				// element in focus and element prev in focus are siblings
  				if( focusElementParent && focusElementParent == prevFocusElementParent) {
  					if(prevFocusElementSibling) self.hideLevel(prevFocusElementSibling);
  					return;
  				}
  
  				// element in focus is inside submenu triggered by element prev in focus
  				if( prevFocusElementSibling && focusElementParent && focusElementParent == prevFocusElementSibling) return;
  				
  				// shift tab -> element in focus triggers the submenu of the element prev in focus
  				if( focusElementSibling && prevFocusElementParent && focusElementSibling == prevFocusElementParent) return;
  				
  				var focusElementParentParent = focusElementParent.parentNode.closest('.js-dropdown__menu');
  				
  				// shift tab -> element in focus is inside the dropdown triggered by a siblings of the element prev in focus
  				if(focusElementParentParent && focusElementParentParent == prevFocusElementParent) {
  					if(prevFocusElementSibling) self.hideLevel(prevFocusElementSibling);
  					return;
  				}
  				
  				if(prevFocusElementParent && Util.hasClass(prevFocusElementParent, 'dropdown__menu--is-visible')) {
  					self.hideLevel(prevFocusElementParent);
  				}
  			}
  		});
  	};
  
  	Dropdown.prototype.hideSubLevels = function(){
  		var visibleSubLevels = this.dropdown.getElementsByClassName('dropdown__menu--is-visible');
  		if(visibleSubLevels.length == 0) return;
  		while (visibleSubLevels[0]) {
  			this.hideLevel(visibleSubLevels[0]);
  	 	}
  	 	var hoveredItems = this.dropdown.getElementsByClassName('dropdown__item--hover');
  	 	while (hoveredItems[0]) {
  			Util.removeClass(hoveredItems[0], 'dropdown__item--hover');
  	 	}
  	};
  
  	Dropdown.prototype.showLevel = function(level, bool){
  		if(bool == undefined) {
  			//check if the sublevel needs to be open to the left
  			Util.removeClass(level, 'dropdown__menu--left');
  			var boundingRect = level.getBoundingClientRect();
  			if(window.innerWidth - boundingRect.right < 5 && boundingRect.left + window.scrollX > 2*boundingRect.width) Util.addClass(level, 'dropdown__menu--left');
  		}
  		Util.addClass(level, 'dropdown__menu--is-visible');
  		Util.removeClass(level, 'dropdown__menu--is-hidden');
  	};
  
  	Dropdown.prototype.hideLevel = function(level, bool){
  		if(!Util.hasClass(level, 'dropdown__menu--is-visible')) return;
  		Util.removeClass(level, 'dropdown__menu--is-visible');
  		Util.addClass(level, 'dropdown__menu--is-hidden');
  		
  		level.addEventListener('transitionend', function cb(event){
  			if(event.propertyName != 'opacity') return;
  			level.removeEventListener('transitionend', cb);
  			if(Util.hasClass(level, 'dropdown__menu--is-hidden')) Util.removeClass(level, 'dropdown__menu--is-hidden dropdown__menu--left');
  			if(bool && !Util.hasClass(level, 'dropdown__menu--is-visible')) level.setAttribute('style', 'width: 0px; overflow: hidden;');
  		});
  	};
  
  	window.Dropdown = Dropdown;
  
  	var dropdown = document.getElementsByClassName('js-dropdown');
  	if( dropdown.length > 0 ) { // init Dropdown objects
  		for( var i = 0; i < dropdown.length; i++) {
  			(function(i){new Dropdown(dropdown[i]);})(i);
  		}
  	}
  }());
  // File#: _2_flexi-header
  // Usage: codyhouse.co/license
  (function() {
    var flexHeader = document.getElementsByClassName('js-f-header');
  	if(flexHeader.length > 0) {
  		var menuTrigger = flexHeader[0].getElementsByClassName('js-anim-menu-btn')[0],
  			firstFocusableElement = getMenuFirstFocusable();
  
  		// we'll use these to store the node that needs to receive focus when the mobile menu is closed 
  		var focusMenu = false;
  
  		resetFlexHeaderOffset();
  		setAriaButtons();
  
  		menuTrigger.addEventListener('anim-menu-btn-clicked', function(event){
  			toggleMenuNavigation(event.detail);
  		});
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger)) {
  					focusMenu = menuTrigger; // move focus to menu trigger when menu is close
  					menuTrigger.click();
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger) && !document.activeElement.closest('.js-f-header')) menuTrigger.click();
  			}
  		});
  
  		// detect click on a dropdown control button - expand-on-mobile only
  		flexHeader[0].addEventListener('click', function(event){
  			var btnLink = event.target.closest('.js-f-header__dropdown-control');
  			if(!btnLink) return;
  			!btnLink.getAttribute('aria-expanded') ? btnLink.setAttribute('aria-expanded', 'true') : btnLink.removeAttribute('aria-expanded');
  		});
  
  		// detect mouseout from a dropdown control button - expand-on-mobile only
  		flexHeader[0].addEventListener('mouseout', function(event){
  			var btnLink = event.target.closest('.js-f-header__dropdown-control');
  			if(!btnLink) return;
  			// check layout type
  			if(getLayout() == 'mobile') return;
  			btnLink.removeAttribute('aria-expanded');
  		});
  
  		// close dropdown on focusout - expand-on-mobile only
  		flexHeader[0].addEventListener('focusin', function(event){
  			var btnLink = event.target.closest('.js-f-header__dropdown-control'),
  				dropdown = event.target.closest('.f-header__dropdown');
  			if(dropdown) return;
  			if(btnLink && btnLink.hasAttribute('aria-expanded')) return;
  			// check layout type
  			if(getLayout() == 'mobile') return;
  			var openDropdown = flexHeader[0].querySelector('.js-f-header__dropdown-control[aria-expanded="true"]');
  			if(openDropdown) openDropdown.removeAttribute('aria-expanded');
  		});
  
  		// listen for resize
  		var resizingId = false;
  		window.addEventListener('resize', function() {
  			clearTimeout(resizingId);
  			resizingId = setTimeout(doneResizing, 500);
  		});
  
  		function getMenuFirstFocusable() {
  			var focusableEle = flexHeader[0].getElementsByClassName('f-header__nav')[0].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary'),
  				firstFocusable = false;
  			for(var i = 0; i < focusableEle.length; i++) {
  				if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
  					firstFocusable = focusableEle[i];
  					break;
  				}
  			}
  
  			return firstFocusable;
      };
      
      function isVisible(element) {
        return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  		};
  
  		function doneResizing() {
  			if( !isVisible(menuTrigger) && Util.hasClass(flexHeader[0], 'f-header--expanded')) {
  				menuTrigger.click();
  			}
  			resetFlexHeaderOffset();
  		};
  		
  		function toggleMenuNavigation(bool) { // toggle menu visibility on small devices
  			Util.toggleClass(document.getElementsByClassName('f-header__nav')[0], 'f-header__nav--is-visible', bool);
  			Util.toggleClass(flexHeader[0], 'f-header--expanded', bool);
  			menuTrigger.setAttribute('aria-expanded', bool);
  			if(bool) firstFocusableElement.focus(); // move focus to first focusable element
  			else if(focusMenu) {
  				focusMenu.focus();
  				focusMenu = false;
  			}
  		};
  
  		function resetFlexHeaderOffset() {
  			// on mobile -> update max height of the flexi header based on its offset value (e.g., if there's a fixed pre-header element)
  			document.documentElement.style.setProperty('--f-header-offset', flexHeader[0].getBoundingClientRect().top+'px');
  		};
  
  		function setAriaButtons() {
  			var btnDropdown = flexHeader[0].getElementsByClassName('js-f-header__dropdown-control');
  			for(var i = 0; i < btnDropdown.length; i++) {
  				var id = 'f-header-dropdown-'+i,
  					dropdown = btnDropdown[i].nextElementSibling;
  				if(dropdown.hasAttribute('id')) {
  					id = dropdown.getAttribute('id');
  				} else {
  					dropdown.setAttribute('id', id);
  				}
  				btnDropdown[i].setAttribute('aria-controls', id);	
  			}
  		};
  
  		function getLayout() {
  			return getComputedStyle(flexHeader[0], ':before').getPropertyValue('content').replace(/\'|"/g, '');
  		};
  	}
  }());
  // File#: _2_floating-side-nav
  // Usage: codyhouse.co/license
  (function() {
    var FSideNav = function(element) {
  		this.element = element;
      this.triggers = document.querySelectorAll('[aria-controls="'+this.element.getAttribute('id')+'"]');
      this.list = this.element.getElementsByClassName('js-float-sidenav__list')[0];
      this.anchors = this.list.querySelectorAll('a[href^="#"]');
      this.sections = getSections(this);
      this.sectionsContainer = document.getElementsByClassName('js-float-sidenav-target');
  		this.firstFocusable = getFSideNavFirstFocusable(this);
  		this.selectedTrigger = null;
      this.showClass = "float-sidenav--is-visible";
      this.clickScrolling = false;
      this.intervalID = false;
  		initFSideNav(this);
    };
  
    function getSections(nav) {
      var sections = [];
      // get all content sections
      for(var i = 0; i < nav.anchors.length; i++) {
        var section = document.getElementById(nav.anchors[i].getAttribute('href').replace('#', ''));
        if(section) sections.push(section);
      }
      return sections;
    };
  
    function getFSideNavFirstFocusable(nav) {
      var focusableEle = nav.element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary'),
  				firstFocusable = false;
      for(var i = 0; i < focusableEle.length; i++) {
        if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
          firstFocusable = focusableEle[i];
          break;
        }
      }
  
      return firstFocusable;
    };
    
    function initFSideNav(nav) {
      initButtonTriggers(nav); // mobile version behaviour
  
      initAnchorEvents(nav); // select anchor in list
  
      if(intersectionObserverSupported) {
        initSectionScroll(nav); // update anchor appearance on scroll
      } else {
        Util.addClass(nav.element, 'float-sidenav--on-target');
      }
    };
  
    function initButtonTriggers(nav) { // mobile only
      if ( !nav.triggers ) return;
  
      for(var i = 0; i < nav.triggers.length; i++) {
        nav.triggers[i].addEventListener('click', function(event) {
          openFSideNav(nav, event);
        });
      }
  
      // close side nav when clicking on close button/bg layer
      nav.element.addEventListener('click', function(event) {
        if(event.target.closest('.js-float-sidenav__close-btn') || Util.hasClass(event.target, 'js-float-sidenav')) {
          closeFSideNav(nav, event);
        }
      });
  
      // listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				closeFSideNav(nav, event);
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) { // close navigation on mobile if open when nav loses focus
          if( !document.activeElement.closest('.js-float-sidenav')) closeFSideNav(nav, event, true);
  			}
  		});
    };
  
    function openFSideNav(nav, event) { // open side nav - mobile only
      event.preventDefault();
      nav.selectedTrigger = event.target;
      event.target.setAttribute('aria-expanded', 'true');
      Util.addClass(nav.element, nav.showClass);
      nav.element.addEventListener('transitionend', function cb(event){
        nav.element.removeEventListener('transitionend', cb);
        nav.firstFocusable.focus();
      });
    };
  
    function closeFSideNav(nav, event, bool) { // close side nav - mobile only
      if( !Util.hasClass(nav.element, nav.showClass) ) return;
      if(event) event.preventDefault();
      Util.removeClass(nav.element, nav.showClass);
      if(!nav.selectedTrigger) return;
      nav.selectedTrigger.setAttribute('aria-expanded', 'false');
      if(!bool) nav.selectedTrigger.focus();
      nav.selectedTrigger = false; 
    };
  
    function initAnchorEvents(nav) {
      nav.list.addEventListener('click', function(event){
        var anchor = event.target.closest('a[href^="#"]');
        if(!anchor || Util.hasClass(anchor, 'float-sidenav__link--selected')) return;
        if(nav.clickScrolling) { // a different link has already been clicked
          event.preventDefault();
          return;
        }
        // reset link apperance 
        nav.clickScrolling = true;
        resetAnchors(nav, anchor);
        closeFSideNav(nav, false, true);
        if(!canScroll()) window.dispatchEvent(new CustomEvent('scroll'));
      });
    };
  
    function canScroll() {
      var pageHeight = document.documentElement.offsetHeight,
        windowHeight = window.innerHeight,
        scrollPosition = window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0);
      
      return !(pageHeight - 2 <= windowHeight + scrollPosition);
    };
  
    function resetAnchors(nav, anchor) {
      if(!intersectionObserverSupported) return;
      for(var i = 0; i < nav.anchors.length; i++) Util.removeClass(nav.anchors[i], 'float-sidenav__link--selected');
      if(anchor) Util.addClass(anchor, 'float-sidenav__link--selected');
    };
  
    function initSectionScroll(nav) {
      // check when a new section enters the viewport
      var observer = new IntersectionObserver(
        function(entries, observer) { 
          entries.forEach(function(entry){
            var threshold = entry.intersectionRatio.toFixed(1);
            
            if(!nav.clickScrolling) { // do not update classes if user clicked on a link
              getVisibleSection(nav);
            }
  
            // if first section is not inside the viewport - reset anchors
            if(nav.sectionsContainer && entry.target == nav.sections[0] && threshold == 0 && nav.sections[0].getBoundingClientRect().top > 0) {
              setSectionsLimit(nav);
            }
          });
  
          // check if there's a selected dot and toggle the --on-target class from the nav
          Util.toggleClass(nav.element, 'float-sidenav--on-target', nav.list.getElementsByClassName('float-sidenav__link--selected').length != 0);
        }, 
        {
          rootMargin: "0px 0px -50% 0px"
        }
      );
  
      for(var i = 0; i < nav.sections.length; i++) {
        observer.observe(nav.sections[i]);
      }
  
      // detect when sections container is inside/outside the viewport
      if(nav.sectionsContainer) {
        var containerObserver = new IntersectionObserver(
          function(entries, observer) { 
            entries.forEach(function(entry){
              var threshold = entry.intersectionRatio.toFixed(1);
  
              if(entry.target.getBoundingClientRect().top < 0) {
                if(threshold == 0) {
                  setSectionsLimit(nav);
                } else {
                  activateLastSection(nav);
                }
              }
            });
          },
          {threshold: [0, 0.1, 1]}
        );
  
        containerObserver.observe(nav.sectionsContainer[0]);
      }
  
      // detect the end of scrolling -> reactivate IntersectionObserver on scroll
      nav.element.addEventListener('float-sidenav-scroll', function(event){
        if(!nav.clickScrolling) getVisibleSection(nav);
        nav.clickScrolling = false;
      });
    };
  
    function setSectionsLimit(nav) {
      if(!nav.clickScrolling) resetAnchors(nav, false);
      Util.removeClass(nav.element, 'float-sidenav--on-target');
    };
  
    function activateLastSection(nav) {
      Util.addClass(nav.element, 'float-sidenav--on-target');
      if(nav.list.getElementsByClassName('float-sidenav__link--selected').length == 0 ) {
        Util.addClass(nav.anchors[nav.anchors.length - 1], 'float-sidenav__link--selected');
      }
    };
  
    function getVisibleSection(nav) {
      if(nav.intervalID) return;
      nav.intervalID = setTimeout(function(){
        var halfWindowHeight = window.innerHeight/2,
        index = -1;
        for(var i = 0; i < nav.sections.length; i++) {
          var top = nav.sections[i].getBoundingClientRect().top;
          if(top < halfWindowHeight) index = i;
        }
        if(index > -1) {
          resetAnchors(nav, nav.anchors[index]);
        }
        nav.intervalID = false;
      }, 100);
    };
  
    //initialize the Side Nav objects
    var fixedNav = document.getElementsByClassName('js-float-sidenav'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
    
    var fixedNavArray = [];
  	if( fixedNav.length > 0 ) {
  		for( var i = 0; i < fixedNav.length; i++) {
  			(function(i){ fixedNavArray.push(new FSideNav(fixedNav[i])) ; })(i);
      }
      
      // listen to window scroll -> reset clickScrolling property
      var scrollId = false,
        customEvent = new CustomEvent('float-sidenav-scroll');
        
      window.addEventListener('scroll', function() {
        clearTimeout(scrollId);
        scrollId = setTimeout(doneScrolling, 100);
      });
  
      function doneScrolling() {
        for( var i = 0; i < fixedNavArray.length; i++) {
          (function(i){fixedNavArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  	}
  }());
  // File#: _2_footnotes
  // Usage: codyhouse.co/license
  (function() {
  	var Footnote = function(element) {
  		this.element = element;
  		this.link = this.element.getElementsByClassName('footnotes__back-link')[0];
  		this.contentLink = document.getElementById(this.link.getAttribute('href').replace('#', ''));
  		this.initFootnote();
  	};
  
  	Footnote.prototype.initFootnote = function() {
  		Util.setAttributes(this.contentLink, {
  			'aria-label': 'Footnote: '+this.element.getElementsByClassName('js-footnote__label')[0].textContent,
  			'data-tooltip-class': 'tooltip--lg tooltip--sticky',
  			'data-tooltip-describedby': 'false',
  			'title': this.getFootnoteContent(),
  		});
  		new Tooltip(this.contentLink);
  	};
  
  	Footnote.prototype.getFootnoteContent = function() {
  		var clone = this.element.cloneNode(true);
  		clone.removeChild(clone.getElementsByClassName('footnotes__back-link')[0]);
  		return clone.innerHTML;
  	};
  
  	//initialize the Footnote objects
  	var footnotes = document.getElementsByClassName('js-footnotes__item');
  	if( footnotes.length > 0 ) {
  		for( var i = 0; i < footnotes.length; i++) {
  			(function(i){new Footnote(footnotes[i]);})(i);
  		}
  	}
  }());
  // File#: _2_full-screen-select
  (function() {
  	var CustomSelect = function(element) {
  		this.element = element;
  		this.items = this.element.children;
  		initCustomSelect(this);
  	};
  
  	function initCustomSelect(select) {
  		// arrow navigation
  		select.element.addEventListener('keydown', function(event){
  			if( event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown' ) {
  				selectOption(select, 1); // go to next option
  			} else if( event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup' ) {
  				selectOption(select, -1); // go to prev option
  			}
  		});
  	};
  
  	function selectOption(select, direction) {
  		var focusElement = document.activeElement,
  			index = Util.getIndexInArray(select.items, focusElement.closest('li'));
  		if(index < 0) return;
  		index = index + direction;
  		if( index < 0 ) index = select.items.length - 1;
  		if( index >= select.items.length) index = 0;
  		Util.moveFocus(select.items[index].getElementsByTagName(focusElement.tagName)[0]);
  	};
  
  	//initialize the CustomSelect objects
  	var customSelect = document.getElementsByClassName('js-full-screen-select');
  	if( customSelect.length > 0 ) {
  		for( var i = 0; i < customSelect.length; i++) {
  			(function(i){new CustomSelect(customSelect[i]);})(i);
  		}
  	}
  }());
  // File#: _2_grid-switch
  // Usage: codyhouse.co/license
  (function() {
    var GridSwitch = function(element) {
      this.element = element;
      this.controller = this.element.getElementsByClassName('js-grid-switch__controller')[0];
      this.items = this.element.getElementsByClassName('js-grid-switch__item');
      this.contentElements = this.element.getElementsByClassName('js-grid-switch__content');
      // store custom classes
      this.classList = [[this.element.getAttribute('data-gs-item-class-1'), this.element.getAttribute('data-gs-content-class-1')], [this.element.getAttribute('data-gs-item-class-2'), this.element.getAttribute('data-gs-content-class-2')]];
      initGridSwitch(this);
    };
  
    function initGridSwitch(element) {
      // get selected state and apply style
      var selectedInput = element.controller.querySelector('input:checked');
      if(selectedInput) {
        setGridAppearance(element, selectedInput.value);
      }
      // reveal grid
      Util.addClass(element.element, 'grid-switch--is-visible');
      // a new layout has been selected 
      element.controller.addEventListener('change', function(event) {
        setGridAppearance(element, event.target.value);
      });
    };
  
    function setGridAppearance(element, value) {
      var newStatus = parseInt(value) - 1,
        oldStatus = newStatus == 1 ? 0 : 1;
        
      for(var i = 0; i < element.items.length; i++) {
        Util.removeClass(element.items[i], element.classList[oldStatus][0]);
        Util.removeClass(element.contentElements[i], element.classList[oldStatus][1]);
        Util.addClass(element.items[i], element.classList[newStatus][0]);
        Util.addClass(element.contentElements[i], element.classList[newStatus][1]);
      }
    };
  
    //initialize the GridSwitch objects
  	var gridSwitch = document.getElementsByClassName('js-grid-switch');
  	if( gridSwitch.length > 0 ) {
  		for( var i = 0; i < gridSwitch.length; i++) {
  			(function(i){new GridSwitch(gridSwitch[i]);})(i);
      }
    }
  }());
  // File#: _2_image-comparison-slider
  // Usage: codyhouse.co/license
  (function() {
    var ComparisonSlider = function(element) {
      this.element = element;
      this.modifiedImg = this.element.getElementsByClassName('js-compare-slider__img--modified')[0];
      this.handle = this.element.getElementsByClassName('js-compare-slider__handle')[0];
      this.keyboardHandle = this.element.getElementsByClassName('js-compare-slider__input-handle')[0];
      this.captions = this.element.getElementsByClassName('js-compare-slider__caption');
      // drag
      this.dragStart = false;
      this.animating = false;
      this.leftPosition = 50;
      // store container width
      this.sliderWidth = getSliderWidth(this);
      initComparisonSlider(this);
    };
  
    function getSliderWidth(slider) {
      return slider.element.offsetWidth;
    };
  
    function initComparisonSlider(slider) {
      // initial animation
      if(reducedMotion) { // do not animate slider elements
        Util.addClass(slider.element, 'compare-slider--reduced-motion compare-slider--in-viewport');
      } else if(intersectionObserverSupported) { // reveal slider elements when it enters the viewport
        var observer = new IntersectionObserver(sliderObserve.bind(slider), { threshold: [0, 0.3] });
        observer.observe(slider.element);
        modifiedImgAnimation(slider);
      } else { // reveal slider elements right away
        Util.addClass(slider.element, 'compare-slider--in-viewport');
        modifiedImgAnimation(slider);
      }
      // init drag functionality
      new SwipeContent(slider.element);
      slider.element.addEventListener('dragStart', function(event){
        if(!event.detail.origin.closest('.js-compare-slider__handle')) return;
        Util.addClass(slider.element, 'compare-slider--is-dragging');
        if(!slider.dragStart) {
          slider.dragStart = event.detail.x;
          detectDragEnd(slider);
        }
      });
      // slider.element.addEventListener('dragging', function(event){
      slider.element.addEventListener('mousemove', function(event){
        sliderDragging(slider, event)
      });
      slider.element.addEventListener('touchmove', function(event){
        sliderDragging(slider, event)
      });
  
      // detect mouse leave
      slider.element.addEventListener('mouseleave', function(event){
        sliderResetDragging(slider, event);
      });
      slider.element.addEventListener('touchend', function(event){
        sliderResetDragging(slider, event);
      });
  
      // on resize -> update slider width
      window.addEventListener('resize', function(){
        slider.sliderWidth = getSliderWidth(slider);
      });
  
      // detect change in keyboardHandle input -> allow keyboard navigation
      slider.keyboardHandle.addEventListener('change', function(event){
        slider.leftPosition = Number(slider.keyboardHandle.value);
        updateCompareSlider(slider, 0);
      });
    };
  
    function modifiedImgAnimation(slider) {
      // make sure modified img animation runs only one time
      slider.modifiedImg.addEventListener('animationend', function cb() {
        slider.modifiedImg.removeEventListener('animationend', cb);
        slider.modifiedImg.style.animation = 'none';
      });
    };
  
    function sliderDragging(slider, event) {
      if(!slider.dragStart) return;
      var pageX = event.pageX || event.touches[0].pageX;
      if(slider.animating || Math.abs(pageX - slider.dragStart) < 5) return;
      slider.animating = true;
      updateCompareSlider(slider, pageX - slider.dragStart);
      slider.dragStart = pageX;
    };
  
    function sliderResetDragging(slider, event) {
      if(!slider.dragStart) return;
      if(event.pageX < slider.element.offsetLeft) {
        slider.leftPosition = 0;
        updateCompareSlider(slider, 0);
      }
      if(event.pageX > slider.element.offsetLeft + slider.element.offsetWidth) {
        slider.leftPosition = 100;
        updateCompareSlider(slider, 0);
      }
    };
  
    function sliderObserve(entries, observer) {
      if(entries[0].intersectionRatio.toFixed(1) > 0) { // reveal slider elements when in viewport
        Util.addClass(this.element, 'compare-slider--in-viewport');
        observer.unobserve(this.element);
      }
    };
  
    function detectDragEnd(slider) {
      document.addEventListener('click', function cb(event){
        document.removeEventListener('click', cb);
        Util.removeClass(slider.element, 'compare-slider--is-dragging');
        updateCompareSlider(slider, event.detail.x - slider.dragStart);
        slider.dragStart = false;
      });
    };
  
    function updateCompareSlider(slider, delta) {
      var percentage = (delta*100/slider.sliderWidth);
      if(isNaN(percentage)) return;
      slider.leftPosition = Number((slider.leftPosition + percentage).toFixed(2));
      if(slider.leftPosition < 0) slider.leftPosition = 0;
      if(slider.leftPosition > 100) slider.leftPosition = 100; 
      // update slider elements -> modified img width + handle position + input element (keyboard accessibility)
      slider.keyboardHandle.value = slider.leftPosition;
      slider.handle.style.left = slider.leftPosition + '%';
      slider.modifiedImg.style.width = slider.leftPosition + '%'; 
      updateCompareLabels(slider);
      slider.animating = false;
    };
  
    function updateCompareLabels(slider) { // update captions visibility
      for(var i = 0; i < slider.captions.length; i++) {
        var delta = ( i == 0 ) 
          ? slider.captions[i].offsetLeft - slider.modifiedImg.offsetLeft - slider.modifiedImg.offsetWidth
          : slider.modifiedImg.offsetLeft + slider.modifiedImg.offsetWidth - slider.captions[i].offsetLeft - slider.captions[i].offsetWidth;
        Util.toggleClass(slider.captions[i], 'compare-slider__caption--is-hidden', delta < 10);
      }
    };
  
    window.ComparisonSlider = ComparisonSlider;
    
    //initialize the ComparisonSlider objects
    var comparisonSliders = document.getElementsByClassName('js-compare-slider'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype),
      reducedMotion = Util.osHasReducedMotion();
  	if( comparisonSliders.length > 0 ) {
  		for( var i = 0; i < comparisonSliders.length; i++) {
  			(function(i){
          new ComparisonSlider(comparisonSliders[i]);
        })(i);
      }
  	}
  }());
  // File#: _2_points-of-interest
  // Usage: codyhouse.co/license
  (function() {
    function initPoi(element) {
      element.addEventListener('click', function(event){
        var poiItem = event.target.closest('.js-poi__item');
        if(poiItem) Util.addClass(poiItem, 'poi__item--visited');
      });
    };
  
    var poi = document.getElementsByClassName('js-poi');
    for(var i = 0; i < poi.length; i++) {
      (function(i){initPoi(poi[i]);})(i);
    }
  }());
  // File#: _2_image-zoom
  // Usage: codyhouse.co/license
  
  (function() {
    var ImageZoom = function(element, index) {
      this.element = element;
      this.lightBoxId = 'img-zoom-lightbox--'+index;
      this.imgPreview = this.element.getElementsByClassName('js-image-zoom__preview')[0];
      
      initImageZoomHtml(this); // init markup
      
      this.lightbox = document.getElementById(this.lightBoxId);
      this.imgEnlg = this.lightbox.getElementsByClassName('js-image-zoom__fw')[0];
      this.input = this.element.getElementsByClassName('js-image-zoom__input')[0];
      this.animate = this.element.getAttribute('data-morph') != 'off';
      
      initImageZoomEvents(this); //init events
    };
  
    function initImageZoomHtml(imageZoom) {
      // get zoomed image url
      var url = imageZoom.element.getAttribute('data-img');
      if(!url) url = imageZoom.imgPreview.getAttribute('src');
  
      var lightBox = document.createElement('div');
      Util.setAttributes(lightBox, {class: 'image-zoom__lightbox js-image-zoom__lightbox', id: imageZoom.lightBoxId, 'aria-hidden': 'true'});
      lightBox.innerHTML = '<img src="'+url+'" class="js-image-zoom__fw"></img>';
      document.body.appendChild(lightBox);
      
      var keyboardInput = '<input aria-hidden="true" type="checkbox" class="image-zoom__input js-image-zoom__input"></input>';
      imageZoom.element.insertAdjacentHTML('afterbegin', keyboardInput);
  
    };
  
    function initImageZoomEvents(imageZoom) {
      // toggle lightbox on click
      imageZoom.imgPreview.addEventListener('click', function(event){
        toggleFullWidth(imageZoom, true);
        imageZoom.input.checked = true;
      });
      imageZoom.lightbox.addEventListener('click', function(event){
        toggleFullWidth(imageZoom, false);
        imageZoom.input.checked = false;
      });
      // detect swipe down to close lightbox
      new SwipeContent(imageZoom.lightbox);
      imageZoom.lightbox.addEventListener('swipeDown', function(event){
        toggleFullWidth(imageZoom, false);
        imageZoom.input.checked = false;
      });
      // keyboard accessibility
      imageZoom.input.addEventListener('change', function(event){
        toggleFullWidth(imageZoom, imageZoom.input.checked);
      });
      imageZoom.input.addEventListener('keydown', function(event){
        if( (event.keyCode && event.keyCode == 13) || (event.key && event.key.toLowerCase() == 'enter') ) {
          imageZoom.input.checked = !imageZoom.input.checked;
          toggleFullWidth(imageZoom, imageZoom.input.checked);
        }
      });
    };
  
    function toggleFullWidth(imageZoom, bool) {
      if(animationSupported && imageZoom.animate) { // start expanding animation
        window.requestAnimationFrame(function(){
          animateZoomImage(imageZoom, bool);
        });
      } else { // show lightbox without animation
        Util.toggleClass(imageZoom.lightbox, 'image-zoom__lightbox--is-visible', bool);
      }
    };
  
    function animateZoomImage(imageZoom, bool) {
      // get img preview position and dimension for the morphing effect
      var rect = imageZoom.imgPreview.getBoundingClientRect(),
        finalWidth = imageZoom.lightbox.getBoundingClientRect().width;
      var init = (bool) ? [rect.top, rect.left, rect.width] : [0, 0, finalWidth],
        final = (bool) ? [-rect.top, -rect.left, parseFloat(finalWidth/rect.width)] : [rect.top + imageZoom.lightbox.scrollTop, rect.left, parseFloat(rect.width/finalWidth)];
      
      if(bool) {
        imageZoom.imgEnlg.setAttribute('style', 'top: '+init[0]+'px; left:'+init[1]+'px; width:'+init[2]+'px;');
      }
      
      // show modal
      Util.removeClass(imageZoom.lightbox, 'image-zoom__lightbox--no-transition');
      Util.addClass(imageZoom.lightbox, 'image-zoom__lightbox--is-visible');
  
      imageZoom.imgEnlg.addEventListener('transitionend', function cb(event){ // reset elements once animation is over
        if(!bool) Util.removeClass(imageZoom.lightbox, 'image-zoom__lightbox--is-visible');
        Util.addClass(imageZoom.lightbox, 'image-zoom__lightbox--no-transition');
        imageZoom.imgEnlg.removeAttribute('style');
        imageZoom.imgEnlg.removeEventListener('transitionend', cb);
      });
      
      // animate image and bg
      imageZoom.imgEnlg.style.transform = 'translateX('+final[1]+'px) translateY('+final[0]+'px) scale('+final[2]+')';
      Util.toggleClass(imageZoom.lightbox, 'image-zoom__lightbox--animate-bg', bool);
    };
  
    // init ImageZoom object
    var imageZoom = document.getElementsByClassName('js-image-zoom'),
      animationSupported = window.requestAnimationFrame && !Util.osHasReducedMotion();
    if( imageZoom.length > 0 ) {
      var imageZoomArray = [];
      for( var i = 0; i < imageZoom.length; i++) {
        imageZoomArray.push(new ImageZoom(imageZoom[i], i));
      }
  
      // close Zoom Image lightbox on Esc
      window.addEventListener('keydown', function(event){
        if((event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'esc')) {
          for( var i = 0; i < imageZoomArray.length; i++) {
            imageZoomArray[i].input.checked = false;
            if(Util.hasClass(imageZoomArray[i].lightbox, 'image-zoom__lightbox--is-visible')) toggleFullWidth(imageZoomArray[i], false);
          }
        }
      });
    }
  }());
  // File#: _2_main-header-v3
  // Usage: codyhouse.co/license
  (function() {
  	var mainHeader = document.getElementsByClassName('js-header-v3');
  	if(mainHeader.length > 0) {
  		var menuTrigger = mainHeader[0].getElementsByClassName('js-toggle-menu')[0],
  			searchTrigger = mainHeader[0].getElementsByClassName('js-toggle-search'),
  			navigation = mainHeader[0].getElementsByClassName('header-v3__nav')[0];
  
  		// we'll use these to store the node that needs to receive focus when the mobile menu/search input are closed 
  		var focusSearch = false,
  			focusMenu = false;
  			
  		// set delays for list items inside navigation -> mobile animation
  		var navItems = Util.getChildrenByClassName(navigation.getElementsByClassName('header-v3__nav-list')[0], 'header-v3__nav-item');
  		for(var i = 0; i < navItems.length; i++) {
  			setTransitionDelay(navItems[i], i);
  		}
  		// toggle navigation on mobile
  		menuTrigger.addEventListener('switch-icon-clicked', function(event){ // toggle menu visibility an small devices
  			toggleNavigation(event.detail);
  		});
  		// toggle search on desktop
  		if(searchTrigger.length > 0) {
  			searchTrigger[0].addEventListener('switch-icon-clicked', function(event){ // toggle menu visibility an small devices
  				toggleSearch(event.detail);
  			});
  		}
  		
  		window.addEventListener('keyup', function(event){
  			// listen for esc key events
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger)) {
  					focusMenu = menuTrigger; // move focus to menu trigger when menu is close
  					menuTrigger.click();
  				}
  				// close search if open
  				if(searchTrigger.length > 0 && searchTrigger[0].getAttribute('aria-expanded') == 'true' && isVisible(searchTrigger[0])) {
  					focusSearch = searchTrigger[0]; // move focus to search trigger when search is close
  					searchTrigger[0].click();
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger) && !document.activeElement.closest('.js-header-v3')) menuTrigger.click();
  			}
  		});
  
  		// listen for resize
  		var resizingId = false;
  		window.addEventListener('resize', function() {
  			clearTimeout(resizingId);
  			resizingId = setTimeout(doneResizing, 300);
  		});
  
  		function toggleNavigation(bool) {
  			Util.addClass(navigation, 'header-v3__nav--is-visible');
  			Util.addClass(menuTrigger, 'switch-icon--disabled');
  			menuTrigger.setAttribute('aria-expanded', bool);
  			// animate navigation height
  			var finalHeight = bool ? window.innerHeight: 0,
  				initHeight = bool ? 0 : window.innerHeight; 
  			navigation.style.height = initHeight+'px';
  
  			setTimeout(function(){
  				navigation.style.height = finalHeight+'px';
  				Util.toggleClass(navigation, 'header-v3__nav--animate-children', bool);
  			}, 50);
  
  			navigation.addEventListener('transitionend', function cb(event){
  				if (event.propertyName !== 'height') return;
  				if(finalHeight > 0) {
  					var firstFocusableElement = getMenuFirstFocusable();
  					firstFocusableElement.focus(); // move focus to first focusable element
  				} else {
  					Util.removeClass(navigation, 'header-v3__nav--is-visible header-v3__nav--animate-children');
  					if(focusMenu) { // we may need to move the focus to a new element
  						focusMenu.focus();
  						focusMenu = false;
  					}
  				}
  				
  				navigation.removeEventListener('transitionend', cb);
  				navigation.removeAttribute('style');
  				Util.removeClass(menuTrigger, 'switch-icon--disabled');
  			});
  			// toggle expanded class to header
  			Util.toggleClass(mainHeader[0], 'header-v3--expanded', bool);
  		};
  
  		function toggleSearch(bool){
  			Util.addClass(searchTrigger[0], 'switch-icon--disabled');
  			Util.toggleClass(mainHeader[0], 'header-v3--show-search', bool);
  			searchTrigger[0].setAttribute('aria-expanded', bool);
  			mainHeader[0].addEventListener('transitionend', function cb(){
  				mainHeader[0].removeEventListener('transitionend', cb);
  				Util.removeClass(searchTrigger[0], 'switch-icon--disabled');
  				if(bool) mainHeader[0].getElementsByClassName('header-v3__nav-item--search-form')[0].getElementsByTagName('input')[0].focus();
  				else if(focusSearch) {// move focus to a new element when closing the search
  					focusSearch.focus();
  					focusSearch = false;
  				}
  			});
  
  			// toggle expanded class to header
  			Util.toggleClass(mainHeader[0], 'header-v3--expanded', bool);
  		};
  
  		function doneResizing() {
  			// check if main nav is visible (small devices only)
  			if( !isVisible(menuTrigger) && menuTrigger.getAttribute('aria-expanded') == 'true') menuTrigger.click();
  			// check if search input is visible
  			if( searchTrigger.length > 0 && !isVisible(searchTrigger[0]) && searchTrigger[0].getAttribute('aria-expanded') == 'true') searchTrigger[0].click();
  		};
  
  		function getMenuFirstFocusable() {
  			var focusableEle = mainHeader[0].getElementsByClassName('header-v3__nav')[0].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary'),
  				firstFocusable = false;
  			for(var i = 0; i < focusableEle.length; i++) {
  				if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
  					firstFocusable = focusableEle[i];
  					break;
  				}
  			}
  
  			return firstFocusable;
  		};
  
  		function setTransitionDelay(element, index) {
  			element.style.transitionDelay = parseFloat((index/20) + 0.1).toFixed(2)+'s';
  		};
  
  		function isVisible(element) {
  			return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  		};
  	}
  }());
  // File#: _2_menu-bar
  // Usage: codyhouse.co/license
  (function() {
    var MenuBar = function(element) {
      this.element = element;
      this.items = Util.getChildrenByClassName(this.element, 'menu-bar__item');
      this.mobHideItems = this.element.getElementsByClassName('menu-bar__item--hide');
      this.moreItemsTrigger = this.element.getElementsByClassName('js-menu-bar__trigger');
      initMenuBar(this);
    };
  
    function initMenuBar(menu) {
      setMenuTabIndex(menu); // set correct tabindexes for menu item
      initMenuBarMarkup(menu); // create additional markup
      checkMenuLayout(menu); // set menu layout
      Util.addClass(menu.element, 'menu-bar--loaded'); // reveal menu
  
      // custom event emitted when window is resized
      menu.element.addEventListener('update-menu-bar', function(event){
        checkMenuLayout(menu);
        if(menu.menuInstance) menu.menuInstance.toggleMenu(false, false); // close dropdown
      });
  
      // keyboard events 
      // open dropdown when pressing Enter on trigger element
      if(menu.moreItemsTrigger.length > 0) {
        menu.moreItemsTrigger[0].addEventListener('keydown', function(event) {
          if( (event.keyCode && event.keyCode == 13) || (event.key && event.key.toLowerCase() == 'enter') ) {
            if(!menu.menuInstance) return;
            menu.menuInstance.selectedTrigger = menu.moreItemsTrigger[0];
            menu.menuInstance.toggleMenu(!Util.hasClass(menu.subMenu, 'menu--is-visible'), true);
          }
        });
  
        // close dropdown on esc
        menu.subMenu.addEventListener('keydown', function(event) {
          if((event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape')) { // close submenu on esc
            if(menu.menuInstance) menu.menuInstance.toggleMenu(false, true);
          }
        });
      }
      
      // navigate menu items using left/right arrows
      menu.element.addEventListener('keydown', function(event) {
        if( (event.keyCode && event.keyCode == 39) || (event.key && event.key.toLowerCase() == 'arrowright') ) {
          navigateItems(menu.items, event, 'next');
        } else if( (event.keyCode && event.keyCode == 37) || (event.key && event.key.toLowerCase() == 'arrowleft') ) {
          navigateItems(menu.items, event, 'prev');
        }
      });
    };
  
    function setMenuTabIndex(menu) { // set tabindexes for the menu items to allow keyboard navigation
      var nextItem = false;
      for(var i = 0; i < menu.items.length; i++ ) {
        if(i == 0 || nextItem) menu.items[i].setAttribute('tabindex', '0');
        else menu.items[i].setAttribute('tabindex', '-1');
        if(i == 0 && menu.moreItemsTrigger.length > 0) nextItem = true;
        else nextItem = false;
      }
    };
  
    function initMenuBarMarkup(menu) {
      if(menu.mobHideItems.length == 0 ) { // no items to hide on mobile - remove trigger
        if(menu.moreItemsTrigger.length > 0) menu.element.removeChild(menu.moreItemsTrigger[0]);
        return;
      }
  
      if(menu.moreItemsTrigger.length == 0) return;
  
      // create the markup for the Menu element
      var content = '';
      menu.menuControlId = 'submenu-bar-'+Date.now();
      for(var i = 0; i < menu.mobHideItems.length; i++) {
        var item = menu.mobHideItems[i].cloneNode(true),
          svg = item.getElementsByTagName('svg')[0],
          label = item.getElementsByClassName('menu-bar__label')[0];
  
        svg.setAttribute('class', 'icon menu__icon');
        content = content + '<li role="menuitem"><span class="menu__content js-menu__content">'+svg.outerHTML+'<span>'+label.innerHTML+'</span></span></li>';
      }
  
      Util.setAttributes(menu.moreItemsTrigger[0], {'role': 'button', 'aria-expanded': 'false', 'aria-controls': menu.menuControlId, 'aria-haspopup': 'true'});
  
      var subMenu = document.createElement('menu'),
        customClass = menu.element.getAttribute('data-menu-class');
      Util.setAttributes(subMenu, {'id': menu.menuControlId, 'class': 'menu js-menu '+customClass});
      subMenu.innerHTML = content;
      document.body.appendChild(subMenu);
  
      menu.subMenu = subMenu;
      menu.subItems = subMenu.getElementsByTagName('li');
  
      menu.menuInstance = new Menu(menu.subMenu); // this will handle the dropdown behaviour
    };
  
    function checkMenuLayout(menu) { // switch from compressed to expanded layout and viceversa
      var layout = getComputedStyle(menu.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(menu.element, 'menu-bar--collapsed', layout == 'collapsed');
    };
  
    function navigateItems(list, event, direction, prevIndex) { // keyboard navigation among menu items
      event.preventDefault();
      var index = (typeof prevIndex !== 'undefined') ? prevIndex : Util.getIndexInArray(list, event.target),
        nextIndex = direction == 'next' ? index + 1 : index - 1;
      if(nextIndex < 0) nextIndex = list.length - 1;
      if(nextIndex > list.length - 1) nextIndex = 0;
      // check if element is visible before moving focus
      (list[nextIndex].offsetParent === null) ? navigateItems(list, event, direction, nextIndex) : Util.moveFocus(list[nextIndex]);
    };
  
    function checkMenuClick(menu, target) { // close dropdown when clicking outside the menu element
      if(menu.menuInstance && !menu.moreItemsTrigger[0].contains(target) && !menu.subMenu.contains(target)) menu.menuInstance.toggleMenu(false, false);
    };
  
    // init MenuBars objects
    var menuBars = document.getElementsByClassName('js-menu-bar');
    if( menuBars.length > 0 ) {
      var j = 0,
        menuBarArray = [];
      for( var i = 0; i < menuBars.length; i++) {
        var beforeContent = getComputedStyle(menuBars[i], ':before').getPropertyValue('content');
        if(beforeContent && beforeContent !='' && beforeContent !='none') {
          (function(i){menuBarArray.push(new MenuBar(menuBars[i]));})(i);
          j = j + 1;
        }
      }
      
      if(j > 0) {
        var resizingId = false,
          customEvent = new CustomEvent('update-menu-bar');
        // update Menu Bar layout on resize  
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 150);
        });
  
        // close menu when clicking outside it
        window.addEventListener('click', function(event){
          menuBarArray.forEach(function(element){
            checkMenuClick(element, event.target);
          });
        });
  
        function doneResizing() {
          for( var i = 0; i < menuBars.length; i++) {
            (function(i){menuBars[i].dispatchEvent(customEvent)})(i);
          };
        };
      }
    }
  }());
  // File#: _2_modal-video
  // Usage: codyhouse.co/license
  (function() {
  	var ModalVideo = function(element) {
  		this.element = element;
  		this.modalContent = this.element.getElementsByClassName('js-modal-video__content')[0];
  		this.media = this.element.getElementsByClassName('js-modal-video__media')[0];
  		this.contentIsIframe = this.media.tagName.toLowerCase() == 'iframe';
  		this.modalIsOpen = false;
  		this.initModalVideo();
  	};
  
  	ModalVideo.prototype.initModalVideo = function() {
  		var self = this;
  		// reveal modal content when iframe is ready
  		this.addLoadListener();
  		// listen for the modal element to be open -> set new iframe src attribute
  		this.element.addEventListener('modalIsOpen', function(event){
  			self.modalIsOpen = true;
  			self.media.setAttribute('src', event.detail.closest('[aria-controls]').getAttribute('data-url'));
  		});
  		// listen for the modal element to be close -> reset iframe and hide modal content
  		this.element.addEventListener('modalIsClose', function(event){
  			self.modalIsOpen = false;
  			Util.addClass(self.element, 'modal--is-loading');
  			self.media.setAttribute('src', '');
  		});
  	};
  
  	ModalVideo.prototype.addLoadListener = function() {
  		var self = this;
  		if(this.contentIsIframe) {
  			this.media.onload = function () {
  				self.revealContent();
  			};
  		} else {
  			this.media.addEventListener('loadedmetadata', function(){
  				self.revealContent();
  			});
  		}
  		
  	};
  
  	ModalVideo.prototype.revealContent = function() {
  		if( !this.modalIsOpen ) return;
  		Util.removeClass(this.element, 'modal--is-loading');
  		this.contentIsIframe ? this.media.contentWindow.focus() : this.media.focus();
  	};
  
  	//initialize the ModalVideo objects
  	var modalVideos = document.getElementsByClassName('js-modal-video__media');
  	if( modalVideos.length > 0 ) {
  		for( var i = 0; i < modalVideos.length; i++) {
  			(function(i){new ModalVideo(modalVideos[i].closest('.js-modal'));})(i);
  		}
  	}
  }());
  // File#: _2_morphing-image-modal
  // Usage: codyhouse.co/license
  (function() {
    var MorphImgModal = function(opts) {
      this.options = Util.extend(MorphImgModal.defaults, opts);
      this.element = this.options.element;
      this.modalId = this.element.getAttribute('id');
      this.triggers = document.querySelectorAll('[aria-controls="'+this.modalId+'"]');
      this.selectedImg = false;
      // store morph elements
      this.morphBg = document.getElementsByClassName('js-morph-img-bg');
      this.morphImg = document.getElementsByClassName('js-morph-img-clone');
      // store modal content
      this.modalContent = this.element.getElementsByClassName('js-morph-img-modal__content');
      this.modalImg = this.element.getElementsByClassName('js-morph-img-modal__img');
      this.modalInfo = this.element.getElementsByClassName('js-morph-img-modal__info');
      // store close btn element
      this.modalCloseBtn = document.getElementsByClassName('js-morph-img-close-btn');
      // animation duration
      this.animationDuration = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--morph-img-modal-transition-duration'))*1000 || 300;
      // morphing animation should run
      this.animating = false;
      this.reset = false;
      initMorphModal(this);
    };
  
    function initMorphModal(element) {
      if(element.morphImg.length < 1) return;
      element.morphEl = element.morphImg[0].getElementsByTagName('image');
      element.morphRect  = element.morphImg[0].getElementsByTagName('rect');
      initMorphModalMarkup(element);
      initMorphModalEvents(element);
    };
  
    function initMorphModalMarkup(element) {
      // append the clip path + <image> elements to use to morph the image
      element.morphImg[0].innerHTML = '<svg><defs><clipPath id="'+element.modalId+'-clip"><rect/></clipPath></defs><image height="100%" width="100%" clip-path="url(#'+element.modalId+'-clip)"></image></svg>';
    };
  
    function initMorphModalEvents(element) {
      // morph modal was open
      element.element.addEventListener('modalIsOpen', function(event){
        var target = event.detail.closest('[aria-controls="'+element.modalId+'"]');
        setModalImg(element, target);
        setModalContent(element, target);
        toggleModalCloseBtn(element, true);
      });
  
      // morph modal was closed
      element.element.addEventListener('modalIsClose', function(event){
        element.reset = false;
        element.animating = true;
        Util.addClass(element.modalContent[0], 'opacity-0');
        animateImg(element, false, function() {
          if(element.reset) return; // user opened a new modal before the animation was complete - no need to reset the modal
          element.selectedImg = false;
          resetMorphModal(element, false);
          element.animating = false;
        });
        toggleModalCloseBtn(element, false);
      });
  
      // close modal clicking on close btn
      if(element.modalCloseBtn.length > 0) {
        element.modalCloseBtn[0].addEventListener('click', function(event) {
          element.element.click();
        });
      }
    };
  
    function setModalImg(element, target) {
      if(!target) return;
      element.selectedImg = (target.tagName.toLowerCase() == 'img') ? target : target.querySelector('img');
      var src = element.selectedImg.getAttribute('data-modal-src') || element.selectedImg.getAttribute('src');
      // update url modal image + morph
      if(element.modalImg.length > 0) element.modalImg[0].setAttribute('src', src);
      Util.setAttributes(element.morphEl[0], {'xlink:href': src, 'href': src});
      element.reset = false;
      element.animating = true;  
      // wait for image to be loaded, then animate
      loadImage(element, src, function() {
        animateImg(element, true, function() {
          if(element.reset) return; // user closed the modal before the animation was complete - no need to reset the modal
          resetMorphModal(element, true);
          element.animating = false;
        });
      });
    };
  
    function loadImage(element, src, cb) {
      var image = new Image();
      var loaded = false;
      image.onload = function () {
        if(loaded) return;
        cb();
      }
      image.src = src;
      if(image.complete) {
        loaded = true;
        cb();
      }
    };
  
    function setModalContent(element, target) {
      // load the modal info details - using the searchData custom function the user defines
      if(element.modalInfo.length < 1) return;
      element.options.searchData(target, function(data){
        element.modalInfo[0].innerHTML = data;
      });
    };
  
    function toggleModalCloseBtn(element, bool) {
      if(element.modalCloseBtn.length > 0) {
        Util.toggleClass(element.modalCloseBtn[0], 'morph-img-close-btn--is-visible', bool);
      }
    };
  
    function animateImg(element, isOpening, cb) {
      Util.removeClass(element.morphImg[0], 'is-hidden');
  
      var galleryImgRect = element.selectedImg.getBoundingClientRect(),
        modalImgRect = element.modalImg[0].getBoundingClientRect();
  
      runClipAnimation(element, galleryImgRect, modalImgRect, isOpening, cb);
    };
  
    function runClipAnimation(element, startRect, endRect, isOpening, cb) {
      // retrieve all animation params
      // main element animation (<div>)
      var elInitHeight = startRect.height,
        elIntWidth = startRect.width,
        elInitTop = startRect.top,
        elInitLeft = startRect.left;
      
      var elScale = Math.max(endRect.height/startRect.height, endRect.width/startRect.width);
  
      var elTranslateX = endRect.left - startRect.left + (endRect.width - startRect.width*elScale)*0.5,
        elTranslateY = endRect.top - startRect.top + (endRect.height - startRect.height*elScale)*0.5;
  
      // clip <rect> animation
      var rectScaleX = endRect.width/(startRect.width*elScale),
        rectScaleY = endRect.height/(startRect.height*elScale);
  
      element.morphImg[0].style = 'height:'+elInitHeight+'px; width:'+elIntWidth+'px; top:'+elInitTop+'px; left:'+elInitLeft+'px;';
  
      element.morphRect[0].setAttribute('transform', 'scale('+1+','+1+')');
  
      // init morph bg
      element.morphBg[0].style.height = startRect.height + 'px';
      element.morphBg[0].style.width = startRect.width + 'px';
      element.morphBg[0].style.top = startRect.top + 'px';
      element.morphBg[0].style.left = startRect.left + 'px';
  
      Util.removeClass(element.morphBg[0], 'is-hidden');
      
      animateRectScale(element, elInitHeight, elIntWidth, elScale, elTranslateX, elTranslateY, rectScaleX, rectScaleY, isOpening, cb);
    };
  
    function animateRectScale(element, height, width, elScale, elTranslateX, elTranslateY, rectScaleX, rectScaleY, isOpening, cb) {
      var isMobile = getComputedStyle(element.element, ':before').getPropertyValue('content').replace(/\'|"/g, '') == 'mobile';
  
      var currentTime = null,
        duration =  element.animationDuration;
  
      var startRect = element.selectedImg.getBoundingClientRect(),
        endRect = element.modalContent[0].getBoundingClientRect();
      
      var scaleX = endRect.width/startRect.width,
        scaleY = endRect.height/startRect.height;
    
      var translateX = endRect.left - startRect.left,
        translateY = endRect.top - startRect.top;
  
      var animateScale = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        
        // main element values
        if(isOpening) {
          var elScalePr = Math.easeOutQuart(progress, 1, elScale - 1, duration),
          elTransXPr = Math.easeOutQuart(progress, 0, elTranslateX, duration),
          elTransYPr = Math.easeOutQuart(progress, 0, elTranslateY, duration);
        } else {
          var elScalePr = Math.easeOutQuart(progress, elScale, 1 - elScale, duration),
          elTransXPr = Math.easeOutQuart(progress, elTranslateX, - elTranslateX, duration),
          elTransYPr = Math.easeOutQuart(progress, elTranslateY, - elTranslateY, duration);
        }
        
        // rect values
        if(isOpening) {
          var rectScaleXPr = Math.easeOutQuart(progress, 1, rectScaleX - 1, duration),
            rectScaleYPr = Math.easeOutQuart(progress, 1, rectScaleY - 1, duration);
        } else {
          var rectScaleXPr = Math.easeOutQuart(progress, rectScaleX,  1 - rectScaleX, duration),
            rectScaleYPr = Math.easeOutQuart(progress, rectScaleY, 1 - rectScaleY, duration);
        }
  
        element.morphImg[0].style.transform = 'translateX('+elTransXPr+'px) translateY('+elTransYPr+'px) scale('+elScalePr+')';
  
        element.morphRect[0].setAttribute('transform', 'translate('+(width/2)*(1 - rectScaleXPr)+' '+(height/2)*(1 - rectScaleYPr)+') scale('+rectScaleXPr+','+rectScaleYPr+')');
  
        if(isOpening) {
          var valScaleX = Math.easeOutQuart(progress, 1, (scaleX - 1), duration),
            valScaleY = isMobile ? Math.easeOutQuart(progress, 1, (scaleY - 1), duration): rectScaleYPr*elScalePr,
            valTransX = Math.easeOutQuart(progress, 0, translateX, duration),
            valTransY = isMobile ? Math.easeOutQuart(progress, 0, translateY, duration) : elTransYPr + (elScalePr*height - rectScaleYPr*elScalePr*height)/2;
        } else {
          var valScaleX = Math.easeOutQuart(progress, scaleX, 1 - scaleX, duration),
            valScaleY = isMobile ? Math.easeOutQuart(progress, scaleY, 1 - scaleY, duration) : rectScaleYPr*elScalePr,
            valTransX = Math.easeOutQuart(progress, translateX, - translateX, duration),
            valTransY = isMobile ? Math.easeOutQuart(progress, translateY, - translateY, duration) : elTransYPr + (elScalePr*height - rectScaleYPr*elScalePr*height)/2;
        }
  
        // morph bg
        element.morphBg[0].style.transform = 'translateX('+valTransX+'px) translateY('+valTransY+'px) scale('+valScaleX+','+valScaleY+')';
  
        if(progress < duration) {
          window.requestAnimationFrame(animateScale);
        } else if(cb) {
          cb();
        }
      };
      
      window.requestAnimationFrame(animateScale);
    };
    
    function resetMorphModal(element, isOpening) {
      // reset modal at the end of an opening/closing animation
      Util.toggleClass(element.modalContent[0], 'opacity-0', !isOpening);
      Util.toggleClass(element.modalInfo[0], 'opacity-0', !isOpening);
      Util.addClass(element.morphBg[0], 'is-hidden');
      Util.addClass(element.morphImg[0], 'is-hidden');
      if(!isOpening) {
        element.modalImg[0].removeAttribute('src');
        element.modalInfo[0].innerHTML = '';
        element.morphEl[0].removeAttribute('xlink:href');
        element.morphEl[0].removeAttribute('href');
        element.morphBg[0].removeAttribute('style');
        element.morphImg[0].removeAttribute('style');
      }
    };
  
    window.MorphImgModal = MorphImgModal;
  
    MorphImgModal.defaults = {
      element : '',
      searchData: false, // function used to return results
    };
  }());
  // File#: _2_multiple-custom-select
  // Usage: codyhouse.co/license
  (function() {
    var MultiCustomSelect = function(element) {
  		this.element = element;
      this.select = this.element.getElementsByTagName('select')[0];
      this.optGroups = this.select.getElementsByTagName('optgroup');
  		this.options = this.select.getElementsByTagName('option');
  		this.selectId = this.select.getAttribute('id');
  		this.trigger = false;
  		this.dropdown = false;
  		this.customOptions = false;
  		this.arrowIcon = this.element.getElementsByTagName('svg');
  		this.label = document.querySelector('[for="'+this.selectId+'"]');
  		this.selectedOptCounter = 0;
  
  		this.optionIndex = 0; // used while building the custom dropdown
  
  		// label options
  		this.noSelectText = this.element.getAttribute('data-no-select-text') || 'Select';
  		this.multiSelectText = this.element.getAttribute('data-multi-select-text') || '{n} items selected'; 
  		this.nMultiSelect = this.element.getAttribute('data-n-multi-select') || 1;
  		this.noUpdateLabel = this.element.getAttribute('data-update-text') && this.element.getAttribute('data-update-text') == 'off';
  		this.insetLabel = this.element.getAttribute('data-inset-label') && this.element.getAttribute('data-inset-label') == 'on';
  
  		// init
  		initCustomSelect(this); // init markup
  		initCustomSelectEvents(this); // init event listeners
    };
    
    function initCustomSelect(select) {
  		// create the HTML for the custom dropdown element
  		select.element.insertAdjacentHTML('beforeend', initButtonSelect(select) + initListSelect(select));
  		
  		// save custom elements
  		select.dropdown = select.element.getElementsByClassName('js-multi-select__dropdown')[0];
  		select.trigger = select.element.getElementsByClassName('js-multi-select__button')[0];
  		select.customOptions = select.dropdown.getElementsByClassName('js-multi-select__option');
      
      // hide default select
      Util.addClass(select.select, 'is-hidden');
      if(select.arrowIcon.length > 0 ) select.arrowIcon[0].style.display = 'none';
    };
  
    function initCustomSelectEvents(select) {
  		// option selection in dropdown
  		initSelection(select);
  
  		// click events
  		select.trigger.addEventListener('click', function(event){
  			event.preventDefault();
  			toggleCustomSelect(select, false);
  		});
  		if(select.label) {
  			// move focus to custom trigger when clicking on <select> label
  			select.label.addEventListener('click', function(){
  				Util.moveFocus(select.trigger);
  			});
  		}
  		// keyboard navigation
  		select.dropdown.addEventListener('keydown', function(event){
  			if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
  				keyboardCustomSelect(select, 'prev', event);
  			} else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
  				keyboardCustomSelect(select, 'next', event);
  			}
  		});
    };
  
    function toggleCustomSelect(select, bool) {
      var ariaExpanded;
  		if(bool) {
  			ariaExpanded = bool;
  		} else {
  			ariaExpanded = select.trigger.getAttribute('aria-expanded') == 'true' ? 'false' : 'true';
  		}
  		select.trigger.setAttribute('aria-expanded', ariaExpanded);
  		if(ariaExpanded == 'true') {
  			var selectedOption = getSelectedOption(select);
        Util.moveFocus(selectedOption); // fallback if transition is not supported
  			select.dropdown.addEventListener('transitionend', function cb(){
  				Util.moveFocus(selectedOption);
  				select.dropdown.removeEventListener('transitionend', cb);
  			});
  			placeDropdown(select); // place dropdown based on available space
  		}
    };
  
    function placeDropdown(select) {
  		var triggerBoundingRect = select.trigger.getBoundingClientRect();
      Util.toggleClass(select.dropdown, 'multi-select__dropdown--right', (window.innerWidth < triggerBoundingRect.left + select.dropdown.offsetWidth));
      // check if there's enough space up or down
      var moveUp = (window.innerHeight - triggerBoundingRect.bottom) < triggerBoundingRect.top;
      Util.toggleClass(select.dropdown, 'multi-select__dropdown--up', moveUp);
      // check if we need to set a max height
  		var maxHeight = moveUp ? triggerBoundingRect.top - 20 : window.innerHeight - triggerBoundingRect.bottom - 20;
  		// set max-height (based on available space) and width
      select.dropdown.setAttribute('style', 'max-height: '+maxHeight+'px; width: '+triggerBoundingRect.width+'px;');
  	};
  
    function keyboardCustomSelect(select, direction, event) { // navigate custom dropdown with keyboard
  		event.preventDefault();
  		var index = Util.getIndexInArray(select.customOptions, document.activeElement.closest('.js-multi-select__option'));
  		index = (direction == 'next') ? index + 1 : index - 1;
  		if(index < 0) index = select.customOptions.length - 1;
  		if(index >= select.customOptions.length) index = 0;
  		Util.moveFocus(select.customOptions[index].getElementsByClassName('js-multi-select__checkbox')[0]);
    };
  
    function initSelection(select) { // option selection
      select.dropdown.addEventListener('change', function(event){
  			var option = event.target.closest('.js-multi-select__option');
  			if(!option) return;
  			selectOption(select, option);
  		});
  		select.dropdown.addEventListener('click', function(event){
  			var option = event.target.closest('.js-multi-select__option');
  			if(!option || !Util.hasClass(event.target, 'js-multi-select__option')) return;
  			selectOption(select, option);
  		});
  	};
  	
  	function selectOption(select, option) {
  		if(option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') == 'true') {
        // deselecting that option
        option.setAttribute('aria-selected', 'false');
        // update native select element
        updateNativeSelect(select, option.getAttribute('data-index'), false);
  		} else { 
  			option.setAttribute('aria-selected', 'true');
  			// update native select element
  			updateNativeSelect(select, option.getAttribute('data-index'), true);
  			
  		}
  		var triggerLabel = getSelectedOptionText(select);
  		select.trigger.getElementsByClassName('js-multi-select__label')[0].innerHTML = triggerLabel[0]; // update trigger label
  		Util.toggleClass(select.trigger, 'multi-select__button--active', select.selectedOptCounter > 0);
      updateTriggerAria(select, triggerLabel[1]); // update trigger arai-label
  	};
  
  	function updateNativeSelect(select, index, bool) {
  		select.options[index].selected = bool;
  		select.select.dispatchEvent(new CustomEvent('change', {bubbles: true})); // trigger change event
  	};
  
  	function updateTriggerAria(select, ariaLabel) { // new label for custom triegger
      select.trigger.setAttribute('aria-label', ariaLabel);
  	};
  
  	function getSelectedOptionText(select) {// used to initialize the label of the custom select button
  		var noSelectionText = '<span class="multi-select__term">'+select.noSelectText+'</span>';
  		if(select.noUpdateLabel) return [noSelectionText, select.noSelectText];
  		var label = '';
  		var ariaLabel = '';
  		select.selectedOptCounter = 0;
  
  		for (var i = 0; i < select.options.length; i++) {
  			if(select.options[i].selected) {
  				if(select.selectedOptCounter != 0 ) label = label + ', '
  				label = label + '' + select.options[i].text;
  				select.selectedOptCounter = select.selectedOptCounter + 1;
  			} 
  		}
  
  		if(select.selectedOptCounter > select.nMultiSelect) {
  			label = '<span class="multi-select__details">'+select.multiSelectText.replace('{n}', select.selectedOptCounter)+'</span>';
  			ariaLabel = select.multiSelectText.replace('{n}', select.selectedOptCounter)+', '+select.noSelectText;
  		} else if( select.selectedOptCounter > 0) {
  			ariaLabel = label + ', ' +select.noSelectText;
  			label = '<span class="multi-select__details">'+label+'</span>';
  		} else {
  			label = noSelectionText;
  			ariaLabel = select.noSelectText;
  		}
  
  		if(select.insetLabel && select.selectedOptCounter > 0) label = noSelectionText+label;
  		return [label, ariaLabel];
    };
    
    function initButtonSelect(select) { // create the button element -> custom select trigger
  		// check if we need to add custom classes to the button trigger
  		var customClasses = select.element.getAttribute('data-trigger-class') ? ' '+select.element.getAttribute('data-trigger-class') : '';
  
  		var triggerLabel = getSelectedOptionText(select);	
  		var activeSelectionClass = select.selectedOptCounter > 0 ? ' multi-select__button--active' : '';
  		
  		var button = '<button class="js-multi-select__button multi-select__button'+customClasses+activeSelectionClass+'" aria-label="'+triggerLabel[1]+'" aria-expanded="false" aria-controls="'+select.selectId+'-dropdown"><span aria-hidden="true" class="js-multi-select__label multi-select__label">'+triggerLabel[0]+'</span>';
      if(select.arrowIcon.length > 0 && select.arrowIcon[0].outerHTML) {
        button = button +select.arrowIcon[0].outerHTML;
      }
  		
  		return button+'</button>';
  
    };
  
    function initListSelect(select) { // create custom select dropdown
      var list = '<div class="js-multi-select__dropdown multi-select__dropdown" aria-describedby="'+select.selectId+'-description" id="'+select.selectId+'-dropdown">';
      list = list + getSelectLabelSR(select);
      if(select.optGroups.length > 0) {
        for(var i = 0; i < select.optGroups.length; i++) {
          var optGroupList = select.optGroups[i].getElementsByTagName('option'),
            optGroupLabel = '<li><span class="multi-select__item multi-select__item--optgroup">'+select.optGroups[i].getAttribute('label')+'</span></li>';
          list = list + '<ul class="multi-select__list" role="listbox" aria-multiselectable="true">'+optGroupLabel+getOptionsList(select, optGroupList) + '</ul>';
        }
      } else {
        list = list + '<ul class="multi-select__list" role="listbox" aria-multiselectable="true">'+getOptionsList(select, select.options) + '</ul>';
      }
      return list;
    };
  
    function getSelectLabelSR(select) {
      if(select.label) {
        return '<p class="sr-only" id="'+select.selectId+'-description">'+select.label.textContent+'</p>'
      } else {
        return '';
      }
    };
  
    function getOptionsList(select, options) {
      var list = '';
      for(var i = 0; i < options.length; i++) {
        var selected = options[i].hasAttribute('selected') ? ' aria-selected="true"' : ' aria-selected="false"',
          checked = options[i].hasAttribute('selected') ? 'checked' : '';
  			list = list + '<li class="js-multi-select__option" role="option" data-value="'+options[i].value+'" '+selected+' data-label="'+options[i].text+'" data-index="'+select.optionIndex+'"><input aria-hidden="true" class="checkbox js-multi-select__checkbox" type="checkbox" id="'+select.selectId+'-'+options[i].value+'-'+select.optionIndex+'" '+checked+'><label class="multi-select__item multi-select__item--option" aria-hidden="true" for="'+select.selectId+'-'+options[i].value+'-'+select.optionIndex+'"><span>'+options[i].text+'</span></label></li>';
  			select.optionIndex = select.optionIndex + 1;
      };
      return list;
    };
  
    function getSelectedOption(select) { // return first selected option
  		var option = select.dropdown.querySelector('[aria-selected="true"]');
      if(option) return option.getElementsByClassName('js-multi-select__checkbox')[0];
      else return select.dropdown.getElementsByClassName('js-multi-select__option')[0].getElementsByClassName('js-multi-select__checkbox')[0];
    };
  
    function moveFocusToSelectTrigger(select) {
      if(!document.activeElement.closest('.js-multi-select')) return
      select.trigger.focus();
  	};
  	
  	function checkCustomSelectClick(select, target) { // close select when clicking outside it
  		if( !select.element.contains(target) ) toggleCustomSelect(select, 'false');
    };
    
    //initialize the CustomSelect objects
  	var customSelect = document.getElementsByClassName('js-multi-select');
  	if( customSelect.length > 0 ) {
  		var selectArray = [];
  		for( var i = 0; i < customSelect.length; i++) {
  			(function(i){selectArray.push(new MultiCustomSelect(customSelect[i]));})(i);
  		}
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
  				// close custom select on 'Esc'
  				selectArray.forEach(function(element){
  					moveFocusToSelectTrigger(element); // if focus is within dropdown, move it to dropdown trigger
  					toggleCustomSelect(element, 'false'); // close dropdown
  				});
  			} 
  		});
  		// close custom select when clicking outside it
  		window.addEventListener('click', function(event){
  			selectArray.forEach(function(element){
  				checkCustomSelectClick(element, event.target);
  			});
  		});
  	}
  }());
  // File#: _2_off-canvas-navigation
  // Usage: codyhouse.co/license
  (function() {
    var OffCanvasNav = function(element) {
      this.element = element;
      this.panel = this.element.getElementsByClassName('js-off-canvas__panel')[0];
      this.trigger = document.querySelectorAll('[aria-controls="'+this.panel.getAttribute('id')+'"]')[0];
      this.svgAnim = this.trigger.getElementsByTagName('circle');
      initOffCanvasNav(this);
    };
  
    function initOffCanvasNav(canvas) {
      if(transitionSupported) {
        // do not allow click on menu icon while the navigation is animating
        canvas.trigger.addEventListener('click', function(event){
          canvas.trigger.style.setProperty('pointer-events', 'none');
        });
        canvas.panel.addEventListener('openPanel', function(event){
          canvas.trigger.style.setProperty('pointer-events', 'none');
        });
        canvas.panel.addEventListener('transitionend', function(event){
          if(event.propertyName == 'visibility') {
            canvas.trigger.style.setProperty('pointer-events', '');
          }
        });
      }
  
      if(canvas.svgAnim.length > 0) { // create the circle fill-in effect
        var circumference = (2*Math.PI*canvas.svgAnim[0].getAttribute('r')).toFixed(2);
        canvas.svgAnim[0].setAttribute('stroke-dashoffset', circumference);
        canvas.svgAnim[0].setAttribute('stroke-dasharray', circumference);
        Util.addClass(canvas.trigger, 'offnav-control--ready-to-animate');
      }
      
      canvas.panel.addEventListener('closePanel', function(event){
        // if the navigation is closed using keyboard or a11y close btn -> change trigger icon appearance (from arrow to menu icon) 
        if(event.detail == 'key' || event.detail == 'close-btn') {
          canvas.trigger.click();
        }
      });
    };
  
    // init OffCanvasNav objects
    var offCanvasNav = document.getElementsByClassName('js-off-canvas--nav'),
      transitionSupported = Util.cssSupports('transition');
  	if( offCanvasNav.length > 0 ) {
  		for( var i = 0; i < offCanvasNav.length; i++) {
  			(function(i){new OffCanvasNav(offCanvasNav[i]);})(i);
  		}
  	}
  }());
  // File#: _2_page-transition-v1
  // Usage: codyhouse.co/license
  (function() {
    var pageTransitionWrapper = document.getElementsByClassName('js-page-trans');
    if(pageTransitionWrapper.length < 1) return;
    
    var transPanel = document.getElementsByClassName('page-trans-v1'),
      loaderScale = '--page-trans-v1-loader-scale',
      timeoutId = false,
      loaderScaleDown = 0.2;
  
    var timeLeaveAnim = 0;
    
    new PageTransition({
      leaveAnimation: function(initContent, link, cb) {
        timeLeaveAnim = 0;
        Util.addClass(transPanel[0], 'page-trans-v1--is-visible');
        transPanel[0].addEventListener('transitionend', function cbLeave(){
          transPanel[0].removeEventListener('transitionend', cbLeave);
          setTimeout(function(){
            animateLoader(300, 1, loaderScaleDown, function(){
              Util.addClass(initContent, 'is-hidden');
              timeLeaveAnim = new Date().getTime();
              cb();
            });
          }, 100);
        });
      },
      enterAnimation: function(initContent, newContent, link, cb) {
        if(timeoutId) {
          window.cancelAnimationFrame(timeoutId);
          timeoutId = false;
        }
  
        // set a minimum loader animation duration of 0.75s
        var duration = Math.max((750 - new Date().getTime() + timeLeaveAnim), 300);
    
        // complete page-trans-v1__loader scale animation
        animateLoader(duration, parseFloat(getComputedStyle(transPanel[0]).getPropertyValue(loaderScale)), 1, function() {
          Util.removeClass(transPanel[0], 'page-trans-v1--is-visible');
          transPanel[0].addEventListener('transitionend', function cbEnter(){
            transPanel[0].removeEventListener('transitionend', cbEnter);
            cb();
          });
        });
      },
      progressAnimation: function(link) {
        animateLoader(3000, loaderScaleDown, 0.9);
      }
    });
  
    function animateLoader(duration, startValue, finalValue, cb) {
      // takes care of animating the loader element
      var currentTime = false;
  
      var animateScale = function(timestamp) {
        if (!currentTime) currentTime = timestamp;        
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        var val = Math.easeInOutQuart(progress, startValue, finalValue - startValue, duration);
        transPanel[0].style.setProperty(loaderScale, val);
        if(progress < duration) {
          timeoutId = window.requestAnimationFrame(animateScale);
        } else {
          // reveal page content
          if(cb) cb();
        }
      };
      timeoutId = window.requestAnimationFrame(animateScale);
    };
  }());
  // File#: _2_password-strength
  // Usage: codyhouse.co/license
  (function() {
    var PasswordStrength = function(opts) {
      this.options = Util.extend(PasswordStrength.defaults , opts); // used to store custom filter/sort functions
      this.element = this.options.element;
      this.input = this.element.getElementsByClassName('js-password-strength__input');
      this.reqs = this.element.getElementsByClassName('js-password-strength__req');
      this.strengthSection = this.element.getElementsByClassName('js-password-strength__meter-wrapper');
      this.strengthValue = this.element.getElementsByClassName('js-password-strength__value');
      this.strengthMeter = this.element.getElementsByClassName('js-password-strength__meter');
      this.passwordInteracted = false;
      this.reqMetClass = 'password-strength__req--met';
      this.reqNoMetClass = 'password-strength__req--no-met';
      shouldCheckStrength(this); // check if password strength should be checked
      getStrengthLabels(this); // labels for password strength
      initPasswordStrength(this);
    };
  
    function shouldCheckStrength(password) {
      password.checkStrength = true;
      var checkStrength = password.element.getAttribute('data-check-strength');
      if(checkStrength && checkStrength == 'off') password.checkStrength = false;
    };
  
    function getStrengthLabels(password) {
      if(!password.checkStrength) password.strengthLabels = false;
      password.strengthLabels = ['Bad', 'Weak', 'Good', 'Strong'];
      var dataLabel = password.element.getAttribute('data-strength-labels');
      if(dataLabel) {
        var labels = dataLabel.split(',');
        if(labels.length < 4) return;
        password.strengthLabels = labels.map(function(element){return element.trim()});
      }
    };
  
    function initPasswordStrength(password) {
      if(password.input.length == 0) return;
      toggleCheckStrength(password); // hide/show password strenght section
      checkStrength(password);
      checkConditions(password);
      initInput(password);
    };
  
    function initInput(password) {
      password.input[0].addEventListener('input', function(event) { // password changed
        toggleCheckStrength(password); // hide/show password strenght section
        checkStrength(password);
        checkConditions(password);
      });
  
      password.input[0].addEventListener('blur', function cb(event) {
        password.input[0].removeEventListener('blur', cb);
        password.passwordInteracted = true;
        // show error for requirement not met
        for(var i = 0; i < password.reqs.length; i++) {
          if(!Util.hasClass(password.reqs[i], password.reqMetClass)) Util.addClass(password.reqs[i], password.reqNoMetClass);
        }
      });
    };
  
    function toggleCheckStrength(password) {
      if(password.strengthSection.length == 0) return;
      Util.toggleClass(password.strengthSection[0], 'is-hidden', (password.input[0].value.length == 0));
    };
  
    function checkStrength(password) {
      if(!password.checkStrength || !zxcvbn) return;
      var response = zxcvbn(password.input[0].value);
      if(password.strengthValue.length > 0) { // update strength label
        if(response.score >= 1) password.strengthValue[0].textContent = password.strengthLabels[response.score - 1];
        else password.strengthValue[0].textContent = password.strengthLabels[0];
      }
  
      if(password.strengthMeter.length > 0) { // update strength meter
        var score = response.score;
        if(score == 0 && password.input[0].value.length > 0) score = 1;
        password.strengthMeter[0].firstElementChild.style.width = score/0.04+'%';
        removeStrengthClasses(password);
        if(response.score >= 1) Util.addClass(password.strengthMeter[0], 'password-strength__meter--fill-'+response.score);
        else Util.addClass(password.strengthMeter[0], 'password-strength__meter--fill-1');
      }
    };
  
    function checkConditions(password) {
      // uppercase, lowercase, special characters, length, number + custom
      for(var i = 0; i < password.reqs.length; i++) {
        var req = password.reqs[i].getAttribute('data-password-req');
        var result = false;
        if(password.options[req]) {
          result = password.options[req](password.input[0].value);
        } else {
          result = checkSingleCondition(password.input[0].value, req);
        }
  
        Util.toggleClass(password.reqs[i], password.reqMetClass, result);
        if(password.passwordInteracted) Util.toggleClass(password.reqs[i], password.reqNoMetClass, !result);
      }
    };
  
    function checkSingleCondition(value, req) {
      var result;
      switch (true) {
        case (req.trim() == 'uppercase'):
          result = (value.toLowerCase() != value);
          break;
        case (req.trim() == 'lowercase'):
          result = (value.toUpperCase() != value);
          break;
        case (req.trim() == 'number'):
          result = /\d/.test(value);
          break;
        case (req.indexOf('length:') == 0):
          var reqArray = req.split(':');
          result = (value.length >= parseInt(reqArray[1]));
          if(reqArray.length > 2 && result) result = (value.length <= parseInt(reqArray[2]));
          break;
        case (req.trim() == 'special'):
          result = /[!@#$%^&*=~`'"|/\?\_\-\,\;\.\:\(\)\{\}\[\]\+\>\<\\]/.test(value);
          break;
        case (req.trim() == 'letter'):
          result = /[a-zA-Z]/.test(value);
          break;
        default:
          result = false;
          break;
      }
      return result;
    };
  
    function removeStrengthClasses(password) {
      var classes = password.strengthMeter[0].className.split(" ").filter(function(c) {
        return c.lastIndexOf('password-strength__meter--fill-', 0) !== 0;
      });
      password.strengthMeter[0].className = classes.join(" ").trim();
    };
  
    PasswordStrength.defaults = {
      element : false,
    };
  
    window.PasswordStrength = PasswordStrength;
  
    //initialize the PasswordStrength objects
  	var passwordStrength = document.getElementsByClassName('js-password-strength');
  	if( passwordStrength.length > 0 ) {
  		for( var i = 0; i < passwordStrength.length; i++) {
  			(function(i){new PasswordStrength({element: passwordStrength[i]});})(i);
  		}
    };
  }());
  // File#: _2_pricing-table-v2
  // Usage: codyhouse.co/license
  (function() {
  	var pTable = document.getElementsByClassName('js-p-table-v2');
  	if(pTable.length > 0) {
  		for(var i = 0; i < pTable.length; i++) {
  			(function(i){ addPTableEvent(pTable[i]);})(i);
  		}
  
  		function addPTableEvent(element) {
  			// switcher monthly/yearly plan
        var pSwitch = element.getElementsByClassName('js-p-table-v2__switch');
  			if(pSwitch.length > 0) {
  				pSwitch[0].addEventListener('change', function(event) {
            Util.toggleClass(element, 'p-table-v2--monthly-plan', (event.target.value == 'monthly'));
  				});
  			}
  
  			// volume selector for multiple-users plan
  			var pSelect = element.getElementsByClassName('js-p-table-v2__select'),
  				pVolumeBtn = element.getElementsByClassName('js-p-table-v2__btn-volume');
  			if(pSelect.length > 0 && pVolumeBtn.length > 0) {
  				var volumeOptions = pVolumeBtn[0].querySelectorAll('[data-value]');
  				updatePTableTeam(volumeOptions, pSelect[0].value); // init multiple-users plan price
  				pSelect[0].addEventListener('change', function(event) {
            updatePTableTeam(volumeOptions, pSelect[0].value);
  				});
  			}
  		}
  
  		function updatePTableTeam(volumeOpt, value) {
  			for(var i = 0; i < volumeOpt.length; i++) {
  				volumeOpt[i].getAttribute('data-value') == value
  					? volumeOpt[i].removeAttribute('style')
  					: volumeOpt[i].setAttribute('style', 'display: none;');
  			}
  		};
  	}
  }());
  // File#: _2_pricing-table
  // Usage: codyhouse.co/license
  (function() {
  	// NOTE: you need the js code only when using the --has-switch variation of the pricing table
  	// default version does not require js
  	var pTable = document.getElementsByClassName('js-p-table--has-switch');
  	if(pTable.length > 0) {
  		for(var i = 0; i < pTable.length; i++) {
  			(function(i){ addPTableEvent(pTable[i]);})(i);
  		}
  
  		function addPTableEvent(element) {
  			var pSwitch = element.getElementsByClassName('js-p-table__switch')[0];
  			if(pSwitch) {
  				pSwitch.addEventListener('change', function(event) {
            Util.toggleClass(element, 'p-table--yearly', (event.target.value == 'yearly'));
  				});
  			}
  		}
  	}
  }());
  // File#: _2_product-v3
  // Usage: codyhouse.co/license
  (function() {
    var ProductV3 = function(element) {
      this.element = element;
      this.cta = this.element.getElementsByClassName('js-product-v3__cta');
      this.ctaClone = this.element.getElementsByClassName('js-product-v3__cta-clone');
      this.ctaVisible = false;
      this.sectionVisible = false;
      this.cloneDelta = '200px'; // small screen only - clone element visible when section enters the viewport of 200px
  
      // quantity inputs
      this.quantity = this.element.getElementsByClassName('js-product-v3__input');
      this.quantityClone = this.element.getElementsByClassName('js-product-v3__input-clone');
      initProductV3(this);
    };
  
    function initProductV3(product) {
      if(product.ctaClone.length == 0) return;
      if(product.cta.length > 0 && intObservSupported) { // detect when cta enters viewport
        var observer = new IntersectionObserver(observeCta.bind(product), { threshold: [0, 1] });
        observer.observe(product.cta[0]);
      }
      if(intObservSupported) {
        // detect when product section enters the viewport
        var sectionObserver = new IntersectionObserver(observeSection.bind(product), {
          rootMargin: "0px 0px -"+product.cloneDelta+" 0px"
        });
        sectionObserver.observe(product.element);
      }
  
      // sync quantity input with clone element
      if(product.quantity.length > 0 && product.quantityClone.length > 0) syncProductQuantity(product);
    };
  
    function observeCta(entries) {
      if(entries[0].isIntersecting) {
        this.ctaVisible = true;
        Util.removeClass(this.ctaClone[0], 'product-v3__cta-clone--is-visible');
      } else if(this.sectionVisible) {
        this.ctaVisible = false;
        Util.addClass(this.ctaClone[0], 'product-v3__cta-clone--is-visible');
      }
    };
  
    function observeSection(entries) {
      if(entries[0].isIntersecting) {
        this.sectionVisible = true;
      } else {
        this.sectionVisible = false;
        Util.removeClass(this.ctaClone[0], 'product-v3__cta-clone--is-visible');
      }
    };
  
    function syncProductQuantity(product) {
      product.quantity[0].addEventListener('change', function(){
        product.quantityClone[0].value = getAllowedValue(product, parseInt(product.quantity[0].value));
      });
      product.quantityClone[0].addEventListener('change', function(){
        product.quantity[0].value = getAllowedValue(product, parseInt(product.quantityClone[0].value));
      });
    };
  
    function getAllowedValue(product, value) {
      var min = product.quantity[0].getAttribute('min'),
        max = product.quantity[0].getAttribute('max');
      if(min && value < parseInt(min)) value = min;
      if(max && value > parseInt(max)) value = max;
      return value;
    };
  
    //initialize the ProductV3 objects
    var productV3 = document.getElementsByClassName('js-product-v3'),
      intObservSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
    if( productV3.length > 0 ) {
      for( var i = 0; i < productV3.length; i++) {
        (function(i){new ProductV3(productV3[i]);})(i);
      }
    };
  }());
  // File#: _2_slider-multi-value
  // Usage: codyhouse.co/license
  (function() {
  	var SliderMulti = function(element) {
  		this.element = element;
  		this.rangeWrapper = this.element.getElementsByClassName('slider__range');
  		this.rangeInput = this.element.getElementsByClassName('slider__input');
  		this.rangeMin = this.rangeInput[0].getAttribute('min');
  		this.rangeMax = this.rangeInput[0].getAttribute('max');
  		this.sliderWidth = window.getComputedStyle(this.element.getElementsByClassName('slider__range')[0]).getPropertyValue('width');
  		this.thumbWidth = getComputedStyle(this.element).getPropertyValue('--slide-thumb-size');
  		initSliderMulti(this);
  	};
  
  	function initSliderMulti(slider) {
  		// toggle custom class based on browser support
  		toggleMsClass(slider);
  
  		// init bg color of the slider
  		updateRangeColor(slider);
  
  		slider.element.addEventListener('updateRange', function(event){
  			checkRangeValues(slider, event.detail);
  			updateRangeColor(slider);
  		});
  
  		// custom event emitted after window resize
  		slider.element.addEventListener('update-slider-multi-value', function(event){
  			slider.sliderWidth = window.getComputedStyle(slider.element.getElementsByClassName('slider__range')[0]).getPropertyValue('width');
  			updateRangeColor(slider);
  		});
  	};
  
  	function checkRangeValues(slider, index) {
  		// if min value was changed -> make sure min value is smaller than max value 
  		// if max value was changed -> make sure max value is bigger than min value 
  		var i = (index == 0) ? 1 : 0,
  			limit = parseFloat(slider.rangeInput[i].value);
  		if( (index == 0 && slider.rangeInput[0].value >= limit) || (index == 1 && slider.rangeInput[1].value <= limit) ) {
  			slider.rangeInput[index].value = limit;
  			slider.element.dispatchEvent(new CustomEvent('inputRangeLimit', {detail: index}))
  		}
  	};
  
  	function updateRangeColor(slider) { // update background fill color of the slider
  		var percentageStart = parseInt((slider.rangeInput[0].value - slider.rangeMin)/(slider.rangeMax - slider.rangeMin)*100),
  			percentageEnd = parseInt((slider.rangeInput[1].value - slider.rangeMin)/(slider.rangeMax - slider.rangeMin)*100), 
  			start = 'calc('+percentageStart+'*('+slider.sliderWidth+' - 0.5*'+slider.thumbWidth+')/100)',
  			end = 'calc('+percentageEnd+'*('+slider.sliderWidth+' - 0.5*'+slider.thumbWidth+')/100)';
  
  		slider.rangeWrapper[0].style.setProperty('--slider-fill-value-start', start);
  		slider.rangeWrapper[0].style.setProperty('--slider-fill-value-end', end);
  	};
  
  	function toggleMsClass(slider) {
  		var cssVariablesSupport = Util.cssSupports('--color-value', 'red'),
  			imeAlignSuport = Util.cssSupports('-ms-ime-align', 'auto');
  		if(imeAlignSuport || !cssVariablesSupport) Util.addClass(slider.element, 'slider--ms-fallback'); // IE and Edge (<=18) Fallback
  	};
  
  	//initialize the SliderMulti objects
  	var slidersMulti = document.getElementsByClassName('js-slider');
  	if( slidersMulti.length > 0 ) {
  		var slidersMultiArray = [];
  		for( var i = 0; i < slidersMulti.length; i++) {(function(i){
  			if(slidersMulti[i].getElementsByClassName('slider__input').length > 1) slidersMultiArray.push(new SliderMulti(slidersMulti[i]));
  		})(i);}
  		if(slidersMultiArray.length > 0) {
  			var resizingId = false,
          customEvent = new CustomEvent('update-slider-multi-value');
        
        window.addEventListener('resize', function() {
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 500);
        });
  
        function doneResizing() {
          for( var i = 0; i < slidersMultiArray.length; i++) {
            (function(i){slidersMultiArray[i].element.dispatchEvent(customEvent)})(i);
          };
        };
  		}
  	}
  }());
  // File#: _2_slideshow-preview-mode
  // Usage: codyhouse.co/license
  (function() {
  	var SlideshowPrew = function(opts) {
  		this.options = Util.extend(SlideshowPrew.defaults , opts);
  		this.element = this.options.element;
  		this.list = this.element.getElementsByClassName('js-slideshow-pm__list')[0];
  		this.items = this.list.getElementsByClassName('js-slideshow-pm__item');
  		this.controls = this.element.getElementsByClassName('js-slideshow-pm__control'); 
  		this.selectedSlide = 0;
  		this.autoplayId = false;
  		this.autoplayPaused = false;
  		this.navigation = false;
  		this.navCurrentLabel = false;
  		this.ariaLive = false;
  		this.moveFocus = false;
  		this.animating = false;
  		this.supportAnimation = Util.cssSupports('transition');
  		this.itemWidth = false;
  		this.itemMargin = false;
  		this.containerWidth = false;
  		this.resizeId = false;
  		// we will need this to implement keyboard nav
  		this.firstFocusable = false;
  		this.lastFocusable = false;
  		// fallback for browsers not supporting flexbox
  		initSlideshow(this);
  		initSlideshowEvents(this);
  		initAnimationEndEvents(this);
  		Util.addClass(this.element, 'slideshow-pm--js-loaded');
  	};
  
  	SlideshowPrew.prototype.showNext = function(autoplay) {
  		showNewItem(this, this.selectedSlide + 1, 'next', autoplay);
  	};
  
  	SlideshowPrew.prototype.showPrev = function() {
  		showNewItem(this, this.selectedSlide - 1, 'prev');
  	};
  
  	SlideshowPrew.prototype.showItem = function(index) {
  		showNewItem(this, index, false);
  	};
  
  	SlideshowPrew.prototype.startAutoplay = function() {
  		var self = this;
  		if(this.options.autoplay && !this.autoplayId && !this.autoplayPaused) {
  			self.autoplayId = setInterval(function(){
  				self.showNext(true);
  			}, self.options.autoplayInterval);
  		}
  	};
  
  	SlideshowPrew.prototype.pauseAutoplay = function() {
  		var self = this;
  		if(this.options.autoplay) {
  			clearInterval(self.autoplayId);
  			self.autoplayId = false;
  		}
  	};
  
  	function initSlideshow(slideshow) { // basic slideshow settings
  		// if no slide has been selected -> select the first one
  		if(slideshow.element.getElementsByClassName('slideshow-pm__item--selected').length < 1) Util.addClass(slideshow.items[0], 'slideshow-pm__item--selected');
  		slideshow.selectedSlide = Util.getIndexInArray(slideshow.items, slideshow.element.getElementsByClassName('slideshow-pm__item--selected')[0]);
  		// now set translate value to the container element
  		setTranslateValue(slideshow);
  		setTranslate(slideshow);
  		resetSlideshowNav(slideshow, 0, slideshow.selectedSlide);
  		setFocusableElements(slideshow);
  		// if flexbox is not supported, set a width for the list element
  		if(!flexSupported) resetSlideshowFlexFallback(slideshow);
  		// now add class to animate while translating
  		setTimeout(function(){Util.addClass(slideshow.list, 'slideshow-pm__list--has-transition');}, 50);
  		// add arai-hidden to not selected slides
  		for(var i = 0; i < slideshow.items.length; i++) {
  			(i == slideshow.selectedSlide) ? slideshow.items[i].removeAttribute('aria-hidden') : slideshow.items[i].setAttribute('aria-hidden', 'true');
  		}
  		// create an element that will be used to announce the new visible slide to SR
  		var srLiveArea = document.createElement('div');
  		Util.setAttributes(srLiveArea, {'class': 'sr-only js-slideshow-pm__aria-live', 'aria-live': 'polite', 'aria-atomic': 'true'});
  		slideshow.element.appendChild(srLiveArea);
  		slideshow.ariaLive = srLiveArea;
  	};
  
  	function initSlideshowEvents(slideshow) {
  		// if slideshow navigation is on -> create navigation HTML and add event listeners
  		if(slideshow.options.navigation) {
  			var navigation = document.createElement('ol'),
  				navChildren = '';
  			
  			navigation.setAttribute('class', 'slideshow-pm__navigation');
  			for(var i = 0; i < slideshow.items.length; i++) {
  				var className = (i == slideshow.selectedSlide) ? 'class="slideshow-pm__nav-item slideshow-pm__nav-item--selected js-slideshow-pm__nav-item"' :  'class="slideshow-pm__nav-item js-slideshow-pm__nav-item"',
  					navCurrentLabel = (i == slideshow.selectedSlide) ? '<span class="sr-only js-slideshow-pm__nav-current-label">Current Item</span>' : '';
  				navChildren = navChildren + '<li '+className+'><button class="reset"><span class="sr-only">'+ (i+1) + '</span>'+navCurrentLabel+'</button></li>';
  			}
  
  			navigation.innerHTML = navChildren;
  			slideshow.navCurrentLabel = navigation.getElementsByClassName('js-slideshow-pm__nav-current-label')[0]; 
  			slideshow.element.appendChild(navigation);
  			slideshow.navigation = slideshow.element.getElementsByClassName('js-slideshow-pm__nav-item');
  
  			navigation.addEventListener('click', function(event){
  				navigateSlide(slideshow, event, true);
  			});
  			navigation.addEventListener('keyup', function(event){
  				navigateSlide(slideshow, event, (event.key.toLowerCase() == 'enter'));
  			});
  		}
  		// slideshow arrow controls
  		if(slideshow.controls.length > 0) {
  			slideshow.controls[0].addEventListener('click', function(event){
  				event.preventDefault();
  				slideshow.showPrev();
  				updateAriaLive(slideshow);
  			});
  			slideshow.controls[1].addEventListener('click', function(event){
  				event.preventDefault();
  				slideshow.showNext(false);
  				updateAriaLive(slideshow);
  			});
  		}
  		// navigate slideshow when clicking on preview
  		if(slideshow.options.prewNav) {
  			slideshow.element.addEventListener('click', function(event){
  				var item = event.target.closest('.js-slideshow-pm__item');
  				if(item && !Util.hasClass(item, 'slideshow-pm__item--selected')) {
  					slideshow.showItem(Util.getIndexInArray(slideshow.items, item));
  				}
  			});
  		}
  		// swipe events
  		if(slideshow.options.swipe) {
  			//init swipe
  			new SwipeContent(slideshow.element);
  			slideshow.element.addEventListener('swipeLeft', function(event){
  				slideshow.showNext(false);
  			});
  			slideshow.element.addEventListener('swipeRight', function(event){
  				slideshow.showPrev();
  			});
  		}
  		// autoplay
  		if(slideshow.options.autoplay) {
  			slideshow.startAutoplay();
  			// pause autoplay if user is interacting with the slideshow
  			slideshow.element.addEventListener('mouseenter', function(event){
  				slideshow.pauseAutoplay();
  				slideshow.autoplayPaused = true;
  			});
  			slideshow.element.addEventListener('focusin', function(event){
  				slideshow.pauseAutoplay();
  				slideshow.autoplayPaused = true;
  			});
  			slideshow.element.addEventListener('mouseleave', function(event){
  				slideshow.autoplayPaused = false;
  				slideshow.startAutoplay();
  			});
  			slideshow.element.addEventListener('focusout', function(event){
  				slideshow.autoplayPaused = false;
  				slideshow.startAutoplay();
  			});
  		}
  		// keyboard navigation
  		initKeyboardEvents(slideshow);
  		// reset on resize
      window.addEventListener('resize', function(event){
      	slideshow.pauseAutoplay();
        clearTimeout(slideshow.resizeId);
        slideshow.resizeId = setTimeout(function(){
          resetSlideshowResize(slideshow);
          setTimeout(function(){slideshow.startAutoplay();}, 60);
        }, 250)
      });
  	};
  
  	function initKeyboardEvents(slideshow) {
  		// tab on selected slide -> if last focusable -> move to prev or next arrow
  		// tab + shift selected slide -> if first focusable -> move to container
  		if(slideshow.controls.length > 0) {
  			// tab+shift on prev arrow -> move focus to last focusable element inside the selected slide (or to the slider container)
  			slideshow.controls[0].addEventListener('keydown', function(event){
  				if( (event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab') && event.shiftKey ) moveFocusToLast(slideshow);
  			});
  			// tab+shift on next arrow -> if first slide selectes -> move focus to last focusable element inside the selected slide (or to the slider container)
  			slideshow.controls[1].addEventListener('keydown', function(event){
  				if( (event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab') && event.shiftKey && (slideshow.selectedSlide == 0)) moveFocusToLast(slideshow);
  			});
  		}
  		// check tab is pressed when focus is inside selected slide
  		slideshow.element.addEventListener('keydown', function(event){
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  				var target = event.target.closest('.js-slideshow-pm__item');
  				if(target && Util.hasClass(target, 'slideshow-pm__item--selected')) moveFocusOutsideSlide(slideshow, event);
  				else if(target || Util.hasClass(event.target, 'js-slideshow-pm') && !event.shiftKey) moveFocusToSelectedSlide(slideshow);
  			} 
  		});
  
  		// detect tab moves to slideshow 
  		window.addEventListener('keyup', function(event){
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab') {
  				var target = event.target.closest('.js-slideshow-prew__item');
  				if(target || Util.hasClass(event.target, 'js-slideshow-prew') && !event.shiftKey) moveFocusToSelectedSlide(slideshow);
  			}
  		});
  	};
  
  	function moveFocusToLast(slideshow) {
  		event.preventDefault();
  		if(slideshow.lastFocusable)	{
  			slideshow.lastFocusable.focus();
  		} else {
  			Util.moveFocus(slideshow.element);
  		}
  	};
  
  	function moveFocusToSelectedSlide(slideshow) { // focus is inside a slide that is not selected
  		event.preventDefault();
  		if(slideshow.firstFocusable)	{
  			slideshow.firstFocusable.focus();
  		} else if(slideshow.controls.length > 0) {
  			(slideshow.selectedSlide == 0) ? slideshow.controls[1].getElementsByTagName('button')[0].focus() : slideshow.controls[0].getElementsByTagName('button')[0].focus();
  		} else if(slideshow.options.navigation) {
  			slideshow.navigation.getElementsByClassName('js-slideshow-pm__nav-item')[0].getElementsByTagName('button')[0].focus();
  		}
  	};
  
  	function moveFocusOutsideSlide(slideshow, event) {
  		if(event.shiftKey && slideshow.firstFocusable && event.target == slideshow.firstFocusable) {
  			// shift+tab -> focus was on first foucusable element inside selected slide -> move to container
  			event.preventDefault();
  			Util.moveFocus(slideshow.element);
  		} else if( !event.shiftKey && slideshow.lastFocusable && event.target == slideshow.lastFocusable) {
  			event.preventDefault();
  			
  			if(slideshow.selectedSlide != 0) slideshow.controls[0].getElementsByTagName('button')[0].focus();
  			else slideshow.controls[1].getElementsByTagName('button')[0].focus();
  		}
  	};
  
  	function initAnimationEndEvents(slideshow) {
  		slideshow.list.addEventListener('transitionend', function(){
  			setTimeout(function(){ // add a delay between the end of animation and slideshow reset - improve animation performance
  				resetAnimationEnd(slideshow);
  			}, 100);
  		});
  	};
  
  	function resetAnimationEnd(slideshow) {
  		if(slideshow.moveFocus) Util.moveFocus(slideshow.items[slideshow.selectedSlide]);
  		slideshow.items[slideshow.selectedSlide].removeAttribute('aria-hidden');
  		slideshow.animating = false;
  		slideshow.moveFocus = false;
  		slideshow.startAutoplay();
  	};
  
  	function navigateSlide(slideshow, event, keyNav) { 
  		// user has interacted with the slideshow navigation -> update visible slide
  		var target = event.target.closest('.js-slideshow-pm__nav-item');
  		if(keyNav && target && !Util.hasClass(target, 'slideshow-pm__nav-item--selected')) {
  			slideshow.showItem(Util.getIndexInArray(slideshow.navigation, target));
  			slideshow.moveFocus = true;
  			updateAriaLive(slideshow);
  		}
  	};
  
  	function showNewItem(slideshow, index, bool, autoplay) {
  		if(slideshow.animating && slideshow.supportAnimation) return;
  		if(autoplay) {
  			if(index < 0) index = slideshow.items.length - 1;
  			else if(index >= slideshow.items.length) index = 0;
  		}
  		if(index < 0 || index >= slideshow.items.length) return;
  		slideshow.animating = true;
  		Util.removeClass(slideshow.items[slideshow.selectedSlide], 'slideshow-pm__item--selected');
  		slideshow.items[slideshow.selectedSlide].setAttribute('aria-hidden', 'true'); //hide to sr element that is exiting the viewport
  		Util.addClass(slideshow.items[index], 'slideshow-pm__item--selected');
  		resetSlideshowNav(slideshow, index, slideshow.selectedSlide);
  		slideshow.selectedSlide = index;
  		setTranslate(slideshow);
  		slideshow.pauseAutoplay();
  		setFocusableElements(slideshow);
  		if(!transitionSupported) resetAnimationEnd(slideshow);
  	};
  
  	function updateAriaLive(slideshow) {
  		slideshow.ariaLive.innerHTML = 'Item '+(slideshow.selectedSlide + 1)+' of '+slideshow.items.length;
  	};
  
  	function resetSlideshowResize(slideshow) {
  		Util.removeClass(slideshow.list, 'slideshow-pm__list--has-transition');
  		setTimeout(function(){
  			setTranslateValue(slideshow);
  			setTranslate(slideshow);
  			Util.addClass(slideshow.list, 'slideshow-pm__list--has-transition');
  		}, 30)
  	};
  
  	function setTranslateValue(slideshow) {
  		var itemStyle = window.getComputedStyle(slideshow.items[slideshow.selectedSlide]);
  
  		slideshow.itemWidth = parseFloat(itemStyle.getPropertyValue('width'));
  		slideshow.itemMargin = parseFloat(itemStyle.getPropertyValue('margin-right'));
  		slideshow.containerWidth = parseFloat(window.getComputedStyle(slideshow.element).getPropertyValue('width'));
  	};
  
  	function setTranslate(slideshow) {
  		var translate = parseInt(((slideshow.itemWidth + slideshow.itemMargin) * slideshow.selectedSlide * (-1)) + ((slideshow.containerWidth - slideshow.itemWidth)*0.5));
      slideshow.list.style.transform = 'translateX('+translate+'px)';
      slideshow.list.style.msTransform = 'translateX('+translate+'px)';
    };
  
    function resetSlideshowNav(slideshow, newIndex, oldIndex) {
    	if(slideshow.navigation) {
  			Util.removeClass(slideshow.navigation[oldIndex], 'slideshow-pm__nav-item--selected');
  			Util.addClass(slideshow.navigation[newIndex], 'slideshow-pm__nav-item--selected');
  			slideshow.navCurrentLabel.parentElement.removeChild(slideshow.navCurrentLabel);
  			slideshow.navigation[newIndex].getElementsByTagName('button')[0].appendChild(slideshow.navCurrentLabel);
  		}
  		if(slideshow.controls.length > 0) {
  			Util.toggleClass(slideshow.controls[0], 'slideshow-pm__control--active', newIndex != 0);
  			Util.toggleClass(slideshow.controls[1], 'slideshow-pm__control--active', newIndex != (slideshow.items.length - 1));
    	}
    };
  
    function setFocusableElements(slideshow) {
    	//get all focusable elements inside the selected slide
  		var allFocusable = slideshow.items[slideshow.selectedSlide].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary');
  		getFirstVisible(slideshow, allFocusable);
  		getLastVisible(slideshow, allFocusable);
    };
  
    function getFirstVisible(slideshow, elements) {
    	slideshow.firstFocusable = false;
  		//get first visible focusable element inside the selected slide
  		for(var i = 0; i < elements.length; i++) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				slideshow.firstFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function getLastVisible(slideshow, elements) {
    	//get last visible focusable element inside the selected slide
    	slideshow.lastFocusable = false;
  		for(var i = elements.length - 1; i >= 0; i--) {
  			if( elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length ) {
  				slideshow.lastFocusable = elements[i];
  				return true;
  			}
  		}
    };
  
    function resetSlideshowFlexFallback(slideshow) {
  		slideshow.list.style.width = ((slideshow.items.length+1)*(slideshow.itemMargin+slideshow.itemWidth))+'px';
  		for(var i = 0; i < slideshow.items.length; i++) {slideshow.items[i].style.width = slideshow.itemWidth+'px';}
    };
  
  	SlideshowPrew.defaults = {
      element : '',
      navigation : true,
      autoplay : false,
      autoplayInterval: 5000,
      prewNav: false,
      swipe: false
    };
  
    window.SlideshowPrew = SlideshowPrew;
  	
  	// initialize the slideshowsPrew objects
  	var slideshowsPrew = document.getElementsByClassName('js-slideshow-pm'),
  		flexSupported = Util.cssSupports('align-items', 'stretch'),
  		transitionSupported = Util.cssSupports('transition');
  	if( slideshowsPrew.length > 0 ) {
  		for( var i = 0; i < slideshowsPrew.length; i++) {
  			(function(i){
  				var navigation = (slideshowsPrew[i].getAttribute('data-navigation') && slideshowsPrew[i].getAttribute('data-navigation') == 'off') ? false : true,
  					autoplay = (slideshowsPrew[i].getAttribute('data-autoplay') && slideshowsPrew[i].getAttribute('data-autoplay') == 'on') ? true : false,
  					autoplayInterval = (slideshowsPrew[i].getAttribute('data-autoplay-interval')) ? slideshowsPrew[i].getAttribute('data-autoplay-interval') : 5000,
  					prewNav = (slideshowsPrew[i].getAttribute('data-pm-nav') && slideshowsPrew[i].getAttribute('data-pm-nav') == 'on' ) ? true : false, 
  					swipe = (slideshowsPrew[i].getAttribute('data-swipe') && slideshowsPrew[i].getAttribute('data-swipe') == 'on') ? true : false;
  				new SlideshowPrew({element: slideshowsPrew[i], navigation: navigation, autoplay : autoplay, autoplayInterval : autoplayInterval, swipe : swipe, prewNav: prewNav});
  			})(i);
  		}
  	}
  
  }());
  // File#: _2_slideshow
  // Usage: codyhouse.co/license
  (function() {
  	var Slideshow = function(opts) {
  		this.options = Util.extend(Slideshow.defaults , opts);
  		this.element = this.options.element;
  		this.items = this.element.getElementsByClassName('js-slideshow__item');
  		this.controls = this.element.getElementsByClassName('js-slideshow__control'); 
  		this.selectedSlide = 0;
  		this.autoplayId = false;
  		this.autoplayPaused = false;
  		this.navigation = false;
  		this.navCurrentLabel = false;
  		this.ariaLive = false;
  		this.moveFocus = false;
  		this.animating = false;
  		this.supportAnimation = Util.cssSupports('transition');
  		this.animationOff = (!Util.hasClass(this.element, 'slideshow--transition-fade') && !Util.hasClass(this.element, 'slideshow--transition-slide') && !Util.hasClass(this.element, 'slideshow--transition-prx'));
  		this.animationType = Util.hasClass(this.element, 'slideshow--transition-prx') ? 'prx' : 'slide';
  		this.animatingClass = 'slideshow--is-animating';
  		initSlideshow(this);
  		initSlideshowEvents(this);
  		initAnimationEndEvents(this);
  	};
  
  	Slideshow.prototype.showNext = function() {
  		showNewItem(this, this.selectedSlide + 1, 'next');
  	};
  
  	Slideshow.prototype.showPrev = function() {
  		showNewItem(this, this.selectedSlide - 1, 'prev');
  	};
  
  	Slideshow.prototype.showItem = function(index) {
  		showNewItem(this, index, false);
  	};
  
  	Slideshow.prototype.startAutoplay = function() {
  		var self = this;
  		if(this.options.autoplay && !this.autoplayId && !this.autoplayPaused) {
  			self.autoplayId = setInterval(function(){
  				self.showNext();
  			}, self.options.autoplayInterval);
  		}
  	};
  
  	Slideshow.prototype.pauseAutoplay = function() {
  		var self = this;
  		if(this.options.autoplay) {
  			clearInterval(self.autoplayId);
  			self.autoplayId = false;
  		}
  	};
  
  	function initSlideshow(slideshow) { // basic slideshow settings
  		// if no slide has been selected -> select the first one
  		if(slideshow.element.getElementsByClassName('slideshow__item--selected').length < 1) Util.addClass(slideshow.items[0], 'slideshow__item--selected');
  		slideshow.selectedSlide = Util.getIndexInArray(slideshow.items, slideshow.element.getElementsByClassName('slideshow__item--selected')[0]);
  		// create an element that will be used to announce the new visible slide to SR
  		var srLiveArea = document.createElement('div');
  		Util.setAttributes(srLiveArea, {'class': 'sr-only js-slideshow__aria-live', 'aria-live': 'polite', 'aria-atomic': 'true'});
  		slideshow.element.appendChild(srLiveArea);
  		slideshow.ariaLive = srLiveArea;
  	};
  
  	function initSlideshowEvents(slideshow) {
  		// if slideshow navigation is on -> create navigation HTML and add event listeners
  		if(slideshow.options.navigation) {
  			// check if navigation has already been included
  			if(slideshow.element.getElementsByClassName('js-slideshow__navigation').length == 0) {
  				var navigation = document.createElement('ol'),
  					navChildren = '';
  
  				var navClasses = slideshow.options.navigationClass+' js-slideshow__navigation';
  				if(slideshow.items.length <= 1) {
  					navClasses = navClasses + ' is-hidden';
  				}
  				
  				navigation.setAttribute('class', navClasses);
  				for(var i = 0; i < slideshow.items.length; i++) {
  					var className = (i == slideshow.selectedSlide) ? 'class="'+slideshow.options.navigationItemClass+' '+slideshow.options.navigationItemClass+'--selected js-slideshow__nav-item"' :  'class="'+slideshow.options.navigationItemClass+' js-slideshow__nav-item"',
  						navCurrentLabel = (i == slideshow.selectedSlide) ? '<span class="sr-only js-slideshow__nav-current-label">Current Item</span>' : '';
  					navChildren = navChildren + '<li '+className+'><button class="reset"><span class="sr-only">'+ (i+1) + '</span>'+navCurrentLabel+'</button></li>';
  				}
  				navigation.innerHTML = navChildren;
  				slideshow.element.appendChild(navigation);
  			}
  			
  			slideshow.navCurrentLabel = slideshow.element.getElementsByClassName('js-slideshow__nav-current-label')[0]; 
  			slideshow.navigation = slideshow.element.getElementsByClassName('js-slideshow__nav-item');
  
  			var dotsNavigation = slideshow.element.getElementsByClassName('js-slideshow__navigation')[0];
  
  			dotsNavigation.addEventListener('click', function(event){
  				navigateSlide(slideshow, event, true);
  			});
  			dotsNavigation.addEventListener('keyup', function(event){
  				navigateSlide(slideshow, event, (event.key.toLowerCase() == 'enter'));
  			});
  		}
  		// slideshow arrow controls
  		if(slideshow.controls.length > 0) {
  			// hide controls if one item available
  			if(slideshow.items.length <= 1) {
  				Util.addClass(slideshow.controls[0], 'is-hidden');
  				Util.addClass(slideshow.controls[1], 'is-hidden');
  			}
  			slideshow.controls[0].addEventListener('click', function(event){
  				event.preventDefault();
  				slideshow.showPrev();
  				updateAriaLive(slideshow);
  			});
  			slideshow.controls[1].addEventListener('click', function(event){
  				event.preventDefault();
  				slideshow.showNext();
  				updateAriaLive(slideshow);
  			});
  		}
  		// swipe events
  		if(slideshow.options.swipe) {
  			//init swipe
  			new SwipeContent(slideshow.element);
  			slideshow.element.addEventListener('swipeLeft', function(event){
  				slideshow.showNext();
  			});
  			slideshow.element.addEventListener('swipeRight', function(event){
  				slideshow.showPrev();
  			});
  		}
  		// autoplay
  		if(slideshow.options.autoplay) {
  			slideshow.startAutoplay();
  			// pause autoplay if user is interacting with the slideshow
  			if(!slideshow.options.autoplayOnHover) {
  				slideshow.element.addEventListener('mouseenter', function(event){
  					slideshow.pauseAutoplay();
  					slideshow.autoplayPaused = true;
  				});
  				slideshow.element.addEventListener('mouseleave', function(event){
  					slideshow.autoplayPaused = false;
  					slideshow.startAutoplay();
  				});
  			}
  			if(!slideshow.options.autoplayOnFocus) {
  				slideshow.element.addEventListener('focusin', function(event){
  					slideshow.pauseAutoplay();
  					slideshow.autoplayPaused = true;
  				});
  				slideshow.element.addEventListener('focusout', function(event){
  					slideshow.autoplayPaused = false;
  					slideshow.startAutoplay();
  				});
  			}
  		}
  		// detect if external buttons control the slideshow
  		var slideshowId = slideshow.element.getAttribute('id');
  		if(slideshowId) {
  			var externalControls = document.querySelectorAll('[data-controls="'+slideshowId+'"]');
  			for(var i = 0; i < externalControls.length; i++) {
  				(function(i){externalControlSlide(slideshow, externalControls[i]);})(i);
  			}
  		}
  		// custom event to trigger selection of a new slide element
  		slideshow.element.addEventListener('selectNewItem', function(event){
  			// check if slide is already selected
  			if(event.detail) {
  				if(event.detail - 1 == slideshow.selectedSlide) return;
  				showNewItem(slideshow, event.detail - 1, false);
  			}
  		});
  
  		// keyboard navigation
  		slideshow.element.addEventListener('keydown', function(event){
  			if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
  				slideshow.showNext();
  			} else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
  				slideshow.showPrev();
  			}
  		});
  	};
  
  	function navigateSlide(slideshow, event, keyNav) { 
  		// user has interacted with the slideshow navigation -> update visible slide
  		var target = ( Util.hasClass(event.target, 'js-slideshow__nav-item') ) ? event.target : event.target.closest('.js-slideshow__nav-item');
  		if(keyNav && target && !Util.hasClass(target, 'slideshow__nav-item--selected')) {
  			slideshow.showItem(Util.getIndexInArray(slideshow.navigation, target));
  			slideshow.moveFocus = true;
  			updateAriaLive(slideshow);
  		}
  	};
  
  	function initAnimationEndEvents(slideshow) {
  		// remove animation classes at the end of a slide transition
  		for( var i = 0; i < slideshow.items.length; i++) {
  			(function(i){
  				slideshow.items[i].addEventListener('animationend', function(){resetAnimationEnd(slideshow, slideshow.items[i]);});
  				slideshow.items[i].addEventListener('transitionend', function(){resetAnimationEnd(slideshow, slideshow.items[i]);});
  			})(i);
  		}
  	};
  
  	function resetAnimationEnd(slideshow, item) {
  		setTimeout(function(){ // add a delay between the end of animation and slideshow reset - improve animation performance
  			if(Util.hasClass(item,'slideshow__item--selected')) {
  				if(slideshow.moveFocus) Util.moveFocus(item);
  				emitSlideshowEvent(slideshow, 'newItemVisible', slideshow.selectedSlide);
  				slideshow.moveFocus = false;
  			}
  			Util.removeClass(item, 'slideshow__item--'+slideshow.animationType+'-out-left slideshow__item--'+slideshow.animationType+'-out-right slideshow__item--'+slideshow.animationType+'-in-left slideshow__item--'+slideshow.animationType+'-in-right');
  			item.removeAttribute('aria-hidden');
  			slideshow.animating = false;
  			Util.removeClass(slideshow.element, slideshow.animatingClass); 
  		}, 100);
  	};
  
  	function showNewItem(slideshow, index, bool) {
  		if(slideshow.items.length <= 1) return;
  		if(slideshow.animating && slideshow.supportAnimation) return;
  		slideshow.animating = true;
  		Util.addClass(slideshow.element, slideshow.animatingClass); 
  		if(index < 0) index = slideshow.items.length - 1;
  		else if(index >= slideshow.items.length) index = 0;
  		// skip slideshow item if it is hidden
  		if(bool && Util.hasClass(slideshow.items[index], 'is-hidden')) {
  			slideshow.animating = false;
  			index = bool == 'next' ? index + 1 : index - 1;
  			showNewItem(slideshow, index, bool);
  			return;
  		}
  		// index of new slide is equal to index of slide selected item
  		if(index == slideshow.selectedSlide) {
  			slideshow.animating = false;
  			return;
  		}
  		var exitItemClass = getExitItemClass(slideshow, bool, slideshow.selectedSlide, index);
  		var enterItemClass = getEnterItemClass(slideshow, bool, slideshow.selectedSlide, index);
  		// transition between slides
  		if(!slideshow.animationOff) Util.addClass(slideshow.items[slideshow.selectedSlide], exitItemClass);
  		Util.removeClass(slideshow.items[slideshow.selectedSlide], 'slideshow__item--selected');
  		slideshow.items[slideshow.selectedSlide].setAttribute('aria-hidden', 'true'); //hide to sr element that is exiting the viewport
  		if(slideshow.animationOff) {
  			Util.addClass(slideshow.items[index], 'slideshow__item--selected');
  		} else {
  			Util.addClass(slideshow.items[index], enterItemClass+' slideshow__item--selected');
  		}
  		// reset slider navigation appearance
  		resetSlideshowNav(slideshow, index, slideshow.selectedSlide);
  		slideshow.selectedSlide = index;
  		// reset autoplay
  		slideshow.pauseAutoplay();
  		slideshow.startAutoplay();
  		// reset controls/navigation color themes
  		resetSlideshowTheme(slideshow, index);
  		// emit event
  		emitSlideshowEvent(slideshow, 'newItemSelected', slideshow.selectedSlide);
  		if(slideshow.animationOff) {
  			slideshow.animating = false;
  			Util.removeClass(slideshow.element, slideshow.animatingClass);
  		}
  	};
  
  	function getExitItemClass(slideshow, bool, oldIndex, newIndex) {
  		var className = '';
  		if(bool) {
  			className = (bool == 'next') ? 'slideshow__item--'+slideshow.animationType+'-out-right' : 'slideshow__item--'+slideshow.animationType+'-out-left'; 
  		} else {
  			className = (newIndex < oldIndex) ? 'slideshow__item--'+slideshow.animationType+'-out-left' : 'slideshow__item--'+slideshow.animationType+'-out-right';
  		}
  		return className;
  	};
  
  	function getEnterItemClass(slideshow, bool, oldIndex, newIndex) {
  		var className = '';
  		if(bool) {
  			className = (bool == 'next') ? 'slideshow__item--'+slideshow.animationType+'-in-right' : 'slideshow__item--'+slideshow.animationType+'-in-left'; 
  		} else {
  			className = (newIndex < oldIndex) ? 'slideshow__item--'+slideshow.animationType+'-in-left' : 'slideshow__item--'+slideshow.animationType+'-in-right';
  		}
  		return className;
  	};
  
  	function resetSlideshowNav(slideshow, newIndex, oldIndex) {
  		if(slideshow.navigation) {
  			Util.removeClass(slideshow.navigation[oldIndex], 'slideshow__nav-item--selected');
  			Util.addClass(slideshow.navigation[newIndex], 'slideshow__nav-item--selected');
  			slideshow.navCurrentLabel.parentElement.removeChild(slideshow.navCurrentLabel);
  			slideshow.navigation[newIndex].getElementsByTagName('button')[0].appendChild(slideshow.navCurrentLabel);
  		}
  	};
  
  	function resetSlideshowTheme(slideshow, newIndex) {
  		var dataTheme = slideshow.items[newIndex].getAttribute('data-theme');
  		if(dataTheme) {
  			if(slideshow.navigation) slideshow.navigation[0].parentElement.setAttribute('data-theme', dataTheme);
  			if(slideshow.controls[0]) slideshow.controls[0].parentElement.setAttribute('data-theme', dataTheme);
  		} else {
  			if(slideshow.navigation) slideshow.navigation[0].parentElement.removeAttribute('data-theme');
  			if(slideshow.controls[0]) slideshow.controls[0].parentElement.removeAttribute('data-theme');
  		}
  	};
  
  	function emitSlideshowEvent(slideshow, eventName, detail) {
  		var event = new CustomEvent(eventName, {detail: detail});
  		slideshow.element.dispatchEvent(event);
  	};
  
  	function updateAriaLive(slideshow) {
  		slideshow.ariaLive.innerHTML = 'Item '+(slideshow.selectedSlide + 1)+' of '+slideshow.items.length;
  	};
  
  	function externalControlSlide(slideshow, button) { // control slideshow using external element
  		button.addEventListener('click', function(event){
  			var index = button.getAttribute('data-index');
  			if(!index || index == slideshow.selectedSlide + 1) return;
  			event.preventDefault();
  			showNewItem(slideshow, index - 1, false);
  		});
  	};
  
  	Slideshow.defaults = {
      element : '',
      navigation : true,
      autoplay : false,
  		autoplayOnHover: false,
  		autoplayOnFocus: false,
      autoplayInterval: 5000,
  		navigationItemClass: 'slideshow__nav-item',
      navigationClass: 'slideshow__navigation',
      swipe: false
    };
  
  	window.Slideshow = Slideshow;
  	
  	//initialize the Slideshow objects
  	var slideshows = document.getElementsByClassName('js-slideshow');
  	if( slideshows.length > 0 ) {
  		for( var i = 0; i < slideshows.length; i++) {
  			(function(i){
  				var navigation = (slideshows[i].getAttribute('data-navigation') && slideshows[i].getAttribute('data-navigation') == 'off') ? false : true,
  					autoplay = (slideshows[i].getAttribute('data-autoplay') && slideshows[i].getAttribute('data-autoplay') == 'on') ? true : false,
  					autoplayOnHover = (slideshows[i].getAttribute('data-autoplay-hover') && slideshows[i].getAttribute('data-autoplay-hover') == 'on') ? true : false,
  					autoplayOnFocus = (slideshows[i].getAttribute('data-autoplay-focus') && slideshows[i].getAttribute('data-autoplay-focus') == 'on') ? true : false,
  					autoplayInterval = (slideshows[i].getAttribute('data-autoplay-interval')) ? slideshows[i].getAttribute('data-autoplay-interval') : 5000,
  					swipe = (slideshows[i].getAttribute('data-swipe') && slideshows[i].getAttribute('data-swipe') == 'on') ? true : false,
  					navigationItemClass = slideshows[i].getAttribute('data-navigation-item-class') ? slideshows[i].getAttribute('data-navigation-item-class') : 'slideshow__nav-item',
            navigationClass = slideshows[i].getAttribute('data-navigation-class') ? slideshows[i].getAttribute('data-navigation-class') : 'slideshow__navigation';
  				new Slideshow({element: slideshows[i], navigation: navigation, autoplay : autoplay, autoplayOnHover: autoplayOnHover, autoplayOnFocus: autoplayOnFocus, autoplayInterval : autoplayInterval, swipe : swipe, navigationItemClass: navigationItemClass, navigationClass: navigationClass});
  			})(i);
  		}
  	}
  }());
  // File#: _2_split-button
  // Usage: codyhouse.co/license
  (function() {
    function closeSplitBtnPopover(popover) {
      // close popover when clicking option in the dropdown
      popover.addEventListener('click', function(event){
        popover.dispatchEvent(new CustomEvent('closePopover', { detail: true}));
      });
    };
  
    var splitButton = document.getElementsByClassName('js-split-btn');
    if(splitButton.length > 0) {
      for( var i = 0; i < splitButton.length; i++) {
        (function(i){
          closeSplitBtnPopover(splitButton[i]);
        })(i);
      }
    }
  }());
  // File#: _2_sticky-sharebar
  // Usage: codyhouse.co/license
  (function() {
    var StickyShareBar = function(element) {
      this.element = element;
      this.contentTarget = document.getElementsByClassName('js-sticky-sharebar-target');
      this.contentTargetOut = document.getElementsByClassName('js-sticky-sharebar-target-out');
      this.showClass = 'sticky-sharebar--on-target';
      this.threshold = '50%'; // Share Bar will be revealed when .js-sticky-sharebar-target element reaches 50% of the viewport
      initShareBar(this);
      initTargetOut(this);
    };
  
    function initShareBar(shareBar) {
      if(shareBar.contentTarget.length < 1) {
        shareBar.showSharebar = true;
        Util.addClass(shareBar.element, shareBar.showClass);
        return;
      }
      if(intersectionObserverSupported) {
        shareBar.showSharebar = false;
        initObserver(shareBar); // update anchor appearance on scroll
      } else {
        Util.addClass(shareBar.element, shareBar.showClass);
      }
    };
  
    function initObserver(shareBar) { // target of Sharebar
      var observer = new IntersectionObserver(
        function(entries, observer) { 
          shareBar.showSharebar = entries[0].isIntersecting;
          toggleSharebar(shareBar);
        }, 
        {rootMargin: "0px 0px -"+shareBar.threshold+" 0px"}
      );
      observer.observe(shareBar.contentTarget[0]);
    };
  
    function initTargetOut(shareBar) { // target out of Sharebar
      shareBar.hideSharebar = false;
      if(shareBar.contentTargetOut.length < 1) {
        return;
      }
      var observer = new IntersectionObserver(
        function(entries, observer) { 
          shareBar.hideSharebar = entries[0].isIntersecting;
          toggleSharebar(shareBar);
        }
      );
      observer.observe(shareBar.contentTargetOut[0]);
    };
  
    function toggleSharebar(shareBar) {
      Util.toggleClass(shareBar.element, shareBar.showClass, shareBar.showSharebar && !shareBar.hideSharebar);
    };
  
    //initialize the StickyShareBar objects
    var stickyShareBar = document.getElementsByClassName('js-sticky-sharebar'),
      intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
    
  	if( stickyShareBar.length > 0 ) {
  		for( var i = 0; i < stickyShareBar.length; i++) {
  			(function(i){ new StickyShareBar(stickyShareBar[i]); })(i);
      }
  	}
  }());
  // File#: _2_svg-slideshow
  // Usage: codyhouse.co/license
  (function() {
    var ImgSlideshow = function(opts) {
      this.options = Util.extend(ImgSlideshow.defaults , opts);
  		this.element = this.options.element;
  		this.items = this.element.getElementsByClassName('js-svg-slideshow__item');
  		this.controls = this.element.getElementsByClassName('js-svg-slideshow__control'); 
  		this.selectedSlide = 0;
  		this.autoplayId = false;
  		this.autoplayPaused = false;
  		this.navigation = false;
  		this.navCurrentLabel = false;
  		this.ariaLive = false;
  		this.animating = false;
  		this.animatingClass = 'svg-slideshow--is-animating';
      // store svg animation paths
  		this.masks = this.element.getElementsByClassName('js-svg-slideshow__mask');
      this.maskNext = getMaskPoints(this, 'next');
  		this.maskPrev = getMaskPoints(this, 'prev');
  		// random number for mask id
  		this.maskId = getRandomInt(0, 10000);
  		initSlideshow(this);
  		initSlideshowEvents(this);
  		revealSlideshow(this);
    };
  
    function getMaskPoints(slideshow, direction) { // store the path points - will be used to transition between slides
      var array = [];
  		var index = direction == 'next' ? 0 : 1;
  		var groupElements = slideshow.masks[index].getElementsByTagName('g');
  		for(var j = 0; j < groupElements.length; j++) {
  			array[j] = [];
  			var paths =  groupElements[j].getElementsByTagName('path');
  			for(var i = 0; i < paths.length; i++) {
  				array[j].push(paths[i].getAttribute('d'));
  			}
  		}
      return array;
  	};
  	
  	function getRandomInt(min, max) {
  		min = Math.ceil(min);
  		max = Math.floor(max);
  		return Math.floor(Math.random() * (max - min)) + min;
  	};
    
    function initSlideshow(slideshow) { // basic slideshow settings
      // reset slide items content -> replace img element with svg
      for(var i = 0; i < slideshow.items.length; i++) {
        initSlideContent(slideshow, slideshow.items[i], i);
      }
  		// if no slide has been selected -> select the first one
  		if(slideshow.element.getElementsByClassName('svg-slideshow__item--selected').length < 1) Util.addClass(slideshow.items[0], 'svg-slideshow__item--selected');
  		slideshow.selectedSlide = Util.getIndexInArray(slideshow.items, slideshow.element.getElementsByClassName('svg-slideshow__item--selected')[0]);
  		// create an element that will be used to announce the new visible slide to SR
  		var srLiveArea = document.createElement('div');
  		Util.setAttributes(srLiveArea, {'class': 'sr-only js-svg-slideshow__aria-live', 'aria-live': 'polite', 'aria-atomic': 'true'});
  		slideshow.element.appendChild(srLiveArea);
  		slideshow.ariaLive = srLiveArea;
    };
  
    function initSlideContent(slideshow, slide, index) {
  		// replace each slide content with a svg element including image + clip-path
  		var imgElement = slide.getElementsByTagName('img')[0],
  			imgPath = imgElement.getAttribute('src'),
        imgAlt =  imgElement.getAttribute('alt'),
  			viewBox = slideshow.masks[0].getAttribute('viewBox').split(' '),
        imageCode = '<image height="'+viewBox[3]+'px" width="'+viewBox[2]+'px" clip-path="url(#img-slide-'+slideshow.maskId+'-'+index+')" xlink:href="'+imgPath+'" href="'+imgPath+'"></image>';
  		
  			var slideContent = '<svg aria-hidden="true" viewBox="0 0 '+viewBox[2]+' '+viewBox[3]+'"><defs><clipPath id="img-slide-'+slideshow.maskId+'-'+index+'">';
  
  			for(var i = 0; i < slideshow.maskNext.length; i++) {
  				slideContent = slideContent + '<path d="'+slideshow.maskNext[i][slideshow.maskNext[i].length - 1]+'"></path>';
  			}
  
  			slideContent = slideContent + '</clipPath></defs>'+imageCode+'</svg>';
  
      slide.innerHTML = imgElement.outerHTML + slideContent;
      if(imgAlt) slide.setAttribute('aria-label', imgAlt);
    };
  
    function initSlideshowEvents(slideshow) {
      // if slideshow navigation is on -> create navigation HTML and add event listeners
  		if(slideshow.options.navigation) {
  			var navigation = document.createElement('ol'),
  				navChildren = '';
  			
  			navigation.setAttribute('class', 'svg-slideshow__navigation');
  			for(var i = 0; i < slideshow.items.length; i++) {
  				var className = (i == slideshow.selectedSlide) ? 'class="svg-slideshow__nav-item svg-slideshow__nav-item--selected js-svg-slideshow__nav-item"' :  'class="svg-slideshow__nav-item js-svg-slideshow__nav-item"',
  					navCurrentLabel = (i == slideshow.selectedSlide) ? '<span class="sr-only js-svg-slideshow__nav-current-label">Current Item</span>' : '';
  				navChildren = navChildren + '<li '+className+'><button class="reset"><span class="sr-only">'+ (i+1) + '</span>'+navCurrentLabel+'</button></li>';
  			}
  
  			navigation.innerHTML = navChildren;
  			slideshow.navCurrentLabel = navigation.getElementsByClassName('js-svg-slideshow__nav-current-label')[0]; 
  			slideshow.element.appendChild(navigation);
  			slideshow.navigation = slideshow.element.getElementsByClassName('js-svg-slideshow__nav-item');
  
  			navigation.addEventListener('click', function(event){
  				navigateSlide(slideshow, event, true);
  			});
  			navigation.addEventListener('keyup', function(event){
  				navigateSlide(slideshow, event, (event.key.toLowerCase() == 'enter'));
  			});
  		}
      // slideshow arrow controls
  		if(slideshow.controls.length > 0) {
  			slideshow.controls[0].addEventListener('click', function(event){
  				event.preventDefault();
  				showNewItem(slideshow, slideshow.selectedSlide - 1, 'prev', true);
  			});
  			slideshow.controls[1].addEventListener('click', function(event){
  				event.preventDefault();
          showNewItem(slideshow, slideshow.selectedSlide + 1, 'next', true);
  			});
      }
      // swipe events
      if(slideshow.options.swipe) {
  			//init swipe
  			new SwipeContent(slideshow.element);
  			slideshow.element.addEventListener('swipeLeft', function(event){
  				showNewItem(slideshow, slideshow.selectedSlide + 1, 'next');
  			});
  			slideshow.element.addEventListener('swipeRight', function(event){
          showNewItem(slideshow, slideshow.selectedSlide - 1, 'prev');
  			});
  		}
      // autoplay
  		if(slideshow.options.autoplay) {
  			startAutoplay(slideshow);
  			// pause autoplay if user is interacting with the slideshow
  			slideshow.element.addEventListener('mouseenter', function(event){
  				pauseAutoplay(slideshow);
  				slideshow.autoplayPaused = true;
  			});
  			slideshow.element.addEventListener('focusin', function(event){
  				pauseAutoplay(slideshow);
  				slideshow.autoplayPaused = true;
  			});
  			slideshow.element.addEventListener('mouseleave', function(event){
  				slideshow.autoplayPaused = false;
  				startAutoplay(slideshow);
  			});
  			slideshow.element.addEventListener('focusout', function(event){
  				slideshow.autoplayPaused = false;
  				startAutoplay(slideshow);
  			});
  		}
  		// init slide theme colors
  		resetSlideshowTheme(slideshow, slideshow.selectedSlide);
  	};
  	
  	function revealSlideshow(slideshow) {
  		Util.addClass(slideshow.element, 'svg-slideshow--loaded');
  	};
  
    function showNewItem(slideshow, index, direction, bool) { // update visible slide
  		if(slideshow.animating) return;
  		slideshow.animating = true;
  		Util.addClass(slideshow.element, slideshow.animatingClass);
  		if(index < 0) index = slideshow.items.length - 1;
  		else if(index >= slideshow.items.length) index = 0;
  		// reset dot navigation appearance
  		resetSlideshowNav(slideshow, index, slideshow.selectedSlide);
  		// animate slide
  		newItemAnimate(slideshow, index, slideshow.selectedSlide, direction);
  		// if not autoplay, announce new slide to SR
      if(bool) updateAriaLive(slideshow, index); 
  		// reset controls/navigation color themes
  		resetSlideshowTheme(slideshow, index);
    };
  
    function newItemAnimate(slideshow, newIndex, oldIndex, direction) {
      // start slide transition
      var path = slideshow.items[newIndex].getElementsByTagName('path'),
  			mask = direction == 'next' ? slideshow.maskNext : slideshow.maskPrev;
  		for(var i = 0; i < path.length; i++) {
  			path[i].setAttribute('d', mask[i][0]);
  		}
      
      Util.addClass(slideshow.items[newIndex], 'svg-slideshow__item--animating');
      morphPath(path, mask, slideshow.options.transitionDuration, function(){ // morph callback function
        slideshow.items[oldIndex].setAttribute('aria-hidden', 'true');
        slideshow.items[newIndex].removeAttribute('aria-hidden');
        Util.addClass(slideshow.items[newIndex], 'svg-slideshow__item--selected');
        Util.removeClass(slideshow.items[newIndex], 'svg-slideshow__item--animating');
        Util.removeClass(slideshow.items[oldIndex], 'svg-slideshow__item--selected');
        slideshow.selectedSlide = newIndex;
  			slideshow.animating = false;
  			Util.removeClass(slideshow.element, slideshow.animatingClass);
        // reset autoplay
        pauseAutoplay(slideshow);
        startAutoplay(slideshow);
      });
    };
  
  	function morphPath(path, points, duration, cb) { // morph 
  		if(reducedMotion || !animeJSsupported) { // if reducedMotion on or JS animation not supported -> do not animate
  			for(var i = 0; i < path.length; i++) {
  				path[i].setAttribute('d', points[i][points[i].length - 1]);
  			}
  			cb();
        return;
  		}
  		for(var i = 0; i < path.length; i++) {
  			var delay = i*100,
  				cbFunction = (i == path.length - 1) ? cb : false;
  			morphSinglePath(path[i], points[i], delay, duration, cbFunction);
  		}
  	};
  	
  	function morphSinglePath(path, points, delay, duration, cb) {
  		var dAnimation = (points.length == 3) 
  			? [{ value: [points[0], points[1]]}, { value: [points[1], points[2]]}]
  			: [{ value: [points[0], points[1]]}];
      anime({
  			targets: path,
  			d: dAnimation,
        easing: 'easeOutQuad',
  			duration: duration,
  			delay: delay,
        complete: function() {
          if(cb) cb();
        }
      });
  	};
  
    function navigateSlide(slideshow, event, keyNav) { 
  		// user has interacted with the slideshow dot navigation -> update visible slide
  		var target = event.target.closest('.js-svg-slideshow__nav-item');
  		if(keyNav && target && !Util.hasClass(target, 'svg-slideshow__nav-item--selected')) {
        var index = Util.getIndexInArray(slideshow.navigation, target),
          direction = slideshow.selectedSlide < index ? 'next' : 'prev';
        showNewItem(slideshow, index, direction, true);
  		}
  	};
    
    function resetSlideshowNav(slideshow, newIndex, oldIndex) {
      if(slideshow.navigation) { // update selected dot
  			Util.removeClass(slideshow.navigation[oldIndex], 'svg-slideshow__nav-item--selected');
  			Util.addClass(slideshow.navigation[newIndex], 'svg-slideshow__nav-item--selected');
  			slideshow.navCurrentLabel.parentElement.removeChild(slideshow.navCurrentLabel);
  			slideshow.navigation[newIndex].getElementsByTagName('button')[0].appendChild(slideshow.navCurrentLabel);
  		}
  	};
  	
  	function resetSlideshowTheme(slideshow, newIndex) { 
  		// apply to controls/dot navigation, the same color-theme of the selected slide
  		var dataTheme = slideshow.items[newIndex].getAttribute('data-theme');
  		if(dataTheme) {
  			if(slideshow.navigation) slideshow.navigation[0].parentElement.setAttribute('data-theme', dataTheme);
  			if(slideshow.controls[0]) slideshow.controls[0].parentElement.setAttribute('data-theme', dataTheme);
  		} else {
  			if(slideshow.navigation) slideshow.navigation[0].parentElement.removeAttribute('data-theme');
  			if(slideshow.controls[0]) slideshow.controls[0].parentElement.removeAttribute('data-theme');
  		}
  	};
  
    function updateAriaLive(slideshow, index) { // announce new selected slide to SR
      var announce = 'Item '+(index + 1)+' of '+slideshow.items.length,
        label = slideshow.items[index].getAttribute('aria-label');
      if(label) announce = announce+' '+label;
  		slideshow.ariaLive.innerHTML = announce;
    };
  
    function startAutoplay(slideshow) {
  		if(slideshow.options.autoplay && !slideshow.autoplayId && !slideshow.autoplayPaused) {
  			slideshow.autoplayId = setInterval(function(){
  				showNewItem(slideshow, slideshow.selectedSlide + 1, 'next');
  			}, slideshow.options.autoplayInterval);
  		}
    };
  
    function pauseAutoplay(slideshow) {
      if(slideshow.options.autoplay) {
  			clearInterval(slideshow.autoplayId);
  			slideshow.autoplayId = false;
  		}
    };
    
    //initialize the ImgSlideshow objects
    var slideshows = document.getElementsByClassName('js-svg-slideshow'),
  		reducedMotion = Util.osHasReducedMotion(),
  		animeJSsupported = window.Map; // test if the library used for the animation works
  	if( slideshows.length > 0 ) {
  		for( var i = 0; i < slideshows.length; i++) {
  			(function(i){
  				var navigation = (slideshows[i].getAttribute('data-navigation') && slideshows[i].getAttribute('data-navigation') == 'off') ? false : true,
  					autoplay = (slideshows[i].getAttribute('data-autoplay') && slideshows[i].getAttribute('data-autoplay') == 'on') ? true : false,
  					autoplayInterval = (slideshows[i].getAttribute('data-autoplay-interval')) ? slideshows[i].getAttribute('data-autoplay-interval') : 5000,
  					swipe = (slideshows[i].getAttribute('data-swipe') && slideshows[i].getAttribute('data-swipe') == 'on') ? true : false,
  					transitionDuration = (slideshows[i].getAttribute('data-transition-duration')) ? slideshows[i].getAttribute('data-transition-duration') : 400;
  				new ImgSlideshow({element: slideshows[i], navigation: navigation, autoplay : autoplay, autoplayInterval : autoplayInterval, swipe : swipe, transitionDuration: transitionDuration});
  			})(i);
  		}
  	}
  }());
  // File#: _2_table-of-contents
  // Usage: codyhouse.co/license
  (function() {
    var Toc = function(element) {
  		this.element = element;
      this.list = this.element.getElementsByClassName('js-toc__list')[0];
      this.anchors = this.list.querySelectorAll('a[href^="#"]');
      this.sections = getSections(this);
      this.controller = this.element.getElementsByClassName('js-toc__control');
      this.controllerLabel = this.element.getElementsByClassName('js-toc__control-label');
      this.content = getTocContent(this);
      this.clickScrolling = false;
      this.intervalID = false;
      this.staticLayoutClass = 'toc--static';
      this.contentStaticLayoutClass = 'toc-content--toc-static';
      this.expandedClass = 'toc--expanded';
      this.isStatic = Util.hasClass(this.element, this.staticLayoutClass);
      this.layout = 'static';
      initToc(this);
    };
  
    function getSections(toc) {
      var sections = [];
      // get all content sections
      for(var i = 0; i < toc.anchors.length; i++) {
        var section = document.getElementById(toc.anchors[i].getAttribute('href').replace('#', ''));
        if(section) sections.push(section);
      }
      return sections;
    };
  
    function getTocContent(toc) {
      if(toc.sections.length < 1) return false;
      var content = toc.sections[0].closest('.js-toc-content');
      return content;
    };
  
    function initToc(toc) {
      checkTocLayour(toc); // switch between mobile and desktop layout
      if(toc.sections.length > 0) {
        // listen for click on anchors
        toc.list.addEventListener('click', function(event){
          var anchor = event.target.closest('a[href^="#"]');
          if(!anchor) return;
          // reset link apperance 
          toc.clickScrolling = true;
          resetAnchors(toc, anchor);
          // close toc if expanded on mobile
          toggleToc(toc, true);
        });
  
        // check when a new section enters the viewport
        var intersectionObserverSupported = ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype);
        if(intersectionObserverSupported) {
          var observer = new IntersectionObserver(
            function(entries, observer) { 
              entries.forEach(function(entry){
                if(!toc.clickScrolling) { // do not update classes if user clicked on a link
                  getVisibleSection(toc);
                }
              });
            }, 
            {
              threshold: [0, 0.1],
              rootMargin: "0px 0px -70% 0px"
            }
          );
  
          for(var i = 0; i < toc.sections.length; i++) {
            observer.observe(toc.sections[i]);
          }
        }
  
        // detect the end of scrolling -> reactivate IntersectionObserver on scroll
        toc.element.addEventListener('toc-scroll', function(event){
          toc.clickScrolling = false;
        });
      }
  
      // custom event emitted when window is resized
      toc.element.addEventListener('toc-resize', function(event){
        checkTocLayour(toc);
      });
  
      // collapsed version only (mobile)
      initCollapsedVersion(toc);
    };
  
    function resetAnchors(toc, anchor) {
      if(!anchor) return;
      for(var i = 0; i < toc.anchors.length; i++) Util.removeClass(toc.anchors[i], 'toc__link--selected');
      Util.addClass(anchor, 'toc__link--selected');
    };
  
    function getVisibleSection(toc) {
      if(toc.intervalID) {
        clearInterval(toc.intervalID);
      }
      toc.intervalID = setTimeout(function(){
        var halfWindowHeight = window.innerHeight/2,
        index = -1;
        for(var i = 0; i < toc.sections.length; i++) {
          var top = toc.sections[i].getBoundingClientRect().top;
          if(top < halfWindowHeight) index = i;
        }
        if(index > -1) {
          resetAnchors(toc, toc.anchors[index]);
        }
        toc.intervalID = false;
      }, 100);
    };
  
    function checkTocLayour(toc) {
      if(toc.isStatic) return;
      toc.layout = getComputedStyle(toc.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      Util.toggleClass(toc.element, toc.staticLayoutClass, toc.layout == 'static');
      if(toc.content) Util.toggleClass(toc.content, toc.contentStaticLayoutClass, toc.layout == 'static');
    };
  
    function initCollapsedVersion(toc) { // collapsed version only (mobile)
      if(toc.controller.length < 1) return;
      
      // toggle nav visibility
      toc.controller[0].addEventListener('click', function(event){
        var isOpen = Util.hasClass(toc.element, toc.expandedClass);
        toggleToc(toc, isOpen);
      });
  
      // close expanded version on esc
      toc.element.addEventListener('keydown', function(event){
        if(toc.layout == 'static') return;
        if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape') ) {
          toggleToc(toc, true);
          toc.controller[0].focus();
        }
      });
    };
  
    function toggleToc(toc, bool) { // collapsed version only (mobile)
      // toggle mobile version
      Util.toggleClass(toc.element, toc.expandedClass, !bool);
      bool ? toc.controller[0].removeAttribute('aria-expanded') : toc.controller[0].setAttribute('aria-expanded', 'true');
      if(!bool && toc.anchors.length > 0) {
        toc.anchors[0].focus();
      }
    };
    
    var tocs = document.getElementsByClassName('js-toc');
  
    var tocsArray = [];
  	if( tocs.length > 0) {
  		for( var i = 0; i < tocs.length; i++) {
  			(function(i){ tocsArray.push(new Toc(tocs[i])); })(i);
      }
  
      // listen to window scroll -> reset clickScrolling property
      var scrollId = false,
        resizeId = false,
        scrollEvent = new CustomEvent('toc-scroll'),
        resizeEvent = new CustomEvent('toc-resize');
        
      window.addEventListener('scroll', function() {
        clearTimeout(scrollId);
        scrollId = setTimeout(doneScrolling, 100);
      });
  
      window.addEventListener('resize', function() {
        clearTimeout(resizeId);
        scrollId = setTimeout(doneResizing, 100);
      });
  
      function doneScrolling() {
        for( var i = 0; i < tocsArray.length; i++) {
          (function(i){tocsArray[i].element.dispatchEvent(scrollEvent)})(i);
        };
      };
  
      function doneResizing() {
        for( var i = 0; i < tocsArray.length; i++) {
          (function(i){tocsArray[i].element.dispatchEvent(resizeEvent)})(i);
        };
      };
    }
  }());
  // File#: _2_weekly-schedule
  // Usage: codyhouse.co/license
  (function() {
    var WSchedule = function(opts) {
      this.options = Util.extend(WSchedule.defaults, opts);
      this.element = this.options.element;
      this.timeline = this.element.getAttribute('data-w-schedule-timeline');
      this.startTime = getStartTime(this);
      this.endTime = getEndTime(this);
      this.gridRows = 1;
      // grid template
      this.grid = this.element.getElementsByClassName('js-w-schedule__grid');
      this.halfHourGrid = '<div class="w-schedule__grid-row"></div>';
      this.hourGrid = '<div class="w-schedule__grid-row"><span class="w-schedule__grid-row-label">XXXX</span></div>';
      // morph animation duration
      this.animationDuration = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--w-schedule-modal-anim-duration'))*1000 || 300;
      // modal element 
      this.modal = document.getElementsByClassName('js-w-schedule-modal');
      this.morphBg = document.getElementsByClassName('js-w-schedule-morph-bg');
      this.modalCloseBtn = document.getElementsByClassName('js-w-schedule-close-btn');
      initWSchedule(this);
    };
  
    function initWSchedule(element) {
      // create grid
      createScheduleGrid(element);
      // place events on the grid
      placeEvents(element);
      // init modal
      initModalEvents(element);
    };
  
    function createScheduleGrid(element) {
      var gridContent = '';
      // check if we need to start with half an hour
      if(element.startTime[1] != 0) {
        gridContent = gridContent + element.halfHourGrid;
        element.startTime[0] = element.startTime[0] + 1;
        element.gridRows = element.gridRows + 1;
      }
  
      // get index loop
      var index = element.endTime[0] - element.startTime[0];
      for(var i = 0; i < index; i++) {
        gridContent = gridContent + getHourGrid(element, i) + element.halfHourGrid;
      }
  
      // add the last hour grid line
      gridContent = gridContent + getHourGrid(element, index);
  
      // update grid height 
      element.gridRows = element.gridRows + 2*index;
  
      // check if we need to add an additional half hour
      if(element.endTime[1] != 0) {
        gridContent = gridContent + element.halfHourGrid;
        element.gridRows = element.gridRows + 1;
      }
  
      // set grid element content
      element.grid[0].innerHTML = gridContent;
      // update grid element height
      element.element.style.setProperty('--w-schedule-row-nr', element.gridRows);
    };
  
    function placeEvents(element) {
      var events = element.element.getElementsByClassName('js-w-schedule__event');
      for(var i = 0; i < events.length; i++) {
        placeEvent(element, events[i]);
      }
    };
  
    function placeEvent(element, event) {
      var timeEl = event.getElementsByTagName('time')[0],
        timeInfo = timeEl.getAttribute('datetime');
  
      var top = getTime(timeInfo.split('PT')[0]),
        duration = getDuration(timeInfo.split('PT')[1]);
  
      var topDelta = getDelta(top[0] - element.startTime[0], top[1] - element.startTime[1]),
        durationDelta = getDelta(duration[0], duration[1]);
  
      event.style.setProperty('--w-schedule-event-top', 'calc(var(--w-schedule-row-height) * '+topDelta+')');
  
      event.style.setProperty('--w-schedule-event-height', 'calc(var(--w-schedule-row-height) * '+durationDelta+')');
  
      // now set the label for the event time
      timeEl.innerHTML = formatTime(top) + ' - ' + formatTime([top[0]+duration[0], top[1]+duration[1]]);
    };
  
    function getStartTime(element) {
      return getTime(element.timeline.split('-')[0]);
    };
  
    function getEndTime(element) {
      return getTime(element.timeline.split('-')[1]);
    };
  
    function getTime(time) {
      var array = time.split(':');
      return [parseInt(array[0]), parseInt(array[1])];
    };
  
    function getHourGrid(element, index) {
      // get the hour format
      var hour = formatHour(element.startTime[0] + index);
      return element.hourGrid.replace('XXXX', hour+':00');
    };
  
    function formatTime(time) {
      // first check if minutes >= 60 and increase hours
      if(time[1] >= 60) {
        var remainder = time[1]%60;
        time[0] = time[0] + (time[1] - remainder)/60;
        time[1] = remainder;
      }
      return formatHour(time[0])+':'+ formatMinutes(time[1]);
    };
  
    function formatHour(hour) {
      // e.g., 9 -> 09; 12 -> 12
      if(hour < 10) return '0'+hour;
      if(hour > 24) return formatHour(hour - 24);
      return hour;
    };
  
    function formatMinutes(minutes) {
      // e.g., 9 -> 09; 30 -> 30
      if(minutes < 10) return '0'+minutes;
      if(minutes > 60) return formatMinutes(minutes - 60);
      return minutes;
    };
  
    function getDuration(duration) {
      var hour = 0;
      if(duration. indexOf('H') > -1) {
        var array = duration.split('H');
        duration = array[1];
        hour = parseInt(array[0]);
      }
      var minutes = 0;
      if(duration. indexOf('M') > -1) {
        minutes = parseInt(duration.split('M')[0]);
      }
      return [hour, minutes];
    };
  
    function getDelta(hour, minutes) {
      // this will return a number; e.g. 1h -> 2; 1h30m -> 3; 1h15m -> 2.5
      return 2*(hour + minutes/60);
    };
  
    function initModalEvents(element) {
      if(element.modal.length < 1 || element.morphBg.length < 1) return;
      // store some modal info
      element.modalContent = element.modal[0].getElementsByClassName('js-w-schedule-modal__content')[0];
      element.skeletonContent = element.modalContent.innerHTML;
      element.modalId = element.modal[0].getAttribute('id');
  
      // detect modal opening
      element.modal[0].addEventListener('modalIsOpen', function(event){
        element.target = event.detail.closest('[aria-controls="'+element.modalId+'"]');
        // animate morph bg
        animateMorphBg(element, function(){
          // hide morph element and reset style
          Util.addClass(element.morphBg[0], 'is-hidden');
          element.morphBg[0].style = '';
          Util.removeClass(element.modalContent, 'opacity-0');
        });
        // load event content
        setModalContent(element);
        // show modal close btn
        toggleModalCloseBtn(element, true);
      });
  
      // detect modal closing
      element.modal[0].addEventListener('modalIsClose', function(event) {
        element.modal[0].addEventListener('transitionend', function cb(event) {
          if(event.propertyName != 'opacity') return;
          resetModalContent(element);
  
          element.modal[0].removeEventListener('transitionend', cb);
        });
        element.target = false;
        // hide modal close btn
        toggleModalCloseBtn(element, false);
        // reset modal content if reduced motion is on
        if(reducedMotion) resetModalContent(element);
      });
  
      // close modal clicking on close btn
      if(element.modalCloseBtn.length > 0) {
        element.modalCloseBtn[0].addEventListener('click', function(event) {
          element.modal[0].click();
        });
      }
    };
  
    function animateMorphBg(element, cb) {
      if(reducedMotion) return cb();
      var startPoint = element.target.getBoundingClientRect(),
        endPoint = element.modalContent.getBoundingClientRect();
      
      var translateX = endPoint.left - startPoint.left,
        translateY = endPoint.top - startPoint.top,
        scaleX = startPoint.width/endPoint.width,
        scaleY = startPoint.height/endPoint.height;
  
      var currentTime = null,
        duration = element.animationDuration;
  
      // init element
      element.morphBg[0].style = 'top: '+startPoint.top+'px; left: '+startPoint.left+'px; width: '+endPoint.width+'px; height: '+endPoint.height+'px; transform: scaleX('+scaleX+') scaleY('+scaleY+')';
      // show element
      Util.removeClass(element.morphBg[0], 'is-hidden');
      
      // animate from initial to final state
      var animateElement = function(timestamp) {
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
  
        var scaleXPr = Math.easeOutQuart(progress, scaleX, 1 - scaleX, duration),
          scaleYPr = Math.easeOutQuart(progress, scaleY, 1 - scaleY, duration),
          translateXPr = Math.easeOutQuart(progress, 0, translateX, duration),
          translateYPr = Math.easeOutQuart(progress, 0, translateY, duration);
          
        element.morphBg[0].style.transform = 'translateX('+translateXPr+'px) translateY('+translateYPr+'px) scaleX('+scaleXPr+') scaleY('+scaleYPr+')';
  
        if(progress < duration) {
          window.requestAnimationFrame(animateElement);
        } else if(cb) {
          cb();
        }
      };  
  
      window.requestAnimationFrame(animateElement);
    };
  
    function toggleModalCloseBtn(element, bool) {
      if(element.modalCloseBtn.length > 0) {
        Util.toggleClass(element.modalCloseBtn[0], 'w-schedule-close-btn--is-visible', bool);
      }
    };
  
    function setModalContent(element) {
      // load the modal info details - using the searchData custom function the user defines
      element.options.searchData(element.target, function(data){
        Util.addClass(element.modalContent, 'w-schedule-modal__content--loaded');
        element.modalContent.innerHTML = data;
      });
    };
  
    function resetModalContent(element) {
      Util.addClass(element.modalContent, 'opacity-0');
      element.modalContent.innerHTML = element.skeletonContent;
      Util.removeClass(element.modalContent, 'w-schedule-modal__content--loaded');
    };
  
    window.WSchedule = WSchedule;
  
    WSchedule.defaults = {
      element : '',
      searchData: false, // function used to return results
    };
  
    var reducedMotion = Util.osHasReducedMotion();
  }());
  // File#: _3_advanced-filter
  // Usage: codyhouse.co/license
  (function() {
    // the AdvFilter object is used to handle: 
    // - number of results
    // - form reset
    // - filtering sections label (to show a preview of the option selected by the users)
    var AdvFilter = function(element) {
      this.element = element; 
      this.form = this.element.getElementsByClassName('js-adv-filter__form');
      this.resultsList = this.element.getElementsByClassName('js-adv-filter__gallery')[0];
      this.resultsCount = this.element.getElementsByClassName('js-adv-filter__results-count');
      initAdvFilter(this);
    };
  
    function initAdvFilter(filter) {
      if(filter.form.length > 0) {
        // reset form
        filter.form[0].addEventListener('reset', function(event){
          setTimeout(function(){
            resetFilters(filter);
            resetGallery(filter);
          });
        });
        // update section labels on form change
        filter.form[0].addEventListener('change', function(event){
          var section = event.target.closest('.js-adv-filter__item');
          if(section) resetSelection(filter, section);
          else if( Util.is(event.target, '.js-adv-filter__form') ) {
            // reset the entire form lables
            var sections = filter.form[0].getElementsByClassName('js-adv-filter__item');
            for(var i = 0; i < sections.length; i++) resetSelection(filter, sections[i]);
          }
        });
      }
  
      // reset results count
      if(filter.resultsCount.length > 0) {
        filter.resultsList.addEventListener('filter-selection-updated', function(event){
          updateResultsCount(filter);
        });
      }
    };
  
    function resetFilters(filter) {
      // check if there are custom form elemets - reset appearance
      // custom select
      var customSelect = filter.element.getElementsByClassName('js-select');
      if(customSelect.length > 0) {
        for(var i = 0; i < customSelect.length; i++) customSelect[i].dispatchEvent(new CustomEvent('select-updated'));
      }
      // custom slider
      var customSlider = filter.element.getElementsByClassName('js-slider');
      if(customSlider.length > 0) {
        for(var i = 0; i < customSlider.length; i++) customSlider[i].dispatchEvent(new CustomEvent('slider-updated'));
      }
    };
  
    function resetSelection(filter, section) {
      // change label value based on input types
      var labelSelection = section.getElementsByClassName('js-adv-filter__selection');
      if(labelSelection.length == 0) return;
      // select
      var select = section.getElementsByTagName('select');
      if(select.length > 0) {
        labelSelection[0].textContent = getSelectLabel(section, select[0]);
        return;
      }
      // input number
      var number = section.querySelectorAll('input[type="number"]');
      if(number.length > 0) {
        labelSelection[0].textContent = getNumberLabel(section, number);
        return;
      }
      // input range
      var slider = section.querySelectorAll('input[type="range"]');
      if(slider.length > 0) {
        labelSelection[0].textContent = getSliderLabel(section, slider);
        return;
      }
      // radio/checkboxes
      var radio = section.querySelectorAll('input[type="radio"]'),
        checkbox = section.querySelectorAll('input[type="checkbox"]');
      if(radio.length > 0) {
        labelSelection[0].textContent = getInputListLabel(section, radio);
        return;
      } else if(checkbox.length > 0) {
        labelSelection[0].textContent = getInputListLabel(section, checkbox);
        return;
      }
    };
  
    function getSelectLabel(section, select) {
      if(select.multiple) {
        var label = '',
          counter = 0;
        for (var i = 0; i < select.options.length; i++) {
          if(select.options[i].selected) {
            label = label + '' + select.options[i].text;
            counter = counter + 1;
          } 
          if(counter > 1) label = section.getAttribute('data-multi-select-text').replace('{n}', counter);
        }
        return label;
      } else {
        return select.options[select.selectedIndex].text;
      }
    };
  
    function getNumberLabel(section, number) {
      var counter = 0;
      for(var i = 0; i < number.length; i++) {
        if(number[i].value != number[i].min) counter = counter + 1;
      }
      if(number.length > 1) { // multiple input number in this section
        if(counter > 0) {
          return section.getAttribute('data-multi-select-text').replace('{n}', counter);
        } else {
          return section.getAttribute('data-default-text');
        }
        
      } else {
        if(number[0].value == number[0].min) return section.getAttribute('data-default-text');
        else return section.getAttribute('data-number-format').replace('{n}', number[0].value);
      }
    };
  
    function getSliderLabel(section, slider) {
      var label = '',
        labelFormat = section.getAttribute('data-number-format');
      for(var i = 0; i < slider.length; i++) {
        if(i != 0 ) label = label+' - ';
        label = label + labelFormat.replace('{n}', slider[i].value);
      }
      return label;
    };
  
    function getInputListLabel(section, inputs) {
      var counter = 0;
        label = '';
      for(var i = 0; i < inputs.length; i++) {
        if(inputs[i].checked) {
          var labelElement = inputs[i].parentNode.getElementsByTagName('label');
          if(labelElement.length > 0) label = labelElement[0].textContent;
          counter = counter + 1;
        }
      }
      if(counter > 1) return section.getAttribute('data-multi-select-text').replace('{n}', counter);
      else if(counter == 0 ) return section.getAttribute('data-default-text');
      else return label;
    };
  
    function resetGallery(filter) {
      // emit change event + reset filtering 
      filter.form[0].dispatchEvent(new CustomEvent('change'));
      filter.resultsList.dispatchEvent(new CustomEvent('update-filter-results'));
    };
  
    function updateResultsCount(filter) {
      var resultItems = filter.resultsList.children,
        counter = 0;
      for(var i = 0; i < resultItems.length; i++) {
        if(isVisible(resultItems[i])) counter = counter + 1;
      }
      filter.resultsCount[0].textContent = counter;
    };
  
    function isVisible(element) {
  		return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  	};
    
    //initialize the AdvFilter objects
  	var advFilter = document.getElementsByClassName('js-adv-filter');
  	if( advFilter.length > 0 ) {
  		for( var i = 0; i < advFilter.length; i++) {
  			(function(i){new AdvFilter(advFilter[i]);})(i);
  		}
    }
  
    // Remove the code below if you want to use a custom filtering function (e.g., you need to fetch your results from a database)
    
    // The code below is used for filtering of page content (animation of DOM elements, no fetching results from database).  
    // It uses the Filter component (https://codyhouse.co/ds/components/app/filter) - you can modify the custom filtering functions based on your needs
    // Check the info page of the component for info on how to use it: https://codyhouse.co/ds/components/info/filter
    var gallery = document.getElementById('adv-filter-gallery');
    if(gallery) {
      new Filter({
        element: gallery, // this is your gallery element
        priceRange: function(items){ // this is the price custom function
          var filteredArray = [],
            minVal = document.getElementById('slider-min-value').value,
            maxVal = document.getElementById('slider-max-value').value;
          for(var i = 0; i < items.length; i++) {
            var price = parseInt(items[i].getAttribute('data-price'));
            filteredArray[i] = (price >= minVal) && (price <= maxVal);
          } 
          return filteredArray;
        },
        indexValue: function(items){ // this is the index custom function
          var filteredArray = [],
            value = document.getElementById('index-value').value;
          for(var i = 0; i < items.length; i++) {
            var index = parseInt(items[i].getAttribute('data-sort-index'));
            filteredArray[i] = index >= value;
          } 
          return filteredArray;
        },
        searchInput: function(items) {
          var filteredArray = [],
            value = document.getElementById('search-products').value;
          for(var i = 0; i < items.length; i++) {
            var searchFilter = items[i].getAttribute('data-search');
            filteredArray[i] = searchFilter == '' || searchFilter.toLowerCase().indexOf(value.toLowerCase()) > -1;
          } 
          return filteredArray;
        }
      });
    }
  }());
  // File#: _3_area-chart
  // Usage: codyhouse.co/license
  (function() {
    // --default chart demo
    var areaChart1 = document.getElementById('area-chart-1');
    if(areaChart1) {
      new Chart({
        element: areaChart1,
        type: 'area',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {
            data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]
          }
        ],
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> $'+chartOptions.datasets[datasetIndex].data[index]+'';
          }
        },
        animate: true
      });
    };
  
    // --smooth chart demo
    var areaChart2 = document.getElementById('area-chart-2');
    if(areaChart2) {
      new Chart({
        element: areaChart2,
        type: 'area',
        smooth: true,
        xAxis : {
          line: true,
          range: [0, 10],
          step: 2,
          labels: true
        },
        yAxis: {
          labels: true
        },
        datasets: [
          {
            data: [[0, 1], [1, 2], [2, -3], [3, 12], [4, 8], [5, 7], [6, 10], [7, 4], [8, 9], [9, 5], [10, 16]]
          }
        ],
        tooltip: {
          enabled: true,
          position: 'top',
          customHTML: function(index, chartOptions, datasetIndex) {
            // show only Y value (chartOptions.datasets[datasetIndex].data[index][1])
            return 'Value: <span class="color-primary">'+chartOptions.datasets[datasetIndex].data[index][1]+'</span>';
          }
        },
        animate: true
      });
    }
  
    // --negative-values chart demo
    var areaChart3 = document.getElementById('area-chart-3');
    if(areaChart3) {
      new Chart({
        element: areaChart3,
        type: 'area',
        fillOrigin: true,
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {
            data: [10, 7, 4, -1, -5, -7, -6, -4, -1, 3, 5, 2]
          }
        ],
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> '+chartOptions.datasets[datasetIndex].data[index]+'$';
          }
        },
        animate: true
      });
    }
  
    // --multiset chart demo
    var multiSet = document.getElementById('multi-set-chart');
    if(multiSet) {
      new Chart({
        element: multiSet,
        type: 'area',
        xAxis: {
          line: true,
          ticks: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months'
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [5, 7, 11, 13, 18, 16, 17, 13, 16, 8, 15, 8]},
          {data: [1, 2, 3, 6, 4, 11, 9, 10, 9, 4, 7, 3]}
        ],
        tooltip: {
          enabled: true,
          position: 'top',
          customHTML: function(index, chartOptions, datasetIndex) {
            var html = '<p class="margin-bottom-xxs">Total '+chartOptions.xAxis.labels[index] + '</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-primary margin-right-xxs"></span>$'+chartOptions.datasets[0].data[index]+'</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-accent margin-right-xxs"></span>$'+chartOptions.datasets[1].data[index]+'</p>';
            return html;
          }
        },
        animate: true
      });
    }
  
    // --external-data-value chart demo
    var externalData = document.getElementById('ext-area-chart');
    if(externalData) {
      new Chart({
        element: externalData,
        type: 'area',
        xAxis: {
          line: true,
          ticks: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months'
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 6, 4, 11, 9, 10, 9, 4, 7, 3]},
        ],
        animate: true,
        externalData : {
          customXHTML: function(index, chartOptions, datasetIndex) {
            return ' '+chartOptions.xAxis.labels[index];
          }
        }
      });
    }
  }());
  // File#: _3_column-chart
  // Usage: codyhouse.co/license
  (function() {
    // --default chart demo
    var columnChart1 = document.getElementById('column-chart-1');
    if(columnChart1) {
      new Chart({
        element: columnChart1,
        type: 'column',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]},
        ],
        column: {
          width: '60%',
          gap: '2px',
          radius: '4px'
        },
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> $'+chartOptions.datasets[datasetIndex].data[index]+'';
          }
        },
        animate: true
      });
    };
  
    // --multiset chart demo
    var columnChart2 = document.getElementById('column-chart-2');
    if(columnChart2) {
      new Chart({
        element: columnChart2,
        type: 'column',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]},
          {data: [4, 8, 10, 12, 15, 11, 7, 3, 5, 2, 12, 6]}
        ],
        column: {
          width: '60%',
          gap: '2px',
          radius: '4px'
        },
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            var html = '<p class="margin-bottom-xxs">Total '+chartOptions.xAxis.labels[index] + '</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-primary margin-right-xxs"></span>$'+chartOptions.datasets[0].data[index]+'</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-contrast-higher margin-right-xxs"></span>$'+chartOptions.datasets[1].data[index]+'</p>';
            return html;
          },
          position: 'top'
        },
        animate: true
      });
    };
  
    // --stacked chart demo
    var columnChart3 = document.getElementById('column-chart-3');
    if(columnChart3) {
      new Chart({
        element: columnChart3,
        type: 'column',
        stacked: true,
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]},
          {data: [4, 8, 10, 12, 15, 11, 7, 3, 5, 2, 12, 6]}
        ],
        column: {
          width: '60%', 
          gap: '2px',
          radius: '4px'
        },
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            var html = '<p class="margin-bottom-xxs">Total '+chartOptions.xAxis.labels[index] + '</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-primary margin-right-xxs"></span>$'+chartOptions.datasets[0].data[index]+'</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-contrast-higher margin-right-xxs"></span>$'+chartOptions.datasets[1].data[index]+'</p>';
            return html;
          },
          position: 'top'
        },
        animate: true
      });
    };
  
    // --negative-values chart demo
    var columnChart4 = document.getElementById('column-chart-4');
    if(columnChart4) {
      new Chart({
        element: columnChart4,
        type: 'column',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 4, 8, 5, 3, -2, -5, -7, 4, 9, 5, 10, 3]},
        ],
        column: {
          width: '60%',
          gap: '2px',
          radius: '4px'
        },
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> '+chartOptions.datasets[datasetIndex].data[index]+'$';
          }
        },
        animate: true
      });
    };
  }());
  // File#: _3_dashboard-navigation
  // Usage: codyhouse.co/license
  (function() {
    var appUi = document.getElementsByClassName('js-app-ui');
    if(appUi.length > 0) {
      var appMenuBtn = appUi[0].getElementsByClassName('js-app-ui__menu-btn');
      if(appMenuBtn.length < 1) return;
      var appExpandedClass = 'app-ui--nav-expanded';
      var firstFocusableElement = false,
        // we'll use these to store the node that needs to receive focus when the mobile menu is closed 
        focusMenu = false;
  
      // toggle navigation on mobile
      appMenuBtn[0].addEventListener('click', function(event) {
        var openMenu = !Util.hasClass(appUi[0], appExpandedClass);
        Util.toggleClass(appUi[0], appExpandedClass, openMenu);
        appMenuBtn[0].setAttribute('aria-expanded', openMenu);
  			if(openMenu) {
          firstFocusableElement = getMenuFirstFocusable();
          if(firstFocusableElement) firstFocusableElement.focus(); // move focus to first focusable element
        } else if(focusMenu) {
  				focusMenu.focus();
  				focusMenu = false;
  			}
      });
  
      // listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(appMenuBtn[0].getAttribute('aria-expanded') == 'true' && isVisible(appMenuBtn[0])) {
  					focusMenu = appMenuBtn[0]; // move focus to menu trigger when menu is close
  					appMenuBtn[0].click();
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(appMenuBtn[0].getAttribute('aria-expanded') == 'true' && isVisible(appMenuBtn[0]) && !document.activeElement.closest('.js-app-ui__nav')) appMenuBtn[0].click();
  			}
      });
      
      // listen for resize
  		var resizingId = false;
  		window.addEventListener('resize', function() {
  			clearTimeout(resizingId);
  			resizingId = setTimeout(doneResizing, 500);
  		});
  
  		function doneResizing() {
  			if( !isVisible(appMenuBtn[0]) && Util.hasClass(appUi[0], appExpandedClass)) appMenuBtn[0].click();
  		};
  
      function getMenuFirstFocusable() {
        var mobileNav = appUi[0].getElementsByClassName('js-app-ui__nav');
        if(mobileNav.length < 1) return false;
  			var focusableEle = mobileNav[0].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex="-1"]), [controls], summary'),
          firstFocusable = false;
  			for(var i = 0; i < focusableEle.length; i++) {
  				if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
  					firstFocusable = focusableEle[i];
  					break;
  				}
        }
        
  			return firstFocusable;
      };
      
      function isVisible(element) {
        return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
      };
    }
  }());
  // File#: _3_drop-menu
  // Usage: codyhouse.co/license
  (function() {
    var DropMenu = function(element) {
      this.element = element;
      this.innerElement = this.element.getElementsByClassName('js-drop-menu__inner');
      this.trigger = document.querySelector('[aria-controls="'+this.element.getAttribute('id')+'"]');
      this.autocompleteInput = false;
      this.autocompleteList = false;
      this.animationDuration = parseFloat(getComputedStyle(this.element).getPropertyValue('--drop-menu-transition-duration')) || 0.3;
      // store some basic classes
      this.menuIsVisibleClass = 'drop-menu--is-visible';
      this.menuLevelClass = 'js-drop-menu__list';
      this.menuBtnInClass = 'js-drop-menu__btn--sublist-control';
      this.menuBtnOutClass = 'js-drop-menu__btn--back';
      this.levelInClass = 'drop-menu__list--in';
      this.levelOutClass = 'drop-menu__list--out';
      // store the max height of the element
      this.maxHeight = false;
      // store drop menu layout 
      this.layout = false;
      // vertical gap - desktop layout
      this.verticalGap = parseInt(getComputedStyle(this.element).getPropertyValue('--drop-menu-gap-y')) || 4;
      // store autocomplete search results
      this.searchResults = [];
      // focusable elements
      this.focusableElements = [];
      initDropMenu(this);
    };
  
    function initDropMenu(menu) {
      // trigger drop menu opening/closing
      toggleDropMenu(menu);
      // toggle sublevels
      menu.element.addEventListener('click', function(event){
        // check if we need to show a new sublevel
        var menuBtnIn = event.target.closest('.'+menu.menuBtnInClass);
        if(menuBtnIn) showSubLevel(menu, menuBtnIn);
        // check if we need to go back to a previous level
        var menuBtnOut = event.target.closest('.'+menu.menuBtnOutClass);
        if(menuBtnOut) hideSubLevel(menu, menuBtnOut);
      });
      // init automplete search
      initAutocomplete(menu);
      // close drop menu on focus out
      initFocusOut(menu);
    };
  
    function toggleDropMenu(menu) { // toggle drop menu
      if(!menu.trigger) return;
      // actions to be performed when closing the drop menu
      menu.dropMenuClosed = function(event) {
        if(event.propertyName != 'visibility') return;
        if(getComputedStyle(menu.element).getPropertyValue('visibility') != 'hidden') return;
        menu.element.removeEventListener('transitionend', menu.dropMenuClosed);
        menu.element.removeAttribute('style');
        resetAllLevels(menu); // go back to main list
        resetAutocomplete(menu); // if autocomplte is enabled -> reset input fields
      };
  
      // on mobile - close drop menu when clicking on close btn
      menu.element.addEventListener('click', function(event){
        var target = event.target.closest('.js-drop-menu__close-btn');
        if(!target || !dropMenuVisible(menu)) return;
        menu.trigger.click();
      });
  
      // click on trigger
      menu.trigger.addEventListener('click', function(event){
        menu.element.removeEventListener('transitionend', menu.dropMenuClosed);
        var isVisible = dropMenuVisible(menu);
        Util.toggleClass(menu.element, menu.menuIsVisibleClass, !isVisible);
        isVisible ? menu.trigger.removeAttribute('aria-expanded') : menu.trigger.setAttribute('aria-expanded', true);
        if(isVisible) {
          menu.element.addEventListener('transitionend', menu.dropMenuClosed);
        } else {
          menu.element.addEventListener('transitionend', function cb(){
            menu.element.removeEventListener('transitionend', cb);
            focusFirstElement(menu, menu.element);
          });
          getLayoutValue(menu);
          setDropMenuMaxHeight(menu); // set max-height
          placeDropMenu(menu); // desktop only
        }
      });
    };
  
    function dropMenuVisible(menu) {
      return Util.hasClass(menu.element, menu.menuIsVisibleClass);
    };
  
    function showSubLevel(menu, menuBtn) {
      var mainLevel = menuBtn.closest('.'+menu.menuLevelClass),
        subLevel = Util.getChildrenByClassName(menuBtn.parentNode, menu.menuLevelClass);
      if(!mainLevel || subLevel.length == 0 ) return;
      // trigger classes
      Util.addClass(subLevel[0], menu.levelInClass);
      Util.addClass(mainLevel, menu.levelOutClass);
      Util.removeClass(mainLevel, menu.levelInClass);
      // animate height of main element
      animateDropMenu(menu, mainLevel.offsetHeight, subLevel[0].offsetHeight, function(){
        focusFirstElement(menu, subLevel[0]);
      });
    };
  
    function hideSubLevel(menu, menuBtn) {
      var subLevel = menuBtn.closest('.'+menu.menuLevelClass),
        mainLevel = subLevel.parentNode.closest('.'+menu.menuLevelClass);
      if(!mainLevel || !subLevel) return;
      // trigger classes
      Util.removeClass(subLevel, menu.levelInClass);
      Util.addClass(mainLevel, menu.levelInClass);
      Util.removeClass(mainLevel, menu.levelOutClass);
      // animate height of main element
      animateDropMenu(menu, subLevel.offsetHeight, mainLevel.offsetHeight, function(){
        var menuBtnIn = Util.getChildrenByClassName(subLevel.parentNode, menu.menuBtnInClass);
        if(menuBtnIn.length > 0) menuBtnIn[0].focus();
        // if primary level -> reset height of element + inner element
        if(Util.hasClass(mainLevel, 'js-drop-menu__list--main') && menu.layout == 'desktop') {
          menu.element.style.height = '';
          if(menu.innerElement.length > 0) menu.innerElement[0].style.height = '';
        }
      });
    };
  
    function animateDropMenu(menu, initHeight, finalHeight, cb) {
      if(menu.innerElement.length < 1) {
        if(cb) setTimeout(function(){cb();}, menu.animationDuration*1000);
        return;
      }
      if(menu.layout == 'mobile') {
        menu.innerElement[0].style.height = finalHeight+"px";
        if(cb) setTimeout(function(){cb();}, menu.animationDuration*1000);
        return;
      } else {
        menu.innerElement[0].style.height = "";
      }
      var resetHeight = false;
      // make sure init and final height are smaller than max height
      if(initHeight > menu.maxHeight) initHeight = menu.maxHeight;
      if(finalHeight > menu.maxHeight) {
        resetHeight = finalHeight;
        finalHeight = menu.maxHeight;
      }
      var change = finalHeight - initHeight,
        currentTime = null,
        duration = menu.animationDuration*1000;
  
      var animateHeight = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
        var val = Math.easeOutQuart(progress, initHeight, change, duration);
        menu.element.style.height = val+"px";
        if(progress < duration) {
          window.requestAnimationFrame(animateHeight);
        } else {
          menu.innerElement[0].style.height = resetHeight ? resetHeight+'px' : '';
          if(cb) cb();
        }
      };
      
      //set the height of the element before starting animation -> fix bug on Safari
      menu.element.style.height = initHeight+"px";
      window.requestAnimationFrame(animateHeight);
    };
  
    function resetAllLevels(menu) {
      var openLevels = menu.element.getElementsByClassName(menu.levelInClass),
        closeLevels = menu.element.getElementsByClassName(menu.levelOutClass);
      while(openLevels[0]) {
        Util.removeClass(openLevels[0], menu.levelInClass);
      }
      while(closeLevels[0]) {
        Util.removeClass(closeLevels[0], menu.levelOutClass);
      }
    };
  
    function focusFirstElement(menu, level) {
      var element = getFirstFocusable(level);
      element.focus();
    };
  
    function getFirstFocusable(element) {
      var elements = element.querySelectorAll(focusableElString);
      for(var i = 0; i < elements.length; i++) {
  			if(elements[i].offsetWidth || elements[i].offsetHeight || elements[i].getClientRects().length) {
  				return elements[i];
  			}
  		}
    };
  
    function getFocusableElements(menu) { // all visible focusable elements
      var elements = menu.element.querySelectorAll(focusableElString);
      menu.focusableElements = [];
      for(var i = 0; i < elements.length; i++) {
  			if( isVisible(menu, elements[i]) ) menu.focusableElements.push(elements[i]);
  		}
    };
  
    function isVisible(menu, element) {
      var elementVisible = false;
      if( (element.offsetWidth || element.offsetHeight || element.getClientRects().length) && getComputedStyle(element).getPropertyValue('visibility') == 'visible') {
        elementVisible = true;
        if(menu.element.contains(element) && element.parentNode) elementVisible = isVisible(menu, element.parentNode);
      }
      return elementVisible;
    };
  
    function initAutocomplete(menu) {
      if(!Util.hasClass(menu.element, 'js-autocomplete')) return;
      // get list of search results
      getSearchResults(menu);
      var autocompleteCharacters = 1;
      menu.autocompleteInput = menu.element.getElementsByClassName('js-autocomplete__input');
      menu.autocompleteList = menu.element.getElementsByClassName('js-autocomplete__results');
      new Autocomplete({
        element: menu.element,
        characters: autocompleteCharacters,
        searchData: function(query, cb) {
          var data = [];
          if(query.length >= autocompleteCharacters) {
            data = menu.searchResults.filter(function(item){
              return item['label'].toLowerCase().indexOf(query.toLowerCase()) > -1;
            });
          }
          cb(data);
        }
      });
    };
  
    function resetAutocomplete(menu) {
      if(menu.autocompleteInput && menu.autocompleteInput.length > 0) {
        menu.autocompleteInput[0].value = '';
      }
    };
  
    function getSearchResults(menu) {
      var anchors = menu.element.getElementsByClassName('drop-menu__link');
      for(var i = 0; i < anchors.length; i++) {
        menu.searchResults.push({label: anchors[i].textContent, url: anchors[i].getAttribute('href')});
      }
    };
  
    function setDropMenuMaxHeight(menu) {
      if(!menu.trigger) return;
      if(menu.layout == 'mobile') {
        menu.maxHeight = '100%';
        menu.element.style.maxHeight = menu.maxHeight;
        if(menu.autocompleteList.length > 0) menu.autocompleteList[0].style.maxHeight = 'calc(100% - '+menu.autocompleteInput[0].offsetHeight+'px)';
      } else {
        menu.maxHeight = window.innerHeight - menu.trigger.getBoundingClientRect().bottom - menu.verticalGap - 15;
        menu.element.style.maxHeight = menu.maxHeight + 'px';
        if(menu.autocompleteList.length > 0) menu.autocompleteList[0].style.maxHeight = (menu.maxHeight - menu.autocompleteInput[0].offsetHeight) + 'px';
      }
    };
  
    function getLayoutValue(menu) {
      menu.layout = getComputedStyle(menu.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
    };
  
    function placeDropMenu(menu) {
      if(menu.layout == 'mobile') {
        menu.element.style.top = menu.element.style.left = menu.element.style.right = '';
      } else {
        var selectedTriggerPosition = menu.trigger.getBoundingClientRect();
  			
        var left = selectedTriggerPosition.left,
          right = (window.innerWidth - selectedTriggerPosition.right),
          isRight = (window.innerWidth < selectedTriggerPosition.left + menu.element.offsetWidth);
  
        var rightVal = 'auto', leftVal = 'auto';
        if(isRight) {
          rightVal = right+'px';
        } else {
          leftVal = left+'px';
        }
  
        var topVal = (selectedTriggerPosition.bottom+menu.verticalGap)+'px';
        if( isRight && (right + menu.element.offsetWidth) > window.innerWidth) {
          rightVal = 'auto';
          leftVal = parseInt((window.innerWidth - menu.element.offsetWidth)/2)+'px';
        }
        menu.element.style.top = topVal;
        menu.element.style.left = leftVal;
        menu.element.style.right = rightVal;
      }
    };
  
    function closeOnResize(menu) {
      getLayoutValue(menu);
      if(menu.layout == 'mobile' || !dropMenuVisible(menu)) return;
      menu.trigger.click();
    };
  
    function closeOnClick(menu, target) {
      if(menu.layout == 'mobile' || !dropMenuVisible(menu)) return;
      if(menu.element.contains(target) || menu.trigger.contains(target)) return;
      menu.trigger.click();
    };
  
    function initFocusOut(menu) {
      menu.element.addEventListener('keydown', function(event){
        if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
          getFocusableElements(menu);
          if( (menu.focusableElements[0] == document.activeElement && event.shiftKey) || (menu.focusableElements[menu.focusableElements.length - 1] == document.activeElement && !event.shiftKey)) {
            menu.trigger.click();
          }
        } else if(event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' && dropMenuVisible(menu)) {
          menu.trigger.click();
  			}
      });
    };
  
    // init DropMenu objects
    var dropMenus = document.getElementsByClassName('js-drop-menu');
    var focusableElString = '[href], input:not([disabled]), select:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable], summary';
    if( dropMenus.length > 0 ) {
      var dropMenusArray = [];
      for( var i = 0; i < dropMenus.length; i++) {(function(i){
        dropMenusArray.push(new DropMenu(dropMenus[i]));
      })(i);}
  
      // on resize -> close all drop menu elements
  		window.addEventListener('resize', function(event){
  			dropMenusArray.forEach(function(element){
  				closeOnResize(element);
  			});
      });
      
      // close drop menu when clicking outside it
  		window.addEventListener('click', function(event){
        dropMenusArray.forEach(function(element){
  				closeOnClick(element, event.target);
  			});
  		});
    }
  }());
  // File#: _3_expandable-img-gallery
  // Usage: codyhouse.co/license
  
  (function() {
    var ExpGallery = function(element) {
      this.element = element;
      this.slideshow = this.element.getElementsByClassName('js-exp-lightbox__body')[0];
      this.slideshowList = this.element.getElementsByClassName('js-exp-lightbox__slideshow')[0];
      this.slideshowId = this.element.getAttribute('id')
      this.gallery = document.querySelector('[data-controls="'+this.slideshowId+'"]');
      this.galleryItems = this.gallery.getElementsByClassName('js-exp-gallery__item');
      this.lazyload = this.gallery.getAttribute('data-placeholder');
      this.animationRunning = false;
      // menu bar
      this.menuBar = this.element.getElementsByClassName('js-menu-bar');
      initNewContent(this);
      initLightboxMarkup(this);
      lazyLoadLightbox(this);
      initSlideshow(this);
      initModal(this);
      initModalEvents(this);
    };
  
    function initNewContent(gallery) {
      // if the gallery uses the infinite load - make sure to update the modal gallery when new content is loaded
      gallery.infiniteScrollParent = gallery.gallery.closest('[data-container]');
      
      if(!gallery.infiniteScrollParent && Util.hasClass(gallery.gallery, 'js-infinite-scroll')) {
        gallery.infiniteScrollParent = gallery.gallery;
      }
      
      if(gallery.infiniteScrollParent) {
        gallery.infiniteScrollParent.addEventListener('content-loaded', function(event){
          initLightboxMarkup(gallery);
          initSlideshow(gallery);
        });
      }
    };
  
    function initLightboxMarkup(gallery) {
      // create items inside lightbox - modal slideshow
      var slideshowContent = '';
      for(var i = 0; i < gallery.galleryItems.length; i++) {
        var caption = gallery.galleryItems[i].getElementsByClassName('js-exp-gallery__caption'),
          image = gallery.galleryItems[i].getElementsByTagName('img')[0],
          caption = gallery.galleryItems[i].getElementsByClassName('js-exp-gallery__caption');
        // details
        var src = image.getAttribute('data-modal-src');
        if(!src) src = image.getAttribute('data-src');
        if(!src) src = image.getAttribute('src');
        var altAttr = image.getAttribute('alt')
        altAttr = altAttr ? 'alt="'+altAttr+'"' : '';
        var draggable = gallery.slideshow.getAttribute('data-swipe') == 'on' ? 'draggable="false" ondragstart="return false;"' : '';
        var imgBlock = gallery.lazyload 
          ? '<img data-src="'+src+'" data-loading="lazy" src="'+gallery.lazyload+'" '+altAttr+' '+draggable+' class=" pointer-events-auto">'
          : '<img src="'+src+'" data-loading="lazy" '+draggable+' class=" pointer-events-auto">';
  
        var captionBlock = caption.length > 0
          ? '<figcaption class="exp-lightbox__caption pointer-events-auto">'+caption[0].textContent+'</figcaption>'
          : '';
  
        slideshowContent = slideshowContent + '<li class="slideshow__item js-slideshow__item"><figure class="exp-lightbox__media"><div class="exp-lightbox__media-outer"><div class="exp-lightbox__media-inner">'+imgBlock+'</div></div>'+captionBlock+'</li>';
      }
      gallery.slideshowList.innerHTML = slideshowContent;
      gallery.slides = gallery.slideshowList.getElementsByClassName('js-slideshow__item');
  
      // append the morphing image - we will animate it from the selected slide to the final position (and viceversa)
      var imgMorph = document.createElement("div");
      Util.setAttributes(imgMorph, {'aria-hidden': 'true', 'class': 'exp-lightbox__clone-img-wrapper js-exp-lightbox__clone-img-wrapper', 'data-exp-morph': gallery.slideshowId});
      imgMorph.innerHTML = '<svg><defs><clipPath id="'+gallery.slideshowId+'-clip"><rect/></clipPath></defs><image height="100%" width="100%" clip-path="url(#'+gallery.slideshowId+'-clip)"></image></svg>';
      document.body.appendChild(imgMorph);
      gallery.imgMorph = document.querySelector('.js-exp-lightbox__clone-img-wrapper[data-exp-morph="'+gallery.slideshowId+'"]');
      gallery.imgMorphSVG = gallery.imgMorph.getElementsByTagName('svg')[0];
      gallery.imgMorphRect = gallery.imgMorph.getElementsByTagName('rect')[0];
      gallery.imgMorphImg = gallery.imgMorph.getElementsByTagName('image')[0];
      
      // append image for zoom in effect
      if(gallery.slideshow.getAttribute('data-zoom') == 'on') {
        var zoomImg = document.createElement("div");
        Util.setAttributes(zoomImg, {'aria-hidden': 'true', 'class': 'exp-lightbox__zoom exp-lightbox__zoom--no-transition js-exp-lightbox__zoom'});
        zoomImg.innerHTML = '<img>';
        gallery.element.appendChild(zoomImg);
        gallery.zoomImg = gallery.element.getElementsByClassName('js-exp-lightbox__zoom')[0];
      }
    };
  
    function lazyLoadLightbox(gallery) {
      // lazyload media of selected slide/prev slide/next slide
      gallery.slideshow.addEventListener('newItemSelected', function(event){
        // 'newItemSelected' is emitted by the Slideshow object when a new slide is selected
        gallery.selectedSlide = event.detail;
        lazyLoadSlide(gallery);
        // menu element - trigger new slide event
        triggerMenuEvent(gallery);
      });
    };
  
    function lazyLoadSlide(gallery) {
      setSlideMedia(gallery, gallery.selectedSlide);
      setSlideMedia(gallery, gallery.selectedSlide + 1);
      setSlideMedia(gallery, gallery.selectedSlide - 1);
    };
  
    function setSlideMedia(gallery, index) {
      if(index < 0) index = gallery.slides.length - 1;
      if(index > gallery.slides.length - 1) index = 0;
      var imgs = gallery.slides[index].querySelectorAll('img[data-src]');
      for(var i = 0; i < imgs.length; i++) {
        imgs[i].src = imgs[i].getAttribute('data-src');
      }
    };
  
    function initSlideshow(gallery) { 
      // reset slideshow navigation
      resetSlideshowControls(gallery);
      gallery.slideshowNav = gallery.element.getElementsByClassName('js-slideshow__control');
  
      if(gallery.slides.length <= 1) {
        toggleSlideshowElements(gallery, true);
        return;
      } 
      var swipe = (gallery.slideshow.getAttribute('data-swipe') && gallery.slideshow.getAttribute('data-swipe') == 'on') ? true : false;
      gallery.slideshowObj = new Slideshow({element: gallery.slideshow, navigation: false, autoplay : false, swipe : swipe});
    };
  
    function resetSlideshowControls(gallery) {
      var arrowControl = gallery.element.getElementsByClassName('js-slideshow__control');
      if(arrowControl.length == 0) return;
      var controlsWrapper = arrowControl[0].parentElement;
      if(!controlsWrapper) return;
      controlsWrapper.innerHTML = controlsWrapper.innerHTML;
    };
  
    function toggleSlideshowElements(gallery, bool) { // hide slideshow controls if gallery is composed by one item only
      if(gallery.slideshowNav.length > 0) {
        for(var i = 0; i < gallery.slideshowNav.length; i++) {
          bool ? Util.addClass(gallery.slideshowNav[i], 'is-hidden') : Util.removeClass(gallery.slideshowNav[i], 'is-hidden');
        }
      }
    };
  
    function initModal(gallery) {
      Util.addClass(gallery.element, 'exp-lightbox--no-transition'); // add no-transition class to lightbox - used to select the first visible slide
      gallery.element.addEventListener('modalIsClose', function(event){ // add no-transition class
        Util.addClass(gallery.element, 'exp-lightbox--no-transition');
        gallery.imgMorph.style = '';
      });
      // trigger modal lightbox
      gallery.gallery.addEventListener('click', function(event){
        openModalLightbox(gallery, event);
      });
    };
  
    function initModalEvents(gallery) {
     if(gallery.zoomImg) { // image zoom
        gallery.slideshow.addEventListener('click', function(event){
          if(event.target.tagName.toLowerCase() == 'img' && event.target.closest('.js-slideshow__item') && !gallery.modalSwiping) modalZoomImg(gallery, event.target);
        });
  
        gallery.zoomImg.addEventListener('click', function(event){
          modalZoomImg(gallery, false);
        });
  
        gallery.element.addEventListener('modalIsClose', function(event){
          modalZoomImg(gallery, false); // close zoom-in image if open
          closeModalAnimation(gallery);
        });
      }
  
      if(!gallery.slideshowObj) return;
  
      if(gallery.slideshowObj.options.swipe) { // close gallery when you swipeUp/SwipeDown
        gallery.slideshowObj.element.addEventListener('swipeUp', function(event){
          closeModal(gallery);
        });
        gallery.slideshowObj.element.addEventListener('swipeDown', function(event){
          closeModal(gallery);
        });
      }
      
      if(gallery.zoomImg && gallery.slideshowObj.options.swipe) {
        gallery.slideshowObj.element.addEventListener('swipeLeft', function(event){
          gallery.modalSwiping = true;
        });
        gallery.slideshowObj.element.addEventListener('swipeRight', function(event){
          gallery.modalSwiping = true;
        });
        gallery.slideshowObj.element.addEventListener('newItemVisible', function(event){
          gallery.modalSwiping = false;
        });
      }
    };
  
    function openModalLightbox(gallery, event) {
      var item = event.target.closest('.js-exp-gallery__item');
      if(!item) return;
      // reset slideshow items visibility
      resetSlideshowItemsVisibility(gallery);
      gallery.selectedSlide = Util.getIndexInArray(gallery.galleryItems, item);
      setSelectedItem(gallery);
      lazyLoadSlide(gallery);
      if(animationSupported) { // start expanding animation
        window.requestAnimationFrame(function(){
          animateSelectedImage(gallery);
          openModal(gallery, item);
        });
      } else { // no expanding animation -> show modal
        openModal(gallery, item);
        Util.removeClass(gallery.element, 'exp-lightbox--no-transition');
      }
      // menu element - trigger new slide event
      triggerMenuEvent(gallery);
    };
  
    function resetSlideshowItemsVisibility(gallery) {
      var index = 0;
      for(var i = 0; i < gallery.galleryItems.length; i++) {
        var itemVisible = isVisible(gallery.galleryItems[i]);
        if(itemVisible) {
          index = index + 1;
          Util.removeClass(gallery.slides[i], 'is-hidden');
        } else {
          Util.addClass(gallery.slides[i], 'is-hidden');
        }
      }
      toggleSlideshowElements(gallery, index < 2);
    };
  
    function setSelectedItem(gallery) {
      // if a specific slide was selected -> make sure to show that item first
      var lastSelected = gallery.slideshow.getElementsByClassName('slideshow__item--selected');
      if(lastSelected.length > 0 ) Util.removeClass(lastSelected[0], 'slideshow__item--selected');
      Util.addClass(gallery.slides[gallery.selectedSlide], 'slideshow__item--selected');
      if(gallery.slideshowObj) gallery.slideshowObj.selectedSlide = gallery.selectedSlide;
    };
  
    function openModal(gallery, item) {
      gallery.element.dispatchEvent(new CustomEvent('openModal', {detail: item}));
      gallery.modalSwiping = false;
    };
  
    function closeModal(gallery) {
      gallery.modalSwiping = true;
      modalZoomImg(gallery, false);
      gallery.element.dispatchEvent(new CustomEvent('closeModal'));
    };
  
    function closeModalAnimation(gallery) { // modal is already closing -> start image closing animation
      gallery.selectedSlide = gallery.slideshowObj ? gallery.slideshowObj.selectedSlide : 0;
      // on close - make sure last selected image (of the gallery) is in the viewport
      var boundingRect = gallery.galleryItems[gallery.selectedSlide].getBoundingClientRect();
  		if(boundingRect.top < 0 || boundingRect.top > window.innerHeight) {
  			var windowScrollTop = window.scrollY || document.documentElement.scrollTop;
  			window.scrollTo(0, boundingRect.top + windowScrollTop);
  		}
      // animate on close
      animateSelectedImage(gallery, true);
    };
  
    function modalZoomImg(gallery, img) { // toggle zoom-in image
      if(!gallery.zoomImg) return;
      var bool = false;
      if(img) { // open zoom-in image
        gallery.originImg = img;
        gallery.zoomImg.children[0].setAttribute('src', img.getAttribute('src'));
        bool = true;
      }
      (animationSupported) 
        ? requestAnimationFrame(function(){animateZoomImg(gallery, bool)})
        : Util.toggleClass(gallery.zoomImg, 'exp-lightbox__zoom--is-visible', bool);
    };
  
    function animateZoomImg(gallery, bool) {
      if(!gallery.originImg) return;
      
      var originImgPosition = gallery.originImg.getBoundingClientRect(),
        originStyle = 'translateX('+originImgPosition.left+'px) translateY('+(originImgPosition.top + gallery.zoomImg.scrollTop)+'px) scale('+ originImgPosition.width/gallery.zoomImg.scrollWidth+')',
        finalStyle = 'scale(1)';
  
      if(bool) {
        gallery.zoomImg.children[0].style.transform = originStyle;
      } else {
        gallery.zoomImg.addEventListener('transitionend', function cb(){
          Util.addClass(gallery.zoomImg, 'exp-lightbox__zoom--no-transition');
          gallery.zoomImg.scrollTop = 0;
          gallery.zoomImg.removeEventListener('transitionend', cb);
        });
      }
      setTimeout(function(){
        Util.removeClass(gallery.zoomImg, 'exp-lightbox__zoom--no-transition');
        Util.toggleClass(gallery.zoomImg, 'exp-lightbox__zoom--is-visible', bool);
        gallery.zoomImg.children[0].style.transform = (bool) ? finalStyle : originStyle;
      }, 50);
    };
  
    function animateSelectedImage(gallery, bool) { // create morphing image effect
      var imgInit = gallery.galleryItems[gallery.selectedSlide].getElementsByTagName('img')[0],
        imgInitPosition = imgInit.getBoundingClientRect(),
        imgFinal = gallery.slides[gallery.selectedSlide].getElementsByTagName('img')[0],
        imgFinalPosition = imgFinal.getBoundingClientRect();
  
      if(bool) {
        runAnimation(gallery, imgInit, imgInitPosition, imgFinal, imgFinalPosition, bool);
      } else {
        imgFinal.style.visibility = 'hidden';
        gallery.animationRunning = false;
        var image = new Image();
        image.onload = function () {
          if(gallery.animationRunning) return;
          imgFinalPosition = imgFinal.getBoundingClientRect();
          runAnimation(gallery, imgInit, imgInitPosition, imgFinal, imgFinalPosition, bool);
        }
        image.src = imgFinal.getAttribute('data-src') ? imgFinal.getAttribute('data-src') : imgFinal.getAttribute('src');
        if(image.complete) {
          gallery.animationRunning = true;
          imgFinalPosition = imgFinal.getBoundingClientRect();
          runAnimation(gallery, imgInit, imgInitPosition, imgFinal, imgFinalPosition, bool);
        }
      }
    };
  
    function runAnimation(gallery, imgInit, imgInitPosition, imgFinal, imgFinalPosition, bool) {
      // retrieve all animation params
      var scale = imgFinalPosition.width > imgFinalPosition.height ? imgFinalPosition.height/imgInitPosition.height : imgFinalPosition.width/imgInitPosition.width;
      var initHeight = imgFinalPosition.width > imgFinalPosition.height ? imgInitPosition.height : imgFinalPosition.height/scale,
        initWidth = imgFinalPosition.width > imgFinalPosition.height ? imgFinalPosition.width/scale : imgInitPosition.width;
  
      var initTranslateY = (imgInitPosition.height - initHeight)/2,
        initTranslateX = (imgInitPosition.width - initWidth)/2,
        initTop = imgInitPosition.top + initTranslateY,
        initLeft = imgInitPosition.left + initTranslateX;
  
      // get final states
      var translateX = imgFinalPosition.left - imgInitPosition.left,
        translateY = imgFinalPosition.top - imgInitPosition.top;
  
      var finTranslateX = translateX - initTranslateX,
      finTranslateY = translateY - initTranslateY;
  
      var initScaleX = imgInitPosition.width/initWidth,
        initScaleY = imgInitPosition.height/initHeight,
        finScaleX = 1,
        finScaleY = 1;
  
      if(bool) { // update params if this is a closing animation
        scale = 1/scale;
        finScaleX = initScaleX;
        finScaleY = initScaleY;
        initScaleX = 1;
        initScaleY = 1;
        finTranslateX = -1*finTranslateX;
        finTranslateY = -1*finTranslateY;
        initTop = imgFinalPosition.top;
        initLeft = imgFinalPosition.left;
        initHeight = imgFinalPosition.height;
        initWidth = imgFinalPosition.width;
      }
      
      if(!bool) {
        imgFinal.style.visibility = ''; // reset visibility
      }
  
      // set initial status
      gallery.imgMorph.setAttribute('style', 'height: '+initHeight+'px; width: '+initWidth+'px; top: '+initTop+'px; left: '+initLeft+'px;');
      gallery.imgMorphSVG.setAttribute('viewbox', '0 0 '+initWidth+' '+initHeight);
      Util.setAttributes(gallery.imgMorphImg, {'xlink:href': imgInit.getAttribute('src'), 'href': imgInit.getAttribute('src')});
      Util.setAttributes(gallery.imgMorphRect, {'style': 'height: '+initHeight+'px; width: '+initWidth+'px;', 'transform': 'translate('+(initWidth/2)*(1 - initScaleX)+' '+(initHeight/2)*(1 - initScaleY)+') scale('+initScaleX+','+initScaleY+')'});
  
      // reveal image and start animation
      Util.addClass(gallery.imgMorph, 'exp-lightbox__clone-img-wrapper--is-visible');
      Util.addClass(gallery.slideshowList, 'slideshow__content--is-hidden');
      Util.addClass(gallery.galleryItems[gallery.selectedSlide], 'exp-gallery-item-hidden');
  
      gallery.imgMorph.addEventListener('transitionend', function cb(event){ // reset elements once animation is over
        if(event.propertyName.indexOf('transform') < 0) return;
  			Util.removeClass(gallery.element, 'exp-lightbox--no-transition');
        Util.removeClass(gallery.imgMorph, 'exp-lightbox__clone-img-wrapper--is-visible');
        Util.removeClass(gallery.slideshowList, 'slideshow__content--is-hidden');
        gallery.imgMorph.removeAttribute('style');
        gallery.imgMorphRect.removeAttribute('style');
        gallery.imgMorphRect.removeAttribute('transform');
        gallery.imgMorphImg.removeAttribute('href');
        gallery.imgMorphImg.removeAttribute('xlink:href');
        Util.removeClass(gallery.galleryItems[gallery.selectedSlide], 'exp-gallery-item-hidden');
  			gallery.imgMorph.removeEventListener('transitionend', cb);
      });
  
      // trigger expanding/closing animation
      gallery.imgMorph.style.transform = 'translateX('+finTranslateX+'px) translateY('+finTranslateY+'px) scale('+scale+')';
      animateRectScale(gallery.imgMorphRect, initScaleX, initScaleY, finScaleX, finScaleY, initWidth, initHeight);
    };
  
    function animateRectScale(rect, scaleX, scaleY, finScaleX, finScaleY, width, height) {
      var currentTime = null,
        duration =  parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--exp-gallery-animation-duration'))*1000 || 300;
  
      var animateScale = function(timestamp){  
        if (!currentTime) currentTime = timestamp;         
        var progress = timestamp - currentTime;
        if(progress > duration) progress = duration;
  
        var valX = easeOutQuad(progress, scaleX, finScaleX-scaleX, duration),
          valY = easeOutQuad(progress, scaleY, finScaleY-scaleY, duration);
  
        rect.setAttribute('transform', 'translate('+(width/2)*(1 - valX)+' '+(height/2)*(1 - valY)+') scale('+valX+','+valY+')');
        if(progress < duration) {
          window.requestAnimationFrame(animateScale);
        }
      };
  
      function easeOutQuad(t, b, c, d) {
        t /= d;
        return -c * t*(t-2) + b;
      };
      
      window.requestAnimationFrame(animateScale);
    };
  
    function keyboardNavigateLightbox(gallery, direction) {
      if(!Util.hasClass(gallery.element, 'modal--is-visible')) return;
      if(!document.activeElement.closest('.js-exp-lightbox__body') && document.activeElement.closest('.js-modal')) return;
      if(!gallery.slideshowObj) return;
      (direction == 'next') ? gallery.slideshowObj.showNext() : gallery.slideshowObj.showPrev();
    };
  
    function triggerMenuEvent(gallery) {
      if(gallery.menuBar.length < 1) return;
      var event = new CustomEvent('update-menu', 
        {detail: {
          index: gallery.selectedSlide,
          item: gallery.slides[gallery.selectedSlide]
        }});
      gallery.menuBar[0].dispatchEvent(event);
    };
  
    function isVisible(element) {
      return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
    };
  
    window.ExpGallery = ExpGallery;
  
    // init ExpGallery objects
    var expGalleries = document.getElementsByClassName('js-exp-lightbox'),
      animationSupported = window.requestAnimationFrame && !Util.osHasReducedMotion();
    if( expGalleries.length > 0 ) {
      var expGalleriesArray = [];
      for( var i = 0; i < expGalleries.length; i++) {
        (function(i){ expGalleriesArray.push(new ExpGallery(expGalleries[i]));})(i);
  
        // Lightbox gallery navigation with keyboard
        window.addEventListener('keydown', function(event){
          if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
            updateLightbox('next');
          } else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
            updateLightbox('prev');
          }
        });
  
        function updateLightbox(direction) {
          for( var i = 0; i < expGalleriesArray.length; i++) {
            (function(i){keyboardNavigateLightbox(expGalleriesArray[i], direction);})(i);
          };
        };
      }
    }
  }());
  // File#: _3_explorer
  // Usage: codyhouse.co/license
  (function() {
    /// 👇you should remove this from your live code
  
    // demo only: array of static results -> replace with your real values
    var explorerQuickLinks = [
      { 
        label: 'New File', 
        class: 'js-explorer__command',
        icon: '<svg class="icon" viewBox="0 0 20 20"><g stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"><line x1="1" y1="19" x2="19" y2="19" /><polygon points="13 1 17 5 8 14 3 15 4 10 13 1" /></g></svg>',
        shortcut: '<i class="explorer__shortcut">N</i>',
        template: 'button'
      },
      { 
        label: 'New Project', 
        class: 'js-explorer__command',
        icon: '<svg class="icon" viewBox="0 0 20 20"><g stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"><path d="M10,19H4a3,3,0,0,1-3-3V1H8l2,4h9v5" /><line x1="15" y1="11" x2="15" y2="19" /><line x1="11" y1="15" x2="19" y2="15" /></g></svg>',
        shortcut: '<i class="explorer__shortcut">P</i>',
        template: 'button'
      },
      { 
        label: 'Move to Project', 
        class: 'js-explorer__command',
        icon: '<svg class="icon" viewBox="0 0 20 20"><g stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"><path d="M11,19H4a3,3,0,0,1-3-3V1H8l2,4h9V9" /><line x1="9" y1="14" x2="19" y2="14" /><polyline points="15 10 19 14 15 18" /></g></svg>',
        shortcut: '<i class="explorer__shortcut">M</i>',
        template: 'button'
      },
      { 
        label: 'Delete File', 
        class: 'js-explorer__command',
        icon: '<svg class="icon" viewBox="0 0 20 20"><g stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"><circle cx="10" cy="10" r="9" /><line x1="6" y1="6" x2="14" y2="14" /><line x1="14" y1="6" x2="6" y2="14" /></g></svg>',
        shortcut: '<i class="explorer__shortcut">⌘</i> <i class="explorer__shortcut">D</i>',
        template: 'button'
      }
    ];
  
    var explorerAdditionalLinks = [
      { 
        label: 'Remove from Project', 
        class: 'js-explorer__command',
        icon: '<svg class="icon" viewBox="0 0 20 20"><g stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"><path d="M10,19H4a3,3,0,0,1-3-3V1H8l2,4h9v5" /><line x1="11" y1="15" x2="19" y2="15" /></g></svg>',
        shortcut: '<i class="explorer__shortcut">R</i>',
        template: 'button'
      }
    ];
  
    if(document.getElementById('explorer-link-variation')) { // --link variation
      // use different results for the --link variation 
      explorerQuickLinks = [
        { 
          label: 'Link 1', 
          class: 'js-explorer__link',
          url: '#0',
          category: 'Category',
          template: 'link'
        },
        { 
          label: 'Project 1', 
          class: 'js-explorer__link',
          url: '#0',
          category: 'Category',
          template: 'link'
        },
        { 
          label: 'Link 2', 
          class: 'js-explorer__link',
          url: '#0',
          category: 'Category',
          template: 'link'
        }
      ];
    
      explorerAdditionalLinks = [
        { 
          label: 'Project 2', 
          class: 'js-explorer__link',
          url: '#0',
          category: 'Category',
          template: 'link'
        }
      ];
    }
  
    /// 👆end of demo code
  
    
    function explorerSearch(query, cb) { 
      // get search results
      // more info: https://codyhouse.co/ds/components/info/autocomplete#search-data
      
      // quick links - visible when the input is empty
      if(query == '') {
        cb(explorerQuickLinks); // pass your real list of quick links
        return;
      } 
  
      // 👇 get results - you should modify this with your real data
      var quickLinks = explorerQuickLinks.filter(function(item){
        // return item if item['label'] contains 'query'
        return item['label'].toLowerCase().indexOf(query.toLowerCase()) > -1;
      });
      var data = explorerAdditionalLinks.filter(function(item){
        // return item if item['label'] contains 'query'
        return item['label'].toLowerCase().indexOf(query.toLowerCase()) > -1;
      });
      data = quickLinks.concat(data);
      // 👆 get results - you should modify this with your real data
  
      if(data.length == 0) { // fallback for no results found
        // no results found
        data = [{
          label: 'No results',
          template: 'no-results'
        }];
      }
  
      // make sure to call the callback function and pass the data array as its argument
      cb(data);
    };
  
    function explorerClick(option, obj, event) { 
      // custom function to be execute when user selects an option
      // more info: https://codyhouse.co/ds/components/info/autocomplete#on-click
      event.preventDefault();
    };
  
    var explorer = document.getElementsByClassName('js-explorer');
    if(explorer.length > 0) {
      var modalExplorer = explorer[0].closest('.js-modal');
      var explorerInput =  explorer[0].getElementsByClassName('js-autocomplete__input');
      new Autocomplete({
        element: explorer[0],
        characters: 0,
        searchData: function(value, cb) { // function that gets result data
          explorerSearch(value, cb);
        },
        onClick: function(option, obj, event) { // function to be executed on click
          explorerClick(option, obj, event);
        }
      });
  
      if(modalExplorer) {
        modalExplorer.addEventListener('modalIsClose', function(event){
          // reset search input when closing the modal window
          if(explorerInput.length > 0) {
            explorerInput[0].value = '';
          }
        });
      } 
    }
  }());
  // File#: _3_interactive-table
  // Usage: codyhouse.co/license
  (function() {
    var IntTable = function(element) {
      this.element = element;
      this.header = this.element.getElementsByClassName('js-int-table__header')[0];
      this.headerCols = this.header.getElementsByTagName('tr')[0].children;
      this.body = this.element.getElementsByClassName('js-int-table__body')[0];
      this.sortingRows = this.element.getElementsByClassName('js-int-table__sort-row');
      initIntTable(this);
    };
  
    function initIntTable(table) {
      // check if table has actions
      initIntTableActions(table);
      // check if there are checkboxes to select/deselect a row/all rows
      var selectAll = table.element.getElementsByClassName('js-int-table__select-all');
      if(selectAll.length > 0) initIntTableSelection(table, selectAll);
      // check if there are sortable columns
      table.sortableCols = table.element.getElementsByClassName('js-int-table__cell--sort');
      if(table.sortableCols.length > 0) {
        // add a data-order attribute to all rows so that we can reset the order
        setDataRowOrder(table);
        // listen to the click event on a sortable column
        table.header.addEventListener('click', function(event){
          var selectedCol = event.target.closest('.js-int-table__cell--sort');
          if(!selectedCol || event.target.tagName.toLowerCase() == 'input') return;
          sortColumns(table, selectedCol);
        });
        table.header.addEventListener('change', function(event){ // detect change in selected checkbox (SR only)
          var selectedCol = event.target.closest('.js-int-table__cell--sort');
          if(!selectedCol) return;
          sortColumns(table, selectedCol, event.target.value);
        });
        table.header.addEventListener('keydown', function(event){ // keyboard navigation - change sorting on enter
          if( event.keyCode && event.keyCode == 13 || event.key && event.key.toLowerCase() == 'enter') {
            var selectedCol = event.target.closest('.js-int-table__cell--sort');
            if(!selectedCol) return;
            sortColumns(table, selectedCol);
          }
        });
  
        // change cell style when in focus
        table.header.addEventListener('focusin', function(event){
          var closestCell = document.activeElement.closest('.js-int-table__cell--sort');
          if(closestCell) Util.addClass(closestCell, 'int-table__cell--focus');
        });
        table.header.addEventListener('focusout', function(event){
          for(var i = 0; i < table.sortableCols.length; i++) {
            Util.removeClass(table.sortableCols[i], 'int-table__cell--focus');
          }
        });
      }
    };
  
    function initIntTableActions(table) {
      // check if table has actions and store them
      var tableId = table.element.getAttribute('id');
      if(!tableId) return;
      var tableActions = document.querySelector('[data-table-controls="'+tableId+'"]');
      if(!tableActions) return;
      table.actionsSelection = tableActions.getElementsByClassName('js-int-table-actions__items-selected');
      table.actionsNoSelection = tableActions.getElementsByClassName('js-int-table-actions__no-items-selected');
    };
  
    function initIntTableSelection(table, select) { // checkboxes for rows selection
      table.selectAll = select[0];
      table.selectRow = table.element.getElementsByClassName('js-int-table__select-row');
      // select/deselect all rows
      table.selectAll.addEventListener('click', function(event){ // we cannot use the 'change' event as on IE/Edge the change from "indeterminate" to either "checked" or "unchecked"  does not trigger that event
        toggleRowSelection(table);
      });
      // select/deselect single row - reset all row selector 
      table.body.addEventListener('change', function(event){
        if(!event.target.closest('.js-int-table__select-row')) return;
        toggleAllSelection(table);
      });
      // toggle actions
      toggleActions(table, table.element.getElementsByClassName('int-table__row--checked').length > 0);
    };
  
    function toggleRowSelection(table) { // 'Select All Rows' checkbox has been selected/deselected
      var status = table.selectAll.checked;
      for(var i = 0; i < table.selectRow.length; i++) {
        table.selectRow[i].checked = status;
        Util.toggleClass(table.selectRow[i].closest('.int-table__row'), 'int-table__row--checked', status);
      }
      toggleActions(table, status);
    };
  
    function toggleAllSelection(table) { // Single row has been selected/deselected
      var allChecked = true,
        oneChecked = false;
      for(var i = 0; i < table.selectRow.length; i++) {
        if(!table.selectRow[i].checked) {allChecked = false;}
        else {oneChecked = true;}
        Util.toggleClass(table.selectRow[i].closest('.int-table__row'), 'int-table__row--checked', table.selectRow[i].checked);
      }
      table.selectAll.checked = oneChecked;
      // if status if false but one input is checked -> set an indeterminate state for the 'Select All' checkbox
      if(!allChecked) {
        table.selectAll.indeterminate = oneChecked;
      } else if(allChecked && oneChecked) {
        table.selectAll.indeterminate = false;
      }
      toggleActions(table, oneChecked);
    };
  
    function setDataRowOrder(table) { // add a data-order to rows element - will be used when resetting the sorting 
      var rowsArray = table.body.getElementsByTagName('tr');
      for(var i = 0; i < rowsArray.length; i++) {
        rowsArray[i].setAttribute('data-order', i);
      }
    };
  
    function sortColumns(table, selectedCol, customOrder) {
      // determine sorting order (asc/desc/reset)
      var order = customOrder || getSortingOrder(selectedCol),
        colIndex = Util.getIndexInArray(table.headerCols, selectedCol);
      // sort table
      sortTableContent(table, order, colIndex, selectedCol);
      
      // reset appearance of the th column that was previously sorted (if any) 
      for(var i = 0; i < table.headerCols.length; i++) {
        Util.removeClass(table.headerCols[i], 'int-table__cell--asc int-table__cell--desc');
      }
      // reset appearance for the selected th column
      if(order == 'asc') Util.addClass(selectedCol, 'int-table__cell--asc');
      if(order == 'desc') Util.addClass(selectedCol, 'int-table__cell--desc');
      // reset checkbox selection
      if(!customOrder) selectedCol.querySelector('input[value="'+order+'"]').checked = true;
    };
  
    function getSortingOrder(selectedCol) { // determine sorting order
      if( Util.hasClass(selectedCol, 'int-table__cell--asc') ) return 'desc';
      if( Util.hasClass(selectedCol, 'int-table__cell--desc') ) return 'none';
      return 'asc';
    };
  
    function sortTableContent(table, order, index, selctedCol) { // determine the new order of the rows
      var rowsArray = table.body.getElementsByTagName('tr'),
        switching = true,
        i = 0,
        shouldSwitch;
      while (switching) {
        switching = false;
        for (i = 0; i < rowsArray.length - 1; i++) {
          var contentOne = (order == 'none') ? rowsArray[i].getAttribute('data-order') : rowsArray[i].children[index].textContent.trim(),
            contentTwo = (order == 'none') ? rowsArray[i+1].getAttribute('data-order') : rowsArray[i+1].children[index].textContent.trim();
  
          shouldSwitch = compareValues(contentOne, contentTwo, order, selctedCol);
          if(shouldSwitch) {
            table.body.insertBefore(rowsArray[i+1], rowsArray[i]);
            switching = true;
            break;
          }
        }
      }
    };
  
    function compareValues(val1, val2, order, selctedCol) {
      var compare,
        dateComparison = selctedCol.getAttribute('data-date-format');
      if( dateComparison && order != 'none') { // comparing dates
        compare =  (order == 'asc' || order == 'none') ? parseCustomDate(val1, dateComparison) > parseCustomDate(val2, dateComparison) : parseCustomDate(val2, dateComparison) > parseCustomDate(val1, dateComparison);
      } else if( !isNaN(val1) && !isNaN(val2) ) { // comparing numbers
        compare =  (order == 'asc' || order == 'none') ? Number(val1) > Number(val2) : Number(val2) > Number(val1);
      } else { // comparing strings
        compare =  (order == 'asc' || order == 'none') 
          ? val2.toString().localeCompare(val1) < 0
          : val1.toString().localeCompare(val2) < 0;
      }
      return compare;
    };
  
    function parseCustomDate(date, format) {
      var parts = date.match(/(\d+)/g), 
        i = 0, fmt = {};
      // extract date-part indexes from the format
      format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; });
  
      return new Date(parts[fmt['yyyy']], parts[fmt['mm']]-1, parts[fmt['dd']]);
    };
  
    function toggleActions(table, selection) {
      if(table.actionsSelection && table.actionsSelection.length > 0) {
        Util.toggleClass(table.actionsSelection[0], 'is-hidden', !selection);
      }
      if(table.actionsNoSelection && table.actionsNoSelection.length > 0) {
        Util.toggleClass(table.actionsNoSelection[0], 'is-hidden', selection);
      }
    };
  
    //initialize the IntTable objects
  	var intTable = document.getElementsByClassName('js-int-table');
  	if( intTable.length > 0 ) {
  		for( var i = 0; i < intTable.length; i++) {
  			(function(i){new IntTable(intTable[i]);})(i);
      }
    }
  }());
  // File#: _3_lightbox
  // Usage: codyhouse.co/license
  
  (function() {
    var Lightbox = function(element) {
      this.element = element;
      this.id = this.element.getAttribute('id');
      this.slideshow = this.element.getElementsByClassName('js-lightbox__body')[0];
      this.slides = this.slideshow.getElementsByClassName('js-slideshow__item');
      this.thumbWrapper = this.element.getElementsByClassName('js-lightbox_thumb-list');
      lazyLoadLightbox(this);
      initSlideshow(this);
      initThumbPreview(this);
      initThumbEvents(this);
    }
  
    function lazyLoadLightbox(modal) {
      // add no-transition class to lightbox - used to select the first visible slide
      Util.addClass(modal.element, 'lightbox--no-transition');
      //load first slide media when modal is open
      modal.element.addEventListener('modalIsOpen', function(event){
        setSelectedItem(modal, event);
        var selectedSlide = modal.slideshow.getElementsByClassName('slideshow__item--selected');
        modal.selectedSlide = Util.getIndexInArray(modal.slides, selectedSlide[0]);
        if(selectedSlide.length > 0) {
          if(modal.slideshowObj) modal.slideshowObj.selectedSlide = modal.selectedSlide;
          lazyLoadSlide(modal);
          resetVideos(modal, false);
          resetIframes(modal, false);
          updateThumb(modal);
        }
        Util.removeClass(modal.element, 'lightbox--no-transition');
      });
      modal.element.addEventListener('modalIsClose', function(event){ // add no-transition class
        Util.addClass(modal.element, 'lightbox--no-transition');
      });
      // lazyload media of selected slide/prev slide/next slide
      modal.slideshow.addEventListener('newItemSelected', function(event){
        // 'newItemSelected' is emitted by the Slideshow object when a new slide is selected
        var prevSelected = modal.selectedSlide;
        modal.selectedSlide = event.detail;
        lazyLoadSlide(modal);
        resetVideos(modal, prevSelected); // pause video of previous visible slide and start new video (if present)
        resetIframes(modal, prevSelected);
        updateThumb(modal);
      });
    };
  
    function lazyLoadSlide(modal) {
      setSlideMedia(modal, modal.selectedSlide);
      setSlideMedia(modal, modal.selectedSlide + 1);
      setSlideMedia(modal, modal.selectedSlide - 1);
    };
  
    function setSlideMedia(modal, index) {
      if(index < 0) index = modal.slides.length - 1;
      if(index > modal.slides.length - 1) index = 0;
      setSlideImgs(modal, index);
      setSlidesVideos(modal, index, 'video');
      setSlidesVideos(modal, index, 'iframe');
    };
  
    function setSlideImgs(modal, index) {
      var imgs = modal.slides[index].querySelectorAll('img[data-src]');
      for(var i = 0; i < imgs.length; i++) {
        imgs[i].src = imgs[i].getAttribute('data-src');
      }
    };
  
    function setSlidesVideos(modal, index, type) {
      var videos = modal.slides[index].querySelectorAll(type+'[data-src]');
      for(var i = 0; i < videos.length; i++) {
        videos[0].src = videos[0].getAttribute('data-src');
        videos[0].removeAttribute('data-src');
      }
    };
  
    function initSlideshow(modal) { 
      if(modal.slides.length <= 1) {
        hideSlideshowElements(modal);
        return;
      } 
      var swipe = (modal.slideshow.getAttribute('data-swipe') && modal.slideshow.getAttribute('data-swipe') == 'on') ? true : false;
      modal.slideshowObj = new Slideshow({element: modal.slideshow, navigation: false, autoplay : false, swipe : swipe});
    };
  
    function hideSlideshowElements(modal) { // hide slideshow controls if gallery is composed by one item only
      var slideshowNav = modal.element.getElementsByClassName('js-slideshow__control');
      if(slideshowNav.length > 0) {
        for(var i = 0; i < slideshowNav.length; i++) Util.addClass(slideshowNav[i], 'is-hidden');
      }
      var slideshowThumbs = modal.element.getElementsByClassName('js-lightbox_footer');
      if(slideshowThumbs.length > 0) Util.addClass(slideshowThumbs[0], 'is-hidden');
    };
  
    function resetVideos(modal, index) {
      if(index) {
        var actualVideo = modal.slides[index].getElementsByTagName('video');
        if(actualVideo.length > 0 ) actualVideo[0].pause();
      }
      var newVideo = modal.slides[modal.selectedSlide].getElementsByTagName('video');
      if(newVideo.length > 0 ) {
        setVideoWidth(modal, modal.selectedSlide, newVideo[0]);
        newVideo[0].play();
      }
    };
  
    function resetIframes(modal, index) {
      if(index) {
        var actualIframe = modal.slides[index].getElementsByTagName('iframe');
        if(actualIframe.length > 0 ) {
          actualIframe[0].setAttribute('data-src', actualIframe[0].src);
          actualIframe[0].removeAttribute('src');
        }
      }
      var newIframe = modal.slides[modal.selectedSlide].getElementsByTagName('iframe');
      if(newIframe.length > 0 ) {
        setVideoWidth(modal, modal.selectedSlide, newIframe[0]);
      }
    };
  
    function resizeLightbox(modal) { // executed when window has been resized
      if(!modal.selectedSlide) return; // modal not active
      var video = modal.slides[modal.selectedSlide].getElementsByTagName('video');
      if(video.length > 0 ) setVideoWidth(modal, modal.selectedSlide, video[0]);
      var iframe = modal.slides[modal.selectedSlide].getElementsByTagName('iframe');
      if(iframe.length > 0 ) setVideoWidth(modal, modal.selectedSlide, iframe[0]);
    };
  
    function setVideoWidth(modal, index, video) {
      var videoContainer = modal.slides[index].getElementsByClassName('js-lightbox__media-outer');
      if(videoContainer.length == 0 ) return;
      var videoWrapper = videoContainer[0].getElementsByClassName('js-lightbox__media-inner');
      var maxWidth = (video.offsetWidth/video.offsetHeight)*videoContainer[0].offsetHeight;
      if(maxWidth < modal.slides[index].offsetWidth) {
        videoWrapper[0].style.width = maxWidth+'px';
        videoWrapper[0].style.paddingBottom = videoContainer[0].offsetHeight+'px';
      } else {
        videoWrapper[0].removeAttribute('style')
      }
    };
  
    function initThumbPreview(modal) {
      if(modal.thumbWrapper.length < 1) return;
      var content = '';
      for(var i = 0; i < modal.slides.length; i++) {
        var activeClass = Util.hasClass(modal.slides[i], 'slideshow__item--selected') ? ' lightbox__thumb--active': '';
        content = content + '<li class="lightbox__thumb js-lightbox__thumb'+activeClass+'"><img src="'+modal.slides[i].querySelector('[data-thumb]').getAttribute('data-thumb')+'">'+'</li>';
      }
      modal.thumbWrapper[0].innerHTML = content;
    };
  
    function initThumbEvents(modal) {
      if(modal.thumbWrapper.length < 1) return;
      modal.thumbSlides = modal.thumbWrapper[0].getElementsByClassName('js-lightbox__thumb');
      modal.thumbWrapper[0].addEventListener('click', function(event){
        var selectedThumb = event.target.closest('.js-lightbox__thumb');
        if(!selectedThumb || Util.hasClass(selectedThumb, 'lightbox__thumb--active')) return;
        modal.slideshowObj.showItem(Util.getIndexInArray(modal.thumbSlides, selectedThumb));
      });
    };
  
    function updateThumb(modal) {
      if(modal.thumbWrapper.length < 1) return;
      // update selected thumb classes
      var selectedThumb = modal.thumbWrapper[0].getElementsByClassName('lightbox__thumb--active');
      if(selectedThumb.length > 0) Util.removeClass(selectedThumb[0], 'lightbox__thumb--active');
      Util.addClass(modal.thumbSlides[modal.selectedSlide], 'lightbox__thumb--active');
      // update thumb list position (if selected thumb is outside viewport)
      var offsetThumb = modal.thumbSlides[modal.selectedSlide].getBoundingClientRect(),
        offsetThumbList = modal.thumbWrapper[0].getBoundingClientRect();
      if(offsetThumb.left < offsetThumbList.left) {
        modal.thumbWrapper[0].scrollTo(modal.thumbSlides[modal.selectedSlide].offsetLeft - offsetThumbList.left, 0);
      } else if(offsetThumb.right > offsetThumbList.right) {
        modal.thumbWrapper[0].scrollTo( (offsetThumb.right - offsetThumbList.right) + modal.thumbWrapper[0].scrollLeft, 0);
      }
    };
  
    function keyboardNavigateLightbox(modal, direction) {
      if(!Util.hasClass(modal.element, 'modal--is-visible')) return;
      if(!document.activeElement.closest('.js-lightbox__body') && document.activeElement.closest('.js-modal')) return
      (direction == 'next') ? modal.slideshowObj.showNext() : modal.slideshowObj.showPrev();
    };
  
    function setSelectedItem(modal, event) {
      // if a specific slide was selected -> make sure to show that item first
      var selectedItemId = false;
      if(event.detail) {
        var elTarget = event.detail.closest('[aria-controls="'+modal.id+'"]');
        if(elTarget) selectedItemId = elTarget.getAttribute('data-lightbox-item');
      } 
     
      if(!selectedItemId || !modal.slideshowObj) return;
      var selectedItem = document.getElementById(selectedItemId);
      if(!selectedItem) return;
      var lastSelected = modal.slideshow.getElementsByClassName('slideshow__item--selected');
      if(lastSelected.length > 0 ) Util.removeClass(lastSelected[0], 'slideshow__item--selected');
      Util.addClass(selectedItem, 'slideshow__item--selected');
    };
  
    window.Lightbox = Lightbox;
  
    // init Lightbox objects
    var lightBoxes = document.getElementsByClassName('js-lightbox');
    if( lightBoxes.length > 0 ) {
      var lightBoxArray = [];
      for( var i = 0; i < lightBoxes.length; i++) {
        (function(i){ lightBoxArray.push(new Lightbox(lightBoxes[i]));})(i);
        
        // resize video/iframe
        var resizingId = false;
        window.addEventListener('resize', function(event){
          clearTimeout(resizingId);
          resizingId = setTimeout(doneResizing, 300);
        });
  
        function doneResizing() {
          for( var i = 0; i < lightBoxArray.length; i++) {
            (function(i){resizeLightbox(lightBoxArray[i]);})(i);
          };
        };
  
        // Lightbox gallery navigation with keyboard
        window.addEventListener('keydown', function(event){
          if(event.keyCode && event.keyCode == 39 || event.key && event.key.toLowerCase() == 'arrowright') {
            updateLightbox('next');
          } else if(event.keyCode && event.keyCode == 37 || event.key && event.key.toLowerCase() == 'arrowleft') {
            updateLightbox('prev');
          }
        });
  
        function updateLightbox(direction) {
          for( var i = 0; i < lightBoxArray.length; i++) {
            (function(i){keyboardNavigateLightbox(lightBoxArray[i], direction);})(i);
          };
        };
      }
    }
  }());
  // File#: _3_line-chart
  // Usage: codyhouse.co/license
  (function() {
    // --default chart demo
    var lineChart1 = document.getElementById('line-chart-1');
    if(lineChart1) {
      new Chart({
        element: lineChart1,
        type: 'line',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months',
          ticks: true
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {
            data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]
          }
        ],
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> $'+chartOptions.datasets[datasetIndex].data[index]+'';
          }
        },
        animate: true
      });
    }
  
    // --smooth chart demo
    var lineChart2 = document.getElementById('line-chart-2');
    if(lineChart2) {
      new Chart({
        element: lineChart2,
        type: 'line',
        smooth: true,
        xAxis : {
          line: true,
          range: [0, 10],
          step: 2,
          labels: true
        },
        yAxis: {
          labels: true
        },
        datasets: [
          {
            data: [[0, 1], [1, 2], [2, -3], [3, 12], [4, 8], [5, 7], [6, 10], [7, 4], [8, 9], [9, 5], [10, 16]]
          }
        ],
        tooltip: {
          enabled: true,
          position: 'top',
          customHTML: function(index, chartOptions, datasetIndex) {
            // show only Y value (chartOptions.datasets[datasetIndex].data[index][1])
            return 'Value: <span class="color-primary">'+chartOptions.datasets[datasetIndex].data[index][1]+'</span>';
          }
        },
        animate: true
      });
    }
  
    // --timeline chart demo
    var timelineChart = document.getElementById('timeline-chart');
    if(timelineChart) {
      var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
      function getNiceDate(timestamp) {
        // custom function to transform timestamp values to formatted dates
        var date = new Date(timestamp);
        var day = date.getDate(),
          month = date.getMonth();
        return day+' '+months[month]; //e.g., '12 Mar'
      };
  
      new Chart({
        element: timelineChart,
        type: 'line',
        xAxis: {
          line: true,
          ticks: true,
          labels: true,
          // range: [firstDate, lastDate]
          // use new Date('yyyy-mm-dd').getTime() to get the timestamp value of your date
          range: [new Date('2018-02-25').getTime(), new Date('2018-03-05').getTime()],
          step: (86400000*2), // two days
          labelModifier: function(value) {
            return getNiceDate(value);
          },
        },
        yAxis: {
          legend: 'Temp',
          labels: true
        },
        datasets: [
          {
            data: [
              [new Date('2018-02-25').getTime(), 1], 
              [new Date('2018-02-26').getTime(), 10], 
              [new Date('2018-02-27').getTime(), 7], 
              [new Date('2018-02-28').getTime(), 12], 
              [new Date('2018-03-01').getTime(), 8],
              [new Date('2018-03-02').getTime(), 10], 
              [new Date('2018-03-03').getTime(), 4],
              [new Date('2018-03-04').getTime(), 8], 
              [new Date('2018-03-05').getTime(), 10]
            ]
          }
        ],
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+getNiceDate(chartOptions.datasets[datasetIndex].data[index][0])+' - </span> '+chartOptions.datasets[datasetIndex].data[index][1] + '°C';
          }
        },
        animate: true
      });
    }
  
    // --multiline chart demo
    var multiLine = document.getElementById('multi-line-chart');
    if(multiLine) {
      new Chart({
        element: multiLine,
        type: 'line',
        xAxis: {
          line: true,
          ticks: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months'
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 6, 4, 11, 9, 10, 9, 4, 7, 3]},
          {data: [5, 7, 11, 13, 18, 16, 17, 13, 16, 8, 15, 8]}
        ],
        tooltip: {
          enabled: true,
          position: 'top',
          customHTML: function(index, chartOptions, datasetIndex) {
            var html = '<p class="margin-bottom-xxs">Total '+chartOptions.xAxis.labels[index] + '</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-primary margin-right-xxs"></span>$'+chartOptions.datasets[0].data[index]+'</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-accent margin-right-xxs"></span>$'+chartOptions.datasets[1].data[index]+'</p>';
            return html;
          }
        },
        animate: true
      });
    }
  
    // --external-data-value chart demo
    var externalData = document.getElementById('ext-line-chart');
    if(externalData) {
      new Chart({
        element: externalData,
        type: 'line',
        xAxis: {
          line: true,
          ticks: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          legend: 'Months'
        },
        yAxis: {
          legend: 'Total',
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 6, 4, 11, 9, 10, 9, 4, 7, 3]},
        ],
        animate: true,
        externalData : {
          customXHTML: function(index, chartOptions, datasetIndex) {
            return ' '+chartOptions.xAxis.labels[index];
          }
        }
      });
    }
  }());
  // File#: _3_looping-slideshow
  // Usage: codyhouse.co/license
  (function() {
    var LoopSlideshow = function(element) {
      this.element = element;
      this.slideshowObj = false;
      this.navItems = this.element.getElementsByClassName('js-slideshow__nav-item');
      this.autoplayInterval = 5000;
      this.autoplayPaused = false;
      this.fillingCSS = '--loop-slideshow-filling';
      this.pauseBtnClass = 'js-loop-slideshow__pause-btn';
      this.pauseBtn = this.element.getElementsByClassName(this.pauseBtnClass);
      this.animating = false;
      this.currentTime = false;
  
      initLoopSlideshow(this);
      initEvents(this);
    };
  
    function initLoopSlideshow(obj) {
      var autoplay = true,
  			autoplayInterval = (obj.element.getAttribute('data-autoplay-interval')) ? obj.element.getAttribute('data-autoplay-interval') : obj.autoplayInterval,
  			swipe = (obj.element.getAttribute('data-swipe') && obj.element.getAttribute('data-swipe') == 'on') ? true : false;
  		obj.slideshowObj = new Slideshow({element: obj.element, navigation: true, autoplay : autoplay, autoplayInterval : autoplayInterval, swipe : swipe, navigationClass: 'loop-slideshow__navigation', navigationItemClass: 'loop-slideshow__nav-item', autoplayOnHover: true, autoplayOnFocus: true});
      // update autoplay interval
      obj.autoplayInterval = autoplayInterval;
      // filling effect for first item
      initFilling(obj, obj.slideshowObj.selectedSlide);
    };
  
    function initEvents(obj) {
      obj.element.addEventListener('newItemSelected', function(event){
        // new slide has been selected
        initFilling(obj, event.detail);
        toggleAutoplay(obj, false);
      });
  
      // custom click on image -> animate slideshow
      obj.element.addEventListener('click', function(event){
        if(event.target.closest('.js-loop-slideshow__pause-btn')) {
          toggleAutoplay(obj, !obj.autoplayPaused); // pause/play autoplay
        } else if(event.target.closest('.js-slideshow__item')) {
          showNewSlide(obj, event);
        }
      });
    };
  
    function initFilling(obj, index) {
      cancelFilling(obj);
  
      for(var i = 0; i < obj.navItems.length; i++) {
        setFilling(obj.navItems[i], obj.fillingCSS, 0);
      }
      // trigger animation
      obj.currentTime = false;
      animateFilling(obj, index);
    };
  
    function cancelFilling(obj) {
      if(obj.animating) { // clear previous animation
        window.cancelAnimationFrame(obj.animating);
        obj.animating = false;
      }
    };
  
    function animateFilling(obj, index) {
      obj.animating = window.requestAnimationFrame(function(timestamp){
        if(!obj.currentTime) obj.currentTime = timestamp;
        var progress = timestamp - obj.currentTime;
        if(progress > obj.autoplayInterval) progress = obj.autoplayInterval;
        setFilling(obj.navItems[index], obj.fillingCSS, (progress/obj.autoplayInterval).toFixed(3));
        
        if(progress < obj.autoplayInterval) {
          animateFilling(obj, index);
        } else {
          // animation is over
          obj.animating = false;
          obj.currentTime = false;
        }
      });
    };
  
    function setFilling(element, property, value) {
      element.style.setProperty(property, value);
    };
  
    function showNewSlide(obj, event) {
      // check if we should go next or prev
      var boundingRect = obj.element.getBoundingClientRect(),
        isNext = event.clientX > boundingRect.left + boundingRect.width/2;
  
      isNext ? obj.slideshowObj.showNext() : obj.slideshowObj.showPrev();
    };
  
    function toggleAutoplay(obj, bool) {
      obj.autoplayPaused = bool;
      if(obj.autoplayPaused) {
        cancelFilling(obj);
        obj.slideshowObj.pauseAutoplay();
      } else {
        obj.slideshowObj.startAutoplay();
        initFilling(obj, obj.slideshowObj.selectedSlide);
      }
      if(obj.pauseBtn.length > 0) {
        // update btn appearance
        Util.toggleClass(obj.pauseBtn[0], 'btn-states--state-b', obj.autoplayPaused);
        // update pressed status 
        obj.autoplayPaused ? obj.pauseBtn[0].setAttribute('aria-pressed', 'true'): obj.pauseBtn[0].setAttribute('aria-pressed', 'false');
      }
    };
  
    //initialize the ThumbSlideshow objects
  	var slideshow = document.getElementsByClassName('js-loop-slideshow');
    if( slideshow.length > 0 ) {
      for( var i = 0; i < slideshow.length; i++) {
        (function(i){
          new LoopSlideshow(slideshow[i]);
        })(i);
      }
    }
  }());
  // File#: _3_main-header-v2
  // Usage: codyhouse.co/license
  (function() {
  	var Submenu = function(element) {
  		this.element = element;
  		this.trigger = this.element.getElementsByClassName('header-v2__nav-link')[0];
  		this.dropdown = this.element.getElementsByClassName('header-v2__nav-dropdown')[0];
  		this.triggerFocus = false;
  		this.dropdownFocus = false;
  		this.hideInterval = false;
  		this.prevFocus = false; // nested dropdown - store element that was in focus before focus changed
  		initSubmenu(this);
  		initNestedDropdown(this);
  	};
  
  	function initSubmenu(list) {
  		initElementEvents(list, list.trigger);
  		initElementEvents(list, list.dropdown);
  	};
  
  	function initElementEvents(list, element, bool) {
  		element.addEventListener('focus', function(){
  			bool = true;
  			showDropdown(list);
  		});
  		element.addEventListener('focusout', function(event){
  			bool = false;
  			hideDropdown(list, event);
  		});
  	};
  
  	function showDropdown(list) {
  		if(list.hideInterval) clearInterval(list.hideInterval);
  		Util.addClass(list.dropdown, 'header-v2__nav-list--is-visible');
  		resetDropdownStyle(list.dropdown, true);
  	};
  
  	function hideDropdown(list, event) {
  		if(list.hideInterval) clearInterval(this.hideInterval);
  		list.hideInterval = setTimeout(function(){
  			var submenuFocus = document.activeElement.closest('.header-v2__nav-item--main'),
  				inFocus = submenuFocus && (submenuFocus == list.element);
  			if(!list.triggerFocus && !list.dropdownFocus && !inFocus) { // hide if focus is outside submenu
  				Util.removeClass(list.dropdown, 'header-v2__nav-list--is-visible');
  				resetDropdownStyle(list.dropdown, false);
  				hideSubLevels(list);
  				list.prevFocus = false;
  			}
  		}, 100);
  	};
  
  	function initNestedDropdown(list) {
  		var dropdownMenu = list.element.getElementsByClassName('header-v2__nav-list');
  		for(var i = 0; i < dropdownMenu.length; i++) {
  			var listItems = dropdownMenu[i].children;
  			// bind hover
  	    new menuAim({
  	      menu: dropdownMenu[i],
  	      activate: function(row) {
  	      	var subList = row.getElementsByClassName('header-v2__nav-dropdown')[0];
  	      	if(!subList) return;
  	      	Util.addClass(row.querySelector('a.header-v2__nav-link'), 'header-v2__nav-link--hover');
  	      	showLevel(list, subList);
  	      },
  	      deactivate: function(row) {
  	      	var subList = row.getElementsByClassName('header-v2__nav-dropdown')[0];
  	      	if(!subList) return;
  	      	Util.removeClass(row.querySelector('a.header-v2__nav-link'), 'header-v2__nav-link--hover');
  	      	hideLevel(list, subList);
  	      },
  	      exitMenu: function() {
  	        return true;
  	      },
  	      submenuSelector: '.header-v2__nav-item--has-children',
  	    });
  		}
  		// store focus element before change in focus
  		list.element.addEventListener('keydown', function(event) { 
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  				list.prevFocus = document.activeElement;
  			}
  		});
  		// make sure that sublevel are visible when their items are in focus
  		list.element.addEventListener('keyup', function(event) {
  			if( event.keyCode && event.keyCode == 9 || event.key && event.key == 'Tab' ) {
  				// focus has been moved -> make sure the proper classes are added to subnavigation
  				var focusElement = document.activeElement,
  					focusElementParent = focusElement.closest('.header-v2__nav-dropdown'),
  					focusElementSibling = focusElement.nextElementSibling;
  
  				// if item in focus is inside submenu -> make sure it is visible
  				if(focusElementParent && !Util.hasClass(focusElementParent, 'header-v2__nav-list--is-visible')) {
  					showLevel(list, focusElementParent);
  				}
  				// if item in focus triggers a submenu -> make sure it is visible
  				if(focusElementSibling && !Util.hasClass(focusElementSibling, 'header-v2__nav-list--is-visible')) {
  					showLevel(list, focusElementSibling);
  				}
  
  				// check previous element in focus -> hide sublevel if required 
  				if( !list.prevFocus) return;
  				var prevFocusElementParent = list.prevFocus.closest('.header-v2__nav-dropdown'),
  					prevFocusElementSibling = list.prevFocus.nextElementSibling;
  				
  				if( !prevFocusElementParent ) return;
  				
  				// element in focus and element prev in focus are siblings
  				if( focusElementParent && focusElementParent == prevFocusElementParent) {
  					if(prevFocusElementSibling) hideLevel(list, prevFocusElementSibling);
  					return;
  				}
  
  				// element in focus is inside submenu triggered by element prev in focus
  				if( prevFocusElementSibling && focusElementParent && focusElementParent == prevFocusElementSibling) return;
  				
  				// shift tab -> element in focus triggers the submenu of the element prev in focus
  				if( focusElementSibling && prevFocusElementParent && focusElementSibling == prevFocusElementParent) return;
  				
  				var focusElementParentParent = focusElementParent.parentNode.closest('.header-v2__nav-dropdown');
  				
  				// shift tab -> element in focus is inside the dropdown triggered by a siblings of the element prev in focus
  				if(focusElementParentParent && focusElementParentParent == prevFocusElementParent) {
  					if(prevFocusElementSibling) hideLevel(list, prevFocusElementSibling);
  					return;
  				}
  				
  				if(prevFocusElementParent && Util.hasClass(prevFocusElementParent, 'header-v2__nav-list--is-visible')) {
  					hideLevel(list, prevFocusElementParent);
  				}
  			}
  		});
  	};
  
  	function hideSubLevels(list) {
  		var visibleSubLevels = list.dropdown.getElementsByClassName('header-v2__nav-list--is-visible');
  		if(visibleSubLevels.length == 0) return;
  		while (visibleSubLevels[0]) {
  			hideLevel(list, visibleSubLevels[0]);
  	 	}
  	 	var hoveredItems = list.dropdown.getElementsByClassName('header-v2__nav-link--hover');
  	 	while (hoveredItems[0]) {
  			Util.removeClass(hoveredItems[0], 'header-v2__nav-link--hover');
  	 	}
  	};
  
  	function showLevel(list, level, bool) {
  		if(bool == undefined) {
  			//check if the sublevel needs to be open to the left
  			Util.removeClass(level, 'header-v2__nav-dropdown--nested-left');
  			var boundingRect = level.getBoundingClientRect();
  			if(window.innerWidth - boundingRect.right < 5 && boundingRect.left + window.scrollX > 2*boundingRect.width) Util.addClass(level, 'header-v2__nav-dropdown--nested-left');
  		}
  		Util.addClass(level, 'header-v2__nav-list--is-visible');
  	};
  
  	function hideLevel(list, level) {
  		if(!Util.hasClass(level, 'header-v2__nav-list--is-visible')) return;
  		Util.removeClass(level, 'header-v2__nav-list--is-visible');
  		
  		level.addEventListener('transition', function cb(){
  			level.removeEventListener('transition', cb);
  			Util.removeClass(level, 'header-v2__nav-dropdown--nested-left');
  		});
  	};
  
  	var mainHeader = document.getElementsByClassName('js-header-v2');
  	if(mainHeader.length > 0) {
  		var menuTrigger = mainHeader[0].getElementsByClassName('js-anim-menu-btn')[0],
  			firstFocusableElement = getMenuFirstFocusable();
  
  		// we'll use these to store the node that needs to receive focus when the mobile menu is closed 
  		var focusMenu = false;
  
  		menuTrigger.addEventListener('anim-menu-btn-clicked', function(event){ // toggle menu visibility an small devices
  			Util.toggleClass(document.getElementsByClassName('header-v2__nav')[0], 'header-v2__nav--is-visible', event.detail);
  			Util.toggleClass(mainHeader[0], 'header-v2--expanded', event.detail);
  			menuTrigger.setAttribute('aria-expanded', event.detail);
  			if(event.detail) firstFocusableElement.focus(); // move focus to first focusable element
  			else if(focusMenu) {
  				focusMenu.focus();
  				focusMenu = false;
  			}
  		});
  
  		// take care of submenu
  		var mainList = mainHeader[0].getElementsByClassName('header-v2__nav-list--main');
  		if(mainList.length > 0) {
  			for( var i = 0; i < mainList.length; i++) {
  				(function(i){
  					new menuAim({ // use diagonal movement detection for main submenu
  			      menu: mainList[i],
  			      activate: function(row) {
  			      	var submenu = row.getElementsByClassName('header-v2__nav-dropdown');
  			      	if(submenu.length == 0 ) return;
  			      	Util.addClass(submenu[0], 'header-v2__nav-list--is-visible');
  			      	resetDropdownStyle(submenu[0], true);
  			      },
  			      deactivate: function(row) {
  			      	var submenu = row.getElementsByClassName('header-v2__nav-dropdown');
  			      	if(submenu.length == 0 ) return;
  			      	Util.removeClass(submenu[0], 'header-v2__nav-list--is-visible');
  			      	resetDropdownStyle(submenu[0], false);
  			      },
  			      exitMenu: function() {
  			        return true;
  			      },
  			      submenuSelector: '.header-v2__nav-item--has-children',
  			      submenuDirection: 'below'
  			    });
  
  			    // take care of focus event for main submenu
  					var subMenu = mainList[i].getElementsByClassName('header-v2__nav-item--main');
  					for(var j = 0; j < subMenu.length; j++) {(function(j){if(Util.hasClass(subMenu[j], 'header-v2__nav-item--has-children')) new Submenu(subMenu[j]);})(j);};
  				})(i);
  			}
  		}
  
  		// if data-animation-offset is set -> check scrolling
  		var animateHeader = mainHeader[0].getAttribute('data-animation');
  		if(animateHeader && animateHeader == 'on') {
  			var scrolling = false,
  				scrollOffset = (mainHeader[0].getAttribute('data-animation-offset')) ? parseInt(mainHeader[0].getAttribute('data-animation-offset')) : 400,
  				mainHeaderHeight = mainHeader[0].offsetHeight,
  				mainHeaderWrapper = mainHeader[0].getElementsByClassName('header-v2__wrapper')[0];
  
  			window.addEventListener("scroll", function(event) {
  				if( !scrolling ) {
  					scrolling = true;
  					(!window.requestAnimationFrame) ? setTimeout(function(){checkMainHeader();}, 250) : window.requestAnimationFrame(checkMainHeader);
  				}
  			});
  
  			function checkMainHeader() {
  				var windowTop = window.scrollY || document.documentElement.scrollTop;
  				Util.toggleClass(mainHeaderWrapper, 'header-v2__wrapper--is-fixed', windowTop >= mainHeaderHeight);
  				Util.toggleClass(mainHeaderWrapper, 'header-v2__wrapper--slides-down', windowTop >= scrollOffset);
  				scrolling = false;
  			};
  		}
  
  		// listen for key events
  		window.addEventListener('keyup', function(event){
  			// listen for esc key
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) {
  				// close navigation on mobile if open
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger)) {
  					focusMenu = menuTrigger; // move focus to menu trigger when menu is close
  					menuTrigger.click();
  				}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) {
  				// close navigation on mobile if open when nav loses focus
  				if(menuTrigger.getAttribute('aria-expanded') == 'true' && isVisible(menuTrigger) && !document.activeElement.closest('.js-header-v2')) menuTrigger.click();
  			}
  		});
  
  		// listen for resize
  		var resizingId = false;
  		window.addEventListener('resize', function() {
  			clearTimeout(resizingId);
  			resizingId = setTimeout(doneResizing, 500);
  		});
  
  		function doneResizing() {
  			if( !isVisible(menuTrigger) && Util.hasClass(mainHeader[0], 'header-v2--expanded')) menuTrigger.click();
  		};
  
  		function getMenuFirstFocusable() {
  			var focusableEle = mainHeader[0].getElementsByClassName('header-v2__nav')[0].querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary'),
  				firstFocusable = false;
  			for(var i = 0; i < focusableEle.length; i++) {
  				if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
  					firstFocusable = focusableEle[i];
  					break;
  				}
  			}
  
  			return firstFocusable;
  		};
  	}
  
  	function resetDropdownStyle(dropdown, bool) {
  		if(!bool) {
  			dropdown.addEventListener('transitionend', function cb(){
  				dropdown.removeAttribute('style');
  				dropdown.removeEventListener('transitionend', cb);
  			});
  		} else {
  			var boundingRect = dropdown.getBoundingClientRect();
  			if(window.innerWidth - boundingRect.right < 5 && boundingRect.left + window.scrollX > 2*boundingRect.width) {
  				var left = parseFloat(window.getComputedStyle(dropdown).getPropertyValue('left'));
  				dropdown.style.left = (left + window.innerWidth - boundingRect.right - 5) + 'px';
  			}
  		}
  	};
  
  	function isVisible(element) {
  		return (element.offsetWidth || element.offsetHeight || element.getClientRects().length);
  	};
  }());
  // File#: _3_mega-site-navigation
  // Usage: codyhouse.co/license
  (function() {
    var MegaNav = function(element) {
      this.element = element;
      this.search = this.element.getElementsByClassName('js-mega-nav__search');
      this.searchActiveController = false;
      this.menu = this.element.getElementsByClassName('js-mega-nav__nav');
      this.menuItems = this.menu[0].getElementsByClassName('js-mega-nav__item');
      this.menuActiveController = false;
      this.itemExpClass = 'mega-nav__item--expanded';
      this.classIconBtn = 'mega-nav__icon-btn--state-b';
      this.classSearchVisible = 'mega-nav__search--is-visible';
      this.classNavVisible = 'mega-nav__nav--is-visible';
      this.classMobileLayout = 'mega-nav--mobile';
      this.classDesktopLayout = 'mega-nav--desktop';
      this.layout = 'mobile';
      // store dropdown elements (if present)
      this.dropdown = this.element.getElementsByClassName('js-dropdown');
      // expanded class - added to header when subnav is open
      this.expandedClass = 'mega-nav--expanded';
      // check if subnav should open on hover
      this.hover = this.element.getAttribute('data-hover') && this.element.getAttribute('data-hover') == 'on';
      initMegaNav(this);
    };
  
    function initMegaNav(megaNav) {
      setMegaNavLayout(megaNav); // switch between mobile/desktop layout
      initSearch(megaNav); // controll search navigation
      initMenu(megaNav); // control main menu nav - mobile only
      initSubNav(megaNav); // toggle sub navigation visibility
      
      megaNav.element.addEventListener('update-menu-layout', function(event){
        setMegaNavLayout(megaNav); // window resize - update layout
      });
    };
  
    function setMegaNavLayout(megaNav) {
      var layout = getComputedStyle(megaNav.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
      if(layout == megaNav.layout) return;
      megaNav.layout = layout;
      Util.toggleClass(megaNav.element, megaNav.classDesktopLayout, megaNav.layout == 'desktop');
      Util.toggleClass(megaNav.element, megaNav.classMobileLayout, megaNav.layout != 'desktop');
      if(megaNav.layout == 'desktop') {
        closeSubNav(megaNav, false);
        // if the mega navigation has dropdown elements -> make sure they are in the right position (viewport awareness)
        triggerDropdownPosition(megaNav);
      } 
      closeSearch(megaNav, false);
      resetMegaNavOffset(megaNav); // reset header offset top value
      resetNavAppearance(megaNav); // reset nav expanded appearance
    };
  
    function resetMegaNavOffset(megaNav) {
      document.documentElement.style.setProperty('--mega-nav-offset-y', megaNav.element.getBoundingClientRect().top+'px');
    };
  
    function closeNavigation(megaNav) { // triggered by Esc key press
      // close search
      closeSearch(megaNav);
      // close nav
      if(Util.hasClass(megaNav.menu[0], megaNav.classNavVisible)) {
        toggleMenu(megaNav, megaNav.menu[0], 'menuActiveController', megaNav.classNavVisible, megaNav.menuActiveController, true);
      }
      //close subnav 
      closeSubNav(megaNav, false);
      resetNavAppearance(megaNav); // reset nav expanded appearance
    };
  
    function closeFocusNavigation(megaNav) { // triggered by Tab key pressed
      // close search when focus is lost
      if(Util.hasClass(megaNav.search[0], megaNav.classSearchVisible) && !document.activeElement.closest('.js-mega-nav__search')) {
        toggleMenu(megaNav, megaNav.search[0], 'searchActiveController', megaNav.classSearchVisible, megaNav.searchActiveController, true);
      }
      // close nav when focus is lost
      if(Util.hasClass(megaNav.menu[0], megaNav.classNavVisible) && !document.activeElement.closest('.js-mega-nav__nav')) {
        toggleMenu(megaNav, megaNav.menu[0], 'menuActiveController', megaNav.classNavVisible, megaNav.menuActiveController, true);
      }
      // close subnav when focus is lost
      for(var i = 0; i < megaNav.menuItems.length; i++) {
        if(!Util.hasClass(megaNav.menuItems[i], megaNav.itemExpClass)) continue;
        var parentItem = document.activeElement.closest('.js-mega-nav__item');
        if(parentItem && parentItem == megaNav.menuItems[i]) continue;
        closeSingleSubnav(megaNav, i);
      }
      resetNavAppearance(megaNav); // reset nav expanded appearance
    };
  
    function closeSearch(megaNav, bool) {
      if(megaNav.search.length < 1) return;
      if(Util.hasClass(megaNav.search[0], megaNav.classSearchVisible)) {
        toggleMenu(megaNav, megaNav.search[0], 'searchActiveController', megaNav.classSearchVisible, megaNav.searchActiveController, bool);
      }
    } ;
  
    function initSearch(megaNav) {
      if(megaNav.search.length == 0) return;
      // toggle search
      megaNav.searchToggles = document.querySelectorAll('[aria-controls="'+megaNav.search[0].getAttribute('id')+'"]');
      for(var i = 0; i < megaNav.searchToggles.length; i++) {(function(i){
        megaNav.searchToggles[i].addEventListener('click', function(event){
          // toggle search
          toggleMenu(megaNav, megaNav.search[0], 'searchActiveController', megaNav.classSearchVisible, megaNav.searchToggles[i], true);
          // close nav if it was open
          if(Util.hasClass(megaNav.menu[0], megaNav.classNavVisible)) {
            toggleMenu(megaNav, megaNav.menu[0], 'menuActiveController', megaNav.classNavVisible, megaNav.menuActiveController, false);
          }
          // close subnavigation if open
          closeSubNav(megaNav, false);
          resetNavAppearance(megaNav); // reset nav expanded appearance
        });
      })(i);}
    };
  
    function initMenu(megaNav) {
      if(megaNav.menu.length == 0) return;
      // toggle nav
      megaNav.menuToggles = document.querySelectorAll('[aria-controls="'+megaNav.menu[0].getAttribute('id')+'"]');
      for(var i = 0; i < megaNav.menuToggles.length; i++) {(function(i){
        megaNav.menuToggles[i].addEventListener('click', function(event){
          // toggle nav
          toggleMenu(megaNav, megaNav.menu[0], 'menuActiveController', megaNav.classNavVisible, megaNav.menuToggles[i], true);
          // close search if it was open
          if(Util.hasClass(megaNav.search[0], megaNav.classSearchVisible)) {
            toggleMenu(megaNav, megaNav.search[0], 'searchActiveController', megaNav.classSearchVisible, megaNav.searchActiveController, false);
          }
          resetNavAppearance(megaNav); // reset nav expanded appearance
        });
      })(i);}
    };
  
    function toggleMenu(megaNav, element, controller, visibleClass, toggle, moveFocus) {
      var menuIsVisible = Util.hasClass(element, visibleClass);
      Util.toggleClass(element, visibleClass, !menuIsVisible);
      Util.toggleClass(toggle, megaNav.classIconBtn, !menuIsVisible);
      menuIsVisible ? toggle.removeAttribute('aria-expanded') : toggle.setAttribute('aria-expanded', 'true');
      if(menuIsVisible) {
        if(toggle && moveFocus) toggle.focus();
        megaNav[controller] = false;
      } else {
        if(toggle) megaNav[controller] = toggle;
  			getFirstFocusable(element).focus(); // move focus to first focusable element
      }
    };
  
    function getFirstFocusable(element) {
      var focusableEle = element.querySelectorAll('[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable], audio[controls], video[controls], summary'),
  		  firstFocusable = false;
      for(var i = 0; i < focusableEle.length; i++) {
        if( focusableEle[i].offsetWidth || focusableEle[i].offsetHeight || focusableEle[i].getClientRects().length ) {
          firstFocusable = focusableEle[i];
          break;
        }
      }
      return firstFocusable;
    };
  
    function initSubNav(megaNav) {
      // toggle subnavigation visibility
      megaNav.element.addEventListener('click', function(event){
        toggleSubNav(megaNav, event, 'click');
      });
  
      if(megaNav.hover) { // data-hover="on" => use mouse events 
        megaNav.element.addEventListener('mouseover', function(event) {
          if(megaNav.layout != 'desktop') return;
          toggleSubNav(megaNav, event, 'mouseover')
        });
  
        megaNav.element.addEventListener('mouseout', function(event){
          if(megaNav.layout != 'desktop') return;
          var mainItem = event.target.closest('.js-mega-nav__item');
          if(!mainItem) return;
          var triggerBtn = mainItem.getElementsByClassName('js-mega-nav__control');
          if(triggerBtn.length < 1) return;
          var itemExpanded = Util.hasClass(mainItem, megaNav.itemExpClass);
          if(!itemExpanded) return;
          var mainItemHover = event.relatedTarget;
          if(mainItemHover && mainItem.contains(mainItemHover)) return;
          
          Util.toggleClass(mainItem, megaNav.itemExpClass, !itemExpanded);
          itemExpanded ? triggerBtn[0].removeAttribute('aria-expanded') : triggerBtn[0].setAttribute('aria-expanded', 'true');
        });
      }
    };
  
    function toggleSubNav(megaNav, event, eventType) {
      var triggerBtn = event.target.closest('.js-mega-nav__control');
      if(!triggerBtn) return;
      var mainItem = triggerBtn.closest('.js-mega-nav__item');
      if(!mainItem) return;
      var itemExpanded = Util.hasClass(mainItem, megaNav.itemExpClass);
      if(megaNav.hover && itemExpanded && megaNav.layout == 'desktop' && eventType != 'click') return;
      Util.toggleClass(mainItem, megaNav.itemExpClass, !itemExpanded);
      itemExpanded ? triggerBtn.removeAttribute('aria-expanded') : triggerBtn.setAttribute('aria-expanded', 'true');
      if(megaNav.layout == 'desktop' && !itemExpanded) closeSubNav(megaNav, mainItem);
      // close search if open
      closeSearch(megaNav, false);
      resetNavAppearance(megaNav); // reset nav expanded appearance
    };
  
    function closeSubNav(megaNav, selectedItem) {
      // close subnav when a new sub nav element is open
      if(megaNav.menuItems.length == 0 ) return;
      for(var i = 0; i < megaNav.menuItems.length; i++) {
        if(megaNav.menuItems[i] != selectedItem) closeSingleSubnav(megaNav, i);
      }
    };
  
    function closeSingleSubnav(megaNav, index) {
      Util.removeClass(megaNav.menuItems[index], megaNav.itemExpClass);
      var triggerBtn = megaNav.menuItems[index].getElementsByClassName('js-mega-nav__control');
      if(triggerBtn.length > 0) triggerBtn[0].removeAttribute('aria-expanded');
    };
  
    function triggerDropdownPosition(megaNav) {
      // emit custom event to properly place dropdown elements - viewport awarness
      if(megaNav.dropdown.length == 0) return;
      for(var i = 0; i < megaNav.dropdown.length; i++) {
        megaNav.dropdown[i].dispatchEvent(new CustomEvent('placeDropdown'));
      }
    };
  
    function resetNavAppearance(megaNav) {
      ( (megaNav.element.getElementsByClassName(megaNav.itemExpClass).length > 0 && megaNav.layout == 'desktop') || megaNav.element.getElementsByClassName(megaNav.classSearchVisible).length > 0 ||(megaNav.element.getElementsByClassName(megaNav.classNavVisible).length > 0 && megaNav.layout == 'mobile'))
        ? Util.addClass(megaNav.element, megaNav.expandedClass)
        : Util.removeClass(megaNav.element, megaNav.expandedClass);
    };
  
    //initialize the MegaNav objects
    var megaNav = document.getElementsByClassName('js-mega-nav');
    if(megaNav.length > 0) {
      var megaNavArray = [];
      for(var i = 0; i < megaNav.length; i++) {
        (function(i){megaNavArray.push(new MegaNav(megaNav[i]));})(i);
      }
  
      // key events
      window.addEventListener('keyup', function(event){
  			if( (event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape' )) { // listen for esc key events
          for(var i = 0; i < megaNavArray.length; i++) {(function(i){
            closeNavigation(megaNavArray[i]);
          })(i);}
  			}
  			// listen for tab key
  			if( (event.keyCode && event.keyCode == 9) || (event.key && event.key.toLowerCase() == 'tab' )) { // close search or nav if it looses focus
          for(var i = 0; i < megaNavArray.length; i++) {(function(i){
            closeFocusNavigation(megaNavArray[i]);
          })(i);}
  			}
      });
  
      window.addEventListener('click', function(event){
        if(!event.target.closest('.js-mega-nav')) closeNavigation(megaNavArray[0]);
      });
      
      // resize - update menu layout
      var resizingId = false,
        customEvent = new CustomEvent('update-menu-layout');
      window.addEventListener('resize', function(event){
        clearTimeout(resizingId);
        resizingId = setTimeout(doneResizing, 200);
      });
  
      function doneResizing() {
        for( var i = 0; i < megaNavArray.length; i++) {
          (function(i){megaNavArray[i].element.dispatchEvent(customEvent)})(i);
        };
      };
  
      (window.requestAnimationFrame) // init mega site nav layout
        ? window.requestAnimationFrame(doneResizing)
        : doneResizing();
    }
  }());
  // File#: _3_select-autocomplete
  // Usage: codyhouse.co/license
  (function() {
    var SelectAuto = function(element) {
      this.element = element;
      this.input = this.element.getElementsByClassName('js-autocomplete__input');
      this.resetBtn = this.element.getElementsByClassName('js-select-auto__input-btn');
      this.select = this.element.getElementsByClassName('js-select-auto__select');
      this.selectedValue = false; // value of the <option> the user selected
      this.selectOptions = []; // autocomplete list extracted from the <select> element
      this.focusOutId = false; // keep track of focus status
      this.autocompleteResults = this.element.getElementsByClassName('js-autocomplete__results');
      initSelectAuto(this);
    };
  
    function initSelectAuto(element) {
      if(element.select.length == 0) return;
      initDataResults(element); // populate autocomplete list
      Util.addClass(element.select[0], 'is-hidden'); // hide native <select> element
      initAutocomplete(element);
      initSelectAutoEvents(element);
    };
  
    function initDataResults(element) {
      // create the list of possible results based on the <select> input
      var optgroups = element.select[0].getElementsByTagName('optgroup');
      if(optgroups.length > 0) {
        for(var i = 0; i < optgroups.length; i++) {
          pushOptgroup(element, optgroups[i]);
        }
      } else {
        // no <optgroup>s -> loop through <options>
        pushOptions(element, element.select[0].getElementsByTagName('option'));
      }
    };
  
    function pushOptgroup(element, optgroup) {
      // push <optgroup> item
      var item = {};
      item.label = optgroup.getAttribute('label');
      item.template = 'optgroup';
      item = setCustomData(item, optgroup);
      element.selectOptions.push(item);
      // now push <option>s
      pushOptions(element, optgroup.getElementsByTagName('option'));
    };
  
    function pushOptions(element, options) {
      for(var i = 0; i < options.length; i++) {
        pushSingleOption(element, options[i]);
      };
    };
  
    function pushSingleOption(element, option) {
      // do not push <option>s without a value
      if(!option.getAttribute('value')) return;
      var item = {};
      item.label = option.text;
      item.template = 'option';
      item.value = option.value;
      item = setCustomData(item, option);
      element.selectOptions.push(item);
    };
  
    function setCustomData(obj, element) {
      // get custom data-attributes added to <option>s/<optgroup>s and add them to the autocomplete list
      var dataset = element.dataset;
      for (var prop in dataset) {
        if (Object.prototype.hasOwnProperty.call(dataset, prop)) {
          obj[prop] = dataset[prop];
        }
      }
      return obj;
    };
    
    function initAutocomplete(element) {
      // CodyHouse Autocomplete component
      // more info: https://codyhouse.co/ds/components/info/autocomplete
      new Autocomplete({
        element: element.element,
        characters: 0,
        searchData: function(value, cb, eventType) {
          selectAutoSearch(element, value, cb, eventType);
        },
        onClick: function(option, obj, event, cb) {
          selectAutoClick(element, option, obj, event, cb);
        }
      });
    };
  
    function selectAutoSearch(element, query, cb, eventType) {
      // get search results
      // more info: https://codyhouse.co/ds/components/info/autocomplete#search-data
  
      if(eventType == 'focus') { 
        // show all results when input is first in focus
        var data = JSON.parse(JSON.stringify(element.selectOptions));
      } else {
        // filter results
        var data = element.selectOptions.filter(function(item){
          // return item if item['label'] contains 'query' or if it is an <optgroup>
          return (query == '' || item['template'] == 'optgroup') ? true : item['label'].toLowerCase().indexOf(query.toLowerCase()) > -1;
        });
    
        // remove empty <optgroup>s
        var i = data.length;
        while (i--) {
          if (data[i].template == 'optgroup' && ( i == data.length - 1 || data[i+1].template == 'optgroup') ) { 
            data.splice(i, 1);
          } 
        }
      }
  
      // add a custom class to the selected <option> in the autocomplete list
      for(var i = 0; i < data.length; i++) {
        if(element.selectedValue && data[i].value && data[i].value == element.selectedValue && data[i].template != 'optgroup') {
          data[i].class = 'select-auto__option--selected';
        } else if(data[i].class) {
          delete data[i].class;
        }
      }
  
      if(data.length == 0) { // fallback for no results found
        data = [{
          label: 'No results',
          template: 'no-results'
        }];
      }
  
      // required by the Autocomplete component
      cb(data);
    };
  
    function selectAutoClick(element, option, obj, event, cb) {
      // an option in the autocomplete list has been selected
      if(option.getAttribute('data-autocomplete-template') != 'option') return;
      // get selected value + selected label
      var value = option.querySelector('[data-autocomplete-value]').innerText;
      var label = option.querySelector('[data-autocomplete-label]').innerText;
      resetSelectAuto(element, value, label);
      cb(); // this closes the autocomplete
    };
  
    function initSelectAutoEvents(element) {
      // on focus out -> reset input to initial value or to '' if the option was not selected
      element.input[0].addEventListener('focusout', function(event) {
        if(element.focusOutId) clearTimeout(element.focusOutId);
        element.focusOutId = setTimeout(function(){
          if(!element.element.contains(document.activeElement) || element.resetBtn[0].contains(document.activeElement)) {
            checkSelectAuto(element);
          }
        }, 100);
      });
  
      // when clicking on x -> reset selection to false
      if(element.resetBtn.length > 0) {
        element.resetBtn[0].addEventListener('click', function(event) {
          event.preventDefault();
          resetSelectAuto(element, false, '');
          element.input[0].focus();
        });
      }
    };
  
    function checkSelectAuto(element) {
      // check if we need to reset the value of the autocomplete input -> used when input loses focus
      var selectedLabel = !element.selectedValue ? '' : element.select[0].options[element.select[0].selectedIndex].text;
      if(element.input[0].value == selectedLabel) return;
      
      // user typed one of the possible options
      var optionInList = optionSelectedInList(element);
      if(optionInList[0]) {
        // update <select> element and return
        resetSelectAuto(element, optionInList[2], optionInList[1]);
        return;
      }
  
      (element.input[0].value == '') 
        ? resetSelectAuto(element, false, '')
        : resetSelectAuto(element, element.selectedValue, selectedLabel);
    };
  
    function optionSelectedInList(element) {
      var inList = false,
        label = '',
        value = false;
      for(var i = 0; i < element.selectOptions.length; i++) {
        if(element.selectOptions[i].template == 'option' && element.selectOptions[i].label.toLowerCase() == element.input[0].value.toLowerCase()) {
          inList = true;
          label = element.selectOptions[i].label;
          value = element.selectOptions[i].value;
          break;
        }
      }
      return [inList, label, value];
    };
  
    function resetSelectAuto(element, value, label) {
      // a new <option> has been selected
      element.input[0].value = label;
      element.selectedValue = value;
      Util.toggleClass(element.element, 'select-auto--selection-done', value);
      if(value === false) { // no value set
        element.select[0].selectedIndex = -1;
      } else { 
        element.select[0].value = value;
      }
      element.select[0].dispatchEvent(new Event('change'));
    };
  
    window.SelectAuto = SelectAuto;
  
    // init the SelectAuto object
    var selectAuto = document.getElementsByClassName('js-select-auto');
    if( selectAuto.length > 0 ) {
      for( var i = 0; i < selectAuto.length; i++) {
        (function(i){new SelectAuto(selectAuto[i]);})(i);
      }
    }
  }());
  // File#: _3_thumbnail-slideshow
  // Usage: codyhouse.co/license
  (function() {
  	var ThumbSlideshow = function(element) {
  		this.element = element;
  		this.slideshow = this.element.getElementsByClassName('slideshow')[0];
  		this.slideshowItems = this.slideshow.getElementsByClassName('js-slideshow__item');
  		this.carousel = this.element.getElementsByClassName('thumbslide__nav-wrapper')[0];
  		this.carouselList = this.carousel.getElementsByClassName('thumbslide__nav-list')[0];
  		this.carouselListWrapper = this.carousel.getElementsByClassName('thumbslide__nav')[0];
  		this.carouselControls = this.element.getElementsByClassName('js-thumbslide__tb-control');
  		// custom obj
  		this.slideshowObj = false;
  		// thumb properties
  		this.thumbItems = false;
  		this.thumbOriginalWidth = false;
  		this.thumbOriginalHeight = false;
  		this.thumbVisibItemsNb = false;
  		this.itemsWidth = false;
  		this.itemsHeight = false;
  		this.itemsMargin = false;
  		this.thumbTranslateContainer = false;
  		this.thumbTranslateVal = 0;
  		// vertical variation
  		this.thumbVertical = Util.hasClass(this.element, 'thumbslide--vertical');
  		// recursive update 
  		this.recursiveDirection = false;
  		// drag events 
  		this.thumbDragging = false;
  		this.dragStart = false;
  		// resize
  		this.resize = false;
  		// image load -> store info about thumb image being loaded
  		this.loaded = false;
  		initThumbs(this);
  		initSlideshow(this);
  		checkImageLoad(this);
  	};
  
  	function initThumbs(thumbSlider) { // create thumb items
  		var carouselItems = '';
  		for(var i = 0; i < thumbSlider.slideshowItems.length; i++) {
  			var url = thumbSlider.slideshowItems[i].getAttribute('data-thumb'),
  				alt = thumbSlider.slideshowItems[i].getAttribute('data-alt');
  			if(!alt) alt = 'Image Preview';
  			carouselItems = carouselItems + '<li class="thumbslide__nav-item"><img src="'+url+'" alt="'+alt+'">'+'</li>';
  		}
  		thumbSlider.carouselList.innerHTML = carouselItems;
  		if(!thumbSlider.thumbVertical) initThumbsLayout(thumbSlider);
  		else loadThumbsVerticalLayout(thumbSlider);
  	};
  
  	function initThumbsLayout(thumbSlider) {  // set thumbs visible numbers + width
  		// evaluate size of single elements + number of visible elements
  		thumbSlider.thumbItems = thumbSlider.carouselList.getElementsByClassName('thumbslide__nav-item');
  		
  		var itemStyle = window.getComputedStyle(thumbSlider.thumbItems[0]),
        containerStyle = window.getComputedStyle(thumbSlider.carouselListWrapper),
  			itemWidth = parseFloat(itemStyle.getPropertyValue('width')),
  			itemMargin = parseFloat(itemStyle.getPropertyValue('margin-right')),
        containerPadding = parseFloat(containerStyle.getPropertyValue('padding-left')),
        containerWidth = parseFloat(containerStyle.getPropertyValue('width'));
  
      if( !thumbSlider.thumbOriginalWidth) { // on resize -> use initial width of items to recalculate 
        thumbSlider.thumbOriginalWidth = itemWidth;
      } else {
        itemWidth = thumbSlider.thumbOriginalWidth;
      }
      // get proper width of elements
      thumbSlider.thumbVisibItemsNb = parseInt((containerWidth - 2*containerPadding + itemMargin)/(itemWidth+itemMargin));
      thumbSlider.itemsWidth = ((containerWidth - 2*containerPadding + itemMargin)/thumbSlider.thumbVisibItemsNb) - itemMargin;
      thumbSlider.thumbTranslateContainer = (((thumbSlider.itemsWidth+itemMargin)* thumbSlider.thumbVisibItemsNb));
      thumbSlider.itemsMargin = itemMargin;
      // flexbox fallback
      if(!flexSupported) thumbSlider.carouselList.style.width = (thumbSlider.itemsWidth + itemMargin)*thumbSlider.slideshowItems.length+'px';
  		setThumbsWidth(thumbSlider);
  	};
  
  	function checkImageLoad(thumbSlider) {
  		if(!thumbSlider.thumbVertical) { // no need to wait for image load, we already have their width
  			updateVisibleThumb(thumbSlider, 0);
  			updateThumbControls(thumbSlider);
  			initTbSlideshowEvents(thumbSlider);
  		} else { // wait for image to be loaded -> need to know the right height
  			var image = new Image();
  			image.onload = function () {thumbSlider.loaded = true;}
  			image.onerror = function () {thumbSlider.loaded = true;}
  			image.src = thumbSlider.slideshowItems[0].getAttribute('data-thumb');
  		}
  	};
  
  	function loadThumbsVerticalLayout(thumbSlider) {
  		// this is the vertical layout -> we need to make sure the thumb are loaded before checking the value of their height
  		if(thumbSlider.loaded) {
  			initThumbsVerticalLayout(thumbSlider);
  			updateVisibleThumb(thumbSlider, 0);
  			updateThumbControls(thumbSlider);
  			initTbSlideshowEvents(thumbSlider);
  		} else { // wait for thumbs to be loaded
  			setTimeout(function(){
  				loadThumbsVerticalLayout(thumbSlider);
  			}, 100);
  		}
  	}
  
  	function initThumbsVerticalLayout(thumbSlider) {
  		// evaluate size of single elements + number of visible elements
  		thumbSlider.thumbItems = thumbSlider.carouselList.getElementsByClassName('thumbslide__nav-item');
  		
  		var itemStyle = window.getComputedStyle(thumbSlider.thumbItems[0]),
        containerStyle = window.getComputedStyle(thumbSlider.carouselListWrapper),
  			itemWidth = parseFloat(itemStyle.getPropertyValue('width')),
  			itemHeight = parseFloat(itemStyle.getPropertyValue('height')),
  			itemRatio = itemWidth/itemHeight,
  			itemMargin = parseFloat(itemStyle.getPropertyValue('margin-bottom')),
        containerPadding = parseFloat(containerStyle.getPropertyValue('padding-top')),
        containerWidth = parseFloat(containerStyle.getPropertyValue('width')),
        containerHeight = parseFloat(containerStyle.getPropertyValue('height'));
  
      if(!flexSupported) containerHeight = parseFloat(window.getComputedStyle(thumbSlider.element).getPropertyValue('height'));
      
      if( !thumbSlider.thumbOriginalHeight ) { // on resize -> use initial width of items to recalculate 
        thumbSlider.thumbOriginalHeight = itemHeight;
        thumbSlider.thumbOriginalWidth = itemWidth;
      } else {
      	resetOriginalSize(thumbSlider);
        itemHeight = thumbSlider.thumbOriginalHeight;
      }
      // get proper height of elements
      thumbSlider.thumbVisibItemsNb = parseInt((containerHeight - 2*containerPadding + itemMargin)/(itemHeight+itemMargin));
      thumbSlider.itemsHeight = ((containerHeight - 2*containerPadding + itemMargin)/thumbSlider.thumbVisibItemsNb) - itemMargin;
      thumbSlider.itemsWidth = thumbSlider.itemsHeight*itemRatio,
      thumbSlider.thumbTranslateContainer = (((thumbSlider.itemsHeight+itemMargin)* thumbSlider.thumbVisibItemsNb));
      thumbSlider.itemsMargin = itemMargin;
      // flexbox fallback
      if(!flexSupported) {
      	thumbSlider.carousel.style.height = (thumbSlider.itemsHeight + itemMargin)*thumbSlider.slideshowItems.length+'px';
  			thumbSlider.carouselListWrapper.style.height = containerHeight+'px';
      }
  		setThumbsWidth(thumbSlider);
  	};
  
  	function setThumbsWidth(thumbSlider) { // set thumbs width
      for(var i = 0; i < thumbSlider.thumbItems.length; i++) {
        thumbSlider.thumbItems[i].style.width = thumbSlider.itemsWidth+"px";
        if(thumbSlider.thumbVertical) thumbSlider.thumbItems[i].style.height = thumbSlider.itemsHeight+"px";
      }
  
      if(thumbSlider.thumbVertical) {
      	var padding = parseFloat(window.getComputedStyle(thumbSlider.carouselListWrapper).getPropertyValue('padding-left'));
      	thumbSlider.carousel.style.width = (thumbSlider.itemsWidth + 2*padding)+"px";
      	if(!flexSupported) thumbSlider.slideshow.style.width = (parseFloat(window.getComputedStyle(thumbSlider.element).getPropertyValue('width')) - (thumbSlider.itemsWidth + 2*padding) - 10) + 'px';
      }
    };
  
  	function initSlideshow(thumbSlider) { // for the main slideshow, we are using the Slideshow component -> we only need to initialize the object
  		var autoplay = (thumbSlider.slideshow.getAttribute('data-autoplay') && thumbSlider.slideshow.getAttribute('data-autoplay') == 'on') ? true : false,
  			autoplayInterval = (thumbSlider.slideshow.getAttribute('data-autoplay-interval')) ? thumbSlider.slideshow.getAttribute('data-autoplay-interval') : 5000,
  			swipe = (thumbSlider.slideshow.getAttribute('data-swipe') && thumbSlider.slideshow.getAttribute('data-swipe') == 'on') ? true : false;
  		thumbSlider.slideshowObj = new Slideshow({element: thumbSlider.slideshow, navigation: false, autoplay : autoplay, autoplayInterval : autoplayInterval, swipe : swipe});
  	};
  
  	function initTbSlideshowEvents(thumbSlider) {
      // listen for new slide selection -> 'newItemSelected' custom event is emitted each time a new slide is selected
      thumbSlider.slideshowObj.element.addEventListener('newItemSelected', function(event){
  			updateVisibleThumb(thumbSlider, event.detail);
      });
  
  		// click on a thumbnail -> update slide in slideshow
  		thumbSlider.carouselList.addEventListener('click', function(event){
  			if(thumbSlider.thumbDragging) return;
  			var selectedOption = event.target.closest('.thumbslide__nav-item');
  			if(!selectedOption || Util.hasClass(selectedOption, 'thumbslide__nav-item--active')) return;
  			thumbSlider.slideshowObj.showItem(Util.getIndexInArray(thumbSlider.carouselList.getElementsByClassName('thumbslide__nav-item'), selectedOption));
  		});
  
  		// reset thumbnails on resize
      window.addEventListener('resize', function(event){
      	if(thumbSlider.resize) return;
      	thumbSlider.resize = true;
        window.requestAnimationFrame(resetThumbsResize.bind(thumbSlider));
      });
  
      // enable drag on thumbnails
  		new SwipeContent(thumbSlider.carouselList);
  		thumbSlider.carouselList.addEventListener('dragStart', function(event){
  			var coordinate =  getDragCoordinate(thumbSlider, event);
  			thumbSlider.dragStart = coordinate;
  			thumbDragEnd(thumbSlider);
  		});
  		thumbSlider.carouselList.addEventListener('dragging', function(event){
  			if(!thumbSlider.dragStart) return;
  			var coordinate =  getDragCoordinate(thumbSlider, event);
  			if(thumbSlider.slideshowObj.animating || Math.abs(coordinate - thumbSlider.dragStart) < 20) return;
  			Util.addClass(thumbSlider.element, 'thumbslide__nav-list--dragging');
  			thumbSlider.thumbDragging = true;
  			Util.addClass(thumbSlider.carouselList, 'thumbslide__nav-list--no-transition');
  			var translate = thumbSlider.thumbVertical ? 'translateY' : 'translateX';
  			setTranslate(thumbSlider, translate+'('+(thumbSlider.thumbTranslateVal + coordinate - thumbSlider.dragStart)+'px)');
  		});
  	};
  
  	function thumbDragEnd(thumbSlider) {
  		thumbSlider.carouselList.addEventListener('dragEnd', function cb(event){
  			var coordinate = getDragCoordinate(thumbSlider, event);
  			thumbSlider.thumbTranslateVal = resetTranslateToRound(thumbSlider, thumbSlider.thumbTranslateVal + coordinate - thumbSlider.dragStart);
  			thumbShowNewItems(thumbSlider, false);
  			thumbSlider.dragStart = false;
  			Util.removeClass(thumbSlider.carouselList, 'thumbslide__nav-list--no-transition');
  			thumbSlider.carouselList.removeEventListener('dragEnd', cb);
  			setTimeout(function(){
  				thumbSlider.thumbDragging = false;
  			}, 50);
  			Util.removeClass(thumbSlider.element, 'thumbslide__nav-list--dragging');
  		});
  	};
  
  	function getDragCoordinate(thumbSlider, event) { // return the drag value based on direction of thumbs navugation
  		return thumbSlider.thumbVertical ? event.detail.y : event.detail.x;
  	}
  
  	function resetTranslateToRound(thumbSlider, value) { // at the ed of dragging -> set translate of coontainer to right value
  		var dimension = getItemDimension(thumbSlider);
  		return Math.round(value/(dimension+thumbSlider.itemsMargin))*(dimension+thumbSlider.itemsMargin);
  	};
  
  	function resetThumbsResize() { // reset thumbs width on resize
  		var thumbSlider = this;
  		if(!thumbSlider.thumbVertical) initThumbsLayout(thumbSlider);
  		else initThumbsVerticalLayout(thumbSlider);
      setThumbsWidth(thumbSlider);
      var dimension = getItemDimension(thumbSlider);
      // reset the translate value of the thumbs container as well
      if( (-1)*thumbSlider.thumbTranslateVal % (dimension + thumbSlider.itemsMargin) > 0 ) {
  			thumbSlider.thumbTranslateVal = -1 * parseInt(((-1)*thumbSlider.thumbTranslateVal)/(dimension + thumbSlider.itemsMargin)) * (dimension + thumbSlider.itemsMargin); 
      	thumbShowNewItems(thumbSlider, false);
      }
      thumbSlider.resize = false;
  	};
  
  	function thumbShowNewItems(thumbSlider, direction) { // when a new slide is selected -> update position of thumbs navigation
  		var dimension = getItemDimension(thumbSlider);
  		if(direction == 'next') thumbSlider.thumbTranslateVal = thumbSlider.thumbTranslateVal - thumbSlider.thumbTranslateContainer;
  		else if(direction == 'prev') thumbSlider.thumbTranslateVal = thumbSlider.thumbTranslateVal + thumbSlider.thumbTranslateContainer;
  		// make sure translate value is correct
  		if(-1*thumbSlider.thumbTranslateVal >= (thumbSlider.thumbItems.length - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin)) thumbSlider.thumbTranslateVal = -1*((thumbSlider.thumbItems.length - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin));
  		if(thumbSlider.thumbTranslateVal > 0) thumbSlider.thumbTranslateVal = 0;
  
  		var translate = thumbSlider.thumbVertical ? 'translateY' : 'translateX';
  		setTranslate(thumbSlider, translate+'('+thumbSlider.thumbTranslateVal+'px)');
  		updateThumbControls(thumbSlider);
  	};
  
  	function updateVisibleThumb(thumbSlider, index) { // update selected thumb
  		// update selected thumbnails
  		var selectedThumb = thumbSlider.carouselList.getElementsByClassName('thumbslide__nav-item--active');
  		if(selectedThumb.length > 0) Util.removeClass(selectedThumb[0], 'thumbslide__nav-item--active');
  		Util.addClass(thumbSlider.thumbItems[index], 'thumbslide__nav-item--active');
  		// update carousel translate value if new thumb is not visible
  		recursiveUpdateThumb(thumbSlider, index);
  	};
  
  	function recursiveUpdateThumb(thumbSlider, index) { // recursive function used to update the position of thumbs navigation (eg when going from last slide to first one)
  		var dimension = getItemDimension(thumbSlider);
  		if( ((index + 1 - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin) + thumbSlider.thumbTranslateVal >= 0) || ( index*(dimension + thumbSlider.itemsMargin) + thumbSlider.thumbTranslateVal <= 0 && thumbSlider.thumbTranslateVal < 0) ) {
  			var increment = ((index + 1 - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin) + thumbSlider.thumbTranslateVal >= 0) ? 1 : -1;
  			if( !thumbSlider.recursiveDirection || thumbSlider.recursiveDirection == increment) {
  				thumbSlider.thumbTranslateVal = -1 * increment * (dimension + thumbSlider.itemsMargin) + thumbSlider.thumbTranslateVal;
  				thumbSlider.recursiveDirection = increment;
  				recursiveUpdateThumb(thumbSlider, index);
  			} else {
  				thumbSlider.recursiveDirection = false;
  				thumbShowNewItems(thumbSlider, false);
  			}
  		} else {
  			thumbSlider.recursiveDirection = false;
  			thumbShowNewItems(thumbSlider, false);
  		}
  	}
  
  	function updateThumbControls(thumbSlider) { // reset thumb controls style
  		var dimension = getItemDimension(thumbSlider);
  		Util.toggleClass(thumbSlider.carouselListWrapper, 'thumbslide__nav--scroll-start', (thumbSlider.thumbTranslateVal != 0));
  		Util.toggleClass(thumbSlider.carouselListWrapper, 'thumbslide__nav--scroll-end', (thumbSlider.thumbTranslateVal != -1*((thumbSlider.thumbItems.length - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin))) && (thumbSlider.thumbItems.length > thumbSlider.thumbVisibItemsNb));
  		if(thumbSlider.carouselControls.length == 0) return;
  		Util.toggleClass(thumbSlider.carouselControls[0], 'thumbslide__tb-control--disabled', (thumbSlider.thumbTranslateVal == 0));
  		Util.toggleClass(thumbSlider.carouselControls[1], 'thumbslide__tb-control--disabled', (thumbSlider.thumbTranslateVal == -1*((thumbSlider.thumbItems.length - thumbSlider.thumbVisibItemsNb)*(dimension + thumbSlider.itemsMargin))));
  	};
  
  	function getItemDimension(thumbSlider) {
  		return thumbSlider.thumbVertical ? thumbSlider.itemsHeight : thumbSlider.itemsWidth;
  	}
  
  	function setTranslate(thumbSlider, translate) {
      thumbSlider.carouselList.style.transform = translate;
      thumbSlider.carouselList.style.msTransform = translate;
    };
  
    function resetOriginalSize(thumbSlider) {
  		if( !Util.cssSupports('color', 'var(--var-name)') ) return;
  		var thumbWidth = parseInt(getComputedStyle(thumbSlider.element).getPropertyValue('--thumbslide-thumbnail-auto-size'));
  		if(thumbWidth == thumbSlider.thumbOriginalWidth) return;
  		thumbSlider.thumbOriginalHeight = parseFloat((thumbSlider.thumbOriginalHeight)*(thumbWidth/thumbSlider.thumbOriginalWidth));
    	thumbSlider.thumbOriginalWidth = thumbWidth;
    };
  	
  	//initialize the ThumbSlideshow objects
  	var thumbSlideshows = document.getElementsByClassName('js-thumbslide'),
  		flexSupported = Util.cssSupports('align-items', 'stretch');
  	if( thumbSlideshows.length > 0 ) {
  		for( var i = 0; i < thumbSlideshows.length; i++) {
  			(function(i){
  				new ThumbSlideshow(thumbSlideshows[i]);
  			})(i);
  		}
  	}
  }());
  // File#: _3_wizard-form
  // Usage: codyhouse.co/license
  (function() {
    var WizardForm = function(element, formValidator) {
      this.element = element;
      this.steps = this.element.getElementsByClassName('js-wiz-form__step');
      this.currentIndex = 0;
      this.stepPrevClass = 'wiz-form__step--prev';
      this.stepNextClass = 'wiz-form__step--next';
      this.currentClass = 'js-wiz-form__step--current';
      // navigation
      this.navPrev = this.element.getElementsByClassName('js-wiz-form__prev');
      this.navNext = this.element.getElementsByClassName('js-wiz-form__next');
      this.formSubmit = this.element.getElementsByClassName('js-wiz-form__submit');
      // step bar
      this.stepsBar = this.element.getElementsByClassName('js-wiz-form__step-indicator');
      if(this.stepsBar.length > 0) {
        this.stepsBarCurrent = this.stepsBar[0].getElementsByClassName('js-wiz-form__current-step');
        this.stepsBarTot = this.stepsBar[0].getElementsByClassName('js-wiz-form__tot-steps');
      }
      // form validator
      this.formValidator = formValidator;
      this.formValidatorSteps = [];
      
      initWizardForm(this);
    };
  
    WizardForm.prototype.showStep = function(index) {
      this.currentIndex = index - 1;
  		updateForm(this)
  	};
  
    function initWizardForm(form) {
      // get selected step
      getSelectedStep(form);
      // reset navigation
      resetNav(form);
      setBarTotalSteps(form);
      resetStepBar(form);
      // init form validator
      if(form.formValidator) initFormValidator(form);
      // update form steps
      form.element.addEventListener('click', function(event) {
        if(form.formValidator && event.target.closest('.js-wiz-form__next')) {
          // change step only if no errors are found
          form.formValidatorSteps[form.currentIndex].validate(function(errors) {
            if(errors.length == 0) changeStep(form, event);
          });
        } else {
          changeStep(form, event);
        }
      });
    };
  
    function changeStep(form, event) {
      if(event.target.closest('.js-wiz-form__next')) updateFormStep(form, 'next');
      if(event.target.closest('.js-wiz-form__prev')) updateFormStep(form, 'prev');
    };
  
    function getSelectedStep(form) {
      var selectedStep = form.element.getElementsByClassName(form.currentClass);
      form.currentIndex = (selectedStep.length > 0) ? Util.getIndexInArray(form.steps, selectedStep[0]): 0;
      setStepsClass(form);
    };
  
    function setStepsClass(form) {
      for(var i = 0; i < form.steps.length; i++) {
        if(i < form.currentIndex) {
          Util.addClass(form.steps[i], form.stepPrevClass);
          Util.removeClass(form.steps[i], form.stepNextClass+' '+form.currentClass);
        } else if( i > form.currentIndex) {
          Util.addClass(form.steps[i], form.stepNextClass);
          Util.removeClass(form.steps[i], form.stepPrevClass+' '+form.currentClass);
        } else {
          Util.addClass(form.steps[i], form.currentClass);
          Util.removeClass(form.steps[i], form.stepNextClass+' '+form.stepPrevClass);
        }
      }
    };
  
    function resetNav(form) {
      if(form.navPrev.length > 0) {
        form.currentIndex > 0 ? Util.removeClass(form.navPrev[0], 'is-hidden') : Util.addClass(form.navPrev[0], 'is-hidden');
      }
      if(form.navNext.length > 0 && form.formSubmit.length > 0) {
        if(form.currentIndex == (form.steps.length - 1)) {
          Util.addClass(form.navNext[0], 'is-hidden');
          Util.removeClass(form.formSubmit[0], 'is-hidden');
        } else {
          Util.removeClass(form.navNext[0], 'is-hidden');
          Util.addClass(form.formSubmit[0], 'is-hidden');
        }
      }
    };
  
    function setBarTotalSteps(form) {
      if(form.stepsBarTot && form.stepsBarTot.length > 0) {
        form.stepsBarTot[0].textContent = form.steps.length;
        form.stepsBar[0].style.setProperty('--steps-v2-steps-nr', form.steps.length);
      }
    };
  
    function resetStepBar(form) {
      if(form.stepsBarCurrent && form.stepsBarCurrent.length > 0) {
        form.stepsBar[0].style.setProperty('--step-v2-current-step', form.currentIndex + 1);
        form.stepsBarCurrent[0].textContent = form.currentIndex + 1;
      }
    };
  
    function updateFormStep(form, direction) {
      // update current step
      if(direction == 'next') form.currentIndex = form.currentIndex + 1;
      else form.currentIndex = form.currentIndex - 1;
      updateForm(form);
    };
  
    function updateForm(form) {
      if(form.currentIndex < 0) form.currentIndex = 0;
      if(form.currentIndex > form.steps.length) form.currentIndex = form.steps.length;
      if(form.currentIndex < form.steps.length) {
        setStepsClass(form); // update form visible step
        resetNav(form);
        resetStepBar(form);
      } else {
        form.currentIndex = form.steps.length - 1;
        // form will be submitted here
      }
    };
  
    function initFormValidator(form) {
      var opts = form.formValidator;
      for(var i = 0; i < form.steps.length; i++) {
        opts.element = form.steps[i];
        form.formValidatorSteps.push(new FormValidator(opts));
      }
    };
  
    window.WizardForm = WizardForm;
  }());
  // File#: _4_area-chart-card
  // Usage: codyhouse.co/license
  (function() {
    var areaChartCard = document.getElementById('area-chart-card');
    if(areaChartCard) {
      new Chart({
        element: areaChartCard,
        type: 'area',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          ticks: true
        },
        yAxis: {
          labels: true
        },
        datasets: [
          {
            data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]
          }
        ],
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            return '<span class="color-contrast-medium">'+chartOptions.xAxis.labels[index] + ':</span> $'+chartOptions.datasets[datasetIndex].data[index]+'';
          }
        },
        animate: true
      });
    };
  }());
  // File#: _4_column-chart-card
  // Usage: codyhouse.co/license
  (function() {
    var columnChartCard = document.getElementById('column-chart-card');
    if(columnChartCard) {
      new Chart({
        element: columnChartCard,
        type: 'column',
        xAxis: {
          line: true,
          labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
          ticks: true
        },
        yAxis: {
          labels: true
        },
        datasets: [
          {data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]},
          {data: [4, 8, 10, 12, 15, 11, 7, 3, 5, 2, 12, 6]}
        ],
        column: {
          width: '60%',
          gap: '2px',
          radius: '4px'
        },
        tooltip: {
          enabled: true,
          customHTML: function(index, chartOptions, datasetIndex) {
            var html = '<p class="margin-bottom-xxs">Total '+chartOptions.xAxis.labels[index] + '</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-primary margin-right-xxs"></span>$'+chartOptions.datasets[0].data[index]+'</p>';
            html = html + '<p class="flex items-center"><span class="height-xxxs width-xxxs radius-50% bg-contrast-higher margin-right-xxs"></span>$'+chartOptions.datasets[1].data[index]+'</p>';
            return html;
          },
          position: 'top'
        },
        animate: true
      });
    };
  }());
  // File#: _4_product-v2
  // Usage: codyhouse.co/license
  (function() {
    function initColorSwatches(product) {
      var slideshow = product.getElementsByClassName('js-product-v2__slideshow'),
        colorSwatches = product.getElementsByClassName('js-color-swatches__select');
      if(slideshow.length == 0 || colorSwatches.length == 0) return; // no slideshow available
  
      var slideshowItems = slideshow[0].getElementsByClassName('js-slideshow__item'); // slideshow items
      
      colorSwatches[0].addEventListener('change', function(event){ // new color has been selected
        selectNewSlideshowItem(colorSwatches[0].options[colorSwatches[0].selectedIndex].value, slideshow[0], slideshowItems);
      });
    };
  
    function selectNewSlideshowItem(value, slideshow, items){
      var selectedItem = document.getElementById('item-'+value);
      if(!selectedItem) return;
      var event = new CustomEvent('selectNewItem', {detail: Util.getIndexInArray(items, selectedItem) + 1});
      slideshow.dispatchEvent(event); // reveal new slide
    };
  
    var productV2 = document.getElementsByClassName('js-product-v2');
    if(productV2.length > 0) {
      for(var i = 0; i < productV2.length; i++) {(function(i){
        initColorSwatches(productV2[i]);
      })(i);}
    }
  }());
  // File#: _4_stats-card
  // Usage: codyhouse.co/license
  (function() {
    var statsCard = document.getElementById('stats-card-chart-1');
    if(statsCard) {
      new Chart({
        element: statsCard,
        type: 'area',
        xAxis: {
          labels: false,
          guides: false
        },
        yAxis: {
          labels: false,
          range: [0, 16], // 16 is the max value in the chart data
          step: 1
        },
        datasets: [
          {
            data: [1, 2, 3, 12, 8, 7, 10, 4, 9, 5, 16, 3]
          }
        ],
        tooltip: {
          enabled: true,
        },
        padding: 6,
        animate: true
      });
    };
  }());