/*
 * GM Bricklaying — pattern CSS.
 *
 * Everything here is keyed to a pattern class name. Nothing inline, so a
 * section can be reordered or removed in the site editor without stranding
 * styles. Layout reflows on flex-wrap and auto-fit minmax() rather than on
 * breakpoints, which degrades better on a page this photo-heavy. There is ONE
 * breakpoint, 859px, and the only things allowed inside it are the ones that
 * genuinely cannot reflow: the mobile call bar, and the MOBILE block at the
 * foot of this file.
 */

/* ==========================================================================
   SECTION SHELL
   Spec: max-width 1240 / margin auto / padding 96px 40px 0.
   Width comes from theme.json layout.contentSize; the horizontal gutter comes
   from root padding. Only the vertical rhythm belongs here.
   ========================================================================== */

.gm-section        { padding-top: var(--wp--custom--section-padding); }
.gm-section--flush { padding-top: 0; }

/* Dark panels have to pad themselves.
   The section shell only owns vertical rhythm, and root padding lands on the
   wrapper OUTSIDE a coloured group, not inside it — so anything with a
   background of its own is a box whose edge is visible, and type set flush to
   that edge reads as a clipping bug. Inset uses bandPadding (the token that
   existed in theme.json for exactly this and was never wired up) and the same
   gutter as the page, so the dark panel's inner margin matches the outer one. */
.gm-hero  { padding: var(--wp--custom--band-padding) var(--wp--custom--gutter); }

/* The trust strip keeps its own 22px vertical rhythm — it is a strip, not a
   section — so it only needs the horizontal inset. */
.gm-trust { padding-inline: var(--wp--custom--gutter); }

/* Full-bleed bands opt out of the container entirely. */
.gm-band {
	position: relative;
	overflow: hidden;
}

/* Decorative photo behind type. aria-hidden + empty alt on the img itself. */
.gm-band__bg {
	position: absolute;
	inset: 0;
	margin: 0;
	pointer-events: none;
}
.gm-band__bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
/* The only two opacities on the site, and the only place a photo sits under text. */
.gm-band__bg--texture img     { opacity: .14; }
.gm-band__bg--contractors img { opacity: .26; object-position: 50% 35%; }

/* Horizontal inset already arrives from has-global-padding; the vertical was
   coming from block gap alone (24px above, nothing below), so the photo bands
   ran their last line into the bottom edge. padding-block is a separate
   longhand, so it does not fight the global padding on the inline axis. */
.gm-band__inner {
	position: relative;
	z-index: 1;
	padding-block: var(--wp--custom--band-padding);
	/* __inner is the SECOND child of the band — the decorative __bg is first —
	   so flow block-gap adds 24px above it and the top inset lands at 96
	   against a 72 bottom. Zero it here, not on __inner's first child. */
	margin-block-start: 0;
}

/* ==========================================================================
   IMAGE FRAMES
   Fixed-height box + object-fit: cover, so a weak photo is cropped small
   rather than stretched. Heights are fixed; widths come from the grid, so the
   aspect ratio changes with viewport — which is why these are heights and not
   theme.json aspectRatio values.
   ========================================================================== */

.gm-frame           { overflow: hidden; margin: 0; }
.gm-frame img       { width: 100%; display: block; object-fit: cover; }
.gm-frame--hero img { height: var(--wp--custom--frame--hero); }
.gm-frame--card img { height: var(--wp--custom--frame--card); }
.gm-frame--tile img { height: var(--wp--custom--frame--tile); }
.gm-frame--band     { height: 100%; min-height: var(--wp--custom--frame--band); }
.gm-frame--band img { height: 100%; }

/*
 * object-position is load-bearing, not decoration. matching1.jpeg is 3024x4032
 * portrait in a 1.7:1 box, so cover shows only a 44%-tall band; at 50% 8% that
 * band lands on the matched stepped gable. Above roughly 15% it reintroduces
 * grey blockwork and the card advertises unfinished work.
 * Do not normalise these to 50% 50%.
 */
