/* ============================================================
   Bristol Furniture — stylesheet
   Sections follow the order of the markup in index.html:
   tokens, reset, primitives, navbar, hero, about, products,
   manufacturing, footer.
   Breakpoints match the previous Tailwind build: 640 / 768 / 1024.
   ============================================================ */

/* ---------- Graphik ----------
   Converted to WOFF2 and subset to Latin from the desktop OTFs supplied in
   docs/ (666KB -> 125KB). Same approach the ARCHIDEX landing page takes.
   NOTE: the licence on file is desktop-only — see README before launch. */
/* Graphik ships asymmetric vertical metrics: ascent 809, descent 191 against a
   715 cap height, so the glyphs' optical centre lands at 45.2% of the content
   box and every flex-centred label sits high. Safari honours those metrics;
   Chrome on Windows uses the win metrics (1123/225) and leans the other way,
   which is why the navbar button looked centred here and high in Safari.
   These overrides make ascent - descent == cap height, so the cap box is
   centred in every engine. The line-gap override keeps `line-height: normal`
   at the 1.2 it was, so nothing else reflows. */
@font-face {
	font-family: "Graphik";
	src: url("../assets/fonts/graphik-300.woff2") format("woff2");
	font-weight: 300;
	font-style: normal;
	font-display: swap;
	ascent-override: 85.8%;
	descent-override: 14.2%;
	line-gap-override: 20%;
}

@font-face {
	font-family: "Graphik";
	src: url("../assets/fonts/graphik-400.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
	ascent-override: 85.8%;
	descent-override: 14.2%;
	line-gap-override: 20%;
}

@font-face {
	font-family: "Graphik";
	src: url("../assets/fonts/graphik-500.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
	ascent-override: 85.8%;
	descent-override: 14.2%;
	line-gap-override: 20%;
}

@font-face {
	font-family: "Graphik";
	src: url("../assets/fonts/graphik-600.woff2") format("woff2");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
	ascent-override: 85.8%;
	descent-override: 14.2%;
	line-gap-override: 20%;
}

@font-face {
	font-family: "Graphik";
	src: url("../assets/fonts/graphik-700.woff2") format("woff2");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
	ascent-override: 85.8%;
	descent-override: 14.2%;
	line-gap-override: 20%;
}

/* ---------- Tokens ---------- */
:root {
	--brand: #96c93d;
	--brand-dark: #85b534;

	--zinc-50: #fafafa;
	--zinc-100: #f4f4f5;
	--zinc-200: #e4e4e7;
	--zinc-300: #d4d4d8;
	--zinc-400: #a1a1aa;
	--zinc-500: #71717a;
	--zinc-600: #52525b;
	--zinc-700: #3f3f46;
	--zinc-800: #27272a;
	--zinc-900: #18181b;

	--font-sans: "Graphik", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
		Roboto, "Helvetica Neue", Arial, sans-serif;

	--container: 80rem;
	--gutter: 1.5rem;

	--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
	--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07),
		0 2px 4px -2px rgba(0, 0, 0, 0.05);
	--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
		0 8px 10px -6px rgba(0, 0, 0, 0.1);

	--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- Reset ---------- */
*,
*::before,
*::after {
	box-sizing: border-box;
}

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	scroll-padding-top: 6rem;
}

body {
	font-family: var(--font-sans);
	color: var(--zinc-900);
	background: #fff;
	line-height: 1.5;
	min-height: 100vh;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

body::selection,
::selection {
	background: rgba(150, 201, 61, 0.3);
	color: var(--zinc-900);
}

img,
svg {
	display: block;
	max-width: 100%;
}
img {
	height: auto;
}

a {
	color: inherit;
	text-decoration: none;
}
ul {
	list-style: none;
	padding: 0;
}

button {
	/* Safari keeps -webkit-appearance: push-button on <button> even once the
	   background and border are gone, and the native control centres its own
	   content rather than deferring to flex alignment. That is what leaves a
	   label sitting high in Safari while every other browser centres it. */
	appearance: none;
	-webkit-appearance: none;
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	cursor: pointer;
}

h1,
h2,
h3,
h4 {
	line-height: 1.15;
	font-weight: 700;
}

:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
	border-radius: 4px;
}

/* The sprite only holds <defs>; it must never take up space. */
.icon-sprite {
	position: absolute;
	width: 0;
	height: 0;
}

/* ---------- Layout primitives ---------- */
.container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.section {
	--section-pad: 4.5rem;
	padding-block: var(--section-pad);
}

/* Neighbours on the same ground have no colour change to mark the join, so
   the doubled padding reads as one dead void rather than two sections. */
.section:not(.section--muted):not(.section--dark)
	+ .section:not(.section--muted):not(.section--dark) {
	padding-top: calc(var(--section-pad) / 3);
}

.section--muted {
	background: var(--zinc-50);
}
.section--bordered {
	border-bottom: 1px solid var(--zinc-200);
}
.section--dark {
	background: var(--zinc-900);
	color: #fff;
}

.section__head {
	max-width: 50rem;
	margin: 0 auto 5rem;
	text-align: center;
}

.section__title {
	font-size: 1.875rem;
	font-weight: 400;
	letter-spacing: -0.025em;
	margin-bottom: 2rem;
}

.section__title--sm {
	margin-bottom: 1.5rem;
}

.section__title--left {
	text-align: left;
	margin-bottom: 0;
	/* Optical alignment. A glyph's left side bearing — the blank built into the
	   character before its ink — scales with font size, so at display sizes the
	   heading's ink sits a couple of pixels inside its box while the small text
	   and the cards below start flush. Pulling the box out by the same fraction
	   lands the ink on the column edge at every breakpoint. */
	margin-left: -0.045em;
}

.section__lead {
	font-size: 1.25rem;
	font-weight: 300;
	line-height: 1.7;
	margin-top: 0.5rem;
	color: var(--zinc-600);
}

.section__lead--dim {
	font-size: 1.25rem;
	color: rgba(255, 255, 255, 0.768);
}

.grid-4 {
	display: grid;
	grid-template-columns: 1fr;
	gap: 2rem;
}

/* Two-column media/copy layout used by Philosophy. */
.split {
	display: grid;
	grid-template-columns: 1fr;
	gap: 4rem;
	align-items: center;
}

/* ---------- Type helpers ---------- */
.br-md {
	display: none;
}

.prose {
	display: grid;
	gap: 1.5rem;
	font-size: 1.125rem;
	font-weight: 300;
	line-height: 1.75;
	color: var(--zinc-600);
}

/* ---------- Buttons ---------- */
.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	/* Height comes from padding, with min-height only as a floor. Safari does
	   not reliably distribute the slack between min-height and content on a
	   <button>, so relying on align-items alone left the label sitting high —
	   most visible on the navbar button, which has the most slack because its
	   content is a single line of 14px text with no icon. */
	min-height: 2.5625rem;
	padding: 0.75rem 1.25rem;
	line-height: 1.2;
	border-radius: 9999px;
	font-size: 0.875rem;
	font-weight: 500;
	transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}

.btn--lg {
	min-height: 3.5rem;
	padding: 1.15rem 2rem;
	font-size: 1rem;
}

/* Graphik reserves ascender room for accents, so with plain padding the label
   sits low. A fixed pixel nudge is the wrong fix — Blink and WebKit read
   different metric tables, so it over-corrects in one of them. text-box trims
   the leading to the real cap height, which every engine agrees on. Padding is
   re-stated because trimming shrinks the line box. */
.btn > span {
	display: block;
}

@supports (text-box: trim-both cap alphabetic) {
	/* The trim needs a real block box — on the flex container itself the label
	   is an anonymous flex item and is left untouched. */
	.btn > span {
		text-box: trim-both cap alphabetic;
	}
}

.btn--block {
	width: 100%;
}

.btn--brand {
	background: var(--brand);
	color: #fff;
	box-shadow: var(--shadow-sm);
}
.btn--brand:hover {
	background: var(--brand-dark);
}

.is-safari .btn > span {
	transform: translateY(1px);
}

.btn--light {
	background: #fff;
	color: var(--zinc-900);
}

.hero .btn {
	box-shadow: 0 0px 8px rgba(0, 0, 0, 0.156);
}
.btn--light:hover {
	background: var(--zinc-100);
}

.link-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-weight: 500;
	color: var(--zinc-900);
	transition: color 0.2s;
}
.link-btn:hover {
	color: var(--brand);
}

.icon-btn {
	display: inline-flex;
	padding: 0.5rem;
	transition: color 0.2s;
}

/* ---------- Icons ---------- */
.icon {
	width: 1.25rem;
	height: 1.25rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
	flex: none;
}

.icon--lg {
	width: 1.5rem;
	height: 1.5rem;
}

.icon--nudge {
	transition: transform 0.2s;
}
.group:hover .icon--nudge {
	transform: translateX(4px);
}

/* ---------- Logo ----------
   assets/bristol-logo.svg is a green square with the ® sitting outside it to
   the right, so --logo-size drives the height and the width follows. */
.logo {
	--logo-size: 3rem;
	height: var(--logo-size);
	width: auto;
}

.logo--lg {
	--logo-size: 4rem;
}

/* ---------- Reveal on scroll (replaces motion/react) ---------- */
.reveal {
	opacity: 0;
	transition: opacity 0.6s var(--ease-out-expo) var(--delay, 0s),
		transform 0.6s var(--ease-out-expo) var(--delay, 0s);
	will-change: opacity, transform;
}

.reveal--up {
	transform: translateY(20px);
}
/* Kept under the 24px mobile gutter, otherwise the offset pushes content
   past the viewport edge and the page scrolls sideways. */
.reveal--left {
	transform: translateX(-20px);
}
.reveal--right {
	transform: translateX(20px);
}
.reveal--scale {
	transform: scale(0.95);
}

.reveal.is-visible {
	opacity: 1;
	transform: none;
}

/* Hero copy uses the longer entrance the old motion config had. */
.hero__copy {
	transform: translateY(30px);
	transition-duration: 0.8s;
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	.reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		transition-duration: 0.01ms !important;
	}
}

/* ============================================================
   Navbar
   ============================================================ */
.navbar {
	position: fixed;
	inset-block-start: 0;
	inset-inline: 0;
	z-index: 50;
	padding-block: 1.5rem;
	background: transparent;
	transition: background-color 0.3s, padding 0.3s, box-shadow 0.3s;
}

/* Pages with no dark hero behind the bar have nothing for white links to sit
   on, so they opt into the solid treatment from first paint rather than
   waiting for a scroll that may never come. */
.navbar.is-scrolled,
.navbar--solid {
	padding-block: 1rem;
	background: rgba(255, 255, 255, 0.95);
	backdrop-filter: blur(12px);
	box-shadow: var(--shadow-sm);
}

.navbar__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}

.navbar__brand {
	display: inline-flex;
}

.navbar__links,
.navbar__actions {
	display: none;
}

.nav-link {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	padding-block: 0.5rem;
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	white-space: nowrap;
	transition: color 0.2s;
}

/* Over the hero the bar is transparent, so the chrome is white. */
.navbar .nav-link,
.navbar__actions .icon-btn {
	color: rgb(255, 255, 255);
}

.navbar .nav-link:hover,
.navbar__actions .icon-btn:hover {
	color: #fff;
}

/* Once scrolled — or while a dropdown is open — the bar is white. */
.navbar.is-scrolled .nav-link,
.navbar.has-menu-open .nav-link,
.navbar--solid .nav-link,
.navbar.is-scrolled .navbar__actions .icon-btn,
.navbar.has-menu-open .navbar__actions .icon-btn,
.navbar--solid .navbar__actions .icon-btn {
	color: var(--zinc-600);
}

.navbar.is-scrolled .nav-link:hover,
.navbar.has-menu-open .nav-link:hover,
.navbar--solid .nav-link:hover,
.navbar.is-scrolled .navbar__actions .icon-btn:hover,
.navbar.has-menu-open .navbar__actions .icon-btn:hover,
.navbar--solid .navbar__actions .icon-btn:hover {
	color: var(--zinc-900);
}

.navbar.has-menu-open {
	background: #fff;
	box-shadow: none;
}

.navbar__toggle {
	padding: 0.5rem;
	color: #fff;
}

.navbar.is-scrolled .navbar__toggle,
.navbar--solid .navbar__toggle {
	color: var(--zinc-900);
}

/* ---------- Dropdown trigger ---------- */
.nav-item {
	position: static;
}

.nav-link--trigger {
	letter-spacing: 0.12em;
	cursor: pointer;
}

.icon--caret {
	width: 0.875rem;
	height: 0.875rem;
	stroke-width: 2.5;
	transition: transform 0.2s;
}

.nav-item.is-open .icon--caret {
	transform: rotate(180deg);
}

/* Beats the .navbar.is-scrolled colour rules above (0,4,0 vs 0,3,0). */
.navbar .nav-item.is-open > .nav-link {
	color: var(--brand);
}

/* ---------- Mega menu panel ----------
   Sized by its contents and anchored under its trigger. app.js sets `left`
   (and keeps the panel inside the viewport); everything else is CSS. */
.mega {
	--mega-col: 9.5rem;
	--mega-pad: 2.5rem;

	position: absolute;
	top: 100%;
	left: 0;
	width: max-content;
	max-width: calc(100vw - 2rem);
	background: #fff;
	border: 1px solid var(--zinc-200);
	border-top: 0;
	box-shadow: 0 18px 40px -20px rgba(24, 24, 27, 0.28);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-0.5rem);
	pointer-events: none;
	transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}

