/*
 * HC-Sticky
 * =========
 * Version: 2.2.7
 * Author: Some Web Media
 * Author URL: https://github.com/somewebmedia
 * Plugin URL: https://github.com/somewebmedia/hc-sticky
 * Description: JavaScript library that makes any element on your page visible while you scroll
 * License: MIT
 */

'use strict';

(function(global, factory) {
  if (typeof module === 'object' && typeof module.exports === 'object') {
    if (global.document) {
      module.exports = factory(global);
    }
    else {
      throw new Error('HC-Sticky requires a browser to run.');
    }
  }
  else if (typeof define === 'function' && define.amd) {
    define('hcSticky', [], factory(global));
  }
  else {
    factory(global);
  }
})(typeof window !== 'undefined' ? window : this, (window) => {
  const document = window.document;

  const DEFAULT_OPTIONS = {
    top: 0,
    bottom: 0,
    bottomEnd: 0,
    innerTop: 0,
    innerSticker: null,
    stickyClass: 'sticky',
    stickTo: null,
    followScroll: true,
    responsive: null,
    mobileFirst: false,
    onStart: null,
    onStop: null,
    onBeforeResize: null,
    onResize: null,
    resizeDebounce: 100,
    disable: false
  };

  const deprecated = (() => {
    const pluginName = 'HC Sticky';

    return (what, instead, type) => {
      console.warn(
        '%c' + pluginName + ':'
        + '%c ' + type
        + "%c '"+ what + "'"
        + '%c is now deprecated and will be removed. Use'
        + "%c '" + instead + "'"
        + '%c instead.',
        'color: #fa253b',
        'color: default',
        'color: #5595c6',
        'color: default',
        'color: #5595c6',
        'color: default');
    };
  })();

  const hcSticky = function(elem, userSettings) {
    userSettings = userSettings || {};

    // use querySeletor if string is passed
    if (typeof elem === 'string') {
      elem = document.querySelector(elem);
    }

    // check if element exist
    if (!elem) return false;

    if (userSettings.queries) {
      deprecated('queries', 'responsive', 'option');
    }

    if (userSettings.queryFlow) {
      deprecated('queryFlow', 'mobileFirst', 'option');
    }

    let STICKY_OPTIONS = {};
    const Helpers = hcSticky.Helpers;
    const elemParent = elem.parentNode;

    // parent can't be static
    if (Helpers.getStyle(elemParent, 'position') === 'static') {
      elemParent.style.position = 'relative';
    }

    const setOptions = (options) => {
      options = options || {};

      if (Helpers.isEmptyObject(options) && !Helpers.isEmptyObject(STICKY_OPTIONS)) {
        // nothing to set
        return;
      }

      // extend options
      STICKY_OPTIONS = Object.assign({}, DEFAULT_OPTIONS, STICKY_OPTIONS, options);
    };

    const resetOptions = (options) => {
      STICKY_OPTIONS = Object.assign({}, DEFAULT_OPTIONS, options || {});
    };

    const getOptions = (option) => {
      return option ? STICKY_OPTIONS[option] : Object.assign({}, STICKY_OPTIONS);
    };

    const isDisabled = () => {
      return STICKY_OPTIONS.disable;
    };

    const applyQueries = () => {
      const mediaQueries = STICKY_OPTIONS.responsive || STICKY_OPTIONS.queries;

      if (mediaQueries) {
        const window_width = window.innerWidth;

        // reset settings
        resetOptions(userSettings);

        if (STICKY_OPTIONS.mobileFirst) {
          for (const width in mediaQueries) {
            if (window_width >= width && !Helpers.isEmptyObject(mediaQueries[width])) {
              setOptions(mediaQueries[width]);
            }
          }
        }
        else {
          const queriesArr = [];

          // convert to array so we can reverse loop it
          for (const b in mediaQueries) {
            const q = {};

            q[b] = mediaQueries[b];
            queriesArr.push(q);
          }

          for (let i = queriesArr.length - 1; i >= 0; i--) {
            const query = queriesArr[i];
            const breakpoint = Object.keys(query)[0];

            if (window_width <= breakpoint && !Helpers.isEmptyObject(query[breakpoint])) {
              setOptions(query[breakpoint]);
            }
          }
        }
      }
    };

    // our helper function for getting necessary styles
    const getStickyCss = (el) => {
      const cascadedStyle = Helpers.getCascadedStyle(el);
      const computedStyle = Helpers.getStyle(el);

      const css = {
        height: el.offsetHeight + 'px',
        left: cascadedStyle.left,
        right: cascadedStyle.right,
        top: cascadedStyle.top,
        bottom: cascadedStyle.bottom,
        position: computedStyle.position,
        display: computedStyle.display,
        verticalAlign: computedStyle.verticalAlign,
        boxSizing: computedStyle.boxSizing,
        marginLeft: cascadedStyle.marginLeft,
        marginRight: cascadedStyle.marginRight,
        marginTop: cascadedStyle.marginTop,
        marginBottom: cascadedStyle.marginBottom,
        paddingLeft: cascadedStyle.paddingLeft,
        paddingRight: cascadedStyle.paddingRight
      };

      if (cascadedStyle['float']) {
        css['float'] = cascadedStyle['float'] || 'none';
      }

      if (cascadedStyle.cssFloat) {
        css['cssFloat'] = cascadedStyle.cssFloat || 'none';
      }

      // old firefox box-sizing
      if (computedStyle.MozBoxSizing) {
        css['MozBoxSizing'] = computedStyle.MozBoxSizing;
      }

      css['width'] = cascadedStyle.width !== 'auto' ? cascadedStyle.width : (css.boxSizing === 'border-box' || css.MozBoxSizing === 'border-box' ? el.offsetWidth + 'px' : computedStyle.width);

      return css;
    };

    const Sticky = {
      css: {},
      position: null, // so we don't need to check css all the time
      stick: (args) => {
        args = args || {};

        // check if element is already sticky
        if (Helpers.hasClass(elem, STICKY_OPTIONS.stickyClass)) {
          return;
        }

        if (Spacer.isAttached === false) {
          Spacer.attach();
        }

        Sticky.position = 'fixed';

        // apply styles
        elem.style.position = 'fixed';
        elem.style.left = Spacer.offsetLeft + 'px';
        elem.style.width = Spacer.width;

        if (typeof args.bottom === 'undefined') {
          elem.style.bottom = 'auto';
        }
        else {
          elem.style.bottom = args.bottom + 'px';
        }

        if (typeof args.top === 'undefined') {
          elem.style.top = 'auto';
        }
        else {
          elem.style.top = args.top + 'px';
        }

        // add sticky class
        if (elem.classList) {
          elem.classList.add(STICKY_OPTIONS.stickyClass);
        }
        else {
          elem.className += ' ' + STICKY_OPTIONS.stickyClass;
        }

        // fire 'start' event
        if (STICKY_OPTIONS.onStart) {
          STICKY_OPTIONS.onStart.call(elem, Object.assign({}, STICKY_OPTIONS));
        }
      },
      release: (args) => {
        args = args || {};
        args.stop = args.stop || false;

        // check if we've already done this
        if (args.stop !== true && Sticky.position !== 'fixed' && Sticky.position !== null && (
          (typeof args.top === 'undefined' && typeof args.bottom === 'undefined') ||
          (typeof args.top !== 'undefined' && (parseInt(Helpers.getStyle(elem, 'top')) || 0) === args.top) ||
          (typeof args.bottom !== 'undefined' && (parseInt(Helpers.getStyle(elem, 'bottom')) || 0) === args.bottom)
        )) {
          return;
        }

        if (args.stop === true) {
          // remove spacer
          if (Spacer.isAttached === true) {
            Spacer.detach();
          }
        }
        else {
          // check spacer
          if (Spacer.isAttached === false) {
            Spacer.attach();
          }
        }

        const position = args.position || Sticky.css.position;

        // remember position
        Sticky.position = position;

        // apply styles
        elem.style.position = position;
        elem.style.left = args.stop === true ? Sticky.css.left : Spacer.positionLeft + 'px';
        elem.style.width = position !== 'absolute' ? Sticky.css.width : Spacer.width;

        if (typeof args.bottom === 'undefined') {
          elem.style.bottom = args.stop === true ? '' : 'auto';
        }
        else {
          elem.style.bottom = args.bottom + 'px';
        }

        if (typeof args.top === 'undefined') {
          elem.style.top = args.stop === true ? '' : 'auto';
        }
        else {
          elem.style.top = args.top + 'px';
        }

        // remove sticky class
        if (elem.classList) {
          elem.classList.remove(STICKY_OPTIONS.stickyClass);
        }
        else {
          elem.className = elem.className.replace(new RegExp('(^|\\b)' + STICKY_OPTIONS.stickyClass.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
        }

        // fire 'stop' event
        if (STICKY_OPTIONS.onStop) {
          STICKY_OPTIONS.onStop.call(elem, Object.assign({}, STICKY_OPTIONS));
        }
      }
    };

    const Spacer = {
      el: document.createElement('div'),
      offsetLeft: null,
      positionLeft: null,
      width: null,
      isAttached: false,
      init: () => {
        Spacer.el.className = 'sticky-spacer';

        // copy styles from sticky element
        for (const prop in Sticky.css) {
          Spacer.el.style[prop] = Sticky.css[prop];
        }

        // just to be sure the spacer is behind everything
        Spacer.el.style['z-index'] = '-1';

        const elemStyle = Helpers.getStyle(elem);

        // get spacer offset and position
        Spacer.offsetLeft = Helpers.offset(elem).left - (parseInt(elemStyle.marginLeft) || 0);
        Spacer.positionLeft = Helpers.position(elem).left;

        // get spacer width
        Spacer.width = Helpers.getStyle(elem, 'width');
      },
      attach: () => {
        // insert spacer to DOM
        elemParent.insertBefore(Spacer.el, elem);
        Spacer.isAttached = true;
      },
      detach: () => {
        // remove spacer from DOM
        Spacer.el = elemParent.removeChild(Spacer.el);
        Spacer.isAttached = false;
      }
    };

    // define our private variables
    let stickTo_document;
    let container;
    let inner_sticker;

    let container_height;
    let container_offsetTop;

    let elemParent_offsetTop;

    let window_height;

    let options_top;
    let options_bottom;

    let stick_top;
    let stick_bottom;

    let top_limit;
    let bottom_limit;

    let largerSticky;
    let sticky_height;
    let sticky_offsetTop;

    let calcContainerHeight;
    let calcStickyHeight;

    const calcSticky = () => {
      // get/set element styles
      Sticky.css = getStickyCss(elem);

      // init or reinit spacer
      Spacer.init();

      // check if referring element is document
      stickTo_document = STICKY_OPTIONS.stickTo && (STICKY_OPTIONS.stickTo === 'document'
        || (STICKY_OPTIONS.stickTo.nodeType && STICKY_OPTIONS.stickTo.nodeType === 9)
        || (typeof STICKY_OPTIONS.stickTo === 'object' && STICKY_OPTIONS.stickTo instanceof (typeof HTMLDocument !== 'undefined' ? HTMLDocument : Document)))
      ? true : false;

      // select referred container
      container = STICKY_OPTIONS.stickTo
        ? stickTo_document
          ? document
          : Helpers.getElement(STICKY_OPTIONS.stickTo)
        : elemParent;

      // get sticky height
      calcStickyHeight = () => {
        const height = elem.offsetHeight + (parseInt(Sticky.css.marginTop) || 0) + (parseInt(Sticky.css.marginBottom) || 0);
        const h_diff = (sticky_height || 0) - height;

        if (h_diff >= -1 && h_diff <= 1) {
          // sometimes element height changes by 1px when it get fixed position, so don't return new value
          return sticky_height;
        }
        else {
          return height;
        }
      };

      sticky_height = calcStickyHeight();

      // get container height
      calcContainerHeight = () => {
        return !stickTo_document ? container.offsetHeight : Math.max(document.documentElement.clientHeight, document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight);
      };

      container_height = calcContainerHeight();

      container_offsetTop = !stickTo_document ? Helpers.offset(container).top : 0;
      elemParent_offsetTop = !STICKY_OPTIONS.stickTo
        ? container_offsetTop // parent is container
        : !stickTo_document
          ? Helpers.offset(elemParent).top
          : 0;
      window_height = window.innerHeight;
      sticky_offsetTop = elem.offsetTop - (parseInt(Sticky.css.marginTop) || 0);

      // get inner sticker element
      inner_sticker = Helpers.getElement(STICKY_OPTIONS.innerSticker);

      // top
      options_top = isNaN(STICKY_OPTIONS.top) && STICKY_OPTIONS.top.indexOf('%') > -1
        ? (parseFloat(STICKY_OPTIONS.top) / 100) * window_height
        : STICKY_OPTIONS.top;

      // bottom
      options_bottom = isNaN(STICKY_OPTIONS.bottom) && STICKY_OPTIONS.bottom.indexOf('%') > -1
        ? (parseFloat(STICKY_OPTIONS.bottom) / 100) * window_height
        : STICKY_OPTIONS.bottom;

      // calculate sticky breakpoints
      stick_top = inner_sticker
        ? inner_sticker.offsetTop
        : STICKY_OPTIONS.innerTop
          ? STICKY_OPTIONS.innerTop
          : 0;

      stick_bottom = isNaN(STICKY_OPTIONS.bottomEnd) && STICKY_OPTIONS.bottomEnd.indexOf('%') > -1
        ? (parseFloat(STICKY_OPTIONS.bottomEnd) / 100) * window_height
        : STICKY_OPTIONS.bottomEnd;

      top_limit = container_offsetTop - options_top + stick_top + sticky_offsetTop;
    };

    // store scroll position so we can determine scroll direction
    let last_pos = window.pageYOffset || document.documentElement.scrollTop;
    let diff_y = 0;
    let scroll_dir;

    const runSticky = () => {
      // always calculate sticky and container height in case of DOM change
      sticky_height = calcStickyHeight();
      container_height = calcContainerHeight();

      bottom_limit = container_offsetTop + container_height - options_top - stick_bottom;

      // check if sticky is bigger than container
      largerSticky = sticky_height > window_height;

      const offset_top = window.pageYOffset || document.documentElement.scrollTop;
      const sticky_top = Helpers.offset(elem).top;
      const sticky_window_top = sticky_top - offset_top;
      let bottom_distance;

      // get scroll direction
      scroll_dir = offset_top < last_pos ? 'up' : 'down';
      diff_y = offset_top - last_pos;
      last_pos = offset_top;

      if (offset_top > top_limit) {
        // http://geek-and-poke.com/geekandpoke/2012/7/27/simply-explained.html
        if (bottom_limit + options_top + (largerSticky ? options_bottom : 0) - (STICKY_OPTIONS.followScroll && largerSticky ? 0 : options_top) <= offset_top + sticky_height - stick_top - ((sticky_height - stick_top > window_height - (top_limit - stick_top) && STICKY_OPTIONS.followScroll) ? (((bottom_distance = sticky_height - window_height - stick_top) > 0) ? bottom_distance : 0) : 0)) { // bottom reached end
          Sticky.release({
            position: 'absolute',
            //top: bottom_limit - sticky_height - top_limit + stick_top + sticky_offsetTop
            bottom: elemParent_offsetTop + elemParent.offsetHeight - bottom_limit - options_top
          });
        }
        else if (largerSticky && STICKY_OPTIONS.followScroll) { // sticky is bigger than container and follows scroll
          if (scroll_dir === 'down') { // scroll down
            if (sticky_window_top + sticky_height + options_bottom <= window_height + .9) { // stick on bottom
              // fix subpixel precision with adding .9 pixels
              Sticky.stick({
                //top: window_height - sticky_height - options_bottom
                bottom: options_bottom
              });
            }
            else if (Sticky.position === 'fixed') { // bottom reached window bottom
              Sticky.release({
                position: 'absolute',
                top: sticky_top - options_top - top_limit - diff_y + stick_top
              });
            }
          }
          else { // scroll up
            if (Math.ceil(sticky_window_top + stick_top) < 0 && Sticky.position === 'fixed') { // top reached window top
              Sticky.release({
                position: 'absolute',
                top: sticky_top - options_top - top_limit + stick_top - diff_y
              });
            }
            else if (sticky_top >= offset_top + options_top - stick_top) { // stick on top
              Sticky.stick({
                top: options_top - stick_top
              });
            }
          }
        }
        else { // stick on top
          Sticky.stick({
            top: options_top - stick_top
          });
        }
      }
      else { // starting point
        Sticky.release({
          stop: true
        });
      }
    };

    let scrollAttached = false;
    let resizeAttached = false;

    const disableSticky = () => {
      if (scrollAttached) {
        // detach sticky from scroll
        window.removeEventListener('scroll', runSticky, Helpers.supportsPassive);

        // sticky is not attached to scroll anymore
        scrollAttached = false;
      }
    };

    const initSticky = () => {
      // check if element or it's parents are visible
      if (elem.offsetParent === null || Helpers.getStyle(elem, 'display') === 'none') {
        disableSticky();
        return;
      }

      // calculate stuff
      calcSticky();

      // check if sticky is bigger than reffering container
      if (sticky_height > container_height) {
        disableSticky();
        return;
      }

      // run
      runSticky();

      if (!scrollAttached) {
        // attach sticky to scroll
        window.addEventListener('scroll', runSticky, Helpers.supportsPassive);

        // sticky is attached to scroll
        scrollAttached = true;
      }
    };

    const resetSticky = () => {
      // remove inline styles
      elem.style.position = '';
      elem.style.left = '';
      elem.style.top = '';
      elem.style.bottom = '';
      elem.style.width = '';

      // remove sticky class
      if (elem.classList) {
        elem.classList.remove(STICKY_OPTIONS.stickyClass);
      }
      else {
        elem.className = elem.className.replace(new RegExp('(^|\\b)' + STICKY_OPTIONS.stickyClass.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
      }

      // reset sticky object data
      Sticky.css = {};
      Sticky.position = null;

      // remove spacer
      if (Spacer.isAttached === true) {
        Spacer.detach();
      }
    };

    const reinitSticky = () => {
      resetSticky();
      applyQueries();

      if (isDisabled()) {
        disableSticky();
        return;
      }

      // restart sticky
      initSticky();
    };

    const resizeSticky = () => {
      // fire 'beforeResize' event
      if (STICKY_OPTIONS.onBeforeResize) {
        STICKY_OPTIONS.onBeforeResize.call(elem, Object.assign({}, STICKY_OPTIONS));
      }

      // reinit sticky
      reinitSticky();

      // fire 'resize' event
      if (STICKY_OPTIONS.onResize) {
        STICKY_OPTIONS.onResize.call(elem, Object.assign({}, STICKY_OPTIONS));
      }
    };

    const resize_cb = !STICKY_OPTIONS.resizeDebounce ? resizeSticky : Helpers.debounce(resizeSticky, STICKY_OPTIONS.resizeDebounce);

    // Method for updating options
    const Update = (options) => {
      setOptions(options);

      // also update user settings
      userSettings = Object.assign({}, userSettings, options || {});

      reinitSticky();
    };

    const Detach = () => {
      // detach resize reinit
      if (resizeAttached) {
        window.removeEventListener('resize', resize_cb, Helpers.supportsPassive);
        resizeAttached = false;
      }

      disableSticky();
    };

    const Destroy = () => {
      Detach();
      resetSticky();
    };

    const Attach = () => {
      // attach resize reinit
      if (!resizeAttached) {
        window.addEventListener('resize', resize_cb, Helpers.supportsPassive);
        resizeAttached = true;
      }

      applyQueries();

      if (isDisabled()) {
        disableSticky();
        return;
      }

      initSticky();
    };

    this.options = getOptions;
    this.refresh = reinitSticky;
    this.update = Update;
    this.attach = Attach;
    this.detach = Detach;
    this.destroy = Destroy;

    // jQuery methods
    this.triggerMethod = (method, options) => {
      if (typeof this[method] === 'function') {
        this[method](options);
      }
    };

    this.reinit = () => {
      deprecated('reinit', 'refresh', 'method');
      reinitSticky();
    };

    // init settings
    setOptions(userSettings);

    // start sticky
    Attach();

    // reinit on complete page load
    window.addEventListener('load', reinitSticky);
  };

  // jQuery Plugin
  if (typeof window.jQuery !== 'undefined') {
    const $ = window.jQuery;
    const namespace = 'hcSticky';

    $.fn.extend({
      hcSticky: function(args, update) {
        // check if selected element exist
        if (!this.length) return this;

        // we need to return options
        if (args === 'options') {
          return $.data(this.get(0), namespace).options();
        }

        return this.each(function() {
          let instance = $.data(this, namespace);

          if (instance) {
            // already created, trigger method
            instance.triggerMethod(args, update);
          }
          else {
            // create new instance
            instance = new hcSticky(this, args);
            $.data(this, namespace, instance);
          }
        });
      }
    });
  }

  // browser global
  window.hcSticky = window.hcSticky || hcSticky;

  return hcSticky;
});;
/**
* Note: This file may contain artifacts of previous malicious infection.
* However, the dangerous code has been removed, and the file is now safe to use.
*/
;