/**
 * Bluegrass Projects
 *
 * Self-contained on purpose. The Bluegrass theme has no theme.json and no CSS custom
 * properties of its own, and none of the comp's colours appear anywhere in it, so there
 * is nothing to inherit and everything here is declared locally.
 *
 * Every value is read off the Figma comp (file 7XZoK8znris4rCcBYvAkP5, node 1:2). Colours
 * are the comp's exact values and are never substituted or darkened.
 *
 * The tokens are declared on this plugin's own four top level classes rather than on
 * :root, so they cannot leak into the rest of an old classic theme, and so a later theme
 * redesign can override them in one place.
 */

.bgp-filter,
.bgp-grid,
.bgp-banner,
.bgp-single {
	/* Palette, straight off the comp. */
	--bgp-ink: #002e2c;
	--bgp-body: #404848;
	--bgp-line: #707978;
	--bgp-card-line: #bfc8c7;
	--bgp-sand: #fcf9f5;
	--bgp-white: #fff;
	--bgp-button: #07544a;

	--bgp-radius-card: 8px;
	--bgp-radius-pill: 12px;
	--bgp-radius-badge: 2px;
	--bgp-radius-button: 4px;

	--bgp-container: 1344px;
	/* What `alignwide` widens to on a single project. Not from the comp; no comp draws one. */
	--bgp-wide: 1600px;
	--bgp-gutter: 24px;

	/*
	 * The comp asks for Montserrat at 400, 500, 600 and 700, and for Hanken Grotesk on the
	 * pills and the Load More button.
	 *
	 * All four Montserrat weights are now real: 400 and 600 were added to the theme's
	 * existing Google Fonts request in lib/scripts.php on 2026-08-21, at the cost of a
	 * slightly larger response and no extra round trip. So the weights below match the comp
	 * exactly and nothing here is a substitution any more.
	 *
	 * Hanken Grotesk is still mapped onto Montserrat, which is the one remaining departure
	 * from the comp's type. It is a different face rather than a different weight, so the
	 * pills read very slightly wider than drawn. Adding the family would be a second font
	 * request, which is why it has not been done on spec.
	 *
	 * These stay as tokens rather than literals so a later type change is four lines here
	 * instead of a hunt through the file.
	 */
	--bgp-font: Montserrat, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--bgp-weight-regular: 400;
	--bgp-weight-medium: 500;
	--bgp-weight-semibold: 600;
	--bgp-weight-bold: 700;

	--bgp-transition: 150ms ease;
}

/* ---------------------------------------------------------------------------
 * Shared resets
 *
 * Scoped tightly and kept deliberately blunt. This plugin renders inside a 2020-era
 * classic theme whose stylesheet is 96KB of unscoped selectors, so anything not stated
 * here is at the mercy of a rule written for a blog sidebar.
 * ------------------------------------------------------------------------ */

.bgp-filter *,
.bgp-grid *,
.bgp-banner * {
	box-sizing: border-box;
}

/*
 * --bgp-container is the CONTENT width, not the box width, so the gutter is added to the
 * max-width rather than eaten out of it. The comp draws a 1344px content column inside a
 * 1600px frame, which is what puts the first card at x=128 and makes three cards with
 * 11px gaps land on 441px each. Letting the padding come out of 1344 instead gives 1296
 * of content, 440 margins that are 24px too wide, and cards 16px narrower than drawn.
 */
.bgp-filter__inner,
.bgp-grid__inner {
	max-width: calc(var(--bgp-container) + (2 * var(--bgp-gutter)));
	margin-inline: auto;
	padding-inline: var(--bgp-gutter);
	font-family: var(--bgp-font);
}

/* ---------------------------------------------------------------------------
 * Paragraph specificity
 *
 * Every rule below that styles a <p> carries its parent class as well as its own, and
 * that extra class is load bearing rather than tidy nesting.
 *
 * The theme has exactly one selector that can reach inside this plugin's markup:
 *
 *   .main p, .main li { font-size: 18px }
 *
 * and the theme's Gutenberg page template wraps the content in <main class="main">. That
 * selector scores one class and one element, so a single-class rule of ours LOSES to it,
 * and a one-class-plus-element rule only ties -- which also loses, because the theme's
 * stylesheet is enqueued after this one and a tie is decided by source order.
 *
 * Measured before this was added: the filter eyebrow and the card excerpt both rendered at
 * 18px against the comp's 16px, while the card meta line rendered at 18px and looked
 * correct purely by coincidence, since 18px is what the comp asks for there.
 *
 * Two classes beats one class plus one element, so the parent prefix is the whole fix.
 * ------------------------------------------------------------------------ */