.nav-item.is-open .mega {
	opacity: 1;
	visibility: visible;
	transform: none;
	pointer-events: auto;
}

.mega__inner {
	display: grid;
	grid-auto-flow: column;
	/* Columns take their width from the heading so the rules under them line
     up across the panel; long link labels wrap instead of widening it. */
	grid-auto-columns: minmax(var(--mega-col), max-content);
	gap: 2rem;
	padding: 3rem var(--mega-pad) 3.25rem;
	align-items: start;
}

/* Ungrouped single-column panel (Resources) sits tighter. */
.mega--compact {
	--mega-pad: 2rem;
}
.mega--compact .mega__inner {
	padding-block: 2rem 2.25rem;
}

.mega__heading {
	padding-bottom: 1rem;
	margin-bottom: 1.25rem;
	border-bottom: 1px solid var(--zinc-300);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--zinc-900);
}

.mega__list {
	display: grid;
	gap: 0.875rem;
}

.mega__list a {
	display: inline-block;
	max-width: var(--mega-col);
	font-size: 0.75rem;
	letter-spacing: 0.11em;
	line-height: 1.5;
	text-transform: uppercase;
	color: var(--zinc-500);
	transition: color 0.2s;
}

.mega__list a:hover {
	color: var(--brand);
}

/* ---------- Mobile menu ---------- */
.mobile-menu {
	position: fixed;
	inset: 0;
	z-index: 60;
	display: flex;
	flex-direction: column;
	padding: 1.5rem;
	background: #fff;
	opacity: 0;
	transform: translateY(-20px);
	transition: opacity 0.25s ease, transform 0.25s ease;
}

.mobile-menu[hidden] {
	display: none;
}
.mobile-menu.is-open {
	opacity: 1;
	transform: none;
}

.mobile-menu__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 3rem;
}

.icon-btn--dark {
	color: var(--zinc-500);
}
.icon-btn--dark:hover {
	color: var(--zinc-900);
}

.mobile-menu__links {
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding-bottom: 1.5rem;
}

/* Top-level mobile items match the uppercase desktop nav treatment. */
.mobile-menu__links > a,
.m-acc__head {
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.mobile-menu__foot {
	padding-top: 2rem;
	padding-bottom: 2rem;
}

/* ---------- Mobile products accordion (native <details>) ---------- */
.m-acc__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	cursor: pointer;
	list-style: none;
}

.m-acc__head::-webkit-details-marker {
	display: none;
}

.m-acc__head .icon--caret {
	width: 1.125rem;
	height: 1.125rem;
	color: var(--zinc-400);
}

.m-acc[open] .m-acc__head .icon--caret {
	transform: rotate(180deg);
}

.m-acc__body {
	display: grid;
	gap: 1.75rem;
	padding: 1.75rem 0 0.5rem 1rem;
	border-left: 1px solid var(--zinc-200);
	margin-top: 1.25rem;
}

.m-group__title {
	margin-bottom: 0.875rem;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--zinc-900);
}

.m-group__list {
	display: grid;
	gap: 0.75rem;
}

.m-group__list a {
	font-size: 0.8125rem;
	font-weight: 400;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--zinc-500);
}

/* ============================================================
   Hero
   ============================================================ */
.hero {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	height: 100vh;
	height: 100dvh; /* avoids the mobile URL-bar jump; ignored where unsupported */
	min-height: 600px;
	overflow: hidden;
	background: var(--zinc-900);
}

.hero__media {
	position: absolute;
	inset: 0;
}

.hero__video,
.hero__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Anchor to the bottom of the photo so the chair castors stay in frame
     whatever the viewport ratio; the ceiling crops instead. */
	object-position: center bottom;
	transition: opacity 0.9s ease;
}

/* Photo is the resting state; the video fades in over it. */
.hero__video {
	opacity: 0;
}
.hero.is-video .hero__video {
	opacity: 1;
}
.hero.is-video .hero__media img {
	opacity: 0;
}

/* ---------- Parallax ----------
   Scroll-driven animations run off the main thread, so no scroll listener
   and no jank. Browsers without support just get the static image.
   transform-origin is bottom on the hero, so scaling adds headroom ABOVE
   and the chair castors stay exactly where they are at rest. */
@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.hero__media {
			transform-origin: center bottom;
			animation: hero-drift linear both;
			animation-timeline: scroll(root block);
			animation-range: 0 100vh;
		}
	}
}

/* Travel must stay within the headroom above the frame, or the image pulls
   away from the top edge and the container shows through. Origin is bottom,
   so the headroom is (scale - 1) plus whatever object-fit already overhangs. */
@keyframes hero-drift {
	from {
		transform: translate3d(0, 0, 0) scale(1);
	}
	to {
		transform: translate3d(0, 40%, 0) scale(1);
	}
}

/* The photo runs at full colour; these gradients buy the text its contrast.
   Measured against the brand green, which is the hardest case. */
.hero__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
			to bottom,
			rgba(24, 24, 27, 0.5) 0%,
			rgba(24, 24, 27, 0.18) 9%,
			rgba(24, 24, 27, 0.1) 15%
		),
		linear-gradient(
			to top,
			rgba(24, 24, 27, 0.72) 0%,
			rgba(24, 24, 27, 0.5) 45%,
			rgba(24, 24, 27, 0.32) 75%
		);
}

.hero__inner {
	position: relative;
	z-index: 10;
	padding-top: 5rem;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.hero__copy {
	max-width: 48rem;
}

.hero__title {
	/* Optical alignment — see .section__title--left. */
	margin-left: -0.065em;
	/* text-shadow has no spread parameter, so the falloff is built by stacking
	   layers at growing blur radii with lower alpha each. Third value is the
	   blur (reach), alpha is the density. One faint tight layer keeps the
	   edges crisp; the wide ones do the diffusion.
	   NOTE: text-shadow aids legibility but is NOT counted by WCAG contrast
	   maths, which compares text against background pixels only. */
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.26), 0 0px 2px rgba(0, 0, 0, 0.1),
		0 0px 4px rgba(0, 0, 0, 0.2), 0 0 10px rgba(0, 0, 0, 0.1);
	font-size: 2.25rem;
	font-weight: 400;
	letter-spacing: -0.025em;
	color: #fff;
	margin-bottom: 1.5rem;
}

.hero__lead {
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0px 2px rgba(0, 0, 0, 0.1),
		0 0px 2px rgba(0, 0, 0, 0.14), 0 0 2px rgba(0, 0, 0, 0.4);
	/* 38rem, not 36: at weight 400 the line broke to three with an orphan. */
	max-width: 38rem;
	margin: 0 auto 2.5rem;
	font-size: 1.125rem;
	font-weight: 300;
	line-height: 1.7;
	color: white;
}

.hero__actions {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
}

.card {
	padding: 2rem;
	background: #fff;
	border: 1px solid var(--zinc-100);
	border-radius: 1rem;
	box-shadow: var(--shadow-sm);
	transition: box-shadow 0.2s, background-color 0.2s;
}

.card:hover {
	box-shadow: var(--shadow-md);
}

.card--dark {
	background: rgba(39, 39, 42, 0.5);
	border-color: rgba(63, 63, 70, 0.5);
	box-shadow: none;
}

.card--dark:hover {
	background: var(--zinc-800);
	box-shadow: none;
}

.card__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	margin-bottom: 1.5rem;
	border-radius: 0.75rem;
	background: var(--zinc-50);
	color: var(--brand);
}

.card__icon--dark {
	background: rgba(150, 201, 61, 0.2);
}

.card__title {
	font-size: 1.25rem;
	font-weight: 600;
	margin-bottom: 0.75rem;
}

.card__text {
	font-weight: 300;
	line-height: 1.7;
	color: var(--zinc-500);
}

.card--dark .card__text {
	color: var(--zinc-200);
}

/* ============================================================
   The Bristol Group
   ============================================================ */
.frame {
	overflow: hidden;
	border-radius: 1.5rem;
	background: var(--zinc-100);
}

.frame img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.frame--portrait {
	aspect-ratio: 4 / 5;
}
.frame--landscape {
	aspect-ratio: 4 / 3;
}

.co__head {
	display: grid;
	grid-template-columns: 1fr;
	gap: 3rem;
	margin-bottom: 4rem;
}

.co__title {
	/* Optical alignment — see .section__title--left. This one opens on a "B",
	   whose side bearing is wider than the "O" those headings use. */
	margin-left: -0.062em;
	max-width: 24ch;
	font-weight: 400;
	margin-bottom: 1.25rem;
	font-size: 1.875rem;
	line-height: 1.2;
	letter-spacing: -0.025em;
}

/* The positioning line, one step up from body copy. */
.co__statement {
	max-width: 32ch;
	margin-bottom: 2rem;
	font-size: 1.25rem;
	font-weight: 300;
	line-height: 1.45;
	color: var(--zinc-900);
}

/* ---------- Key figures ---------- */
/* One panel, 2x2, with rules only between the cells. */
.stats {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	padding: 1rem;
	background: var(--zinc-50);
	border-radius: 1.5rem;
}

.stat {
	padding: 1.25rem;
}

.stat:nth-child(odd) {
	border-right: 1px solid var(--zinc-200);
}

.stat:nth-child(-n + 2) {
	border-bottom: 1px solid var(--zinc-200);
}

.stat__icon {
	display: block;
	color: var(--zinc-500);
	width: 1.75rem;
	height: 1.75rem;
	margin-bottom: 1.25rem;
	stroke-width: 1.5;
}

.stat__value {
	font-size: 2.75rem;
	font-weight: 500;
	line-height: 1;
	letter-spacing: -0.03em;
	color: var(--brand);
}

.stat__unit {
	font-size: 0.42em;
	font-weight: 700;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	margin-left: 0.12em;
}

.stat__label {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	line-height: 1.45;
	color: var(--zinc-800);
}

.co__more {
	margin-top: 1.5rem;
}

.co__figure {
	overflow: hidden;
	border-radius: 1.5rem;
	background: var(--zinc-100);
}

.co__gallery {
	position: relative;
	aspect-ratio: 3 / 2;
	background-image: url("assets/about-banner.jpg");
	background-position: center;
	background-size: cover;
}

.co__slide {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0;
	will-change: opacity;
	animation: about-gallery-fade 48s ease-in-out infinite both;
}

.co__slide--1 {
	animation-delay: 0s;
}
.co__slide--2 {
	animation-delay: 6s;
}
.co__slide--3 {
	animation-delay: 12s;
}
.co__slide--4 {
	animation-delay: 18s;
}
.co__slide--5 {
	animation-delay: 24s;
}
.co__slide--6 {
	animation-delay: 30s;
}
.co__slide--7 {
	animation-delay: 36s;
}
.co__slide--8 {
	animation-delay: 42s;
}

@keyframes about-gallery-fade {
	0% {
		opacity: 0;
	}
	3.8%,
	13.3% {
		opacity: 1;
	}
	18.1%,
	100% {
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.co__slide {
		animation: none !important;
		opacity: 0;
	}

	.co__slide--1 {
		opacity: 1;
	}
}

/* ============================================================
   Our Solutions
   Card treatment carried over from the ARCHIDEX landing page:
   tall image, title centred over it, category list beneath.
   ============================================================ */
.head-row {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	margin-bottom: 1.5rem;
}

.head-row__lead {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

/* Names the category the product row is showing. */
.solutions__active {
	font-size: 1.25rem;
	font-weight: 400;
	line-height: 1.2;
	color: var(--zinc-500);
}

.solutions__active.is-revealed {
	animation: label-wipe 0.5s var(--ease-out-expo) both;
}

/* Uncovers the word left to right rather than fading it in, so a change of
   category reads as a swap instead of a flicker. */
@keyframes label-wipe {
	0% {
		clip-path: inset(0 100% 0 0);
		opacity: 0;
		translate: -0.4rem 0;
	}
	100% {
		clip-path: inset(0 0 0 0);
		opacity: 1;
		translate: 0 0;
	}
}

/* Mobile: a swipeable, snapping row with the next card peeking. */
.solutions {
	display: flex;
	gap: 1rem;
	overflow-x: auto;
	padding-bottom: 0.5rem;
	margin-inline: calc(var(--gutter) * -1);
	padding-inline: var(--gutter);
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
}

.solutions::-webkit-scrollbar {
	display: none;
}

.solution {
	padding: 0;
	flex: 0 0 min(78vw, 16rem);
	scroll-snap-align: center;
	overflow: hidden;
	border-radius: 1.125rem;
	background: var(--zinc-50);
	color: inherit;
	text-align: left;
	box-shadow: var(--shadow-sm);
	cursor: pointer;
	transform-origin: center;
	transition: box-shadow 0.32s ease, translate 0.32s var(--ease-out-expo);
	-webkit-tap-highlight-color: transparent;
}

/* Hover is deliberately cheap — a lift and a shadow, no relayout, nothing that
   moves a neighbouring card. Opening the gallery is a click. */
.solution:hover,
.solution:focus-visible {
	box-shadow: var(--shadow-md);
	translate: 0 -6px;
}

@media (prefers-reduced-motion: reduce) {
	.solution {
		transition: box-shadow 0.32s ease;
	}
	.solution:hover,
	.solution:focus-visible {
		translate: none;
	}
}

.solution__media {
	position: relative;
	aspect-ratio: 1.5 / 1;
	overflow: hidden;
}

.solution__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.32s ease;
}

/* Darkens the lower half so the white title always holds up. */
.solution__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: linear-gradient(
		180deg,
		rgba(255, 255, 255, 0) 28%,
		rgba(0, 0, 0, 0.16) 100%
	);
	background-color: transparent;
	transition: background-color 0.32s ease;
}

