// Bootstrap Grid v4 Mixins

@mixin clearfix() {
	&::after {
		content: "";
		display: table;
		clear: both;
	}
}

// Breakpoint viewport sizes and media queries.
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
//    (xs: 0, sm: 576px, md: 768px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.

// Name of the next breakpoint, or null for the last breakpoint.
//
//    >> breakpoint-next(sm)
//    md
//    >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px))
//    md
//    >> breakpoint-next(sm, $breakpoint-names: (xs sm md))
//    md
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
	$n: index($breakpoint-names, $name);
	@return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}

// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
//    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px))
//    576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
	$min: map-get($breakpoints, $name);
	@return if($min != 0, $min, null);
}

// Maximum breakpoint width. Null for the largest (last) breakpoint.
// The maximum value is calculated as the minimum of the next one less 0.1.
//
//    >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px))
//    767px
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
	$next: breakpoint-next($name, $breakpoints);
	@return if($next, breakpoint-min($next, $breakpoints) - 1px, null);
}

// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront.
// Useful for making responsive utilities.
//
//    >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px))
//    ""  (Returns a blank string)
//    >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px))
//    "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
	@return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}

// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
// Makes the @content apply to the given breakpoint and wider.
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
	$min: breakpoint-min($name, $breakpoints);
	@if $min {
		@media (min-width: $min) {
			@content;
		}
	} @else {
		@content;
	}
}

// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
// Makes the @content apply to the given breakpoint and narrower.
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
	$max: breakpoint-max($name, $breakpoints);
	@if $max {
		@media (max-width: $max) {
			@content;
		}
	} @else {
		@content;
	}
}

// Media that spans multiple breakpoint widths.
// Makes the @content apply between the min and max breakpoints
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
	@include media-breakpoint-up($lower, $breakpoints) {
		@include media-breakpoint-down($upper, $breakpoints) {
			@content;
		}
	}
}

// Media between the breakpoint's minimum and maximum widths.
// No minimum for the smallest breakpoint, and no maximum for the largest one.
// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.
@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
	@include media-breakpoint-between($name, $name, $breakpoints) {
		@content;
	}
}

// Framework grid generation
//
// Used only by Bootstrap to generate the correct number of grid classes given
// any value of `$grid-columns`.

@mixin make-grid-columns($columns: $grid-columns, $gutters: $grid-gutter-widths, $breakpoints: $grid-breakpoints) {
	// Common properties for all breakpoints
	%grid-column {
		position: relative;
		width: 100%;
		min-height: 1px; // Prevent columns from collapsing when empty

		@include make-gutters($gutters);
	}

	@each $breakpoint in map-keys($breakpoints) {
		$infix: breakpoint-infix($breakpoint, $breakpoints);

		// Allow columns to stretch full width below their breakpoints
		@for $i from 1 through $columns {
			.col#{$infix}-#{$i} {
				@extend %grid-column;
			}
		}
		.col#{$infix} {
			@extend %grid-column;
		}

		@include media-breakpoint-up($breakpoint, $breakpoints) {
			// Provide basic `.col-{bp}` classes for equal-width flexbox columns
			.col#{$infix} {
				flex-basis: 0;
				flex-grow: 1;
				max-width: 100%;
			}
			.col#{$infix}-auto {
				flex: 0 0 auto;
				width: auto;
			}

			@for $i from 1 through $columns {
				.col#{$infix}-#{$i} {
					@include make-col($i, $columns);
				}
			}

			@each $modifier in (pull, push) {
				@for $i from 0 through $columns {
					.#{$modifier}#{$infix}-#{$i} {
						@include make-col-modifier($modifier, $i, $columns)
					}
				}
			}

			// `$columns - 1` because offsetting by the width of an entire row isn't possible
			@for $i from 0 through ($columns - 1) {
				@if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-xs-0
					.offset#{$infix}-#{$i} {
						@include make-col-modifier(offset, $i, $columns)
					}
				}
			}
		}
	}
}

/// Grid system
//
// Generate semantic grid columns with these mixins.

@mixin make-container($gutters: $grid-gutter-widths) {
	position: relative;
	margin-left: auto;
	margin-right: auto;

	@each $breakpoint in map-keys($gutters) {
		@include media-breakpoint-up($breakpoint) {
			$gutter: map-get($gutters, $breakpoint);
			padding-right: calc($gutter / 2);
			padding-left: calc($gutter / 2);
		}
	}
}

// For each breakpoint, define the maximum width of the container in a media query
@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) {
	@each $breakpoint, $container-max-width in $max-widths {
		@include media-breakpoint-up($breakpoint, $breakpoints) {
			width: $container-max-width;
			max-width: 100%;
		}
	}
}

@mixin make-gutters($gutters: $grid-gutter-widths) {
	@each $breakpoint in map-keys($gutters) {
		@include media-breakpoint-up($breakpoint) {
			$gutter: map-get($gutters, $breakpoint);
			padding-right: calc($gutter / 2);
			padding-left: calc($gutter / 2);
		}
	}
}

@mixin make-row($gutters: $grid-gutter-widths) {
	display: flex;
	flex-wrap: wrap;

	@each $breakpoint in map-keys($gutters) {
		@include media-breakpoint-up($breakpoint) {
			$gutter: map-get($gutters, $breakpoint);
			margin-right: calc($gutter / -2);
			margin-left: calc($gutter / -2);
		}
	}
}

@mixin make-col-ready($gutters: $grid-gutter-widths) {
	position: relative;
	// Prevent columns from becoming too narrow when at smaller grid tiers by
	// always setting `width: 100%;`. This works because we use `flex` values
	// later on to override this initial width.
	width: 100%;
	min-height: 1px; // Prevent collapsing

	@each $breakpoint in map-keys($gutters) {
		@include media-breakpoint-up($breakpoint) {
			$gutter: map-get($gutters, $breakpoint);
			padding-right: calc($gutter / 2);
			padding-left: calc($gutter / 2);
		}
	}
}

@mixin make-col($size, $columns: $grid-columns) {
	flex: 0 0 percentage(calc($size / $columns));
	// width: percentage(calc($size / $columns));
	// Add a `max-width` to ensure content within each column does not blow out
	// the width of the column. Applies to IE10+ and Firefox. Chrome and Safari
	// do not appear to require this.
	max-width: percentage(calc($size / $columns));
}

@mixin make-col-offset($size, $columns: $grid-columns) {
	margin-left: percentage(calc($size / $columns));
}

@mixin make-col-push($size, $columns: $grid-columns) {
	left: if($size > 0, percentage(calc($size / $columns)), auto);
}

@mixin make-col-pull($size, $columns: $grid-columns) {
	right: if($size > 0, percentage(calc($size / $columns)), auto);
}

@mixin make-col-modifier($type, $size, $columns) {
	// Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626)
	@if $type == push {
		@include make-col-push($size, $columns);
	} @else if $type == pull {
		@include make-col-pull($size, $columns);
	} @else if $type == offset {
		@include make-col-offset($size, $columns);
	}
}
