$default-browser-font-size: 16px;
$base-font-size: 10px;

/// Returns the value in rem for a given pixel value.
/// @param {Number} $value - The pixel value to be converted.
/// @return {Number} The converted value in rem.

@function rem($value) {
  $unit: unit($value);

  @if $value == 0 {
    @return 0;
  } @else if $unit == 'rem' {
    @return $value;
  } @else if $unit == 'px' {
    @return $value / $base-font-size * 1rem;
  } @else if $unit == 'em' {
    @return $unit / 1em * 1rem;
  } @else {
    @error 'Value must be in px, em, or rem.';
  }
}

/// Returns the value in pixels for a given rem value.
/// @param {Number} $value - The rem value to be converted.
/// @return {Number} The converted value in pixels.

@function px($value) {
  $unit: unit($value);

  @if $value == 0 {
    @return 0;
  } @else if $unit == 'px' {
    @return $value;
  } @else if $unit == 'em' {
    @return ($value / 1em) * $base-font-size;
  } @else if $unit == 'rem' {
    @return ($value / 1rem) * $base-font-size;
  } @else {
    @error 'Value must be in rem, em, or px.';
  }
}

/// Returns the value in ems for a given pixel value. Note that this
/// only works for elements that have had no font-size changes.
/// @param {Number} $value - The pixel value to be converted.
/// @return {Number} The converted value in ems.

@function em($value) {
  $unit: unit($value);

  @if $value == 0 {
    @return 0;
  } @else if $unit == 'em' {
    @return $value;
  } @else if $unit == 'rem' {
    @return $value / 1rem * 1em * ($base-font-size / $default-browser-font-size);
  } @else if $unit == 'px' {
    @return $value / $default-browser-font-size * 1em;
  } @else {
    @error 'Value must be in px, rem, or em.';
  }
}

/// Returns the list of available names in a given map.
/// @param {Map} $map - The map of data to list the names from.
/// @param {Number} $map - The level of depth to get names from.
/// @return {String} The list of names in the map.

@function available-names($map, $level: 1) {
  @if type-of($map) != 'map' {
    @return null;
  }

  $output: '';
  $newline: '\A ';

  @if $level == 1 {
    @each $key, $value in $map {
      $output: $output +
        '#{$newline}- #{$key} #{available-names($value, $level + 1)}';
    }
  } @else {
    $output: '(';
    $i: 1;

    @each $key, $value in $map {
      $sep: if($i < length($map), ', ', '');
      $output: $output + '#{$key}#{$sep}#{available-names($value, $level + 1)}';
      $i: $i + 1;
    }

    $output: $output + ')';
  }

  @return $output;
}

// Merge multiple maps into one.
// @param {Map} $map - Initial default map.
// @param {ArgList} $maps - Other maps to merge.
// @return {Map} The final merged map.
@function map-extend($map, $maps...) {
  @for $i from 1 through length($maps) {
    @each $key, $value in nth($maps, $i) {
      $map: map-merge(
        $map,
        (
          $key: $value,
        )
      );

      @if (type-of($value) == map) and (type-of(map-get($map, $key)) == map) {
        $value: map-extend(map-get($map, $key), $value);
      }
    }
  }

  @return $map;
}
