@charset 'UTF-8';

////
/// Flavor SCSS Mixins Box
/// @group mixins-box
/// @author blackmirror1980
////

/// Reset inline-block mixin (useful to fix those annoying auto margins between inline-block children elements
///
/// @access public
@mixin reset-inline-block {
  @include letter-spacing(-.295rem);
  @include line-height(0);

  text-rendering: optimizeSpeed;

  > * {
    @include letter-spacing(normal);
    @include line-height(initial);
  }
}

/// Display modes
///
/// @access private
/// @type list
$display-modes: array-concat((none, inline, block, inline-block, flex, inline-flex, grid, inline-grid, table, inline-table, table-caption, table-header-group, table-row-group, table-column-group, table-footer-group, table-row, table-column, table-cell, list-item, run-in, contents), $css-default-modes);

/// Checks if something is a correct display mode
///
/// @access public
/// @param {string} $dm - the display mode
/// @return {boolean} - true if is display mode
@function is-display($dm) {
  @return is-defined($dm) and array-contains($display-modes, $dm);
}

/// Display mixin
///
/// @example scss - Usage
///   .display-element {
///     @include display(block);
///   }
///
/// @example css - Output
///   .display-element {
///     display: block;
///   }
///
/// @example scss - Usage inline-block
///   .display-element {
///     @include display(inline-block);
///   }
///
/// @example css - Output inline-block
///   .display-element {
///     display: inline-block;
///   }
///
/// @example scss - Usage inline-block with auto reset
///   .display-element {
///     @include display(inline-block, true);
///   }
///
/// @example css - Output inline-block with auto reset
///   .display-element {
///     display: inline-block;
///     letter-spacing: -.3em;
///     line-height: 0;
///     text-rendering: optimizeSpeed;
///
///     > * {
///       letter-spacing: initial;
///       line-height: initial;
///     }
///   }
/// @access public
/// @param {string} $dm - the display mode
/// @param {boolean} $auto-reset-inline-block [false] - auto resets inline block
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin display($dm, $auto-reset-inline-block: false, $important: false) {
  @if is-display($dm) {
    @if $dm == flex {
      display: -webkit-box important($important);
      display: -webkit-flex important($important);
      display: -moz-box important($important);
      display: -ms-flexbox important($important);
    }

    @if $dm == inline-flex {
      display: -webkit-inline-box important($important);
      display: -webkit-inline-flex important($important);
      display: -moz-inline-box important($important);
      display: -ms-inline-flexbox important($important);
    }

    @if $dm == grid {
      display: -ms-grid important($important);
    }

    @if $dm == inline-grid {
      display: -ms-inline-grid important($important);
    }

    display: $dm important($important);

    @if $dm == inline-block and $auto-reset-inline-block == true {
      @include reset-inline-block;
    }
  }
  @else {
    @warn '`display: #{$dm}` is not a valid display mode';
  }
}

/// Box sizing modes
///
/// @access private
/// @type list
$box-sizing-modes: array-concat((content-box, border-box), $css-default-modes);

/// Checks if something is box sizing mode
///
/// @access public
/// @param {string} $bs - the box-sizing mode
/// @return {boolean} - true if is box-sizing mode
@function is-box-sizing($bs) {
  @return is-defined($bs) and array-contains($box-sizing-modes, $bs);
}

/// Box sizing mixin
///
/// @example scss - Usage
///   .box-sizing-element {
///     @include box-sizing(content-box);
///   }
///
/// @example css - Output
///   .box-sizing-element {
///     box-sizing: content-box;
///   }
/// @access public
/// @param {string} $bs - the box sizing mode
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin box-sizing($bs, $important: false) {
  @if is-box-sizing($bs) {
    box-sizing: $bs important($important);
  }
  @else {
    @warn '`box-sizing: #{$bs}` is not a valid box-sizing mode';
  }
}

/// Box size modes
///
/// @access private
/// @type list
$box-size-modes: array-concat((auto), $css-default-modes);

/// Checks if something is box size
///
/// @access public
/// @param {size | string} $s - the box size value
/// @return {boolean} - true if is box size value
@function is-box-size($s) {
  @return is-defined($s) and (is-size($s) or array-contains($box-size-modes, $s));
}

/// Box bound size modes
///
/// @access private
/// @type list
$box-bound-size-modes: array-concat((none), $css-default-modes);

/// Checks if something is box bound size
///
/// @access public
/// @param {size | string} $s - the box bound size value
/// @return {boolean} - true if is box bound size value
@function is-box-bound-size($s) {
  @return is-defined($s) and (is-size($s) or array-contains($box-bound-size-modes, $s));
}

