/*
Theme Name: Kitchensmiths
Description: Child theme of Hello Elementor for the Kitchensmiths website.
Author: PrimeXeon
Template: hello-elementor
Version: 0.1.0
Text Domain: kitchensmiths
*/

/* Theme styles live here. Keep this file small — Elementor owns layout and
   most typography. Only add rules Elementor genuinely cannot express. */

/* ---------------------------------------------------------------------------
   Content column cap
   ---------------------------------------------------------------------------
   The design is drawn with a 1320px content column and 40px gutters. Elementor
   containers are full-width, so without a cap the content keeps stretching
   with the viewport. */
:root {
	--ks-navy: #1C2A33;
	--ks-navy-deep: #16222A;
	--ks-brass: #B08D57;
	--ks-cream: #F5F2EC;
	--ks-offwhite: #FFFDF9;
	--ks-border: #EBE5DB;
	--ks-text-muted: #57616A;
	--ks-text-secondary: #6B747C;
	--ks-text-light: #8C9099;
	--ks-content-max: 1320px;
	--ks-gutter: 40px;
	--ks-section-pad: 110px;
}

body {
	background: var(--ks-cream);
	color: var(--ks-navy);
}

/* The Matterport embed on /virtual-showroom/.
   These live here rather than in archives.css because that sheet is only
   enqueued on the archive and single templates -- the virtual showroom is an
   Elementor page, so it never loaded it, and the tour rendered 1320px wide
   and 157px tall with its aspect-ratio rule nowhere in the document. */
.ks-tour {
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	background: #EBE5DB;
	overflow: hidden;
}

.ks-tour-frame {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (max-width: 640px) {
	.ks-tour { aspect-ratio: 4 / 3; }
}

/* The showroom map at the foot of /contact/, rendered by [ks_map]
   (inc/contact.php). Here rather than in contact-form.css for the same reason
   as the tour above: that sheet is scoped to the form skin, and this is a page
   element.

   TWO MODES, and the shared box below serves both. With a Maps API key the
   map is drawn feature by feature in this palette by assets/js/map.js. Without
   one it falls back to Google's keyless embed, tinted by the filter further
   down — the honest substitute, and the reason the .--embed modifier exists. */
.ks-map {
	width: 100%;
}

.ks-map-frame {
	position: relative;
	width: 100%;
	aspect-ratio: 21 / 7;
	background: #EBE5DB;
	overflow: hidden;
	border: 1px solid #EBE5DB;
}

/* THE FILTER IS ONLY FOR THE KEYLESS FALLBACK. With a Maps API key the map is
   drawn in this palette by assets/js/map.js, feature by feature, and filtering
   it again would knock the labels back out of contrast. */
.ks-map-frame--embed iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
	filter: grayscale(0.85) sepia(0.22) saturate(0.85) contrast(0.94) brightness(1.03);
}

/* True colour once someone interacts with it: at that point they are reading
   the map rather than looking at the page, and a tinted map is harder to read
   than an untinted one. */
.ks-map-frame--embed:hover iframe,
.ks-map-frame--embed:focus-within iframe {
	filter: none;
}

.ks-map-link {
	margin: 14px 0 0;
	font: 300 15px/1.6 Jost, sans-serif;
	color: #57616A;
}

.ks-map-link a {
	color: #1C2A33;
	border-bottom: 1px solid #B08D57;
	padding-bottom: 2px;
	text-decoration: none;
}

.ks-map-link a:hover,
.ks-map-link a:focus-visible {
	border-bottom-color: #1C2A33;
}

@media (max-width: 640px) {
	.ks-map-frame { aspect-ratio: 4 / 3; }
}

/* [ks_slider] — the ex-display photographs (inc/slider.php).

   A scroll-snap track, so it works as a slider with the script switched off.
   Two slides visible on a desktop and one on a phone: these are photographs of
   one kitchen from different angles, and showing a second half-slide is what
   tells someone there is more to the right without a control having to say so. */
.ks-slider {
	width: 100%;
}

.ks-slider-track {
	display: flex;
	gap: 16px;
	margin: 0;
	padding: 0;
	list-style: none;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: thin;
	scrollbar-color: #B08D57 #EBE5DB;
	-webkit-overflow-scrolling: touch;
}

.ks-slider-track:focus-visible {
	outline: 2px solid #B08D57;
	outline-offset: 4px;
}