.solution:hover .solution__media img,
.solution:focus-visible .solution__media img {
	transform: scale(1.06);
}

.solution__title {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	z-index: 1;
	width: 100%;
	padding-inline: 0.75rem;
	text-align: center;
	text-transform: uppercase;
	font-size: 1.625rem;
	font-weight: 500;
	line-height: 0.95;
	color: #fff;
	text-shadow: 0 2px 6px rgba(0, 0, 0, 0.35), 0 0 18px rgba(0, 0, 0, 0.18);
}

/* The category detail now lives in the product row below, so the cards are the
   photograph and its title alone. Kept in the markup rather than deleted so
   the copy is still there when it is wanted again. */
.solution__list {
	display: none;
}

/* The category the product row is currently showing: the card's own shadow
   turns green and lifts, so selection is carried by the card rather than by a
   border, a fill or a badge added on top of it. */
.solution.is-active {
	box-shadow: 0 12px 28px -10px rgba(150, 201, 61, 0.75),
		0 4px 10px -4px rgba(150, 201, 61, 0.45);
}

/* Inactive categories sit under a dark wash. It rides the media's existing
   overlay layer, which paints above the photograph but below the title — so
   the image recedes while the white title actually gains contrast. */
.solution:not(.is-active) .solution__media::after {
	background-color: rgba(0, 0, 0, 0.611);
}

.solution:not(.is-active):hover .solution__media::after,
.solution:not(.is-active):focus-visible .solution__media::after {
	background-color: rgba(0, 0, 0, 0.15);
}

/* ---------- The dealt product row ---------- */
.products {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1rem;
	margin-top: 1.5rem;
	perspective: 1200px;
}

.product {
	display: block;
	overflow: hidden;
	/* border-radius: 1.125rem; */
	background: var(--zinc-50);
	box-shadow: var(--shadow-sm);
	color: inherit;
	text-decoration: none;
	transform-origin: center;
	border: 1px solid var(--zinc-100);
	transform-style: preserve-3d;
	will-change: transform, opacity;
	transition: box-shadow 0.32s ease, translate 0.32s var(--ease-out-expo);
	-webkit-tap-highlight-color: transparent;
}

.product:hover,
.product:focus-visible {
	box-shadow: var(--shadow-md);
	translate: 0 -6px;
}

.product__media {
	display: block;
	position: relative;
	aspect-ratio: 4 / 5;
	overflow: hidden;
}

.product__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.32s ease;
}

.product:hover .product__media img,
.product:focus-visible .product__media img {
	transform: scale(1.06);
}

.product__name {
	display: block;
	padding: 1.5rem 0;
	text-align: center;
	font-size: 1rem;
	color: var(--zinc-600);
}

.product.is-dealt {
	animation: solution-deal 0.5s var(--ease-out-expo) both;
	animation-delay: var(--deal-delay, 0s);
}

@keyframes solution-deal {
	0% {
		opacity: 0;
		transform: translateY(14px) rotateY(-72deg) scale(0.97);
	}
	58% {
		opacity: 1;
	}
	100% {
		opacity: 1;
		transform: translateY(0) rotateY(0deg) scale(1);
	}
}

@media (prefers-reduced-motion: reduce) {
	.product.is-dealt,
	.solutions__active.is-revealed {
		animation: none;
	}
	.product:hover,
	.product:focus-visible {
		translate: none;
	}
}

/* ============================================================
   Our Portfolio
   Portrait project shots with the client name sitting on the
   image — distinct from Solutions (centred) and News (below).
   ============================================================ */
.works {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1rem;
}

.work {
	position: relative;
	display: block;
	overflow: hidden;
	border-radius: 1rem;
	background: var(--zinc-100);
}

.work__media {
	position: relative;
	aspect-ratio: 2 / 3;
	overflow: hidden;
}

.work__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.6s var(--ease-out-expo);
}

/* Extra shots for the hover cycle, stacked over the base image. app.js
   injects them on first hover and drives the order, so a visitor who never
   hovers a card never downloads the other twelve photos.
   Scoped to .work__media so it outweighs the transition on `.work__media img`,
   which would otherwise drop the opacity transition entirely. */
.work__media .work__frame {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 0.55s ease, transform 0.6s var(--ease-out-expo);
}

.work__media .work__frame.is-on {
	opacity: 1;
}

.work:hover .work__media img,
.work:focus-visible .work__media img {
	transform: scale(1.05);
}

/* Scrim only over the lower third, so the photo stays readable. */
.work::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(
		to top,
		rgba(24, 24, 27, 0.72) 0%,
		rgba(24, 24, 27, 0.15) 32%,
		rgba(24, 24, 27, 0) 55%
	);
	pointer-events: none;
}

.work__title {
	position: absolute;
	left: 1.25rem;
	right: 1.25rem;
	bottom: 1.125rem;
	z-index: 1;
	font-size: 1rem;
	font-weight: 500;
	line-height: 1.3;
	color: #fff;
}

/* ============================================================
   Manufacturing
   The real production floor sits behind the cards at low opacity —
   grounds the section without adding a fourth photo grid.
   ============================================================ */
.manufacturing {
	position: relative;
	/* clip, not hidden: `hidden` makes this a scroll container, which would
	   anchor the backdrop's view() timeline to a box that never scrolls. */
	overflow: clip;
}

.manufacturing > .container {
	position: relative;
	z-index: 1;
}

.manufacturing__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
}

@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.manufacturing__bg {
			animation: mfg-drift linear both;
			animation-timeline: view();
			animation-range: cover;
		}
	}
}

/* Scaling by S leaves (S-1)/2 of overflow at each edge, so a translate of T
   needs S >= 1 + 2T. At scale 1.1 the headroom is 5% a side, and a 20% travel
   dragged the image clean off its own edge. 1.24 covers a 9% travel twice
   over. */
@keyframes mfg-drift {
	from {
		transform: translate3d(0, -9%, 0) scale(1.24);
	}
	to {
		transform: translate3d(0, 9%, 0) scale(1.24);
	}
}

.manufacturing__bg span {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	opacity: 0;
	animation: mfg-cycle 32s linear infinite;
}

/* Each frame holds ~7s, then cross-fades with the next over 1s. */
.manufacturing__bg span:nth-child(2) {
	animation-delay: 8s;
}
.manufacturing__bg span:nth-child(3) {
	animation-delay: 16s;
}
.manufacturing__bg span:nth-child(4) {
	animation-delay: 24s;
}

@keyframes mfg-cycle {
	0% {
		opacity: 0;
	}
	3% {
		opacity: 1;
	}
	25% {
		opacity: 1;
	}
	28% {
		opacity: 0;
	}
	100% {
		opacity: 0;
	}
}

/* The wash lives on the section, not the backdrop — the backdrop drifts, and
   a moving wash would leave undarkened bands at the edges. */
.manufacturing::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	/* Weighted, not flat: the heading and lead sit straight on the photo so
	   the top stays dark, while the lower half lightens because the cards
	   bring their own backing. */
	background: linear-gradient(
		rgba(24, 24, 27, 0.689) 0%,
		rgba(24, 24, 27, 0.416) 30%,
		rgba(24, 24, 27, 0.527) 80%,
		rgba(24, 24, 27, 0.586) 100%
	);
}

/* No cycling for anyone who asked for less motion — hold the first frame. */
@media (prefers-reduced-motion: reduce) {
	.manufacturing__bg span {
		animation: none;
		opacity: 0;
	}
	.manufacturing__bg span:first-child {
		opacity: 1;
	}
}

/* Solid tiles would sit like patches on the photo, so let it through. */
/* Frosted glass: the blur evens out whatever frame is behind, the tint
   supplies the darkness, and the drop shadow lifts the card off the photo. */
.manufacturing .card--dark {
	background: rgba(20, 20, 23, 0.527);
	backdrop-filter: blur(20px) saturate(115%);
	-webkit-backdrop-filter: blur(20px) saturate(115%);
	border: 1px solid rgba(255, 255, 255, 0.09);
	box-shadow: 0 20px 44px -14px rgba(0, 0, 0, 0.85),
		0 2px 8px rgba(0, 0, 0, 0.4);
}

/* Without backdrop-filter the blur never happens, so the tint alone has to
   carry the contrast. */
@supports not (
	(backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))
) {
	.manufacturing .card--dark {
		background: rgba(20, 20, 23, 0.93);
	}
}

.manufacturing .card--dark:hover {
	background: rgba(24, 24, 27, 0.82);
	border-color: rgba(255, 255, 255, 0.16);
	box-shadow: 0 26px 52px -14px rgba(0, 0, 0, 0.9),
		0 2px 8px rgba(0, 0, 0, 0.45);
}

/* ============================================================
   Clients
   Greyscale unifies 45 logos with wildly different palettes;
   colour returns on hover, and stays on for touch devices.
   ============================================================ */
.clients__wall {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75rem;
}

.clients__item {
	display: grid;
	place-items: center;
	width: 6rem; /* three per row at 390px */
	height: 3.5rem;
	padding: 0.5rem;
	background: #fff;
	border: 1px solid var(--zinc-100);
	border-radius: 0.75rem;
}

.clients__item img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	object-fit: contain;
	/* contrast lifts the pale marks (Unilever, unicef) out of the background */
	filter: grayscale(1) contrast(1.15);
	opacity: 0.78;
	transition: filter 0.3s ease, opacity 0.3s ease;
}

.clients__item:hover img {
	filter: none;
	opacity: 1;
}

/* No hover on touch, so never leave them permanently greyed out. */
@media (hover: none) {
	.clients__item img {
		filter: none;
		opacity: 1;
	}
}

/* ============================================================
   News & Insights
   ============================================================ */
.news {
	display: grid;
	grid-template-columns: 1fr;
	gap: 2.5rem;
}

.news__card {
	display: block;
}

.news__media {
	overflow: hidden;
	margin-bottom: 1.25rem;
	border-radius: 1rem;
	aspect-ratio: 3 / 2;
	background: var(--zinc-100);
}

.news__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s var(--ease-out-expo);
}

/* Portrait artwork — anchor to the top so the subject is not cut out of a
   centred crop. Nudge the percentage to reframe without touching the file. */
.news__media--top img {
	object-position: center -40px;
}

.news__card:hover .news__media img,
.news__card:focus-visible .news__media img {
	transform: scale(1.05);
}

.news__title {
	font-size: 1.125rem;
	font-weight: 500;
	line-height: 1.35;
	transition: color 0.2s ease;
}

.news__card:hover .news__title {
	color: var(--brand);
}

/* ============================================================
   Footer
   ============================================================ */
.footer {
	padding-top: 6rem;
	padding-bottom: 3rem;
	background: var(--zinc-50);
	border-top: 1px solid var(--zinc-200);
}

.footer__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 3rem;
	margin-bottom: 4rem;
}

.footer__about .logo {
	margin-bottom: 1.125rem;
}

.footer__entity {
	margin-bottom: 0.625rem;
	font-size: 1rem;
	font-weight: 500;
	letter-spacing: -0.005em;
	color: var(--zinc-900);
}

.footer__blurb {
	max-width: 28rem;
	font-weight: 300;
	font-size: 0.875rem;
	line-height: 1.7;
	color: var(--zinc-500);
}

.footer__heading {
	font-weight: 500;
	margin-bottom: 1.5rem;
}

.footer__list {
	display: grid;
	gap: 1rem;
	font-weight: 300;
	font-size: 0.875rem;
	color: var(--zinc-500);
}

@media (max-width: 767px) {
	.footer__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 1.5rem;
	}
}

.footer__list a {
	transition: color 0.2s;
}
.footer__list a:hover {
	color: var(--brand);
}

.footer__bar {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	padding-top: 2rem;
	border-top: 1px solid var(--zinc-200);
	font-size: 0.8125rem;
	font-weight: 300;
	color: var(--zinc-400);
	text-align: center;
}

.footer__reg {
	white-space: nowrap;
}

.footer__legal {
	display: flex;
	gap: 1.5rem;
}

.footer__legal a {
	transition: color 0.2s;
}
.footer__legal a:hover {
	color: var(--zinc-900);
}

/* ---------- Social ---------- */
.social {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 2rem;
}

.social__link {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	border: 1px solid var(--zinc-200);
	border-radius: 9999px;
	color: var(--zinc-500);
	background: #fff;
	transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.social__link:hover {
	color: #fff;
	background: var(--brand);
	border-color: var(--brand);
}

/* ---------- Offices strip ---------- */
.offices {
	display: grid;
	gap: 1.25rem;
	padding: 2rem 0;
	border-top: 1px solid var(--zinc-200);
}

.offices__label {
	font-size: 0.8rem;
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--zinc-400);
}

.offices__list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem 2rem;
	font-size: 1rem;
	font-weight: 300;
	color: var(--zinc-600);
}

.offices__list li {
	display: flex;
	align-items: center;
	gap: 0.625rem;
}

.offices__pin {
	width: 0.375rem;
	height: 0.375rem;
	border-radius: 9999px;
	background: var(--brand);
	flex: none;
}

.offices__note {
	color: var(--zinc-400);
}

/* ============================================================
   Breakpoints
   ============================================================ */
@media (min-width: 640px) {
	.hero__actions {
		flex-direction: row;
	}
}

