/**
 * Post loop grid
 *
 * THE PARTIAL LAST ROW. Rick, 2026-09-15: "the final row does not center when
 * it is partial row."
 *
 * It could not. The card grid was `display: grid` with Tailwind container-query
 * column classes, and CSS Grid has no way to centre an incomplete final row:
 * the tracks are fixed, so four items in a three-column grid leave the fourth
 * hard against the left edge with two empty tracks beside it. The usual
 * workarounds need to know how many items are left over AND how many columns
 * there are at that moment — and the column count changes at every breakpoint,
 * so no single rule can be right.
 *
 * Flex wrapping has the property grid lacks: `justify-content: center` centres
 * whatever ends up on the last line, at every width, without anyone counting.
 * The column count survives as a custom property so the responsive steps are
 * the same ones the grid had.
 *
 * `--loop-max` is written by Plexa_Card_Grid_Post_Loop from the `columns`
 * schema value; the steps below clamp it so a 6-column loop still shows 1 on a
 * narrow container. min() on unitless numbers is what keeps that to one
 * declaration per step rather than one per column count.
 *
 * @package Plexa_AI_Theme
 */

.post-loop__grid {
    --loop-max: 3;
    --loop-cols: 1;
    --loop-gap: 1.5rem;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--loop-gap);
}

.post-loop__grid > * {
    /* The width a cell would have had in the equivalent grid: the row minus its
       gaps, divided by the columns. Items keep their track width, so a full row
       is indistinguishable from the grid it replaced — only the leftovers move. */
    flex: 0 1 calc((100% - (var(--loop-cols) - 1) * var(--loop-gap)) / var(--loop-cols));
    min-width: 0;
}

/* The same container-query steps the Tailwind classes used, so nothing about
   the responsive behaviour changes. */
@container (min-width: 24rem) {
    .post-loop__grid { --loop-cols: min(2, var(--loop-max)); }
}
@container (min-width: 28rem) {
    .post-loop__grid { --loop-cols: min(3, var(--loop-max)); }
}
@container (min-width: 32rem) {
    .post-loop__grid { --loop-cols: min(4, var(--loop-max)); }
}
@container (min-width: 36rem) {
    .post-loop__grid { --loop-cols: min(5, var(--loop-max)); }
}
@container (min-width: 42rem) {
    .post-loop__grid { --loop-cols: min(6, var(--loop-max)); }
}

/* Gap sizes, matching the gap-4/6/8 the grid classes used. */
.post-loop__grid--gap-sm { --loop-gap: 1rem; }
.post-loop__grid--gap-md { --loop-gap: 1.5rem; }
.post-loop__grid--gap-lg { --loop-gap: 2rem; }

/* A single item should not stretch to the full width of a six-column loop just
   because it is alone — it reads as a banner rather than as one card of many. */
.post-loop__grid > *:only-child {
    flex-basis: calc((100% - (var(--loop-cols) - 1) * var(--loop-gap)) / var(--loop-cols));
}

/* ==========================================================================
   Cards in a row are the same size, and their actions line up
   ==========================================================================

   Rick, 2026-09-15: "cards should always be the same size when in a row. And
   the read me should always be aligned to each other" and "images should be the
   same size when on a row".

   THIS REVERSES AN EARLIER ATTEMPT, and the earlier one was wrong. Told that a
   stretched card left white space under its text, the first fix let the IMAGE
   grow to absorb it. That removes the gap and breaks something more important:
   a row of cards whose pictures are all different heights, because each one
   swallowed whatever slack its own text left. The slack is real but the image
   is not where it should go.

   The structure a card actually wants:

     image     FIXED, so every picture in a row is the same height. The 16/9
               from Plexa_Post_Loop::$base_css is right and is left alone.
     content   takes the remaining height, however much that is
     read-more  pushed to the BOTTOM of that content with margin-top: auto, so
               it sits on the same line across every card in the row no matter
               how long the titles above it run

   The slack ends up in one place — between the text and the action — instead of
   distorting the pictures, and the row reads as a row. */

