/*
 * bpd-two/media-mosaic — flexible image/video grid, "masonry" in the sense the client means it:
 * cells of different shapes and spans on one grid, not a true masonry column flow.
 *
 * WHAT THIS FILE DOES NOT DO: the grid itself. That is CORE's grid layout support
 * (`"layout":{"type":"grid"}` on the wrapping group), which emits grid-template-columns, the gap,
 * and every child's `grid-column: span N` / `grid-row: span N` from the block attributes. All of it
 * is driven by controls the client already has in the block sidebar — Grid "Columns"/"Minimum column
 * width" on the parent, and Column span / Row span at the foot of each cell's "Dimensions" panel.
 * (The editor does NOT label that group "Grid placement" — THEME-GUIDE.md says where to look.) Nothing here
 * duplicates or overrides any of that; re-declaring tracks would fight the editor controls and lose.
 *
 * WHY minimumColumnWidth IS SET ON THE PATTERN'S GRID: with it, core wraps each child's columnSpan
 * in a container query and drops the span once the grid is narrower than span x minimumColumnWidth
 * (wp-includes/block-supports/layout.php, "If columnSpan or columnStart is set, and the parent grid
 * is responsive"). That is the whole mobile story for column spans — no media query in this file,
 * and none wanted (CLAUDE.md rule 6: minmax()/container-driven over breakpoints).
 *
 * WHAT THIS FILE DOES: make the media inside a cell fill the cell, at a chosen shape. Two cases have
 * to work from the same rules:
 *   1. An ordinary cell, in a content-sized row. Its height is indefinite, so `height: 100%`
 *      resolves to `auto` and the frame's `aspect-ratio` decides the shape. The row then sizes to it.
 *   2. A cell spanning 2+ rows (scenario 2's full-height column). Its grid area has a definite
 *      height set by the OTHER column's cells, so `height: 100%` resolves against that and the frame
 *      fills exactly, gap included. `aspect-ratio` yields to the definite height, which is why the
 *      "Fill cell" style below exists as the explicit, non-accidental way to ask for this.
 * Both fall out of the same two declarations. Verified by measurement, not by eye — see PROGRESS.md.
 */

/* The cell is a grid so its single frame child stretches to the full cell in both axes. */
.bpd-media-mosaic__cell {
	display: grid;
	min-height: 0;
}

.bpd-media-frame {
	/* width:100% is load-bearing, not tidiness. A plain <div> frame fills its cell anyway, but
	   core/cover is a flex container with auto width; left to itself in a row where nothing else
	   sets the height, it shrink-wraps to its only child (the video controls, 32px) and then
	   aspect-ratio resolves the WRONG WAY — deriving width from that height instead of height from
	   width. Measured: a 4:3 cover in a 616px cell rendering 43x32. Pinning the width forces the
	   ratio to resolve height-from-width, which is the direction every shape style assumes. */
	width: 100%;
	height: 100%;
	min-height: 0;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--lg);
}

/*
 * BOTH PATTERNS NOW SHIP EVERY FRAME AS A core/cover (bpd_media_frame(), inc/pattern-helpers.php),
 * so a still is a `.wp-block-cover__image-background` — already absolutely positioned and
 * object-fit: cover by core, needing nothing from this file. The two core/image rules below are
 * therefore no longer exercised by the shipped patterns, and they stay anyway: the shape block
 * styles are registered on core/group as well as core/cover, so anyone building a frame by hand out
 * of a group + image gets the same fill behaviour. Deleting them would silently break that path.
 */

/*
 * core/image renders a <figure> between the frame and the <img>, and it is content-height by
 * default — so without this the image sizes itself and leaves the frame's bottom empty (measured:
 * a 4:3 frame of 462px holding a 344px image). Stretching the figure is what makes `height: 100%`
 * on the <img> below mean anything. The margin reset is core's own .wp-block-image bottom margin,
 * which otherwise pushes the image up by ~5px inside the frame (measured: 697px in a 702px frame).
 */
.bpd-media-frame > .wp-block-image {
	height: 100%;
	margin: 0;
}

/*
 * Fill the frame and crop rather than letterbox — the frame's shape is the design decision, the
 * source image's own proportions are not.
 *
 * The `.wp-block-image` in this selector is load-bearing, not decoration. Core ships
 * `.wp-block-image img { height: auto }`, which is specificity (0,1,1) — exactly the same as a bare
 * `.bpd-media-frame img`. A tie is resolved by source order, so that version won on one pattern and
 * LOST on the other (measured: a 519px frame holding a 217px image in media-caption-grid, while the
 * identical markup filled correctly in media-mosaic). Going to (0,2,1) makes it win everywhere, on
 * merit rather than on enqueue order. Do not simplify this selector back.
 */
