@use '../../compiled/tokens/scss/aspect-ratio';
@use '../../compiled/tokens/scss/breakpoint';
@use '../../compiled/tokens/scss/brightness';
@use '../../compiled/tokens/scss/color';
@use '../../compiled/tokens/scss/ease';
@use '../../compiled/tokens/scss/size';
@use '../../compiled/tokens/scss/transition';
@use '../../mixins/border-radius';
@use '../../mixins/fluid';
@use '../../mixins/focus';
@use '../../mixins/headings';
@use '../../mixins/media-query';
@use '../../mixins/ms';
@use '../../mixins/spacing';
@use '../../mixins/theme';

/// We can't use `grid-gap` exclusively due to some containers only being
/// present some of the time, so we re-use this value to define the space
/// between chunks of content.
///
/// @type Number
/// @access private

$_content-gap: ms.step(-1, 1rem);

/// We add more space between the cover and text elements simply because it
/// feels better visually.
///
/// @type Number
/// @access private

$_cover-gap: ms.step(1, 1rem);

/// The focus outline feels a little snug directly on the outer edge, but we
/// don't want to extend _too_ far out for fear of colliding with adjacent
/// content. Doubling the size of the focus edge felt like a nice compromise.
///
/// @type Number
/// @access private

$_focus-overflow: (size.$edge-large * -1);

/// The cloudy modifier adds clouds to the bottom right corner and also applies
/// some fluid padding to accommodate. The clouds feel best when they are sized
/// just a _tad_ larger than this fluid padding.
///
/// @type Number
/// @access private

$_cloud-height: fluid.fluid-clamp(
  size.$padding-container-vertical-min * 1.33,
  size.$padding-container-vertical-max * 1.33,
  breakpoint.$s,
  breakpoint.$m
);

/**
 * The main card container
 *
 * 1. We define our column gap here instead of in the `c-card--horizontal`
 *    modifiers so we don't have to define it within multiple media queries.
 * 2. We use `minmax(0, auto)` to prevent these rows from displaying in some
 *    browsers even if their elements are nonexistent.
 * 3. This allows our `c-card__link` pseudo element to position itself relative
 *    to this container.
 */

.c-card {
  display: grid;
  grid-column-gap: fluid.fluid-clamp(
    size.$spacing-gap-fluid-min,
    size.$spacing-gap-fluid-max,
    breakpoint.$s,
    breakpoint.$xl
  ); /* 1 */
  grid-template-areas:
    'cover'
    'header'
    'content'
    'footer';
  grid-template-rows: minmax(0, auto) minmax(0, auto) 1fr minmax(0, auto); /* 2 */
  position: relative; /* 3 */
}

.c-card--contained {
  @include border-radius.conditional;
  padding: ms.step(1);

  @include theme.unthemed-styles {
    background-color: var(--theme-color-background-secondary);
  }
}

/**
 * Center-align text content to better match a circular cover image
 */

.c-card--circle-cover {
  text-align: center;
}

/**
 * Responsive horizontal modifiers
 *
 * 1. If this is in a multi-column grid layout, this insures it will fill the
 *    available width.
 * 2. We define the layout as three columns instead of `2fr 1fr` so that the
 *    gaps will line up with three-column elements below.
 * 3. The `fr` rows on the ends keep the content rows vertically centered.
 */

.c-card--horizontal {
  @include media-query.breakpoint-classes(
    $from: m,
    $to: xl,
    $include-default: false
  ) {
    grid-column: 1 / -1; /* 1 */
    grid-template-areas:
      'cover cover .'
      'cover cover header'
      'cover cover content'
      'cover cover footer'
      'cover cover .';
    grid-template-columns: repeat(3, 1fr); /* 2 */
    grid-template-rows: 1fr repeat(3, minmax(0, auto)) 1fr; /* 3 */

    /**
     * When the cover image is circular (and thus taller), give it a smaller
     * amount of space and keep the text left-aligned.
     */

    &.c-card--circle-cover {
      grid-template-areas:
        'cover . .'
        'cover header header'
        'cover content content'
        'cover footer footer'
        'cover . .';
      text-align: start;
    }
  }
}

/**
 * Cloudy modifier
 *
 * Chrome and Safari often introduce little subpixel artifacts between the edge
 * of a bottom-right image or positioned element that is sized responsively. To
 * minimize this, we assume that this modifier will be shown on a default/light
 * background, and we use a pseudo element for the cloud of the same color so
 * we can offset it slightly (which overlays any artifacting).
 *
 * 1. On the element itself we can include the "background" clouds. These are
 *    lower contrast so the artifacting is less noticeable, and they do not
 *    match light backgrounds so we can't offset them.
 * 2. We include more generous spacing to account for the clouds. It is still
 *    theoretically possible for content to overlap the clouds, so this modifier
 *    should be used carefully.
 */

.c-card--cloudy {
  @include spacing.fluid-padding-block; /* 2 */
  @include spacing.fluid-padding-inline; /* 2 */
  background-image: svg-load('clouds/background.svg'); /* 1 */
  background-position: bottom right;
  background-repeat: no-repeat;
  background-size: auto $_cloud-height;
}

/**
 * Pseudo element used to position the cloud matching the container background,
 * offset to obscure rounding artifacts.
 *
 * 1. Fluid sizing based on asset's natural dimensions, since we don't have an
 *    `auto` width in this context.
 * 2. Offsetting to obscure artifacts.
 * 3. Prevent pointer events so that cloud can never block interactions (clicks,
 *    text selection, etc.)
 */