@media (min-width: 768px) {
	.section {
		--section-pad: 6rem;
	}
	.footer {
		padding-top: 6rem;
	}

	.br-md {
		display: block;
	}

	.section__title {
		font-size: 3rem;
	}

	.hero__title {
		font-size: 3.75rem;
	}
	.hero__lead {
		font-size: 1.25rem;
	}

	.co__title {
		font-size: 3rem;
	}
	.co__statement {
		font-size: 1.4375rem;
	}
	.stats {
		padding: 1.5rem;
	}

	.stat {
		padding: 1.75rem;
	}

	.navbar .logo {
		--logo-size: 3.5rem;
	}

	.grid-4 {
		grid-template-columns: repeat(2, 1fr);
	}
	.footer__grid {
		grid-template-columns: repeat(2, 1fr);
	}
	.footer__about {
		grid-column: span 2;
	}
	.offices {
		display: flex;
		align-items: center;
		gap: 2.5rem;
	}

	.clients__item {
		width: 8rem;
		height: 4.5rem;
	}

	.head-row {
		flex-direction: row;
		align-items: baseline;
		justify-content: space-between;
		gap: 2rem;
	}

	/* Enough room for a grid — drop the swipe row. */
	.solutions {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 1.125rem;
		overflow: visible;
		margin-inline: 0;
		padding-inline: 0;
	}

	.solution {
		flex: none;
	}

	.products {
		gap: 1.125rem;
	}

	.footer__bar {
		flex-direction: row;
		justify-content: space-between;
		text-align: left;
	}
}

@media (min-width: 1024px) {
	:root {
		--gutter: 2rem;
	}

	.navbar__links {
		display: flex;
		align-items: center;
		gap: 2.25rem;
	}

	.navbar__actions {
		display: flex;
		align-items: center;
		gap: 1.5rem;
	}

	.navbar__toggle {
		display: none;
	}
	.mobile-menu {
		display: none !important;
	}

	.hero__inner {
		align-items: flex-start;
		text-align: left;
	}

	.hero__lead {
		margin-inline: 0;
	}

	.hero__scrim {
		background: linear-gradient(
				to bottom,
				rgba(24, 24, 27, 0.5) 0%,
				rgba(24, 24, 27, 0.12) 12%
			),
			linear-gradient(
				95deg,
				rgba(24, 24, 27, 0.84) 0%,
				rgba(24, 24, 27, 0.78) 34%,
				rgba(24, 24, 27, 0.55) 54%,
				rgba(24, 24, 27, 0.22) 70%,
				rgba(24, 24, 27, 0) 84%
			);
	}

	.hero__actions {
		justify-content: flex-start;
	}
	.hero__title {
		font-size: 4.5rem;
	}

	.split {
		grid-template-columns: repeat(2, 1fr);
	}
	.co__head {
		grid-template-columns: 7fr 5fr;
		gap: 5rem;
		align-items: start;
	}
	.co__gallery {
		aspect-ratio: 2.2 / 1;
	}

	.clients__item {
		width: 9rem;
		height: 5rem;
	}

	.solutions,
	.products {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
	.works {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 1.5rem;
	}
	.work__title {
		font-size: 1.0625rem;
	}
	.news {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 1.5rem;
	}
	.solution__title {
		font-size: 1.875rem;
	}

	.grid-4 {
		grid-template-columns: repeat(4, 1fr);
	}
	.grid-4 {
		gap: 1.5rem;
	}
	.section--dark .grid-4 {
		gap: 2rem;
	}

	/* Five tracks, five blocks — the brand block just gets a wider one. */
	.footer__grid {
		grid-template-columns: 1.7fr 1fr 1fr 1fr 1fr;
		gap: 2.5rem;
	}
	.footer__about {
		grid-column: auto;
	}

	/* Heading column beside the panels, with a hairline between them. */
}

/* ============================================================
   Product detail page (zenon.html)
   ============================================================ */

.pdp-hero {
	padding-block: 7.5rem 4.5rem;
}

.pdp-hero__inner {
	display: grid;
	gap: 2.5rem;
	grid-template-areas:
		"viewer"
		"intro"
		"facts"
		"actions";
}

.pdp-viewer {
	grid-area: viewer;
	min-width: 0;
}
.pdp-intro {
	grid-area: intro;
}
.pdp-facts {
	grid-area: facts;
}
.pdp-actions {
	grid-area: actions;
}

@media (min-width: 900px) {
	.pdp-hero__inner {
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
		grid-template-areas:
			"viewer intro"
			"viewer actions"
			"facts  facts";
		column-gap: 3rem;
		/* the actions row is spaced by its own margin; a row gap here would
		   stack on top of it and push the buttons 80px off the list */
		row-gap: 0;
		align-items: center;
	}
}

/* Only at this width is there room for a genuine third column; below it the
   rail lies flat under both so it never squeezes the copy. */
@media (min-width: 1200px) {
	.pdp-hero__inner {
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr) 14rem;
		grid-template-areas:
			"viewer intro   facts"
			"viewer actions facts";
		align-items: center;
	}
}

/* The stage owns the aspect ratio so nothing reflows as frames swap and the
   loader occupies the exact final footprint. */
.stage {
	position: relative;
	aspect-ratio: 384 / 648;
	/* No plate. The frames carry alpha, and a tinted ground that flatters the
	   black frame would fight the white and grey ones, so the product sits
	   straight on the page and every finish is presented the same way. */
	background: transparent;
	cursor: grab;
	/* Horizontal drag is ours; vertical stays with the page scroller. */
	touch-action: pan-y;
	-webkit-tap-highlight-color: transparent;
	user-select: none;
}

.stage.is-dragging {
	cursor: grabbing;
}

.stage:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}

/* A canvas rather than 36 <img> tags: swapping a src re-enters the decode
   path, and a half-decoded frame mid-drag is the exact stutter the
   pre-decoding exists to avoid. */
.stage canvas {
	display: block;
	width: 100%;
	height: 100%;
}

.loader {
	position: absolute;
	inset: auto 0 0;
	display: grid;
	justify-items: center;
	padding: 1.5rem;
}

.loader[hidden] {
	display: none;
}

.loader__bar {
	width: 55%;
	height: 3px;
	border-radius: 999px;
	background: var(--zinc-200);
	overflow: hidden;
}

.loader__bar span {
	display: block;
	height: 100%;
	width: 0%;
	background: var(--brand);
	transition: width 0.2s linear;
}

/* The viewer looks like a picture until you touch it, so the hint has to do
   the advertising: a swiping arrow and a slow halo, both of which stop for
   good on first interaction. */
.hint {
	position: absolute;
	left: 50%;
	bottom: 1rem;
	display: flex;
	align-items: center;
	gap: 0.45rem;
	padding: 0.5rem 0.95rem;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.94);
	backdrop-filter: blur(10px);
	box-shadow: var(--shadow-sm);
	font-size: 0.8125rem;
	font-weight: 500;
	color: var(--zinc-800);
	white-space: nowrap;
	pointer-events: none;
	transform: translateX(-50%);
	animation: hint-halo 2.6s ease-in-out infinite;
	transition: opacity 0.4s ease;
}

.hint__icon {
	display: grid;
	place-items: center;
	width: 1.1rem;
	height: 1.1rem;
	animation: hint-swipe 2.6s ease-in-out infinite;
}

.hint__icon svg {
	width: 100%;
	height: 100%;
	fill: none;
	stroke: var(--brand);
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

@keyframes hint-swipe {
	0%,
	100% {
		transform: translateX(-2.5px);
	}
	50% {
		transform: translateX(2.5px);
	}
}

@keyframes hint-halo {
	0%,
	100% {
		box-shadow: var(--shadow-sm), 0 0 0 0 rgba(150, 201, 61, 0);
	}
	50% {
		box-shadow: var(--shadow-sm), 0 0 0 7px rgba(150, 201, 61, 0.16);
	}
}

.hint.is-gone {
	opacity: 0;
	animation: none;
}

@media (prefers-reduced-motion: reduce) {
	.hint,
	.hint__icon {
		animation: none;
	}
}

.crumbs {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.8125rem;
	color: var(--zinc-500);
	margin-bottom: 1.25rem;
}

.crumbs a {
	color: var(--zinc-600);
}

.crumbs a:hover {
	color: var(--brand);
}

.pdp-title {
	font-size: clamp(2.75rem, 6vw, 4rem);
	font-weight: 400;
	line-height: 1;
	letter-spacing: -0.03em;
	/* Optical alignment, as on the display headings: a glyph's left side
	   bearing scales with font size, so at this scale the ink sits inside the
	   box while the copy below starts flush. */
	margin-left: -0.05em;
}

.pdp-tagline {
	margin-top: 0.75rem;
	font-size: 1.25rem;
	font-weight: 300;
	color: var(--brand-dark);
}

.pdp-lead {
	margin-top: 1.5rem;
	max-width: 34rem;
	font-size: 1.0625rem;
	line-height: 1.75;
	color: var(--zinc-600);
}

.pdp-highlights {
	margin-top: 1.75rem;
	max-width: 34rem;
	display: grid;
	gap: 0.75rem;
	list-style: none;
	padding: 0;
}

.pdp-highlights li {
	position: relative;
	padding-left: 1.5rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--zinc-700);
}

/* A drawn dot rather than a list-style bullet: the glyph's size and baseline
   vary by font, this stays put and takes the brand colour. */
.pdp-highlights li::before {
	content: "";
	position: absolute;
	left: 0.185rem;
	top: 0.62em;
	width: 0.375rem;
	height: 0.375rem;
	border-radius: 999px;
	background: var(--brand);
}

.pdp-actions {
	margin-top: 2rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

/* The hero ground is white, so a white button has no edge of its own. */
.pdp-actions .btn--light {
	border: 1px solid var(--zinc-300);
}

.pdp-actions .btn--light:hover {
	border-color: var(--zinc-400);
}

.pdp-section-sub {
	margin-top: 0.5rem;
	font-size: 0.9375rem;
	color: var(--zinc-500);
}

.pdp-overview {
	display: grid;
	gap: 1.5rem;
}

@media (min-width: 900px) {
	.pdp-overview {
		grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
		gap: 4rem;
		align-items: start;
	}
}

/* Overview gains a figure column once there is room for one. The figure is
   taller than the copy, so centring keeps the text from stranding a block of
   white space beneath it. */
.pdp-overview--figure {
	gap: 2.5rem;
	align-items: flex-start;
}

/* Centring the row pulled the heading down with it; a section title reads as
   a label for what follows, so it stays at the top. */
.pdp-overview--figure > .section__title {
	align-self: start;
}

@media (min-width: 900px) {
	.pdp-overview--figure {
		grid-template-columns: minmax(0, 13rem) minmax(0, 1fr) minmax(0, 15rem);
		gap: 3rem;
	}
}

.pdp-figure {
	margin: 0;
}

/* The cut-out carries real alpha, so it sits on the section with no plate. */
.pdp-figure {
	display: flex;
	justify-content: center;
}

.pdp-figure img {
	display: block;
	width: auto;
	max-width: 100%;
	/* capped so the tall cut-out does not set the row height on its own */
	max-height: 24rem;
	height: auto;
}

.pdp-figure figcaption {
	margin-top: 0.75rem;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--zinc-500);
}

.pdp-overview__body {
	display: grid;
	gap: 1.25rem;
	max-width: 44rem;
	font-size: 1.0625rem;
	line-height: 1.8;
	color: var(--zinc-600);
}

/* Ten features never divide evenly into three columns, so the rules are drawn
   on the cells themselves. A 1px grid gap over a grey ground would be simpler,
   but it paints the ground into the two empty cells of the last row. */
/* Separators come from a 1px gap showing the grid's own background, not from
   per-card borders. Borders doubled up against the outer border on the last
   row, and needed a different nth-child rule at every breakpoint. */
.feature-grid {
	display: grid;
	gap: 1px;
	background: var(--zinc-200);
	border: 1px solid var(--zinc-200);
	border-radius: 1rem;
	overflow: hidden;
}

.feature {
	display: flex;
	flex-direction: column;
	background: #fff;
	transition: background 0.2s ease;
}

.feature__media {
	display: block;
	background: var(--zinc-50);
	border-bottom: 1px solid var(--zinc-200);
	overflow: hidden;
}

.feature__media img {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform 0.5s var(--ease-out-expo);
}

.feature__body {
	display: block;
	padding: 1.5rem;
}

@media (min-width: 640px) {
	.feature-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.feature-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.feature:hover {
	background: var(--zinc-50);
}

.feature__title {
	font-size: 1rem;
	font-weight: 500;
	line-height: 1.4;
	margin-bottom: 0.5rem;
}

.feature__text {
	font-size: 0.9375rem;
	line-height: 1.65;
	color: var(--zinc-600);
}

.pdp-specs {
	display: grid;
	gap: 2.5rem;
}

@media (min-width: 900px) {
	.pdp-specs {
		grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
		gap: 4rem;
		align-items: start;
	}
}

.pdp-variants {
	margin-top: 1.25rem;
	font-size: 0.9375rem;
	color: var(--zinc-600);
}

.pdp-variants strong {
	font-weight: 600;
	color: var(--zinc-900);
}

/* Downloads */
.download {
	display: flex;
	align-items: center;
	gap: 1.25rem;
	padding: 1.25rem 1.5rem;
	background: #fff;
	border: 1px solid var(--zinc-200);
	border-radius: 1rem;
	transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.download:hover {
	border-color: var(--brand);
	box-shadow: var(--shadow-md);
}

.download__icon {
	display: grid;
	place-items: center;
	flex: none;
	width: 3rem;
	height: 3rem;
	border-radius: 0.75rem;
	background: var(--zinc-100);
	color: var(--zinc-700);
}

.download:hover .download__icon {
	background: var(--brand);
	color: #fff;
}

.download__body {
	display: grid;
	gap: 0.2rem;
	min-width: 0;
}

.download__title {
	font-weight: 500;
	color: var(--zinc-900);
}

.download__meta {
	font-size: 0.8125rem;
	color: var(--zinc-500);
}

.download__cta {
	margin-left: auto;
	flex: none;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--brand-dark);
}

@media (max-width: 480px) {
	.download__cta {
		display: none;
	}
}

/* Dimensions
   The drawings are line art on transparent ground, so they sit straight on the
   section with no plate. The figure list repeats the headline numbers as text
   so they are searchable and readable without loading the image. */
.dims {
	display: grid;
	gap: 2.5rem;
}

@media (min-width: 860px) {
	.dims {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 3rem;
	}
}

.dim {
	margin: 0;
}

.dim__title {
	font-size: 1rem;
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--zinc-900);
	margin-bottom: 1rem;
}