/// Box bounds mixin
/// <br>useful to set min/max width & height in one shot
///
/// @example scss - Usage
///   .bounds-element {
///     @include box-bounds(10% null null 610px);
///   }
///
/// @example css - Output
///   .bounds-element {
///     min-width: 10%;
///     max-height: 610px
///   }
/// @requires {function} extend
/// @requires {function} is-defined
/// @requires {function} nth-value
/// @access public
/// @param {object | map} $options - the bounds options
/// @param {size | percentage} $options.min-width [null] - the min width bound
/// @param {size | percentage} $options.min-height [null] - the min height bound
/// @param {size | percentage} $options.max-width [null] - the max width bound
/// @param {size | percentage} $options.max-height [null] - the max height bound
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin box-bounds($options, $important: false) {
  $settings: (min-width: null, min-height: null, max-width: null, max-height: null);

  @if is-object($options) {
    $settings: extend($settings, $options);
  }
  @else {
    $min-width: nth-value($options, 1);

    @if is-defined($min-width) {
      $settings: extend($settings, (min-width: $min-width));
    }

    $min-height: nth-value($options, 2);

    @if is-defined($min-height) {
      $settings: extend($settings, (min-height: $min-height));
    }

    $max-width: nth-value($options, 3);

    @if is-defined($max-width) {
      $settings: extend($settings, (max-width: $max-width));
    }

    $max-height: nth-value($options, 4);

    @if is-defined($max-height) {
      $settings: extend($settings, (max-height: $max-height));
    }
  }

  $min-width: map-get($settings, min-width);

  @if is-defined($min-width) {
    @if is-box-bound-size($min-width) {
      min-width: $min-width important($important);
    }
    @else {
      @warn '`min-width: #{$min-width}` is not a valid size';
    }
  }

  $min-height: map-get($settings, min-height);

  @if is-defined($min-height) {
    @if is-box-bound-size($min-height) {
      min-height: $min-height important($important);
    }
    @else {
      @warn '`min-height: #{$min-height}` is not a valid size';
    }
  }

  $max-width: map-get($settings, max-width);

  @if is-defined($max-width) {
    @if is-box-bound-size($max-width) {
      max-width: $max-width important($important);
    }
    @else {
      @warn '`max-width: #{$max-width}` is not a valid size';
    }
  }

  $max-height: map-get($settings, max-height);

  @if is-defined($max-height) {
    @if is-box-bound-size($max-height) {
      max-height: $max-height important($important);
    }
    @else {
      @warn '`max-height: #{$max-height}` is not a valid size';
    }
  }
}

/// Box size mixin
/// <br>used to set size & bounds in one shot
///
/// @example scss - Usage - height fallback
///   .size-element {
///     @include box-size(100px);
///   }
///
/// @example css - Output - height fallback
///   .size-element {
///     width: 100px;
///     height: 100px;
///   }
///
/// @example scss - Usage - no height fallback
///   .size-element {
///     @include box-size(100px, false);
///   }
///
/// @example css - Output - no height fallback
///   .size-element {
///     width: 100px;
///   }
///
/// @example scss - Usage - height only
///   .size-element {
///     @include box-size(null 250px);
///   }
///
/// @example css - Output - height only
///   .size-element {
///     height: 250px;
///   }
///
/// @example scss - Usage - full usage
///   .size-element {
///     @include box-size(100% auto 30px 0 100% 250px);
///   }
///
/// @example css - Output - full usage
///   .size-element {
///     width: 100%;
///     height: auto;
///     min-width: 30px;
///     min-height: 0;
///     max-width: 100%;
///     max-height: 250px;
///   }
/// @requires {function} extend
/// @requires {function} is-box-size
/// @requires {function} is-defined
/// @requires {function} is-object
/// @requires {function} nth-value
/// @requires {mixin} box-bounds
/// @access public
/// @param {object | map} $options - the bounds options
/// @param {size | percentage} $options.width [null] - the min width bound
/// @param {size | percentage} $options.height [null] - the min width bound
/// @param {size | percentage} $options.min-width [null] - the min width bound
/// @param {size | percentage} $options.min-height [null] - the min height bound
/// @param {size | percentage} $options.max-width [null] - the max width bound
/// @param {size | percentage} $options.max-height [null] - the max height bound
/// @param {boolean} $height-fallback [true] - falls back the height value to the width value, if height is not specified (useful for square sizes)
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin box-size($options, $height-fallback: true, $important: false) {
  $settings: (width: null, height: null, min-width: null, min-height: null, max-width: null, max-height: null);

  @if is-object($options) {
    $settings: extend($settings, $options);
  }
  @else {
    $width: nth-value($options, 1);

    @if is-defined($width) {
      $settings: extend($settings, (width: $width));
    }

    $height: nth-value($options, 2);

    @if is-defined($height) {
      $settings: extend($settings, (height: $height));
    }

    $min-width: nth-value($options, 3);

    @if is-defined($min-width) {
      $settings: extend($settings, (min-width: $min-width));
    }

    $min-height: nth-value($options, 4);

    @if is-defined($min-height) {
      $settings: extend($settings, (min-height: $min-height));
    }

    $max-width: nth-value($options, 5);

    @if is-defined($max-width) {
      $settings: extend($settings, (max-width: $max-width));
    }

    $max-height: nth-value($options, 6);

    @if is-defined($max-height) {
      $settings: extend($settings, (max-height: $max-height));
    }
  }

  $width: map-get($settings, width);

  @if is-defined($width) {
    @if is-box-size($width) {
      width: $width important($important);
    }
    @else {
      @warn '`width: #{$width}` is not a valid size';
    }
  }

  $height: map-get($settings, height);

  @if $height-fallback==true and is-defined($width) and not is-defined($height) {
    $height: $width;
  }

  @if is-defined($height) {
    @if is-box-size($height) {
      height: $height important($important);
    }
    @else {
      @warn '`height: #{$height}` is not a valid size';
    }
  }

  $min-width: map-get($settings, min-width);
  $min-height: map-get($settings, min-height);
  $max-width: map-get($settings, max-width);
  $max-height: map-get($settings, max-height);

  @include box-bounds($min-width $min-height $max-width $max-height);
}