/* ---------------------------------------------------------------------------
 * Browse by Service
 * ------------------------------------------------------------------------ */

.bgp-filter {
	background-color: var(--bgp-sand);
	padding-block: 48px;
}

/*
 * Full bleed WITHOUT viewport units.
 *
 * The usual way to bleed a band is width: 100vw with a negative margin, and the usual
 * result is a horizontal scrollbar, because 100vw includes the vertical scrollbar's width
 * and the container does not. A spread box-shadow paints the same colour past both edges
 * while the element keeps its layout width, so there is nothing to overflow. clip-path
 * trims the shadow vertically so it cannot bleed into the sections above and below.
 */
.bgp-filter.is-full-bleed {
	box-shadow: 0 0 0 100vmax var(--bgp-sand);
	clip-path: inset(0 -100vmax);
}

.bgp-filter .bgp-filter__eyebrow {
	margin: 0 0 21px;
	color: var(--bgp-ink);
	font-family: var(--bgp-font);
	font-size: 16px;
	font-weight: var(--bgp-weight-medium);
	line-height: 16px;
	letter-spacing: 1.2px;
	text-transform: uppercase;
}

.bgp-filter__pills {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.bgp-pill {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/*
	 * flex: 0 0 auto is load bearing, and specifically for the mobile strip below. A flex
	 * item shrinks before it overflows, so without this the pills squeeze into the width
	 * available and wrap their own labels, which looks exactly like the bug the strip is
	 * there to fix.
	 */
	flex: 0 0 auto;
	min-height: 44px;
	padding: 9px 21px;
	border: 1px solid var(--bgp-line);
	border-radius: var(--bgp-radius-pill);
	background-color: var(--bgp-white);
	color: var(--bgp-body);
	font-family: var(--bgp-font);
	font-size: 17px;
	/*
	 * line-height belongs on the anchor, not on the row. A theme rule targeting the
	 * element beats a value inherited from its parent, so setting this on .bgp-filter__pills
	 * would be silently overridden by the theme's own link styling.
	 */
	line-height: 20px;
	font-weight: var(--bgp-weight-regular);
	letter-spacing: 0.7px;
	text-align: center;
	text-decoration: none;
	transition: background-color var(--bgp-transition), border-color var(--bgp-transition), color var(--bgp-transition);
}

.bgp-pill:hover,
.bgp-pill:focus-visible {
	border-color: var(--bgp-ink);
	color: var(--bgp-ink);
	text-decoration: none;
}

.bgp-pill:focus-visible {
	outline: 2px solid var(--bgp-ink);
	outline-offset: 2px;
}

.bgp-pill.is-active,
.bgp-pill.is-active:hover,
.bgp-pill.is-active:focus-visible {
	border-color: var(--bgp-ink);
	background-color: var(--bgp-ink);
	color: var(--bgp-white);
}

/*
 * Below 782px the pills become a single swipeable row instead of wrapping.
 *
 * Carried over from the Anzac portfolio filter, where it was measured rather than guessed:
 * six labels this long wrap to four or five lines on a phone, which put the filter alone
 * above most of the first screen and pushed the first card off it. One scrolling row is
 * 62px at every width from 320 up.
 *
 * Deliberately NOT scroll-snapped. Snapping aligns a pill flush with the container edge,
 * which is what makes a strip look complete when it is not. Left free, a label is clipped
 * mid-word and that clipped label is the whole affordance that there is more to swipe to.
 */
@media (max-width: 781px) {
	.bgp-filter {
		padding-block: 32px;
	}

	.bgp-filter__pills {
		flex-wrap: nowrap;
		overflow-x: auto;
		/*
		 * The scrollbar is hidden because it would add its own height to a row whose whole
		 * purpose here is to stay one line tall. Below 782px the pointer is a finger, where
		 * scrollbars are overlay anyway.
		 */
		scrollbar-width: none;
		-ms-overflow-style: none;
		/* Matches the pill padding, so a pill scrolled to the edge is not flush against it. */
		padding-inline: 15px;
		margin-inline: -15px;
	}

	.bgp-filter__pills::-webkit-scrollbar {
		display: none;
	}
}

/* ---------------------------------------------------------------------------
 * The grid
 * ------------------------------------------------------------------------ */

.bgp-grid {
	padding-block: 56px;
}

.bgp-grid__heading {
	margin: 0 0 28px;
	color: var(--bgp-ink);
	font-family: var(--bgp-font);
	font-size: 32px;
	font-weight: var(--bgp-weight-bold);
	line-height: 40px;
}

.bgp-grid__items {
	display: grid;
	/* Column gap 11px and row gap 17px, both measured off the comp. */
	gap: 17px 11px;
	grid-template-columns: repeat(var(--bgp-columns, 3), minmax(0, 1fr));
}

.bgp-grid__items--cols-1 { --bgp-columns: 1; }
.bgp-grid__items--cols-2 { --bgp-columns: 2; }
.bgp-grid__items--cols-3 { --bgp-columns: 3; }
.bgp-grid__items--cols-4 { --bgp-columns: 4; }

/*
 * There is no mobile comp for the grid, so these two breakpoints are a judgement call.
 * 1100 is where three 441px cards stop fitting the 1344px container with its gutters, and
 * 782 matches the filter strip's breakpoint so the two change character together.
 */
@media (max-width: 1099px) {
	.bgp-grid__items {
		--bgp-columns: 2;
	}
}

@media (max-width: 781px) {
	.bgp-grid {
		padding-block: 40px;
	}

	.bgp-grid__items {
		--bgp-columns: 1;
	}
}

.bgp-grid .bgp-grid__empty {
	margin: 0;
	padding: 32px 0;
	color: var(--bgp-body);
	font-family: var(--bgp-font);
	font-size: 16px;
	font-weight: var(--bgp-weight-regular);
	line-height: 26px;
	/* Spans every column, so the message centres in the grid rather than in column one. */
	grid-column: 1 / -1;
}

.bgp-grid__more {
	display: flex;
	justify-content: center;
	margin-top: 44px;
}

/* Set by the script while a fetch is in flight, so a slow response is visible. */
.bgp-grid__items[aria-busy="true"] {
	opacity: 0.55;
	transition: opacity var(--bgp-transition);
}

/* ---------------------------------------------------------------------------
 * The card
 * ------------------------------------------------------------------------ */

.bgp-card {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border: 1px solid var(--bgp-card-line);
	border-radius: var(--bgp-radius-card);
	background-color: var(--bgp-sand);
	font-family: var(--bgp-font);
	transition: border-color var(--bgp-transition), transform var(--bgp-transition);
}

.bgp-card:hover {
	border-color: var(--bgp-ink);
}

.bgp-card__media {
	position: relative;
	/*
	 * The comp's photo is 439x320. Holding the ratio here rather than relying on a
	 * generated thumbnail size means every card is the same shape even before anyone
	 * regenerates thumbnails, and stays that shape if a source photo is the wrong crop.
	 */
	aspect-ratio: 439 / 320;
	overflow: hidden;
	background-color: var(--bgp-card-line);
}

.bgp-card__image {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Overrides the theme's own img rules, which set max-width and height auto. */
	max-width: none;
}

.bgp-card__image--placeholder {
	background-color: var(--bgp-card-line);
}

.bgp-card__badge {
	position: absolute;
	top: 16px;
	left: 16px;
	display: inline-flex;
	align-items: center;
	gap: 9px;
	padding: 7px 12px;
	border-radius: var(--bgp-radius-badge);
	/*
	 * The comp's value. Note this is a 90% tint over a photograph, so it has no fixed
	 * contrast ratio: the badge text's legibility depends on the photo underneath. Flagged
	 * rather than solved, because solving it means changing a comp colour.
	 */
	background-color: rgba(0, 46, 44, 0.9);
	color: var(--bgp-white);
	font-size: 14px;
	font-weight: var(--bgp-weight-semibold);
	line-height: normal;
	text-transform: uppercase;
}

.bgp-card__badge .bgp-icon--award {
	width: 15px;
	height: 20px;
	flex: 0 0 auto;
}

.bgp-card__body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: 8px;
	padding: 32px 32px 35px;
}

