/**
 * Taxonomy archives: /door-styles/, /finishes/, /layouts/ and every term
 * under them.
 *
 * WHY A STYLESHEET RATHER THAN THE SECTION COMPOSERS. Term archives are
 * rendered by a PHP template, not seeded as Elementor documents, so they
 * cannot use tools/lib/page-sections.php at all -- that emits Elementor JSON.
 * The two mechanisms are different; the DESIGN VALUES are the same, and they
 * are written here once so an archive and a seeded page look like the same
 * site.
 *
 * Every value below is the design's, and matches the composers exactly:
 *   ink #1C2A33, accent #B08D57, cream #F5F2EC, panel #FFFDF9, sand #EBE5DB,
 *   body #57616A, secondary #6B747C
 *   Marcellus for anything that speaks, Jost 300 for body, Jost 500 uppercase
 *   at 0.14-0.22em tracking for eyebrows
 *   1320px content, 40px inset, 110px vertical rhythm, ZERO border-radius
 *
 * Mobile mirrors the composers' decisions rather than inventing its own:
 * padding scales to 0.68x tablet and 0.5x mobile, the inset narrows to 24px,
 * and image tiles go TWO across rather than one -- a six-tile grid at one per
 * row is six screens tall.
 */

/* hello-elementor caps main.site-main at its own content width -- measured
   1140px, centring the whole archive at x=150 so the 1320px shell below never
   applied and content opened at 190 instead of 100. The seeded Elementor
   pages never hit this because Elementor supplies its own full-width wrapper.
   It also pads the element 10px each side under 576px, which opened mobile
   content at 34 instead of 24.

   THE SELECTOR NEEDS THREE PARTS, and `main.ks-arch` was not enough. The rule
   being overridden is

       body:not([class*=elementor-page-]) .site-main { max-width: 1140px }

   at specificity (0,2,1) -- `body` plus the attribute selector inside :not()
   plus the class. `main.ks-arch` is only (0,1,1), so it matched, appeared in
   devtools, and lost anyway; measured still 1140px wide with the rule live.
   `body main.site-main.ks-arch` is (0,2,2) and wins on its own merits rather
   than on stylesheet order. */
body main.site-main.ks-arch {
	width: 100%;
	max-width: none;
	padding: 0;
}

/* TWO SETS OF COLOURS, AND THE DIFFERENCE IS DELIBERATE.
   The design's palette is unchanged: --ks-accent, --ks-secondary and --ks-muted
   still hold the values the design file states, and everything that draws a
   rule, a border, a hover or a large heading still uses them.

   What changed at the 2026-08-10 review is the values used for SMALL TEXT.
   Measured against the real rendered backdrop, the design's own three carried
   eyebrows, breadcrumbs, card captions, chip counts and form sub-labels at
   2.47-4.26:1 against a 4.5:1 floor for text under 18.66px — 158 failing text
   groups across all 18 page types, on the most-repeated elements on the site.

   The -text variants below are the same hues darkened in HLS space until they
   clear 4.5:1 on the DARKEST ground they actually sit on, which is sand
   (#EBE5DB) rather than cream. That last part matters: darkening only far
   enough to pass on cream still fails on sand, which is where the first attempt
   at this landed. Measured worst case for each is 4.51, 4.52 and 4.52. */
.ks-arch {
	--ks-ink: #1c2a33;
	--ks-accent: #b08d57;
	--ks-cream: #f5f2ec;
	--ks-panel: #fffdf9;
	--ks-sand: #ebe5db;
	--ks-body: #57616a;
	--ks-secondary: #606870;
	--ks-muted: #636770;
	--ks-hairline: rgba(28, 42, 51, 0.16);
	--ks-inset: 40px;
	--ks-rhythm: 110px;

	/* Brass, dark enough to carry a 10-12px eyebrow. The undarkened
	   --ks-accent stays above for rules, borders and hover. */
	--ks-accent-text: #7d633b;
}

@media (max-width: 1024px) {
	.ks-arch {
		--ks-inset: 32px;
		--ks-rhythm: 75px;
	}
}

@media (max-width: 767px) {
	.ks-arch {
		--ks-inset: 24px;
		--ks-rhythm: 55px;
	}
}

.ks-arch-shell {
	max-width: 1320px;
	margin: 0 auto;
	padding: 0 var(--ks-inset);
}

.ks-arch-section {
	padding: var(--ks-rhythm) 0;
}

/* ---------------------------------------------------------------- hero -- */

.ks-arch-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: center;
	/* Set per screen as an inline custom property, because the design varies
	   it: 460px on Kitchens and Sinks, 500 on Finishes and Layouts, 520 on the
	   door styles, 560 on the furniture houses. The mobile rule below
	   overrides min-height DIRECTLY rather than this variable, so an inline
	   value cannot leak past the breakpoint. */
	min-height: var(--ks-hero-h, 460px);
	background-position: center center;
	background-size: cover;
	color: var(--ks-cream);
}

/* The ink wash is a pseudo-element rather than a second background layer so
   the alpha is stated once and is not multiplied by anything. Elementor's own
   overlay control applies opacity: 0.5 on top of whatever you set, which
   halved this gradient on the seeded pages and washed the heading out. */
.ks-arch-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(100deg, rgba(22, 34, 42, 0.84) 0%, rgba(22, 34, 42, 0.5) 55%, rgba(22, 34, 42, 0.1) 100%);
	pointer-events: none;
}

/* WIDTH 100% IS LOAD-BEARING. The hero is a column flex container, and an
   item with `margin: 0 auto` has auto margins on the CROSS axis -- which
   suppresses the default stretch and sizes the shell to fit its content
   instead. Measured: the shell came out 640px wide with 400px auto margins
   either side, putting the breadcrumb and the h1 at x=440 while every section
   below them sat at 100. Stating the width restores the stretch; the
   max-width and auto margins then centre it as they do everywhere else. */
.ks-arch-hero > .ks-arch-shell {
	position: relative;
	width: 100%;
}

.ks-arch-crumb {
	font: 300 13px/1 Jost, sans-serif;
	color: rgba(245, 242, 236, 0.6);
}

.ks-arch-hero h1 {
	max-width: 700px;
	margin: 22px 0 0;
	font: 400 58px/1.1 Marcellus, serif;
	letter-spacing: -0.015em;
	color: var(--ks-cream);
}

.ks-arch-lede {
	/* 580 on every product screen the design draws; the 560 this had came
	   from the Kitchens screen, which is the one exception. */
	max-width: 580px;
	margin: 20px 0 0;
	font: 300 18px/1.8 Jost, sans-serif;
	color: rgba(245, 242, 236, 0.84);
}

/* --------------------------------------------------------------- tiles -- */

.ks-arch-section h2 {
	margin: 0 0 44px;
	font: 400 40px/1.2 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-arch-grid {
	display: grid;
	gap: 40px 24px;
	grid-template-columns: repeat(var(--ks-cols, 4), minmax(0, 1fr));
}

/* `align-self: start` matters. A grid item stretches to the height of the
   tallest cell in its row by default, and these tiles carry a name and
   sometimes a description, so the rows are ragged. Stretched, the tile box grew
   taller than its own contents and the image below inherited that height. */
.ks-arch-tile {
	display: block;
	align-self: start;
	color: inherit;
	text-decoration: none;
}

/* HEIGHT IS auto, AND HAS TO BE. This rule read `height: 100%` and produced two
   visible faults at once.

   `aspect-ratio` only applies when one of the two dimensions is auto. With both
   width and height set, the ratio was ignored entirely: the "Other door styles"
   tiles measured 1.15 against the 4/3 they ask for, and "Other finishes"
   measured 0.67 against 3/4. The tiles were not the shape the template asked
   for, and no two rows agreed.

   Worse, `height: 100%` resolved against the stretched tile box, so the image
   filled the whole of it and the <h3> after it was laid out past the bottom
   edge -- printing the name on top of whatever the next row held. That is the
   overlap; it was never a z-index or a margin.

   With height auto the ratio governs, the image is the shape it claims, and the
   name sits under it. */
.ks-arch-tile img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: var(--ks-ratio, 1);
	object-fit: cover;
}