.post-loop__card {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* A card in a row is as tall as the row, INCLUDING ONE WITH NO PICTURE.
   `height: 100%` above is a definite cross size, and a flex item with a
   definite cross size does not stretch — so the rule that was supposed to keep
   a row level only ever worked by accident, because cards with the same parts
   come out the same height on their own. The moment a post without a featured
   image landed in a row it showed: measured on the blog landing page, the
   card-grid band rendered two cards 548px tall and the imageless one 275px,
   ending halfway up the row with page background beneath it.

   `align-self: stretch` against an auto height is what actually levels a flex
   line. The shorter card's slack then goes where all the other slack goes —
   between the text and the read-more, which margin-top: auto already pins to
   the foot. */
.post-loop__grid > .post-loop__card {
    height: auto;
    align-self: stretch;
}

/* Fixed: the picture keeps its ratio so a row of them matches. */
.post-loop__card-image {
    flex: 0 0 auto;
}

.post-loop__card-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    /* Children keep their own width. A flex column stretches its items across
       the cross axis by default, which turned the category badge — an
       inline-block pill — into a full-width bar across the bottom of every
       overlay card. Making the content a column to pin the read-more link is
       not a licence to resize everything inside it. */
    align-items: flex-start;
}

/* The line that makes the actions align. Everything above keeps its natural
   height; this takes all the slack, so the link sits at the card's foot
   whatever the title above it did. */
.post-loop__card-read-more {
    margin-top: auto;
}

/* The overlay card is a full-bleed picture with text over it, so it fills its
   cell rather than stacking image above content. */
.post-loop__card--overlay {
    height: 100%;
}

/* Titles run to three lines and stop.
   Rick, 2026-09-15: "Titles are max 3 lines."
   A twenty-one word title otherwise pushes the excerpt and the read-more down
   by two lines in one card and not its neighbours, which is the thing that
   breaks a row even when every card is the same height. Clamping at the title
   keeps every card's content starting and ending on the same lines. */
