/*
 * Shared foundation for every generated preview.
 *
 * Everything a build used to invent — header, nav, footer, buttons, sections, gallery, responsive
 * behaviour — lives here once, so the mistakes we kept shipping cannot come back: a 127px header with a
 * 152px logo tile, links that break under a subfolder, pages that disagree with each other.
 *
 * A site's personality comes from the TOKENS below (set per site by a palette + type pack) and from its
 * variant stylesheet. Nothing here should need editing per business.
 */

/* ── tokens: the only per-site knobs ─────────────────────────────────────────── */
:root {
	--ink: #14110f; /* dark sections + body text */
	--ground: #f7f2e8; /* warm off-white. NEVER #fff — the instant tell of a generated page */
	--accent: #b4763a; /* buttons, small marks, one or two moments */
	--ink-soft: color-mix(in srgb, var(--ink) 66%, var(--ground));
	--line: color-mix(in srgb, var(--ink) 14%, transparent);
	--line-dark: color-mix(in srgb, var(--ground) 18%, transparent);

	--display: 'Forum', Georgia, serif;
	--body: 'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
	--display-weight: 400;
	--display-tracking: -0.01em;

	/*
	 * Contrast tokens. Defaults live HERE, in CSS read fresh on every build, and the per-site :root
	 * that render-blocks appends overrides --on-accent with the value picked for that palette.
	 *
	 * --on-accent: text ON the accent (buttons). The default is --ink, not --ground: measured across
	 * the ten palettes, ink beats ground on eight of them and cream-on-accent was as low as 2.12:1.
	 * --accent-ink: the accent darkened toward ink, for small accent-coloured text on the ground —
	 * kickers, eyebrows, prices — where the raw accent ran 2.12–4.94:1 at 11px. Derived from tokens
	 * the site block already sets, so it needs nothing from the build step.
	 */
	--on-accent: var(--ink);
	--accent-ink: color-mix(in srgb, var(--accent) 55%, var(--ink));

	--radius: 14px;
	--pad: clamp(20px, 5vw, 64px); /* page gutter */
	--section: clamp(64px, 9vw, 150px); /* vertical rhythm: whitespace is the luxury signal */
	/*
	 * For bands that are a LINE of content, not a section of it: the facts strip, the plain cta band.
	 * One padding for every section is right while the content is tall and absurd when it is not —
	 * measured on a real page, the facts strip held 101px of content inside 374px of section, so 73%
	 * of it was empty, and the cta band 55%. The tall sections were 14-22%, which is the look working.
	 */
	--section-tight: clamp(32px, 4vw, 72px);
	--bar: 72px; /* header height — see HEADER below */
}

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

html {
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--ground);
	color: var(--ink);
	font-family: var(--body);
	font-size: 17px;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
}

img {
	display: block;
	max-width: 100%;
}

a {
	color: inherit;
}

h1,
h2,
h3 {
	font-family: var(--display);
	font-weight: var(--display-weight);
	letter-spacing: var(--display-tracking);
	line-height: 1.02;
	margin: 0;
	text-wrap: balance;
}

/* One focus ring for every link, button and field, in the site's own accent (darkened on light palettes so it
   keeps 3:1). :where() keeps it at zero specificity, so a block that draws its own ring keeps it. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--accent-ink, var(--accent));
	outline-offset: 3px;
}

/* The sticky header must not cover what just took focus, or the target of an in-page link. */
html {
	scroll-padding-top: calc(var(--bar) + 16px);
}

.skip-link {
	position: fixed;
	top: -64px;
	left: 12px;
	z-index: 200;
	padding: 11px 18px;
	border-radius: 999px;
	background: var(--accent);
	color: var(--on-accent, var(--ground));
	font-weight: 600;
	font-size: 0.9rem;
	text-decoration: none;
	transition: top 0.15s ease-out;
}
.skip-link:focus-visible {
	top: 12px;
}

h1 {
	font-size: clamp(2.6rem, 6.4vw, 5.2rem);
}
h2 {
	font-size: clamp(2rem, 4.2vw, 3.4rem);
}
h3 {
	font-size: clamp(1.15rem, 1.7vw, 1.45rem);
}

/* A heading followed straight by copy had NO gap — h1/h2/h3 carry margin:0 and p only has a bottom
   margin, so "…you arriving?" sat on the line under it in every block that pairs the two. A block that
   wants its own spacing sets it on its own class, which wins on specificity. */
:is(h1, h2, h3) + :is(p, .muted, ul, ol, blockquote) {
	margin-top: 0.7em;
}

p {
	margin: 0 0 1em;
	max-width: 62ch;
}

.wrap {
	width: 100%;
	max-width: 1240px;
	margin-inline: auto;
	padding-inline: var(--pad);
}

/* A site can ask for the whole window (content.json brand.wide): the page keeps its side gutter but no
   longer stops at 1240px. Reading text keeps its own measure (p is capped at 62ch). */
.is-wide .wrap { max-width: none; }

.eyebrow {
	font-size: 0.72rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	/* Darkened accent: this is 11px of tracked-out uppercase on the ground, where the raw accent was
	   2.21:1 and effectively invisible. */
	color: var(--accent-ink);
	margin: 0 0 14px;
}

.muted {
	color: var(--ink-soft);
}

/* ── header ───────────────────────────────────────────────────────────────────
 * HARD SIZES. Generated sites drifted to a 127px bar carrying a 152x103 logo tile; the mark is a brand
 * mark, not a banner. Bar 72px (60 on phones), logo 40px tall (32), everything on one line.
 */
.site-head {
	position: sticky;
	top: 0;
	z-index: 50;
	background: color-mix(in srgb, var(--ground) 92%, transparent);
	backdrop-filter: blur(10px);
	border-bottom: 1px solid transparent;
	transition: border-color 0.2s ease-out, background-color 0.2s ease-out;
}

.site-head.is-stuck {
	border-bottom-color: var(--line);
}

.site-head__in {
	display: flex;
	align-items: center;
	gap: 18px;
	height: var(--bar);
}

/* white-space: nowrap keeps the mark and the name on one line, which is right until the name is
   "Animal Kingdom Veterinary Hospital" — 410px of it in a 390px viewport, which pushed the whole
   document to 482px wide and gave every page a horizontal scrollbar on a phone. min-width: 0 lets the
   flex item shrink instead of forcing the header open; below the breakpoint the name is allowed to
   wrap rather than be truncated, because a business's own name is the last thing to cut short. */
.brand {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	min-width: 0;
	text-decoration: none;
	font-family: var(--display);
	font-size: 1.15rem;
	letter-spacing: 0.01em;
	white-space: nowrap;
}

@media (max-width: 560px) {
	.brand {
		white-space: normal;
		font-size: 1rem;
		line-height: 1.15;
	}
	.brand span {
		/* Two lines at most; a name longer than that is a sign to shorten it in the content. */
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}
}

.brand img {
	height: 40px;
	width: auto;
	max-width: 132px;
	object-fit: contain;
	border-radius: 999px;
	background: #fff;
}

.brand img.is-lockup {
	border-radius: 8px;
	max-width: 168px;
}

.nav {
	display: flex;
	align-items: center;
	gap: clamp(16px, 2.2vw, 30px);
	margin-left: auto;
}

.nav a {
	position: relative;
	font-size: 0.93rem;
	text-decoration: none;
	color: var(--ink-soft);
	padding: 4px 0;
	transition: color 0.18s ease-out;
}