.ks-arch-tile h3 {
	margin: 18px 0 0;
	font: 400 23px/1.3 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-arch-tile p {
	margin: 8px 0 0;
	font: 300 15px/1.7 Jost, sans-serif;
	color: var(--ks-secondary);
}

.ks-arch-tile:hover h3 {
	color: var(--ks-accent);
}

/* ------------------------------------------------------------ CTA band -- */

.ks-arch-cta {
	background: var(--ks-ink);
	color: var(--ks-cream);
}

.ks-arch-cta > .ks-arch-shell {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 60px;
	padding-top: 96px;
	padding-bottom: 96px;
}

.ks-arch-cta h2 {
	max-width: 620px;
	margin: 0;
	font: 400 40px/1.2 Marcellus, serif;
	color: var(--ks-cream);
}

.ks-arch-button {
	flex: none;
	display: inline-block;
	padding: 21px 36px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #16222a;
	background: var(--ks-accent);
	text-decoration: none;
}

.ks-arch-button:hover {
	background: var(--ks-cream);
}

/* --------------------------------------------------------- empty state -- */

.ks-arch-empty {
	margin: 0;
	font: 300 17px/1.8 Jost, sans-serif;
	color: var(--ks-secondary);
}

/* ---------------------------------------------------------- responsive -- */

@media (max-width: 1024px) {
	.ks-arch-hero h1 {
		font-size: 44px;
	}

	.ks-arch-section h2,
	.ks-arch-cta h2 {
		font-size: 32px;
	}

	.ks-arch-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.ks-arch-hero {
		min-height: 360px;
	}

	.ks-arch-hero h1 {
		font-size: 34px;
	}

	.ks-arch-lede {
		font-size: 16px;
	}

	.ks-arch-section h2,
	.ks-arch-cta h2 {
		font-size: 26px;
		margin-bottom: 28px;
	}

	/* TWO across, not one: the composers made the same call for the same
	   reason -- one full-width tile per row turns a six-tile grid into six
	   screens of scrolling. */
	.ks-arch-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 28px 16px;
	}

	.ks-arch-tile h3 {
		margin-top: 12px;
		font-size: 19px;
	}

	.ks-arch-cta > .ks-arch-shell {
		flex-direction: column;
		align-items: flex-start;
		gap: 26px;
		padding-top: 56px;
		padding-bottom: 56px;
	}
}

/* ---------------------------------------------- ACF-driven term content -- */

.ks-arch-intro {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 90px;
	align-items: start;
}

.ks-arch-intro-heading {
	margin: 0;
	font: 400 44px/1.18 Marcellus, serif;
	color: var(--ks-ink);
	text-wrap: pretty;
}

.ks-arch-prose p {
	margin: 0 0 22px;
	font: 300 18px/1.85 Jost, sans-serif;
	color: var(--ks-body);
	text-wrap: pretty;
}

.ks-arch-prose p:last-child {
	margin-bottom: 0;
}

.ks-arch-eyebrow {
	display: block;
	margin-bottom: 18px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--ks-accent-text);
}

.ks-arch-points {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 40px 34px;
}

.ks-arch-point h3 {
	margin: 0;
	font: 400 25px/1.25 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-arch-point p {
	margin: 12px 0 0;
	font: 300 16px/1.8 Jost, sans-serif;
	color: var(--ks-secondary);
	text-wrap: pretty;
}

.ks-arch-more {
	margin: 32px 0 0;
}

@media (max-width: 1024px) {
	.ks-arch-intro {
		grid-template-columns: minmax(0, 1fr);
		gap: 34px;
	}

	.ks-arch-intro-heading {
		font-size: 34px;
	}

	.ks-arch-points {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.ks-arch-intro-heading {
		font-size: 28px;
	}

	.ks-arch-prose p {
		font-size: 16px;
	}

	/* ONE across for text, unlike the image tiles above: two columns of
	   prose at 390px leaves about 170px of measure, which is unreadable. */
	.ks-arch-points {
		grid-template-columns: minmax(0, 1fr);
		gap: 28px;
	}

	.ks-arch-point h3 {
		font-size: 22px;
	}
}

/* ------------------------------------------- the designed door-style bits --
   Everything below reproduces a section the design actually draws, measured
   from docs/design/kitchensmiths-redesign.html:
     cards    Handleless line 2645, reused on Shaker 2879 and Traditional 3051
     gallery  Handleless line 2671, reused on In-Frame 2967
     detail   Shaker line 2905
     split    Traditional line 3077                                          */

.ks-arch-cards {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 24px;
}

.ks-arch-card {
	background: var(--ks-panel);
}

.ks-arch-card-media {
	position: relative;
	width: 100%;
	aspect-ratio: 4 / 3;
}

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

.ks-arch-card-body {
	padding: 34px 34px 40px;
}

.ks-arch-card-body h3 {
	margin: 0;
	font: 400 27px/1.2 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-arch-card-body p {
	margin: 14px 0 0;
	font: 300 16px/1.8 Jost, sans-serif;
	color: var(--ks-secondary);
	text-wrap: pretty;
}

.ks-arch-gallery {
	display: grid;
	grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
	gap: 24px;
}

.ks-arch-gallery-stack {
	display: grid;
	gap: 24px;
}

.ks-arch-gallery-lead {
	position: relative;
	aspect-ratio: 1;
}

.ks-arch-gallery-stack > div {
	position: relative;
	aspect-ratio: 16 / 9;
}

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

.ks-arch-detail {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 90px;
	align-items: center;
}

.ks-arch-detail-media {
	position: relative;
	aspect-ratio: 4 / 5;
}

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

.ks-arch-detail-body h2 {
	margin: 20px 0 0;
	font: 400 40px/1.18 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-arch-rows {
	margin-top: 34px;
}

.ks-arch-row {
	padding: 20px 0;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

/* The design rules the LAST row underneath as well, closing the list. */
.ks-arch-row:last-child {
	border-bottom: 1px solid rgba(28, 42, 51, 0.16);
}

.ks-arch-row-label {
	display: block;
	font: 400 17px/1.4 Jost, sans-serif;
	color: var(--ks-ink);
}

.ks-arch-row-text {
	display: block;
	margin-top: 6px;
	font: 300 16px/1.7 Jost, sans-serif;
	color: var(--ks-secondary);
}

/* A text link underlined in brass, NOT a filled button -- the same call
   tools/lib/page-sections.php makes for the panels' call to action. */
.ks-arch-textlink {
	display: inline-block;
	margin-top: 34px;
	padding-bottom: 8px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ks-ink);
	border-bottom: 1px solid var(--ks-accent);
	text-decoration: none;
}

.ks-arch-split {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	background: var(--ks-ink);
	color: var(--ks-cream);
}

.ks-arch-split-media {
	position: relative;
	min-height: 420px;
}

.ks-arch-split-media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.ks-arch-split-body {
	padding: 68px 60px;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.ks-arch-split-body h2 {
	margin: 20px 0 0;
	font: 400 36px/1.2 Marcellus, serif;
	color: var(--ks-cream);
}

.ks-arch-split-body .ks-arch-prose p {
	margin: 20px 0 0;
	font: 300 17px/1.8 Jost, sans-serif;
	color: rgba(245, 242, 236, 0.78);
}

@media (max-width: 1024px) {
	.ks-arch-cards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.ks-arch-detail {
		grid-template-columns: minmax(0, 1fr);
		gap: 34px;
	}

	.ks-arch-detail-body h2 {
		font-size: 32px;
	}

	.ks-arch-split-body {
		padding: 48px 40px;
	}

	.ks-arch-split-body h2 {
		font-size: 30px;
	}
}

@media (max-width: 767px) {
	/* ONE across: every card carries a paragraph, so this follows the points
	   grid rather than the image tiles. */
	.ks-arch-cards {
		grid-template-columns: minmax(0, 1fr);
	}

	.ks-arch-card-body {
		padding: 26px 26px 30px;
	}

	.ks-arch-card-body h3 {
		font-size: 23px;
	}

	/* The stack falls under the lead image rather than beside it, and the two
	   wide images sit side by side -- image tiles, so two across. */
	.ks-arch-gallery {
		grid-template-columns: minmax(0, 1fr);
		gap: 16px;
	}

	.ks-arch-gallery-stack {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 16px;
	}

	.ks-arch-detail-body h2 {
		font-size: 26px;
	}

	.ks-arch-split {
		grid-template-columns: minmax(0, 1fr);
	}

	.ks-arch-split-media {
		min-height: 240px;
	}

	.ks-arch-split-body {
		padding: 34px 24px 40px;
	}

	.ks-arch-split-body h2 {
		font-size: 26px;
	}

	.ks-arch-split-body .ks-arch-prose p {
		font-size: 16px;
	}
}

/* --------------------------------------------------------- projects -------
   The Projects archive (design line 1379). It reuses .ks-arch-shell, the
   section rhythm, the empty state and the closing band; only the header, the
   filter chips and the card grid are its own.                              */

.ks-proj-head {
	padding: 96px 0 64px;
}

.ks-proj-body {
	padding: 0 0 var(--ks-rhythm);
}

.ks-proj-crumb {
	color: var(--ks-muted);
}

.ks-proj-title {
	max-width: 860px;
	margin: 24px 0 0;
	font: 400 62px/1.08 Marcellus, serif;
	letter-spacing: -0.015em;
	color: var(--ks-ink);
	text-wrap: pretty;
}

.ks-proj-lede {
	max-width: 660px;
	margin: 26px 0 0;
	font: 300 19px/1.8 Jost, sans-serif;
	color: var(--ks-body);
	text-wrap: pretty;
}

/* Chips are LINKS, not toggles — each is a filtered URL. See inc/projects.php
   for why. */
.ks-proj-filters {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 44px;
}

.ks-proj-chip {
	padding: 13px 20px;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ks-body);
	border: 1px solid rgba(28, 42, 51, 0.2);
	text-decoration: none;
	transition: border-color 0.2s ease, color 0.2s ease;
}

.ks-proj-chip:hover {
	border-color: var(--ks-accent);
	color: var(--ks-ink);
}

.ks-proj-chip.is-on {
	color: var(--ks-cream);
	background: var(--ks-ink);
	border-color: var(--ks-ink);
}

.ks-proj-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 40px 24px;
}

.ks-proj-card {
	display: block;
	text-decoration: none;
}

/* The project cards gave the pointer NOTHING back — measured by pixel-diffing
   each element hovered against not, with transitions disabled: 0.00% change.
   The blog cards in this same stylesheet do respond (8-85%), so the grid that
   matters most was the one grid that read as a set of photographs rather than a
   set of destinations, and on /projects/ that is the entire browsing mechanic.

   The image lifts very slightly and the caption takes the accent, matching what
   .ks-blog-card-title already does. :focus-visible is paired with it throughout
   so a keyboard gets the same signal a mouse does, which was the other half
   missing. */
.ks-proj-card-media {
	overflow: hidden;
}

.ks-proj-card-media img {
	transition: transform 0.45s cubic-bezier(0.2, 0.6, 0.2, 1);
}

.ks-proj-card:hover .ks-proj-card-media img,
.ks-proj-card:focus-visible .ks-proj-card-media img {
	transform: scale(1.03);
}

.ks-proj-card:hover .ks-proj-card-title,
.ks-proj-card:focus-visible .ks-proj-card-title {
	color: var(--ks-accent-text, #7d633b);
}

.ks-proj-card:focus-visible {
	outline: 2px solid var(--ks-accent, #b08d57);
	outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
	.ks-proj-card-media img,
	.ks-proj-card:hover .ks-proj-card-media img,
	.ks-proj-card:focus-visible .ks-proj-card-media img {
		transition: none;
		transform: none;
	}
}

.ks-proj-card-media {
	display: block;
	position: relative;
	width: 100%;
	aspect-ratio: 4 / 3;
}

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

.ks-proj-card-caption {
	display: block;
	margin-top: 18px;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ks-muted);
}

.ks-proj-card-title {
	display: block;
	margin-top: 10px;
	font: 400 25px/1.3 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-proj-card-summary {
	display: block;
	margin-top: 8px;
	font: 300 15px/1.6 Jost, sans-serif;
	color: var(--ks-secondary);
}

@media (max-width: 1024px) {
	.ks-proj-head {
		padding: 66px 0 44px;
	}

	.ks-proj-title {
		font-size: 44px;
	}

	.ks-proj-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.ks-proj-head {
		padding: 48px 0 32px;
	}

	.ks-proj-title {
		font-size: 34px;
	}

	.ks-proj-lede {
		font-size: 16px;
	}

	/* TWO across, as every other image grid on the site does at 390: one card
	   per row would make twelve projects twelve screens of scrolling. */
	.ks-proj-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 28px 16px;
	}

	.ks-proj-card-title {
		font-size: 19px;
	}

	.ks-proj-card-summary {
		display: none;
	}
}

/* The way out of a filter combination that found nothing. Inline with the
   empty-state sentence rather than a button: it is a correction, not a call
   to action. */
.ks-proj-clear {
	color: var(--ks-ink);
	border-bottom: 1px solid var(--ks-accent);
	padding-bottom: 2px;
	text-decoration: none;
	white-space: nowrap;
}

/* ---------------------------------------------------- one project --------
   The Project screen (design line 756).                                    */

.ks-proj-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	min-height: 640px;
	padding-bottom: 64px;
	background-position: center center;
	background-size: cover;
	color: var(--ks-cream);
}

/* The wash runs UPWARDS here, not across: the title sits at the foot of the
   image, so the dark end has to be at the bottom (design line 760). */
.ks-proj-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgba(22, 34, 42, 0.86) 0%, rgba(22, 34, 42, 0.2) 55%, rgba(22, 34, 42, 0.35) 100%);
	pointer-events: none;
}

.ks-proj-hero > .ks-arch-shell {
	position: relative;
	width: 100%;
}

.ks-proj-hero-eyebrow {
	display: block;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--ks-accent);
}

