// Foundation for Sites by ZURB
// foundation.zurb.com
// Licensed under MIT Open Source

////
/// @group off-canvas
////

/// Width map of a left/right off-canvas panel.
/// @type Map
$offcanvas-sizes: (
  small: 250px,
) !default;

/// Height map of a top/bottom off-canvas panel.
/// @type Map
$offcanvas-vertical-sizes: (
  small: 250px,
) !default;

/// Background color of an off-canvas panel.
/// @type Color
$offcanvas-background: $light-gray !default;

/// Box shadow for the off-canvas overlap panel.
/// @type Shadow
$offcanvas-shadow: 0 0 10px rgba($black, 0.7) !default;

/// Inner box shadow size for the off-canvas push panel.
/// @type Number
$offcanvas-inner-shadow-size: 20px !default;

/// Inner box shadow color for the off-canvas push panel.
/// @type Color
$offcanvas-inner-shadow-color: rgba($black, 0.25) !default;

/// Z-index of an off-canvas content overlay.
/// @type Number
$offcanvas-overlay-zindex: 11 !default;

/// Z-index of an off-canvas panel with the `push` transition.
/// @type Number
$offcanvas-push-zindex: 12 !default;

/// Z-index of an off-canvas panel with the `overlap` transition.
/// @type Number
$offcanvas-overlap-zindex: 13 !default;

/// Z-index of an off-canvas panel using the `reveal-for-*` classes or mixin.
/// @type Number
$offcanvas-reveal-zindex: 12 !default;

/// Length of the animation on an off-canvas panel.
/// @type Number
$offcanvas-transition-length: 0.5s !default;

/// Timing function of the animation on an off-canvas panel.
/// @type Keyword
$offcanvas-transition-timing: ease !default;

/// If `true`, a revealed off-canvas will be fixed-position, and scroll with the screen.
/// @type Bool
$offcanvas-fixed-reveal: true !default;

/// Background color for the overlay that appears when an off-canvas panel is open.
/// @type Color
$offcanvas-exit-background: rgba($white, 0.25) !default;

/// CSS class used for the main content area. The off-canvas mixins use this to target the page content.
$maincontent-class: 'off-canvas-content' !default;

/// Adds baseline styles for off-canvas. This CSS is required to make the other pieces work.
@mixin off-canvas-basics {

  /// Transform deprecated size settings into map & show warning
  @if variable-exists(offcanvas-size) {
    $offcanvas-sizes: (small: $offcanvas-size, medium: $offcanvas-size) !global;
    @warn '$offcanvas-size is deprecated and not used anymore! Please update your settings and use the map $offcanvas-sizes instead';
  }
  @if variable-exists(offcanvas-vertical-size) {
    $offcanvas-vertical-sizes: (small: $offcanvas-vertical-size, medium: $offcanvas-vertical-size) !global;
    @warn '$offcanvas-vertical-size is deprecated and not used anymore! Please update your settings and use the map $offcanvas-vertical-sizes instead';
  }

  // Checks the z-indexes and increase them due to backwards compatibility.
  // This is necessary because the overlay's z-index is new since v6.4 and may be identical to the user custom settings of the push z-index.
  @if $offcanvas-push-zindex <= $offcanvas-overlay-zindex { $offcanvas-push-zindex: $offcanvas-overlay-zindex + 1 !global; }
  @if $offcanvas-overlap-zindex <= $offcanvas-push-zindex { $offcanvas-overlap-zindex: $offcanvas-push-zindex + 1 !global; }
  @if $offcanvas-reveal-zindex <= $offcanvas-overlay-zindex { $offcanvas-reveal-zindex: $offcanvas-overlay-zindex + 1 !global; }

  // Hides overflow on body when an off-canvas panel is open.
  .is-off-canvas-open {
    overflow: hidden;
  }

  // Off-canvas overlay (generated by JavaScript)
  .js-off-canvas-overlay {
    position: absolute;
    top: 0;
    left: 0;
    z-index: $offcanvas-overlay-zindex;

    width: 100%;
    height: 100%;

    transition: opacity $offcanvas-transition-length $offcanvas-transition-timing, visibility $offcanvas-transition-length $offcanvas-transition-timing;

    background: $offcanvas-exit-background;

    opacity: 0;
    visibility: hidden;

    overflow: hidden;

    &.is-visible {
      opacity: 1;
      visibility: visible;
    }

    &.is-closable {
      cursor: pointer;
    }

    &.is-overlay-absolute {
      position: absolute;
    }

    &.is-overlay-fixed {
      position: fixed;
    }
  }
}

// Adds basic styles for an off-canvas wrapper.
@mixin off-canvas-wrapper() {
  position: relative;
  overflow: hidden;
}