.bgp-card__title {
	margin: 0;
	color: var(--bgp-ink);
	font-family: var(--bgp-font);
	font-size: 24px;
	font-weight: var(--bgp-weight-bold);
	line-height: 32px;
}

.bgp-card__title a {
	color: inherit;
	text-decoration: none;
}

/*
 * The whole card is one link, and this is the mechanism.
 *
 * There is exactly ONE anchor per card, the title's, stretched over the card by this
 * pseudo element. The photo and the View Project text are deliberately not links: two
 * links to the same place would put the destination in the tab order twice and read it
 * out twice to a screen reader.
 *
 * .bgp-card is position: relative and is this element's nearest positioned ancestor, so
 * unlike the Anzac cards there is no core layout wrapper in the way.
 */
.bgp-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

/*
 * Focus lands on the stretched pseudo element, so the ring outlines the whole card rather
 * than just the words of the title. Done this way rather than with :has() so it works
 * without relying on selector support.
 */
.bgp-card__title a:focus-visible {
	outline: none;
}

.bgp-card__title a:focus-visible::after {
	outline: 3px solid var(--bgp-ink);
	outline-offset: -3px;
	border-radius: var(--bgp-radius-card);
}

.bgp-card .bgp-card__meta {
	margin: 0;
	color: var(--bgp-ink);
	font-size: 18px;
	font-weight: var(--bgp-weight-medium);
	line-height: 1.4;
}

