@use 'sass:math';
@use '../../compiled/tokens/scss/color';
@use '../../compiled/tokens/scss/ease';
@use '../../compiled/tokens/scss/font-weight';
@use '../../compiled/tokens/scss/line-height';
@use '../../compiled/tokens/scss/opacity';
@use '../../compiled/tokens/scss/size';
@use '../../compiled/tokens/scss/transition';
@use '../../mixins/focus';
@use '../../mixins/headings';
@use '../../mixins/ms';
@use '../../mixins/unit';

// Variables that define the size and shape of the (optional) permalink element.
// 1. The total size of the element.
// 2. The size of the icon within the element.
// 3. The element's rounded corners.
$permalink-size: size.$height-control-default; // 1
$permalink-icon-size: size.$square-control-icon; // 2
$permalink-radius: size.$border-radius-full; // 3

// We want the permalink's position to change when there is enough room to
// display a full line of prose _plus_ the permalink. To pull this off, we use
// the prose width and permalink size (above) to build some component-specific
// media query breakpoints.
$min-width-permalink-shift: size.$max-width-prose + $permalink-size * 4;
$max-width-permalink-shift: math.div($min-width-permalink-shift * 16 - 1, 16);

/// This containing element may be applied to a heading directly to apply a
/// heading style, or to a containing element if you want to display a heading
/// and permalink.
///
/// We default to the lowest heading level supported by HTML5, which forces
/// the template designer to specify an intended visual heading level.
.c-heading {
  @include headings.level(6);
}

/// Level modifiers
///
/// These will apply the styles for a specific heading level.
///
/// We start at `-2` so template designers have three sizes larger than a
/// default `<h1>` to apply thoughtfully within templates.
///
/// Even though distinct sizes end at level 3, we output modifier classes for
/// all 6 levels to encourage semantic sizing that will be future-friendly if
/// that ever changes.
@for $level from -2 through 6 {
  $level-segment: ms.step-class-segment($level);

  .c-heading--level-#{$level-segment} {
    @include headings.level($level);
  }
}

/// Weight modifier
///
/// The default font weight for headings is normally defined by heading level.
/// This modifier will change the heading to font-weight.$light. We do this to
/// maintain the importance of headings without drowning out other content.
///
/// 1. Restore default font weight for bold/emphasis elements nested within
///    light and medium headings. Without this, `b` and `strong` elements will
///    only be one step up in weight.

.c-heading--light {
  font-weight: font-weight.$light;

  b,
  strong {
    font-weight: font-weight.$bold; // 1
  }
}

.c-heading--medium {
  font-weight: font-weight.$medium;

  b,
  strong {
    font-weight: font-weight.$bold; // 1
  }
}

/// Modifier for when the heading contains a subheading. At large sizes, the
/// subheading will position itself inline with the main heading.
.c-heading--with-subheading {
  @media (min-width: $min-width-permalink-shift) {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
  }
}

/// For complex headings (those that include a permalink and/or subheading), the
/// heading content and optionally permalink are contained in this element. This
/// gives us two benefits: We can position the permalink relative to the heading
/// (and not a subheading), and the `line-height` of the larger heading will
/// play a bit nicer when there's a wrapper element.
.c-heading__main {
  flex: none;

  // When a permalink is present, we want to position it relative to this. We
  // also want to make sure there's enough space for it since we'll be using
  // absolute positioning.
  .c-heading--with-permalink & {
    position: relative;

    @media (max-width: $max-width-permalink-shift) {
      padding-inline-end: unit.swap($permalink-size, rem);
    }
  }

  // When a subheading is present and the container is large enough for the
  // permalink (if any) to be positioned outside, we add some space between
  // the main heading and subheading that is visually similar to the space
  // between the permalink and main heading.
  .c-heading--with-subheading & {
    @media (min-width: $min-width-permalink-shift) {
      margin-inline-end: ms.step(-1, 1rem);
    }
  }
}

/// For complex headings (those containing a permalink and/or subheading), the
/// actual `h*` element must be a child element, so we inherit the container's
/// font and color styles. It's important the containing element retain the
/// heading font styles for vertical rhythm to work as intended!
.c-heading__content {
  color: inherit;
  font: inherit;
}

/// The optional subheading element displays at the default/base font size and
/// at a reduced weight. At larger sizes, it will follow the main heading inline
/// unless it's long enough to break onto its own line.
.c-heading__subheading {
  flex: none;
  font-size: ms.step(0, 1rem);
  font-weight: font-weight.$medium;
  line-height: line-height.$tight;
  max-inline-size: 100%;
  text-wrap: balance;

  .c-heading--light & {
    font-weight: font-weight.$normal;
  }

  .c-heading--with-permalink & {
    @media (max-width: $max-width-permalink-shift) {
      padding-inline-end: unit.swap($permalink-size, rem);
    }
  }
}

/// Optional permalink to be included adjacent to the heading itself.
///
/// 1. We define the element's `font-size` using `rem` so its size will remain
///    consistent between differently sized headings in the same article.
/// 2. The link's shape is not visible unless focused, so applying some negative
///    offset based on the inner padding makes the link appear better aligned
///    with content above and below.
///
/// @link http://codepen.io/marcysutton/pen/rLKvgZ
.c-heading__permalink {
  align-items: center;
  block-size: $permalink-size;
  border-radius: $permalink-radius;
  display: flex;
  font-size: unit.swap($permalink-icon-size, rem); // 1
  inline-size: $permalink-size;
  inset-block: 0;
  inset-inline-end: math.div($permalink-size - $permalink-icon-size, -2); // 2
  justify-content: center;
  margin: auto;
  position: absolute;
  text-decoration: none;
  transition: color transition.$quick ease.$out,
    opacity transition.$quick ease.$out;

  @include focus.focus-visible {
    box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter;
  }

  // We use negation selectors to apply the non-hover style so the permalink
  // inherits any existing theme link styles for free.
  &:not(:hover):not(:focus):not(:active) {
    color: inherit;
    opacity: opacity.$muted;
  }

  // Above a certain size, we display the icon to the left of the heading but
  // outside of the container (so it doesn't bump the heading to the right,
  // which can disrupt the flow of reading the content).
  @media (min-width: $min-width-permalink-shift) {
    inset-inline-end: 100%;
  }
}