.ks-proj-hero-eyebrow a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid rgba(176, 141, 87, 0.5);
	padding-bottom: 2px;
}

.ks-proj-hero-eyebrow a:hover {
	border-bottom-color: var(--ks-accent);
}

.ks-proj-hero h1 {
	max-width: 780px;
	margin: 20px 0 0;
	font: 400 60px/1.08 Marcellus, serif;
	color: var(--ks-cream);
	text-wrap: pretty;
}

/* NAMED ks-proj-LAYOUT, NOT ks-proj-body. The archive already uses
   .ks-proj-body for its own <section>, whose rule is `padding: 0 0 rhythm` --
   and this grid sits ON the shell, so that rule zeroed the shell's 40px inset
   and opened the body copy at x=60 while every other block on the page sat at
   100. A collision between two files' section names, measured rather than
   spotted. */
.ks-proj-layout {
	display: grid;
	grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
	gap: 90px;
	align-items: start;
}

.ks-proj-standfirst {
	margin: 0;
	font: 400 27px/1.5 Marcellus, serif;
	color: var(--ks-ink);
	text-wrap: pretty;
}

.ks-proj-prose p {
	margin: 22px 0 0;
	font: 300 17px/1.9 Jost, sans-serif;
	color: var(--ks-body);
	text-wrap: pretty;
}

/* 30px under the standfirst, 22 between the paragraphs (design 771-772). */
.ks-proj-standfirst + .ks-proj-prose p:first-child {
	margin-top: 30px;
}

.ks-proj-aside {
	padding-top: 6px;
}

.ks-proj-spec-row {
	display: flex;
	justify-content: space-between;
	gap: 20px;
	padding: 18px 0;
	border-top: 1px solid var(--ks-hairline);
}

.ks-proj-spec-row:last-child {
	border-bottom: 1px solid var(--ks-hairline);
}

.ks-proj-spec-label {
	font: 500 11px/1.4 Jost, sans-serif;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ks-muted);
}

.ks-proj-spec-value {
	font: 300 16px/1.4 Jost, sans-serif;
	color: var(--ks-ink);
	text-align: right;
}

/* A value that goes somewhere says so, quietly — the brand and the term
   archives this project is tagged with. */
.ks-proj-spec-value.is-link {
	text-decoration: none;
	border-bottom: 1px solid rgba(176, 141, 87, 0.6);
	padding-bottom: 2px;
}

.ks-proj-spec-value.is-link:hover {
	border-bottom-color: var(--ks-accent);
	color: var(--ks-accent-text);
}

.ks-proj-gallery-section,
.ks-proj-quote-section {
	padding-top: 0;
}

.ks-proj-gallery {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 24px;
}

/* One item class; the aspect ratio is set inline per image because it is
   derived from that image, and a wide one spans the pair. */
.ks-proj-gallery-item {
	position: relative;
}

.ks-proj-gallery-item.is-wide {
	grid-column: span 2;
}

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

.ks-proj-quote {
	max-width: 1000px;
	margin: 0 auto;
	padding: 0;
	text-align: center;
}

.ks-proj-quote-text {
	display: block;
	font: 400 30px/1.5 Marcellus, serif;
	color: var(--ks-ink);
	text-wrap: pretty;
}

.ks-proj-quote-by {
	display: block;
	margin-top: 28px;
	font: 500 11px/1 Jost, sans-serif;
	font-style: normal;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--ks-muted);
}

.ks-proj-quote-link {
	display: inline-block;
	margin-top: 24px;
	padding-bottom: 8px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ks-ink);
	border-bottom: 1px solid var(--ks-accent);
	text-decoration: none;
}

.ks-proj-more {
	background: var(--ks-sand);
}

.ks-proj-more h2 {
	font-size: 38px;
}

