@use 'sass:math';
@use '../../styles/mixins';

// Bone dimensions
$text-height: 16px;
$heading-height: 22px;
$avatar-size: 40px;
$icon-size: 24px;
$button-height: 36px;
$button-width: 96px;
$chip-height: 24px;
$chip-width: 72px;
$image-height: 160px;
$table-cell-height: 14px;

// Line boxes of an info-card row, so the placeholder keeps the final height
$info-card-row-height: 24px;
$info-card-label-height: 16px;
$info-card-label-gap: 2px;
$info-card-label-block: $info-card-label-height + $info-card-label-gap;
$info-card-row-vertical-height: $info-card-label-block + $info-card-row-height;

// Row pitch of each info-card variant: the margin the real rows leave between
// them. Consumers read these instead of repeating the numbers.
$info-card-row-gap: 10px;
$info-card-row-vertical-gap: 12px;

// Line box of a card title (22px font), its icon, and the card divider margins
$card-title-line-height: 28px;
$card-title-icon-size: 22px;
$card-title-icon-gap: 6px;
$card-divider-spacing: 12px;

// Layout breakpoint shared with the info-card rows
$mobile-breakpoint: 768px;

// Theming defaults. They are read through custom properties so a consumer can
// override them on the component or on any ancestor (a dark card, a panel, …):
//   --epag-skeleton-bone-color
//   --epag-skeleton-highlight-color
//   --epag-skeleton-radius
//   --epag-skeleton-gap
//   --epag-skeleton-speed
$bone-color: #e4e8ec;
$highlight-color: rgba(255, 255, 255, 0.7);
$radius: 4px;
$gap: 12px;
$speed: 1.6s;

/* Once the content is in, the host generates no box at all: the projected
   content lays out against the real parent, as a flex item, a grid item or a
   table row of its own, and nothing left over from the placeholder — a width, a
   height, a block formatting context — can constrain it */
:host {
  display: contents;

  /* Row pitch each info-card variant expects, published so the consumer does not
     repeat numbers that have to match the row heights defined here */
  --epag-skeleton-info-card-row-gap: #{$info-card-row-gap};
  --epag-skeleton-info-card-row-vertical-gap: #{$info-card-row-vertical-gap};
}