.gm-pos-50-8  img { object-position: 50%  8%; }   /* matching1 — the stepped gable */
.gm-pos-50-40 img { object-position: 50% 40%; }   /* cowper-rd */
.gm-pos-40-55 img { object-position: 40% 55%; }   /* castleknock */
.gm-pos-50-55 img { object-position: 50% 55%; }   /* chimney1 */
.gm-pos-35-50 img { object-position: 35% 50%; }   /* matching2 — the tight join */
.gm-pos-50-50 img { object-position: 50% 50%; }   /* dundrum, terenure */
.gm-pos-50-60 img { object-position: 50% 60%; }   /* sutton */
.gm-pos-50-45 img { object-position: 50% 45%; }   /* foxrock */
.gm-pos-55-45 img { object-position: 55% 45%; }   /* malahide */

figcaption.gm-caption {
	font-size: var(--wp--preset--font-size--caption);
	line-height: 1.46;
	margin-top: 10px;
	color: var(--wp--preset--color--muted);
}
.gm-caption--reversed { color: var(--wp--preset--color--reversed-caption); }

/* ==========================================================================
   GRIDS
   auto-fit + minmax so the page reflows on content, not on breakpoints.
   ========================================================================== */

.gm-grid { display: grid; }

.gm-grid--services {
	grid-template-columns: repeat(auto-fit, minmax(min(var(--wp--custom--grid--services), 100%), 1fr));
	gap: 22px;
}
/* The fifth card spans the full row so a five-card set resolves with no
   orphan at any column count. */
.gm-grid--services > .gm-card--wide { grid-column: 1 / -1; }

.gm-grid--work {
	grid-template-columns: repeat(auto-fit, minmax(min(var(--wp--custom--grid--work), 100%), 1fr));
	gap: 22px;
}
.gm-grid--process {
	grid-template-columns: repeat(auto-fit, minmax(min(var(--wp--custom--grid--process), 100%), 1fr));
	gap: 0 32px;
}
.gm-grid--facts {
	grid-template-columns: repeat(auto-fit, minmax(min(var(--wp--custom--grid--facts), 100%), 1fr));
	gap: 0 32px;
}
.gm-grid--quotes {
	grid-template-columns: repeat(auto-fit, minmax(min(var(--wp--custom--grid--quotes), 100%), 1fr));
	gap: 24px;
}
/* auto-fit, not repeat(2). A hard two-column track list cannot drop to one:
   130 + 28 + 130 = 288, which is wider than the Where-we-work panel is on a
   320px phone, so the second town column hung off the side of the page.
   auto-fit collapses empty tracks, and there are only ever two children, so
   this still renders as exactly two columns everywhere two will fit. */
.gm-grid--towns {
	grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr));
	gap: 28px;
}

/*
 * Cell dividers are border-TOP, never border-right. On an auto-fit grid a
 * right border cannot know which cell ends a row, so a partial final row
 * leaves a rule dangling in empty space.
 */
.gm-grid--process > * { border-top: 1px solid var(--wp--preset--color--rule);     padding: 22px 0 28px; }
.gm-grid--facts   > * { border-top: 1px solid var(--wp--preset--color--ink-rule); padding: 20px 0 22px; }

.gm-process__num {
	font-size: var(--wp--preset--font-size--label-lg);
	font-weight: 700;
	letter-spacing: .10em;
	color: var(--wp--preset--color--oxide);
}

/* ==========================================================================
   CARDS
   ========================================================================== */

.gm-card {
	background: var(--wp--preset--color--card);
	border: 1px solid var(--wp--preset--color--rule);
}
.gm-card__body { padding: 22px 24px 24px; }

/* Fifth services card: the Landscaping one carrying the "Photo needed" note. */
.gm-card--wide {
	background: var(--wp--preset--color--ink);
	border: 0;
	padding: 38px 32px;
	display: flex;
	flex-wrap: wrap;
	gap: 32px;
	align-items: flex-end;
	justify-content: space-between;
}

/*
 * Dashed placeholders ship as-is until the client resolves them. Two exist:
 * the Landscaping "Photo needed" note and the "Email · address TBC" button.
 * They are deliberately visible. Do not style them to look resolved.
 */
.gm-placeholder {
	border: 1px dashed var(--wp--preset--color--dashed);
	padding: 16px 18px;
}

/* ==========================================================================
   TRUST BAR — a strip, not a section. 22-24px, never the 96px section rhythm.
   ========================================================================== */