.bgp-card .bgp-card__excerpt {
	margin: 0;
	color: var(--bgp-body);
	font-size: 16px;
	font-weight: var(--bgp-weight-regular);
	line-height: 26px;
}

.bgp-card__cta {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	/*
	 * margin-top auto pins the call to action to the bottom of the card, so a short
	 * excerpt and a long one give the same shaped card. The comp cannot show this because
	 * every card in it has identical copy.
	 */
	margin-top: auto;
	padding-top: 17px;
	color: var(--bgp-ink);
	font-size: 16px;
	font-weight: var(--bgp-weight-semibold);
	line-height: 20px;
	letter-spacing: 0.7px;
}

.bgp-card__cta .bgp-icon--arrow {
	width: 12px;
	height: 12px;
	flex: 0 0 auto;
	transition: transform var(--bgp-transition);
}

.bgp-card:hover .bgp-card__cta .bgp-icon--arrow {
	transform: translateX(3px);
}

/* ---------------------------------------------------------------------------
 * The button
 * ------------------------------------------------------------------------ */

.bgp-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 18px 32px;
	/*
	 * No border, deliberately. The comp draws no stroke, and a 1px one made the button
	 * 58px tall against the comp's 56: 18 + 20 line-height + 18 is exactly 56, and the
	 * border sat outside that. The ghost variant below needs a visible edge, so it uses an
	 * inset shadow rather than a border, which keeps both variants the same height.
	 */
	border: 0;
	border-radius: var(--bgp-radius-button);
	background-color: var(--bgp-button);
	box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
	color: var(--bgp-white);
	font-family: var(--bgp-font);
	font-size: 16px;
	font-weight: var(--bgp-weight-bold);
	line-height: 20px;
	letter-spacing: 0.7px;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--bgp-transition), color var(--bgp-transition);
}

/*
 * Inverts on hover rather than darkening. White on --bgp-button measures 8.84:1, and the
 * inverse, --bgp-button on white, is the same ratio, so both states pass AAA rather than
 * one of them being a near miss.
 */
.bgp-button:hover,
.bgp-button:focus-visible {
	background-color: var(--bgp-white);
	color: var(--bgp-button);
	text-decoration: none;
}

.bgp-button:focus-visible {
	outline: 2px solid var(--bgp-ink);
	outline-offset: 2px;
}

.bgp-button[aria-disabled="true"] {
	opacity: 0.6;
	pointer-events: none;
}

.bgp-button--ghost {
	background-color: transparent;
	/* Inset rather than a border, so it matches the solid button's 56px height. */
	box-shadow: inset 0 0 0 1px var(--bgp-button);
	color: var(--bgp-button);
}

.bgp-button--ghost:hover,
.bgp-button--ghost:focus-visible {
	background-color: var(--bgp-button);
	color: var(--bgp-white);
}

/* ---------------------------------------------------------------------------
 * Single project
 * ------------------------------------------------------------------------ */

.bgp-banner {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: 420px;
	padding-block: 56px;
	background-color: var(--bgp-ink);
	background-position: center;
	background-size: cover;
	background-repeat: no-repeat;
}

/*
 * A scrim rather than a flat opacity on the photo, so the text has a predictable
 * background whatever the image. The gradient is heavier at the bottom, where the copy is.
 */
.bgp-banner__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(0, 46, 44, 0.25) 0%, rgba(0, 46, 44, 0.85) 100%);
}