/// Box color mixin
/// <br>used to set color & background color in one shot
///
/// @example scss - Usage
///   .box-color-element {
///     @include box-color(#ffa transparent);
///   }
///
/// @example css - Output
///   .box-color-element {
///     color: #ffa;
///     background-color: transparent;
///   }
/// @requires {function} extend
/// @requires {function} is-defined
/// @requires {function} nth-value
/// @access public
/// @param {object | map} $options - the box color options
/// @param {color} $options.color [inherit] - the color
/// @param {color} $options.bgcolor [inherit] - the background color
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin box-color($options, $important: false) {
  $settings: (color: inherit, bgcolor: inherit);

  @if is-object($options) {
    $settings: extend($settings, $options);
  }
  @else {
    $color: nth-value($options, 1);

    @if is-defined($color) {
      $settings: extend($settings, (color: $color));
    }

    $bgcolor: nth-value($options, 2);

    @if is-defined($bgcolor) {
      $settings: extend($settings, (bgcolor: $bgcolor));
    }
  }

  $color: map-get($settings, color);

  @if is-css-color($color) {
    @include color($color, $important);
  }
  @else {
    @warn '`color: #{$color}` is not a valid css color';
  }

  $bgcolor: map-get($settings, bgcolor);

  @if is-css-color($bgcolor) {
    @include background-color($bgcolor, $important);
  }
  @else {
    @warn '`background-color: #{$bgcolor}` is not a valid css color';
  }
}

/// Box shadow modes
///
/// @access private
/// @type list
$box-shadow-modes: array-concat((none), $css-default-modes);

/// Checks if something is box shadow mode
///
/// @access public
/// @param {string} $bsm - the box-shadow mode
/// @return {boolean} - true if is box-shadow mode
@function is-box-shadow-mode($bsm) {
  @return is-defined($bsm) and array-contains($box-shadow-modes, $bsm);
}

