/**
 * Blog, archive and search — post cards, and the single post.
 *
 * WHAT WAS WRONG
 *
 * The query loop emitted a featured image, a title, a meta row and an excerpt as
 * four loose blocks in a grid cell. No card, no fill, no edge: the only thing
 * separating one post from the next was the grid gap, so at two columns the eye
 * read across the gap and paired the wrong title with the wrong image. Search and
 * index had no images at all and ran as an undifferentiated list of title/date/
 * excerpt — three of the eight templates on this site looked like a different,
 * unstyled site.
 *
 * These are the same cards as everywhere else: 4:3 photo, rounded, two-layer
 * shadow, text below. The one addition is the stretched link, borrowed from the
 * homepage fleet tiles — a post card whose photo and title are separate links
 * gives a screen-reader user two stops per post for one destination.
 *
 * SELECTOR NOTE: these hang off .pd-posts on the query block rather than off
 * .wp-block-post-template, because the same classes have to work whether the loop
 * is a grid (blog, archive) or a single column (search).
 */

.pd-posts .wp-block-post-template {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( min( 320px, 100% ), 1fr ) );
	gap: var( --wp--preset--spacing--50 );

	/* Core's post-template carries its own list styling. */
	padding-left: 0;
	list-style: none;
}

/* One column for search results — a result list is read down, not scanned across. */
.pd-posts--list .wp-block-post-template {
	grid-template-columns: 1fr;
	gap: var( --wp--preset--spacing--40 );
}

.pd-posts .wp-block-post-template > li {
	/**
	 * Kill core's flow-layout block margin — the grid gap owns spacing.
	 *
	 * The post template renders as `is-layout-flow`, so core puts a
	 * margin-block-start on every child except the first. In a grid that margin
	 * pushes each card down inside its own cell: the first card in a row started
	 * 16px above its neighbours and stretched 16px taller to reach the same
	 * bottom edge, so no row of cards ever lined up. Measured before the fix —
	 * card 1 top 403.6 / height 557, cards 2 and 3 top 419.6 / height 541.
	 */
	margin-top: 0;

	/* Containing block for the stretched link. */
	position: relative;

	display: flex;
	flex-direction: column;

	padding-bottom: 1.5rem;
	border-radius: 14px;
	overflow: hidden;

	background-color: var( --wp--preset--color--base );

	box-shadow:
		0 1px 3px rgba( 0, 0, 0, 0.05 ),
		0 10px 24px rgba( 0, 0, 0, 0.06 );

	--pd-post-pad: 1.5rem;
}

/**
 * Featured image.
 *
 * A post with no featured image renders nothing here rather than a gap: core
 * omits the block entirely, and because the card's padding lives on the text
 * rather than the card, the title simply becomes the first thing in it.
 */
.pd-posts .wp-block-post-featured-image {
	margin: 0 0 1.25rem;
	background-color: var( --wp--preset--color--cream );

	/**
	 * WHY min-height AND overflow ARE HERE.
	 *
	 * The block already sets `aspect-ratio: 4/3` inline on this figure, and the
	 * image inside carries `height: 100%; object-fit: cover`. That should be the
	 * whole story — but the card is a flex column, which makes the figure a flex
	 * item, and a flex item's `min-height: auto` refuses to shrink below its
	 * content. The image's intrinsic height is larger than the 4:3 box on most of
	 * these photos, so the box lost and every card kept its photo's natural ratio:
	 * a 636x567 image and a 610x614 image side by side put their titles 46px
	 * apart, which is exactly the raggedness the cards exist to prevent.
	 *
	 * min-height: 0 lets the ratio win; overflow clips what cover pushes out.
	 */
	flex: 0 0 auto;
	min-height: 0;
	overflow: hidden;
}

.pd-posts .wp-block-post-title {
	margin: 0 var( --pd-post-pad );
	font-size: 1.25rem;
	line-height: 1.3;
	text-wrap: balance;
}

.pd-posts .wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}

/**
 * Stretched link — the whole card is the hit area, using the one anchor already
 * in the markup. Same technique as .pd-rig-card__title in rigs.css; see the note
 * there for why this beats linking the image and the title separately.
 */
.pd-posts .wp-block-post-title a::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 14px;
}

.pd-posts .wp-block-post-template > li:hover .wp-block-post-title a {
	color: var( --wp--preset--color--primary );
	text-decoration: underline;
}

.pd-posts .wp-block-post-title a:focus-visible {
	outline: none;
}

.pd-posts .wp-block-post-title a:focus-visible::after {
	outline: 3px solid var( --wp--preset--color--primary );
	outline-offset: 3px;
}

/* Meta row — date, author, category. */
.pd-posts .pd-post-meta {
	margin: 0.6rem var( --pd-post-pad ) 0;
	font-size: 0.8125rem;
	opacity: 0.75;
}

