@use 'sass:math';
@use "sass:map";


/** === Window Sizes === */


/**
 * The max desktop width.
 */
$max-width: 1000px;

/**
 * Desktop-mode width.
 */
$desktop-width: 850px;

/**
 * Tablet-mode width.
 */
$tablet-width: 700px;

/**
 * Mobile-mode width.
 */
$mobile-width: 600px;

/**
 * The min width.
 */
$min-width: 450px;


/** === Font Sizes === */


/**
 * Default Desktop font size (in px).
 */
$desktop-em-size: 13;

/**
 * Default tablet/mobile font size (in px).
 */
$mobile-em-size: 12;


/** === Sizing Scale Computations === */


/**
 * The sizing scale's fundamental frequency.
 */
$f0: 1;

/**
 * The sizing scale's ratio.
 */
$ratio: 1.618033;

/**
 * The sizing scale's # of intervals.
 */
$n: 2;

/**
 * The sizing scale's units.
 */
$units: 1em;

/**
 * Generates a sizing scale from Tiny -> Small -> Medium -> Large -> Huge.
 * @param i
 *  The index to align the center of the scale to.
 * @returns
 *  The sizing scale.
 */
 @function make-scale($i) {
  @return (
    xxt : $i - 6,  // Extra Extra Tiny
    xt  : $i - 5,  // Extra Tiny
    t   : $i - 4,  // Tiny
    xxs : $i - 3,  // Extra Extra Small
    xs  : $i - 2,  // Extra Small
    s   : $i - 1,  // Small
    m   : $i,      // Medium
    l   : $i + 1,  // Large
    xl  : $i + 2,  // Extra Large
    xxl : $i + 3,  // Extra Extra Large
    h   : $i + 4,  // Huge
    xh  : $i + 5,  // Extra Huge
    xxh : $i + 6   // Extra Extra Huge
  );
}
$sizes: make-scale(0);

/**
 * Rounds a number to the specified decimal place.
 * @param $n
 *  The number to round.
 * @param $d
 *  The number of decimal places.
 * @returns
 *  The rounded number.
 */
@function round($n, $d) {
  @return math.div(math.round($n * math.pow(10, $d)), math.pow(10, $d));
}

/**
 * Returns a size from the sizing scale (without units).
 * @param i
 *  The size's index.
 * @returns
 *  The calculated size without $units.
 */
 @function size-of-unitless($i) {
  @return round($f0 * math.pow($ratio, math.div($i, $n)), 3);
}

/**
 * Returns a semitone from the sizing scale (without units).
 * @param i
 *  The first size's index.
 * @param j
 *  The second size's index.
 * @returns
 *  The calculated semitone, between i and j, without $units.
 */
@function semitone-of-unitless($i, $j) {
  @return round((size-of-unitless($i) + size-of-unitless($j)) * 0.5, 3);
}

/**
 * Returns a size from the sizing scale.
 * @param i
 *  The size's index.
 * @returns
 *  The calculated size expressed in $units.
 */
@function size-of($i) {
  @return $units * size-of-unitless($i);
}

/**
 * Returns a semitone from the sizing scale.
 * @param i
 *  The first size's index.
 * @param i
 *  The second size's index.
 * @returns
 *  The calculated semitone, between i and j, expressed in $units.
 */
@function semitone-of($i, $j) {
  @return $units * semitone-of-unitless($i, $j);
}

/**
 * Returns a size from the sizing scale (relative to the specified font).
 *
 * In order to add space between text and non-text elements (according to the sizing
 * scale), the text's line-height needs to be accounted for. When provided a size from
 * the sizing scale and the text's font metrics, this function returns the amount of
 * padding to add to the text such that the space between the text's glyphs and its
 * neighboring element are equal in size to the size requested.
 *
 * @param i
 *  The index of the desired size.
 * @param t
 *  The index of the font's size.
 * @param h
 *  The index of the font's line-height.
 * @param scale
 *  If `true`, the padding will be sized relative to the text's font size.
 *  If `false`, the padding will be sized relative to the container's font size.
 * @returns
 *  The calculated size expressed in $units.
 */
@function vertical-size-of-around-font($i, $t, $h, $scale) {
  $exp: if($scale == true, $i, $i - $t);
  $height: math.pow($ratio, math.div($exp, $n));
  $offset: (math.pow($ratio, math.div($h, $n)) - 1) * 0.5;
  @return $units * round($height - $offset, 3);
}

/**
 * Returns a size from the sizing scale (relative to the specified fonts).
 *
 * In order to add space between text elements (according to the sizing scale), each
 * text's line-height needs to be accounted for. When provided a size from the sizing
 * scale, the parent text's font metrics, and the child text's font metrics, this
 * function returns the amount of padding to add to the parent text such that the space
 * between parent and child glyphs are equal in size to the requested size.
 *
 * @param i
 *  The index of the desired size.
 * @param t1
 *  The index of the parent font's size.
 * @param h1
 *  The index of the parent font's line-height.
 * @param t2
 *  The index of the child font's size.
 * @param h2
 *  The index of the child font's line-height.
 * @param scale
 *  If `true`, the padding will be sized relative to the parent text's font size.
 *  If `false`, the padding will be sized relative to the container's font size.
 * @returns
 *  The calculated size expressed in $units.
 */