.nav a:hover,
.nav a[aria-current='page'] {
	color: var(--ink);
}

/* The nav's own `a` rule is more specific than .btn, which flattened the CTA's padding to 4px 0 and
   left the pill hugging its text. Restore it for a button that happens to live in the nav. */
.nav a.btn {
	padding: 11px 20px;
	color: var(--ground);
}

.nav a[aria-current='page']::after {
	content: '';
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1.5px;
	background: var(--accent);
}

.nav a.btn::after {
	content: none;
}

/*
 * A row of buttons. SIX blocks render .b-actions — the five heroes and cta-band — and only three of
 * them ever declared it a flex row. In the other three the buttons fell back to inline-flex and sat
 * with nothing between them but the whitespace in the HTML, which on pill buttons reads as a single
 * blob; cta-band's own `justify-content: center` was a no-op, because the children of a block
 * element cannot be justified. Declared once, here, so a block only states what it ADDS.
 */
.b-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px;
}

.btn {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	border: 0;
	border-radius: 999px;
	padding: 12px 22px;
	font: inherit;
	font-size: 0.92rem;
	font-weight: 500;
	text-decoration: none;
	cursor: pointer;
	background: var(--accent);
	/* Not --ground. A button is normal-size text, so it needs 4.5:1, and cream on a mid-tone accent
	   gave 2.21:1 on pearl — nine of the ten palettes failed. --on-accent is picked per palette. */
	color: var(--on-accent);
	transition: transform 0.18s ease-out, filter 0.18s ease-out;
}

.btn:hover {
	transform: translateY(-1px);
	filter: brightness(1.06);
}

.btn--ghost {
	background: transparent;
	color: var(--ink);
	box-shadow: inset 0 0 0 1px var(--line);
}

.burger {
	display: none;
	margin-left: auto;
	width: 40px;
	height: 40px;
	border: 0;
	background: transparent;
	cursor: pointer;
}

.burger span {
	display: block;
	height: 1.5px;
	width: 22px;
	margin: 5px auto;
	background: var(--ink);
	transition: transform 0.2s ease-out, opacity 0.2s ease-out;
}

/* ── sections ─────────────────────────────────────────────────────────────── */
.section {
	padding-block: var(--section);
}

.section--ink {
	background: var(--ink);
	color: var(--ground);
}

/* Any surface that flips to the ink background has to flip its secondary text with it. The footer was
   missing from this list, so .muted there kept --ink-soft — a dark grey meant for a light background —
   and the business description and address sat at 2.68:1 against near-black. AA wants 4.5:1. */
.section--ink .muted,
.section--ink .nav a,
.site-foot .muted {
	color: color-mix(in srgb, var(--ground) 72%, transparent);
}

.section__head {
	display: grid;
	gap: 18px;
	margin-bottom: clamp(28px, 4vw, 56px);
}

@media (min-width: 900px) {
	.section__head--split {
		grid-template-columns: 1.1fr 0.9fr;
		align-items: end;
	}
}

.grid {
	display: grid;
	gap: clamp(16px, 2.4vw, 28px);
}

.grid--2 {
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.grid--3 {
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.card {
	border-radius: var(--radius);
	overflow: hidden;
	background: color-mix(in srgb, var(--ink) 4%, var(--ground));
}

.card img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	aspect-ratio: 4 / 3;
}

.card__body {
	padding: 18px 20px 22px;
}

.figure {
	border-radius: var(--radius);
	overflow: hidden;
}

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

/* Full-bleed photo band between sections. */
.interstitial img {
	width: 100%;
	height: clamp(260px, 42vw, 520px);
	object-fit: cover;
}

/* ── menu ─────────────────────────────────────────────────────────────────── */
.menu-item {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 6px 18px;
	padding: 14px 0;
	border-bottom: 1px solid var(--line);
}

/* The last item in a group left a rule hanging under it with nothing beneath — a divider that divides
   nothing. The group's own edge does that job. */
.menu-item:last-child {
	border-bottom: 0;
	padding-bottom: 0;
}

.menu-item__name {
	font-weight: 500;
}

.menu-item__price {
	font-variant-numeric: tabular-nums;
	color: var(--accent-ink);
	white-space: nowrap;
}

.menu-item__desc {
	grid-column: 1 / -1;
	margin: 0;
	font-size: 0.93rem;
	color: var(--ink-soft);
}

/* A SHORT menu — a café's six drinks rather than a restaurant's eleven dishes. The item carries sizes
   instead of a description, so the line stays one row and the prices line up down the column. */
.menu-item--sizes {
	grid-template-columns: 1fr auto;
	align-items: baseline;
}

.menu-sizes {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 14px;
	justify-content: flex-end;
	font-variant-numeric: tabular-nums;
}

.menu-size {
	display: inline-flex;
	align-items: baseline;
	gap: 6px;
	font-size: 0.93rem;
}

.menu-size__label {
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--ink-soft);
}

.menu-size__price {
	color: var(--accent-ink);
}

/* A short menu reads better as one narrow column than as two wide ones. */
.menu-cols--short {
	max-width: 760px;
	grid-template-columns: 1fr;
}

/* ── gallery ──────────────────────────────────────────────────────────────── */
.gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 10px;
}

.gallery img {
	width: 100%;
	height: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: 10px;
}

/* ── facts / contact ──────────────────────────────────────────────────────── */
.facts {
	display: grid;
	gap: 2px;
}

.fact {
	display: grid;
	grid-template-columns: 7.5rem 1fr;
	gap: 14px;
	padding: 12px 0;
	border-bottom: 1px solid var(--line);
	font-size: 0.95rem;
}

.fact dt {
	color: var(--ink-soft);
	font-size: 0.78rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	padding-top: 3px;
}

.fact dd {
	margin: 0;
}

.map {
	width: 100%;
	height: clamp(240px, 34vw, 420px);
	border: 0;
	border-radius: var(--radius);
	background: color-mix(in srgb, var(--ink) 6%, var(--ground));
}

/* ── footer ───────────────────────────────────────────────────────────────── */
.site-foot {
	background: var(--ink);
	color: var(--ground);
	padding-block: clamp(48px, 6vw, 88px) 28px;
}

.site-foot a {
	color: color-mix(in srgb, var(--ground) 80%, transparent);
	text-decoration: none;
	/* a link is a target: at least 28px tall (40 on a touch screen), not a 23.8px line of text */
	display: inline-flex;
	align-items: center;
	min-height: 28px;
}
@media (pointer: coarse) {
	.site-foot a { min-height: 40px; }
}