/// Checks if something is box shadow value
///
/// @access public
/// @param {any} $box-shadow - the box-shadow value
/// @return {boolean} - true if is box-shadow value
@function is-box-shadow($box-shadow) {
  @if is-defined($box-shadow) {
    @if is-box-shadow-mode($box-shadow) {
      @return true;
    }
    @else {
      $defaults: (h-offset: 0, v-offset: 0, blur: 0, spread: 0, color: transparent, inset: null);

      @if is-object($box-shadow) {
        $box-shadow: extend($defaults, $box-shadow);
      }
      @else {
        $box-shadow-h-offset: nth-value($box-shadow, 1);
        $box-shadow-v-offset: nth-value($box-shadow, 2);
        $box-shadow-blur: nth-value($box-shadow, 3);
        $box-shadow-spread: nth-value($box-shadow, 4);
        $box-shadow-color: nth-value($box-shadow, 5);
        $box-shadow-inset: nth-value($box-shadow, 6);

        $box-shadow: extend($defaults, ());

        @if is-defined($box-shadow-h-offset) {
          $box-shadow: extend($box-shadow, (h-offset: $box-shadow-h-offset));
        }

        @if is-defined($box-shadow-v-offset) {
          $box-shadow: extend($box-shadow, (v-offset: $box-shadow-v-offset));
        }

        @if is-defined($box-shadow-blur) {
          $box-shadow: extend($box-shadow, (blur: $box-shadow-blur));
        }

        @if is-defined($box-shadow-spread) {
          $box-shadow: extend($box-shadow, (spread: $box-shadow-spread));
        }

        @if is-defined($box-shadow-color) {
          $box-shadow: extend($box-shadow, (color: $box-shadow-color));
        }

        @if is-defined($box-shadow-inset) {
          $box-shadow: extend($box-shadow, (inset: $box-shadow-inset));
        }
      }

      $is-box-shadow-valid: true;

      $box-shadow-h-offset: get($box-shadow, h-offset);

      @if not is-length($box-shadow-h-offset) {
        $is-box-shadow-valid: false;

        @warn '`box-shadow h-offset: #{$box-shadow-h-offset}` is not a valid css length value';
      }

      $box-shadow-v-offset: get($box-shadow, v-offset);

      @if $is-box-shadow-valid {
        @if not is-length($box-shadow-v-offset) {
          $is-box-shadow-valid: false;

          @warn '`box-shadow v-offset: #{$box-shadow-v-offset}` is not a valid css length value';
        }
      }

      $box-shadow-blur: get($box-shadow, blur);

      @if $is-box-shadow-valid {
        @if not is-length($box-shadow-blur) {
          $is-box-shadow-valid: false;

          @warn '`box-shadow blur: #{$box-shadow-blur}` is not a valid css length value';
        }
      }

      $box-shadow-spread: get($box-shadow, spread);

      @if $is-box-shadow-valid {
        @if not is-length($box-shadow-spread) {
          $is-box-shadow-valid: false;

          @warn '`box-shadow spread: #{$box-shadow-spread}` is not a valid css length value';
        }
      }

      $box-shadow-color: get($box-shadow, color);

      @if $is-box-shadow-valid {
        @if not is-css-color($box-shadow-color) {
          $is-box-shadow-valid: false;

          @warn '`box-shadow color: #{$box-shadow-color}` is not a valid css color value';
        }
      }

      $box-shadow-inset: get($box-shadow, inset);

      @if $is-box-shadow-valid {
        @if is-string($box-shadow-inset) and $box-shadow-inset !=inset {
          $is-box-shadow-valid: false;

          @warn '`box-shadow inset: #{$box-shadow-inset}` is not a valid css inset value';
        }
      }

      @return $is-box-shadow-valid;
    }
  }

  @return false;
}

/// Checks if a list is a box-shadow values list (e.g. `0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000`)
///
/// @access public
/// @param {array | list} $box-shadows - the box-shadow values list
/// @return {boolean} - true if is box-shadow values list
@function is-box-shadows($box-shadows) {
  @if is-defined($box-shadows) {
    $is-box-shadows-valid: true;

    @each $box-shadow in $box-shadows {
      @if $is-box-shadows-valid {
        $is-box-shadows-valid: is-box-shadow($box-shadow);
      }
    }

    @return $is-box-shadows-valid;
  }

  @return false;
}

/// Box shadow mixin
///
/// @example scss - Usage
///   .box-shadow-element {
///     @include box-shadow(0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000);
///   }
///
/// @example css - Output
///   .box-shadow-element {
///     -webkit-box-shadow: 0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000;
///     -moz-box-shadow: 0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000;
///     -ms-box-shadow: 0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000;
///     -o-box-shadow: 0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000;
///     box-shadow: 0 2px 0 0 #dcffa6 inset, 0 2px 5px 0 #000;
///   }
/// @access public
/// @param {shadow} $box-shadows... - the box shadows list
@mixin box-shadow($box-shadows...) {
  @if list-separator($box-shadows) != comma {
    $box-shadows: ($box-shadows,);
  }

  @if is-box-shadows($box-shadows) {
    @include prefixer(box-shadow, $box-shadows);
  }
  @else {
    @warn '`box-shadow: #{$box-shadows}` one or more are not valid css box-shadow values';
  }
}

/// Z-index modes
///
/// @access private
/// @type list
$z-index-modes: array-concat((auto), $css-default-modes);

/// Checks if something is z-index value
///
/// @access public
/// @param {integer | string} $zi - the z-index value
/// @return {boolean} - true if is z-index value
@function is-z-index($zi) {
  @return is-defined($zi) and (is-integer($zi) or array-contains($z-index-modes, $zi));
}