@media (max-width: 1024px) {
	.ks-proj-hero {
		min-height: 460px;
		padding-bottom: 48px;
	}

	.ks-proj-hero h1 {
		font-size: 42px;
	}

	.ks-proj-layout {
		grid-template-columns: minmax(0, 1fr);
		gap: 40px;
	}

	.ks-proj-standfirst {
		font-size: 23px;
	}

	.ks-proj-quote-text {
		font-size: 24px;
	}
}

@media (max-width: 767px) {
	.ks-proj-hero {
		min-height: 380px;
		padding-bottom: 36px;
	}

	.ks-proj-hero h1 {
		font-size: 32px;
	}

	.ks-proj-standfirst {
		font-size: 20px;
	}

	.ks-proj-prose p {
		font-size: 16px;
	}

	/* The two uprights stay side by side — they are a pair, and one per row
	   would separate them. The wide shot already spans both. */
	.ks-proj-gallery {
		gap: 12px;
	}

	.ks-proj-quote-text {
		font-size: 20px;
	}

	.ks-proj-more h2 {
		font-size: 26px;
	}
}

/* -------------------------------------------------------------------------
   Client reviews — /reviews/ and one review.
   Design: the "Client reviews" screen at line 2703. Every number below is
   read off that screen: 96px/64px then 110px section padding, a 1320px shell
   inset 40px, a three column grid at 24px, the first card in ink at 46px/42px
   with a 25px quote and the rest on cream at 42px/38px with 21px, and
   attributions at 11px uppercase tracked 0.18em — gold on the ink card,
   grey on the others.
   ------------------------------------------------------------------------- */

.ks-rev-archive .ks-rev-head { padding: 96px 0 64px; }
.ks-rev-archive .ks-rev-body,
.ks-rev-archive .ks-rev-invite { padding: 0 0 110px; }

.ks-rev-head .ks-rev-title {
	max-width: 900px;
	margin: 24px 0 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 62px;
	line-height: 1.08;
	letter-spacing: -0.015em;
	text-wrap: pretty;
}

.ks-rev-head .ks-rev-lede {
	max-width: 680px;
	margin: 26px 0 0;
	font: 300 19px/1.8 Jost, sans-serif;
	color: #57616A;
	text-wrap: pretty;
}

.ks-rev-stats {
	display: flex;
	gap: 60px;
	margin-top: 56px;
	padding-top: 36px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
	flex-wrap: wrap;
}

.ks-rev-stat-figure {
	display: block;
	font-family: Marcellus, serif;
	font-size: 44px;
	line-height: 1;
}

.ks-rev-stat-label {
	display: block;
	margin-top: 10px;
	font: 300 15px/1.5 Jost, sans-serif;
	color: #606870;
}

.ks-rev-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 24px;
	align-items: start;
}

.ks-rev-card {
	background: #FFFDF9;
	padding: 42px 38px;
	display: flex;
	flex-direction: column;
	gap: 22px;
}

.ks-rev-card.is-ink {
	background: #1C2A33;
	color: #F5F2EC;
	padding: 46px 42px;
	gap: 24px;
}

.ks-rev-quote {
	margin: 0;
	border: 0;
	padding: 0;
	font-family: Marcellus, serif;
	font-size: 21px;
	line-height: 1.52;
	text-wrap: pretty;
}

.ks-rev-card.is-ink .ks-rev-quote {
	font-size: 25px;
	line-height: 1.48;
	color: #F5F2EC;
}

/* margin-top: auto pins the attribution to the foot of an uneven card, which
   is what keeps a three-across row reading straight. */
.ks-rev-meta {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin-top: auto;
}

.ks-rev-by {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	font-style: normal;
	color: #636770;
}