.bpd-media-frame .wp-block-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * Shape styles. Registered on core/group AND core/cover (functions.php) so an image cell and a video
 * cell offer the identical dropdown. They set only aspect-ratio: the fill/crop behaviour above is
 * shared, so a shape change never needs anything else changed with it.
 *
 * A cell that spans rows should carry "Fill cell", which sets no ratio and lets the definite grid-area
 * height win. Leaving a ratio on a row-spanning cell is not broken — the ratio simply loses to the
 * definite height — but saying "fill" makes the intent legible to the next person in the editor.
 */
.bpd-media-frame.is-style-bpd-media-16-9 { aspect-ratio: 16 / 9; }
.bpd-media-frame.is-style-bpd-media-4-3  { aspect-ratio: 4 / 3; }
.bpd-media-frame.is-style-bpd-media-1-1  { aspect-ratio: 1 / 1; }
.bpd-media-frame.is-style-bpd-media-3-4  { aspect-ratio: 3 / 4; }
.bpd-media-frame.is-style-bpd-media-fill { aspect-ratio: auto; }

/*
 * Video cells. core/cover ships a 300px min-height default that would out-size a short frame and
 * break the row rhythm, so it is cleared here rather than per-instance in the block attributes —
 * a minHeight of 0 in the attributes reads as a mistake to anyone opening the editor.
 */
.bpd-media-frame.wp-block-cover {
	min-height: 0;
}

/*
 * FALLBACK SHAPE FOR A "FILL" VIDEO. An <img> has intrinsic dimensions to fall back on; a
 * core/cover has none, so a fill-styled cover with nothing to fill against collapses to its only
 * child — the video controls. Measured 2026-08-27 on media-caption-grid: 343x32 at 375px, and the
 * same 32px at 600 and 900, because a full-width cell is alone in its subgrid row at those widths
 * and no sibling sets the row height. Only 1440 looked right, which is why the first pass missed it.
 *
 * This declares a ratio rather than a min-height on purpose: `height: 100%` above still wins
 * wherever the grid area HAS a definite height (a stretched subgrid track, a row-spanning mosaic
 * cell), because an explicit height makes aspect-ratio inapplicable. So the ratio is used only in
 * the case that was broken — nothing to fill — and desktop alignment is untouched. Verified both
 * ways at 375/600/900/1440.
 *
 * Matched by EXCLUSION rather than by naming the fill style. "Default" is also a no-ratio style and
 * collapsed exactly the same way, which this rule missed on its first pass: /the-one/ rendered its
 * two default-styled video frames at 519px on 1440 and 32px at every width below (issue #192). Any
 * style that sets a real ratio is excluded and keeps it; everything else — Default, Fill, or a
 * variation added later — falls back to 16/9 instead of collapsing to its controls.
 */
.bpd-media-frame.wp-block-cover:not(.is-style-bpd-media-16-9):not(.is-style-bpd-media-4-3):not(.is-style-bpd-media-1-1):not(.is-style-bpd-media-3-4) {
	aspect-ratio: 16 / 9;
}

/*
 * A STILL FRAME CARRIES THE VIDEO CONTROLS BLOCK TOO, and must not show it.
 *
 * bpd_media_frame() puts bpd-two/hero-video-controls inside every cover, still or clip, so that
 * swapping an image for a video via core's Replace control yields working play/pause with no second
 * edit by the client. The block's own view.js already hides itself when it finds no <video>, but
 * that runs after paint; this hides it in the same pass as the rest of the page, so a still never
 * flashes a play button.
 *
 * :has() rather than a class, because the swap happens in the editor and changes only the cover's
 * media element — no attribute we could hang a class off changes with it, and asking the client to
 * toggle one by hand would give back exactly the friction this whole change removed.
 */
.bpd-media-frame.wp-block-cover:not(:has(video)) .bpd-hero-video-controls {
	display: none;
}

/*
 * Anchor bpd-two/hero-video-controls to the frame's bottom-right. Core centres and shrink-wraps
 * .wp-block-cover__inner-container, so an absolutely-positioned control inside it lands mid-frame
 * instead of pinned to the corner. Same fix, same reason, as media-cover.css's entry for the
 * case-study hero and growth cards — see that file's header for the full explanation.
 */