/* Grab-and-drag with a mouse. A finger already swipes the track natively, so
   the cursor is the only affordance missing — and a slider that does not say
   it can be dragged may as well not be. */
.ks-slider-track {
	cursor: grab;
}

.ks-slider.is-dragging .ks-slider-track {
	cursor: grabbing;
	/* Text selection across the slides while dragging looks like a bug. */
	user-select: none;
	scroll-behavior: auto;
}

.ks-slider.is-dragging .ks-slider-img {
	pointer-events: none;
}

@media (hover: none) {
	/* No cursor on a touch device, and no grab affordance to imply one. */
	.ks-slider-track { cursor: auto; }
}

.ks-slider-slide {
	flex: 0 0 calc(50% - 8px);
	scroll-snap-align: start;
	aspect-ratio: var(--ks-slider-ratio, 4 / 3);
	background: #EBE5DB;
	overflow: hidden;
}

.ks-slider-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ks-slider-controls {
	display: flex;
	align-items: center;
	gap: 14px;
	margin-top: 16px;
}

.ks-slider-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	padding: 0;
	border: 1px solid #DCD5C8;
	background: transparent;
	color: #1C2A33;
	cursor: pointer;
	transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.ks-slider-btn:hover:not(:disabled) {
	background: #1C2A33;
	border-color: #1C2A33;
	color: #F5F2EC;
}

.ks-slider-btn:focus-visible {
	outline: 2px solid #B08D57;
	outline-offset: 2px;
}

.ks-slider-btn:disabled {
	opacity: 0.35;
	cursor: default;
}

.ks-slider-count {
	font: 300 13px/1 Jost, sans-serif;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #636770;
}

@media (max-width: 640px) {
	.ks-slider-slide { flex-basis: 100%; }
}

@media (prefers-reduced-motion: reduce) {
	.ks-slider-btn { transition: none; }
}

/* The footer's three legal lines, set solid.
   "Privacy policy · Photographic release", the copyright line and "KBSA Approved
   TrustMark Registered" are Elementor text-editor widgets carrying 13px on
   13px (11px on 11px for the third) — leading of exactly 1.0. At one line each
   that is invisible. Between roughly 768px and 880px all three wrap to two
   lines, and because the rendered glyph box for 13px Jost is 19px the
   descenders of line one overlap the ascenders of line two: "Photographic"
   into "release", "rights" into "reserved". Found by walking sibling bounding
   boxes at 768 across every page type; it is the only overlap on the site.

   Fixed here rather than in the footer template because that template is
   build-locked, and a CSS floor cannot be discarded by a future build the way
   a widget setting can.

   The coupling worth knowing: these are Elementor element classes, stable only
   while the footer document is. If the footer is ever rebuilt the ids are
   rewritten (see known-issues on exports rewriting element ids) and these
   selectors go dead silently — so if the legal lines ever collide again, this
   is the first place to look. Scoped to the three rather than to every footer
   text-editor, because the column blurb above them is deliberately looser than
   1.5 and a blanket rule would tighten it. */
footer .elementor-element-6412855 p,
footer .elementor-element-1453627 p,
footer .elementor-element-2650077 p {
	line-height: 1.5;
}

/* The footer's social icons, rendered by [ks_footer_social]
   (inc/footer-parts.php). They were the three platform NAMES set as text,
   which the design draws — but the design also drew them going nowhere, and
   once they point at real accounts a row of small marks reads faster than a
   row of words and takes a third of the width.

   Sized generously on purpose: the glyph is 19px but the target is 40px, which
   is the smallest thing a thumb should have to hit. */
.ks-social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	margin-left: -10px; /* Pulls the first icon back to the column's left edge. */
	border-radius: 50%;
	color: rgba(245, 242, 236, 0.72);
	transition: color 0.18s ease, background-color 0.18s ease;
}

.ks-social-link + .ks-social-link {
	margin-left: 0;
}

.ks-social-link:hover,
.ks-social-link:focus-visible {
	color: #1C2A33;
	background: #B08D57;
}

.ks-social-link:focus-visible {
	outline: 2px solid #B08D57;
	outline-offset: 2px;
}

.ks-social-icon {
	display: block;
}

@media (prefers-reduced-motion: reduce) {
	.ks-social-link { transition: none; }
}