/* ---------- Homepage hero product ---------- */

/* .pdp-viewer carries `grid-area: viewer` for the product page, so this grid
   has to name the same area or the viewer lands in a phantom column. */
.hero-product__inner {
	display: grid;
	gap: 2.5rem;
	align-items: center;
	grid-template-areas:
		"viewer"
		"body";
}

.hero-product__body {
	grid-area: body;
}

@media (min-width: 900px) {
	.hero-product__inner {
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
		grid-template-areas: "viewer body";
		gap: 10rem;
	}
}

/* Sits under the product name as a tagline rather than over it as a label,
   so it is set in sentence case at a normal weight. */
.hero-product__tagline {
	margin-top: 0.5rem;
	font-size: 1.125rem;
	font-weight: 400;
	color: var(--brand);
}

.hero-product__lead {
	max-width: 42rem;
	margin-top: 1rem;
	font-size: 1.0625rem;
	line-height: 1.7;
	color: var(--zinc-600);
}

/* Two up once there is room: one tall column left the right half of the
   section empty. */
.hero-product__points {
	display: grid;
	gap: 0.7rem 2.5rem;
	margin: 1.75rem 0 1.2rem;
	padding: 0;
	list-style: none;
}

@media (min-width: 640px) {
	.hero-product__points {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		margin: 1.75rem 0 2rem;
	}
}

.hero-product__points li {
	position: relative;
	padding-left: 1.4rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--zinc-700);
}

.hero-product__points li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.55em;
	width: 0.4rem;
	height: 0.4rem;
	border-radius: 999px;
	background: var(--brand);
}

/* Loupe: the drawings are vector, so magnifying them stays crisp at any
   factor. The lens paints the same SVG as a background at `--z` times the
   rendered size and offsets it to follow the pointer. */
.dim__figure {
	position: relative;
}

@media (hover: hover) and (pointer: fine) {
	.dim__figure {
		cursor: zoom-in;
	}
}

.dim__lens {
	position: absolute;
	top: 0;
	left: 0;
	display: none;
	width: 12rem;
	height: 12rem;
	border-radius: 999px;
	border: 1px solid var(--zinc-300);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
	/* the drawing is transparent, so the lens supplies its own ground */
	background-color: #fff;
	background-repeat: no-repeat;
	pointer-events: none;
	will-change: background-position, transform;
}

.dim__lens.is-on {
	display: block;
}

.dim img {
	display: block;
	width: 100%;
	height: auto;
}

.dim__list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.75rem 1.5rem;
	margin: 1.5rem 0 0;
	padding-top: 1.25rem;
	border-top: 1px solid var(--zinc-200);
}

.dim__list dt {
	font-size: 0.75rem;
	color: var(--zinc-500);
}

.dim__list dd {
	margin: 0.15rem 0 0;
	font-size: 0.9375rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--zinc-900);
}

/* The unit rides along at text weight so the figure stays the thing you read. */
.dim__list dd span {
	font-size: 0.8125rem;
	font-weight: 400;
	color: var(--zinc-500);
}

/* Gallery */
.gallery {
	display: grid;
	gap: 1rem;
}

@media (min-width: 700px) {
	.gallery {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
	.gallery__item--wide {
		grid-column: 1 / -1;
	}
}

/* Tiles hold a fixed frame and crop the photo to it; the whole uncropped
   frame is what the lightbox shows. Each tile carries its own
   object-position so the chair's base stays in the crop. */
.gallery__item {
	position: relative;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 1rem;
	overflow: hidden;
	background: var(--zinc-100);
	aspect-ratio: 4 / 3;
	cursor: zoom-in;
	font: inherit;
	color: inherit;
}

.gallery__item--wide {
	aspect-ratio: 16 / 9;
}

.gallery__item img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.6s var(--ease-out-expo);
}

.gallery__item:hover img,
.gallery__item:focus-visible img {
	transform: scale(1.03);
}

.gallery__zoom {
	position: absolute;
	right: 0.75rem;
	bottom: 0.75rem;
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.9);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
	opacity: 0;
	transform: translateY(0.35rem);
	transition: opacity 0.25s ease, transform 0.25s ease;
}

.gallery__item:hover .gallery__zoom,
.gallery__item:focus-visible .gallery__zoom {
	opacity: 1;
	transform: none;
}

.gallery__zoom svg {
	width: 1.05rem;
	height: 1.05rem;
	fill: none;
	stroke: var(--zinc-900);
	stroke-width: 1.8;
	stroke-linecap: round;
}

/* ---------- Lightbox ---------- */

.lightbox {
	--lb-pad: clamp(1rem, 4vw, 3.5rem);
	width: 100vw;
	max-width: 100vw;
	height: 100dvh;
	max-height: 100dvh;
	margin: 0;
	padding: 0;
	border: 0;
	background: rgba(9, 9, 11, 0.94);
	overflow: hidden;
}

.lightbox::backdrop {
	background: rgba(9, 9, 11, 0.94);
}

.lightbox__stage {
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	margin: 0;
	padding: var(--lb-pad);
	box-sizing: border-box;
}

/* Sized against the viewport, not the grid area: a percentage max-height on a
   grid item resolves against an auto-sized row, which is circular, so the
   photo would render at its natural size and overflow. */
/* Product renders carry alpha and are shot on white; the dark ground reads as
   a mistake behind them. Photographs keep the dark ground. */
.lightbox--light,
.lightbox--light::backdrop {
	background: #fff;
}

.lightbox--light .lightbox__nav,
.lightbox--light .lightbox__close {
	background: rgba(9, 9, 11, 0.06);
	color: var(--zinc-900);
}

.lightbox--light .lightbox__nav:hover,
.lightbox--light .lightbox__close:hover {
	background: rgba(9, 9, 11, 0.12);
}

.lightbox--light .lightbox__count {
	color: var(--zinc-500);
}

/* Sits over the artwork, so it carries its own plate rather than relying on
   whatever is behind it. Retires once the visitor has zoomed. */
.lightbox__hint {
	position: absolute;
	left: 50%;
	top: clamp(0.75rem, 2vw, 1.5rem);
	transform: translateX(-50%);
	padding: 0.35rem 0.8rem;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.92);
	box-shadow: var(--shadow-sm);
	font-size: 0.8125rem;
	color: var(--zinc-700);
	pointer-events: none;
	transition: opacity 0.3s ease;
}

.lightbox__hint.is-gone {
	opacity: 0;
}

.lightbox__stage img {
	/* An <img> is draggable by default, and starting a native drag cancels the
	   pointer stream mid-gesture, so the swipe never gets its pointerup. */
	-webkit-user-drag: none;
	user-select: none;
	display: block;
	max-width: calc(100vw - 2 * var(--lb-pad));
	max-height: calc(100dvh - 2 * var(--lb-pad));
	width: auto;
	height: auto;
	border-radius: 0.5rem;
	object-fit: contain;
	/* zoom is applied here by script; the transition is only for the reset */
	transform-origin: 0 0;
	will-change: transform;
}

/* The stage fills the viewport and never scrolls, so every gesture on it is
   ours: swipe to page, or pan once zoomed. Leaving pan-y here let Chromium
   claim the drag for its scroller and fire pointercancel mid-swipe. */
.lightbox__stage {
	touch-action: none;
}

.lightbox__stage.is-zoomed {
	cursor: grab;
	overflow: hidden;
	touch-action: none;
}

.lightbox__stage.is-panning {
	cursor: grabbing;
}

.lightbox__nav,
.lightbox__close {
	position: absolute;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.12);
	color: #fff;
	cursor: pointer;
	transition: background 0.2s ease;
}

.lightbox__nav:hover,
.lightbox__close:hover {
	background: rgba(255, 255, 255, 0.24);
}

.lightbox__nav svg,
.lightbox__close svg {
	width: 1.35rem;
	height: 1.35rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
}

.lightbox__nav {
	top: 50%;
	transform: translateY(-50%);
}

.lightbox__nav--prev {
	left: clamp(0.5rem, 2vw, 1.5rem);
}

.lightbox__nav--next {
	right: clamp(0.5rem, 2vw, 1.5rem);
}

.lightbox__close {
	top: clamp(0.75rem, 2vw, 1.5rem);
	right: clamp(0.75rem, 2vw, 1.5rem);
}

.lightbox__count {
	position: absolute;
	left: 50%;
	bottom: clamp(0.75rem, 2vw, 1.5rem);
	transform: translateX(-50%);
	font-size: 0.8125rem;
	font-variant-numeric: tabular-nums;
	color: rgba(255, 255, 255, 0.7);
}

@media (prefers-reduced-motion: reduce) {
	.gallery__item img,
	.gallery__zoom {
		transition: none;
	}
}

/* Hero facts rail */
.pdp-facts {
	display: grid;
	gap: 1.5rem;
	align-content: start;
}

/* Between 900 and 1199 the rail sits under the row, so it reads across
   instead of down. */
@media (min-width: 900px) and (max-width: 1199px) {
	.pdp-facts {
		grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
		gap: 1.5rem 2rem;
		margin-top: 3rem;
		padding-top: 1.75rem;
		border-top: 1px solid var(--zinc-200);
	}
}

@media (min-width: 1200px) {
	.pdp-facts {
		padding-left: 2rem;
		border-left: 1px solid var(--zinc-200);
	}
}

.fact__label {
	font-size: 0.75rem;
	font-weight: 400;
	letter-spacing: 0.01em;
	/* Capitalised rather than shouted: at 400 weight the all-caps tracking
	   read as a system label instead of a spec sheet. */
	text-transform: capitalize;
	color: var(--zinc-500);
	margin-bottom: 0.4rem;
}

.fact__value {
	font-size: 1rem;
	font-weight: 500;
	color: var(--zinc-900);
	font-variant-numeric: tabular-nums;
}

.fact__value span {
	font-size: 0.8125rem;
	font-weight: 400;
	color: var(--zinc-500);
}

.finishes {
	display: grid;
	gap: 0.5rem;
	list-style: none;
	padding: 0;
	margin: 0;
}

.finishes li {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	font-size: 0.875rem;
	color: var(--zinc-700);
}

.finish__chip {
	width: 0.9rem;
	height: 0.9rem;
	border-radius: 999px;
	background: var(--chip);
	flex: none;
}

/* The white chip would vanish on the page ground without an edge. */
.finish__chip--light {
	box-shadow: inset 0 0 0 1px var(--zinc-300);
}

.fact__link {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-size: 0.875rem;
	font-weight: 500;
	color: var(--zinc-900);
}

.fact__link:hover {
	color: var(--brand-dark);
}

/* The subtitle keeps its size and rhythm on the dark section; only the colour
   changes, since zinc-500 has too little contrast against zinc-900. */
.section--dark .pdp-section-sub {
	color: rgba(255, 255, 255, 0.65);
}

/* Same stack as .head-row__lead: the 0.4rem flex gap adds to the subtitle's
   own margin, so heading-to-subtitle spacing matches the other sections. */
.pdp-specs__lead {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

/* Colourway swatches under the viewer */
.swatches {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.75rem;
	margin-top: 1.5rem;
}

.swatch {
	width: 1.75rem;
	height: 1.75rem;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: var(--swatch);
	cursor: pointer;
	/* The ring is drawn outside the fill so the colour circle stays the same
	   size whether or not it is selected. */
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12), 0 0 0 0 var(--brand);
	transition: box-shadow 0.2s ease, transform 0.2s var(--ease-out-expo);
}

.swatch:hover {
	transform: scale(1.08);
}

.swatch[aria-pressed="true"] {
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12), 0 0 0 2px #fff,
		0 0 0 4px var(--brand);
}

.swatch:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 4px;
}

/* Visually hidden but still read out, so each swatch has a real name. */
.u-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Nudge the viewer toward the page edge so the product leads rather than
   sitting boxed inside the text column.

   The pull is limited to half the free space beside the container, so it fades
   to nothing exactly when the container fills the viewport. A fixed negative
   margin looked right on a wide screen and pushed the chair to within 12px of
   the edge at 1200px. */
@media (min-width: 1200px) {
	.pdp-viewer {
		margin-left: calc(
			-1 * min(2.5rem, max(0px, (100vw - var(--container)) / 2))
		);
	}
}

/* ============================================================
   The mechanism — the product's headline claim
   ============================================================ */

.mech__grid {
	display: grid;
	gap: 2.5rem;
	align-items: center;
}

/* As the lead item of Product Features it needs air beneath it, so the six
   cards below read as a second tier rather than a continuation. */
.mech__grid--lead {
	margin-top: 0.5rem;
	margin-bottom: 4rem;
}