.c-card--cloudy::before {
  aspect-ratio: 580 / 220; /* 1 */
  background-image: svg-load('clouds/foreground.svg');
  background-position: bottom right;
  background-repeat: no-repeat;
  background-size: contain;
  block-size: $_cloud-height; /* 1 */
  content: '';
  inset-block-end: -1px; /* 2 */
  inset-inline-end: -1px; /* 2 */
  pointer-events: none; /* 3 */
  position: absolute;
}

/**
 * Header area
 *
 * This exists separately from the heading to encourage the use of the `header`
 * element within an `article`.
 *
 * 1. This display type and gap exist in case an `eyebrow` block is included.
 */

.c-card__header {
  display: grid; /* 1 */
  gap: $_content-gap; /* 1 */
  grid-area: header;

  /**
   * If there's content after this, add margin below. This gets a little weird
   * if only a cover and header are shown, but I think that will be uncommon
   * enough to make this a fair solution.
   */

  &:not(:last-child) {
    margin-block-end: $_content-gap;
  }
}

/**
 * We style the heading regardless of level to encourage using the most
 * appropriate semantic heading level for the document outline.
 */

.c-card__heading {
  @include headings.level(2);
}

/**
 * The eyebrow should precede the heading visually.
 */

.c-card__eyebrow {
  order: -1;
}

/**
 * This is the primary link, presumed but not required to be within the heading.
 */

.c-card__link {
  /**
   * Keyboard focus styles take inspiration from buttons and similar elements
   */

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

  /**
   * Only show the underline on hover.
   */

  &:not(:hover) {
    text-decoration: none;
  }

  /**
   * Cover the entire card with an absolute positioned pseudo element. This
   * is easier to use for assistive devices than a block-level link or multiple
   * redundant links and requires no JavaScript. It does sacrifice ease of text
   * selection, but that shouldn't be a huge issue if a `Card` is linking to
   * more information.
   */

  &::after {
    border-radius: size.$border-radius-medium;
    content: '';
    inset: $_focus-overflow;
    position: absolute;
    z-index: 1;

    /**
     * Do not overflow when the card's edges are distinct
     */

    .c-card--contained & {
      inset: 0;
    }
  }
}

/**
 * Cover area
 *
 * 1. In case the image is missing or slow to load.
 * 2. Fix for Safari bug where transitions cause overflow to no longer be
 *    respected. Although other fixes seem to use 3D transforms, this does not
 *    appear to be necessary when the child effect is not 3D.
 *    @see https://bugs.webkit.org/show_bug.cgi?id=68196
 *    @see https://stackoverflow.com/questions/14383632/
 */

.c-card__cover {
  aspect-ratio: aspect-ratio.$wide;
  background-color: var(--theme-color-background-secondary); /* 1 */
  border-radius: size.$border-radius-medium;
  grid-area: cover;
  overflow: hidden;
  transform: translate(0, 0); /* 2 */

  /**
   * Allows cover image to break out of 16/9 aspect-ratio and fill the space
   * vertically at smallish viewports (only applies in the horizontal layout)
   */

  @include media-query.breakpoint-parent-classes(
    $selector: '.c-card--horizontal',
    $from: m,
    $to: xl,
    $include-default: false
  ) {
    block-size: 100%;
    inline-size: 100%;
  }

  /**
   * Subtly brighten covers within our alternate theme containers to help offset
   * imagery with light backgrounds from the surrounding container. We could
   * also do this for contained cards, but since those are a less common
   * occurrence we'll keep this simple for now.
   */

  @include theme.styles(alternate) {
    filter: brightness(brightness.$image-brighten);
  }

  /**
   * Square aspect ratio + fully rounded corners = circular cover image
   *
   * 1. Fixes bug where the circle cover wasn't a circle at smallest viewports
   */

  .c-card--circle-cover & {
    aspect-ratio: 1;
    block-size: auto; /* 1 */
    border-radius: size.$border-radius-full;
  }

  /**
   * Since this element is always visually on top, we can assume it needs a
   * bottom margin _unless_ it's an only child. Unfortunately we need to
   * override this for the horizontal modifier.
   */

  &:not(:only-child) {
    margin-block-end: $_cover-gap;

    @include media-query.breakpoint-parent-classes(
      $selector: '.c-card--horizontal',
      $from: m,
      $to: xl,
      $include-default: false
    ) {
      margin-block-end: 0;
    }
  }
}

/**
 * Hover effect for when the card contains a link. The image appears to zoom in
 * a very slight amount. We negate that zoom for the `:active` state for some
 * subtle consistency with other scale interactions, such as buttons and event
 * summary calendars, but we don't go quite as dramatic since these are larger
 * elements that would feel a bit more jarring.
 */

.c-card__cover > *,
.c-card__cover > picture > img {
  block-size: 100%;
  inline-size: 100%;
  object-fit: cover;
  transition: transform transition.$prompt ease.$out;

  .c-card--with-link:hover:not(:active) & {
    transform: scale(1.025);
  }
}

/**
 * Content area. Not especially exciting.
 */

.c-card__content {
  grid-area: content;

  &:not(:last-child) {
    margin-block-end: $_content-gap;
  }
}

/**
 * Footer area. Wooooooo.
 */

.c-card__footer {
  grid-area: footer;
}