/**
 * The excerpt block holds both the text and the "Read More" link, and it is the
 * card's only elastic element — so it does the growing, which puts every card's
 * action on the same line as its neighbours' regardless of how much text is above
 * it. Without this the link sits directly under a short excerpt and a screen away
 * from a long one, in the same row.
 *
 * Excerpt length itself is capped in the templates (excerptLength: 26) rather than
 * clamped here: truncating in CSS still ships the full text to the browser and
 * still lets a screen reader read all of it, so the card looks tidy while
 * announcing a paragraph nobody can see.
 */
.pd-posts .wp-block-post-excerpt {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;

	margin: 0.75rem var( --pd-post-pad ) 0;
}

.pd-posts .wp-block-post-excerpt__more-text {
	margin: 0;
	padding-top: 0.6rem;

	/* Pushes the action to the foot of the card. */
	margin-top: auto;
}

.pd-posts .wp-block-post-excerpt__excerpt {
	font-size: 0.9375rem;
	line-height: 1.65;
	opacity: 0.85;
}

/**
 * "Read More »" sits inside the excerpt block as a link. It is raised out of the
 * paragraph flow so it reads as the card's action rather than as the end of the
 * sentence — and it is NOT given the stretched-link treatment, because the card
 * already has one and two overlapping hit areas is a debugging session waiting to
 * happen.
 */
.pd-posts .wp-block-post-excerpt__more-link {
	display: inline-block;
	color: var( --wp--preset--color--primary-darker );
	font-weight: 700;
	text-decoration: none;
}

.pd-posts .wp-block-post-excerpt__more-link:hover,
.pd-posts .wp-block-post-excerpt__more-link:focus {
	text-decoration: underline;
}

/* Pagination — centred, with the numbers reading as a set rather than a sentence. */
.pd-posts .wp-block-query-pagination {
	gap: 0.5rem;
	align-items: center;
	justify-content: center;
	margin-top: var( --wp--preset--spacing--60 );
	font-weight: 600;
}

.pd-posts .wp-block-query-pagination a {
	text-decoration: none;
}

.pd-posts .wp-block-query-pagination a:hover {
	text-decoration: underline;
}

.pd-posts .wp-block-query-pagination-numbers .page-numbers {
	display: inline-grid;
	place-items: center;
	min-width: 2.25rem;
	height: 2.25rem;
	padding: 0 0.5rem;
	border-radius: 8px;
}

.pd-posts .wp-block-query-pagination-numbers .page-numbers.current {
	background-color: var( --wp--preset--color--primary );
	color: var( --wp--preset--color--base );
}

/* Empty state — a sentence alone on a white screen reads as a broken page. */
.pd-posts .wp-block-query-no-results {
	max-width: 44ch;
	margin-inline: auto;
	padding: var( --wp--preset--spacing--50 );
	border-radius: 14px;
	background-color: var( --wp--preset--color--cream );
	text-align: center;
}

/**
 * Single post.
 *
 * Body copy at a measure, and the elements a post actually contains — headings,
 * lists, quotes, images — given the spacing they need. Without this the post
 * content inherits only theme.json's global type and runs to the template's full
 * width, which is fine for a landing page built from full-bleed bands and wrong
 * for eight paragraphs of prose.
 */
.pd-post-content {
	font-size: 1.0625rem;
	line-height: 1.75;
}

.pd-post-content > * {
	max-width: 68ch;
	margin-inline: auto;
}

/* Media and quotes are allowed to break the measure. */
.pd-post-content > .wp-block-image,
.pd-post-content > .wp-block-embed,
.pd-post-content > .wp-block-gallery,
.pd-post-content > .wp-block-video {
	max-width: 100%;
}

.pd-post-content > .wp-block-image img {
	border-radius: 12px;
}

/**
 * A self-hosted video in a post — the core Video block.
 *
 * Added 2026-09-04 for the OB Pier project video in the GeoEngineers post. The
 * block itself is added in wp-admin (it is post content, not a pattern), so this
 * is the theme's whole contribution: making a bare <video controls> look like it
 * belongs on this site rather than like a browser default dropped into prose.
 *
 * Same treatment as the About page's Vimeo frame in video.css — rounded, on a dark
 * ground, lifted — so a native player and an embedded one read as the same kind of
 * object. The dark ground also covers the moment before the poster paints, and any
 * pillarboxing if a clip's ratio does not match its poster.
 *
 * `figure.wp-block-video` is tag-qualified at (0,1,1): core's own block style is
 * `.wp-block-video` at (0,1,0) and is enqueued after the theme, so a bare class
 * here would tie and lose. The rule below the figure needs nothing beyond
 * `.wp-block-video video` because core sets no width on the element itself.
 */
.pd-post-content > figure.wp-block-video {
	margin-block: 2.25rem;
	border-radius: 14px;
	overflow: hidden;
	background-color: var( --wp--preset--color--dark );
	box-shadow:
		0 1px 3px rgba( 0, 0, 0, 0.06 ),
		0 18px 40px rgba( 0, 0, 0, 0.16 );
}