.gm-trust { background: var(--wp--preset--color--eyebrow-warm); }
.gm-trust__list {
	display: flex;
	flex-wrap: wrap;
	gap: 14px 24px;
	padding: 22px 0;
	margin: 0;
	list-style: none;
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .10em;
	text-transform: uppercase;
	color: var(--wp--preset--color--graphite);
}
.gm-trust__list li + li::before {
	content: "·";
	margin-right: 24px;
	color: var(--wp--preset--color--muted);
}

/* ==========================================================================
   TESTIMONIALS — stacked, never a carousel. Reads right with two, takes four.
   ========================================================================== */

.gm-quote {
	background: var(--wp--preset--color--card);
	border: 1px solid var(--wp--preset--color--rule);
	border-left: 3px solid var(--wp--preset--color--oxide);
	padding: 28px 28px 24px;
	margin: 0;
}
.gm-quote p {
	font-family: var(--wp--preset--font-family--newsreader);
	font-size: var(--wp--preset--font-size--quote);
	font-style: italic;
	font-weight: 400;
	line-height: 1.48;
	margin: 0;
}
.gm-quote cite,
.gm-quote footer {
	display: block;
	margin-top: 20px;
	font-family: var(--wp--preset--font-family--archivo);
	font-size: var(--wp--preset--font-size--label);
	font-style: normal;
	font-weight: 600;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

/* ==========================================================================
   FAQ — core/details, native disclosure, no JavaScript.
   Keyboard and screen-reader behaviour comes free from <details>.
   ========================================================================== */

.gm-faq { max-width: 820px; border-top: 1px solid var(--wp--preset--color--rule); }
.gm-faq .wp-block-details {
	border-bottom: 1px solid var(--wp--preset--color--rule);
	padding: 0;
}
.gm-faq summary {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 24px;
	padding: 20px 0;
	font-size: 18px;
	font-weight: 600;
	cursor: pointer;
	list-style: none;
}
.gm-faq summary::-webkit-details-marker { display: none; }
.gm-faq summary::after {
	content: "+";
	font-weight: 400;
	font-size: 22px;
	line-height: 1;
	color: var(--wp--preset--color--muted);
}
.gm-faq details[open] > summary::after {
	content: "—";
	color: var(--wp--preset--color--oxide);
}
.gm-faq .wp-block-details > :not(summary) {
	padding-bottom: 22px;
	max-width: var(--wp--custom--measure--prose);
	color: var(--wp--preset--color--body-soft);
	margin: 0;
}

/* ==========================================================================
   CONTACT FORM — fields sit on graphite over ink.
   Phone always renders above the form. Non-negotiable; it is the one
   conversion action on the page.
   ========================================================================== */

.gm-form input,
.gm-form textarea,
.gm-form .kb-field {
	background: var(--wp--preset--color--graphite);
	border: 1px solid var(--wp--preset--color--ink-rule);
	border-radius: 0;
	color: var(--wp--preset--color--reversed);
	font-family: var(--wp--preset--font-family--archivo);
	font-size: 16px;
	padding: 15px;
	width: 100%;
}
.gm-form ::placeholder { color: var(--wp--preset--color--placeholder); opacity: 1; }
.gm-form button[type="submit"],
.gm-form .kb-forms-submit-button {
	background: var(--wp--preset--color--limestone);
	color: var(--wp--preset--color--ink);
	border: 0;
	border-radius: 0;
	font-weight: 700;
	font-size: 16px;
	padding: 18px 24px;
}

/* The line under Send. Colour and size come from the paragraph's own preset
   classes, matching the "Phone is answered on site" note in the column beside
   it, so this rule is only the gap. The flat 24px block gap would set the
   sentence adrift as a third element in the column; fine print belongs to the
   form above it, so pull it in. Scoped through .gm-contact because a bare
   .gm-form-privacy ties on specificity with the layout container's own
   `> * + *` rule and would then be decided by stylesheet order.
   Fine print, not a second call to action: never let it compete with Send. */
.gm-contact .gm-form-privacy {
	margin-top: 14px;
	line-height: 1.5;
}

/* Spam trap. Off-screen rather than display:none so bots that skip hidden
   fields still fill it. Never announced to assistive tech. */
.gm-hp {
	position: absolute !important;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ==========================================================================
   BUTTONS
   Oxide is reserved for the phone and section eyebrows. Nothing else.
   If it appears elsewhere it stops meaning "ring this number".
   ========================================================================== */

.gm-btn-outline .wp-block-button__link,
.wp-block-button.gm-btn-outline .wp-block-button__link {
	background: transparent;
	border: 1.5px solid var(--wp--preset--color--muted);
	color: var(--wp--preset--color--reversed);
	transition: border-color .15s ease;
}
.gm-btn-outline .wp-block-button__link:hover,
.gm-btn-outline .wp-block-button__link:focus-visible,
.gm-btn-outline .wp-block-button__link:active,
.wp-block-button.gm-btn-outline .wp-block-button__link:hover,
.wp-block-button.gm-btn-outline .wp-block-button__link:focus-visible,
.wp-block-button.gm-btn-outline .wp-block-button__link:active {
	border-color: var(--wp--preset--color--reversed);
	background: transparent;
}
.gm-btn-dashed .wp-block-button__link,
.wp-block-button.gm-btn-dashed .wp-block-button__link {
	background: transparent;
	border: 1.5px dashed var(--wp--preset--color--dashed);
	color: var(--wp--preset--color--reversed-muted);
}
/* Every phone button is a 48px tap target and carries the digits as text. */
.gm-btn-phone .wp-block-button__link { min-height: 48px; display: inline-flex; align-items: center; }

/*
 * Rollover on the main CTA — the oxide buttons: Ring, Ask about a match, Call now.
 *
 * They had none, and the reason is not obvious. Their colour arrives as the
 * preset class WordPress emits for backgroundColor:"oxide", and WordPress
 * emits every preset colour class with !important:
 *
 *     .has-oxide-background-color { background-color: ... !important; }
 *
 * theme.json's button :hover ships as `:root :where(.wp-element-button:hover)`,
 * and :where() is specificity zero, so the hover never landed on the one
 * element on the page that most needs to look pressable. Matching the
 * !important is the only thing that wins it back — no selector, however
 * narrow, beats !important.
 *
 * :focus-visible carries the state to the keyboard. :active carries it to
 * touch, where :hover either never fires or sticks lit after the tap — and
 * touch is the device this CTA is built for.
 */
.wp-block-button__link.has-oxide-background-color {
	transition: background-color .15s ease;
}
.wp-block-button__link.has-oxide-background-color:hover,
.wp-block-button__link.has-oxide-background-color:focus-visible,
.wp-block-button__link.has-oxide-background-color:active {
	background-color: var(--wp--preset--color--oxide-dark) !important;
}

/* ==========================================================================
   MOBILE CALL BAR — the one genuine breakpoint on the page.
   ========================================================================== */

.gm-callbar { display: none; }

@media (max-width: 859px) {
	.gm-callbar {
		display: flex;
		position: fixed;
		inset: auto 0 0 0;
		z-index: 40;
		justify-content: space-between;
		align-items: center;
		gap: 12px;
		background: var(--wp--preset--color--ink);
		border-top: 1px solid var(--wp--preset--color--ink-rule);
		padding: 9px 14px;
		padding-bottom: calc(9px + env(safe-area-inset-bottom));
	}
	/* So the bar cannot cover the statutory company line. */
	.gm-footer { padding-bottom: calc(64px + env(safe-area-inset-bottom)) !important; }
}

.gm-callbar__name {
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--wp--preset--color--reversed-body);
}

/* ==========================================================================
   HEADER / FOOTER
   ========================================================================== */

.gm-header {
	position: sticky;
	top: 0;
	z-index: 30;
	background: var(--wp--preset--color--ink);
	border-bottom: 1px solid var(--wp--preset--color--ink-rule-soft);
}
/* Type only — no logo mark. Logo design was excluded from the quote;
   this is the agreed answer, not a placeholder. */
.gm-logotype {
	font-size: 19px;
	font-weight: 800;
	letter-spacing: -0.01em;
	text-transform: uppercase;
	color: var(--wp--preset--color--reversed);
	text-decoration: none;
}

.gm-footer { background: var(--wp--preset--color--ink); }
/* The statutory line. A <ul> keeps the browser's 16px list indent even with
   list-style:none, so this strip sat 16px right of the logotype above it and
   16px off the gutter every section on the page is set to. The other four
   lists in this file zero their padding; this one was missed. */
.gm-footer__legal {
	border-top: 1px solid var(--wp--preset--color--ink-rule);
	margin-top: 32px;
	padding-top: 24px;
	padding-inline: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 10px 22px;
	font-size: 12px;
	font-weight: 500;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--wp--preset--color--reversed-caption);
	list-style: none;
	margin-bottom: 0;
}