/// Adds basic styles for an off-canvas panel.
@mixin off-canvas-base(
  $background: $offcanvas-background,
  $transition: $offcanvas-transition-length $offcanvas-transition-timing,
  $fixed: true
) {
  @include disable-mouse-outline;

  @if $fixed == true {
    position: fixed;
  }
  @else {
    position: absolute;
  }

  // Set the off-canvas z-index.
  z-index: $offcanvas-push-zindex;

  // Increase CSS specificity
  &.is-transition-push {
    z-index: $offcanvas-push-zindex;
  }

  transition: transform $transition;
  backface-visibility: hidden;

  background: $background;

  // Hide inactive off-canvas within the content that have the same position
  &.is-closed {
    visibility: hidden;
  }

  // Overlap only styles.
  &.is-transition-overlap {
    z-index: $offcanvas-overlap-zindex;

    &.is-open {
      box-shadow: $offcanvas-shadow;
    }
  }

  // Sets transform to 0 to show an off-canvas panel.
  &.is-open {
    transform: translate(0, 0);
  }
}

/// Adds styles to position an off-canvas panel to the left/right/top/bottom.
@mixin off-canvas-position(
  $position: left,
  $orientation: horizontal,
  $sizes: if($orientation == horizontal, $offcanvas-sizes, $offcanvas-vertical-sizes)
) {
  @if $position == left {
    top: 0;
    left: 0;
    height: 100%;
    overflow-y: auto;

    @each $name, $size in $sizes {
      @include breakpoint($name) {
        width: $size;
        transform: translateX(-$size);
      }
    }

    // Sets the position for nested off-canvas element
    @at-root .#{$maincontent-class} .off-canvas.position-#{$position} {

      @each $name, $size in $sizes {
        @include breakpoint($name) {
          transform: translateX(-$size);
        }
      }
      &.is-transition-overlap.is-open {
        transform: translate(0, 0);
      }
    }

    // Sets the open position for the content
    @at-root .#{$maincontent-class}.is-open-#{$position} {
      &.has-transition-push {
        @each $name, $size in $sizes {
          @include breakpoint($name) {
            transform: translateX($size);
          }
        }
      }
    }
  }
  @else if $position == right {
    top: 0;
    right: 0;
    height: 100%;
    overflow-y: auto;

    @each $name, $size in $sizes {
      @include breakpoint($name) {
        width: $size;
        transform: translateX($size);
      }
    }

    // Sets the position for nested off-canvas element
    @at-root .#{$maincontent-class} .off-canvas.position-#{$position} {

      @each $name, $size in $sizes {
        @include breakpoint($name) {
          transform: translateX($size);
        }
      }
      &.is-transition-overlap.is-open {
        transform: translate(0, 0);
      }
    }

    // Sets the open position for the content
    @at-root .#{$maincontent-class}.is-open-#{$position} {
      &.has-transition-push {
        @each $name, $size in $sizes {
          @include breakpoint($name) {
            transform: translateX(-$size);
          }
        }
      }
    }
  }
  @else if $position == top {
    top: 0;
    left: 0;
    width: 100%;
    overflow-x: auto;

    @each $name, $size in $sizes {
      @include breakpoint($name) {
        height: $size;
        transform: translateY(-$size);
      }
    }

    // Sets the position for nested off-canvas element
    @at-root .#{$maincontent-class} .off-canvas.position-#{$position} {
      @each $name, $size in $sizes {
        @include breakpoint($name) {
          transform: translateY(-$size);
        }
      }
      &.is-transition-overlap.is-open {
        transform: translate(0, 0);
      }
    }

    // Sets the open position for the content
    @at-root .#{$maincontent-class}.is-open-#{$position} {
      &.has-transition-push {
        @each $name, $size in $sizes {
          @include breakpoint($name) {
            transform: translateY($size);
          }
        }
      }
    }
  }
  @else if $position == bottom {
    bottom: 0;
    left: 0;
    width: 100%;
    overflow-x: auto;

    @each $name, $size in $sizes {
      @include breakpoint($name) {
        height: $size;
        transform: translateY($size);
      }
    }

    // Sets the position for nested off-canvas element
    @at-root .#{$maincontent-class} .off-canvas.position-#{$position} {
      @each $name, $size in $sizes {
        @include breakpoint($name) {
          transform: translateY($size);
        }
      }
      &.is-transition-overlap.is-open {
        transform: translate(0, 0);
      }
    }

    // Sets the open position for the content
    @at-root .#{$maincontent-class}.is-open-#{$position} {
      &.has-transition-push {
        @each $name, $size in $sizes {
          @include breakpoint($name) {
            transform: translateY(-$size);
          }
        }
      }
    }
  }

  // If $offcanvas-inner-shadow-size is set, add inner box-shadow.
  // This mimics the off-canvas panel having a lower z-index, without having to have one.
  @if $offcanvas-inner-shadow-size {
    &.is-transition-push {
      @if $position == left {
        @include inner-side-shadow(right, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color);
      }
      @else if $position == right {
        @include inner-side-shadow(left, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color);
      }
      @else if $position == top {
        @include inner-side-shadow(bottom, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color);
      }
      @else if $position == bottom {
        @include inner-side-shadow(top, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color);
      }
    }
  }

}