.mech__title {
	/* Subordinate to the section's own h2, so it steps down rather than
	   competing with "Product Features" directly above it. */
	font-size: clamp(1.5rem, 2.4vw, 2rem);
	font-weight: 500;
	line-height: 1.1;
	margin-bottom: 0.5rem;
	letter-spacing: -0.02em;
	color: var(--zinc-900);
}

@media (min-width: 900px) {
	.mech__grid {
		grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
		gap: 4rem;
	}
}

.mech__figure {
	margin: 0;
	border-radius: 1.25rem;
	overflow: hidden;
	/* A soft plate rather than flat white, so the transparent render has
	   something to sit on and the figure reads as one object. */
	background: linear-gradient(
		160deg,
		var(--zinc-100) 0%,
		var(--zinc-50) 55%,
		#ececed 100%
	);
}

/* The gallery: slides stack inside a fixed frame, stepped by the arrows.
   It used to crossfade on a timer; navigating by hand means a visitor can stay
   on the angle they care about instead of waiting for it to come round. */
.mech__figure {
	position: relative;
	margin: 0;
	border-radius: 1.25rem;
	overflow: hidden;
	background: linear-gradient(
		160deg,
		var(--zinc-100) 0%,
		var(--zinc-50) 55%,
		#ececed 100%
	);
}

.mech__frame {
	position: relative;
	aspect-ratio: 1400 / 1070;
	touch-action: pan-y;
}

.mech__slide {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0;
	transition: opacity 0.35s ease;
}

.mech__slide.is-current {
	opacity: 1;
}

.mech__nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 1px solid var(--zinc-200);
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.92);
	backdrop-filter: blur(8px);
	color: var(--zinc-700);
	cursor: pointer;
	transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.mech__nav:hover {
	background: #fff;
	border-color: var(--zinc-300);
	color: var(--zinc-900);
}

.mech__nav:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}

.mech__nav svg {
	width: 1.15rem;
	height: 1.15rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.75;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.mech__nav--prev {
	left: 0.85rem;
}
.mech__nav--next {
	right: 0.85rem;
}

.mech__count {
	position: absolute;
	right: 0.9rem;
	bottom: 0.8rem;
	padding: 0.25rem 0.6rem;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.9);
	font-size: 0.75rem;
	font-variant-numeric: tabular-nums;
	color: var(--zinc-600);
}

.mech__points {
	display: grid;
	gap: 1.5rem;
	margin-top: 2.25rem;
	max-width: 34rem;
}

.mech__point {
	padding-left: 1.1rem;
	border-left: 2px solid var(--brand);
}

.mech__point h4 {
	font-size: 0.9375rem;
	font-weight: 600;
	margin-bottom: 0.35rem;
	color: var(--zinc-900);
}

.mech__point p {
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--zinc-600);
}

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

/* ---------- Product angles ---------- */

/* A row of angle thumbnails under the overview. Tapping one opens it full
   screen in the shared lightbox, where the 1600px render is worth pinching
   into. Scrolls sideways only if the viewport is too narrow for five. */
.angles {
	display: flex;
	gap: 0.5rem;
	margin-top: 2rem;
	overflow-x: auto;
	scroll-snap-type: x proximity;
	scrollbar-width: none;
}

.angles::-webkit-scrollbar {
	display: none;
}

.angle {
	display: block;
	flex: 0 0 4.5rem;
	padding: 0;
	border: 1px solid var(--zinc-200);
	border-radius: 0.5rem;
	background: var(--zinc-50);
	cursor: zoom-in;
	overflow: hidden;
	aspect-ratio: 3 / 4;
	scroll-snap-align: start;
	transition: border-color 0.2s ease, background 0.2s ease;
}

.angle:hover,
.angle:focus-visible {
	border-color: var(--zinc-400);
	background: #fff;
}

.angle img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
	/* the renders carry generous margins already, so a little inset is enough */
	padding: 0.35rem;
	box-sizing: border-box;
	transition: transform 0.35s var(--ease-out-expo);
}

.angle:hover img {
	transform: scale(1.04);
}

@media (prefers-reduced-motion: reduce) {
	.angle img {
		transition: none;
	}
}

/* ---------- Tests and certificates ---------- */

/* Flex, not a fixed two-column grid: the badge is optional, and a grid would
   hold an empty 16rem column open while the copy crushed into the rest. */
.certs {
	display: flex;
	flex-wrap: wrap;
	gap: 2rem 3.5rem;
	align-items: start;
}

.certs__badge {
	/* the source badge is 196px wide, so it is never scaled up past its own
	   pixels */
	flex: 0 0 12rem;
	margin: 0;
}

.certs__body {
	flex: 1 1 30rem;
	min-width: 0;
}

.certs__badge {
	margin: 0;
}

.certs__badge img {
	display: block;
	width: 100%;
	max-width: 12rem;
	height: auto;
}

/* The two statements sit side by side when there is room for them. */
.certs__body {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
	gap: 2rem 3rem;
}

.cert__title {
	font-size: 1rem;
	font-weight: 600;
	margin-bottom: 0.6rem;
	color: var(--zinc-900);
}

.cert p {
	font-size: 0.9375rem;
	line-height: 1.7;
	color: var(--zinc-600);
}

/* ==========================================================================
   Mobile typography and layout

   The desktop scale reads as oversized on a phone: leads at 18-20px and the
   stat figures at 44px crowd a 390px column. Body copy settles at 16px, the
   standard mobile reading size, and everything above it steps down to match.
   ========================================================================== */

@media (max-width: 639px) {
	/* --- body copy lands on 16px, up or down --- */
	.prose p,
	.hero-product__lead,
	.hero-product__points li,
	.pdp-lead,
	.pdp-highlights li,
	.pdp-overview__body p,
	.mech__lead,
	.mech__point p,
	.feature__text,
	.dim__list dd {
		font-size: 1rem;
	}

	/* the hero is the one place that carries a larger lead: it is the first
	   thing read and has no competing copy around it */
	.hero__lead {
		font-size: 1.125rem;
	}

	/* The hard break is placed for the desktop measure; on a phone it just
	   strands a short second line. */
	.hero__lead br {
		display: none;
	}

	/* --- section leads and statements step down from 20px --- */
	.section__lead,
	.co__statement,
	.solutions__active,
	.pdp-tagline {
		font-size: 1.125rem;
	}

	.hero-product__tagline {
		font-size: 1.0625rem;
	}

	/* --- the stat figures no longer dominate the column, and the icon moves
	       beside the number instead of stacking above it, which saves roughly
	       48px of height per row --- */
	.stat {
		position: relative;
		padding: 1rem;
	}

	.stat__value {
		font-size: 2rem;
	}

	/* The icon is markup-wise the first child of the value, but it reads as a
	   corner marker rather than part of the figure, so it is lifted out of the
	   flow to the top right instead of sitting inline with the number. */
	.stat__icon {
		position: absolute;
		top: 1rem;
		right: 1rem;
		width: 1.25rem;
		height: 1.25rem;
		margin: 0;
	}

	.stat__label {
		margin-top: 0.5rem;
	}

	/* --- both hero buttons run the full column, so they match --- */
	.hero__actions {
		display: grid;
		gap: 0.75rem;
		width: 100%;
	}

	.hero__actions > * {
		width: 100%;
		justify-content: center;
	}

	/* the strip runs to the screen edge so it reads as scrollable */
	.angles {
		margin-top: 1.5rem;
		margin-inline: calc(var(--gutter) * -1);
		padding-inline: var(--gutter);
	}

	/* --- the certification badge reads as a mark, not an illustration:
	       smaller and aligned with the copy it sits above --- */
	.certs__badge {
		flex-basis: 100%;
		display: flex;
		justify-content: flex-start;
	}

	.certs__badge img {
		max-width: 8rem;
	}

	/* --- four swatches down a full-width column wastes the right half --- */
	.finishes {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 0.6rem 1rem;
	}

	/* --- 2.5rem between the heading and the copy is a desktop gap. The grid's
	       own row gap sets the rhythm; the title's bottom margin would stack a
	       second gap on top of it. --- */
	.pdp-overview--figure {
		gap: 1.25rem;
	}

	.pdp-overview .section__title {
		margin-bottom: 0;
	}

	/* --- the two CTAs were a pill and a bare word; one width, one shape --- */
	.pdp-actions {
		display: grid;
		gap: 0.75rem;
		/* the hero grid's own 2.5rem row gap already separates this from the
		   facts rail; the margin was stacking a second gap on top */
		margin-top: 0;
	}

	.pdp-actions .btn {
		width: 100%;
		justify-content: center;
	}

	/* --- text-plus-arrow links read as body copy on a phone and give a 24px
	       tap target. As bordered full-width pills they read as the actions
	       they are, and clear the 44px minimum. --- */
	.link-btn {
		display: flex;
		width: 100%;
		align-items: center;
		justify-content: space-between;
		min-height: 3rem;
		padding: 0.7rem 1.15rem;
		border: 1px solid var(--zinc-200);
		border-radius: 999px;
		background: #fff;
		font-size: 0.9375rem;
	}

	/* the arrow already sits at the far edge, so it needs no nudge room */
	.link-btn .icon {
		flex: none;
	}

	/* The head row stacks on mobile, so its own gap sets the rhythm: a tight
	   pair of title and label, then a clear step down to the action. The
	   title's bottom margin would double up with .head-row__lead's gap. */
	.head-row {
		gap: 0.75rem;
	}

	.head-row .section__title {
		margin-bottom: 0;
	}

	/* --- four categories fit two-up, so show them all rather than hiding
	       three behind a swipe with nothing to signal it --- */
	.solutions {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 0.75rem;
		overflow: visible;
		margin-inline: 0;
		padding-inline: 0;
		scroll-snap-type: none;
	}

	.solution {
		flex: none;
	}

	.solution__media {
		aspect-ratio: 1.35 / 1;
	}

	.solution__title {
		font-size: 0.875rem;
	}

	/* --- 72px top and bottom puts 144px of nothing between neighbouring
	       sections on a 390px column. The same-ground rule still divides this
	       by three, so adjacent light sections join on 40 + 13. --- */
	.section {
		--section-pad: 2.5rem;
	}

	/* --- the About block: 3rem between the copy and the stats, then 4rem to
	       the photo below, is desktop rhythm on a 390px column --- */
	.co__head {
		gap: 1.75rem;
		margin-bottom: 2rem;
	}

	/* --- 5rem under a section head is a third of a phone screen --- */
	.section__head {
		margin-bottom: 2.5rem;
	}

	.section__title {
		margin-bottom: 1rem;
	}

	/* --- the viewer is portrait 384:648, so at full column width it eats a
	       whole phone screen before any copy is reached --- */
	.stage {
		max-width: 14rem;
		margin-inline: auto;
	}

	/* --- capability cards: icon beside the text rather than above it --- */
	.card {
		padding: 1.5rem;
	}

	.card--dark {
		display: grid;
		grid-template-columns: auto minmax(0, 1fr);
		column-gap: 1rem;
	}

	.card--dark .card__icon {
		grid-row: span 2;
		width: 2.5rem;
		height: 2.5rem;
		margin-bottom: 0;
	}

	.card--dark .card__title {
		grid-column: 2;
		align-self: center;
		font-size: 1.0625rem;
		margin-bottom: 0.35rem;
	}

	/* The break exists to even the cards out side by side; stacked, it just
	   makes every card taller. */
	.card__title br {
		display: none;
	}

	.card--dark .card__text {
		grid-column: 2;
		font-size: 0.9375rem;
	}
}

/* Once the capability cards sit side by side, their titles wrap to different
   line counts and the descriptions stop lining up. Subgrid hands the icon,
   title and text rows to the parent so every card shares the same three row
   heights; where it is unsupported, a two-line floor on the title gets most
   of the way there. */
@media (min-width: 640px) {
	.card__title {
		line-height: 1.3;
	}
}

@supports (grid-template-rows: subgrid) {
	@media (min-width: 640px) {
		.grid-4 {
			grid-template-rows: auto auto auto;
		}

		.grid-4 > .card {
			display: grid;
			grid-row: span 3;
			grid-template-rows: subgrid;
			/* the row gap is the only spacing now: the children's own margins
			   would stack on top of the shared row heights and open a void */
			row-gap: 0.85rem;
		}

		.grid-4 > .card .card__icon,
		.grid-4 > .card .card__title {
			margin-bottom: 0;
		}

		.card__title {
			min-height: 0;
			/* the title row is as tall as the longest title; sitting the short
			   ones at its foot keeps every title the same distance above its
			   own description, and puts the slack under the icon where it
			   reads as breathing room rather than a gap */
			align-self: end;
		}
	}
}

/* ============================================================
   3D product viewer (clova.html)
   A three.js scene in place of the frame-sequence turntable. The stage
   keeps the same loader and hint chrome, but the desk is landscape and
   reads from above, so the aspect and the hero grid differ from the
   portrait chair layout.
   ============================================================ */

.stage--3d {
	aspect-ratio: 4 / 3;
	cursor: grab;
	touch-action: auto;
}

.stage--3d:active {
	cursor: grabbing;
}

.viewer-canvas {
	display: block;
	width: 100%;
	height: 100%;
	outline: none;
}

.viewer-canvas:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}

/* The poster covers the canvas until the model is in, then fades out so
   the live render appears to develop from the still. */
.viewer-poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: contain;
	pointer-events: none;
	transition: opacity 0.5s ease;
}

.viewer-poster.is-gone {
	opacity: 0;
}

/* Toolbar: mode toggle on the left, reset and fullscreen on the right.
   White pills, as the hint uses, so the chrome reads as one family. */