.pd-post-content .wp-block-video video {
	display: block;
	width: 100%;
	height: auto;
}

/* Core centres a caption under the video; the post's captions are otherwise
   left-aligned prose, so this one follows them. */
.pd-post-content .wp-block-video figcaption {
	margin: 0.6rem 0 0;
	padding-inline: 0.25rem;
	text-align: left;
	font-size: 0.9rem;
	opacity: 0.75;
}

.pd-post-content h2,
.pd-post-content h3 {
	margin-top: 2.25rem;
}

.pd-post-content > .wp-block-quote {
	padding-left: 1.25rem;
	border-left: 4px solid var( --wp--preset--color--gold );
	font-size: 1.125rem;
}

.pd-post-content li {
	margin-bottom: 0.4rem;
}

/**
 * Search results — horizontal cards.
 *
 * The grid cards work because they are ~380px wide, which makes a 4:3 photo about
 * 285px tall. In the single-column results list the same card is 820px wide, so
 * the same photo becomes 615px of image above every result — one result per
 * screen, and a page of them reads as a slideshow rather than a list of answers.
 *
 * Photo left at a fixed width, text right. The row is as tall as its text, and the
 * photo fills whatever that turns out to be.
 *
 * WHY search.html's featured image DOES NOT SET aspectRatio, while the grid
 * templates do: the block writes that attribute out as an inline `aspect-ratio`
 * on the figure, and inline styles cannot be overridden from a stylesheet without
 * !important. A fixed ratio is right for a grid tile and wrong for a row that
 * needs to be as tall as its text, so the ratio is left to CSS here — which is
 * also why the two rules below have to restate width/height/object-fit that the
 * block would otherwise have set inline.
 */

.pd-posts--list .wp-block-post-featured-image {
	/* Mobile, and the fallback before the grid rule below takes over. */
	aspect-ratio: 16 / 9;
	overflow: hidden;
}

/* (0,2,1) beats core's `.wp-block-post-featured-image :where(img) { height: auto }`
   at (0,1,1) — core's block styles load after the theme's, so a tie loses. */
.pd-posts--list .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
@media ( min-width: 640px ) {
	/**
	 * TWO children, not five.
	 *
	 * search.html wraps the title, meta and excerpt in .pd-post-body so this row
	 * is a two-column grid of [photo][text]. The obvious alternative — leaving the
	 * five blocks as siblings and spanning the figure with `grid-row: 1 / -1` —
	 * does not work: -1 counts back from the last line of the EXPLICIT grid, and
	 * these rows are implicit, so the figure spans one row and the card ends up
	 * with a thumbnail above a band of dead space.
	 */
	.pd-posts--list .wp-block-post-template > li {
		display: grid;
		grid-template-columns: 240px 1fr;
		align-items: stretch;
		padding-bottom: 0;
	}

	.pd-posts--list .wp-block-post-featured-image {
		/* Height comes from the row, not from a ratio — dropping the ratio set
		   above is what lets the photo stretch to the text beside it. */
		aspect-ratio: auto;
		height: 100%;
		margin: 0;
	}

	.pd-posts--list .pd-post-body {
		display: flex;
		flex-direction: column;
		padding: 1.5rem;
	}

	/* The body wrapper owns the padding now, so the blocks inside drop the inline
	   margin they carry in the grid cards. */
	.pd-posts--list .pd-post-body > * {
		margin-inline: 0;
	}

	/**
	 * A result with no featured image — a Page, usually — has no figure to fill
	 * the first column, and would otherwise sit in a 240px indent with nothing
	 * beside it. :has() is what lets the card know which of the two it is.
	 */
	.pd-posts--list .wp-block-post-template > li:not( :has( .wp-block-post-featured-image ) ) {
		grid-template-columns: 1fr;
	}
}

/**
 * Previous / next post links under a single post.
 *
 * New: the template previously ended at the last paragraph, so the only way on
 * from a post was the browser's back button. Given as two plain links rather than
 * cards — they are navigation, and a post's own content should stay the loudest
 * thing on the page.
 */
.pd-post-nav {
	max-width: 68ch;
	margin-inline: auto;
	padding-top: var( --wp--preset--spacing--50 );
	border-top: 1px solid rgba( 0, 0, 0, 0.1 );
	gap: var( --wp--preset--spacing--40 );
}

.pd-post-nav .wp-block-post-navigation-link {
	max-width: 45%;
	font-weight: 600;
}

.pd-post-nav .wp-block-post-navigation-link a {
	color: var( --wp--preset--color--primary-darker );
	text-decoration: none;
}

.pd-post-nav .wp-block-post-navigation-link a:hover,
.pd-post-nav .wp-block-post-navigation-link a:focus {
	text-decoration: underline;
}

/* The next link sits hard right so the pair reads as a pagination row. */
.pd-post-nav .post-navigation-link-next {
	text-align: right;
}