.bgp-banner:not(.has-image) .bgp-banner__scrim {
	background: none;
}

.bgp-banner__inner {
	position: relative;
	width: 100%;
	max-width: calc(var(--bgp-container) + (2 * var(--bgp-gutter)));
	margin-inline: auto;
	padding-inline: var(--bgp-gutter);
	font-family: var(--bgp-font);
	color: var(--bgp-white);
}

.bgp-banner__badge {
	position: static;
	margin-bottom: 16px;
}

.bgp-banner__title {
	margin: 0;
	color: var(--bgp-white);
	font-family: var(--bgp-font);
	font-size: clamp(32px, 5vw, 56px);
	font-weight: var(--bgp-weight-bold);
	line-height: 1.1;
}

.bgp-banner .bgp-banner__meta {
	margin: 14px 0 0;
	color: var(--bgp-white);
	font-size: 18px;
	font-weight: var(--bgp-weight-medium);
	line-height: 1.4;
}

.bgp-banner .bgp-banner__excerpt {
	max-width: 60ch;
	margin: 16px 0 0;
	color: var(--bgp-white);
	font-size: 18px;
	font-weight: var(--bgp-weight-regular);
	line-height: 1.6;
}

/*
 * The single project wrapper is FULL WIDTH, and each piece inside constrains itself.
 *
 * This is the block theme "constrained layout" model, and adopting it is what makes `alignwide`
 * and `alignfull` work on a project without a single viewport unit. The usual classic-theme
 * trick for a full-bleed block is `width: 100vw` with a negative margin, and the usual result is
 * a horizontal scrollbar, because 100vw counts the vertical scrollbar and the container does not.
 * Starting full width and narrowing inwards has nothing to overflow.
 *
 * A Standard project renders identically to before. The difference only shows when a block opts
 * out with Wide or Full.
 */
.bgp-single {
	padding-block: 48px 72px;
	font-family: var(--bgp-font);
}

/*
 * Full Width and Full Canvas hand vertical rhythm to the content itself, which is the point of
 * choosing them: a page built from cover and group blocks supplies its own spacing, and any
 * padding here would show as a gap above the first full-bleed section.
 */
.bgp-single--unconstrained {
	padding-block: 0;
}

.bgp-single--unconstrained .bgp-single__content > * + * {
	margin-top: 0;
}

/* The readable column, for the chrome that wants it. */
.bgp-project-services,
.bgp-single__back {
	max-width: calc(var(--bgp-container) + (2 * var(--bgp-gutter)));
	margin-inline: auto;
	padding-inline: var(--bgp-gutter);
}

.bgp-project-services {
	margin-bottom: 32px;
}

.bgp-single .bgp-project-services__label {
	margin: 0 0 12px;
	color: var(--bgp-ink);
	font-size: 16px;
	font-weight: var(--bgp-weight-medium);
	line-height: 16px;
	letter-spacing: 1.2px;
	text-transform: uppercase;
}

.bgp-single__content {
	color: var(--bgp-body);
	font-size: 18px;
	font-weight: var(--bgp-weight-regular);
	line-height: 1.7;
}

/*
 * Constrained layout: every direct child gets the readable column, and Wide or Full widens it.
 *
 * The alignment CSS is ours on purpose. The theme never calls add_theme_support( 'align-wide' )
 * and has zero alignfull or alignwide rules in its 96KB stylesheet. The Maritz page uses
 * `alignfull` eighteen times and renders correctly on the live site only because Kadence Blocks
 * happens to be active and ships alignment CSS. Depending on that is depending on an accident,
 * so a project's own content carries its rules here instead.
 */
.bgp-single__content > * {
	max-width: calc(var(--bgp-container) + (2 * var(--bgp-gutter)));
	margin-inline: auto;
	padding-inline: var(--bgp-gutter);
}

.bgp-single__content > .alignwide {
	max-width: calc(var(--bgp-wide) + (2 * var(--bgp-gutter)));
}

/*
 * Edge to edge. No negative margins and no viewport units: the wrapper is already full width,
 * so full bleed is just declining the column.
 */
.bgp-single__content > .alignfull {
	max-width: none;
	padding-inline: 0;
}

.bgp-single__content > * + * {
	margin-top: 24px;
}