.viewer-tools {
	position: absolute;
	top: 0.75rem;
	left: 0.75rem;
	right: 0.75rem;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	opacity: 0;
	transition: opacity 0.4s ease;
	pointer-events: none;
}

.stage--3d.is-ready .viewer-tools {
	opacity: 1;
	pointer-events: auto;
}

.viewer-modes {
	display: inline-flex;
	padding: 0.2rem;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.94);
	backdrop-filter: blur(10px);
	box-shadow: var(--shadow-sm);
	margin-right: auto;
}

.viewer-mode {
	padding: 0.35rem 0.85rem;
	border: 0;
	border-radius: 999px;
	background: transparent;
	font: inherit;
	font-size: 0.8125rem;
	font-weight: 500;
	color: var(--zinc-600);
	cursor: pointer;
	transition: background 0.2s ease, color 0.2s ease;
}

.viewer-mode:hover {
	color: var(--zinc-900);
}

.viewer-mode[aria-pressed="true"] {
	background: var(--zinc-900);
	color: #fff;
}

.viewer-mode:focus-visible,
.viewer-tool:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}

.viewer-tool {
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.94);
	backdrop-filter: blur(10px);
	box-shadow: var(--shadow-sm);
	color: var(--zinc-800);
	cursor: pointer;
	transition: transform 0.2s var(--ease-out-expo), color 0.2s ease;
}

.viewer-tool:hover {
	transform: scale(1.06);
	color: var(--brand);
}

.viewer-tool svg {
	width: 1.1rem;
	height: 1.1rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.viewer-tool__exit,
.viewer-tool[aria-pressed="true"] .viewer-tool__enter {
	display: none;
}

.viewer-tool[aria-pressed="true"] .viewer-tool__exit {
	display: block;
}

/* Key legend: only meaningful in Explore mode, and only with a keyboard. */
.viewer-keys {
	position: absolute;
	left: 0.75rem;
	bottom: 0.75rem;
	display: none;
	flex-wrap: wrap;
	gap: 0.35rem 0.9rem;
	margin: 0;
	padding: 0.45rem 0.8rem;
	border-radius: 0.6rem;
	background: rgba(255, 255, 255, 0.94);
	backdrop-filter: blur(10px);
	box-shadow: var(--shadow-sm);
	font-size: 0.75rem;
	color: var(--zinc-700);
	pointer-events: none;
}

.viewer-keys span {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
}

.viewer-keys kbd {
	display: inline-grid;
	place-items: center;
	min-width: 1.35rem;
	height: 1.35rem;
	padding: 0 0.3rem;
	border-radius: 0.3rem;
	border: 1px solid var(--zinc-300);
	background: #fff;
	font: inherit;
	font-size: 0.7rem;
	font-weight: 600;
	color: var(--zinc-900);
}

@media (hover: hover) and (pointer: fine) {
	.stage--3d[data-mode="explore"] .viewer-keys {
		display: flex;
	}
}

/* Fullscreen. The real API and the class fallback (iPhone) share styles. */
.stage--3d:fullscreen,
.stage--3d.is-fullscreen {
	position: fixed;
	inset: 0;
	z-index: 1000;
	width: 100vw;
	height: 100vh;
	max-width: none;
	aspect-ratio: auto;
	margin: 0;
	background: #fff;
}

.stage--3d:fullscreen .viewer-tools,
.stage--3d.is-fullscreen .viewer-tools {
	top: calc(1rem + env(safe-area-inset-top, 0px));
	left: calc(1rem + env(safe-area-inset-left, 0px));
	right: calc(1rem + env(safe-area-inset-right, 0px));
}

.stage--3d:fullscreen .viewer-keys,
.stage--3d.is-fullscreen .viewer-keys {
	bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
}

.has-fullscreen-viewer {
	overflow: hidden;
}

/* Studio credit: bottom-right of the stage, fullscreen only. Gradient text
   with a plain colour fallback where background-clip: text is unsupported. */
.viewer-credit {
	display: none;
	position: absolute;
	right: calc(1rem + env(safe-area-inset-right, 0px));
	bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
	margin: 0;
	font-size: 0.75rem;
	line-height: 1rem;
	font-weight: 300;
	color: var(--zinc-500);
	white-space: nowrap;
}

.stage--3d:fullscreen .viewer-credit,
.stage--3d.is-fullscreen .viewer-credit {
	display: block;
}

/* Lines up with the Customize panel's right edge; the panel leaves a strip
   free beneath itself (see viewer-popovers.js) so the credit sits under it. */
.stage--3d:fullscreen .viewer-credit,
.stage--3d.is-fullscreen .viewer-credit {
	right: calc(12px + env(safe-area-inset-right, 0px));
	bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}

.viewer-credit__link {
	font-weight: 400;
	color: #0075c9;
	transition: color 0.3s ease;
}

@supports (-webkit-background-clip: text) or (background-clip: text) {
	.viewer-credit__link {
		background: linear-gradient(to right, #00b098, #0075c9);
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
		transition: background 0.3s ease;
	}

	.viewer-credit__link:hover {
		background: #000;
		-webkit-background-clip: text;
		background-clip: text;
	}
}

/* A landscape model needs the width a portrait chair gave up, so the viewer
   takes the wider column and the facts rail drops beneath both. */
@media (min-width: 900px) {
	.pdp-hero--3d .pdp-hero__inner {
		grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
	}
}

@media (min-width: 1200px) {
	.pdp-hero--3d .pdp-hero__inner {
		grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) 13rem;
	}
}

/* On phones the portrait stage is capped at 14rem; a landscape one should
   run the full column instead. */
@media (max-width: 899px) {
	.stage--3d {
		max-width: none;
	}
}

/* Product photos and the optional 3D chip share the existing quiet chrome. */
.view-toggle {
	display: flex;
	justify-content: center;
	margin-top: 0.5rem;
}

.view-chip {
	border: 1px solid var(--zinc-300);
	border-radius: 999px;
	padding: 0.65rem 1.1rem;
	min-height: 44px;
	background: #fff;
	color: var(--zinc-800);
	font: inherit;
	font-size: 0.8125rem;
	font-weight: 500;
	cursor: pointer;
	transition: background 0.2s ease, color 0.2s ease;
}

.view-chip:hover,
.view-chip[aria-pressed="true"] {
	background: var(--zinc-900);
	border-color: var(--zinc-900);
	color: #fff;
}

.view-chip:focus-visible,
.product-carousel button:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}

.product-carousel__viewport {
	cursor: default;
}
.product-carousel__slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 0.35s ease;
	pointer-events: none;
}
.product-carousel__slide.is-current {
	opacity: 1;
}
.product-carousel__slide img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}
.product-carousel__controls {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.25rem;
	margin-top: 0.75rem;
}
.product-carousel__controls button {
	display: grid;
	place-items: center;
	min-width: 30px;
	min-height: 30px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: transparent;
	color: var(--zinc-700);
	font: inherit;
	cursor: pointer;
}
.product-carousel__controls button:hover {
	background: var(--zinc-100);
}
.product-carousel__dots {
	display: flex;
	gap: 0.5rem;
}
.product-carousel__dots span {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--zinc-300);
	transition: background 0.2s ease, transform 0.2s ease;
}
.product-carousel__dots [aria-pressed="true"] span {
	background: var(--zinc-900);
	transform: scale(1.3);
}
.viewer-status {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	z-index: 1;
	width: max-content;
	max-width: calc(100% - 2rem);
	margin: 0;
	padding: 0.5rem 0.75rem;
	border-radius: 0.5rem;
	background: rgba(255, 255, 255, 0.92);
	font-size: 0.75rem;
	line-height: 1.6;
	color: var(--zinc-600);
	text-align: center;
}
.view-toggle[hidden],
.product-carousel[hidden],
.swatches[hidden],
.viewer-status[hidden] {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.product-carousel__slide,
	.product-carousel__dots span,
	.view-chip {
		transition: none !important;
	}
}

/* A chair is portrait; keep the photo gallery's proportions so nothing shifts
   when the two views are switched. */
.stage--3d.stage--portrait {
	aspect-ratio: 384 / 648;
}

/* Both portrait views stay compact until the desktop hero starts at 900px. */
@media (width < 900px) {
	.product-carousel__viewport,
	.stage--3d.stage--portrait {
		max-width: 14rem;
		margin-inline: auto;
	}
}

/* Override portrait and mobile dimensions in both fullscreen paths. */
.stage--3d:fullscreen,
.stage--3d.is-fullscreen {
	width: 100vw;
	height: 100vh;
	height: 100dvh;
	max-width: none;
	aspect-ratio: auto;
	margin: 0;
}

.stage--3d[hidden] {
	display: none;
}

/* Optional textile samples, kept beside the chair's existing finish controls. */
.mesh-options {
	margin-top: 1rem;
	border-block: 1px solid var(--zinc-200);
	font-size: 0.8125rem;
	text-align: left;
}

.mesh-options[hidden],
.mesh-options__choices[hidden] {
	display: none;
}

.mesh-options summary {
	padding-block: 0.9rem;
	cursor: pointer;
	font-weight: 600;
}

.mesh-options__selected {
	float: right;
	font-size: 0.7rem;
	font-weight: 400;
	color: var(--zinc-500);
}

.mesh-options fieldset {
	border: 0;
	padding: 0;
	margin: 0;
	min-width: 0;
}
.mesh-options fieldset:disabled {
	opacity: 0.5;
}
.mesh-options__fields {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}
.mesh-options label {
	display: grid;
	gap: 0.4rem;
	font-weight: 500;
}

.mesh-options select {
	width: 100%;
	min-width: 0;
	min-height: 44px;
	padding: 0.5rem;
	border: 1px solid var(--zinc-300);
	border-radius: 0.4rem;
	background: #fff;
	color: var(--zinc-900);
	font: inherit;
}

.mesh-options__choices {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 0.5rem;
	margin-top: 0.85rem;
}

.mesh-option {
	display: grid;
	align-content: start;
	gap: 0.35rem;
	padding: 0.25rem;
	border: 2px solid transparent;
	border-radius: 0.4rem;
	background: transparent;
	color: var(--zinc-600);
	font: inherit;
	font-size: 0.65rem;
	line-height: 1.25;
	cursor: pointer;
}

.mesh-option img {
	width: 100%;
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: 0.2rem;
}
.mesh-swatch-preview,
.original-weave-preview {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	overflow: hidden;
	border-radius: 0.2rem;
	isolation: isolate;
}
.mesh-swatch-preview img,
.original-weave-preview img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}
.original-weave-preview img {
	mix-blend-mode: screen;
}
.mesh-option:hover {
	background: var(--zinc-100);
}
.mesh-option[aria-pressed="true"] {
	border-color: var(--zinc-900);
	color: var(--zinc-900);
}
.mesh-options :is(button, select, input, summary):focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}
.mesh-options__reset {
	min-height: 44px;
	margin-top: 0.3rem;
	padding: 0;
	border: 0;
	background: transparent;
	font: inherit;
	text-decoration: underline;
	text-underline-offset: 3px;
	cursor: pointer;
	color: var(--zinc-700);
}
.mesh-options__status {
	margin: 0.5rem 0;
	color: var(--zinc-700);
}
.mesh-options__note {
	margin: 0 0 0.9rem;
	color: var(--zinc-500);
	font-size: 0.7rem;
	line-height: 1.5;
}