/* While loading the host is the box that stacks the root bones */
:host(.epag-skeleton-loader--loading) {
  display: flex;
  flex-direction: column;
  width: 100%;
  gap: var(--epag-skeleton-gap, #{$gap});
}

/* Painted element: every leaf of the skeleton tree */
.epag-skeleton-loader__bone {
  position: relative;
  flex: 0 0 auto;
  overflow: hidden;
  background-color: var(--epag-skeleton-bone-color, #{$bone-color});
  border-radius: var(--epag-skeleton-radius, #{$radius});

  &::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
      90deg,
      transparent,
      var(--epag-skeleton-highlight-color, #{$highlight-color}),
      transparent
    );
    transform: translateX(-100%);
    animation: epag-skeleton-shimmer var(--epag-skeleton-speed, #{$speed}) ease-in-out infinite;
  }
}

/* Layout element: every composite of the skeleton tree */
.epag-skeleton-loader__group {
  display: flex;
  flex-direction: column;
  gap: var(--epag-skeleton-gap, #{$gap});
  width: 100%;
}

/* A shape with a single root fills the size given to the component, so `width`
   and `height` size the bone itself. With several roots each keeps its own size. */
:host(.epag-skeleton-loader--loading) > :only-child {
  flex: 1 1 auto;
}

// ============================================================================
// Primitives
// ============================================================================

.epag-skeleton-loader__text {
  width: 100%;
  height: $text-height;
  border-radius: calc($text-height / 2);
}

.epag-skeleton-loader__heading {
  width: 40%;

  /* Never wider than the container, so a heading in a column shape still fits a
     narrow card; row shapes drop the floor entirely */
  min-width: min(120px, 100%);
  flex-shrink: 1;
  height: $heading-height;
  border-radius: 6px;
}

.epag-skeleton-loader__avatar {
  @include mixins.circle($avatar-size);
}

.epag-skeleton-loader__icon {
  @include mixins.circle($icon-size);
}

.epag-skeleton-loader__button {
  width: $button-width;
  height: $button-height;
  border-radius: 8px;
}

.epag-skeleton-loader__chip {
  width: $chip-width;
  height: $chip-height;
  border-radius: calc($chip-height / 2);
}

.epag-skeleton-loader__divider {
  width: 100%;
  height: 1px;
  border-radius: 0;
}

.epag-skeleton-loader__image {
  width: 100%;
  height: $image-height;
  border-radius: 8px;
}

.epag-skeleton-loader__table-cell {
  width: 100%;
  height: $table-cell-height;
  border-radius: calc($table-cell-height / 2);
}

// ============================================================================
// Composites
// ============================================================================

.epag-skeleton-loader__sentences,
.epag-skeleton-loader__paragraph {
  gap: 8px;

  .epag-skeleton-loader__text:last-child {
    width: 65%;
  }
}

.epag-skeleton-loader__article {
  gap: 16px;
}

.epag-skeleton-loader__list-item,
.epag-skeleton-loader__list-item-avatar {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  min-height: $avatar-size;

  /* The line takes the space left next to the avatar, not the whole row */
  .epag-skeleton-loader__text {
    flex: 1 1 0;
    min-width: 0;
  }
}

.epag-skeleton-loader__actions {
  flex-direction: row;
  justify-content: flex-end;
  gap: 8px;
}

/* Title line of a card. The margin around the bone keeps the line box of the
   real 22px title, so the content underneath does not move on load. */
.epag-skeleton-loader__card-title,
.epag-skeleton-loader__card-title-icon {
  .epag-skeleton-loader__heading {
    /* A title placeholder fills the width the shape is given, so the consumer
       decides how much of the header row the title occupies */
    width: 100%;
    min-width: 0;
    margin: math.div($card-title-line-height - $heading-height, 2) 0;
  }
}

/* Same title line with the icon that precedes it */
.epag-skeleton-loader__card-title-icon {
  flex-direction: row;
  align-items: center;
  gap: $card-title-icon-gap;

  .epag-skeleton-loader__icon {
    @include mixins.circle($card-title-icon-size);
  }

  /* Beside the icon the heading gives up its floor rather than overflow */
  .epag-skeleton-loader__heading {
    min-width: 0;
  }
}

.epag-skeleton-loader__card {
  gap: 16px;
}

/* Mirrors the info-card row grid: label on the left, value aligned to the right.
   The min-height matches the line box of a real row so nothing moves on load. */
.epag-skeleton-loader__info-card-row {
  display: grid;
  grid-template-columns: minmax(160px, 40%) 1fr;
  grid-auto-rows: $info-card-row-height;
  gap: 8px 16px;
  align-items: center;
  min-height: $info-card-row-height;

  .epag-skeleton-loader__text:first-child {
    width: 70%;
  }

  .epag-skeleton-loader__text:last-child {
    width: 45%;
    justify-self: end;
  }

  /* Same breakpoint as the info-card rows: label and value stack */
  @media (max-width: $mobile-breakpoint) {
    grid-template-columns: 1fr;
    gap: 4px;

    .epag-skeleton-loader__text:last-child {
      justify-self: start;
    }
  }
}

/* Stacked counterpart, mirroring the info-card `vertical` variant:
   a small label line above a regular value line */
.epag-skeleton-loader__info-card-row-vertical {
  display: grid;
  grid-template-columns: 1fr;
  gap: 9px;
  align-content: center;

  /* Height of a real vertical row (label line, gap, value line), so the rows
     line up with the loaded ones however the bones inside are sized */
  min-height: $info-card-row-vertical-height;

  .epag-skeleton-loader__text:first-child {
    width: 40%;
    height: 14px;
  }

  .epag-skeleton-loader__text:last-child {
    width: 55%;
  }
}

.epag-skeleton-loader__table {
  gap: 20px;
}

.epag-skeleton-loader__table-heading {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 16px;

  .epag-skeleton-loader__text {
    width: 25%;
  }

  /* Sharing the row with the count, the heading gives up its floor */
  .epag-skeleton-loader__heading {
    min-width: 0;
  }
}

.epag-skeleton-loader__table-thead,
.epag-skeleton-loader__table-row {
  flex-direction: row;
  align-items: center;
  gap: 16px;

  /* Cells share the row width evenly; standalone cells keep their own width */
  .epag-skeleton-loader__table-cell {
    flex: 1 1 0;
    min-width: 0;
  }
}

.epag-skeleton-loader__table-thead .epag-skeleton-loader__table-cell {
  height: 16px;
}

.epag-skeleton-loader__table-tbody {
  gap: 16px;
}

// ============================================================================
// Motion
// ============================================================================

:host(.epag-skeleton-loader--boilerplate) .epag-skeleton-loader__bone::after {
  content: none;
}

@media (prefers-reduced-motion: reduce) {
  .epag-skeleton-loader__bone::after {
    animation: none;
  }
}

@keyframes epag-skeleton-shimmer {
  100% {
    transform: translateX(100%);
  }
}