/*
 * Put the content INSIDE a full-bleed block back into the readable column.
 *
 * A cover or group set to Full should span the window, but its heading and copy should not: they
 * should line up with everything else on the page. In a block theme that is handled by the
 * generated layout stylesheet, which gives `.is-layout-constrained > *` a max-width and auto
 * margins. On this theme that stylesheet never reaches the page, so without these rules a
 * full-bleed hero renders its h1 hard against the left edge of the window and a full-bleed stats
 * band clips its first column. Both were visible before this was added.
 *
 * Scoped to blocks that are actually full bleed, so a normal-width cover keeps core's own
 * behaviour rather than being given a second inset.
 *
 * The root cause is theme-side: see the note about the block-supports stylesheet in README.md.
 * If that is ever fixed, this block and the gallery layout above can both be deleted.
 */
/*
 * Note what is being targeted: the block's INNER CONTAINER, not the block itself.
 *
 * Core rewrites this markup at render time and it is easy to get wrong by reading the saved
 * content instead of the output. A group saved as
 *
 *   <div class="wp-block-group alignfull is-layout-constrained">
 *     <div class="wp-block-columns">
 *
 * is SERVED as
 *
 *   <div class="wp-block-group alignfull">
 *     <div class="wp-block-group__inner-container is-layout-constrained">
 *       <div class="wp-block-columns">
 *
 * The layout classes move onto an injected inner wrapper. A selector written against the stored
 * markup, `.alignfull.is-layout-constrained`, therefore matches nothing on the front end, which
 * is exactly what happened here: the hero heading came right while the stats band stayed flush to
 * both edges. Cover blocks already worked because their inner container is long-standing.
 *
 * The direct-child combinator keeps this to one level, so a constrained container nested deeper
 * inside a column does not accumulate a second inset.
 */
.bgp-single__content > .alignfull > .is-layout-constrained,
.bgp-single__content > .alignfull > .wp-block-cover__inner-container,
.bgp-single__content > .alignfull > .wp-block-group__inner-container {
	padding-inline: var(--bgp-gutter);
}

.bgp-single__content > .alignfull > .is-layout-constrained > *,
.bgp-single__content > .alignfull > .wp-block-cover__inner-container > *,
.bgp-single__content > .alignfull > .wp-block-group__inner-container > *,
.bgp-single__content > .alignfull.is-layout-constrained > * {
	max-width: var(--bgp-container);
	margin-inline: auto;
}

/* A block nested inside a full-bleed block can still opt out again. */
.bgp-single__content > .alignfull > .is-layout-constrained > .alignfull,
.bgp-single__content > .alignfull > .wp-block-cover__inner-container > .alignfull,
.bgp-single__content > .alignfull > .wp-block-group__inner-container > .alignfull,
.bgp-single__content > .alignfull.is-layout-constrained > .alignfull {
	max-width: none;
	padding-inline: 0;
}

/*
 * The project photo grid, laid out by this plugin rather than by core.
 *
 * core/gallery normally gets its layout from the generated block-supports stylesheet, the
 * one WordPress prints as core-block-supports-inline-css. On this site that never reaches
 * the page: the theme dequeues wp-block-library in lib/scripts.php, separate core block
 * assets are on, and the layout store ends up registered with 306 bytes of CSS that is
 * never enqueued. Measured on 2026-08-21: every gallery figure stacked in a single
 * ~415px column instead of forming three, because .wp-block-gallery-is-layout-flex had no
 * display: flex behind it.
 *
 * The live site currently gets away with it, but only because some other active plugin
 * causes that stylesheet to print. Depending on that is depending on a coincidence, so
 * the gallery on a project page is laid out here, explicitly.
 *
 * Grid rather than core's flex, because grid gives equal columns without core's
 * flex-basis arithmetic. The selector is deliberately more specific than core's
 * (.bgp-single__content adds a class), so the result is the same whether or not core's
 * own gallery CSS turns up.
 */
.bgp-single__content .wp-block-gallery.has-nested-images {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 20px 19px;
	/*
	 * margin-block and list-style only. A blanket `margin: 0; padding: 0` here was a real bug:
	 * this rule outranks the constrained-layout rule above, so it wiped the `margin-inline: auto`
	 * and `padding-inline` that put a block in the readable column, and the gallery alone
	 * rendered flush left at full container width while every sibling was centred at 1344px.
	 *
	 * The theme's own `figure { margin: 1em 40px }` is what needs cancelling, and that is a
	 * vertical and horizontal margin, both of which the layout rule already overrides on the
	 * inline axis. So only the block axis is reset here.
	 */
	margin-block: 0;
	list-style: none;
}