.bpd-media-frame .wp-block-cover__inner-container {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-self: stretch;
}

/* =============================================================================
 * bpd-two/media-caption-grid — media cells that carry their own caption.
 *
 * WHY IT IS A SEPARATE PATTERN FROM THE MOSAIC. The mosaic's cells are media only. This one's cells
 * are media + heading + copy, and the reason it exists at all is that the older
 * bpd-two/case-study-content-container hard-codes its rows (an intro, then a large cell, then a
 * fixed 2-up row). Clients kept having to delete rows they did not want, which is exactly the kind
 * of editing a non-WordPress user finds intimidating. Here there are no rows to manage: every cell
 * is independent, you add one by duplicating a cell and remove one by deleting it, and the layout
 * re-flows on its own.
 *
 * HOW THE ALIGNMENT WORKS — subgrid, per CLAUDE.md rule 6 ("when a pattern's children need to align
 * to a parent grid's tracks, use subgrid rather than re-declaring tracks"). Each cell spans two
 * parent rows and adopts them with `grid-template-rows: subgrid`: track 1 holds the media, track 2
 * the caption. Because the tracks belong to the PARENT, every media frame in a row ends at the same
 * y and every caption starts at the same y — regardless of how much copy each caption carries, and
 * regardless of the cells being different widths. That is the behaviour the design has (measured off
 * the RWJF SHIFT section: a 2/3 video and a 1/3 illustration, different aspect ratios, identical
 * heights, captions sharing a baseline) and it is the part a client could never reproduce by hand.
 *
 * The cell's `grid-row: span 2` lives HERE rather than in the block attributes on purpose: it is
 * structural, the client should never have to know about it, and a stray edit to it in the sidebar
 * would silently break the row alignment for the whole section.
 *
 * DELIBERATE SPECIFICITY FIGHT — read before "simplifying" this selector. Core emits a child's grid
 * placement as a generated class, `.wp-container-content-xxxx { grid-row: span N }`, specificity
 * (0,1,0). The selector below is (0,2,0), so it WINS and a Row span set in the sidebar is discarded.
 * That is intentional: the row axis here is spent on caption alignment, and a client-set row span
 * would break it for every cell in the section. Verified by probe (2026-08-27): setting Row span 4
 * rendered as `span 2` and the layout reflowed into ordinary rows.
 *
 * The cost is a control that appears to work and does not, so THEME-GUIDE.md says plainly that Row
 * span does nothing in this pattern and points at bpd-two/media-mosaic for a full-height cell. If
 * you ever need both behaviours in one pattern, it means a cell spanning 4 tracks with the media
 * across three and the caption in the fourth — possible, but it turns a one-number control into
 * something a non-WordPress editor will get wrong, which is why it was not built that way.
 * ============================================================================= */

.bpd-media-caption-grid > .bpd-mc-cell {
	grid-row: span 2;
	display: grid;
	grid-template-rows: subgrid;
	/* Without this the implicit column is max-content and a long caption overflows the cell. */
	grid-template-columns: minmax(0, 1fr);
	/* Media -> caption gap, matching the case-study content cells (Space/400). */
	gap: var(--wp--preset--spacing--400);
}

/* One column on mobile leaves each cell alone in its row pair, so there is no neighbour left to
   align to — and a caption-less cell just reserves an empty caption track plus the grid's row gap,
   reading as a hole under the image. Stacking normally there keeps the between-cell gap the only
   spacing. Same selector as above so it beats core's generated grid-row class. */
@media (max-width: 781px) {
	.bpd-media-caption-grid > .bpd-mc-cell {
		grid-row: auto;
		grid-template-rows: none;
	}
}

/*
 * Fallback for a browser without subgrid. The cell stops sharing the parent's tracks, so cross-cell
 * alignment is lost, but every cell still stacks media over caption correctly and nothing collapses
 * or overlaps — a graceful degradation, not a broken layout. Subgrid is in every current evergreen
 * browser; this is here so the failure mode is defined rather than discovered.
 */
@supports not (grid-template-rows: subgrid) {
	.bpd-media-caption-grid > .bpd-mc-cell {
		display: flex;
		flex-direction: column;
	}
}

/* A caption-less cell is a legitimate arrangement: delete the caption group and the media simply
   occupies its own track, still aligned with the captioned cells beside it. */
.bpd-mc-caption {
	min-width: 0;
}