@function vertical-size-of-between-fonts($i, $t1, $h1, $t2, $h2, $scale) {
  $base: vertical-size-of-around-font($i, $t1, $h1, $scale);
  $lh: math.pow($ratio, math.div($t2 + $h2 - $t1, $n));
  $fs: math.pow($ratio, math.div($t2 - $t1, $n));
  @return $base - (($lh - $fs) * 0.5);
}

/**
 * The size of each heading's line-height
 */
$line-heights: (
  h1    : size-of(0),
  h2    : size-of(0),
  h3    : size-of(1),
  h4    : size-of(1),
  h5    : size-of(1),
  h6    : size-of(1),
  h7    : size-of(1),
  p     : semitone-of(2, 3),
  small : size-of(2),
);

/**
 * Oswald font adjustment.
 */
$oa: 0.25;

/**
 * The size of each heading.
 */
$font-sizes: (
  h1    : size-of(5 - $oa),
  h2    : size-of(4 - $oa),
  h3    : size-of(3 - $oa),
  h4    : semitone-of(1 - $oa, 2 - $oa),
  h5    : size-of(1 - $oa),
  h6    : semitone-of(0 - $oa, 1 - $oa),
  h7    : size-of(0 - $oa),
  p     : size-of(0),
  small : semitone-of(-1, 0),
);

/**
 * Returns a size from the configured sizing scale (without units).
 * @param i
 *  The size's id.
 * @returns
 *  The calculated size expressed without $units..
 */
@function size-unitless($i) {
  @return size-of-unitless(map.get($sizes, $i));
}

/**
 * Returns a size from the configured sizing scale.
 * @param i
 *  The size's id.
 * @returns
 *  The calculated size expressed in $units.
 */
@function size($i) {
  @return size-of(map.get($sizes, $i));
}

/**
 * Returns the size of a hypotenuse from the configured sizing scale.
 * @param i
 *  The size's id.
 * @returns
 *  The calculated hypotenuse expressed in $units.
 */
@function hypo($i) {
  @return math.sqrt(2 * math.pow(size-unitless($i), 2)) * $units;
}

/**
 * Returns a font style's size.
 * @param i
 *  The font style. (e.g. "h1", "h2", ..., "p")
 * @returns
 *  The calculated size expressed in $units.
 */
@function font-size($i) {
  @return map.get($font-sizes, $i);
}

/**
 * Returns a font style's line height.
 * @param i
 *  The font style. (e.g. "h1", "h2", ..., "p")
 * @returns
 *  The calculated size expressed in $units.
 */
 @function line-height($i) {
  @return map.get($line-heights, $i);
}

/** === Media Queries === */


@mixin above-max-width {
  @media only screen and (
    min-width: #{ $max-width + 1 }
  ) {
    @content;
  }
}

/** == Desktop == */

@mixin above-desktop-width {
  @media only screen and (
    min-width: #{ $desktop-width + 1 }
  ) {
    @content;
  }
}

@mixin at-and-above-desktop-width {
  @media only screen and (
    min-width: #{ $tablet-width + 1 }
  ) {
    @content;
  }
}

@mixin at-desktop-width {
  @media only screen and (
    max-width: $desktop-width
  ) and (
    min-width: #{ $tablet-width + 1 }
  ) {
    @content;
  }
}

@mixin at-and-below-desktop-width {
  @media only screen and (
    max-width: $desktop-width
  ) {
    @content;
  }
}

@mixin below-desktop-width {
  @media only screen and (
    max-width: $tablet-width
  ) {
    @content;
  }
}

/** == Tablet == */

@mixin above-tablet-width {
  @include at-and-above-desktop-width {
    @content;
  }
}

@mixin at-and-above-tablet-width {
  @media only screen and (
    min-width: #{ $mobile-width + 1 }
  ) {
    @content;
  }
}

@mixin at-tablet-width {
  @media only screen and (
    max-width: $tablet-width
  ) and (
    min-width: #{ $mobile-width + 1 }
  ) {
    @content;
  }
}

@mixin at-and-below-tablet-width {
  @include below-desktop-width {
    @content;
  }
}


@mixin below-tablet-width {
  @media only screen and (
    max-width: $mobile-width
  ) {
    @content;
  }
}

/** == Mobile == */

@mixin above-mobile-width {
  @include at-and-above-tablet-width {
    @content;
  }
}

@mixin at-and-above-mobile-width {
  @media only screen and (
    min-width: #{ $min-width + 1 }
  ) {
    @content;
  }
}

@mixin at-mobile-width {
  @media only screen and (
    max-width: $mobile-width
  ) and (
    min-width: #{ $min-width + 1 }
  ) {
    @content;
  }
}