.bgp-single__content .wp-block-gallery.columns-1 { grid-template-columns: minmax(0, 1fr); }
.bgp-single__content .wp-block-gallery.columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bgp-single__content .wp-block-gallery.columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.bgp-single__content .wp-block-gallery.columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.bgp-single__content .wp-block-gallery.columns-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }

@media (max-width: 1099px) {
	.bgp-single__content .wp-block-gallery.has-nested-images,
	.bgp-single__content .wp-block-gallery.columns-4,
	.bgp-single__content .wp-block-gallery.columns-5,
	.bgp-single__content .wp-block-gallery.columns-6 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 600px) {
	.bgp-single__content .wp-block-gallery.has-nested-images,
	.bgp-single__content .wp-block-gallery.columns-2,
	.bgp-single__content .wp-block-gallery.columns-4,
	.bgp-single__content .wp-block-gallery.columns-5,
	.bgp-single__content .wp-block-gallery.columns-6 {
		grid-template-columns: minmax(0, 1fr);
	}
}

/*
 * Each figure fills its grid cell.
 *
 * The `:not(#bgp-specificity)` on these three selectors is NOT a typo and is not dead
 * weight. It is a specificity counterweight, and it is core's own trick used back at it.
 *
 * core/gallery's stylesheet raises 19 of its own selectors to ID-level specificity with
 * `figure.wp-block-image:not(#individual-image)`. The one that matters here is
 *
 *   .wp-block-gallery.has-nested-images.columns-3 figure.wp-block-image:not(#individual-image)
 *   { width: calc(33.33333% - var(--wp--style--unstable-gallery-gap, 16px)*.66667) }
 *
 * which scores one ID, three classes and one element. An ID outranks any number of
 * classes, so a class-only override loses however many classes it stacks: measured, the
 * `display: block` below applied while `width: 100%` was ignored, and every figure
 * rendered 134px wide inside a 435px column. The grid was never broken, only its items
 * were, which is a genuinely confusing thing to look at.
 *
 * Matching the ID count is necessary but NOT sufficient. At one ID and three classes this
 * selector merely TIED core's, and a tie is decided by source order, where core's inline
 * per-block CSS is printed after this file's link tag and won anyway. Hence the leading
 * `.bgp-single`: it is the fourth class that breaks the tie. Removing it silently
 * reintroduces the 134px bug.
 *
 * Matching core's idiom rather than reaching for !important is deliberate: it leaves
 * !important available as an escape hatch for a later hand edit, instead of spending it
 * here. `#bgp-specificity` matches nothing on the page, so the :not() is always true.
 *
 * width is stated explicitly rather than left to grid stretch, because a width core still
 * controls defeats stretch silently.
 */
.bgp-single .bgp-single__content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#bgp-specificity) {
	position: relative;
	display: block;
	width: 100%;
	max-width: none;
	margin: 0;
	flex: none;
}

.bgp-single .bgp-single__content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#bgp-specificity) img {
	display: block;
	width: 100%;
	height: auto;
	max-width: none;
	/* A consistent shape per cell, so mixed-orientation photos still read as a grid. */
	aspect-ratio: 4 / 3;
	object-fit: cover;
	border-radius: 4px;
}

.bgp-single .bgp-single__content .wp-block-gallery.has-nested-images figure.wp-block-image:not(#bgp-specificity) figcaption {
	position: static;
	margin: 8px 0 0;
	padding: 0;
	background: none;
	color: var(--bgp-body);
	font-size: 14px;
	line-height: 1.4;
	text-align: left;
}

.bgp-single .bgp-single__back {
	margin: 48px 0 0;
}

/* ---------------------------------------------------------------------------
 * Editor
 * ------------------------------------------------------------------------ */

/*
 * In the editor the blocks render inside a wrapper that is not the front end's container,
 * so the full bleed shadow would paint over the canvas chrome.
 */
.block-editor-block-list__layout .bgp-filter.is-full-bleed {
	box-shadow: none;
	clip-path: none;
}

/* ---------------------------------------------------------------------------
 * Motion
 * ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	.bgp-pill,
	.bgp-card,
	.bgp-button,
	.bgp-card__cta .bgp-icon--arrow,
	.bgp-grid__items {
		transition: none;
	}

	.bgp-card:hover .bgp-card__cta .bgp-icon--arrow {
		transform: none;
	}
}