/* The showroom notice bar. Rendered by the theme from the closure calendar in
   wp-admin — see inc/hours.php. On the live site this is a CloudFront JSON file
   the widget fetches; here the data is in the same database as the page, so
   there is nothing to publish and no flash of a page without its notice. */
.ks-notice {
	background: #1C2A33;
	color: #F5F2EC;
}

.ks-notice-inner {
	max-width: 1320px;
	margin: 0 auto;
	padding: 12px 40px;
	font: 400 14px/1.5 Jost, sans-serif;
	letter-spacing: 0.02em;
	text-align: center;
	text-wrap: pretty;
}

@media (max-width: 640px) {
	.ks-notice-inner { padding: 10px 20px; font-size: 13px; }
}

/* Footer column links, phone only (DES-11).

   Measured 342x14 at 390px with 27px between line tops — a column of links,
   which WCAG 2.2 SC 2.5.8's inline-text exemption does not cover, and the
   classic mis-tap pattern: a wide, short target with a near-miss directly
   above and below it.

   Mostly this formalises space that is already there. The rhythm is 27px, so
   padding the anchors to a 44px box adds about 17px per row on a phone and
   nothing at all on desktop, where the rule does not apply. */
@media (max-width: 767px) {
	footer a:not(.ks-social-link):not(.ks-logo) {
		display: inline-flex;
		align-items: center;

		/* PADDING, NOT min-height — and this is the whole point of the rule.
		   The footer columns are flex with a 13px `gap`, so a 44px min-height
		   box does not absorb that gap, it ADDS to it: measured 44px links 57px
		   apart, against 14px links 27px apart on desktop. The footer came out
		   1812px tall on a phone and read as though the links had been spaced
		   out on purpose.

		   Vertical padding grows the hit area INTO the space that is already
		   there. 11px each side of a 22px line box gives a 44px target while
		   the visible rhythm stays close to the desktop's — the touch area of
		   neighbouring links meets rather than pushing them apart.

		   -6px margin then reclaims most of the gap the padding duplicates, so
		   the text baselines land near where they did before any of this. */
		padding-block: 8px;
	}

	/* And the link column's own 13px flex gap goes, because the padding above
	   now provides the separation. Leaving both meant every link occupied 39px
	   of vertical rhythm against the desktop's 27px — measured — which is what
	   made the mobile footer read as though the links had been spread out on
	   purpose.

	   The gap is an INLINE style on an unclassed div that the footer shortcode
	   emits (`style="display:flex; flex-direction:column; gap:13px"`), so it
	   cannot be overridden without !important — an inline declaration outranks
	   any selector. The rule is therefore aimed as narrowly as it can be: a
	   flex column inside .elementor-shortcode in the footer, and only below
	   768px, where the padding it is compensating for exists.

	   Net effect: a 30px touch target on a 30px rhythm — the targets tile
	   exactly, with no dead space between them.

	   30, NOT 44. WCAG 2.2 SC 2.5.8 requires 24x24; 44 is a comfort guideline,
	   and chasing it here made the footer 1812px tall on a phone and read as
	   though the links had been spaced out on purpose — the owner noticed
	   before any check did. A footer list of nine links is not the same problem
	   as a lone menu button, which is why .ks-hamburger keeps its 44 and this
	   does not. 30 clears the requirement with room to spare and keeps the
	   footer close to the rhythm the design draws. */
	footer .elementor-shortcode > div {
		row-gap: 0 !important;
	}
}

/* ---------------------------------------------------------------------------
   Links inherit their context. The parent theme's reset does not.

   hello-elementor/assets/css/reset.css ships:

       a { background-color: transparent; color: #c36; text-decoration: none }
       a:active, a:hover { color: #336 }

   #c36 is #CC3366 — a pink that appears nowhere in this palette, and the reason
   a grep for "CC3366" across the codebase finds nothing: it is written in
   shorthand. Everything the theme styles explicitly overrides it, which is why
   this went unnoticed; everything the theme does NOT falls through. That is a
   long list, because most anchors here are WRAPPERS whose job is to inherit:
   the skip link, the logo, every mega-menu card and promo, every project card,
   the blog card media links, the review pagination. Any text inside them that
   does not set its own colour comes out pink, and a plain link written into an
   Elementor text editor — the Siemens URL on /aftercare/ is the clearest one —
   is pink outright.

   `inherit` rather than a fixed colour on purpose: these anchors sit on cream,
   on ink and on photographs, and each should take the colour of the thing it
   wraps. Links that need to look like links get an underline below rather than
   a colour of their own, which also keeps them legible on every ground.

   This rule is (0,0,1), the same specificity as the reset's — it wins on order,
   because style.css declares hello-elementor as a dependency and therefore
   loads after it. If the enqueue order in functions.php is ever changed, the
   pink comes back. */