/* The privacy notice is the only link in this strip. Left to the global link
   colour it renders oxide on ink, which measures 2.8:1 — the statutory row is
   12px, so that is well under AA. Take the body tint instead and underline it,
   since it is one link in a row of six items that are not links.
   NB the six section links in the row above have the same 2.8:1 problem and
   are deliberately left alone here; that is a design call, not a bug fix to
   fold into this. */
.gm-footer__legal a {
	color: var(--wp--preset--color--reversed-body);
	text-decoration: underline;
	text-underline-offset: 2px;
}
.gm-footer__legal a:hover { color: var(--wp--preset--color--reversed); }

/* ==========================================================================
   LEGAL PAGES
   The privacy notice is the only route on this site that is a page rather
   than a section of the one-pager, and the only place a run of h2s appears in
   a body of prose. At the h2 preset they are 34px uppercase Archivo, which
   turns six quiet section breaks into six shouted ones in a document meant to
   be scanned rather than sold from. Keep the level, because the outline under
   the h1 has to stay correct, and take the size and case from h3.
   ========================================================================== */

.gm-legal h2 {
	font-size: var(--wp--preset--font-size--h-3);
	font-weight: 700;
	letter-spacing: normal;
	text-transform: none;
	margin-top: 44px;
}

/* Block gap is a flat 24px everywhere, which gives a heading exactly as much
   air as the gap between two paragraphs and so reads as no break at all. More
   above, less below. Both of these have to out-specify the layout container's
   own `.wp-container-x > * + *` rule, which is a single class — hence the
   descendant and sibling selectors rather than a bare `h2`. A margin-bottom
   here would not do it: it collapses against the next paragraph's 24px and
   the larger value wins, so the space after has to be taken off that
   paragraph instead. */