.post-loop__card-title {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ==========================================================================
   Bento: images match across a row even though the tiles do not
   ==========================================================================

   A bento row deliberately mixes tile widths — a 2-wide tile beside a 1-wide
   one. With a fixed 16/9 ratio the wider tile's picture is proportionally
   taller, so the two images in that row did not line up, which breaks the rule
   that images match across a row.

   A ratio cannot satisfy it, because the tiles are different widths by design.
   A share of the tile's HEIGHT can: every tile in a bento row is the same
   height (the grid row sets it), so the same percentage of it is the same
   number of pixels whatever the tile's width. The picture then crops wider
   rather than growing taller. */

.post-loop__bento-item .post-loop__card-image {
    height: 46%;
    flex: 0 0 auto;
}

.post-loop__bento-item .post-loop__card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* The featured tile is a full-bleed overlay — it has no separate image band to
   size, and giving it one would crop the picture it exists to show. */
.post-loop__bento-item--featured .post-loop__card-image {
    height: 100%;
}

/* ==========================================================================
   The excerpt yields; the link never does
   ==========================================================================

   Rick, 2026-09-15: "the excerpt link is pusing the readmore link out of view
   on some of them."

   A bento tile's height comes from its grid row, not from its contents, so a
   card carrying a two-line badge, a three-line title, a date AND an excerpt can
   want more room than the tile has. Everything inside was equally unyielding,
   so the overflow fell off the bottom — and what sits at the bottom is the
   Read More. The card with the longest title lost its link entirely while its
   neighbour kept one, which is the row reading as broken.

   Ranked by what a reader can afford to lose:

     read-more   NEVER shrinks. It is the action; a card without it is a dead
                 end, and rule 3 cannot hold if some cards have no link to align.
     title       already clamped at three lines, so it is bounded.
     excerpt     the one part that can lose its last line without costing the
                 reader anything — it is a preview, not the content.

   So the excerpt shrinks and clips, capped at four lines so in most cards it
   never has to. The link stays put. */

.post-loop__card-content {
    min-height: 0;
    overflow: hidden;
}

.post-loop__card-excerpt {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* THE CLAMP IS THE AUTHORITY ON HEIGHT, not flex. With `flex: 0 1 auto`
       the two were fighting: line-clamp put its ellipsis at line two while the
       flex-assigned height still let a third line paint underneath, half cut
       off by the overflow rule. The clamp sizes the box; flex leaves it alone.
       Safe now that the small tile's budget actually fits its contents — see
       the arithmetic below. */
    flex: 0 0 auto;
}

.post-loop__card-read-more {
    flex: 0 0 auto;
    margin-top: auto;
}

/* ==========================================================================
   Nothing clips mid-line
   ==========================================================================

   Making the excerpt yield stopped the Read More falling off the bottom, but
   the overflow then landed on the text instead: a card whose category wrapped
   to two lines had its title and excerpt sliced through the middle of the
   letterforms. That is not better than losing the link, it is a different
   ugly.

   Two causes, both budget. A long category name took a whole extra line before
   the title even started, and the small bento tiles have less room than the
   clamps assumed. Fix the budget and the clip never fires — `overflow: hidden`
   on the content stays, but as a backstop rather than as the mechanism. */

/* One line, always. A category is a label; if it is too long to fit it should
   end in an ellipsis, not consume a line of the card. */
.post-loop__card-badge {
    display: inline-block;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A `small` card carries the same furniture as a full one in roughly half the
   height, so its clamps are tighter. Three lines remains the ceiling
   everywhere; this is under it.

   KEYED ON THE CARD, NOT ON BENTO. It was written for the bento tiles and the
   featured-grid secondaries are the same thing at a different scale — both are
   rendered at size `small`. Scoping it to bento meant the blog landing page's
   top band had no cap, so putting an excerpt back doubled the band's height
   and the excerpt had to come out again. A clamp is what makes an excerpt cost
   a KNOWN amount of height instead of an unbounded one. */
.post-loop__card--small .post-loop__card-title {
    -webkit-line-clamp: 2;
}

.post-loop__card--small .post-loop__card-excerpt {
    -webkit-line-clamp: 2;
}

/* The small bento tile's budget, done as arithmetic rather than guessed at.
   A 1x1 tile in a 5x2 pattern is about 350px tall. At a 46% image that leaves
   ~189px for a badge (24), a two-line title (48), a date (20), a two-line
   excerpt (44), a link (24) and padding (32) — about 192px. It was always
   going to clip by a few pixels, which is why tightening the clamps twice did
   not fix it: the clamp was never the binding constraint, the box was.

   So the tile gives up the two things it can afford to. The picture takes a
   smaller share, and the date goes: in a tile this size the date is the least
   useful thing present, and the excerpt it was crowding out is the thing Rick
   asked for. Title, excerpt and link all survive intact. */

.post-loop__bento-item--small .post-loop__card-image {
    height: 38%;
}

.post-loop__bento-item--small .post-loop__card-meta {
    display: none;
}

/* ==========================================================================
   Two height problems that were being treated as text problems
   ==========================================================================

   THE CLAMP BLEED. -webkit-line-clamp puts its ellipsis at the right line but
   does not by itself stop the box being taller, so a third line kept painting
   under the ellipsis and getting half cut by the overflow rule. Five attempts
   went at it as a clamp problem; it is a height problem. An explicit max-height
   in the element's own line-height units leaves no room for the extra line to
   paint in, whatever the clamp does. */

.post-loop__card-excerpt {
    line-height: 1.5;
    max-height: calc(4 * 1.5em);
}

.post-loop__card--small .post-loop__card-excerpt {
    max-height: calc(2 * 1.5em);
}

/* THE SLACK, AND WHICH WAY IT RUNS.

   A featured-grid band is a lead beside a 2x2 of smaller cards, and one of the
   two has to decide the band's height. Letting the lead decide is what the
   first cut did, and it runs away: an overlay card's picture IS the card, the
   source is a portrait (687x1024 on the blog landing page), and in a 741px
   column that asks for 1104px with the secondaries stretching to match and
   nothing to fill the extra.

   Capping the lead at `aspect-ratio: 4/3` fixed that and caused the mirror
   defect, because a ratio on a grid item suppresses the stretch that would
   otherwise make it fill its row. Measured on the three mosaic bands of the
   blog landing page: the lead came to 555px and the secondaries to 867, 919
   and 919, leaving 312px, 364px and 454px of white down the left half of each
   band.

   So the secondaries decide, which is the right way round — their height is
   text, and text is the thing that actually has to fit. The lead carries no
   ratio and simply fills the row. The other half of this is in
   class-post-loop.php: the lead's picture is taken out of flow so that it
   contributes no height and cannot drag the row back up. That cannot be
   written here — base_css rules are emitted with the loop's id in front and
   win against anything in this file.

   min-height is the floor for the single-column layout, where there is no
   second column to take the height from. */

.post-loop__featured-card {
    /* No aspect-ratio. A ratio on a grid item suppresses the stretch that makes
       it fill its row, which is what left the void. The lead is sized by the
       row, and the row is sized by the four cards beside it. */
    min-height: 15rem;
}

.post-loop__featured-card > .post-loop__card {
    height: 100%;
}

/* A loop that carries its own heading (close research KG3: the read-next row
   puts its head in the loop's header rows, so a loop with too few posts takes
   its heading with it). The heading group takes the row, and a group's worth
   of air separates it from the cards. */
.post-loop__header:has(> .post-loop__row > .simple-section) {
    margin-bottom: 2rem;
}

.post-loop__header > .post-loop__row > .simple-section {
    flex: 1 1 100%;
}