/// Sets the styles for the content container.
@mixin off-canvas-content() {
  transform: none;
  backface-visibility: hidden;

  // Bind to has-transition-X class to prevent transition for transform:none
  &.has-transition-overlap,
  &.has-transition-push {
    transition: transform $offcanvas-transition-length $offcanvas-transition-timing;
  }

  // Transform scope until the element is closed (makes sure transitionend gets triggered)
  &.has-transition-push {
    transform: translate(0, 0);
  }

  // Consider element & content, nested in another content
  .off-canvas.is-open {
    transform: translate(0, 0);
  }
}

/// Adds styles that reveal an off-canvas panel.
@mixin off-canvas-reveal(
$position: left,
$zindex: $offcanvas-reveal-zindex,
$content: $maincontent-class,
$breakpoint: small
) {
  transform: none;
  z-index: $zindex;
  transition: none;
  visibility: visible;

  @if not $offcanvas-fixed-reveal {
    position: absolute;
  }

  .close-button {
    display: none;
  }

  // Consider revealed element is nested in content
  .#{$maincontent-class} & {
    transform: none;
  }

  @at-root .#{$content}.has-reveal-#{$position} {
    margin-#{$position}: -zf-get-bp-val($offcanvas-sizes, $breakpoint);
  }

  // backwards compatibility (prior to v6.4)
  & ~ .#{$content} {
    margin-#{$position}: -zf-get-bp-val($offcanvas-sizes, $breakpoint);
  }
}

/// Overrides the off-canvas styles
@mixin in-canvas() {
  visibility: visible;
  height: auto;
  position: static;
  background: none;
  width: auto;
  overflow: visible;
  transition: none;

  // Increase CSS specificity
  &.position-left,
  &.position-right,
  &.position-top,
  &.position-bottom {
    box-shadow: none;
    transform: none;
  }

  .close-button {
    display: none;
  }
}

@mixin foundation-off-canvas {
  @include off-canvas-basics;

  // Off-canvas wrapper
  .off-canvas-wrapper {
    @include off-canvas-wrapper;
  }

  // Off-canvas container
  .off-canvas {
    @include off-canvas-base;

    // Force position absolute for nested off-canvas because fixed doesn't work for push transition within the transform scope.
    @at-root .#{$maincontent-class} & {
      // NOTE: since overlap transition is currently forced if nested, there's no need to force position absolute until nested push transition is supported.
      // position: absolute;
    }
  }

  // Off-canvas container with absolute position
  .off-canvas-absolute {
    @include off-canvas-base($fixed: false);
  }

  // Off-canvas position classes
  .position-left    { @include off-canvas-position(left,   horizontal); }
  .position-right   { @include off-canvas-position(right,  horizontal); }
  .position-top     { @include off-canvas-position(top,    vertical); }
  .position-bottom  { @include off-canvas-position(bottom, vertical); }

  .off-canvas-content {
    @include off-canvas-content;
  }

  // Reveal off-canvas panel on larger screens
  @each $name, $value in $breakpoint-classes {
    @if $name != $-zf-zero-breakpoint {
      @include breakpoint($name) {
        .position-left.reveal-for-#{$name} {
          @include off-canvas-reveal(left, $offcanvas-reveal-zindex, $maincontent-class, $name);
        }

        .position-right.reveal-for-#{$name} {
          @include off-canvas-reveal(right, $offcanvas-reveal-zindex, $maincontent-class, $name);
        }

        .position-top.reveal-for-#{$name} {
          @include off-canvas-reveal(top, $offcanvas-reveal-zindex, $maincontent-class, $name);
        }

        .position-bottom.reveal-for-#{$name} {
          @include off-canvas-reveal(bottom, $offcanvas-reveal-zindex, $maincontent-class, $name);
        }
      }
    }
  }

  // Move in-canvas for larger screens
  @each $name, $value in $breakpoint-classes {
    @if $name != $-zf-zero-breakpoint {
      @include breakpoint($name) {
        .off-canvas.in-canvas-for-#{$name} {
          @include in-canvas;
        }
      }
    }
  }
}