/// Z-index mixin
///
/// @example scss - Usage
///   .z-index-element {
///     @include z-index(1);
///   }
///
/// @example css - Output
///   .z-index-element {
///     z-index: 1;
///   }
/// @access public
/// @param {integer | string} $zi - the z-index
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin z-index($zi, $important: false) {
  @if(is-z-index($zi)) {
    z-index: $zi important($important);
  }
  @else {
    @warn '`z-index: #{$zi}` is not a valid z-index value';
  }
}

/// Visibility modes
///
/// @access private
/// @type list
$visibility-modes: array-concat((visible, hidden, collapse), $css-default-modes);

/// Checks if something is supported visibility mode
///
/// @access public
/// @param {string} $vm - the visibility mode
/// @return {boolean} - true if is visibility mode
@function is-visibility($vm) {
  @return is-defined($vm) and array-contains($visibility-modes, $vm);
}

/// Visibility mixin
///
/// @example scss - Usage
///   .visibility-element {
///     @include visibility(hidden);
///   }
///
/// @example css - Output
///   .visibility-element {
///     visibility: hidden;
///   }
/// @access public
/// @param {string} $v - the visibility
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin visibility($v, $important: false) {
  @if(is-visibility($v)) {
    visibility: $v important($important);
  }
  @else {
    @warn '`visibility: #{$zi}` is not a valid visibility value';
  }
}

/// Backface visibility modes
///
/// @access private
/// @type list
$backface-visibility-modes: array-concat((visible, hidden), $css-default-modes);

/// Checks if something is supported backface-visibility mode
///
/// @access public
/// @param {string} $bv - the backface-visibility mode
/// @return {boolean} - true if is backface-visibility mode
@function is-backface-visibility($bv) {
  @return is-defined($bv) and array-contains($backface-visibility-modes, $bv);
}

/// Backface visibility mixin
///
/// @example scss - Usage
///   .backface-visibility-element {
///     @include backface-visibility(visible);
///   }
///
/// @example css - Output
///   .backface-visibility-element {
///     -webkit-backface-visibility: visible;
///     -moz-backface-visibility: visible;
///     -ms-backface-visibility: visible;
///     -o-backface-visibility: visible;
///     backface-visibility: visible;
///   }
/// @access public
/// @param {string} $bv - the backface visibility
/// @param {boolean} $important [false] - if true, will render the important rule
@mixin backface-visibility($bv, $important: false) {
  @if is-backface-visibility($bv) {
    @include prefixer(backface-visibility, $bv, null, $important);
  }
  @else {
    @warn '`backface-visibility: #{$bv}` is not a valid backface-visibility value';
  }
}

/// Returns the aspect-ratio-factor in percentage for the aspect-ratio padding-top
///
/// @access public
/// @param {integer | size} $width [1] - desired width for aspect ratio calculation
/// @param {integer | size} $height [1] - desired height for aspect ratio calculation
/// @return {percentage} - the calculated percentage of the aspect-ratio-factor
@function aspect-ratio-factor($width, $height) {
  @return (strip-unit($height) / strip-unit($width)) * 100%;
}

/// Aspect ratio mixin
///
/// @example scss - Usage
///   .aspect-ratio-element {
///     @include aspect-ratio(170px, 20px);
///   }
///
/// @example css - Output
///   .aspect-ratio-element {
///     position: relative;
///     display: inline-block; // so you can use text align to align the element
///
///     &:before {
///       display: inline-block;
///       width: 100%;
///       padding-top: 11,764705882352941%; // = 20 / 170 * 100%
///       content: '';
///     }
///
///     > .content {
///       position: absolute;
///       display: inline-block;
///       top: 0;
///       right: 0;
///       bottom: 0;
///       left: 0;
///       width: 100%;
///       height: 100%;
///     }
///   }
/// @requires {function} strip-unit
/// @requires {mixin} box-size
/// @requires {mixin} display
/// @access public
/// @param {integer | size} $width [1] - desired width for aspect ratio calculation
/// @param {integer | size} $height [1] - desired height for aspect ratio calculation
/// @param {integer | size} $content-selector ['.content'] - desired content selector
@mixin aspect-ratio($width, $height, $content-selector: '.content') {
  @if (unit($height)==unit($width)) {
    @include position(relative);
    @include display(inline-block);

    &:before {
      @include display(inline-block);
      @include box-size(100%, false);
      @include padding(aspect-ratio-factor($width, $height) null null null);

      content: '';
    }

    > #{$content-selector} {
      @include position(absolute 0 0 0 0);
      @include display(inline-block);
      @include box-size(100%);
    }
  }
  @else {
    @warn '`$width: #{$width}` and `$height: #{$height}` should have the same measure unit';
  }
}