.gm-legal h2 + p { margin-top: 12px; }
.gm-legal > *:first-child { margin-top: 0; }

/* Left edge. WordPress's constrained layout centres every direct child of the
   container with `margin-left: auto !important`. While the 66ch prose measure
   sat on post-content, post-content was narrower than the content width and so
   got centred — 116px in from the h1 above it, which is capped at the full
   width and stays flush left. Two different left edges on the same page.

   Overriding that centring means matching an !important, which is a fight you
   have to keep winning. Take the measure off post-content instead: at full
   content width the auto margins have nothing to centre and resolve to zero.
   The measure then goes on the children of .gm-legal, which the pattern
   declares as layout:default — a plain flow container that adds no margins at
   all, so max-width simply left-aligns. */
.gm-legal > * { max-width: var(--wp--custom--measure--prose); }

/* ==========================================================================
   SPLIT ROWS
   The design gives every two-column band an explicit flex basis per child
   (hero 380/620, matching 400/420, contact 360/340, area 300/300). Core's
   flex layout has no per-child flex-basis control, so the wrap behaviour is
   declared here instead. This is what makes the page reflow on content
   rather than on breakpoints.
   ========================================================================== */

.gm-split { display: flex; flex-wrap: wrap; }

/* 380 + 52 + 600 = 1032. The hero panel pads itself now, so the two columns
   get 80px less room than they did — at 620 the image column no longer fit and
   the split silently wrapped to two rows, doubling the hero height. Keep the
   sum under the padded inner width or this stacks on desktop. */
.gm-split--hero     { gap: 52px; align-items: center; }
/* min() not a bare 300px. The hero panel pads itself, so its inner width is
   the viewport less 40px of gutter and 40px of panel padding — 240px on a
   320px phone, 295px on a 375px one. A hard 300px floor is wider than that,
   and a flex item cannot shrink below its min-width, so the hero pushed the
   document 20px wider than the screen and every page below 380px scrolled
   sideways. Same min(x, 100%) idiom as the grids above. */
