@charset "UTF-8";
/***
 *                                 /$$$$$$  /$$
 *                                /$$__  $$|__/
 *      ______ _       _     _   | $$  \__/ /$$ /$$$$$$$$  /$$$$$$
 *     |  ____| |     (_)   | |  |  $$$$$$ | $$|____ /$$/ /$$__  $$
 *     | |___ | |_   _ _  __| |  \____  $$| $$   /$$$$/ | $$$$$$$$
 *     |  ___|| | | | | |/ _` |   /$$  \ $$| $$  /$$__/  | $$_____/
 *     | |    | | |_| | | (_| |  |  $$$$$$/| $$ /$$$$$$$$|  $$$$$$$
 *     |_|    |_|\__,_|_|\__,_|  \______/ |__/|________/ \_______/
 *
 **/
@import 'break-points';
@import '~include-media/dist/include-media';
@import '~mathsass/dist/math';
@import '~sass-unitconverter/unitconverter';
@import 'utils';
@import 'others';
@import 'options';

// ** Fluid Size ***************************************************************
$FIRST-KEY:   default !default;
$FIRST-BREAK: 0px     !default;

@function zip-responsive() {
  @return zip(
    map-values($screen-distances), map-values($screen-sizes      ),
    map-values($breakpoints     ), map-values($breakpoints-height)
  );
}

// == Fit Size =================================================================
// Based on Theory
// https://github.com/black7375/Fluid-Size/wiki/The-theory-of-font-size-and-readability
@function calc-ppi($screen-width, $screen-height, $screen-size) {
  @return sqrt(pow($screen-width, 2) + pow($screen-height, 2)) / $screen-size;
}

// -- Measure Angle ------------------------------------------------------------
@function calc-dependency($value) {
  $screen-distance: nth($value, 1) * 100;
  $screen-size:     nth($value, 2);
  $screen-width:    num(nth($value, 3));
  $screen-height:   num(nth($value, 4));

  $ppi: calc-ppi($screen-width, $screen-height, $screen-size);
  $dependent-value: $screen-distance * $ppi;
  @return $dependent-value;
}