.ks-rev-card.is-ink .ks-rev-by {
	color: var(--accent, #B08D57);
}

/* Two colours, because this label appears on both card grounds and one value
   cannot serve both. Measured: #616770 is 5.61:1 on the panel and 2.58:1 on the
   ink card; #A8ADB4 is 6.51:1 on ink and 2.22:1 on the panel. The original set
   #A8ADB4 for every card, which read correctly on the one ink card in the grid
   and failed on all the others. Darkening it globally simply moved the failure
   onto the ink card, which is what the first pass at this did. */
.ks-rev-source {
	font: 300 11px/1 Jost, sans-serif;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: #616770;
}

.ks-rev-card.is-ink .ks-rev-source {
	color: #A8ADB4;
}

/* NOT IN THE DESIGN, which never had a review too long for its card. Kept
   deliberately quiet so it reads as a footnote to the quote rather than a
   second attribution competing with it. */
/* min-height, and only on a phone. At 390 this measured 290x13 — a text link in
   a list rather than in a sentence, so WCAG 2.2's inline-text exemption does not
   cover it, and 13px is a third of the 44px guideline. The rule is scoped to the
   phone breakpoint further down rather than applied here, so desktop spacing is
   unchanged. */
.ks-rev-more,
.ks-rev-source-link {
	font: 400 13px/1 Jost, sans-serif;
	letter-spacing: 0.04em;
	text-decoration: underline;
	text-underline-offset: 4px;
	color: #57616A;
}

.ks-rev-card.is-ink .ks-rev-more {
	color: rgba(245, 242, 236, 0.82);
}

/* The closing panel is a two-up: a photograph beside the invitation. */
.ks-rev-invite-inner {
	background: #EBE5DB;
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	padding: 0;
}

.ks-rev-invite-media {
	position: relative;
	min-height: 380px;
	overflow: hidden;
}

.ks-rev-invite-media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ks-rev-invite-copy { padding: 68px 60px; }

.ks-rev-invite-copy .ks-arch-eyebrow {
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--ks-accent-text, #7d633b);
}

.ks-rev-invite-copy h2 {
	margin: 20px 0 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 36px;
	line-height: 1.2;
}

.ks-rev-invite-copy p {
	margin: 18px 0 0;
	font: 300 17px/1.8 Jost, sans-serif;
	color: #57616A;
}

.ks-rev-invite-cta {
	display: inline-block;
	margin-top: 30px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #F5F2EC;
	background: #1C2A33;
	padding: 18px 30px;
	text-decoration: none;
}

.ks-rev-invite-cta:hover {
	background: var(--accent, #B08D57);
	color: #16222A;
}







/* 0.68x tablet, 0.5x mobile on the section padding, as everywhere else. */
@media (max-width: 1024px) {
	.ks-rev-archive .ks-rev-head { padding: 65px 0 44px; }
	.ks-rev-archive .ks-rev-body,
	.ks-rev-archive .ks-rev-invite { padding: 0 0 75px; }
	.ks-rev-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ks-rev-stats { gap: 40px; }
	.ks-rev-head .ks-rev-title { font-size: 46px; }
	.ks-rev-invite-copy { padding: 46px 40px; }
	/* Steps with the title above it. Pinned at 36px it ended up LARGER than the
	   34px h1 at phone widths, inverting the page's own hierarchy on the one
	   page where that h2 is the call to action. */
	.ks-rev-invite-copy h2 { font-size: 30px; }
}

/* 767, not 640. Every other template block in this file breaks at 767, and so
   does Elementor's own header drawer — so between 641 and 767 the header was
   already in phone mode while this grid was still two columns. At 660px that
   left two 294px columns with 42px of padding, i.e. 210px of measure for a
   21px quote, which wrapped after three or four words on the page whose whole
   job is to be read. */
@media (max-width: 767px) {
	.ks-rev-archive .ks-rev-head { padding: 48px 0 32px; }
	.ks-rev-archive .ks-rev-body,
	.ks-rev-archive .ks-rev-invite { padding: 0 0 55px; }
	.ks-rev-grid { grid-template-columns: minmax(0, 1fr); }
	.ks-rev-card,
	.ks-rev-card.is-ink { padding: 30px 26px; }
	.ks-rev-card.is-ink .ks-rev-quote { font-size: 21px; }
	.ks-rev-stats { gap: 26px; }
	.ks-rev-stat-figure { font-size: 34px; }
	.ks-rev-head .ks-rev-title { font-size: 34px; }
	.ks-rev-invite-inner { grid-template-columns: minmax(0, 1fr); }
	.ks-rev-invite-media { min-height: 240px; }
	.ks-rev-invite-copy { padding: 34px 26px; }
	.ks-rev-invite-copy h2 { font-size: 26px; }
	}

/* Infinite scroll's control. NOT IN THE DESIGN, which draws six reviews and
   stops; with fifty they have to arrive in instalments. Sized and tracked
   like the design's own buttons so it belongs to the page. */
.ks-rev-pagination-wrap {
	margin-top: 48px;
	display: flex;
	justify-content: center;
}

.ks-rev-more-button {
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #F5F2EC;
	background: #1C2A33;
	border: 0;
	padding: 18px 30px;
	cursor: pointer;
}

.ks-rev-more-button:hover:not(:disabled) {
	background: var(--accent, #B08D57);
	color: #16222A;
}

.ks-rev-more-button:disabled {
	opacity: 0.6;
	cursor: default;
}

/* The no-JS fallback: WordPress's own numbered pagination. */
.ks-rev-pagination .page-numbers {
	font: 400 14px/1 Jost, sans-serif;
	padding: 12px 14px;
	color: #57616A;
	text-decoration: none;
}

.ks-rev-pagination .page-numbers.current {
	color: #1C2A33;
	text-decoration: underline;
	text-underline-offset: 4px;
}

/* The archive pages twelve at a time and does it fast enough to be invisible;
   this is what tells the visitor there is more, and how much. */
.ks-rev-count {
	margin: 20px 0 0;
	text-align: center;
	font: 300 13px/1 Jost, sans-serif;
	letter-spacing: 0.08em;
	color: #636770;
}

/* -------------------------------------------------------------------------
   One review — /reviews/<slug>/.
   No design screen exists for this; it is built from the design's own
   vocabulary. Marcellus for the title, Jost 300 at a 68ch measure for the
   client's words, eyebrows at 11px tracked 0.18em, and the copy-and-aside
   rhythm the project page already uses.
   ------------------------------------------------------------------------- */

.ks-rev-single .ks-rev-single-head { padding: 96px 0 0; }
.ks-rev-single .ks-rev-single-body { padding: 40px 0 0; }
.ks-rev-single .ks-rev-single-projects,
.ks-rev-single .ks-rev-single-nav { padding: 72px 0 0; }
.ks-rev-single .ks-rev-invite { padding: 96px 0 110px; }

.ks-rev-single-eyebrow {
	display: block;
	margin-top: 24px;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ks-accent-text, #7d633b);
}

.ks-rev-single-title {
	max-width: 900px;
	margin: 18px 0 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 48px;
	line-height: 1.14;
	letter-spacing: -0.012em;
	text-wrap: pretty;
}

/* Copy and aside, as the project page sets them. */
.ks-rev-single-layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 300px;
	gap: 80px;
	align-items: start;
	padding-top: 36px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

/* READING COPY, not a display quote. Several of these run past two thousand
   characters and Marcellus at that length is punishing. */
.ks-rev-single-copy {
	max-width: 68ch;
	font: 300 19px/1.85 Jost, sans-serif;
	color: #3C464E;
	text-wrap: pretty;
}

.ks-rev-single-copy p { margin: 0 0 1.15em; }
.ks-rev-single-copy p:last-child { margin-bottom: 0; }

/* The opening line carries the page, so it is given a little more air. */
.ks-rev-single-copy p:first-child {
	font-size: 21px;
	line-height: 1.7;
	color: #1C2A33;
}

.ks-rev-single-card {
	background: #FFFDF9;
	padding: 34px 30px;
	display: flex;
	flex-direction: column;
	gap: 18px;
	position: sticky;
	top: 40px;
}

.ks-rev-single-aside-label {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #636770;
}

.ks-rev-single-by {
	font-family: Marcellus, serif;
	font-style: normal;
	font-size: 22px;
	line-height: 1.3;
	color: #1C2A33;
	margin-top: -8px;
}

.ks-rev-single-facts {
	margin: 0;
	padding-top: 18px;
	border-top: 1px solid rgba(28, 42, 51, 0.12);
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.ks-rev-single-facts > div {
	display: flex;
	justify-content: space-between;
	gap: 16px;
}

.ks-rev-single-facts dt {
	font: 300 13px/1.4 Jost, sans-serif;
	color: #636770;
}

.ks-rev-single-facts dd {
	margin: 0;
	font: 400 13px/1.4 Jost, sans-serif;
	color: #3C464E;
	text-align: right;
}

.ks-rev-single-original,
.ks-rev-single-all {
	font: 400 13px/1 Jost, sans-serif;
	letter-spacing: 0.04em;
	text-decoration: underline;
	text-underline-offset: 4px;
	color: #57616A;
}

.ks-rev-single-all { color: var(--ks-accent-text, #7d633b); }

.ks-rev-single-projects .ks-arch-eyebrow,
.ks-rev-single-nav .ks-arch-eyebrow {
	display: block;
	margin-bottom: 26px;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #636770;
}

.ks-rev-single-nav-inner {
	display: flex;
	justify-content: space-between;
	gap: 24px;
	padding-top: 32px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

.ks-rev-single-nav-link {
	display: flex;
	flex-direction: column;
	gap: 8px;
	max-width: 46%;
	text-decoration: none;
}

/* A lone "next" link stays on the right, where it would have been. */
.ks-rev-single-nav-link.is-next {
	margin-left: auto;
	text-align: right;
}

.ks-rev-single-nav-word {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #636770;
}

.ks-rev-single-nav-title {
	font-family: Marcellus, serif;
	font-size: 20px;
	line-height: 1.35;
	color: #1C2A33;
}

.ks-rev-single-nav-link:hover .ks-rev-single-nav-title { color: var(--accent, #B08D57); }

@media (max-width: 1024px) {
	.ks-rev-single .ks-rev-single-head { padding: 65px 0 0; }
	.ks-rev-single .ks-rev-invite { padding: 65px 0 75px; }
	.ks-rev-single-title { font-size: 38px; }
	.ks-rev-single-layout { grid-template-columns: minmax(0, 1fr); gap: 40px; }
	.ks-rev-single-card { position: static; }
}

/* 767 for the same reason as the archive block above. */
@media (max-width: 767px) {
	.ks-rev-single .ks-rev-single-head { padding: 48px 0 0; }
	.ks-rev-single .ks-rev-single-projects,
	.ks-rev-single .ks-rev-single-nav { padding: 48px 0 0; }
	.ks-rev-single .ks-rev-invite { padding: 48px 0 55px; }
	.ks-rev-single-title { font-size: 30px; }
	.ks-rev-single-copy { font-size: 17px; }
	.ks-rev-single-copy p:first-child { font-size: 18px; }
	.ks-rev-single-nav-inner { flex-direction: column; }
	.ks-rev-single-nav-link { max-width: none; }
	.ks-rev-single-nav-link.is-next { margin-left: 0; text-align: left; }
}

/* The breadcrumb anywhere it is NOT over a hero photograph.
   .ks-arch-crumb was written for a term archive, where it sits on a dark image
   and is therefore near-white at 60%. Every page without a hero — reviews,
   articles, the blog index — was rendering it cream-on-cream, and the anchor
   inside it had never been styled at all, so it fell through to the parent
   theme's default link colour and came out #CC3366. That was fixed once for
   reviews and immediately recurred on the article pages, so it is written as
   a rule about heroes rather than a list of page types: the design's #8C9099
   (line 2707) unless a hero section is providing the dark ground. */
.ks-arch .ks-arch-crumb {
	color: #636770;
	font: 300 13px/1 Jost, sans-serif;
}

/* And the general case, which the crumb rule above is one instance of.
   Scoping the last fix to `.ks-arch-crumb a` left every OTHER inline anchor in
   this shell falling through to hello-elementor's #CC3366 — which is how the
   same pink reappeared a third time, on 404.php's phone number. Written for the
   shell rather than for a page type, so the next template to use `.ks-arch`
   inherits it instead of rediscovering it. Buttons opt out: they carry their
   own colour. */
.ks-arch p a:not(.ks-arch-button),
.ks-arch li a:not(.ks-arch-button) {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: rgba(176, 141, 87, 0.65);
}

.ks-arch .ks-arch-crumb a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: rgba(140, 144, 153, 0.5);
}

.ks-arch .ks-arch-crumb a:hover {
	color: var(--accent, #B08D57);
	text-decoration-color: currentColor;
}

/* Except over a hero, where the pale treatment is correct. */
.ks-arch-hero .ks-arch-crumb,
.ks-proj-hero .ks-arch-crumb {
	color: rgba(245, 242, 236, 0.6);
}

.ks-arch-hero .ks-arch-crumb a,
.ks-proj-hero .ks-arch-crumb a {
	color: inherit;
}

/* -------------------------------------------------------------------------
   Projects archive: grouped filters and numbered pagination.
   The design draws a single row of chips (line 1386) because it had six
   placeholder projects to filter. With a hundred and twenty-two, the chips
   have to be grouped by the question they answer, so that "Stoneham" +
   "Shaker" + "Kitchens with Islands" reads as one composed query rather than
   a row of unrelated words.
   ------------------------------------------------------------------------- */

.ks-proj-filters {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 10px 26px;
	margin-top: 32px;
	padding-top: 24px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

.ks-proj-filters-head {
	display: flex;
	align-items: baseline;
	gap: 12px;
	flex: 0 0 auto;
	order: 99;
}

.ks-proj-filters-label {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #1C2A33;
}

.ks-proj-clear {
	font: 400 13px/1 Jost, sans-serif;
	color: var(--ks-accent-text, #7d633b);
	text-decoration: underline;
	text-underline-offset: 4px;
}

/* CONDENSED: the groups flow along one line and wrap, rather than each
   claiming a row of its own with a label column beside it. Four labelled rows
   cost about 200px before a single project was visible; this reads the same
   in roughly a third of the height. */
.ks-proj-facet {
	display: flex;
	align-items: baseline;
	gap: 8px;
	flex-wrap: wrap;
}

/* The group name is set in the accent so it reads as the question and the
   outlined chips under it read as the answers. Ink was tried first and made
   the labels compete with the selected chips, which are ink; the accent
   separates the two jobs. */
.ks-proj-facet-label {
	display: inline-flex;
	align-items: baseline;
	/* Matched to the chips beside it: same 13px, same 7px/12px padding, and a
	   transparent border so the two boxes come out the same height even though
	   only the chips are outlined. */
	padding: 7px 12px;
	border: 1px solid transparent;
	background: var(--accent, #B08D57);
	color: #16222A;
	font: 500 13px/1 Jost, sans-serif;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	white-space: nowrap;
}

.ks-proj-facet-options {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.ks-proj-chip {
	display: inline-flex;
	align-items: baseline;
	gap: 6px;
	padding: 7px 12px;
	border: 1px solid rgba(28, 42, 51, 0.18);
	font: 400 13px/1 Jost, sans-serif;
	white-space: nowrap;
	color: #3C464E;
	text-decoration: none;
	transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}

.ks-proj-chip:hover { border-color: #1C2A33; }

.ks-proj-chip.is-on {
	background: #1C2A33;
	border-color: #1C2A33;
	color: #F5F2EC;
}

/* The count is the honest part of the chip: it says what pressing it gets you
   before you press it. */
.ks-proj-chip-count {
	font-size: 10px;
	color: #636770;
}

.ks-proj-chip.is-on .ks-proj-chip-count { color: rgba(245, 242, 236, 0.7); }

.ks-proj-pagination {
	margin-top: 56px;
	padding-top: 32px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

.ks-proj-pagination .nav-links {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 6px;
	flex-wrap: wrap;
}

.ks-proj-pagination .page-numbers {
	min-width: 44px;
	padding: 12px 14px;
	text-align: center;
	font: 400 14px/1 Jost, sans-serif;
	color: #57616A;
	text-decoration: none;
	border: 1px solid transparent;
}

.ks-proj-pagination a.page-numbers:hover {
	border-color: rgba(28, 42, 51, 0.2);
	color: #1C2A33;
}

.ks-proj-pagination .page-numbers.current {
	background: #1C2A33;
	color: #F5F2EC;
}

.ks-proj-pagination .page-numbers.dots { min-width: 0; padding: 12px 4px; }

.ks-proj-count {
	margin: 18px 0 0;
	text-align: center;
	font: 300 13px/1 Jost, sans-serif;
	letter-spacing: 0.08em;
	color: #636770;
}

@media (max-width: 780px) {
	.ks-proj-filters { gap: 12px 18px; }
	/* The label shrinks with the chips, or the two stop lining up. */
	.ks-proj-chip,
	.ks-proj-facet-label { padding: 8px 11px; font-size: 13px; }
	.ks-proj-pagination .page-numbers { min-width: 38px; padding: 10px 10px; }
}

/* -------------------------------------------------------------------------
   Inspiration — the index at line 2166 and an article at 2761.
   The design's values: a 96px/64px header over a 62px title, a featured
   article across 1.15fr/1fr at a 34px gap, then three across on #FFFDF9 with
   16/10 images and 32px/30px/36px of padding. An article sets its prose on an
   820px measure under a 52px title.
   ------------------------------------------------------------------------- */

.ks-blog .ks-blog-head { padding: 96px 0 64px; }
.ks-blog .ks-blog-body { padding: 0 0 110px; }

.ks-blog-title {
	max-width: 900px;
	margin: 24px 0 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 62px;
	line-height: 1.08;
	letter-spacing: -0.015em;
	text-wrap: pretty;
}

.ks-blog-lede {
	max-width: 680px;
	margin: 26px 0 0;
	font: 300 19px/1.8 Jost, sans-serif;
	color: #57616A;
	text-wrap: pretty;
}

.ks-blog-eyebrow {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ks-accent-text, #7d633b);
}

/* The featured article: photograph and copy side by side. */
.ks-blog-featured {
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
	gap: 34px;
	align-items: stretch;
	margin-bottom: 64px;
}

.ks-blog-featured-media {
	display: block;
	position: relative;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	background: #EBE5DB;
}

.ks-blog-featured-image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ks-blog-featured-copy {
	background: #FFFDF9;
	padding: 68px 60px;
	display: flex;
	flex-direction: column;
	gap: 18px;
	justify-content: center;
}

.ks-blog-featured-title {
	margin: 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 40px;
	line-height: 1.18;
	text-wrap: pretty;
}

.ks-blog-featured-title a,
.ks-blog-card-title a {
	color: inherit;
	text-decoration: none;
}

.ks-blog-featured-title a:hover,
.ks-blog-card-title a:hover { color: var(--accent, #B08D57); }

.ks-blog-featured-summary {
	margin: 0;
	font: 300 17px/1.8 Jost, sans-serif;
	color: #57616A;
	text-wrap: pretty;
}

.ks-blog-featured-link {
	align-self: flex-start;
	margin-top: 6px;
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #1C2A33;
	text-decoration: underline;
	text-underline-offset: 6px;
}

.ks-blog-featured-link:hover { color: var(--accent, #B08D57); }

.ks-blog-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 24px;
	align-items: start;
}

.ks-blog-card { background: #FFFDF9; }

.ks-blog-card-media {
	display: block;
	position: relative;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	background: #EBE5DB;
}

.ks-blog-card-image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ks-blog-card-copy {
	padding: 32px 30px 36px;
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.ks-blog-card-title {
	margin: 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 24px;
	line-height: 1.3;
	text-wrap: pretty;
}

.ks-blog-card-summary {
	margin: 0;
	font: 300 16px/1.7 Jost, sans-serif;
	color: #57616A;
	text-wrap: pretty;
}

/* One article. */
.ks-article .ks-article-head { padding: 96px 0 0; }
.ks-article .ks-article-media { padding: 40px 0 0; }
.ks-article .ks-article-body { padding: 48px 0 0; }
.ks-article .ks-article-more { padding: 96px 0 0; }

.ks-article-title {
	max-width: 820px;
	margin: 20px 0 0;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 52px;
	line-height: 1.1;
	letter-spacing: -0.014em;
	text-wrap: pretty;
}

.ks-article-meta {
	display: flex;
	align-items: baseline;
	gap: 18px;
	margin-top: 22px;
	padding-top: 20px;
	border-top: 1px solid rgba(28, 42, 51, 0.16);
}

.ks-article-cat {
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--ks-accent-text, #7d633b);
}

.ks-article-read {
	font: 300 13px/1 Jost, sans-serif;
	color: #636770;
}

.ks-article-hero {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

/* 820px, because a line of prose across the full 1320px shell is unreadable. */
.ks-article-prose {
	max-width: 820px;
	font: 300 19px/1.85 Jost, sans-serif;
	color: #3C464E;
	text-wrap: pretty;
}

.ks-article-prose > p { margin: 0 0 1.15em; }
.ks-article-prose > p:last-child { margin-bottom: 0; }

.ks-article-prose h2 {
	margin: 1.6em 0 0.5em;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 34px;
	line-height: 1.2;
}

.ks-article-prose h3 {
	margin: 1.4em 0 0.4em;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 25px;
	line-height: 1.25;
}

.ks-article-prose blockquote {
	margin: 1.6em 0;
	padding: 0 0 0 28px;
	border-left: 2px solid var(--accent, #B08D57);
	font-family: Marcellus, serif;
	font-size: 25px;
	line-height: 1.5;
	color: #1C2A33;
}

.ks-article-prose blockquote cite {
	display: block;
	margin-top: 14px;
	font: 500 11px/1 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	font-style: normal;
	color: #636770;
}

.ks-article-prose ol { margin: 1.4em 0; padding: 0; list-style: none; counter-reset: ks-q; }

/* The design numbers these in a 40px column beside the question (2800). */
.ks-article-prose ol > li {
	display: grid;
	grid-template-columns: 40px minmax(0, 1fr);
	gap: 16px;
	padding: 18px 0;
	border-top: 1px solid rgba(28, 42, 51, 0.12);
	counter-increment: ks-q;
}

.ks-article-prose ol > li::before {
	content: "0" counter(ks-q);
	font: 500 13px/1.6 Jost, sans-serif;
	color: var(--ks-accent-text, #7d633b);
}

.ks-article-prose ul { margin: 1.2em 0; padding-left: 1.1em; }
.ks-article-prose li { margin-bottom: 0.4em; }

.ks-article-more-title {
	margin: 0 0 26px;
	font-family: Marcellus, serif;
	font-weight: 400;
	font-size: 34px;
}

@media (max-width: 1024px) {
	.ks-blog .ks-blog-head { padding: 65px 0 44px; }
	.ks-blog .ks-blog-body { padding: 0 0 75px; }
	.ks-blog-title { font-size: 46px; }
	.ks-blog-featured { grid-template-columns: minmax(0, 1fr); gap: 0; }
	.ks-blog-featured-copy { padding: 40px 34px; }
	.ks-blog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ks-article-title { font-size: 38px; }
	.ks-article .ks-article-head { padding: 65px 0 0; }
}

/* 767 for the same reason as the two review blocks above. */
@media (max-width: 767px) {
	.ks-blog .ks-blog-head { padding: 48px 0 32px; }
	.ks-blog .ks-blog-body { padding: 0 0 55px; }
	.ks-blog-title { font-size: 34px; }
	.ks-blog-grid { grid-template-columns: minmax(0, 1fr); }
	.ks-blog-featured-title { font-size: 28px; }
	.ks-blog-featured-copy { padding: 30px 26px; }
	.ks-article-title { font-size: 30px; }
	.ks-article-prose { font-size: 17px; }
	.ks-article-prose h2 { font-size: 26px; }
	.ks-article-prose blockquote { font-size: 21px; padding-left: 20px; }
}

/* ---------------------------------------------------------------------------
   Tap targets, phone only (DES-11).

   Measured at 390px: "Read the full review" 290x13, the blog featured link
   132x12, the project filter chips 31px tall. All are lists of links rather
   than links inside a sentence, so WCAG 2.2 SC 2.5.8's inline exemption does
   not apply to them, and all sit under the 24x24 minimum on height.

   Height only, and only under 768px. The visual rhythm of these pages is set by
   their own margins on desktop and none of it needs disturbing; what a phone
   needs is somewhere bigger to put a thumb. `align-items: center` keeps the
   text where it was inside the taller box.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
	.ks-rev-more,
	.ks-rev-source-link,
	.ks-blog-featured-link {
		display: inline-flex;
		align-items: center;
		min-height: 44px;
	}

	/* 36, not 44. The 44px floor was set when these were 342px-wide bars stacked
	   13px apart, where the risk was hitting the wrong one. They are now 169px
	   wide in their own horizontal row, with a label and a gap between rows, so
	   that risk is largely gone — and at 44 they were rendering TALLER on a
	   phone (44px) than on a desktop (29px), which reads as a mistake. 36
	   clears WCAG 2.2 SC 2.5.8's 24x24 minimum with room to spare and sits much
	   closer to the desktop size. */
	.ks-proj-chip {
		min-height: 36px;
		display: inline-flex;
		align-items: center;
	}

	.ks-arch .page-numbers {
		min-width: 44px;
		min-height: 44px;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}
}

/* ---------------------------------------------------------------------------
   Filtering the projects archive, in place.

   The 17 chips were plain links, so narrowing 119 kitchens to 25 cost a full
   page teardown — white flash, 640px hero redrawn, scroll reset. Pagination on
   this same page was ALREADY ajax and already wrote `aria-busy` on the results
   region; the chips simply were not wired into it. Filtering is the browsing
   mechanic on this archive, and changing the grid in place is what tells a
   visitor the chips are a lens on one set rather than a menu of pages.

   The dim is driven entirely by the aria-busy attribute the script already
   sets, so it costs no JavaScript at all. 0.4 rather than something fainter:
   enough to read as "working", not so much that the grid disappears and the
   page appears to empty.
   --------------------------------------------------------------------------- */
[data-ks-proj-results] {
	transition: opacity 180ms ease;
}

[data-ks-proj-results][aria-busy="true"] {
	opacity: 0.4;
}

/* The arriving grid. 6px, which is a settle rather than a slide — the content
   has not travelled anywhere, it has been replaced. `backwards` holds the
   from-state so it cannot flash at full opacity for a frame first. */
.ks-proj-grid.is-fresh {
	animation: ks-grid-in 260ms cubic-bezier(0.2, 0, 0, 1) backwards;
}

@keyframes ks-grid-in {
	from {
		opacity: 0;
		transform: translateY(6px);
	}
}

@media (prefers-reduced-motion: reduce) {
	/* The busy dim stays: it is state, not decoration, and it is the only
	   signal that a fetch is in flight. Only the movement goes. */
	.ks-proj-grid.is-fresh {
		animation: none;
	}
}

/* ---------------------------------------------------------------------------
   The filter chips as scroll rows, on a phone only.

   Measured at 390px: the filter block is 755px tall and the first kitchen sits
   at y=1157 — on an 844px screen a visitor scrolls past more than a full
   screenful of controls before seeing any work. The chips wrap because there
   are 17 of them across four facets, and wrapping is the right answer on a
   desktop where they are all scannable at once. On a phone it buries the
   product.

   One row per facet, scrolled horizontally. This is the site's own idiom, not a
   new one: style.css's .ks-slider is scroll-snap-type: x mandatory with the
   half-visible next item as the affordance that says "there is more to the
   right" without a control having to. No JavaScript, and with CSS off it
   degrades to exactly the wrap it has today.

   Phone only. Above 767px the wrap is fine and a scannable grid of filters
   beats a row you have to operate — the same argument that rejected carousels
   for the projects grid itself.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
	/* min-width: 0 is load-bearing, on BOTH the row and its parent. A flex item
	   defaults to min-width: auto, which means "never shrink below your content"
	   — so `overflow-x: auto` had nothing to overflow: the row simply grew, and
	   the whole document went with it. Measured before this line: the page was
	   944px wide inside a 390px viewport and the row did not scroll at all. */
	.ks-proj-facet {
		min-width: 0;
	}

	.ks-proj-facet-options {
		display: flex;
		flex-wrap: nowrap;
		min-width: 0;
		overflow-x: auto;
		scroll-snap-type: x proximity;

		/* Full-bleed track, text-aligned first chip. The row scrolls edge to
		   edge of the screen so the cut-off chip on the right is visible, while
		   the first chip still lines up with the heading above it. */
		margin-inline: calc(var(--ks-inset) * -1);
		padding-inline: var(--ks-inset);

		/* scroll-padding, not just padding. A snap position aligns to the
		   SCROLLPORT edge, which ignores padding-inline — so the row rested at
		   scrollLeft: 24 and put the first chip flush against the screen edge
		   while its own label sat 24px in. Measured, then fixed: scroll-padding
		   moves the snap position itself. */
		scroll-padding-inline: var(--ks-inset);

		/* Room for the focus ring, which `overflow-x: auto` would otherwise
		   clip on the vertical axis. */
		padding-block: 4px;

		scrollbar-width: thin;
		scrollbar-color: rgba(28, 42, 51, 0.25) transparent;
		-webkit-overflow-scrolling: touch;
	}

	.ks-proj-facet-options .ks-proj-chip {
		flex: 0 0 auto;
		scroll-snap-align: start;
	}
}

/* ---------------------------------------------------------------------------
   Projects archive: keyword search (direction A, "Search first").
   docs/superpowers/plans/2026-10-03-our-work-search.md. (Dan, 2026-10-03)

   A large serif line rather than a boxed field, so it reads as the first
   question the page asks ("Search 120 kitchens") and the chips under it as
   refinements. Label, then the field row (icon / input / clear) carrying the
   underline, then the "N kitchens mention …" status directly under it, as in
   the mock. The status moved INTO the form in review, which is why the
   underline is on .ks-proj-search-field and not drawn across the form: the
   form's bottom edge is now under the status line.
   --------------------------------------------------------------------------- */

.ks-proj-search {
	max-width: 860px;
	margin: 44px 0 0;
	padding: 0;
}

.ks-proj-search-field {
	position: relative;
	display: grid;
	grid-template-columns: 20px minmax(0, 1fr) 44px;
	align-items: center;
	column-gap: 12px;
	margin-top: 10px;
	border-bottom: 1px solid var(--ks-ink);
}

/* The chips' own hairline sat 56px under the search underline, two parallel
   rules reading as a mistake (seen at 390px). The search line already
   separates the lede from the controls, so the chips drop theirs when the
   search is above them. */
.ks-proj-search + .ks-proj-filters {
	margin-top: 28px;
	padding-top: 0;
	border-top: 0;
}

/* Focus is shown on the line the visitor is writing on, since the input
   itself has no box to ring. Thicker AND brass, so it is not colour alone.
   --ks-accent-text rather than --ks-accent: the plain brass is about 2.9:1 on
   cream and a focus indicator needs 3:1. The second pixel is a shadow, not a
   wider border, so focusing does not nudge everything below down by 1px. */
.ks-proj-search-field:focus-within {
	border-bottom-color: var(--ks-accent-text);
	box-shadow: 0 1px 0 var(--ks-accent-text);
}

.ks-proj-search > label,
.ks-proj-search-label {
	display: block;
	font: 500 11px/1.4 Jost, sans-serif;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #1c2a33;
}

.ks-proj-search-icon {
	grid-column: 1;
	width: 20px;
	height: 20px;
	color: var(--ks-ink);
	pointer-events: none;
}

/* WebKit draws type=search as a rounded, inset native control with its own
   cancel cross. Both go: the cross duplicates our clear button (and cannot be
   styled or given a 44px target), and the rounding is the iOS default that
   makes it look like a system field dropped into the page. 24px keeps iOS
   Safari from zooming on focus, which it does below 16px. */
.ks-proj-search input[type="search"] {
	grid-column: 2;
	width: 100%;
	min-width: 0;
	min-height: 44px;
	margin: 0;
	padding: 8px 0 10px;
	-webkit-appearance: none;
	appearance: none;
	border: 0;
	border-radius: 0;
	background: transparent;
	box-shadow: none;
	font: 400 30px/1.2 Marcellus, serif;
	color: var(--ks-ink);
}

.ks-proj-search input[type="search"]:focus {
	outline: none; /* Replaced by the :focus-within underline above. */
}

.ks-proj-search input[type="search"]::placeholder {
	color: var(--ks-muted);
	opacity: 1;
}

.ks-proj-search input[type="search"]::-webkit-search-cancel-button,
.ks-proj-search input[type="search"]::-webkit-search-decoration,
.ks-proj-search input[type="search"]::-webkit-search-results-button,
.ks-proj-search input[type="search"]::-webkit-search-results-decoration {
	-webkit-appearance: none;
	display: none;
}

.ks-proj-search .ks-proj-search-clear {
	grid-column: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	margin: 0;
	padding: 0;
	-webkit-appearance: none;
	appearance: none;
	border: 0;
	border-radius: 0;
	background: transparent;
	font: 300 28px/1 Jost, sans-serif;
	color: var(--ks-ink);
	cursor: pointer;
	transition: color 0.2s ease;
}

.ks-proj-search .ks-proj-search-clear svg {
	width: 18px;
	height: 18px;
}

.ks-proj-search .ks-proj-search-clear:hover,
.ks-proj-search .ks-proj-search-clear:focus {
	background: transparent;
	color: var(--ks-accent-text);
}

.ks-proj-search .ks-proj-search-clear:focus-visible {
	outline: 2px solid var(--ks-accent-text);
	outline-offset: -2px;
}

/* Hidden when the box is empty, but its column is kept: collapsing it made
   the input 56px wider on the first keystroke. visibility rather than
   display also keeps it out of the tab order and the accessibility tree. */
.ks-proj-search .ks-proj-search-clear[hidden] {
	display: flex;
	visibility: hidden;
}

/* The search buttons are bare <button>s, so the parent theme's reset (and
   style.css's answer to its pink hover, ~line 483) reach them at (0,1,1) —
   [type=submit]:focus beat the single-class rules here and drew the submit as
   a 12px grey sliver. Every button rule below is scoped under .ks-proj-search
   to out-rank both. */

/* The no-JS submit. Enter submits the form anyway, so the button only has to
   exist for a keyboard user tabbing through, and it appears when they reach
   it rather than sitting under a search box that already works. */
.ks-proj-search .ks-proj-search-submit {
	/* The parent reset gives every button `transition: all .3s`, which
	   animated the padding and height in from the clipped state — a 2px box
	   for the first 300ms of focus. It should simply be there. */
	transition: none;
	position: absolute;
	top: 100%;
	right: 0;
	margin-top: 8px;
	padding: 12px 18px;
	min-height: 44px;
	border: 0;
	border-radius: 0;
	-webkit-appearance: none;
	appearance: none;
	background: var(--ks-ink);
	color: var(--ks-cream);
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	cursor: pointer;
	z-index: 2;
}

.ks-proj-search .ks-proj-search-submit:not(:focus-visible) {
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	width: 1px;
	height: 1px;
	min-height: 0;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	white-space: nowrap;
}

.ks-proj-search .ks-proj-search-submit:focus-visible {
	background: var(--ks-ink);
	color: var(--ks-cream);
	outline: 2px solid var(--ks-accent-text);
	outline-offset: 2px;
}

/* "19 kitchens mention “quooker”", directly under the field so the answer
   to what was typed sits where the eye already is. Empty, and gone, when
   nothing is searched — but the element stays in the DOM: it is the live
   region, and the script keeps the same node across swaps so screen readers
   announce it. */
.ks-proj-search-status {
	margin: 12px 0 0;
	font: 400 14px/1.5 Jost, sans-serif;
	color: var(--ks-body);
}

.ks-proj-search-status:empty {
	display: none;
}

.ks-proj-search-status strong {
	font-weight: 500;
	color: var(--ks-ink);
}

/* Zero results: the no-results panel already says "No kitchens mention …"
   in a 26px heading, so the line would be a stutter on screen. Hidden
   visually only — display: none would also take it out of the live region,
   and a screen reader would hear nothing at all for a search that failed. */
.ks-proj-search-status.is-empty {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* The line on each card that matched. Set like the summary it stands in for,
   but kept on a phone (where the summary is hidden): on a search it is the
   answer to "why is this kitchen here", and without it a Quooker search
   returns photographs with no visible Quooker. Four lines at most so one long
   paragraph cannot make one card twice the height of its neighbour. */
.ks-proj-card-match {
	display: block;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 4;
	overflow: hidden;
	margin-top: 8px;
	font: 300 15px/1.6 Jost, sans-serif;
	color: var(--ks-secondary);
	overflow-wrap: anywhere;
}

.ks-proj-card-match mark {
	padding: 0 2px;
	background: rgba(176, 141, 87, 0.28);
	color: inherit;
}

/* Nothing matched. A panel rather than the one-line .ks-arch-empty because
   it carries two ways forward, and the first — a showroom visit — is the
   point: someone searching for a thing we have not photographed yet is
   still someone who wants it fitted. */
.ks-proj-noresults {
	max-width: 640px;
	padding: 32px 24px;
	border: 1px solid var(--ks-hairline);
	background: var(--ks-panel, #fffdf9);
}

.ks-proj-noresults h2 {
	margin: 0;
	font: 400 26px/1.25 Marcellus, serif;
	color: var(--ks-ink);
	overflow-wrap: anywhere;
}

.ks-proj-noresults p {
	margin: 14px 0 0;
	font: 300 15px/1.7 Jost, sans-serif;
	color: var(--ks-body);
}

.ks-proj-noresults .ks-proj-noresults-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 24px;
	margin-top: 24px;
}

.ks-proj-noresults .ks-arch-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 48px;
	padding: 0 26px;
	background: var(--ks-ink);
	border: 1px solid var(--ks-ink);
	color: var(--ks-cream);
	font: 500 12px/1 Jost, sans-serif;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	text-decoration: none;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.ks-proj-noresults .ks-arch-button:hover {
	background: var(--ks-cream);
	color: var(--ks-ink);
}

.ks-arch .ks-proj-noresults .ks-proj-search-reset {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font: 400 14px/1 Jost, sans-serif;
	color: var(--ks-accent-text);
	text-decoration: underline;
	text-underline-offset: 4px;
	border: 0;
	padding: 0;
}

.ks-proj-noresults a:focus-visible {
	outline: 2px solid var(--ks-accent-text);
	outline-offset: 3px;
}

@media (max-width: 767px) {
	.ks-proj-search {
		margin-top: 32px;
	}

	.ks-proj-search input[type="search"] {
		font-size: 24px;
	}

	.ks-proj-card-match {
		font-size: 14px;
	}

	.ks-proj-noresults .ks-arch-button {
		width: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	.ks-proj-search .ks-proj-search-clear,
	.ks-proj-noresults .ks-arch-button {
		transition: none;
	}
}