.gm-split--hero    > :nth-child(1) { flex: 1 1 380px; min-width: min(300px, 100%); }
.gm-split--hero    > :nth-child(2) { flex: 0 1 600px; min-width: min(300px, 100%); }

.gm-split--match   > :nth-child(1) { flex: 1 1 400px; }
.gm-split--match   > :nth-child(2) { flex: 1 1 420px; }

.gm-split--quality  { gap: 56px; }
.gm-split--quality > :nth-child(1) { flex: 1 1 380px; }
.gm-split--quality > :nth-child(2) { flex: 1 1 380px; }

.gm-split--contact  { gap: 56px; }
.gm-split--contact > :nth-child(1) { flex: 1 1 360px; }
.gm-split--contact > :nth-child(2) { flex: 1 1 340px; }

.gm-split--area     { gap: 44px; }
.gm-split--area    > :nth-child(1) { flex: 1 1 300px; }
.gm-split--area    > :nth-child(2) { flex: 1 1 300px; }

/*
 * core/image wraps every photo in a <figure>. Height rules must reach the
 * figure as well as the img, or the figure keeps its natural height and the
 * fixed-height frame does nothing — which is what made the brick-matching
 * band render at full image height and the two backdrop photos overflow
 * their bands.
 */
.gm-band__bg .wp-block-image,
.gm-band__bg figure { height: 100%; margin: 0; }
.gm-frame--band,
.gm-frame--band .wp-block-image { height: 100%; }
.gm-split--match > :nth-child(2) { display: flex; }
.gm-split--match > :nth-child(2) > * { flex: 1; }

/*
 * Kadence emits per-form inline CSS keyed to the form's uniqueID, which
 * outranks a plain `.gm-form input`. These selectors match its specificity so
 * the fields take the design's graphite-on-ink treatment and square corners.
 */
.gm-form .kadence-blocks-form-field input.kb-field,
.gm-form .kadence-blocks-form-field textarea.kb-field,
.gm-form .kadence-blocks-form-field select.kb-field {
	background: var(--wp--preset--color--graphite);
	border: 1px solid var(--wp--preset--color--ink-rule);
	border-radius: 0;
	color: var(--wp--preset--color--reversed);
	font-family: var(--wp--preset--font-family--archivo);
	font-size: 16px;
	padding: 15px;
}
.gm-form .kadence-blocks-form-field input.kb-field::placeholder,
.gm-form .kadence-blocks-form-field textarea.kb-field::placeholder {
	color: var(--wp--preset--color--placeholder);
	opacity: 1;
}
.gm-form .kadence-blocks-form-field .kb-forms-submit {
	background: var(--wp--preset--color--limestone);
	color: var(--wp--preset--color--ink);
	border: 0;
	border-radius: 0;
	font-family: var(--wp--preset--font-family--archivo);
	font-weight: 700;
	font-size: 16px;
	padding: 18px 24px;
}
.gm-form .kadence-blocks-form-field .kb-forms-submit:hover {
	background: var(--wp--preset--color--card);
}
/* Kadence's own honeypot. Keep it unreachable but present for bots. */
.gm-form .kadence-blocks-field.verify,
.gm-form .kadence-verify-label { position: absolute !important; left: -9999px; }

/*
 * Fifth services card. Spec: left flex 1 1 420px (heading + copy), right
 * flex 0 1 300px (the dashed "Photo needed" note), aligned to the baseline of
 * the row. Without explicit bases the two children size to content and the
 * note drops beneath the copy instead of sitting beside it.
 */
.gm-card--wide > :nth-child(1) { flex: 1 1 420px; }
.gm-card--wide > :nth-child(2) { flex: 0 1 300px; }

/*
 * WordPress gives any `is-layout-flow` container's non-first children
 * `margin-block-start: var(--wp--style--block-gap)`. Our grid and split rows
 * are flow containers turned into grid/flex by the CSS above, so every item
 * after the first inherited a 24px top margin and sat lower than its
 * neighbours inside its own grid area — cards and tiles in the same row
 * visibly out of line. Gap already handles the spacing here.
 */
.gm-grid > *,
.gm-split > *,
.gm-card--wide > *,
.gm-callbar > *,
.gm-trust > *,
.gm-band__bg > * { margin-block-start: 0; margin-block-end: 0; }