@function calc-angle($size, $options) {
  // String, Color value passing(Ex. !important, black, white, #111111 ...ETC)
  @if not is-calcable($size) {
    @return if(is-num($size), #{$size}num, $size);
  }

  $size:   num(px($size));
  $device: get-option($options, device);
  $target: null;

  @if contain('min' 'max', $device) { // Will look min/max
    $values:   zip-responsive();
    @each $value in $values {
      $dependent-value: calc-dependency($value);

      @if $device == 'min' {
        @if (($target == null) or ($target > $dependent-value)) {
          $target: $dependent-value;
        }
      }
      @if $device == 'max' {
        @if (($target == null) or ($target < $dependent-value)) {
          $target: $dependent-value;
        }
      }
    }
  }
  @else { // based on Device's Key
    $value: list(map-get($screen-distances, $device), map-get($screen-sizes,       $device),
                 map-get($breakpoints,      $device), map-get($breakpoints-height, $device));
    $target: calc-dependency($value);
  }

  $angle: $size * 54 / $target;
  $visual-angle: atan($angle) * (10800 / $PI);
  @return count-round($visual-angle, 2);
}
@function calc-angles($sizes, $options) {
  $angles: ();
  @each $size in $sizes {
    $angles: append($angles, calc-angle($size, $options));
  }
  @return $angles;
}

// -- Generate Fit Size --------------------------------------------------------
@function convert-visual($visual-angle) {
  // if origin $size type is num
  // => ${$size}num
  // Return it to its original type.
  @if is-str($visual-angle) {
    $str-start: str-length($visual-angle) - 2;
    $is-number: str-slice($visual-angle, $str-start) == "num";
    @return if($is-number, num($visual-angle), $visual-angle);
  }
  @else {
    @return $visual-angle;
  }
}

// Calc Fit Size
@function calc-size($visual-angle) {
  $check:       is-num($visual-angle);
  $values:      zip-responsive();
  $break-sizes: ();

  @each $value in $values {
    @if $check { // If Calc able
      $screen-distance: nth($value, 1) * 100;
      $screen-size:     nth($value, 2);
      $screen-width:    num(nth($value, 3));
      $screen-height:   num(nth($value, 4));

      $ppi: calc-ppi($screen-width, $screen-height, $screen-size);
      $angle: tan($PI * $visual-angle / 10800);
      $size: $screen-distance * $angle * $ppi / 54;

      $size: px($size, (callback: null));
      $break-sizes: append($break-sizes, ($size));
    }
    @else { // Can't Calc: passed
      $visual-angle: convert-visual($visual-angle);
      $break-sizes: append($break-sizes, ($visual-angle));
    }
  }

  @return $break-sizes;
}

@function fit-size($sizes, $options: empty-map()) {
  // Each Fit Size
  $visual-angle: calc-angles($sizes, $options);
  $scaled-sizes: map($visual-angle, calc-size, $separator: comma);

  @return if(is-list($sizes), call(zip, $scaled-sizes...), $scaled-sizes);
}

// == Fluid ====================================================================
@function size-break($function, $fluid-unit, $now-sizes, $next-sizes,
                     $now-break, $next-break, $max-size: null) {
  // unit convert
  $now-sizes:  to-unit-data($now-sizes,  $fluid-unit);
  $next-sizes: to-unit-data($next-sizes, $fluid-unit);
  $now-break:  to-unit-data($now-break,  $fluid-unit);
  $next-break: to-unit-data($next-break, $fluid-unit);
  $max-size:   to-unit-data($max-size,   $fluid-unit);

  // Each function args
  $check-function: $function == 'fluid-size';
  $args: if($check-function,
            list($now-sizes, $next-sizes, $now-break, $next-break),
            list($now-sizes, $next-sizes, $max-size,  $now-break, $next-break));

  // Mapping
  $results: ();
  $each-sizes: zip($now-sizes, $next-sizes);
  @each $start-size, $end-size in $each-sizes {
    $result: null;
    @if is-len($start-size) and is-len($end-size) {
      $args: replace-nth($args, 1, $start-size);
      $args: replace-nth($args, 2, $end-size  );

      $result: map($args, $function, 'list');
    }
    @else {
      $result: if($check-function, $start-size, $next-break);
    }
    $results: append($results, $result);
  }
  @return $results;
}

// -- Option::Mode -------------------------------------------------------------
// -- Mode: Fluid --
// https://www.madebymike.com.au/writing/fluid-type-calc-examples/
@function fluid-rate($start-size, $end-size, $min-screen, $max-screen) {
  @return ($end-size - $start-size) / ($max-screen - $min-screen);
}
@function fluid-basic-size($start-size, $min-screen, $rate) {
  @return $start-size - $rate * $min-screen;
}

@function fluid-size($start-size, $end-size, $min-screen, $max-screen) {
  @if $start-size == $end-size {
    @return $start-size;
  }
  // Get based values
  $rate: fluid-rate($start-size, $end-size, $min-screen, $max-screen);
  $basic-size: fluid-basic-size($start-size, $min-screen, $rate);

  // Decide Sign
  $sign: "+";
  @if ($basic-size < 0) {
    $sign: "-";
    $basic-size: abs($basic-size);
  }

  // Conbine
  @return calc(#{$rate*100}vw #{$sign} #{$basic-size});
}
@function fluid-sizes($now-sizes, $next-sizes, $now-break, $next-break, $fluid-unit: px) {
  $fluid-sizes: size-break(fluid-size, $fluid-unit,
                           $now-sizes, $next-sizes, $now-break, $next-break);
  @return $fluid-sizes;
}

// -- Mode: VW-Only --
@function vw-sizes($now-sizes, $now-break) {
  @return to-unit-data($now-sizes, vw, (width: $now-break));
}

// -- Option::Limit ------------------------------------------------------------
// -- Limit with Mode --
@function fluid-limit-break($start-size, $end-size, $max-size,
                            $min-screen, $max-screen) {
  @if($start-size == $end-size) {
    @return $min-screen;
  }
  // Simulate Fluid Size
  $rate: fluid-rate($start-size, $end-size, $min-screen, $max-screen);
  $basic-size: fluid-basic-size($start-size, $min-screen, $rate);

  // Calc Limit Point
  $limit-break: ($max-size - $basic-size) / $rate;
  $limit-break: count-round($limit-break, 1);
  @return if($limit-break <= 0px, 0px, $limit-break);
}
@function fluid-limit-breaks($now-sizes, $next-sizes, $max-size,
                             $now-break, $next-break, $fluid-unit: px) {
  $limit-breaks: size-break(fluid-limit-break, $fluid-unit,
                            $now-sizes, $next-sizes, $now-break, $next-break, $max-size);
  @return $limit-breaks;
}

@function vw-limit-break($now-vw, $max-size) {
  $now-vw:   num($now-vw);
  $max-size: px($max-size);

  // Calc Limit Point
  $limit-break: ($max-size / $now-vw) * 100;
  $limit-break: count-round($limit-break, 1);
  @return if($limit-break <= 0px, 0px, $limit-break);
}
@function vw-limit-breaks($now-sizes, $max-size, $now-break, $next-break) {
  $basic-sizes:  vw-sizes($now-sizes, $now-break);
  $limit-breaks: ();

  @each $basic-size in $basic-sizes {
    $limit-break: if(is-vw($basic-size) and $basic-size != 0vw,
                     vw-limit-break($basic-size, $max-size),
                     $next-break);
    $limit-breaks: append($limit-breaks, $limit-break);
  }
  @return $limit-breaks;
}

// -- Get Limit Types --
@function fluid-limit-type($first, $last, $now-break, $next-break,
                           $limit-break, $type: 'size') {
  @if $type == 'break' { // only Limit: break
    @if $first {
      @return 'pass';
    }

    @if $limit-break <= $now-break {
      @return 'substitution';
    }
    @if $now-break < $limit-break and $limit-break < $next-break {
      @return 'add';
    }
  }

  @if $last and $now-break < $limit-break { // Reach Max Size
    @return 'add';
  }
  @else {
    @return 'pass';
  }
}
@function fluid-limit-types($now-key, $last-key, $now-break, $next-break,
                            $limit-breaks, $type: 'size') {
  $first: $now-key == $FIRST-KEY;
  $last:  $now-key == $last-key;

  $limit-types: ();
  @each $limit-break in $limit-breaks {
    $limit-type:  fluid-limit-type($first, $last, $now-break, $next-break, $limit-break, $type);
    $limit-types: append($limit-types, $limit-type);
  }
  @return $limit-types;
}

// -- Limit --
@mixin fluid-add-break($property,  $next-sizes, $fluid-sizes,  $max-size,
                       $now-break, $next-break, $limit-breaks, $limit-types,
                       $class, $is-iframe, $sorted-index, $increase) {
  $decrease: not $increase;

  // now-break: increase => pass, decrease => subtitution
  @if $decrease {
    @each $i in range($limit-breaks) {
      $index: nth($sorted-index, $i);
      @if nth($limit-types, $index) == 'add' {
        $fluid-sizes: replace-size($fluid-sizes, $index, $max-size);
      }
    }
  }
  @include fluid-option-media($class, $now-break, $is-iframe) {
    #{$property}: $fluid-sizes;
  }

  // add-break: increase => subtitution, decrease => create fluid-size(max, next-size)
  $new-fluid-size: null; // only use decrease
  $prev-fluid-sizes: null;
  $break-size: length($limit-breaks);
  @each $i in range($limit-breaks) {
    $now-index:  nth($sorted-index, $i);
    $next-index: if($i < $break-size, nth($sorted-index, $i + 1), null);

    $now-type:   nth($limit-types,  $now-index);
    $now-limit:  nth($limit-breaks, $now-index);
    $next-size:  if(is-null($next-sizes), null, nth($next-sizes,   $now-index ));
    $next-limit: if(is-null($next-index), null, nth($limit-breaks, $next-index));

    // now-limit == next-limit => only substitution
    // next-limit is null || now-limit != next-limit => substitution && apply
    @if $now-type == 'add' {
      $first: $i == 1;
      $last:  is-null($next-limit);
      $continuous: $now-limit == $next-limit;

      @if $decrease and ($first or not $last or not $continuous) {
        $new-fluid-size: fluid-size($max-size, $next-size, $now-limit, $next-break);
      }

      @if $continuous {
        $subtitue-size: if($increase, $max-size, $new-fluid-size);
        $fluid-sizes: replace-size($fluid-sizes, $now-index, $subtitue-size);
      }
      @else {
        $prev-fluid-sizes: $fluid-sizes;
        $subtitue-size: if($increase, $max-size, $new-fluid-size);
        $fluid-sizes: replace-size($fluid-sizes, $now-index, $subtitue-size);

        @if $last or $fluid-sizes != $prev-fluid-sizes {
          @include fluid-option-media($class, $now-limit, $is-iframe) {
            #{$property}: $fluid-sizes;
          }
        }
      }
    }
  }
}

@mixin fluid-media-limit($property, $now-sizes, $next-sizes, $fluid-sizes,
                         $max-size, $now-break, $next-break, $limit-breaks,
                         $limit-types, $is-fluid, $class, $is-iframe) {
  $exist-sub: contain($limit-types, 'substitution');
  $exist-add: contain($limit-types, 'add');
  $sorted-index: null;
  @if (not $exist-sub) and (not $exist-add) {
    //all pass
    @include fluid-option-media($class, $now-break, $is-iframe) {
      #{$property}: $fluid-sizes;
    }
  }
  @else {
    $sorted-index: list-sort-index($limit-breaks);
  }

  // subtitution
  @if $exist-sub {
    @each $i in range($limit-breaks) {
      $index: nth($sorted-index, $i);
      @if nth($limit-types, $index) == 'substitution' {
        $fluid-sizes: replace-size($fluid-sizes, $index, $max-size);
      }
    }
    @include fluid-option-media($class, $now-break, $is-iframe) {
      #{$property}: $fluid-sizes;
    }
  }

  // add break
  @if $exist-add {
    $increase: not $is-fluid or check-sizes($now-sizes, $next-sizes);

    // increase: next-size > now-size > max-size
    // decrease: next-size > max-size > now-size

    // increase => now-break(pass),        add-break(subtitution)
    // decrease => now-break(subtitution), add-break(create fluide-size)
    @include fluid-add-break($property,  $next-sizes, $fluid-sizes,  $max-size,
                             $now-break, $next-break, $limit-breaks, $limit-types,
                             $class, $is-iframe, $sorted-index, $increase);
  }
}

// -- Option::Class ------------------------------------------------------------
@mixin fluid-class-media($fls-class, $break) {
  @if $fls-class == true {
    @include media(">=#{$break}") {
      .fluid-class &,
      &.fluid-class {
        @content;
      }
    }
  }
  @else {
    @include media(">=#{$break}") {
      @content;
    }
  }
}

// -- Option -------------------------------------------------------------------
@mixin fluid-option-media($fls-class, $break, $is-iframe) {
  @include fluid-class-media($fls-class, $break) {
    @content;

    @if $is-iframe {
      @include safari-iframe-resize-fix;
    }
  }
}


// == Medias ===================================================================
@mixin fluid-media-apply($property, $fit-sizes, $fluid-breakpoints, $i, $last-key,
                         $fluid-mode, $fluid-unit, $breakunit,
                         $min-size, $max-size, $limit, $class, $iframe-fix) {
  // Get key and Sizes
  $now-key:  map-nth($fluid-breakpoints, $i);
  $next-key: map-nth($fluid-breakpoints, $i + 1);

  $now-sizes:  map-get($fit-sizes, $now-key );
  $next-sizes: map-get($fit-sizes, $next-key);
  $now-break:  map-get($fluid-breakpoints, $now-key );
  $next-break: map-get($fluid-breakpoints, $next-key);

  $first: $now-key == $FIRST-KEY;
  $prev-key:   if($first, null, map-nth($fluid-breakpoints, $i - 1));
  $prev-sizes: if(is-null($prev-key), null, map-get($fit-sizes, $prev-key));

  // Apply Options
  $is-fit:    $fluid-mode == 'fit';
  $is-fluid:  $fluid-mode == 'fluid';
  $is-vw:     $fluid-mode == 'vw-only';
  $is-last:   if($is-fluid, $now-key == $last-key, $next-key == $last-key);
  $is-iframe: (not $is-fit) and $iframe-fix;

  @if (not is-null($min-size) or not is-null($max-size)) and
      ($is-fit                or $limit == 'size') {
    $now-sizes:  limit-sizes($now-sizes,  $min-size, $max-size);
    $next-sizes: limit-sizes($next-sizes, $min-size, $max-size);
  }

  // for fluid mode
  $limit-breaks: null;
  $limit-types:  null;
  $fluid-sizes:  null;
  @if not $is-fit and not is-null($max-size) {
    $limit-breaks: if($is-fluid,
                      fluid-limit-breaks($now-sizes,  $next-sizes, $max-size,
                                         $now-break, $next-break),
                      vw-limit-breaks($now-sizes, $max-size, $now-break, $next-break));
    $limit-types: fluid-limit-types($now-key, $last-key, $now-break, $next-break,
                                    $limit-breaks, $limit);
    $max-size: to-unit-data($max-size, $fluid-unit);
  }

  // Set size
  $now-sizes:  to-unit-data($now-sizes,  $fluid-unit);
  $next-sizes: to-unit-data($next-sizes, $fluid-unit);
  @if not $is-fit {
    $fluid-sizes: if($is-fluid,
                     fluid-sizes($now-sizes, $next-sizes, $now-break, $next-break, $fluid-unit),
                     vw-sizes($now-sizes, $now-break));
  }

  // Set Break Units
  $now-break:  to-unit-data($now-break,  $breakunit);
  $next-break: to-unit-data($next-break, $breakunit);

  // Apply Media
  $not-continuous: $now-sizes != $prev-sizes;

  @if $first {
    #{$property}: $now-sizes;
  }
  @else if not $is-fit and not is-null($max-size) and $not-continuous {
    @include fluid-media-limit($property, $now-sizes, $next-sizes, $fluid-sizes,
                               $max-size, $now-break, $next-break, $limit-breaks,
                               $limit-types, $is-fluid, $class, $is-iframe);

    @if $is-vw and $is-last and $now-sizes != $next-sizes {
      $limit-breaks: vw-limit-breaks($next-sizes, $max-size, $next-break, $next-break);
      $limit-types:  fluid-limit-types($next-key, $last-key, $next-break, $next-break,
                                       $limit-breaks, $limit);
      $fluid-sizes: vw-sizes($next-sizes, $next-break);
      $last-sizes: null;

      @include fluid-media-limit($property, $next-sizes, $last-sizes, $fluid-sizes,
                                 $max-size, $next-break, $next-break, $limit-breaks,
                                 $limit-types, $is-fluid, $class, $is-iframe);
    }
  }
  @else if $not-continuous {
    $now-values: if(not $is-fit, $fluid-sizes, $now-sizes);
    @include fluid-option-media($class, $now-break, $is-iframe) {
      #{$property}: $now-values;
    }

    // Last at fit, vw-only mode
    $next-values: if($is-fit, $next-sizes, vw-sizes($next-sizes, $next-break));
    @if not $is-fluid and $is-last and $now-sizes != $next-sizes {
      @include fluid-option-media($class, $next-break, $is-iframe) {
        #{$property}: $next-values;
      }
    }
  }
}

@mixin fluid-media($property, $devices-sizes, $options: empty-map()) {
  // Basics
  $fit-sizes:         to-unit-data($devices-sizes, px);
  $fluid-breakpoints: map-merge(($FIRST-KEY: $FIRST-BREAK), to-unit-map($breakpoints, px));
  $fluid-breakpoints: map-sort-values($fluid-breakpoints);
  @if not map-has-key($fit-sizes, $FIRST-KEY) {
    $default-map: ($FIRST-KEY: $DEAFULT-SIZE);
    $fit-sizes: map-merge($default-map, $fit-sizes);
  }
  $fluid-basics: ($property, $fit-sizes, $fluid-breakpoints);

  // Get Options
  $fluid-mode: get-option($options,  mode);
  $fluid-unit: get-option($options,  unit);
  $breakunit:  get-option($options, breakunit);
  $min-size:   get-option($options,   min);
  $max-size:   get-option($options,   max);
  $limit:      get-option($options, limit);
  $class:      get-option($options, class);
  $iframe-fix: get-option($options, iframe-fix);
  $fluid-options: ($fluid-mode, $fluid-unit, $breakunit,
                   $min-size, $max-size, $limit, $class, $iframe-fix);

  // Apply media
  $last-size: length($fluid-breakpoints) - 1;
  $last-key:  map-nth($fluid-breakpoints, if($fluid-mode == 'fluid',
                                             $last-size, $last-size + 1));
  @each $i in range($last-size) {
    $fluid-context: ($i, $last-key);
    $args: flatten($fluid-basics, $fluid-context, $fluid-options);

    @include fluid-media-apply($args...);
  }
}

// -- Wrapper --
@mixin fluid($property, $sizes, $options: empty-map(), $type: 'font') {
  // Preprocessing for $options
  @if not is-map($options) {
    $options: (max-size: $options);
  }
  @if      get-option($options, unit) == each and $type == 'font' {
    $options: map-merge($options, (unit: rem));
  }
  @else if get-option($options, unit) == each and $type ==  'box' {
    $options: map-merge($options, (unit:  px));
  }

  // Validate
  $validate-breakpoints: validate-breakpoints();
  $validate-options:     validate-options($options);

  // Set Unit Scoped Option
  $temp-root: $root-font-size;
  $temp-base: $base-font-size;
  $root-font-size: get-option($options, root-size) !global;
  $base-font-size: get-option($options, base-size) !global;

  // Single value to List processing
  @if not is-list($sizes) {
    $sizes: ($sizes, );
  }

  $fit-sizes:     fit-size($sizes, $options);
  $keys:          join($FIRST-KEY, map-keys($breakpoints));
  $values:        join(($sizes,), $fit-sizes);
  $devices-sizes: to-map($keys, $values);

  @include fluid-media($property, $devices-sizes, $options);

  // Set to Original
  $root-font-size: $temp-root !global;
  $base-font-size: $temp-base !global;
}

// == Interface ================================================================
// -- Font --
@mixin font-size($sizes, $options: empty-map()) {
  @include fluid(font-size, $sizes, $options);
}
@mixin line-height($sizes, $options: empty-map()) {
  @include fluid(line-height, $sizes, $options);
}
@mixin text-indent($sizes, $options: empty-map()) {
  @include fluid(text-indent, $sizes, $options);
}
@mixin letter-spacing($sizes, $options: empty-map()) {
  @include fluid(letter-spacing, $sizes, $options);
}
@mixin word-spacing($sizes, $options: empty-map()) {
  @include fluid(word-spacing, $sizes, $options);
}
@mixin tab-size($sizes, $options: empty-map()) {
  @include fluid(tab-size, $sizes, $options);
}

// -- Box --
@mixin width($sizes, $options: empty-map()) {
  @include fluid(width, $sizes, $options, 'box');
}
@mixin height($sizes, $options: empty-map()) {
  @include fluid(height, $sizes, $options, 'box');
}
@mixin border-width($sizes, $options: empty-map()) {
  @include fluid(border-width, $sizes, $options, 'box');
}
@mixin margin($sizes, $options: empty-map()) {
  @include fluid(margin, $sizes, $options, 'box');
}
@mixin margin-top($sizes, $options: empty-map()) {
  @include fluid(margin-top, $sizes, $options, 'box');
}
@mixin margin-bottom($sizes, $options: empty-map()) {
  @include fluid(margin-bottom, $sizes, $options, 'box');
}
@mixin margin-left($sizes, $options: empty-map()) {
  @include fluid(margin-left, $sizes, $options, 'box');
}
@mixin margin-right($sizes, $options: empty-map()) {
  @include fluid(margin-right, $sizes, $options, 'box');
}
@mixin padding($sizes, $options: empty-map()) {
  @include fluid(padding, $sizes, $options, 'box');
}
@mixin padding-top($sizes, $options: empty-map()) {
  @include fluid(padding-top, $sizes, $options, 'box');
}
@mixin padding-bottom($sizes, $options: empty-map()) {
  @include fluid(padding-bottom, $sizes, $options, 'box');
}
@mixin padding-left($sizes, $options: empty-map()) {
  @include fluid(padding-left, $sizes, $options, 'box');
}
@mixin padding-right($sizes, $options: empty-map()) {
  @include fluid(padding-right, $sizes, $options, 'box');
}