@mixin at-and-below-mobile-width {
  @include below-tablet-width {
    @content;
  }
}

@mixin below-mobile-width {
  @media only screen and (
    max-width: $min-width
  ) {
    @content;
  }
}

/** === Typography === */


body {
  font-family: "Libre Franklin";
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

@include at-and-above-desktop-width() {
  body {
    /* font-size: 20px; */
    font-size: #{ $desktop-em-size }px;
  }
}

@include below-desktop-width() {
  body {
    font-size: #{ $mobile-em-size }px;
  }
}

@mixin h1 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h1");
  line-height: line-height("h1");
  text-transform: uppercase;
}
h1 { @include h1; }

@mixin h2 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h2");
  line-height: line-height("h2");
  text-transform: uppercase;
}
h2 { @include h2; }

@mixin h3 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h3");
  line-height: line-height("h3");
  text-transform: uppercase;
}
h3 { @include h3; }

@mixin h4 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h4");
  line-height: line-height("h4");
  text-transform: uppercase;
}
h4 { @include h4; }

@mixin h5 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h5");
  line-height: line-height("h5");
  text-transform: uppercase;
}
h5 { @include h5; }

@mixin h6 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h6");
  line-height: line-height("h6");
  text-transform: uppercase;
}
h6 { @include h6; }

@mixin h7 {
  font-family: "Oswald";
  font-weight: 500;
  font-size: font-size("h7");
  line-height: line-height("h7");
  text-transform: uppercase;
}

@mixin p {
  font-family: "Libre Franklin";
  font-weight: 400;
  font-size: font-size("p");
  line-height: line-height("p");
}
p { @include p; }

@mixin small {
  font-family: "Libre Franklin";
  font-weight: 400;
  font-size: font-size("small");
  line-height: line-height("small");
}
small {
  @include small;
  display: block;
}

@mixin var {
  font-family: "Roboto Mono";
  font-weight: 400;
  font-style: normal;
  font-size: font-size("small");
  line-height: line-height("small");
  padding: size("xt") size("m");
}
var { @include var }

@mixin code {
  font-family: "Roboto Mono";
  font-weight: 400;
  font-style: normal;
  font-size: font-size("small");
  line-height: line-height("small");
  word-break: break-all;
  padding: size("xxt") size("t");
}
code { @include code }

@mixin blockquote {
  padding: size("m") size("l");
  border-left-style: solid;
  border-left-width: 4px;
}
blockquote { @include blockquote }

@mixin codeblock {
  @include code;
  display: block;
  padding: size("m") size("l");
}
.codeblock { @include codeblock }

@mixin placeholder {
  font-family: "Oswald";
  font-weight: 400;
  font-size: font-size("p");
  line-height: line-height("p");
  text-transform: uppercase;
}
.placeholder { @include placeholder }

ul {
  padding-inline-start: size("h");
}

sup > a {
  text-decoration: none;
}

@mixin learn-more {

  & {
    @include h6;
    display: inline-block;
    text-decoration: none;
    padding-bottom: size("s");
    border-bottom: solid 2px;
  }

  &::after {
    content: var(--learn-more-arrow, "⟶");
    padding-left: size("xl");
    transition: padding .15s;
  }

  &:hover::after {
    content: var(--learn-more-arrow-hover, "⟶");
    padding-left: size("xxl");
  }

  &-hover-trigger:hover &::after {
    content: var(--learn-more-arrow-hover, "⟶");
    padding-left: size("xxl");
  }

}
.learn-more { @include learn-more }


/** === Shapes === **/


@mixin box($size) {
  box-sizing: border-box;
  width: size($size);
  height: size($size);
}


/** === Layouts === **/


@mixin grid-layout-fixed($cols, $col-gap, $rows, $row-gap){
  display: grid;
  align-items: center;
  grid-template-rows: repeat($rows, 1fr);
  grid-template-columns: repeat($cols, 1fr);
  row-gap: size($row-gap);
  column-gap: size($col-gap);
}

@mixin grid-layout-dynamic($cols, $col-gap, $rows, $row-gap){
  display: grid;
  align-items: center;
  grid-template-rows: repeat($rows, auto);
  grid-template-columns: repeat($cols, auto);
  row-gap: size($row-gap);
  column-gap: size($col-gap);
}


/** === Interface === **/


button {
  @include h7;
  display: flex;
  align-items: center;
  padding: size("s") size("m");
  border-style: solid;
  border-width: 1px;
  user-select: none;
  cursor: pointer;
  transition: background 0.15s;
}

button svg {
  height: 10px;
}

button {
  svg ~ span {
    margin-left: size("xs");
  }
}

input {
  @include p;
  padding: size("xt") size("xs");
  border-style: solid;
  border-width: 1px;
}

@mixin selection-area {
  & {
    transition: background .15s;
  }
  &:hover {
    background: var(--accent-2-border);
  }
}