/* Same rule reaches inside the image frames, which are figures. */
.gm-frame { margin-block-start: 0; margin-block-end: 0; }

/* ==========================================================================
   BAND LISTS
   Both sit on dark grounds. Their colour is set on the block (textColor) so it
   is visible and editable in the editor; the structure is here.
   ========================================================================== */

/* "Why choose GM Bricklaying Limited?" - six rules, not bullets. */
.gm-why { list-style: none; padding: 0; margin: 16px 0 0; }
.gm-why li {
	border-top: 1px solid var(--wp--preset--color--ink-rule);
	padding: 13px 0;
	font-size: var(--wp--preset--font-size--base);
}
.gm-why li:last-child { border-bottom: 1px solid var(--wp--preset--color--ink-rule); }

/* Recent trade clients - names in a wrapping row, not a bulleted list. */
.gm-clients {
	list-style: none;
	padding: 0;
	margin: 16px 0 32px;
	display: flex;
	flex-wrap: wrap;
	gap: 12px 28px;
	font-size: 14px;
	font-weight: 600;
}

/* Town lists sit on the light card ground, so they keep the body colour. */
.gm-towns { list-style: none; padding: 0; margin: 8px 0 0; font-size: 16px; line-height: 1.85; }

/* ==========================================================================
   MOBILE — 859px, the same breakpoint as the call bar above.
   Everything in here is something that cannot reflow on its own: a fixed
   frame height, a separator that only works on one line, and padding that is
   a hard px block attribute rather than a token.
   ========================================================================== */

@media (max-width: 859px) {

	/* Hero photo. --frame--hero is a fixed 440px HEIGHT while the width comes
	   from the column, which is 310px once the split stacks on a phone — so the
	   frame is portrait, and cover crops the landscape original down to a
	   narrow slice of wall with the extension itself out of frame. A ratio
	   keeps the frame landscape at any width; cover still does the cropping, so
	   the object-position work above is untouched.
	   The image column is flex: 0 1 600px, so it never exceeds 600px and the
	   ratio never yields more than 400px of height — the frame only ever gets
	   shorter than the 440 it has at 860px, never taller. */
	.gm-frame--hero img {
		height: auto;
		aspect-ratio: 3 / 2;
	}

	/* Trust strip. The "·" is a ::before on the FOLLOWING item, so once the row
	   wraps every new line opens with orphaned punctuation — "· €2.6M PUBLIC
	   LIABILITY". Columns instead of a wrapping row, and no separators: a
	   column edge already does the separating.
	   auto-fit rather than a fixed column count, so this still reflows on
	   content the way the grids above do: three columns at 859px, two by 500,
	   and a clean stack of five below about 440. A hard one-column rule would
	   have stacked the strip at 859 too, where the facts still sit happily
	   side by side. */
	.gm-trust__list {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
		gap: 9px 24px;
		padding: 18px 0;
	}
	/* Core gives list items a 9.75px bottom margin, which doubled up with the
	   gap and made the strip half again as tall as it needed to be. Gap is the
	   only spacing knob here. */
	.gm-trust__list li { margin: 0; }
	.gm-trust__list li + li::before { content: none; }

	/*
	 * Coloured panels — The difference, Where we work, Get in touch.
	 *
	 * .gm-hero pads itself from tokens, so on a 390px screen its copy sits 40px
	 * from the screen edge. These three carry hard pixel padding instead
	 * (52/44, 40/36 and 56/44), which does not shrink: their copy sat 56-64px
	 * in, visibly narrower than the hero and not even in agreement with each
	 * other. Give them the hero's own two tokens.
	 *
	 * Those px values are block attributes, i.e. inline styles, so !important
	 * is the only thing that reaches them. It is scoped to this media query, so
	 * the padding controls in the editor still behave normally at desktop
	 * widths — Gavin sets 44 and sees 44.
	 */
	.gm-split--match > :nth-child(1),
	.gm-area,
	.gm-contact {
		padding: var(--wp--custom--band-padding) var(--wp--custom--gutter) !important;
	}

	/* The brick-matching caption keeps its own tight 16px rhythm; it only has
	   to line up with the copy above it. */
	.gm-band__caption {
		padding-left:  var(--wp--custom--gutter) !important;
		padding-right: var(--wp--custom--gutter) !important;
	}
}