.viewer-tools--compact {
	justify-content: flex-end;
	flex-wrap: wrap;
	gap: 0.375rem;
}
.viewer-tools--compact .viewer-tool {
	width: 44px;
	height: 44px;
	flex: 0 0 44px;
}
.viewer-tool[aria-expanded="true"] {
	background: var(--zinc-900);
	color: #fff;
}
.mesh-selection {
	display: none;
	position: absolute;
	left: 12px;
	bottom: 12px;
	z-index: 4;
	box-sizing: border-box;
	max-width: calc(100% - 24px);
	padding: 0.65rem 0.75rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.75rem;
	background: rgba(255, 255, 255, 0.96);
	box-shadow: 0 3px 16px rgba(0, 0, 0, 0.06);
	color: var(--zinc-800);
	text-align: left;
	pointer-events: none;
}
@media (min-width: 640px) {
	.stage--3d:fullscreen .mesh-selection:not([hidden]),
	.stage--3d.is-fullscreen .mesh-selection:not([hidden]) { display: block; }
}
.mesh-selection__label {
	margin: 0;
	font-size: 0.75rem;
	font-weight: 600;
}
.viewer-tool.motion-trigger { display: none; }
@media (max-width: 639px) {
    .viewer-tool.motion-trigger:not([hidden]) { display: grid; }
    .stage--3d:not(:fullscreen):not(.is-fullscreen) .viewer-tools--compact {
        left: 2px;
        right: 2px;
        gap: 0;
        flex-wrap: nowrap;
    }
}
.stage--3d:fullscreen .motion-trigger:not([hidden]),
.stage--3d.is-fullscreen .motion-trigger:not([hidden]) { display: grid; }
.motion-trigger svg { fill: currentColor; }
.motion-trigger__stop, .motion-trigger[data-playing="true"] .motion-trigger__play { display: none; }
.motion-trigger[data-playing="true"] .motion-trigger__stop { display: block; }
.motion-trigger[data-playing="true"] { background: var(--zinc-900); color: white; }
.motion-menu__note { margin: .65rem 0; color: var(--zinc-500); font-size: .75rem; }
.motion-menu { display: grid; gap: 4px; }
.motion-menu button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    min-height: 58px;
    padding: 10px 12px;
    border: 1px solid transparent;
    border-radius: 9px;
    background: transparent;
    color: var(--zinc-900);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.motion-menu button:hover:not(:disabled) { background: #f5f9ee; border-color: var(--brand); }
.motion-menu button:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.motion-menu button:disabled { opacity: .4; cursor: default; }
.motion-menu strong, .motion-menu small { display: block; }
.motion-menu strong { font-size: .8125rem; font-weight: 600; }
.motion-menu small { color: var(--zinc-500); font-size: .6875rem; margin-top: 2px; }
.motion-menu svg { width: 16px; height: 16px; flex: 0 0 16px; fill: currentColor; }
.viewer-popover {
	position: fixed;
	z-index: 1100;
	box-sizing: border-box;
	width: min(22rem, calc(100vw - 24px));
	padding: 1rem;
	border: 1px solid var(--zinc-200);
	border-radius: 1rem;
	background: #fff;
	box-shadow: 0 12px 40px rgba(0, 0, 0, 0.14);
	color: var(--zinc-800);
	font-size: 0.8125rem;
	line-height: 1.5;
	text-align: left;
	overflow-y: auto;
	overscroll-behavior: contain;
	touch-action: pan-x pan-y;
	user-select: text;
	cursor: default;
}
.viewer-popover[hidden] {
	display: none;
}
.viewer-popover[data-viewer-popover="customize"] {
	padding: 0.75rem;
}
.viewer-popover__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	position: sticky;
	top: -1rem;
	z-index: 1;
	margin-top: -0.5rem;
	padding-block: 0.5rem;
	background: #fff;
}
.viewer-popover__head h3 {
	margin: 0;
	font-size: 1rem;
	font-weight: 600;
}
.viewer-popover[data-viewer-popover="customize"] .viewer-popover__head {
	top: -0.75rem;
	margin-top: -0.25rem;
	padding-block: 0;
}
.viewer-popover__close {
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	flex: 0 0 44px;
	border: 0;
	border-radius: 0;
	background: transparent;
	color: var(--zinc-700);
	cursor: pointer;
}
.viewer-popover__close:hover {
	color: var(--zinc-900);
}
.viewer-popover__close svg {
	width: 18px;
	height: 18px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
}
.viewer-popover__close:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}
.viewer-popover__subheading {
	margin: 0.75rem 0;
	font-size: 0.8125rem;
	font-weight: 600;
}
.viewer-popover .swatches {
	justify-content: flex-start;
	margin-block: 0.5rem 1rem;
}
.viewer-popover .mesh-options {
	margin-top: 0.25rem;
	border-bottom: 0;
}
.viewer-popover .mesh-options__note {
	margin-bottom: 0;
}
.combination-presets {
	padding-top: 0.5rem;
	padding-bottom: 0.5rem;
	margin-bottom: 0.85rem;
	border-bottom: 1px solid var(--zinc-200);
}
.combination-presets > h4 {
	margin: 0 0 0.6rem;
	font-size: 0.8rem;
	font-weight: 600;
	padding: 0.2rem 0;
}
.combination-presets__toggle {
	display: block;
	width: 100%;
	min-height: 36px;
	margin-top: 0.4rem;
	border: 0;
	border-radius: 0.35rem;
	background: transparent;
	color: var(--zinc-600);
	font: inherit;
	font-size: 0.75rem;
	cursor: pointer;
}
.combination-presets__toggle:hover {
	background: var(--zinc-100);
	color: var(--zinc-900);
}
.combination-presets__toggle:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
}
.combination-preset[hidden],
.combination-presets__toggle[hidden] {
	display: none;
}
.combination-presets__list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.45rem;
}
.combination-preset {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	min-width: 0;
	padding: 0.6rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.45rem;
	background: #fff;
	color: var(--zinc-800);
	text-align: left;
	font: inherit;
	cursor: pointer;
}
.combination-preset strong {
	font-size: 0.75rem;
}
.combination-preset__collection {
	font-size: 0.65rem;
	color: var(--zinc-500);
}
.combination-preset__colours {
	display: flex;
	gap: 0.2rem;
	margin-bottom: 0.15rem;
}
.combination-preset__colours span {
	width: 0.95rem;
	height: 0.95rem;
	border-radius: 50%;
	border: 1px solid #00000018;
}
.combination-preset:hover:not(:disabled) {
	border-color: var(--zinc-400);
}
.combination-preset[aria-pressed="true"] {
	border-color: var(--brand);
	background: #f5f9ee;
}
.combination-preset:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}
.combination-preset:disabled {
	opacity: 0.5;
	cursor: default;
}
.custom-parts {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.4rem;
	margin-block: 0.375rem 0.625rem;
}
.custom-part {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	min-width: 0;
	min-height: 48px;
	padding: 0.375rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.5rem;
	background: #fff;
	color: var(--zinc-800);
	font: inherit;
	text-align: left;
	cursor: pointer;
}
.custom-part:hover {
	background: var(--zinc-50);
}
.custom-part[aria-pressed="true"] {
	border-color: var(--brand);
	box-shadow: inset 0 0 0 1px var(--brand);
	background: #f7faef;
}
.custom-part:disabled {
	opacity: 0.45;
	cursor: default;
}
.custom-part strong {
	display: block;
	font-size: 0.75rem;
	font-weight: 600;
}
.custom-part [data-part-summary] {
	display: block;
	margin-top: 0.15rem;
	font-size: 0.65rem;
	line-height: 1.3;
	color: var(--zinc-500);
}
.custom-part__chip {
	overflow: hidden;
	width: 24px;
	height: 24px;
	flex: 0 0 24px;
	border: 1px solid var(--zinc-200);
	border-radius: 50%;
	background-size: cover;
}
.custom-part__chip > img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.part-editor {
	border-top: 1px solid var(--zinc-200);
}
.part-editor__fields {
	display: grid;
	gap: 0.65rem;
}
.part-option > p,
.part-editor__choice-label {
	margin: 0 0 0.4rem;
	font-size: 0.75rem;
	font-weight: 600;
}
.part-option__choices {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.4rem;
}
.part-option > .mesh-options__note {
	margin: 0.5rem 0 0;
	font-weight: 400;
	line-height: 1.5;
}
.part-option__choices button {
	min-height: 40px;
	padding: 0.45rem 0.75rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.5rem;
	background: #fff;
	color: var(--zinc-800);
	font: inherit;
	cursor: pointer;
}
.part-option__choices button[aria-pressed="true"] {
	border-color: var(--brand);
	background: #f6f9f0;
	box-shadow: inset 0 0 0 1px var(--brand);
}
.part-option__choices button:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}
.part-option__choices button:disabled {
	opacity: 0.5;
	cursor: default;
}
.part-editor__choice-label {
	margin-top: 0.85rem;
}
.part-editor__choice-label:not([hidden]) ~ .mesh-options__choices {
	margin-top: 0;
}
.mesh-options__choices.is-grouped {
	display: block;
	padding: 2px;
}
.mesh-family + .mesh-family {
	margin-top: 0.9rem;
	padding-top: 0.9rem;
	border-top: 1px solid var(--zinc-200);
}
.mesh-family h5 {
	margin: 0 0 0.45rem;
	font-size: 0.75rem;
	font-weight: 600;
	color: var(--zinc-900);
}
.mesh-family__swatches {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 0.45rem;
}
.mesh-options__choices:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}
.part-editor__selected {
	margin: -0.35rem 0 1rem;
	font-size: 0.7rem;
	color: var(--zinc-500);
}
.part-editor [hidden] {
	display: none;
}
.finish-option__colour {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	border: 1px solid var(--zinc-200);
	border-radius: 50%;
}
.custom-reset {
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	margin-top: 0.5rem;
}
.saved-combinations {
	margin-top: 1rem;
	padding-top: 1rem;
	border-top: 1px solid var(--zinc-200);
}
.saved-combinations h4 {
	margin: 0 0 0.75rem;
	font-size: 0.875rem;
}
.saved-combinations form {
	display: grid;
	gap: 0.5rem;
}
.saved-combinations label {
	display: block;
	font-size: 0.75rem;
}
.saved-combinations__optional {
	color: var(--zinc-500);
	font-weight: 400;
}
.saved-combinations input {
	box-sizing: border-box;
	width: 100%;
	min-width: 0;
	min-height: 44px;
	padding: 0.6rem 0.7rem;
	border: 1px solid var(--zinc-300);
	border-radius: 0.4rem;
	font: inherit;
	color: var(--zinc-900);
	background: #fff;
}
.saved-combinations__save {
	min-height: 44px;
	padding: 0.6rem 0.75rem;
	border: 0;
	border-radius: 0.4rem;
	background: var(--zinc-900);
	color: #fff;
	font: inherit;
	font-weight: 500;
	cursor: pointer;
}
.saved-combinations button:disabled {
	opacity: 0.45;
	cursor: wait;
}
.configuration-image {
	display: block;
	width: 100%;
	min-height: 44px;
	margin-top: 0.5rem;
	padding: 0.6rem 0.75rem;
	border: 1px solid var(--zinc-300);
	border-radius: 0.4rem;
	background: #fff;
	color: var(--zinc-900);
	font: inherit;
	cursor: pointer;
}
.configuration-image:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 2px;
}
.saved-combinations__note,
.saved-combinations__status,
.saved-combinations__empty {
	font-size: 0.7rem;
	color: var(--zinc-500);
}
.mesh-options__status:empty,
.saved-combinations__status:empty {
	display: none;
}
.saved-combinations > details > summary {
	padding-block: 0.65rem;
	font-weight: 600;
}
.saved-combination {
	border-top: 1px solid var(--zinc-200);
	overflow-wrap: anywhere;
}
.saved-combination > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	min-height: 44px;
	padding-block: 0.65rem;
	font-size: 0.8125rem;
	list-style: none;
	cursor: pointer;
}
.saved-combination > summary > span {
	min-width: 0;
}
.saved-combination > summary::-webkit-details-marker {
	display: none;
}
.saved-combination > summary::after {
	content: "";
	flex: 0 0 0.4rem;
	height: 0.4rem;
	margin-right: 0.2rem;
	border-right: 1.5px solid var(--zinc-500);
	border-bottom: 1.5px solid var(--zinc-500);
	transform: rotate(45deg);
}
.saved-combination[open] > summary::after {
	transform: rotate(225deg);
}
.saved-combination__reference {
	display: block;
	margin-top: 0.15rem;
	font-size: 0.65rem;
	font-weight: 400;
	color: var(--zinc-500);
	letter-spacing: 0.04em;
}
.saved-combination__content {
	padding-bottom: 0.8rem;
}
.saved-combination__content h6 {
	margin: 0;
	font-size: 0.75rem;
	font-weight: 600;
}
.saved-combination dl {
	margin: 0.6rem 0;
	font-size: 0.7rem;
}
.saved-combination dt {
	margin-top: 0.45rem;
	font-weight: 500;
}
.saved-combination dd {
	margin: 0;
	color: var(--zinc-500);
}
.saved-combination__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-top: 0.65rem;
}
.saved-combination__actions button {
	min-height: 36px;
	padding: 0.35rem 0.6rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.35rem;
	background: #fff;
	color: var(--zinc-800);
	font: inherit;
	font-size: 0.7rem;
	cursor: pointer;
}
.saved-combination__actions button:hover {
	background: var(--zinc-50);
}
.mesh-options .custom-part-mobile {
	display: none;
}
@media (max-width: 639px) {
	.custom-parts {
		display: none;
	}
	.viewer-popover .mesh-options {
		margin-top: 0.25rem;
		border-top: 0;
	}
	.part-editor {
		border-top: 0;
	}
	.part-editor > h4 {
		display: none;
	}
	.part-editor__selected {
		margin: 0.5rem 0 0.75rem;
	}
	.part-editor__fields {
		grid-template-columns: minmax(0, 1fr);
	}
	.mesh-options .custom-part-mobile {
		display: grid;
	}
}
.viewer-shortcuts {
	margin: 1rem 0;
}
.viewer-shortcuts > div {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 0.5rem;
	border-bottom: 1px solid var(--zinc-100);
}
.viewer-shortcuts dt {
	display: flex;
	flex-wrap: wrap;
	flex-shrink: 0;
	gap: 0.25rem;
}
.viewer-shortcuts dd {
	margin: 0;
	color: var(--zinc-600);
	text-align: right;
}
.viewer-shortcuts .viewer-shortcut-mouse {
	align-items: center;
	flex-wrap: nowrap;
	gap: 0.4rem;
}
.viewer-mouse-icon {
	width: 20px;
	height: 28px;
	flex: 0 0 auto;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
}
.viewer-mouse-icon__wheel {
	fill: var(--brand);
	stroke: var(--zinc-800);
}
.viewer-shortcuts kbd {
	min-width: 1.5rem;
	padding: 0.15rem 0.3rem;
	border: 1px solid var(--zinc-200);
	border-radius: 0.3rem;
	background: var(--zinc-50);
	font: inherit;
	font-size: 0.75rem;
	text-align: center;
}
.viewer-popover__note {
	margin: 0;
	font-size: 0.75rem;
	color: var(--zinc-500);
}

/* ============================================================
   WordPress performance / resilience patch v2.1
   Content must never depend on JavaScript in order to be readable.
   ============================================================ */
html:not(.bristol-js) .reveal,
html.bristol-js .reveal {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Keep transitions lightweight on the WordPress build. */
.reveal,
.hero__copy {
  transition: none;
}

/* Browser can skip layout/paint work for long off-screen sections. */
@supports (content-visibility: auto) {
  .section:not(.hero-product),
  .footer {
    content-visibility: auto;
    contain-intrinsic-size: auto 900px;
  }
}
