/**
 * @file
 * The shared teaser card (biopama_libraries/teaser-card): ONE geometry for
 * every content type that renders a `.teaser-card`, site-wide.
 *
 * Five bundles ship one of these — dataset (indicator), tool, storymap, map
 * layer and news (blog_post) — from five near-identical templates. They all
 * already carried the `teaser-card` class, so the alignment lives here rather
 * than being repeated in each template; the templates only supply the parts
 * Bootstrap cannot express as a class (the shared text class, the p-3 title).
 *
 * What varied before this file, measured at 1400px across /landingpage,
 * /all_tools, /all_stories and /news:
 *   image height  200-248px  (image_style('medium') keeps the aspect ratio, so
 *                             the height simply followed the source image)
 *   card height   428-582px
 *   title offset  105-185px from the top of the card
 *   card width    384-416px  (mb-3 w-100 against m-3 flex-fill)
 *
 * The card is a fixed height and composed of fixed parts, so a row that mixes
 * content types (the home page's "What's new" lists datasets and news
 * together) lines up exactly:
 *   - the image is cropped to one height with object-fit, never letterboxed;
 *   - the title is flush with the bottom edge of the image on every card and
 *     clamped to two lines, with the full text offered as a tooltip;
 *   - the description is clamped to a set number of lines;
 *   - whatever follows is pushed to the bottom by the card body's own
 *     justify-content-between.
 *
 * The one exception is deliberate: a card whose "Related Policies" / "Related
 * Topics" disclosure is open grows to fit it, because a disclosure that cannot
 * show its content is worse than a row that is briefly uneven. It returns to
 * the fixed height when closed.
 */

/* `.card.teaser-card`, not `.teaser-card`: Bootstrap's own `.card` sets
   `height: var(--bs-card-height)` at the same specificity and its stylesheet
   loads after this one, so a single class here is silently reset to auto.
   Specificity, never !important. */
.card.teaser-card {
  /* Change the card's proportions here, once, for the whole site. */
  --akp-teaser-image-height: 220px;
  --akp-teaser-height: 32rem;
  --akp-teaser-title-lines: 2;
  --akp-teaser-line-height: 1.5rem;
  --akp-teaser-text-lines: 3;

  height: var(--akp-teaser-height);
}

/* An open disclosure gets the room it needs; the card is fixed again once it
   closes. .collapsing covers the animation, so the card grows with it. */
.card.teaser-card:has(.collapse.show),
.card.teaser-card:has(.collapse.collapsing) {
  height: auto;
  min-height: var(--akp-teaser-height);
}

/* The image block is the card's fixed header, and keeps its height even when
   there is no image to put in it: a bundle with an empty image field and no
   usable default would otherwise collapse the block to nothing and drag the
   title, which the overlay positions against it, off the top of the card. */
.teaser-card .card-image {
  position: relative;
  flex: 0 0 auto;
  height: var(--akp-teaser-image-height);
}

/* One image size everywhere. The card's own image is the direct child: the
   title overlay is a div that carries .card-img-top as well, and the source
   badge logos are images nested deeper inside the badges heading. */
.teaser-card .card-image > img {
  width: 100%;
  height: var(--akp-teaser-image-height);
  object-fit: cover;
}

/* The title sits on the bottom edge of the image (the overlay's
   align-items-end) and is clamped to --akp-teaser-title-lines, so it never
   reaches a third line whatever the card's width.

   Two things have to hold for that clamp to be clean, and both were learned
   the hard way. The element must carry NO min-height, or a third line is laid
   out inside the fixed box and only partly clipped. And it must carry NO
   padding: `overflow: hidden` clips at the PADDING box, not the content box,
   so 1rem of bottom padding on a clamped title leaves a 16px window that
   two-thirds of the next line shows through — ellipsis on line two AND a
   sliced line under it. The inset therefore lives on the overlay, and the
   title itself has neither padding nor min-height.

   Trimming here rather than by character count in Twig is deliberate: 80
   characters is two lines in a 416px column and three in a 264px one, so a
   character limit cannot express "never a third line". The full title stays
   in the DOM for js/teaserCard.js to offer as a tooltip.

   The line height is pinned so every card's title wraps on the same rhythm
   whatever the theme does to headings. */
.teaser-card .card-image .card-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--akp-teaser-title-lines);
  overflow: hidden;
  line-height: var(--akp-teaser-line-height);
}

/* The body takes the rest of the fixed height; its own
   justify-content-between then pins the button row to the bottom edge. */
.teaser-card > .card-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.card.teaser-card:has(.collapse.show) > .card-body,
.card.teaser-card:has(.collapse.collapsing) > .card-body {
  overflow: visible;
}

/* The description. Clamped rather than truncated by character count: 200
   characters is a different number of lines in a 288px column than in a
   416px one, which is half of why card heights drifted. */
.teaser-card .teaser-card-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  /* -webkit-line-clamp only; current Chromium computes `display: flow-root`
     for it either way, and cuts on an exact line boundary. Do not also give
     this a min-height: that combination is what cut the title in half. */
  -webkit-line-clamp: var(--akp-teaser-text-lines);
  overflow: hidden;
}

/* The description is rendered body HTML — paragraphs, links, sometimes a
   list — and a clamp counts line boxes while the box height also collects
   the children's own line-heights and vertical margins. Left alone, the cut
   lands inside a margin or part way down a line with a different rhythm, and
   a sliver of the next line shows. One rhythm and no vertical margins inside
   the clamped box put every cut on a line boundary. Margins are no loss
   here: three clamped lines rarely reach a second paragraph. */
/* The description keeps the height its clamp gives it. It is a flex item of
   the card body, so with `flex-shrink: 1` a card whose content did not quite
   fit took the difference out of this box — leaving it a fraction of a line
   tall and cutting the last line through the middle. It is the card height
   that has to accommodate the content, not this box that gives way.

   The content is rendered body HTML — paragraphs, links, sometimes a list —
   and a clamp counts line boxes while the box height also collects the
   children's own line-heights and vertical margins. One rhythm and no
   vertical margins inside the clamped box keep every cut on a line boundary
   whatever the body contains; three clamped lines rarely reach a second
   paragraph, so the margins are no loss. */
.teaser-card .teaser-card-text {
  flex: 0 0 auto;
}

.teaser-card .teaser-card-text,
.teaser-card .teaser-card-text * {
  line-height: var(--akp-teaser-line-height);
  margin-top: 0;
  margin-bottom: 0;
}

/* The button row is the card's fixed footer: it keeps its place when the
   description is short and wraps within the card when it is crowded. */
.teaser-card .card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: flex-end;
  align-items: center;
}

/* The RCoE action chips, stacked over the top-left of the image. Their
   colours are editorial data on the taxonomy term, so they arrive as one
   generated stylesheet of --bs-btn-bg per term class rather than as an inline
   style on each chip. */
.teaser-card .card-chips {
  max-width: calc(100% - 1rem);
}

.teaser-card .akp-rcoe-action {
  font-size: 0.875rem;
  text-align: start;
}