a,
a:hover,
a:active,
a:focus {
	color: inherit;
}

/* Prose links still have to read as links. Scoped to the places real sentences
   live — Elementor's text editor and the article body — so wrapper anchors and
   buttons are untouched. Brass underline rather than brass text: it survives
   being set on cream, on sand and on the ink bands, and it keeps the text
   itself at the body colour, which is the only one measured to clear AA on all
   three (see DES-04). */
.elementor-widget-text-editor a:not(.elementor-button),
.ks-article-prose a,
.ks-article-body a {
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: rgba(176, 141, 87, 0.65);
	text-decoration-thickness: 1px;
}

.elementor-widget-text-editor a:not(.elementor-button):hover,
.ks-article-prose a:hover,
.ks-article-body a:hover {
	text-decoration-color: var(--ks-brass, #B08D57);
}

/* The same reset pinks bare buttons:
       [type=button], [type=submit], button { border: 1px solid #c36; color: #c36 }
   Every themed button on the site overrides both, so nothing shows pink today —
   the one bare button is .ks-hamburger, which sets `border: 0` and gives its
   bars an explicit cream background. It is fixed anyway because the inherited
   colour is what `currentColor` would resolve to, so the next icon or outline
   drawn inside a button would come out pink for no visible reason.

   Colour only. The reset's border is deliberately left alone: themed buttons
   all set their own, and overriding border-colour globally is the kind of rule
   that quietly changes something three pages away. */
button,
[type="button"],
[type="submit"] {
	color: inherit;
}

/* And the same reset's hover/focus state, which is the half the first pass at
   this missed:

       [type=button]:focus, [type=button]:hover, button:focus, button:hover
       { background-color: #c36; color: #fff }

   `color` alone was not enough — this rule paints the BACKGROUND pink, so any
   bare button flashed crimson the moment it was hovered or focused. It was
   found by opening the project lightbox, which focuses its close button on
   open and therefore rendered it pink immediately. Every themed button sets its
   own hover, so this only ever showed on the bare ones. */
button:hover,
button:focus,
[type="button"]:hover,
[type="button"]:focus,
[type="submit"]:hover,
[type="submit"]:focus {
	background-color: transparent;
	color: inherit;
}

/* ---------------------------------------------------------------------------
   Elementor buttons had no hover state at all.

   Measured with a real pointer and a byte-comparison of the button clipped
   before and after: the hero's "Book a design consultation" was PIXEL-IDENTICAL
   on hover, as were the /brochures/ category pills. The header's own
   .ks-nav-cta does respond — so a visitor got feedback from the small button in
   the corner and none from the large one under the headline, on the control
   that books the appointment.

   Elementor had even written `transition: all 0.3s` onto these buttons: a
   transition sitting there for a change that never happened. Its own hover rule
   is `{color:#fff}`, which the `a:hover { color: inherit }` above cancels —
   correctly, since that is what stops the parent theme's pink, but it left
   these mute.

   THE STATES ARE NOT NEW. Both are the inversion the site already uses:
   .ks-nav-cta and contact-form.css:262 swap ink and cream exactly this way, and
   archives.css:747 does it for the outline buttons. Contrast is therefore
   already-measured territory — cream on ink is about 13:1.

   Three button variants exist, and only one needs its own rule:
     filled brass        bg #B08D57, ink text        -> ink bg, cream text
     ghost on cream      transparent, grey text      -> ink bg, cream text
     ghost on INK        transparent, cream text     -> cream bg, ink text
   The first two share a hover, so only the ink-ground ghosts are overridden.
   --------------------------------------------------------------------------- */
.elementor-button {
	transition: background-color 160ms ease, color 160ms ease,
		border-color 160ms ease, transform 160ms cubic-bezier(0.2, 0, 0, 1);
}

/* Hover is gated to real pointers so a tap does not leave a phone stuck in a
   hover state it cannot clear. :focus-visible is NOT gated — a keyboard needs
   the same signal on every device. */
/* WHY !important, which is not usually the answer.
   Elementor writes per-element styles as
   `.elementor-9 .elementor-element.elementor-element-8913119 .elementor-button`
   — specificity (0,4,0), with a different generated id per button. A theme rule
   cannot beat that generically without either matching the depth (fragile: the
   ids are rewritten on export, see known-issues on element ids) or winning on
   source order, which is not guaranteed between two enqueued stylesheets.
   Confirmed by measurement: the same rules WITHOUT !important left the hero
   button pixel-identical on hover.

   It is confined to the :hover and :focus-visible states, so it can never
   affect how a button renders at rest — which is where Elementor's per-element
   styling is doing real work and should keep winning. */
@media (hover: hover) and (pointer: fine) {
	.elementor-button:hover {
		background-color: #1C2A33 !important;
		border-color: #1C2A33 !important;
		color: #F5F2EC !important;
	}

	.ks-home-hero .elementor-button:hover,
	[class*="ks-home-location"] .elementor-button:hover {
		background-color: #F5F2EC !important;
		border-color: #F5F2EC !important;
		color: #1C2A33 !important;
	}
}

.elementor-button:focus-visible {
	background-color: #1C2A33 !important;
	border-color: #1C2A33 !important;
	color: #F5F2EC !important;
}

.ks-home-hero .elementor-button:focus-visible,
[class*="ks-home-location"] .elementor-button:focus-visible {
	background-color: #F5F2EC !important;
	border-color: #F5F2EC !important;
	color: #1C2A33 !important;
}

/* A press worth feeling, and no more than that. 0.985 rather than a bounce:
   the button gives very slightly under the finger and returns. */
.elementor-button:active {
	transform: scale(0.985);
}

@media (prefers-reduced-motion: reduce) {
	/* The colour change stays — it is information, not decoration. Only the
	   easing and the press are dropped. */
	.elementor-button {
		transition: none;
	}

	.elementor-button:active {
		transform: none;
	}
}

/* Accreditation marks in the footer.
   They were the words "KBSA Approved   TrustMark Registered", unlinked — which is
   indistinguishable from a claim nobody has checked. TrustMark publishes a
   per-firm register, so its mark links there and the claim becomes verifiable
   in one click. KBSA's listing 404s and their site search returns nothing for
   this firm, so that mark is deliberately NOT linked: a logo pointing at a dead
   page is worse than the plain text it replaced.

   Sized by height so the two marks agree optically despite different aspect
   ratios, and set in cream/white variants because the footer ground is ink. The
   KBSA file is a knockout — the band is cream and the word APPROVED is the ink
   behind it showing through. */
.ks-accreds {
	display: flex;
	align-items: center;
	gap: 22px;
	flex-wrap: wrap;
}

/* The footer is an Elementor document and its text-editor widgets carry their
   own image rules at a higher specificity than a single class, so these are
   scoped under the paragraph AND marked important. Without it the KBSA mark
   rendered at its natural 782x536 — measured. */
.ks-accreds .ks-accred,
.ks-accred {
	display: block;
	width: auto !important;
	height: 34px !important;
	max-width: none;
	/* The marks are trademarks and should not be recoloured or stretched; height
	   alone, with width auto, keeps each one in proportion. */
	opacity: 0.9;
}

.ks-accreds .ks-accred--trustmark {
	height: 30px !important;
}

.ks-accred-link {
	display: inline-flex;
	align-items: center;
	/* 44px of height for a thumb, without making the mark itself bigger. */
	min-height: 44px;
}

.ks-accred-link:hover .ks-accred,
.ks-accred-link:focus-visible .ks-accred {
	opacity: 1;
}

.ks-accred-link:focus-visible {
	outline: 2px solid var(--ks-brass, #B08D57);
	outline-offset: 4px;
}

/* ---------------------------------------------------------------------------
   The four homepage category cards are landscape, not portrait.

   A DELIBERATE DEVIATION FROM THE DESIGN, recorded as such. The design draws
   these at `aspect-ratio: 3 / 4` (design lines 251, 261 and their siblings) and
   the build follows it. The trouble is the photographs: the design's own source
   images for these four slots are 16:9 landscape — 800x450 as rendered — so a
   3:4 box discards roughly 58% of each frame's width and lands on whatever
   happens to sit in the middle. On a kitchen that is usually a run of cabinetry
   with the island, the light and the room cropped out of it.

   The site already treats these cards as landscape on a phone: the builder
   appends `@media (max-width: 767px) { aspect-ratio: 4 / 3 }` to this exact
   widget (build-homepage.php, kitchensmiths_category_card(), following design
   line 1101). So landscape is an established treatment for these four cards
   rather than something invented here — this extends it to every width instead
   of only the small one.

   Done in the theme because /home/ is build-locked: the CSS holds whether or
   not the page is ever rebuilt, and it does not touch the saved document.

   Anchored on .ks-home-cat-card, which is hand-authored in the builder and
   therefore survives an export/reimport. The generated .elementor-element-*
   ids beside it do not (see known-issues on element ids being rewritten), which
   is why they are not used here. !important because Elementor writes the ratio
   as a per-element custom_css rule that outranks a plain class selector. */
.ks-home-cat-card img {
	aspect-ratio: 4 / 3 !important;
}

/* ---------------------------------------------------------------------------
   The history timeline on /our-story/: rhythm, alignment, and one stray measure.

   The alternating rows were sound in principle and ragged in fact. Measured at
   1440 before this block, reading down the page:

     1992  image 383 / text 304      1993  text 353 / image 719
     1994  image 719 / text 272      2001  text 322 / image 383
     2020  text 1240 wide, no image
     2025  image 383 / text 459      2026  text 353 / image 383

   Three separate faults, which together are what reads as mess.

   ONE — NO RHYTHM BETWEEN ROWS. The rows abut exactly: 1992 ends at y=1097 and
   1993 begins at y=1098. The only thing separating them was 40px of padding
   under the PROSE column, which shows up only when the prose happens to be the
   taller of the two cells. So the gap between rows alternated between 40px and
   nothing at all, governed by which side had the taller content — a rhythm set
   by accident. The gap now belongs to the row list, so it is the same 72px
   every time, and the padding that used to fake it is removed.

   TWO — THE HOLES. Cells were top-aligned, so a 272px paragraph beside a 719px
   portrait left a 447px void beneath it, and the eye reads the void as a break
   in the timeline rather than as part of the row. Centring the pair splits that
   space above and below, which is what makes a short entry look placed rather
   than stranded. The mixed aspect ratios stay: they are deliberate, and they
   are what stops the column reading as a table.

   THREE — ONE ROW AT THE WRONG MEASURE. 2020 has no photograph, on purpose —
   there is none in the media map for that year and captioning it with another
   year's picture would be a small lie on the one page that is entirely about
   chronology. But with nothing beside it the prose stretched the full 1240px,
   so a single paragraph ran at more than double the line length of every other
   entry. It now takes the same half-column the other entries take. `:only-child`
   is doing the work: it matches that row precisely because it is the only one
   with a single cell, so no year is named here and adding a photograph for 2020
   later undoes this rule automatically.

   IN CSS, NOT IN tools/pages/our-story.php, because page 10 is build-locked AND
   has drifted from its definition — there are hand edits in the saved document
   that the seeder does not know about, and re-seeding would discard them. The
   definition and tools/lib/page-sections.php carry the same values so a future
   rebuild matches, but nothing here depends on that rebuild happening.

   Anchored on .ks-story-rows, added to the saved document directly rather than
   by a re-seed for the same reason. The .elementor-element-* ids beside it are
   regenerated on every build and must never be named (see known-issues). */

/* The row list: one gap, applied once. */
.ks-story-rows > .e-con-inner > .e-con {
	row-gap: 72px;
}

/* Each row: centre the picture against its paragraphs. */
.ks-story-rows > .e-con-inner > .e-con > .e-con {
	--align-items: center;
}

/* The 40px that used to stand in for a row gap, from whichever cell carried it. */
.ks-story-rows > .e-con-inner > .e-con > .e-con > .e-con {
	--padding-bottom: 0px;
}

/* A row with no photograph keeps the column measure rather than running full
   width. 90px is the row's own column gap, so this is exactly the width the
   two-cell rows give their prose. */
.ks-story-rows > .e-con-inner > .e-con > .e-con > .e-con:only-child {
	max-width: calc((100% - 90px) / 2);
}

@media (max-width: 1024px) {

	/* Stacked, so there is no picture to centre against and no second column
	   for a lone entry to be measured against. Both rules would otherwise
	   fight the single-column layout — the max-width above would squeeze 2020
	   into half a phone screen. */
	.ks-story-rows > .e-con-inner > .e-con {
		row-gap: 56px;
	}

	.ks-story-rows > .e-con-inner > .e-con > .e-con > .e-con:only-child {
		max-width: none;
	}

	/* THE PICTURE FIRST, IN EVERY ROW. Stacked, a timeline that reads
	   picture-then-words on one entry and words-then-picture on the next has
	   no pattern left to follow — the alternation is a two-column device and
	   it means nothing in one column. page-sections.php says exactly this in
	   a comment above the row it builds, and then does not do it: the ternary
	   there tests image_side against 'column-reverse', a value it never holds,
	   so both branches return 'column' and every row stacks in DOM order.
	   Fixed in the builder too, but the fix cannot reach this page without a
	   re-seed, and page 10 is locked and drifted.

	   Matches on the rows whose picture is the LAST cell, which is precisely
	   the set the builder would have reversed. The 2020 row has one cell and
	   no picture, so it matches nothing and is left alone. */
	.ks-story-rows > .e-con-inner > .e-con > .e-con:has(> .e-con:last-child img) {
		--flex-direction: column-reverse;
	}
}

/* ---------------------------------------------------------------------------
   The consent banner steps out of the way of a full-screen viewer.

   MEASURED: the brochure viewer opens at z-index 9000 and fills the screen.
   #wpconsent-root carries --wpconsent-z-index: 900000 — a hundred times
   higher — so the banner went on sitting over the open brochure, across the
   page-turn controls at the foot of it. Same for the project lightbox.

   This is also the honest fix for the reason the consent plugins were
   deactivated in the first place. The symptom was recorded as the banner
   breaking the viewer's focus trap, and it was real: a modal that traps focus
   cannot trap what is painted on top of it, so tabbing inside an open
   brochure could land on the banner's buttons. `display: none` takes those
   controls out of the accessibility tree and the tab order together with the
   pixels, which is what a focus trap needs — `visibility: hidden` or an
   opacity of 0 would hide the banner while leaving it tabbable, which is the
   worse half of the same bug.

   NOT DISMISSED, ONLY HIDDEN. No consent is given or withdrawn by opening a
   brochure; the banner is unanswered when it goes and unanswered when it
   comes back, and closing the viewer returns it exactly as it was.

   Plain CSS reaches this even though the banner itself is inside a shadow
   root: #wpconsent-root is an ordinary element in the document, and hiding
   the host hides everything it contains. */
html.ks-viewer-open #wpconsent-root,
html.ks-lb-open #wpconsent-root {
	display: none;
}

/* ---------------------------------------------------------------------------
   The sustainability hero, re-scrimmed for a bright photograph.

   kitchensmiths_sec_hero() lays a 100deg gradient over the image, from
   rgba(22,34,42,0.84) on the left to 0.1 on the right. That is tuned for the
   design's own hero images, which are dark kitchen interiors. This one is the
   More:Trees planting site: open field, big sky, shot in daylight. Measured
   against the bare scrim with the text hidden, the breadcrumb ran at 1.92:1,
   the h1 at 2.09:1 and the standfirst at 2.48:1 — against the 4.5:1 and 3:1
   WCAG AA asks for. The heading spans the full 1240px column, so its right
   half sits on the transparent end of the gradient over the brightest part of
   the sky.

   Same remedy as the booking hero, and for the same reason: a flat wash heavy
   enough to fix it turns the photograph into a grey panel, which defeats the
   point of showing the actual site. So the copy moves instead of the light —
   pushed to the foot of a slightly taller hero, over a ramp that reaches 0.82
   beneath it. The sky and the tree tubes stay legible across the top half,
   which is the half worth seeing. */
body .elementor .elementor-element.ks-sus-hero {
	--min-height: 520px;
	--justify-content: flex-end;
	--padding-bottom: 40px;
}

body .elementor .elementor-element.ks-sus-hero::before {
	background-image: linear-gradient(
		180deg,
		rgba(22, 34, 42, 0.10) 0%,
		rgba(22, 34, 42, 0.14) 22%,
		rgba(22, 34, 42, 0.82) 44%,
		rgba(22, 34, 42, 0.88) 100%
	);
}