/* A footer that opts in to icons (content.socialIcons) shows its messenger and social links as round icon buttons. */
.foot-icons { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.site-foot a.foot-icon {
	display: grid; place-items: center; width: 44px; height: 44px; min-height: 0; border-radius: 50%;
	border: 1px solid var(--line-dark); color: color-mix(in srgb, var(--ground) 88%, transparent);
	transition: color 0.2s ease-out, border-color 0.2s ease-out, background-color 0.2s ease-out;
}
.site-foot a.foot-icon:hover { color: var(--ground); border-color: color-mix(in srgb, var(--ground) 55%, transparent); background: color-mix(in srgb, var(--ground) 8%, transparent); }
.foot-icon svg { display: block; width: 21px; height: 21px; }

.site-foot a:hover {
	color: var(--ground);
}

.site-foot__grid {
	display: grid;
	gap: 32px;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	padding-bottom: 36px;
	border-bottom: 1px solid var(--line-dark);
}

.site-foot__bottom {
	display: grid;
	grid-template-columns: 1fr auto 1fr; /* the middle item stays centred whatever the outer two weigh */
	gap: 10px 24px;
	padding-top: 22px;
	font-size: 0.82rem;
	color: color-mix(in srgb, var(--ground) 60%, transparent);
}

.fb-start { grid-column: 1; }
.fb-mid { grid-column: 2; justify-self: center; }
.fb-end { grid-column: 3; justify-self: end; }
@media (max-width: 640px) {
	.site-foot__bottom { grid-template-columns: 1fr; }
	.fb-start, .fb-mid, .fb-end { grid-column: auto; justify-self: start; }
}

.stack {
	display: grid;
	gap: 8px;
	align-content: start;
	font-size: 0.93rem;
}

/* A footer with several stores: the stores column takes two grid columns and lays its stores out in a row. */
.stack--stores { grid-column: span 2; }
.foot-stores { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px 28px; }
@media (min-width: 1000px) {
	/* wide enough to give the stores their own wide column: three stores side by side, no wrapping names */
	.site-foot__grid:has(.stack--stores) { grid-template-columns: minmax(160px, 1fr) minmax(0, 3fr) minmax(212px, 1.1fr) minmax(90px, .6fr); } /* 212px: four 44px icon buttons fit one row */
	.stack--stores { grid-column: auto; }
}
.foot-store { display: grid; gap: 3px; align-content: start; line-height: 1.4; }
.foot-store a { font-weight: 600; }
@media (max-width: 640px) { .stack--stores { grid-column: auto; } .foot-stores { grid-template-columns: 1fr; } }

/* ── page header (inner pages) ────────────────────────────────────────────── */
.page-head {
	padding-block: clamp(44px, 6vw, 92px) clamp(28px, 4vw, 56px);
}

/* ── motion: on-load only. No scroll-tied animation anywhere ───────────────── */
@keyframes rise {
	from {
		opacity: 0;
		transform: translateY(14px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

[data-rise] {
	animation: rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
	animation-delay: var(--d, 0ms);
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation: none !important;
		transition: none !important;
	}
}

/* ── phones ───────────────────────────────────────────────────────────────── */
@media (max-width: 820px) {
	:root {
		--bar: 60px;
	}

	.brand img {
		height: 32px;
		max-width: 108px;
	}

	.burger {
		display: block;
	}

	.nav {
		position: absolute;
		top: var(--bar);
		left: 0;
		right: 0;
		display: none;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: 8px var(--pad) 18px;
		background: var(--ground);
		border-bottom: 1px solid var(--line);
	}

	.site-head.is-open .nav {
		display: flex;
	}

	.nav a {
		padding: 13px 0;
		font-size: 1.05rem;
		border-bottom: 1px solid var(--line);
	}

	.nav .btn {
		margin-top: 12px;
		justify-content: center;
	}

	.fact {
		grid-template-columns: 1fr;
		gap: 2px;
	}
}

/* ── virtual scroll ──────────────────────────────────────────────────────────
   Only live when a look sets --virtual-scroll: 1 AND motion.js decided the device suits it; until
   then none of these classes exist and the page is an ordinary scrolling document. */
.vscroll-on .vscroll {
	position: fixed;
	inset: 0 0 auto 0;
	will-change: transform;
}
/* The spacer is the document's real height — it is what the scrollbar measures and what the browser
   scrolls. Take it out of the flow's normal sizing so it cannot add its own margins. */
.vscroll-on .vscroll-spacer {
	pointer-events: none;
}
/* The header has to sit outside the translated wrapper, so sticky becomes fixed. Same result: it was
   pinned to the top at every scroll position anyway. */
.vscroll-on .site-head {
	position: fixed;
	inset: 0 0 auto 0;
	width: 100%;
}
/* There is no scrolling ancestor left inside the wrapper, so a sticky pin cannot stick. It lays out
   fine as an ordinary column — the photograph scrolls with its text instead of holding. A look that
   wants pinned columns should not ask for virtual scroll. */
.vscroll-on .sticky-split__pin {
	position: static;
}

/* Styling for the interaction components in components.js. Structural, not decorative: a variant
   restyles these, it does not need to re-implement them. */

/* ── carousel ─────────────────────────────────────────────────────────────── */
.rail {
	display: flex;
	gap: 16px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-bottom: 4px;
}

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

.rail.is-dragging { cursor: grabbing; scroll-snap-type: none; }

.rail > * {
	flex: 0 0 min(78vw, 420px);
	scroll-snap-align: start;
}

.rail--wide > * { flex-basis: min(92vw, 720px); }

.carousel__bar {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 18px;
}

.carousel__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 0;
	border-radius: 999px;
	cursor: pointer;
	background: color-mix(in srgb, var(--ink) 8%, var(--ground));
	color: var(--ink);
	font-size: 1.1rem;
	transition: background-color .2s ease-out, opacity .2s ease-out;
}

.carousel__btn:hover { background: color-mix(in srgb, var(--accent) 30%, var(--ground)); }
.carousel__btn:disabled { opacity: .35; cursor: default; }

.dots { display: flex; gap: 7px; margin-left: auto; }

.dot {
	width: 7px; height: 7px; padding: 0; border: 0; border-radius: 999px; cursor: pointer;
	background: color-mix(in srgb, var(--ink) 22%, transparent);
	transition: width .25s ease-out, background-color .25s ease-out;
}

.dot.is-on { width: 22px; background: var(--accent); }

/* ── slideshow ────────────────────────────────────────────────────────────── */
.slideshow { position: relative; overflow: hidden; }

.slideshow [data-frame] {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 1.4s ease-in-out;
}

.slideshow [data-frame].is-on { opacity: 1; }

.slideshow [data-frame] img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The slow push that makes a still photograph read as footage. */
.slideshow [data-frame].is-on img { animation: kenburns 9s ease-out both; }

@keyframes kenburns {
	from { transform: scale(1.01) translate3d(0, 0, 0); }
	to { transform: scale(1.12) translate3d(-1.5%, -1%, 0); }
}

/* ── before / after ───────────────────────────────────────────────────────── */
.compare { position: relative; overflow: hidden; border-radius: var(--radius); touch-action: none; }
.compare img { display: block; width: 100%; }
.compare__after { position: absolute; inset: 0; width: var(--split, 50%); overflow: hidden; }
.compare__after img { width: auto; height: 100%; max-width: none; }

.compare__handle {
	position: absolute;
	top: 0; bottom: 0;
	left: var(--split, 50%);
	width: 2px;
	background: #fff;
	box-shadow: 0 0 14px rgba(0,0,0,.4);
	pointer-events: none;
}

.compare__handle::after {
	content: '';
	position: absolute;
	top: 50%; left: 50%;
	width: 42px; height: 42px;
	transform: translate(-50%, -50%);
	border-radius: 999px;
	background: #fff;
	box-shadow: 0 4px 16px rgba(0,0,0,.35);
}

.compare input[type=range] { position: absolute; inset: auto 0 10px; width: 100%; opacity: 0; height: 44px; }
.compare__label {
	position: absolute; bottom: 12px;
	padding: 5px 12px; border-radius: 999px;
	background: color-mix(in srgb, #000 55%, transparent);
	color: #fff; font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
}
.compare__label--a { left: 12px; }
.compare__label--b { right: 12px; }

/* ── lightbox ─────────────────────────────────────────────────────────────── */
.lightbox {
	position: fixed; inset: 0; z-index: 200;
	display: none; place-items: center;
	padding: 4vmin;
	background: color-mix(in srgb, #000 88%, transparent);
	backdrop-filter: blur(6px);
}

.lightbox.is-open { display: grid; animation: fade .25s ease-out both; }
.lightbox img { max-width: 100%; max-height: 92vh; border-radius: 4px; }

.lightbox__close {
	position: absolute; top: 18px; right: 22px;
	width: 44px; height: 44px;
	border: 0; border-radius: 999px; cursor: pointer;
	background: rgba(255,255,255,.14); color: #fff; font-size: 1.6rem; line-height: 1;
}

@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

/* ── stat row (works with data-count) ─────────────────────────────────────── */
.stats { display: grid; gap: clamp(18px,3vw,40px); grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); }
.stat__n { font-family: var(--display); font-size: clamp(2.4rem,5vw,4rem); line-height: 1; }
.stat__n sup { font-size: .4em; vertical-align: super; color: var(--accent); }
.stat__label { margin: 8px 0 0; font-size: .82rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft); }

/* ── sticky split: one pane holds while the other scrolls ─────────────────── */
@media (min-width: 950px) {
	.sticky-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(30px,4vw,70px); align-items: start; }
	.sticky-split__pin { position: sticky; top: calc(var(--bar) + 28px); }
}

@media (prefers-reduced-motion: reduce) {
	.slideshow [data-frame] { transition: none; }
	.slideshow [data-frame].is-on img { animation: none; }
}

/* ── form fields ─────────────────────────────────────────────────────────────
   Used by booking-dates, appointment and reservation. These MUST live here and not in one of those
   blocks: the renderer only includes the stylesheets of blocks a page uses, so a page with the
   appointment block and no booking-dates block was getting unstyled browser controls. */
.b-field { display: grid; gap: 6px; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.b-field--wide { grid-column: 1/-1; }
.b-field input, .b-field select, .b-field textarea { font: inherit; font-size: .98rem; letter-spacing: 0; text-transform: none;
	color: var(--ink); padding: 12px 14px; border: 1px solid var(--line); border-radius: calc(var(--radius) - 4px);
	background: var(--ground); width: 100%; box-sizing: border-box;
	/* The line-height puts every control's text on the same baseline. The HEIGHT — not a min-height —
	   is what keeps them identical: a date input's native calendar button sets a taller content box than
	   a select's, so a minimum let the date fields stand 2px proud of the rest of the form. */
	line-height: 1.4; height: 48px; }
.b-field textarea { height: auto; min-height: 96px; }
.b-field input:focus, .b-field select:focus, .b-field textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.b-book__submit { grid-column: 1/-1; justify-content: center; }
.b-book__hint { grid-column: 1/-1; margin: 0; font-size: .82rem; color: var(--ink-soft); }

/* ── custom form controls ────────────────────────────────────────────────────
   handoff.js upgrades the date input and the selects of these forms in place. The native control stays
   in the form behind the custom one, invisible but still submitted. Only tokens here, never a literal
   colour, so every palette gets the same controls, light or dark. */
.b-pick { position: relative; }
.b-pick .b-native { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; }

/* the button that shows the value: the same box as .b-field input */
.b-pick__btn { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; height: 48px; box-sizing: border-box; padding: 0 14px;
	font: inherit; font-size: .98rem; line-height: 1.4; letter-spacing: 0; text-transform: none; text-align: left; color: var(--ink);
	background: var(--ground); border: 1px solid var(--line); border-radius: calc(var(--radius) - 4px); cursor: pointer;
	transition: border-color .15s ease, box-shadow .15s ease; }
.b-pick__btn:hover { border-color: color-mix(in srgb, var(--ink) 38%, transparent); }
.b-pick__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.b-pick__btn[aria-expanded="true"] { border-color: var(--accent); }
.b-pick__btn.is-invalid { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 24%, transparent); }
.b-pick__val { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b-pick__val.is-empty { color: var(--ink-soft); }
.b-pick__ico { flex: none; width: 18px; height: 18px; color: var(--ink-soft); transition: transform .18s ease; }
.b-pick__btn[aria-expanded="true"] .is-chev { transform: rotate(180deg); }

/* the popup, shared by the calendar and the listbox */
.b-pop { position: absolute; left: 0; top: calc(100% + 6px); z-index: 40; box-sizing: border-box; min-width: 100%;
	scroll-margin-bottom: 96px; /* clear of the fixed preview bar when scrolled into view */
	font-size: .98rem; letter-spacing: 0; text-transform: none; color: var(--ink); background: var(--ground);
	border: 1px solid var(--line); border-radius: var(--radius);
	box-shadow: 0 24px 48px -20px color-mix(in srgb, var(--ink) 50%, transparent); animation: b-pop-in .16s ease-out; }
.b-pop[hidden] { display: none; }
.b-pop.is-right { left: auto; right: 0; }
/* a look that stacks its sections would otherwise paint the next one over an open popup */
.is-popping { position: relative; z-index: 45 !important; }
@keyframes b-pop-in { from { opacity: 0; transform: translateY(-4px); } }

/* calendar */
.b-cal { width: 316px; padding: 14px; }
.b-cal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.b-cal__title { font-family: var(--display); font-weight: var(--display-weight); font-size: 1.06rem; }
.b-cal__nav { display: grid; place-items: center; width: 38px; height: 38px; padding: 0; border: 0; border-radius: 999px; background: transparent; color: var(--ink); cursor: pointer; }
.b-cal__nav:hover:not(:disabled) { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.b-cal__nav:disabled { opacity: .3; cursor: default; }
.b-cal__nav:focus-visible, .b-cal__day:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.b-cal__grid { width: 100%; border-collapse: collapse; table-layout: fixed; }
.b-cal__grid th { padding: 6px 0; font-size: .7rem; font-weight: 500; color: var(--ink-soft); text-align: center; }
.b-cal__grid td { padding: 1px; text-align: center; }
.b-cal__day { position: relative; width: 38px; height: 38px; padding: 0; border: 0; border-radius: 999px; background: transparent; color: var(--ink);
	font: inherit; font-size: .92rem; cursor: pointer; }
.b-cal__day:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.b-cal__day.is-range { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.b-cal__day.is-today { box-shadow: inset 0 0 0 1px var(--accent); }
.b-cal__day.is-sel, .b-cal__day.is-sel:hover { background: var(--accent); color: var(--on-accent); }
.b-cal__day[aria-disabled="true"], .b-cal__day[aria-disabled="true"]:hover { background: transparent; color: color-mix(in srgb, var(--ink) 28%, transparent); cursor: not-allowed; box-shadow: none; }

/* time slots */
.b-chips { display: grid; grid-template-columns: repeat(auto-fill, minmax(68px, 1fr)); gap: 8px; }
.b-chip { min-width: 0; height: 42px; padding: 0 8px; font: inherit; font-size: .94rem; letter-spacing: 0; text-transform: none; color: var(--ink);
	background: var(--ground); border: 1px solid var(--line); border-radius: calc(var(--radius) - 4px); cursor: pointer;
	transition: background-color .15s ease, border-color .15s ease, color .15s ease; }
.b-chip:hover { border-color: color-mix(in srgb, var(--ink) 38%, transparent); }
.b-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.b-chip[aria-checked="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* stepper */
.b-step { display: flex; align-items: center; height: 48px; overflow: hidden; background: var(--ground); border: 1px solid var(--line); border-radius: calc(var(--radius) - 4px); }
.b-step__btn { flex: none; width: 48px; height: 100%; padding: 0; border: 0; background: transparent; color: var(--ink); font: inherit; font-size: 1.3rem; line-height: 1; cursor: pointer; }
.b-step__btn:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.b-step__btn:disabled { color: color-mix(in srgb, var(--ink) 28%, transparent); cursor: default; }
.b-step__val { flex: 1; text-align: center; font-size: .98rem; letter-spacing: 0; text-transform: none; color: var(--ink); line-height: 46px; }
.b-step__val:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: 4px; }

/* listbox */
.b-list { margin: 0; padding: 6px; list-style: none; max-height: 280px; overflow-y: auto; }
.b-list li { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 11px 12px; border-radius: calc(var(--radius) - 6px); cursor: pointer; }
.b-list li.is-active { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.b-list li[aria-selected="true"] { font-weight: 600; }
.b-list li[aria-selected="true"]::after { content: ''; flex: none; width: 6px; height: 11px; margin-right: 4px; border: solid var(--accent); border-width: 0 2px 2px 0; transform: rotate(45deg) translateY(-2px); }

/* on a phone the popup is a bottom sheet over a scrim (handoff.js moves it to <body>) */
.b-scrim { position: fixed; inset: 0; z-index: 155; background: color-mix(in srgb, var(--ink) 42%, transparent); }
@media (min-width: 561px) { .b-scrim { display: none; } }
@media (max-width: 560px) {
	.b-pop, .b-pop.is-right { position: fixed; inset: auto 0 0 0; z-index: 160; width: auto; min-width: 0; max-height: 82vh; overflow-y: auto; overscroll-behavior: contain;
		border-width: 1px 0 0; border-radius: 20px 20px 0 0; padding-bottom: calc(18px + env(safe-area-inset-bottom));
		box-shadow: 0 -24px 60px -24px color-mix(in srgb, var(--ink) 55%, transparent); animation: b-sheet-in .22s ease-out; }
	.b-cal { padding: 18px 14px; }
	.b-cal__day { width: 100%; height: 46px; border-radius: 12px; }
	.b-list { padding: 10px 10px calc(18px + env(safe-area-inset-bottom)); max-height: 60vh; }
	.b-list li { padding: 15px 14px; }
}
@keyframes b-sheet-in { from { transform: translateY(24px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .b-pop { animation: none; } .b-pick__ico { transition: none; } }

/* ── pointer + scroll effects ────────────────────────────────────────────────
   The CSS half of components.js. Everything here is inert until the script adds the element or the
   class, so a page with JavaScript off loses the effect and keeps the content. */

/* Anything a script appends to <body> that must never join the page flow. A look that restyles direct
   children of body has to leave these alone — one of them did not, and the cursor ended up in the
   document, 470px tall, below the footer. */
.is-overlay { position: fixed; }

/* A hairline of progress along the top of the page. --scroll-progress is written by motion.js. */
.scroll-progress { position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 60; transform-origin: 0 50%;
	transform: scaleX(var(--scroll-progress, 0)); background: var(--accent); pointer-events: none; }

/* The cursor. The dot is exact, the ring lags — and both are centred on the pointer, which is why
   they are translated to the raw coordinates and then pulled back by half their own size. */
.cursor-dot, .cursor-ring { position: fixed; top: 0; left: 0; z-index: 90; border-radius: 999px;
	pointer-events: none; will-change: transform; }
.cursor-dot { width: 6px; height: 6px; margin: -3px 0 0 -3px; background: var(--accent); }
.cursor-ring { width: 34px; height: 34px; margin: -17px 0 0 -17px; border: 1px solid color-mix(in srgb,var(--ink) 40%,transparent);
	transition: width .22s ease, height .22s ease, margin .22s ease, border-color .22s ease, background-color .22s ease; }
.cursor-ring.is-over { width: 58px; height: 58px; margin: -29px 0 0 -29px;
	border-color: color-mix(in srgb,var(--accent) 70%,transparent); background: color-mix(in srgb,var(--accent) 12%,transparent); }
@media (hover: none), (pointer: coarse) { .cursor-dot, .cursor-ring { display: none; } }

/* A button that leans toward the pointer needs to spring back, not snap — but only the opted-in ones
   move at all, so only they get a transform transition. Every button keeps the colour transitions. */
.btn { transition: background-color .2s ease, color .2s ease, box-shadow .2s ease; }
.btn[data-magnetic] { transition: transform .45s cubic-bezier(.2,.8,.2,1), background-color .2s ease, color .2s ease, box-shadow .2s ease; }

/* A photograph that wipes into place the first time it is seen.
   The clip goes on the IMAGE, never on the element being observed: clipping the observed element to
   zero width makes its intersection ratio zero, so the observer that would reveal it never fires and
   the photograph stays invisible forever. */
[data-mask] > img,
[data-mask] > picture > img { clip-path: inset(0 100% 0 0); transition: clip-path 1.1s cubic-bezier(.2,.75,.2,1); }
[data-mask].is-revealed > img,
[data-mask].is-revealed > picture > img { clip-path: inset(0 0 0 0); }
.motion-off [data-mask] > img { clip-path: none; transition: none; }


/* ── reveal on scroll ────────────────────────────────────────────────────────
   The CSS half of motion.js's reveals, which the block system never had.
   motion.js has been adding `is-in` to elements that nothing styled, so nothing faded, nothing rose
   and nothing staggered — the whole motion layer was inert. Worse, `.line` was left unstyled too, so
   the spans a headline is split into ran together inline: "Gel, extensions" + "and nail art" rendered
   as "extensionsand". Both rules lived only in the old per-family stylesheets, which the block system
   does not load.

   Everything here is guarded by `.motion-on`, which motion.js sets only when the visitor has not asked
   for reduced motion — so with the class absent, or with JavaScript off, content renders in its final
   state and nothing is ever stuck invisible. */
.motion-on [data-reveal] {
	opacity: 0;
	transform: translateY(16px);
	transition:
		opacity 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) var(--d, 0ms),
		transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) var(--d, 0ms);
}
.motion-on [data-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* A headline split for the line-by-line rise. The block display is what puts each line on its own
   line; the overflow is what the line rises out from behind. */
.line {
	display: block;
	overflow: hidden;
}
.line > span {
	display: block;
}
.motion-on [data-reveal-lines] .line > span {
	transform: translateY(106%);
	transition: transform 1s cubic-bezier(0.16, 0.84, 0.28, 1) var(--line-d, 0ms);
}
.motion-on [data-reveal-lines].is-in .line > span {
	transform: none;
}


/* ── block: product-masonry ── */
/* product-masonry: tokens only (--ink, --ground, --accent, --on-accent, --line, --ink-soft, --radius), so it
   works on a light or a dark palette. The tile positions come from the script in block.html; this is also
   the whole layout when there is no script (plain columns). */
/* Keep what takes focus, or an in-page link's target, clear of the sticky header and filter bar. */
html:has(.b-wall) { scroll-padding-top: calc(var(--bar, 72px) + 128px); }
.b-wall { --ctl: 38px; --gutter: clamp(20px, 5vw, 64px); --line-ctl: color-mix(in srgb, var(--ink) 32%, transparent); padding-block: clamp(14px, 2vw, 24px) clamp(28px, 4vw, 56px); }

.b-wall__intro { display: flex; align-items: center; justify-content: space-between; gap: 6px 40px; flex-wrap: wrap; padding-bottom: clamp(10px, 1.4vw, 16px); }
/* looks load after blocks and also style h1 and .b-kicker, so these selectors are deliberately one step more specific */
.b-wall .b-wall__intro h1 { font-size: clamp(1.6rem, 2.9vw, 2.3rem); line-height: 1.05; margin: 0; }
.b-wall__aside { flex: 0 1 440px; max-width: 440px; } /* a fixed measure that always fits beside the heading from 900px up */
.b-wall .b-wall__aside p { max-width: none; } /* foundation caps <p> at 62ch: that left the right-aligned kicker 100px short of the container edge */
.b-wall__proof { display: flex; align-items: center; gap: 6px; margin: 0 0 4px; font-size: .8125rem; line-height: 1.3; color: var(--ink-soft); }
.b-wall__proof svg { flex: none; color: var(--accent); }
.b-wall__proof b { font-weight: 600; color: var(--ink); }
.b-wall__lead { margin: 0; font-size: .84rem; line-height: 1.4; text-wrap: balance; }
@media (min-width: 900px) { .b-wall__aside { text-align: right; } .b-wall__proof { justify-content: flex-end; } }

/* ── the filter bar: sticks under the header while the wall scrolls ── */
.b-wall__bar {
	position: sticky; top: var(--bar, 72px); z-index: 20;
	background: color-mix(in srgb, var(--ground) 94%, transparent);
	backdrop-filter: blur(12px);
	border-block: 1px solid var(--line);
}
.b-wall__bar-in { display: grid; gap: 8px; padding-block: 10px; }
.b-wall__row { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; min-width: 0; }

.b-chips { display: flex; gap: 8px; min-width: 0; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding-block: 3px; margin-block: -3px; }
.b-chips::-webkit-scrollbar { display: none; }
.b-chips { --fade-l: 0px; --fade-r: 0px;
	-webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
	mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%); }
.b-chips.has-more { --fade-r: 40px; }
.b-chips.has-less { --fade-l: 28px; }
.b-chip {
	appearance: none; flex: none; cursor: pointer; white-space: nowrap;
	display: inline-flex; align-items: center; box-sizing: border-box; height: var(--ctl);
	font: inherit; font-size: .875rem; line-height: 1; color: var(--ink);
	padding: 0 14px; border-radius: 999px; border: 1px solid var(--line-ctl); background: transparent;
	transition: background-color .18s, border-color .18s, color .18s;
}
.b-chip span { margin-left: 5px; opacity: .55; font-variant-numeric: tabular-nums; }
.b-chip:hover { border-color: var(--ink); }
.b-chip.is-on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.b-chip.is-on span { opacity: .7; }
.b-chips--small .b-chip { padding: 0 12px; }

.b-search { position: relative; flex: 0 1 260px; min-width: 150px; color: var(--ink-soft); }
.b-search svg { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); pointer-events: none; }
.b-search input {
	width: 100%; height: var(--ctl); box-sizing: border-box; padding: 0 14px 0 38px;
	font: inherit; font-size: .875rem; color: var(--ink);
	background: transparent; border: 1px solid var(--line-ctl); border-radius: 999px;
}
.b-search input::placeholder { color: var(--ink-soft); opacity: .8; }
.b-search input:hover { border-color: var(--ink); }
.b-search input::-webkit-search-cancel-button { filter: grayscale(1); }

.b-sort { display: inline-flex; position: relative; }
.b-sort__toggle { display: none; }
.b-seg { display: inline-flex; align-items: center; flex: none; box-sizing: border-box; height: var(--ctl); padding: 3px; border: 1px solid var(--line-ctl); border-radius: 999px; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.b-seg::-webkit-scrollbar { display: none; }
.b-seg button {
	appearance: none; cursor: pointer; white-space: nowrap; border: 0; background: transparent;
	font: inherit; font-size: .875rem; line-height: 1; color: var(--ink-soft); height: 100%; padding: 0 13px; border-radius: 999px;
	transition: background-color .18s, color .18s;
}
.b-seg button:hover { color: var(--ink); }
.b-seg button.is-on { background: var(--ink); color: var(--ground); }
.b-wall__tail { display: inline-flex; align-items: center; gap: 14px; margin-left: auto; }
.b-wall__count { margin: 0; font-size: .82rem; color: var(--ink-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }
.b-wall__clear { appearance: none; cursor: pointer; background: none; border: 0; padding: 6px 2px; font: inherit; font-size: .8125rem; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.b-wall__clear:hover { color: var(--accent); }
.b-wall__clear[hidden] { display: none; }
.b-wall__clear--inline { display: inline; padding: 0; font-size: inherit; }

.b-chip:focus-visible, .b-seg button:focus-visible, .b-search input:focus-visible, .b-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── the wall ── */
.b-wall__grid { columns: 2 150px; column-gap: 10px; margin-top: clamp(12px, 1.6vw, 18px); }
@media (min-width: 640px) { .b-wall__grid { columns: 3 200px; column-gap: 18px; } }
@media (min-width: 1000px) { .b-wall__grid { columns: 5 196px; } .is-wide .b-wall__grid { columns: 10 196px; } }
.b-wall__grid.is-wall { columns: auto; position: relative; }

.b-tile {
	--pad: 14px;
	position: relative; display: block; box-sizing: border-box; break-inside: avoid; margin: 0 0 10px;
	color: var(--ink); text-decoration: none;
	background: color-mix(in srgb, var(--ink) 5%, var(--ground));
	border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
	transition: transform .55s cubic-bezier(.2, .7, .2, 1), border-color .2s, box-shadow .25s;
}
.is-wall .b-tile { position: absolute; left: 0; top: 0; margin: 0; will-change: transform; }
.b-tile[hidden] { display: none; }
.b-tile:hover, .b-tile:focus-visible { border-color: var(--accent); box-shadow: 0 22px 44px -26px color-mix(in srgb, var(--accent) 75%, transparent); }

.b-tile__media { display: block; aspect-ratio: var(--r, 1 / 1); overflow: hidden; background: var(--bg, #111); }
.b-tile__media img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .7s cubic-bezier(.2, .7, .2, 1); }
.b-tile:hover .b-tile__media img { transform: scale(1.05); }

.b-tile__badge {
	position: absolute; top: 12px; left: var(--pad); z-index: 2; padding: 6px 10px; border-radius: 999px;
	background: var(--accent); color: var(--on-accent);
	font-size: .7rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; line-height: 1;
}
.b-tile__badge--best { background: var(--ink); color: var(--ground); }
.b-tile__go {
	position: absolute; top: 12px; right: var(--pad); z-index: 2; width: 32px; height: 32px; display: grid; place-items: center;
	border-radius: 50%; background: var(--ink); color: var(--ground);
	opacity: 0; transform: scale(.8); transition: opacity .2s, transform .25s;
}
.b-tile:hover .b-tile__go, .b-tile:focus-visible .b-tile__go { opacity: 1; transform: none; }
@media (hover: none) { .b-tile__go { opacity: .92; transform: none; width: 28px; height: 28px; } }

.b-tile__body { display: grid; gap: 2px; padding: 12px var(--pad) 14px; }
.b-tile__name { font-family: var(--display); font-weight: var(--display-weight, 600); font-size: 1.02rem; line-height: 1.2; letter-spacing: -.01em; }
.b-tile__type { font-size: .78rem; line-height: 1.3; color: var(--ink-soft); }
.b-tile__foot { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-top: 8px; }
.b-tile__price { font-size: 1rem; font-variant-numeric: tabular-nums; }
.b-tile__meta { font-size: .74rem; color: var(--ink-soft); white-space: nowrap; }

.b-tile--brand { aspect-ratio: var(--r, 4 / 5); background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.b-tile--brand:hover, .b-tile--brand:focus-visible { box-shadow: 0 22px 44px -26px color-mix(in srgb, var(--accent) 75%, transparent); }
.b-brandtile { display: flex; flex-direction: column; justify-content: space-between; gap: 16px; box-sizing: border-box; height: 100%; padding: calc(var(--pad) + 4px) var(--pad) var(--pad); }
.b-brandtile__title { font-family: var(--display); font-weight: 700; font-size: clamp(1.9rem, 2.7vw, 2.6rem); line-height: .96; letter-spacing: -.025em; text-wrap: balance; }
.b-brandtile__go { display: inline-flex; align-items: center; gap: 6px; font-size: .8125rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.b-wall__empty { max-width: none; margin: 48px 0; text-align: center; color: var(--ink-soft); }
.b-wall__more { max-width: none; margin: clamp(24px, 3vw, 40px) 0 0; text-align: center; }

/* ── phones: products first. The bar is two slim rows (categories, then search and sort), follows the reader
   up the page and steps out of the way going down; chip rows bleed to the screen edge and fade where they scroll;
   controls are 44px; the sort options open as a list. ── */
@media (max-width: 640px) {
	.b-wall { --ctl: 44px; }
	.b-wall .b-wall__intro h1 { font-size: 1.5rem; }
	.b-wall__lead { display: none; }
	.b-wall__bar { top: var(--bar, 60px); transition: transform .3s cubic-bezier(.2, .7, .2, 1); }
	.b-wall__bar.is-away { transform: translateY(-100%); }
	.b-wall__bar-in { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; padding-block: 8px; }
	.b-wall__row, .b-wall__row--sub { display: contents; }
	.b-chips { grid-column: 1 / -1; margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); }
	.b-search { grid-column: 1; min-width: 0; flex: none; }
	.b-sort { grid-column: 2; }
	.b-sort__toggle {
		appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; box-sizing: border-box; height: var(--ctl);
		padding: 0 14px; font: inherit; font-size: .875rem; line-height: 1; color: var(--ink);
		background: transparent; border: 1px solid var(--line-ctl); border-radius: 999px; white-space: nowrap;
	}
	.b-sort__toggle b { font-weight: 600; }
	.b-sort.is-open .b-sort__toggle { border-color: var(--ink); }
	.b-seg {
		display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; flex-direction: column; align-items: stretch;
		height: auto; min-width: 220px; padding: 6px; background: var(--ground); border-radius: 22px;
		box-shadow: 0 18px 40px -12px color-mix(in srgb, #000 70%, transparent);
	}
	.b-sort.is-open .b-seg { display: flex; }
	.b-seg button { height: 44px; padding: 0 16px; text-align: left; font-size: .9375rem; }
	.b-wall__tail { display: none; }
	.b-tile { --pad: 11px; }
	.b-tile__body { padding: 10px var(--pad) 12px; }
	.b-tile__name { font-size: .94rem; }
	.b-tile__meta { display: none; }
}

@media (prefers-reduced-motion: reduce) {
	.b-tile, .b-tile__media img, .b-tile__go, .b-chip, .b-seg button { transition: none; }
}


/* ── block: facts-strip ── */
/* A strip, not a section — see --section-tight. */
.b-facts { padding-block: var(--section-tight); }
.b-facts__grid { display: grid; gap: clamp(14px,2vw,24px); grid-template-columns: repeat(auto-fit,minmax(200px,1fr)); }
.b-fact { padding: 20px 22px; border-radius: var(--radius); background: color-mix(in srgb,var(--accent) 8%,var(--ground)); }
.b-fact__label { margin: 0 0 6px; font-size: .7rem; letter-spacing: .16em; text-transform: uppercase; color: var(--accent-ink); }
.b-fact__value { margin: 0; font-size: .97rem; }


/* ── block: story-split ── */
.b-story__in { display: grid; gap: clamp(30px,4.5vw,72px); align-items: center; }
@media (min-width: 900px) { .b-story__in:not(.sticky-split) { grid-template-columns: 1fr 1fr; } .b-story__in.sticky-split { align-items: start; } }
.b-story__figure { margin: 0; overflow: hidden; border-radius: var(--radius); }
.b-story__figure img { width: 100%; aspect-ratio: 4/5; object-fit: cover; }
.b-story__figure figcaption { margin-top: 10px; font-size: .82rem; color: var(--ink-soft); }
.b-pull { margin: 28px 0 0; padding: 18px 0 18px 26px; border-left: 3px solid color-mix(in srgb,var(--accent) 55%,transparent); font-family: var(--display); font-size: clamp(1.1rem,1.7vw,1.5rem); line-height: 1.3; }
.b-pull cite { display: block; margin-top: 10px; font-family: var(--body); font-size: .8rem; font-style: normal; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.b-link { display: inline-block; margin-top: 20px; font-weight: 500; text-decoration: none; border-bottom: 2px solid var(--accent); padding-bottom: 2px; }
.b-link:hover { opacity: .72; }
/* No photograph for this block: the media column is not rendered at all (see block.html), so the copy
   is the only child and must span both columns — otherwise it sits in the left 1fr with an empty half
   beside it, which is worse than the empty <img> this replaced. */
@media (min-width: 900px) {
  .b-story__in > .b-story__copy:only-child { grid-column: 1 / -1; }
}


/* ── block: cta-band ── */
.b-cta { text-align: center; padding-block: var(--section-tight); }
.b-cta__in p { margin-inline: auto; }
.b-cta .b-actions { justify-content: center; margin-top: 26px; }
.b-cta--photo { position: relative; overflow: hidden; color: #fff; }
/* The scrim is a pseudo-element on the section, but the photo is a real child that comes after it in
   the DOM — and it carries a parallax transform, so it was painting straight over the scrim and the
   headline was white-on-gold. The three layers now say explicitly which is on top. */
.b-cta--photo::before { content: ''; position: absolute; inset: 0; z-index: 1; background:
	linear-gradient(to bottom, rgba(8,9,12,.74), rgba(8,9,12,.58) 45%, rgba(8,9,12,.78)); }
.b-cta__bg { position: absolute; inset: -12% 0; z-index: 0; }
.b-cta__bg img { width: 100%; height: 100%; object-fit: cover; }
.b-cta--photo .b-cta__in { position: relative; z-index: 2; }
.b-cta--photo { padding-block: clamp(56px,7vw,104px); }
.b-cta--photo h2 { color: #fff; }
.b-cta--photo p { color: color-mix(in srgb,#fff 82%,transparent); }
.b-cta--photo .btn--ghost { color: #fff; background: rgba(255,255,255,.1); backdrop-filter: blur(3px);
	box-shadow: inset 0 0 0 1px color-mix(in srgb,#fff 55%,transparent); }
.b-cta__in p { max-width: 54ch; }


/* ── block: map-visit ── */
.b-visit__in { display: grid; gap: clamp(28px,4vw,60px); align-items: start; }
@media (min-width: 900px) { .b-visit__in { grid-template-columns: 1.05fr .95fr; } }
/* when this block opens a page its heading is the h1, drawn at the same size as the h2 it replaces (looks size h1 larger) */
.b-visit .b-visit__in h1 { font-size: clamp(2rem, 4.2vw, 3.4rem); }
.b-visit__hours-head { margin-bottom: 14px; }
.b-visit__map { margin-top: clamp(24px,3.4vw,44px); }

/* the multi-store map: Leaflet + OpenStreetMap, loaded when it scrolls into view (see block.html) */
.b-map { position: relative; height: clamp(320px, 44vw, 480px); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: color-mix(in srgb, var(--ink) 6%, var(--ground)); }
.b-map__canvas { position: absolute; inset: 0; }
.b-map__note { position: absolute; inset: 0; display: grid; place-items: center; margin: 0; padding: 24px; max-width: none; text-align: center; font-size: .9rem; color: var(--ink-soft); }
.b-map.is-ready .b-map__note { display: none; }
.b-map .leaflet-container { font: inherit; background: transparent; }
.b-map.is-dark .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(.9) contrast(.9) saturate(.75); }
.b-pin { background: none; border: 0; }
.b-pin svg { display: block; width: 34px; height: 42px; filter: drop-shadow(0 6px 6px color-mix(in srgb, #000 45%, transparent)); }
.b-map .leaflet-popup-content-wrapper { background: var(--ground); color: var(--ink); border: 1px solid var(--line-ctl, var(--line)); border-radius: calc(var(--radius) - 4px); box-shadow: 0 14px 30px -10px color-mix(in srgb, #000 60%, transparent); }
.b-map .leaflet-popup-tip { background: var(--ground); }
.b-map .leaflet-popup-content { margin: 14px 18px; font-size: .9rem; line-height: 1.45; }
.b-map .leaflet-popup-content strong { display: block; margin-bottom: 2px; font-family: var(--display); font-size: 1.05rem; }
.b-map .leaflet-popup-content a { display: inline-block; margin-top: 8px; color: var(--accent-ink, var(--accent)); text-underline-offset: 3px; }
.b-map .leaflet-popup-close-button { color: var(--ink-soft); }
.b-map .leaflet-bar a { background: var(--ground); color: var(--ink); border-color: var(--line); }
.b-map .leaflet-bar a:hover { background: color-mix(in srgb, var(--ink) 10%, var(--ground)); }
.b-map .leaflet-container .leaflet-control-attribution { background: color-mix(in srgb, var(--ground) 82%, transparent); color: var(--ink-soft); font-size: .7rem; }
.b-map .leaflet-control-attribution a { color: var(--ink); }
.b-visit .btn { margin-top: 20px; }

/* several stores (content.locations): one row each, name and address on the left, directions on the right */
.b-visit__store { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 12px 20px; padding-block: 20px; border-top: 1px solid var(--line); }
.b-visit__store:last-child { border-bottom: 1px solid var(--line); }
.b-visit .b-visit__store h2 { font-size: 1.25rem; line-height: 1.15; margin: 0 0 6px; }
.b-visit__store p { margin: 0; max-width: none; font-size: .95rem; line-height: 1.5; }
.b-visit__store .btn { margin-top: 0; padding: 12px 18px; white-space: nowrap; }
@media (max-width: 480px) { .b-visit__store { grid-template-columns: 1fr; } }


/* ── look: minimal ── */
/* MINIMAL — near-monochrome, enormous space, slow. The restraint is the product. */
.look-minimal { --radius: 2px; --section: clamp(80px,11vw,190px); }
.look-minimal .b-kicker { display: block; margin: 0 0 24px; font-size: .68rem; letter-spacing: .28em; text-transform: uppercase; color: var(--accent-ink); }
.look-minimal h1 { font-size: clamp(2.6rem,5.4vw,4.6rem); line-height: 1.06; }
.look-minimal h1 em, .look-minimal h2 em { font-style: italic; color: inherit; }
.look-minimal .btn { border-radius: 0; font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; padding: 16px 30px; }
.look-minimal .brand { font-size: .95rem; letter-spacing: .2em; text-transform: uppercase; }
.look-minimal .nav a { font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; }
/* A look that draws a box around something owes it padding. This rule turned five things into bordered
   boxes and gave none of them any, so on the services list the group heading sat on the border. The
   forms bring their own padding from their blocks; the rest did not, because in the other looks they
   are not boxes at all. */
.look-minimal .b-card, .look-minimal .b-fact, .look-minimal .b-priced__group, .look-minimal .b-book__form, .look-minimal .b-appt__form, .look-minimal .b-resv__form { background: transparent; box-shadow: inset 0 0 0 1px var(--line); border-radius: 0; }
.look-minimal .b-priced__group { padding: clamp(20px, 2.2vw, 30px) clamp(20px, 2.2vw, 28px) clamp(10px, 1.4vw, 16px); }
.look-minimal .b-fact { padding: clamp(18px, 2vw, 26px) clamp(18px, 2vw, 24px); }
/* .b-card carries a media image to its edges and pads its own body, so it is left alone. */
.look-minimal .b-card__price { background: transparent; color: var(--accent); }
.look-minimal .b-card__media img { aspect-ratio: 1; }
.look-minimal .motion-on [data-reveal] { transition-duration: 1.1s; }
.look-minimal .b-marquee { background: transparent; color: var(--ink-soft); border-block: 1px solid var(--line); }
.look-minimal .b-shot img { aspect-ratio: 4/5; }


/* ── this site ── */
:root{--ink:#f2f3ed;--ground:#13150c;--accent:#d4ff1f;--on-accent:#13150c;--accent-ink:color-mix(in srgb,var(--accent) 55%,var(--ink));--display:'Bricolage Grotesque',Georgia,serif;--body:'Inter',system-ui,sans-serif;--display-weight:600;--display-tracking:-0.03em}

/* ── dark site ── */
/*
 * Appended ONLY for a dark site: a brand palette built with dark: true (brand-colours.ts). Every other
 * palette is a light page, and the templates write their dark bands as `background: var(--ink); color:
 * var(--ground)`, with the text inside them written relative to --ground too. On a black site, where
 * --ink is the light colour, that flips the footer and the marquee to white bands.
 *
 * Giving those surfaces their own --ink and --ground puts the two tokens back to the meaning every
 * rule inside them already assumes (--ink: the band's background, --ground: the text on it), so none
 * of those rules needs to change. A new band surface goes in this selector list.
 */
:root {
	color-scheme: dark; /* form controls, scrollbars and the autofill tint follow the page */
	--on-band: var(--ink);
	--band: color-mix(in srgb, var(--ink) 11%, var(--ground)); /* a lifted black: visible against the page */
}

.section--ink,
.site-foot,
.b-marquee,
.b-card__price {
	--ink: var(--band);
	--ground: var(--on-band);
}
