/* =====================================================================
   Schreiber Foods International — main stylesheet
   Montserrat headlines · Arial body · brand palette · ovalesque dividers
   Built to WCAG 2.2 AA (focus, contrast, reduced-motion, reflow).
   ===================================================================== */

:root {
	--red:      #C52435;
	--red-dark: #a81d2b;
	--green:    #4C9B44;
	--beige:    #CEB099;
	--charcoal: #63696D;
	--ink:      #1A1A1A;
	--paper:    #FFFFFF;
	--mist:     #F5F2EE;

	--font-head: 'Montserrat', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
	--font-body: Arial, 'Helvetica Neue', Helvetica, sans-serif;

	--gold:      #E8C87E;   /* warm accent for the dark variant */
	--ink-2:     #121417;   /* near-black panel */
	--footer-bg: #141416;   /* deep neutral footer (no blue cast) */
	--red-deep:  #9d1b28;   /* rich red for the utility/CTA bar */

	/* Concept B (Showcase) — warm, bright neutrals (client: no dark backgrounds) */
	--cream:     #F7F1E8;   /* warm panel / hero side */
	--sand:      #EFE6D8;   /* slightly deeper warm block */
	--linen:     #FBF8F3;   /* near-white warm section */

	--wrap: 1200px;
	--wrap-wide: 1360px;
	--gutter: clamp(1.15rem, 4vw, 2.75rem);
	--radius: 14px;
	--radius-lg: 22px;
	--section-y: clamp(2.5rem, 6vw, 5.5rem);

	--shadow-sm: 0 2px 8px rgba(28,28,28,.06);
	--shadow-md: 0 18px 40px -18px rgba(28,28,28,.28);
	--shadow-lg: 0 40px 80px -30px rgba(28,28,28,.45);

	--ease: cubic-bezier(.22,.61,.36,1);
	--curve-fill: var(--paper);
}

/* ---------- reset-ish ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
	margin: 0;
	font-family: var(--font-body);
	font-size: 1rem;
	line-height: 1.6;
	color: var(--ink);
	background: var(--paper);
}
img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: var(--red); text-underline-offset: 2px; }
a:hover { color: var(--red-dark); }

h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-head);
	font-weight: 700;
	line-height: 1.08;
	letter-spacing: -0.02em;
	color: var(--ink);
	margin: 0 0 .5em;
	text-wrap: balance;
}
h1 { font-size: clamp(2.4rem, 5.2vw, 4.5rem); font-weight: 800; }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.9rem); }
h3 { font-size: clamp(1.3rem, 2vw, 1.6rem); letter-spacing: -0.01em; }

p { margin: 0 0 1rem; }

.wrap { width: min(100% - 2 * var(--gutter), var(--wrap)); margin-inline: auto; }
.wrap--wide { width: min(100% - 2 * var(--gutter), var(--wrap-wide)); }
.prose { max-width: 62ch; }
.prose p { color: color-mix(in srgb, var(--ink) 82%, transparent); }

/* ---------- eyebrow / kicker ---------- */
.eyebrow {
	font-family: var(--font-head);
	font-weight: 700;
	font-size: .78rem;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--red);
	margin: 0 0 1rem;
	display: inline-flex; align-items: center; gap: .6rem;
}
.eyebrow::before {
	content: ""; width: 28px; height: 2px; background: currentColor; display: inline-block;
}
.eyebrow--light { color: var(--gold); }

/* ---------- animated link with arrow ---------- */
.link-arrow {
	font-family: var(--font-head); font-weight: 700; font-size: .95rem;
	text-decoration: none; color: var(--red);
	display: inline-flex; align-items: center; gap: .5rem;
	letter-spacing: .01em;
}
.link-arrow__icon { transition: transform .3s var(--ease); }
.link-arrow:hover { color: var(--red-dark); }
.link-arrow:hover .link-arrow__icon { transform: translateX(6px); }

/* ---------- scroll reveal (only hides when JS is present → no-JS shows all) ---------- */
.sfi-js .reveal { opacity: 0; transform: translateY(26px); transition: opacity .8s var(--ease), transform .8s var(--ease); transition-delay: calc(var(--i, 0) * 90ms); will-change: opacity, transform; }
.sfi-js .reveal.is-visible { opacity: 1; transform: none; }

/* ---------- accessibility ---------- */
.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px; overflow: hidden;
	clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link {
	position: absolute; left: -9999px; top: 0; z-index: 1000;
	background: var(--ink); color: #fff; padding: .75rem 1rem;
}
.skip-link:focus {
	left: 8px; top: 8px; width: auto; height: auto; clip: auto;
	border-radius: 4px; color: #fff;
}
:focus-visible {
	outline: 3px solid var(--green);
	outline-offset: 2px;
}

/* ---------- buttons ---------- */
.btn {
	display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
	font-family: var(--font-head);
	font-weight: 700;
	font-size: .98rem;
	letter-spacing: .01em;
	text-decoration: none;
	padding: .95rem 1.9rem;
	border-radius: 999px;
	border: 2px solid transparent;
	cursor: pointer;
	min-height: 48px;
	line-height: 1.2;
	transition: transform .25s var(--ease), box-shadow .25s var(--ease), background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn--primary { background: var(--red); color: #fff; box-shadow: 0 14px 26px -12px rgba(197,36,53,.7); }
.btn--primary:hover { background: var(--red-dark); color: #fff; box-shadow: 0 20px 34px -12px rgba(197,36,53,.85); }
/* NOT CURRENTLY USED IN ANY TEMPLATE. White on transparent — it only works over
   photography. It was on both "See All …" links until 2026-08-20, where it
   painted white on cream and the button simply vanished; they use --outline
   below now. Keep it for a future CTA over a hero image, but check the band
   colour before reaching for it. */
.btn--ghost { background: rgba(255,255,255,.06); color: #fff; border-color: rgba(255,255,255,.55); backdrop-filter: blur(4px); }
.btn--ghost:hover { background: #fff; color: var(--ink); border-color: #fff; }
/* The ghost above is for photography; this is its light-band counterpart —
   used by the "See All Olives" step at the foot of a product list, which is
   navigation and must not shout as loudly as the red spec-sheet CTA beside it
   (the restraint the client asked for on 2026-08-10 still holds). */
.btn--outline { background: transparent; color: var(--red); border-color: color-mix(in srgb, var(--red) 45%, transparent); }
.btn--outline:hover { background: var(--red); color: #fff; border-color: var(--red); }
.btn--lg { padding: 1.1rem 2.3rem; font-size: 1.05rem; min-height: 56px; }
.btn--small { padding: .4rem 1rem; min-height: 0; }

/* ---------- header / nav ----------
   Menu items flank a LARGE centred red brand mark (client: "the red logo is what
   chefs recognise"). `.site-nav` is display:contents on desktop so the two halves
   become flex children either side of the logo; below the nav breakpoint it
   becomes a real dropdown panel. */
/* Parent-company mark inside the nav row (client, 2026-08-04). It used to live in
   its own cream strip above the nav with the licensing sentence beside it; both
   the strip and the sentence are gone from the header — the full attribution
   still runs in the footer. */
.parent-lockup {
	display: flex; align-items: center; gap: clamp(.5rem, 1.4vw, .9rem);
	text-decoration: none; color: var(--charcoal);
}
/* Auto width off the natural ratio — the global img reset would otherwise squash it. */
.parent-lockup__logo { width: auto; max-width: none; height: clamp(23px, 2.3vw, 30px); object-fit: contain; display: block; flex: 0 0 auto; }
.parent-lockup__text {
	font-size: clamp(.68rem, .85vw, .78rem); line-height: 1.35; letter-spacing: .01em;
}
a.parent-lockup:hover .parent-lockup__text { color: var(--red); text-decoration: underline; text-underline-offset: 2px; }

/* Sized up ~1.5x on 2026-08-05 at the client's request. It cannot match the
   Ambrosia mark's HEIGHT — the SFI lockup is 4:1, so 68px tall would be 272px
   wide and there is no bar that holds that plus six labels plus a centred mark.
   Matched toward its WIDTH instead: 124px vs Ambrosia's 183px, ~70%. Every pixel
   here comes out of the left-hand nav cluster, which is what runs out first. */
.parent-lockup--nav .parent-lockup__logo { height: clamp(24px, 2.05vw, 31px); transition: height .3s var(--ease); }
.parent-lockup--nav { opacity: .92; transition: opacity .2s var(--ease); }
a.parent-lockup--nav:hover { opacity: 1; }
/* Steps down with the Ambrosia mark once the sticky bar compacts. */
.site-header.is-scrolled .parent-lockup--nav .parent-lockup__logo { height: clamp(20px, 1.7vw, 26px); }

.site-header {
	position: sticky; top: 0; z-index: 100;
	background: rgba(255,255,255,.9);
	backdrop-filter: saturate(150%) blur(12px);
	-webkit-backdrop-filter: saturate(150%) blur(12px);
	border-bottom: 1px solid rgba(28,28,28,.07);
}
/* Five columns: SFI mark · left nav · BRAND · right nav · icons.
   The two end columns are the SAME fixed width and the two nav columns are equal
   fractions, so the brand track lands on the exact centre line of the bar — the
   client's requirement — no matter what the labels say. Flex with equal-basis
   halves could only approximate that, because the SFI mark (~88px) and the search
   icon (44px) don't weigh the same.
   --nav-edge is sized to always exceed the SFI mark's own width: the mark is
   clamp(18px,1.7vw,22px) tall × 4.005 ratio = clamp(72px, 6.8vw, 88px). */
.site-header__inner {
	display: grid; align-items: center;
	--nav-edge: clamp(100px, 8.6vw, 132px);
	grid-template-columns: var(--nav-edge) minmax(0, 1fr) auto minmax(0, 1fr) var(--nav-edge);
	gap: clamp(.6rem, 1.6vw, 1rem); padding: .5rem 0;
}
.site-nav { display: contents; }
.nav-half { min-width: 0; }
.site-header__parent { order: 0; justify-self: start; display: flex; align-items: center; }
.nav-half--left  { order: 1; }
.site-brand      { order: 2; justify-self: center; }
.nav-half--right { order: 3; }
.site-header__actions { order: 4; justify-self: end; display: flex; align-items: center; gap: .25rem; }

/* The mark itself — the anchor of the whole bar. Shrinks once the page scrolls so
   the sticky bar doesn't follow the visitor down at full height.
   `max-width: none` is REQUIRED: the global img reset caps images at 100% of their
   container, which — against a fixed height — squashes the logo horizontally as soon
   as the brand cell gets tight. With it off, width always resolves from the image's
   natural ratio. object-fit stays as a guard in case both axes ever get constrained. */
.site-brand__logo {
	width: auto; max-width: none;
	height: clamp(52px, 4.4vw, 68px);
	object-fit: contain; display: block;
	transition: height .3s var(--ease);
}
.site-header.is-scrolled .site-brand__logo { height: clamp(42px, 3.6vw, 56px); }
.site-header { transition: box-shadow .3s var(--ease); }
.site-header.is-scrolled { box-shadow: 0 6px 22px -14px rgba(28,28,28,.35); }

.primary-nav__list {
	list-style: none; margin: 0; padding: 0;
	display: flex; align-items: center;
	/* The two nav columns are equal fractions, so the longer LEFT cluster is what
	   runs out of room first, just above the nav breakpoint — that's what these
	   clamps are tuned against. */
	gap: clamp(.65rem, 1.9vw, 1.25rem);
}
.nav-half--left  .primary-nav__list { justify-content: flex-start; }
.nav-half--right .primary-nav__list { justify-content: flex-end; }
/* Labels run RED across the bar, as in the client's own product-page concept
   (5.5:1 on white — clears AA). Since red no longer distinguishes the active
   item, the current page is marked by weight + an underline rule instead.

   TITLE CASE, not uppercase (2026-08-04). Six labels either side of a large
   centred mark plus the SFI mark is more than an uppercase bar can hold: measured
   against the real Montserrat 700 metrics, "Products · Distributors · Chefs &
   Kitchens" is 19.66em in title case at .02em versus 26.78em in caps at .085em —
   27% narrower, which is where the room for the SFI mark came from. Tightening
   tracking alone only bought 3%. The type is a notch LARGER as a result. */
.primary-nav__list a {
	font-family: var(--font-head); font-weight: 700;
	font-size: clamp(.78rem, .95vw, .84rem);
	letter-spacing: .02em;
	color: var(--red); text-decoration: none;
	padding: .65rem 0; display: inline-block; white-space: nowrap;
	position: relative;
	transition: color .2s var(--ease);
}
.primary-nav__list a:hover { color: var(--red-dark); }
.primary-nav__list a[aria-current="page"],
.primary-nav__item.is-current > a { color: var(--red-dark); font-weight: 800; }
.primary-nav__list a[aria-current="page"]::after,
.primary-nav__item.is-current > a::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: .3rem;
	height: 2px; background: currentColor;
}
.primary-nav .sub-menu {
	list-style: none; margin: 0; padding: .5rem 0;
	position: absolute; left: 0; top: 100%; background: var(--paper); min-width: 240px;
	box-shadow: 0 8px 24px rgba(0,0,0,.12); border-radius: var(--radius);
	display: none; z-index: 10;
}
.primary-nav__item { position: relative; }
.primary-nav__item:hover > .sub-menu,
.primary-nav__item:focus-within > .sub-menu { display: block; }
.primary-nav .sub-menu a { display: block; padding: .55rem 1.1rem; letter-spacing: .05em; white-space: normal; }
.primary-nav__placeholder { flex: 1; margin: 0; font-size: .85rem; color: var(--charcoal); }

/* icon buttons in the bar (search, hamburger) */
.search-toggle, .nav-toggle {
	background: none; border: 0; cursor: pointer; color: var(--ink);
	width: 44px; height: 44px; position: relative;
	display: inline-flex; align-items: center; justify-content: center;
	border-radius: 999px; transition: background .2s var(--ease), color .2s var(--ease);
}
.search-toggle:hover, .nav-toggle:hover { background: var(--mist); color: var(--red); }
.search-toggle .sfi-icon { width: 21px; height: 21px; }
.search-toggle[aria-expanded="true"] { background: var(--red); color: #fff; }

.nav-toggle { display: none; }
.nav-toggle__bar,
.nav-toggle__bar::before,
.nav-toggle__bar::after {
	content: ""; position: absolute; left: 10px; width: 24px; height: 2px;
	background: currentColor; transition: transform .2s ease, opacity .2s ease;
}
.nav-toggle__bar { top: 21px; }
.nav-toggle__bar::before { top: -7px; }
.nav-toggle__bar::after  { top: 7px; }

/* ---------- search (header drawer + inline forms) ---------- */
.header-search {
	background: var(--mist); border-bottom: 1px solid rgba(28,28,28,.07);
	overflow: hidden;
}
/* Collapsed only when JS can open it — no-JS visitors keep a usable field. */
.sfi-js .header-search { max-height: 0; border-bottom-color: transparent; transition: max-height .3s var(--ease); }
.sfi-js .header-search.is-open { max-height: 140px; border-bottom-color: rgba(28,28,28,.07); }
.header-search .wrap { padding: 1rem 0 1.15rem; }

.nav-search { display: flex; align-items: center; gap: .5rem; }
.nav-search__field {
	flex: 1; min-width: 0; font: inherit; font-size: 1rem;
	padding: .7rem 1rem; min-height: 48px;
	border: 2px solid color-mix(in srgb, var(--ink) 14%, transparent);
	border-radius: 999px; background: var(--paper); color: var(--ink);
}
.nav-search__field::placeholder { color: color-mix(in srgb, var(--ink) 45%, transparent); }
/* Focus ring recoloured to brand red (client preference over the site-wide green).
   Recolour the OUTLINE rather than adding a border on top of it — doing both is what
   gave the field a red inner ring inside a green outer one. */
.nav-search__field:focus-visible { outline-color: var(--red); }
.nav-search__submit {
	flex: 0 0 auto; width: 48px; height: 48px; border-radius: 999px;
	border: 0; background: var(--red); color: #fff; cursor: pointer;
	display: inline-flex; align-items: center; justify-content: center;
	transition: background .2s var(--ease), transform .2s var(--ease);
}
.nav-search__submit:hover { background: var(--red-dark); transform: translateY(-1px); }
/* The in-panel form only exists for the mobile menu. */
.nav-search--panel { display: none; }

/* Nav breakpoint. 1140px: the SFI mark grew ~1.5x on 2026-08-05 and took the
   1081–1140 band with it — below ~1140 the left cluster no longer fits its
   equal-width column, and collapsing to the menu button early beats colliding
   with the centred brand. Above it the bar clears by 32–85px. */
@media (max-width: 1140px) {
	.nav-toggle { display: inline-flex; }
	.search-toggle { display: none; }              /* mobile searches from inside the panel */
	.header-search { display: none; }
	/* Back to a plain row: mark · brand · menu button. The three of them must not
	   shrink — the brand mark is a fixed-height image and flex would squash it. */
	.site-header__inner { display: flex; justify-content: space-between; }
	.site-header__parent,
	.site-brand,
	.site-header__actions { flex: 0 0 auto; }
	.site-nav {
		display: block;
		position: absolute; inset: 100% 0 auto 0; background: var(--paper);
		box-shadow: 0 10px 28px rgba(0,0,0,.14);
		max-height: 0; overflow: hidden; transition: max-height .25s ease;
	}
	.site-nav.is-open { max-height: min(80vh, 640px); overflow: auto; }
	.nav-half { flex: none; }
	.nav-half--left .primary-nav__list { padding-top: .75rem; }
	.nav-half--right .primary-nav__list { padding-bottom: .5rem; }
	.primary-nav__list {
		flex-direction: column; align-items: stretch; gap: 0;
		padding-inline: var(--gutter);
	}
	.primary-nav__list a {
		padding: .9rem 0; font-size: 1rem; letter-spacing: .02em;
		border-bottom: 1px solid rgba(28,28,28,.07);
	}
	.primary-nav .sub-menu { position: static; display: block; box-shadow: none; padding: 0 0 0 1rem; min-width: 0; }
	.nav-search--panel { display: flex; padding: 1rem var(--gutter) 1.35rem; }
	.site-brand__logo { height: clamp(46px, 11vw, 62px); }
	/* Three items on one row now (SFI mark · Ambrosia mark · menu button); the mark
	   steps down again so it still fits a 320px phone. */
	.parent-lockup--nav .parent-lockup__logo,
	.site-header.is-scrolled .parent-lockup--nav .parent-lockup__logo { height: clamp(18px, 3.4vw, 30px); }
}

/* ---------- ovalesque curve divider (brand motif) ---------- */
.sfi-curve { line-height: 0; }
.sfi-curve svg { width: 100%; height: clamp(32px, 5vw, 70px); display: block; }
.sfi-curve--paper svg path    { fill: var(--paper); }
.sfi-curve--mist svg path     { fill: var(--mist); }
.sfi-curve--charcoal svg path { fill: var(--charcoal); }
.sfi-curve--beige svg path    { fill: var(--beige); }
.sfi-curve--band svg path     { fill: var(--curve-fill); }

/* ---------- hero ----------
   SPLIT: solid tan panel (copy) + full-height rotating photography. No scrim and
   no gradient — the client asked for the flat tan because type reads far better
   on it. The copy column is padded out to the site wrap so the headline lines up
   with the content below; the photo bleeds to the viewport edge. */
.hero {
	position: relative; color: var(--ink); background: var(--cream);
	--hero-split: 50%;
	/* Left inset for the copy: it has to land on the site's content edge, so the
	   headline lines up with the nav above it and every section below it.
	   It is (heroWidth - wrap) / 2, and with a 50% split the hero is exactly twice
	   this column — so that reduces to 100% - wrap/2, written longhand. (It used to
	   read (100vw - wrap)/2, but 100vw INCLUDES the scrollbar while the page lays
	   out without it, which pushed the copy 7.5px right of everything else.)
	   Tied to the 50% split — re-derive if --hero-split moves. */
	--hero-inset: max(var(--gutter), calc(100% - var(--wrap) / 2));
	display: grid; grid-template-columns: var(--hero-split) calc(100% - var(--hero-split));
	align-items: stretch; isolation: isolate; overflow: hidden;
}
/* Longhands, not the `padding` shorthand: one bad value in a shorthand takes the
   whole declaration down — and the left inset is the fussy one to lose. */
.hero__inner {
	display: flex; align-items: center; min-width: 0;
	padding-top: clamp(2.75rem, 6vw, 5rem);
	padding-right: clamp(2rem, 3.5vw, 3.5rem);
	padding-bottom: clamp(4.5rem, 8vw, 7rem);
	padding-left: var(--hero-inset);
}
.hero__content { max-width: 46rem; }
.hero__title {
	color: var(--ink); margin-bottom: 1.1rem;
	font-size: clamp(2rem, 5.6vw, 2.7rem); font-weight: 800; letter-spacing: -.03em;
}
/* The registered mark, wherever it appears in display type (sfi_reg()).
   At 40–60px a full-height ® is a glyph the size of a capital and reads as a
   mistake; superscripting it is what every brand guide asks for and, usefully,
   makes a one-line headline NARROWER — the homepage H1's measured 13.52em was
   taken with the mark at full size, so this only buys slack. `top` rather than
   `vertical-align` so the mark cannot inflate the line box. */
.reg {
	font-size: .45em; font-weight: 600; letter-spacing: 0;
	position: relative; top: -.62em; line-height: 0;
}
/* Client: the headline must stay on ONE line — so it is capped to whatever the
   copy panel can actually hold. Measured against the real font, "Ambrosia® Makes
   the Meal" is 13.52em of Montserrat 800 at -.03em tracking (confirmed against a
   rendered screenshot: 596px at 43.2px type).
   Re-fitted TWICE on 2026-08-04: first when the split went 54% → 50% (2.7rem/3.3vw
   → 2.45rem/3.0vw), then again when the copy panel's right inset was opened up
   from ~2rem to 3.5rem because the type was running into the photo edge
   (→ 2.3rem/2.8vw). Holds the line with 41–60px to spare from 1024px up.
   These are NOT free parameters — they are derived from the panel width, so
   re-derive them if either the split or the panel's insets move. */
@media (min-width: 1024px) {
	.hero__title { white-space: nowrap; font-size: min(2.3rem, 2.8vw); }
}
/* 901–1023px: still split, but the panel is too narrow for the big size. */
@media (min-width: 901px) and (max-width: 1023px) {
	.hero__title { font-size: 2.2rem; }
}
.hero__sub {
	font-size: clamp(1.1rem, 1.45vw, 1.32rem); line-height: 1.6;
	max-width: 46ch; color: color-mix(in srgb, var(--ink) 84%, transparent);
	margin-bottom: 2.15rem;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: .85rem; }

/* ---- hero CTA ----
   History, because this went back and forth: the button was stripped to a plain
   ink outline on 2026-08-10 so it could not out-shout the hero copy (the client
   wants visitors to READ the page rather than be fired out of the hero — their
   reference is rolandfoods.com). Seeing it live, the client asked for the RED
   button back (2026-08-11) and judged that the enlarged hero copy plus the
   breathing room around the button already do the work of holding the eye on
   the words. So: brand red is back, and the restraint now lives in the button's
   SIZE and in the space above it, not in its colour —
     · a step below .btn--lg (which would be 1.05rem/56px),
     · a flatter shadow than the site default, so it sits on the cream panel
       instead of floating over it,
     · .hero__sub margin-bottom above, 1.85rem → 2.15rem.
   Overrides .btn--primary/.btn--lg by specificity, so the markup is untouched. */
.hero__actions .btn--primary {
	box-shadow: 0 10px 20px -14px rgba(197,36,53,.75);
}
.hero__actions .btn--lg {
	padding: .88rem 1.85rem; font-size: .98rem; min-height: 52px;
}
.hero__actions .btn--primary:hover {
	box-shadow: 0 16px 26px -14px rgba(197,36,53,.9);
}

/* ---- scroll cue ----
   A small arrow under the CTA nudging the visitor into the page. In the copy
   panel rather than centred on the hero's foot, because the curve divider is
   overlaid there and bulges ~70px up at mid-span — right where a centred cue
   would sit. A real in-page link, so it works without JS. */
.hero__scroll {
	display: inline-flex; align-items: center; gap: .6rem;
	margin-top: clamp(1.75rem, 3.5vw, 2.75rem);
	text-decoration: none; color: var(--charcoal);
	font-family: var(--font-head); font-weight: 700;
	font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
	transition: color .2s var(--ease);
}
.hero__scroll-icon {
	width: 40px; height: 40px; flex: 0 0 auto; border-radius: 999px;
	display: inline-flex; align-items: center; justify-content: center;
	border: 2px solid color-mix(in srgb, var(--red) 35%, transparent);
	color: var(--red); background: rgba(255,255,255,.5);
	transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.hero__scroll-icon .sfi-icon { width: 19px; height: 19px; animation: sfi-nudge 2.4s var(--ease) infinite; }
.hero__scroll:hover { color: var(--red); }
.hero__scroll:hover .hero__scroll-icon { background: var(--red); border-color: var(--red); color: #fff; }
@keyframes sfi-nudge {
	0%, 55%, 100% { transform: translateY(0); }
	72%           { transform: translateY(4px); }
}
/* Zero-height landing point dropped straight after each hero. The offset keeps
   the sticky header from covering the top of the section it lands on. */
.hero-anchor { display: block; height: 0; scroll-margin-top: 5.5rem; }
.hero__media { position: relative; min-width: 0; min-height: min(74vh, 680px); background: var(--sand); }
.hero__video { width: 100%; height: 100%; object-fit: cover; }
.hero .sfi-curve { position: absolute; bottom: -1px; left: 0; right: 0; z-index: 3; }

/* ---- hero carousel ---- */
.hero-carousel { position: absolute; inset: 0; }
.hero-carousel__track { list-style: none; margin: 0; padding: 0; position: absolute; inset: 0; }
.hero-carousel__slide {
	position: absolute; inset: 0; opacity: 0;
	transition: opacity .9s var(--ease);
}
.hero-carousel__slide.is-active { opacity: 1; }
.hero__img { width: 100%; height: 100%; object-fit: cover; object-position: center; }

.hero-carousel__controls {
	position: absolute; z-index: 4;
	right: clamp(1rem, 2.5vw, 2rem); bottom: clamp(3.25rem, 6vw, 4.75rem);
	display: flex; align-items: center; gap: .5rem;
	padding: .35rem .5rem; border-radius: 999px;
	background: rgba(255,255,255,.82);
	backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
	box-shadow: 0 8px 22px -10px rgba(28,28,28,.45);
}
html:not(.sfi-js) .hero-carousel__controls { display: none; }
.hero-carousel__arrow {
	width: 34px; height: 34px; border-radius: 999px; border: 0; cursor: pointer;
	background: none; color: var(--ink);
	display: inline-flex; align-items: center; justify-content: center;
	transition: background .2s var(--ease), color .2s var(--ease);
}
.hero-carousel__arrow:hover { background: var(--red); color: #fff; }
.hero-carousel__arrow .sfi-icon { width: 17px; height: 17px; }
.hero-carousel__dots { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: .3rem; }
.hero-carousel__dot {
	width: 24px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer;
	display: inline-flex; align-items: center; justify-content: center;
}
.hero-carousel__dot::before {
	content: ""; width: 8px; height: 8px; border-radius: 999px;
	background: color-mix(in srgb, var(--ink) 26%, transparent);
	transition: background .25s var(--ease), transform .25s var(--ease);
}
.hero-carousel__dot:hover::before { background: color-mix(in srgb, var(--ink) 45%, transparent); }
.hero-carousel__dot.is-active::before { background: var(--red); transform: scale(1.35); }

/* Stack on small screens: photo on top, tan copy panel beneath (keeps the type
   on the flat tan rather than over the photo). */
@media (max-width: 900px) {
	.hero { grid-template-columns: 1fr; }
	.hero__media { order: -1; min-height: 0; aspect-ratio: 4 / 3; }
	.hero__inner { padding: clamp(2rem, 7vw, 3rem) var(--gutter) clamp(3.75rem, 11vw, 5rem); }
	.hero__content { max-width: 40rem; }
	.hero-carousel__controls { bottom: clamp(.75rem, 3vw, 1.25rem); }
}
@media (max-width: 560px) {
	.hero__media { aspect-ratio: 3 / 2; }
}

/* ---------- generic bands ---------- */
.intro { padding: clamp(2.5rem, 6vw, 5rem) 0; background: var(--mist); }
.inner-hero { background: var(--mist); padding: clamp(2rem, 5vw, 4rem) 0 0; position: relative; }
.inner-hero--media { color: #fff; }
.inner-hero__intro { max-width: 60ch; font-size: 1.125rem; }
.page-body { padding: clamp(2rem, 5vw, 4rem) 0; }

/* ---------- product catalog ---------- */
.catalog__header { background: var(--mist); padding: clamp(2rem,5vw,4rem) 0 0; position: relative; }
.catalog__eyebrow a { font-family: var(--font-head); font-weight: 600; text-decoration: none; }
.catalog__body { padding: 2rem 0 4rem; }

/* filter bar + its selects are styled with the rest of the catalogue below */

.card-grid {
	list-style: none; margin: 0; padding: 0;
	display: grid; gap: 1.5rem;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.card { background: var(--paper); border: 1px solid #e6e0d8; border-radius: var(--radius); padding: 1rem; display: flex; flex-direction: column; }
.card__link { text-decoration: none; color: var(--ink); }
.card__media { aspect-ratio: 4/3; overflow: hidden; border-radius: 8px; background: var(--mist); margin-bottom: .75rem; }
.card__img { width: 100%; height: 100%; object-fit: cover; }
.card__placeholder { display: block; width: 100%; height: 100%; background: repeating-linear-gradient(45deg,#efe9e1,#efe9e1 10px,#e7ded2 10px,#e7ded2 20px); }
.card__title { font-size: 1.1rem; margin: 0 0 .25rem; }
.card__meta { font-size: .85rem; color: var(--charcoal); display: flex; gap: .75rem; flex-wrap: wrap; margin: 0 0 .5rem; }
.card__spec { margin-top: auto; font-family: var(--font-head); font-weight: 600; font-size: .85rem; }
.catalog__empty { padding: 2rem 0; color: var(--charcoal); }

/* ---------- single product ---------- */
.product-single__grid { display: grid; gap: 2.5rem; grid-template-columns: 1fr 1fr; padding: clamp(2rem,5vw,4rem) 0; }
.product-single__img { width: 100%; border-radius: var(--radius); }
.product-single__cats a { font-family: var(--font-head); font-weight: 600; font-size: .85rem; text-transform: uppercase; letter-spacing: .04em; }
.product-single__specs { display: grid; grid-template-columns: auto 1fr; gap: .25rem 1rem; margin: 1rem 0; }
.product-single__specs dt { font-family: var(--font-head); font-weight: 600; color: var(--charcoal); }
.product-single__specs dd { margin: 0; }
.product-single__uses ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.product-single__uses li a { display: inline-block; padding: .35rem .8rem; background: var(--mist); border-radius: 999px; text-decoration: none; font-size: .85rem; }
/* Pack shots are cut-outs or shot on white — contain them in a white panel
   rather than letting a 3:4 jar dictate the height of the row. */
.product-single__media {
	display: grid; place-items: center; overflow: hidden; padding: clamp(1rem, 3vw, 2.5rem);
	background: var(--paper); border: 1px solid rgba(28,28,28,.08); border-radius: var(--radius-lg);
	aspect-ratio: 1; align-self: start;
}
/* Same clamp as the card stage — see the note there for why it is height:100%.
   The max-* pair is the sharpness cap (2026-08-24): --img-w/--img-h are the
   attachment's real pixel dimensions, printed on the wrapper by
   single-product.php, so a 250px pack shot scraped off the old site is not
   simply blown up to fill a 500px panel. Both default to `none`, so an image
   whose metadata is missing behaves exactly as before.

   --img-scale IS THE DIAL, and it is the only number to touch. Those 250px
   files are all that exists — the old site's originals are 250px and the
   spec-sheet PDFs carry no product photo, so there is no sharper source to
   fetch and every value here is a trade:
     1.0  native, sharpest, and the client said too small
     1.5  ~375px in the panel — the product reads at about half again its
          native size, softened but not mushy            <- shipped
     2.0  fills the panel, and is what the client called blurry
   Real photography lands above the cap and it stops applying by itself. */
.product-single__img {
	--img-scale: 1.5;
	width: 100%; height: 100%; min-width: 0; min-height: 0;
	max-width: calc(var(--img-w, 100%) * var(--img-scale));
	max-height: calc(var(--img-h, 100%) * var(--img-scale));
	object-fit: contain; border-radius: 0;
}
.product-single__title { margin: .25rem 0 .5rem; font-size: clamp(1.6rem, 3.2vw, 2.35rem); }
.product-single__id { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.25rem; font-family: var(--font-head); font-weight: 700; color: var(--red); }
.product-single__id span[aria-hidden] { color: var(--beige); }
.product-single__pack { color: var(--charcoal); }
.product-single__specs {
	margin: 1.5rem 0; padding: 1.1rem 1.25rem; gap: .5rem 1.5rem;
	background: var(--mist); border-radius: var(--radius);
}
.product-single__specs dt { font-size: .82rem; letter-spacing: .02em; }
.product-single__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; margin-top: 1.5rem; }
.product-single .cat-crumbs { padding-top: 1.5rem; }
.product-single .cat-crumbs a { color: var(--charcoal); }
.product-single .cat-crumbs span { color: var(--beige); }
@media (max-width: 720px) { .product-single__grid { grid-template-columns: 1fr; } }

/* ---------- footer ---------- */
.site-footer { background: var(--footer-bg); color: rgba(255,255,255,.72); margin-top: clamp(3rem, 6vw, 5rem); position: relative; }
/* The footer's default top margin shows the white page background above it.
   That is only invisible on templates that END on white; anything ending on a
   tinted section gets a white bar between the section and the footer curve.
   Every full-bleed template is therefore flush. */
.front + .site-footer,
.catalog + .site-footer,
.category-page + .site-footer,
.product-single + .site-footer { margin-top: 0; }
/* The footer's valley curve is filled with whatever section sits above it. */
.front + .site-footer { --footer-curve-fill: var(--mist); }
.site-footer a { color: #fff; text-decoration: none; }
.site-footer a:hover { color: var(--gold); }
.site-footer__inner { display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: 1.7fr 1fr 1.3fr; padding: clamp(2.75rem, 5vw, 4.25rem) 0 2.5rem; }

.site-footer__brand { max-width: 40ch; }
/* Red mark on white, sized up to match its new prominence in the header. */
.site-footer__logo { background: #fff; padding: .7rem 1rem; border-radius: 14px; width: clamp(200px, 20vw, 248px); height: auto; }
.site-footer__tagline {
	margin: 1.35rem 0 0; line-height: 1.4; color: #fff;
	font-family: var(--font-head); font-weight: 700; font-size: clamp(1.05rem, 1.5vw, 1.3rem);
	letter-spacing: -.01em;
}
/* Parent-company lockup (replaces the old "…family." sentence). Stacked here —
   the brand column is only ~40ch wide — and it uses the white-knockout wordmark,
   since the supplied art is maroon + black type and black type vanishes on the
   near-black footer. A hairline rule above sets it apart from the tagline. */
.parent-lockup--footer {
	display: block; margin: 1.5rem 0 0; padding: 1.35rem 0 0;
	border-top: 1px solid rgba(255,255,255,.12);
	color: rgba(255,255,255,.68);
}
.parent-lockup--footer .parent-lockup__logo { width: clamp(180px, 17vw, 210px); height: auto; }
.parent-lockup--footer .parent-lockup__text {
	display: block; margin-top: .8rem;
	font-size: .92rem; line-height: 1.6; max-width: 34ch;
	/* Explicit — `.site-footer a` (higher specificity) would otherwise pull it to full white. */
	color: rgba(255,255,255,.68);
}
a.parent-lockup--footer:hover .parent-lockup__text { color: var(--gold); text-decoration: underline; text-underline-offset: 2px; }

/* social icon row */
.social-links { list-style: none; margin: 1.6rem 0 0; padding: 0; display: flex; gap: .6rem; }
.social-links__link {
	width: 42px; height: 42px; border-radius: 999px;
	display: inline-flex; align-items: center; justify-content: center;
	border: 1px solid rgba(255,255,255,.22); color: #fff;
	transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease), transform .2s var(--ease);
}
.social-links__link:hover { background: var(--red); border-color: var(--red); color: #fff; transform: translateY(-2px); }
.social-links .sfi-icon { width: 19px; height: 19px; }

.site-footer__h { font-family: var(--font-head); font-weight: 700; font-size: .78rem; letter-spacing: .15em; text-transform: uppercase; color: rgba(255,255,255,.5); margin: 0 0 1.2rem; }
.site-footer__nav { min-width: 0; }
.site-footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; }
.site-footer__list a { font-family: var(--font-head); font-weight: 600; }

.site-footer__contact address { font-style: normal; line-height: 1.7; margin: 0 0 1.4rem; color: rgba(255,255,255,.72); }
.site-footer__cs-label { display: block; font-family: var(--font-head); font-size: .75rem; text-transform: uppercase; letter-spacing: .13em; color: rgba(255,255,255,.5); margin-bottom: .25rem; }
.site-footer__phone { font-family: var(--font-head); font-weight: 800; font-size: 1.35rem; color: #fff; letter-spacing: .01em; }
.site-footer__phone:hover { color: var(--gold); }
.site-footer__h--search { margin-top: 2rem; }

/* search in the bottom nav — dark-surface treatment of the shared form */
.nav-search--footer .nav-search__field {
	background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.2); color: #fff;
	min-height: 44px; padding: .55rem .95rem; font-size: .95rem;
}
.nav-search--footer .nav-search__field::placeholder { color: rgba(255,255,255,.45); }
/* Red only clears ~2.2:1 against the near-black footer, below the 3:1 a focus ring
   needs to be visible, so the footer keeps a white ring. */
.nav-search--footer .nav-search__field:focus-visible { outline-color: #fff; }
.nav-search--footer .nav-search__submit { width: 44px; height: 44px; }

.site-footer__legal { border-top: 1px solid rgba(255,255,255,.1); font-size: .82rem; color: rgba(255,255,255,.55); padding: 1.35rem 0; }
.site-footer__legal .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1.5rem; }
.site-footer__legal p { margin: 0; }
.site-footer__legal a { color: rgba(255,255,255,.75); }

@media (max-width: 860px) { .site-footer__inner { grid-template-columns: 1fr 1fr; } .site-footer__brand { grid-column: 1 / -1; } }
@media (max-width: 560px) { .site-footer__inner { grid-template-columns: 1fr; } }

/* Footer curve = the INVERSE of the hero's (client request).
   The hero fills the arc with the colour of the section BELOW it and pins it to
   the hero's bottom, so that colour arcs UP → the boundary reads as a dome.
   The footer mirrors it: same arc ROTATED 180° (so the fill hugs the top edge and
   bulges downward) and filled with the colour of the section ABOVE, sitting at
   the footer's top → the boundary reads as a valley.
   BOTH halves matter. Rotated + footer-coloured = invisible (colour on colour).
   Un-rotated + section-coloured = a crescent that floats free of the section
   above it and reads as a blade. */
.sfi-curve--footer { margin-top: -1px; }   /* kill any sub-pixel seam at the join */
.sfi-curve--footer svg path { fill: var(--footer-curve-fill, var(--paper)); }

/* ---------- misc ---------- */
.front__placeholder { padding: 4rem 0; text-align: center; }
.pagination, .nav-links { display: flex; gap: .5rem; flex-wrap: wrap; padding: 2rem 0; }
.pagination a, .pagination span { padding: .5rem .85rem; border-radius: 6px; background: var(--mist); text-decoration: none; }

/* =====================================================================
   HOMEPAGE — one design (Concept 1, approved 2026-07-29). The A/B concept
   switch and the Concept 2 skin were removed on 2026-07-30.
   ===================================================================== */

.front { --curve-fill: var(--paper); }

/* ---- parent-company band: editorial split ---- */
.band { padding: var(--section-y) 0; background: var(--paper); }
.band__grid { display: grid; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.band__grid--split { grid-template-columns: 1.05fr .95fr; }
.band__title { margin-bottom: 1.25rem; }
.band__body { font-size: 1.08rem; line-height: 1.72; }
.band__content .btn { margin-top: .5rem; }
.band__figure { margin: 0; position: relative; }
.band__img {
	width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
	border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
/* brand curve/oval accent tucked behind the image */
.band__figure::after {
	content: ""; position: absolute; z-index: -1;
	inset: auto -20px -20px auto; width: 62%; height: 66%;
	border-radius: var(--radius-lg); background: var(--beige); opacity: .55;
}
@media (max-width: 860px) {
	.band__grid--split { grid-template-columns: 1fr; }
	.band__figure { order: -1; }
}

/* stat highlights — 3-up row with divider rules */
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1rem, 2.5vw, 2rem); margin: 2.25rem 0; padding: 0; }
.stats__item { margin: 0; padding-left: clamp(1rem, 2vw, 1.5rem); border-left: 2px solid color-mix(in srgb, var(--red) 55%, transparent); }
.stats__value { font-family: var(--font-head); font-weight: 800; font-size: clamp(1.9rem, 3.4vw, 3rem); line-height: 1; color: var(--red); letter-spacing: -.03em; }
.stats__label { margin: .5rem 0 0; font-family: var(--font-head); font-weight: 600; font-size: .76rem; text-transform: uppercase; letter-spacing: .1em; color: var(--charcoal); line-height: 1.35; }
@media (max-width: 460px) { .stats { grid-template-columns: 1fr 1fr; } }

/* ---- audience benefit cards ---- */
.benefits { padding: var(--section-y) 0; background: var(--mist); }
.benefits__grid { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); grid-template-columns: repeat(2, 1fr); }
.benefits__grid[data-count="1"] { grid-template-columns: 1fr; max-width: 680px; margin-inline: auto; }
.benefits__grid[data-count="3"] { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 820px) { .benefits__grid { grid-template-columns: 1fr !important; } }
.benefit-card {
	background: var(--paper); border-radius: var(--radius-lg); overflow: hidden;
	box-shadow: var(--shadow-md); display: flex; flex-direction: column;
	transition: transform .45s var(--ease), box-shadow .45s var(--ease);
}
.benefit-card:hover { transform: translateY(-8px); box-shadow: var(--shadow-lg); }
.benefit-card__media { aspect-ratio: 16 / 10; overflow: hidden; }
.benefit-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.benefit-card:hover .benefit-card__img { transform: scale(1.06); }
.benefit-card__inner { padding: clamp(1.7rem, 3vw, 2.5rem); display: flex; flex-direction: column; align-items: flex-start; flex: 1; }
.benefit-card__title { margin: 0 0 .6rem; }
.benefit-card__text { margin: 0; color: color-mix(in srgb, var(--ink) 78%, transparent); line-height: 1.65; }
.benefit-card__cta { margin-top: 1.5rem; }

/* ---- utility strip: a rich red accent bar (breaks up the dark content ↔ dark footer) ---- */
.utility-strip { background: var(--red-deep); color: #fff; }
.utility-strip a { color: #fff; }
.utility-strip__inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem; padding: 1.5rem 0; }
.utility-strip .link-arrow { color: #fff; }
.utility-strip .link-arrow:hover { color: #fff; opacity: .82; }
.utility-strip__cs { margin: 0; font-family: var(--font-head); display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.utility-strip__cs-label { font-weight: 400; opacity: .85; font-size: .95rem; }
.utility-strip__phone { font-weight: 800; font-size: 1.2rem; letter-spacing: .01em; text-decoration: none; }
.utility-strip__phone:hover { color: #fff; opacity: .85; }

/* ---- "What's New": 3 tiles (Market Update / Newsroom / Instagram).
        Client asked for this to sit back — it's a utility footer-of-page block,
        not a feature. Tighter padding, smaller heading, shorter images, flatter
        cards than the audience section above it. ---- */
.whats-new { padding: clamp(2rem, 4vw, 3.25rem) 0 clamp(2.25rem, 4.5vw, 3.75rem); background: var(--paper); }
.whats-new__head { margin-bottom: clamp(1.1rem, 2.2vw, 1.65rem); }
.whats-new__title { margin: 0; font-size: clamp(1.25rem, 1.9vw, 1.6rem); }
.whats-new .eyebrow { font-size: .7rem; margin-bottom: .55rem; }
.whats-new__grid {
	list-style: none; margin: 0; padding: 0;
	display: grid; gap: clamp(.9rem, 1.8vw, 1.35rem);
	grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 900px) { .whats-new__grid { grid-template-columns: 1fr; max-width: 520px; margin-inline: auto; } }
.news-card {
	background: var(--paper); border-radius: var(--radius); overflow: hidden;
	box-shadow: var(--shadow-sm); border: 1px solid rgba(28,28,28,.07);
	transition: transform .4s var(--ease), box-shadow .4s var(--ease);
}
.news-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.news-card__link { display: flex; flex-direction: column; height: 100%; text-decoration: none; color: var(--ink); }
.news-card__media { aspect-ratio: 16 / 8; overflow: hidden; }
.news-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.news-card:hover .news-card__img { transform: scale(1.05); }
.news-card__body { padding: clamp(1rem, 1.8vw, 1.35rem); display: flex; flex-direction: column; align-items: flex-start; gap: .35rem; flex: 1; }
.news-card__eyebrow { margin: 0 0 .2rem; font-size: .66rem; }
.news-card__eyebrow::before { width: 18px; }
.news-card__title { font-family: var(--font-head); font-weight: 700; font-size: 1.02rem; letter-spacing: -.01em; line-height: 1.25; }
.news-card__text { margin: 0; color: color-mix(in srgb, var(--ink) 72%, transparent); line-height: 1.5; font-size: .88rem; }
.news-card__cta { margin-top: auto; padding-top: .6rem; font-size: .85rem; }


/* ---- category browse: "Browse the Catalog" ---- */
.categories { padding: var(--section-y) 0; background: var(--paper); }
.categories__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1.5rem 2rem; flex-wrap: wrap; margin-bottom: clamp(1.75rem, 4vw, 3rem); }
.categories__title { margin: 0; }
.categories__intro { margin: .85rem 0 0; color: color-mix(in srgb, var(--ink) 78%, transparent); }
.categories__all { white-space: nowrap; }
.categories__grid {
	list-style: none; margin: 0; padding: 0;
	display: grid; gap: clamp(1rem, 2vw, 1.5rem);
	grid-template-columns: repeat(5, 1fr);
}
@media (max-width: 1040px) { .categories__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px)  { .categories__grid { grid-template-columns: repeat(2, 1fr); } }
.cat-card__link { display: flex; flex-direction: column; gap: .85rem; text-decoration: none; color: var(--ink); }
.cat-card__media {
	position: relative; display: block; aspect-ratio: 1 / 1; overflow: hidden;
	border-radius: var(--radius-lg); background: var(--mist); box-shadow: var(--shadow-sm);
}
.cat-card__img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.cat-card__placeholder { position: absolute; inset: 0; background: linear-gradient(135deg, var(--sand), var(--mist)); }
/* These tiles are shot on white marble, so on the white catalog band they need a
   hairline to hold their edge. */
.cat-card__media::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-lg); box-shadow: inset 0 0 0 1px rgba(28,28,28,.1); pointer-events: none; }
.cat-card__link:hover .cat-card__img { transform: scale(1.07); }
.cat-card__label { font-family: var(--font-head); font-weight: 700; font-size: 1.02rem; letter-spacing: -.01em; text-align: center; }
.cat-card__link:hover .cat-card__label { color: var(--red); }

/* ===================== SECTION RHYTHM =====================
   Client: "the next section can be a different background colour so it's not tan
   followed by tan":
     hero TAN → catalog WHITE → parent-company MIST → audience WHITE →
     what's-new MIST → footer (dark, valley curve filled with MIST). */
.front .categories { background: var(--paper); }
.front .band       { background: var(--mist); }
.front .benefits   { background: var(--paper); }
.front .whats-new  { background: var(--mist); }
.front .band__figure::after { background: var(--beige); opacity: .5; }
/* Cards need to lift off the tinted bands they sit on. */
.front .benefit-card { background: var(--paper); }
.front .news-card    { background: var(--paper); }


/* =====================================================================
   AUDIENCE LANDING PAGES — "For Chefs & Kitchens", "For Distributors".
   Built out of the homepage's approved components (split cream hero, benefit
   cards, tile grid) so an inner page reads as the same site. Only the pieces
   this page adds are defined here.

   Section rhythm, same alternation as the homepage. Each page shows only the
   sections it has copy for, so the two run:
     Chefs:        hero CREAM → cards WHITE → inspiration MIST → steps WHITE →
                   CTA CREAM → footer (valley curve filled with cream).
     Distributors: hero CREAM → cards WHITE → support MIST → FAQs LINEN →
                   CTA CREAM → footer.
   ===================================================================== */

.audience { --curve-fill: var(--paper); }
.audience + .site-footer { margin-top: 0; --footer-curve-fill: var(--cream); }
/* FAQ answers jump to sections on this same page ("your Regional Sales
   Manager" → the map). Keep the sticky header off whatever they land on. */
.audience :is(h2, h3)[id] { scroll-margin-top: 6rem; }

/* ---- page hero ----
   Same hero as the homepage, on purpose — the client asked why it wasn't, and the
   answer was that nothing forced it apart. Every height/padding override this
   block used to carry has been deleted so the page inherits the homepage values.

   Exactly two things still differ, and both are structural rather than taste:

   1. The headline WRAPS. The homepage H1 is a four-word brand line pinned to one
      line (13.52em); these are sentences — "Ambrosia Imported Foods for Chefs and
      Kitchens" is 24.13em, which cannot fit one line in a half-width panel at any
      readable size. It takes the homepage's own type size and runs to two lines.
   2. The photo is taken out of flow. On the homepage the img sits inside
      .hero-carousel (position:absolute; inset:0) so its height:100% resolves
      against a filled box. Here it is a direct child of the grid item, where
      height:100% computes to auto — the image then sized the row off its own
      intrinsic ratio (a 896x1200 portrait rendered ~954px tall in a ~712px
      column, past 100vh). This is the carousel's positioning, without a carousel. */
.hero--page .hero__title { white-space: normal; }
.hero--page .hero__media > .hero__img { position: absolute; inset: 0; }

/* The homepage H1 is pinned at the largest size that holds ONE line, so it has
   no room to grow. These headlines already wrap, so this is where the client's
   "make the hero copy bigger" actually lands — ~20% up, still two lines at
   every width from 1024px because the panel takes two of them either way. */
.hero--page .hero__title { font-size: clamp(2rem, 3.2vw, 2.75rem); }

/* ---- shared section header ---- */
.section-head { max-width: 62ch; margin-bottom: clamp(1.75rem, 4vw, 2.75rem); }
.section-head h2 { margin: 0; }
.section-head__intro { margin: .85rem 0 0; font-size: 1.06rem; line-height: 1.65; color: color-mix(in srgb, var(--ink) 80%, transparent); }
/* Client (2026-08-10): the copy directly under "How We Support Our Distributor
   Partners" is the section's argument, not a caption — it gets deck-sized type
   and a wider measure than the other section intros. */
.support .section-head__intro {
	font-size: clamp(1.12rem, 1.5vw, 1.3rem); line-height: 1.6; max-width: 72ch;
	color: color-mix(in srgb, var(--ink) 88%, transparent);
}

/* ---- audience cards ---- */
.audience-blocks { background: var(--paper); }

/* ---- recipe inspiration ----
   Same tile component as the homepage's "What's New", but this is a feature on
   this page rather than a utility footer block, so the cards get their height
   and type back. */
.inspiration { padding: var(--section-y) 0; background: var(--mist); }
.inspiration .news-card__media { aspect-ratio: 16 / 10; }
.inspiration .news-card__body { padding: clamp(1.15rem, 2.2vw, 1.6rem); gap: .45rem; }
.inspiration .news-card__eyebrow { font-size: .7rem; }
.inspiration .news-card__title { font-size: clamp(1.08rem, 1.5vw, 1.22rem); }
.inspiration .news-card__text { font-size: .95rem; }
.inspiration .eyebrow { font-size: .78rem; margin-bottom: 1rem; }
.inspiration .cat-card__placeholder { position: static; display: block; height: 100%; }

/* ---- inspiration panels ----
   The client asked for these to open in place, not as separate pages. Each tile
   links to its panel by id: WITHOUT JS the link is an ordinary jump and the
   panels read as content at the foot of the section; WITH JS the same panel
   opens as a modal (js sets role/aria-modal and moves focus). Nothing is ever
   hidden from a no-JS visitor. */
.inspo-panel { padding-top: clamp(1.5rem, 3vw, 2.5rem); }
.inspo-panel__dialog {
	position: relative; background: var(--paper);
	width: min(100% - 2 * var(--gutter), 780px); margin-inline: auto;
	border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
}
.inspo-panel__inner { padding: clamp(1.5rem, 3.5vw, 2.75rem); }
.inspo-panel__title { margin: 0 0 .9rem; font-size: clamp(1.4rem, 2.4vw, 1.9rem); }
.inspo-panel__body { max-width: none; }
.inspo-panel__body > *:last-child { margin-bottom: 0; }
.inspo-panel__body + .btn { margin-top: 1.5rem; }
.inspo-panel__close {
	position: absolute; top: .65rem; right: .65rem; z-index: 1;
	width: 44px; height: 44px; border: 0; border-radius: 999px; cursor: pointer;
	background: var(--mist); color: var(--ink); font-size: 1.6rem; line-height: 1;
	display: inline-flex; align-items: center; justify-content: center;
	transition: background .2s var(--ease), color .2s var(--ease);
}
.inspo-panel__close:hover { background: var(--red); color: #fff; }
/* The close button only means anything once the panel is a modal. */
html:not(.sfi-js) .inspo-panel__close { display: none; }

.sfi-js .inspo-panel { display: none; padding: 0; }
.sfi-js .inspo-panel.is-open {
	display: grid; place-items: center;
	position: fixed; inset: 0; z-index: 200;
	padding: clamp(1rem, 4vw, 3rem);
	background: rgba(20, 20, 22, .55);
	backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.sfi-js .inspo-panel.is-open .inspo-panel__dialog {
	width: min(100%, 780px); max-height: min(86vh, 900px); overflow: auto;
	box-shadow: var(--shadow-lg);
}
/* Body scroll lock while a panel is open. */
body.inspo-open { overflow: hidden; }

/* ---- "How to request…" steps ---- */
.request { padding: var(--section-y) 0; background: var(--paper); }
.request__grid { display: grid; gap: clamp(2rem, 4.5vw, 4rem); grid-template-columns: 1fr 1.05fr; align-items: start; }
.request__title { margin-bottom: 1.15rem; }
.request__body { font-size: 1.06rem; line-height: 1.7; }
.request__body p:last-child { margin-bottom: 1.5rem; }
.request__steps { list-style: none; counter-reset: sfi-step; margin: 0; padding: 0; display: grid; gap: clamp(.7rem, 1.4vw, 1rem); }
.request__step {
	counter-increment: sfi-step; position: relative;
	padding: 1.05rem 1.35rem 1.05rem 4rem;
	background: var(--linen); border: 1px solid rgba(28,28,28,.07);
	border-radius: var(--radius); line-height: 1.6;
}
.request__step::before {
	content: counter(sfi-step);
	position: absolute; left: 1.1rem; top: 1rem;
	width: 2.1rem; height: 2.1rem; border-radius: 999px;
	background: var(--red); color: #fff;
	font-family: var(--font-head); font-weight: 800; font-size: .95rem;
	display: grid; place-items: center;
}
.request__step p { margin: 0; }
.request__step p + p { margin-top: .5rem; }
@media (max-width: 860px) { .request__grid { grid-template-columns: 1fr; } }

/* ---- partner support: sales map + contact cards ----
   The three support blocks are NOT three equal things — the Regional Sales
   Manager map is the section's object and its task ("find your RSM"), the other
   two are short notes. So: one wide lead block with the map beside it, then a
   two-up card row underneath.

   The map is client-supplied. Until it arrives the frame holds its own height
   with a labelled placeholder, so the section reviews at full size and the
   hand-off is one image upload — no layout change. */
.support { padding: var(--section-y) 0; background: var(--mist); }
/* Guard against tan-on-tan if a page ever runs inspiration straight into this. */
.inspiration + .support { background: var(--paper); }
/* Centred heading → the three support blocks → the full-width map and the form
   under it. The blocks moved ABOVE the map on 2026-08-12 (client): they say who
   looks after a distributor, which reads better before the map that shows which
   of them covers your states. (2026-08-10 history: the sales-team copy that used
   to sit beside the map is the first of those three blocks.) */
.support .section-head { max-width: 68ch; margin-inline: auto; text-align: center; }
.support .section-head__intro { margin-inline: auto; }
.support__grid + .support__lead { margin-top: clamp(1.75rem, 4vw, 3rem); }
/* Title + how-to-use line over the map (client, 2026-08-12) — centred with the
   section head above it, since the map itself is full width. */
.support__map-head { text-align: center; margin-bottom: clamp(1rem, 2.5vw, 1.75rem); }
.support__map-title { margin: 0; font-size: clamp(1.35rem, 2.4vw, 1.85rem); letter-spacing: -.02em; }
.support__map-instruction {
	margin: .5rem auto 0; max-width: 52ch;
	color: color-mix(in srgb, var(--ink) 78%, transparent);
	font-size: clamp(1rem, 1.25vw, 1.1rem);
}
.support__map { margin: 0; }
.support__map-img {
	width: 100%; border-radius: var(--radius-lg);
	background: var(--paper); box-shadow: var(--shadow-sm);
}
.support__map-placeholder {
	display: grid; place-content: center; justify-items: center; gap: .75rem;
	aspect-ratio: 16 / 9; max-height: 420px; padding: 1.5rem; text-align: center;
	border: 2px dashed color-mix(in srgb, var(--charcoal) 45%, transparent);
	border-radius: var(--radius-lg); background: var(--linen); color: var(--charcoal);
}
.support__map-pin { width: 34px; height: 34px; color: var(--red); }
.support__map-placeholder-text {
	margin: 0; max-width: 24ch;
	font-family: var(--font-head); font-weight: 700; font-size: .82rem;
	letter-spacing: .12em; text-transform: uppercase; line-height: 1.5;
}
.support__map-note { margin: .9rem 0 0; font-size: .85rem; color: var(--charcoal); text-align: center; }
.support__grid { display: grid; gap: clamp(1rem, 2.2vw, 1.75rem); grid-template-columns: repeat(2, 1fr); }
.support__grid[data-count="1"] { grid-template-columns: 1fr; max-width: 640px; }
.support__grid[data-count="3"] { grid-template-columns: repeat(3, 1fr); }
.support-card {
	background: var(--paper); border: 1px solid rgba(28,28,28,.08);
	border-radius: var(--radius); box-shadow: var(--shadow-sm);
	padding: clamp(1.35rem, 2.6vw, 2rem);
	display: flex; flex-direction: column; align-items: flex-start;
}
.support-card__title { margin: 0 0 .6rem; font-size: clamp(1.15rem, 1.7vw, 1.35rem); }
.support-card__text { margin: 0; color: color-mix(in srgb, var(--ink) 78%, transparent); line-height: 1.65; }
.support-card__contact { list-style: none; margin: 1.15rem 0 0; padding: 0; display: grid; gap: .5rem; }
.support-card__contact-link {
	display: inline-flex; align-items: center; gap: .6rem;
	font-family: var(--font-head); font-weight: 700; font-size: .98rem;
	text-decoration: none; color: var(--ink); overflow-wrap: anywhere;
}
.support-card__contact-link .sfi-icon { flex: 0 0 auto; color: var(--red); }
.support-card__contact-link:hover { color: var(--red); }
.support-card__cta { margin-top: 1.15rem; }
@media (max-width: 900px) {
	.support__lead { grid-template-columns: 1fr; }
	.support__grid { grid-template-columns: 1fr !important; }
}

/* ---- RSM territory map ----
   Built from real state geometry rather than the client's exported slide, so it
   stays sharp at any width, reads on a phone, and every rep is real text.

   Selecting a territory HIGHLIGHTS — it never hides. Non-selected states dim,
   the matching rep card lifts, and the whole rep list stays on the page for
   search engines, assistants and anyone without JavaScript. */
.rsm { --rsm-blank: #DCD7CF; }
.rsm__stage {
	background: var(--paper); border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm); border: 1px solid rgba(28,28,28,.07);
	padding: clamp(.75rem, 2vw, 1.5rem);
}
.rsm__canvas { position: relative; }
.rsm__svg { width: 100%; height: auto; display: block; }
/* --terr-tint is set inline, per state, by render-rsm-map.php. It has to be a
   custom property rather than a fill=" attribute: a presentation attribute is
   the weakest thing in the cascade and this very rule used to beat it, which
   painted all 51 states the same grey and left the resting map with no
   territory colours at all. --rsm-blank is the fallback, so a state nobody
   covers still reads as unassigned. */
.rsm__state {
	fill: var(--terr-tint, var(--rsm-blank)); stroke: var(--paper); stroke-width: 1;
	stroke-linejoin: round;
	transition: opacity .25s var(--ease), filter .25s var(--ease);
}
.rsm__state[data-territory] { cursor: pointer; }
.rsm__label, .rsm__leader-label {
	font-family: var(--font-head); font-weight: 700; font-size: 11px;
	letter-spacing: .02em; text-anchor: middle; pointer-events: none;
	paint-order: stroke;
}
.rsm__leader-label { text-anchor: start; fill: var(--ink); font-size: 10.5px; }
.rsm__leader { stroke: color-mix(in srgb, var(--charcoal) 60%, transparent); stroke-width: .8; }
.rsm__chip { stroke: var(--paper); stroke-width: 1; }

/* Hover reads as "this whole territory", not "this one state". */
.rsm:not([data-active]) .rsm__state[data-territory]:hover { filter: brightness(1.08); }
.rsm[data-active] .rsm__state:not([data-territory]),
.rsm[data-active] .rsm__state[data-territory] { opacity: .28; }
.rsm[data-active] .rsm__state[data-territory].is-active {
	opacity: 1; fill: var(--terr, currentColor); stroke: var(--charcoal); stroke-width: .7;
	filter: drop-shadow(0 2px 6px rgba(28,28,28,.28));
}
/* The selected territory fills with the rep's OWN colour (client, 2026-08-28:
   "didn't the map light up in the RSM's colour?"). The resting map keeps the
   legible tint; only the chosen region goes full strength, so its label flips
   to whichever of ink/white reads on that colour. */
.rsm[data-active] .rsm__label.is-active { fill: var(--terr-ink, #1A1A1A); }
.rsm[data-active] .rsm__label:not(.is-active),
.rsm[data-active] .rsm__leaders :not(.is-active) { opacity: .3; }

/* ---- pins ----
   Client (2026-08-10) asked for the names on the map as tooltips rather than a
   list underneath, with a placeholder person image until headshots arrive.

   The card is hidden, not absent: it is real markup in the HTML, so the rep's
   name, contact details and full state list are still there for search engines
   and assistants. It opens on hover AND on focus-within, which means it also
   works with no JavaScript at all — including on touch, where tapping the
   button focuses it. */
.rsm__pin {
	position: absolute; left: var(--pin-x); top: var(--pin-y);
	transform: translate(-50%, -50%); z-index: 2;
}
/* An open card lifts its whole pin above the neighbours, so the card box paints
   over any avatar it overlaps rather than under it (client, 2026-08-28: clicking
   Kevin put Tina's face inside his box — her pin sits where his card opens). */
.rsm__pin:hover, .rsm__pin:focus-within, .rsm__pin.is-active { z-index: 10; }
.rsm__pin-btn {
	display: block; padding: 0; cursor: pointer; border: 0; background: none;
	border-radius: 999px; line-height: 0;
	transition: transform .25s var(--ease);
}
.rsm__pin-avatar {
	position: relative; display: grid; place-items: center;
	width: clamp(34px, 4.2vw, 54px); aspect-ratio: 1; border-radius: 999px;
	background: var(--paper); border: 3px solid var(--pin-color, var(--red));
	box-shadow: 0 6px 16px -6px rgba(28,28,28,.6);
	color: color-mix(in srgb, var(--charcoal) 85%, transparent);
}
.rsm__pin-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 999px; }
/* No headshot on file: initials on the territory's own colour, so the pin still
   reads as that person's pin without putting a stranger's face under their name. */
.rsm__pin-avatar--initials { background: var(--pin-color, var(--red)); }
.rsm__pin-initials {
	font-family: var(--font-head); font-weight: 800; letter-spacing: .01em;
	font-size: clamp(.72rem, 1.5vw, .95rem); line-height: 1;
	color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.25);
}
.rsm__pin-avatar > .sfi-icon, .rsm__pin-avatar > img { border-radius: 999px; }

.rsm__pin-btn:hover, .rsm__pin-btn:focus-visible { transform: scale(1.08); }

.rsm__card {
	position: absolute; left: 50%; bottom: calc(100% + 14px);
	transform: translateX(-50%) translateY(6px);
	width: max-content; max-width: 270px; z-index: 3;
	padding: .85rem 1rem; text-align: left;
	background: var(--paper); border-radius: var(--radius);
	border: 1px solid rgba(28,28,28,.1); box-shadow: var(--shadow-md);
	opacity: 0; visibility: hidden; pointer-events: none;
	transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
}
.rsm__pin:hover .rsm__card,
.rsm__pin:focus-within .rsm__card,
.rsm__pin.is-active .rsm__card {
	opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.rsm__card::after {
	content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
	border: 8px solid transparent; border-top-color: var(--paper);
}
.rsm__card-name { margin: 0; font-family: var(--font-head); font-weight: 800; font-size: 1rem; }
.rsm__card-title { margin: .1rem 0 0; font-size: .78rem; color: var(--charcoal); }
.rsm__card-contact { list-style: none; margin: .6rem 0 0; padding: 0; display: grid; gap: .3rem; }
.rsm__card-contact a {
	display: inline-flex; align-items: center; gap: .45rem;
	font-family: var(--font-head); font-weight: 700; font-size: .82rem;
	color: var(--ink); text-decoration: none; overflow-wrap: anywhere;
}
.rsm__card-contact a:hover { color: var(--red); }
.rsm__card-contact .sfi-icon { width: 15px; height: 15px; flex: 0 0 auto; color: var(--red); }
.rsm__card-states { margin: .55rem 0 0; font-size: .76rem; line-height: 1.5; color: color-mix(in srgb, var(--ink) 70%, transparent); }

/* Below ~860px the map is narrower than ~800px, so an 11px label in a 1000-unit
   viewBox paints at 8px or less — past legible however it is scaled. The labels
   come off and the map becomes a coloured overview. The pins stay: they are the
   interface, and their cards drop to the foot of the map where there is room. */
@media (max-width: 860px) {
	.rsm__stage { padding: .5rem; }
	.rsm__labels, .rsm__leaders { display: none; }
	.rsm__card {
		position: fixed; left: 50%; bottom: 1rem; top: auto;
		transform: translateX(-50%) translateY(6px);
		width: min(92vw, 340px); max-width: none; z-index: 60;
	}
	.rsm__pin:hover .rsm__card,
	.rsm__pin:focus-within .rsm__card,
	.rsm__pin.is-active .rsm__card { transform: translateX(-50%) translateY(0); }
	.rsm__card::after { display: none; }
}

/* ---- "Contact your Regional Sales Manager" ----
   Sits directly under the map. Collapsed behind its button until asked for, so
   a long page doesn't end up with a full form nailed to the middle of it — the
   client's words were "if they want to reach out, it opens a form". A
   <details>, which means it opens with JS off and the state is announced for
   free, exactly like the FAQs. */
.rsm-contact { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
/* Two disclosure cards, stacked (client, 2026-08-20: a second button beneath the
   routed one, for national non-commercial enquiries). Separate cards rather than
   two buttons in one, because each opens its own form and the open panel has to
   sit directly under the button that opened it. */
.rsm-contact__box + .rsm-contact__box { margin-top: .85rem; }
/* The national desk is the secondary route — same card, quieter button, so the
   distributor's own RSM stays the obvious first choice. */
.rsm-contact__box--natl .rsm-contact__summary-btn {
	background: transparent; color: var(--red);
	border: 1.5px solid color-mix(in srgb, var(--red) 45%, transparent); box-shadow: none;
}
.rsm-contact__box--natl .rsm-contact__summary:hover .rsm-contact__summary-btn {
	background: var(--red); border-color: var(--red); color: #fff;
}
.rsm-contact__box {
	background: var(--paper); border: 1px solid rgba(28,28,28,.1);
	border-radius: var(--radius-lg); overflow: hidden;
}
.rsm-contact__box[open] { box-shadow: var(--shadow-sm); }
.rsm-contact__summary {
	display: flex; flex-wrap: wrap; align-items: center; gap: .85rem 1.25rem;
	padding: clamp(1rem, 2.2vw, 1.5rem); cursor: pointer; list-style: none;
}
.rsm-contact__summary::-webkit-details-marker { display: none; }
.rsm-contact__summary::marker { content: ""; }
/* The button is a <span>: a real <button> inside <summary> swallows the click
   that is supposed to toggle the details. */
.rsm-contact__summary-btn { pointer-events: none; }
.rsm-contact__summary-hint { font-size: .86rem; color: var(--charcoal); }
.rsm-contact__box[open] .rsm-contact__summary-hint { display: none; }
.rsm-contact__summary:focus-visible { outline: 3px solid var(--red); outline-offset: -3px; }
/* Full width inside the card (client, 2026-08-11) — the panel used to cap at
   62rem, which left the fields stopping short of the card's own edge and read
   as a mistake. The intro keeps a readable measure of its own below. */
.rsm-contact__panel {
	padding: 0 clamp(1rem, 2.2vw, 1.5rem) clamp(1.25rem, 2.5vw, 1.75rem);
}
.rsm-contact__intro { margin: 0 0 1.25rem; max-width: 62ch; color: color-mix(in srgb, var(--ink) 82%, transparent); }
.rsm-contact__notice {
	margin: 0 0 1.25rem; padding: .9rem 1.1rem; border-radius: var(--radius);
	font-family: var(--font-head); font-weight: 600; font-size: .95rem; line-height: 1.5;
	border-left: 4px solid;
}
.rsm-contact__notice--success { background: color-mix(in srgb, var(--green) 12%, #fff); border-color: var(--green); }
.rsm-contact__notice--error { background: color-mix(in srgb, var(--red) 9%, #fff); border-color: var(--red); }

/* Two columns by default; three once the card is wide enough, so a full-width
   form doesn't turn "Phone" into a 580px slot. Message always spans the row. */
.rsm-form__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem 1.25rem; }
@media (min-width: 1080px) {
	.rsm-form__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.rsm-form__field { margin: 0; display: flex; flex-direction: column; gap: .35rem; }
.rsm-form__field--wide { grid-column: 1 / -1; }
.rsm-form__field label {
	font-family: var(--font-head); font-weight: 700; font-size: .82rem;
	letter-spacing: .02em; color: var(--ink);
}
.rsm-form__req { color: var(--red); }
.rsm-form__opt { font-weight: 500; color: var(--charcoal); }
.rsm-form__field input, .rsm-form__field select, .rsm-form__field textarea {
	font-family: var(--font-body); font-size: 1rem; color: var(--ink);
	padding: .7rem .85rem; border-radius: 10px; background: var(--linen);
	border: 1.5px solid rgba(28,28,28,.16); width: 100%;
	transition: border-color .2s var(--ease), background .2s var(--ease);
}
.rsm-form__field textarea { resize: vertical; min-height: 7.5rem; }
.rsm-form__field :is(input, select, textarea):focus-visible {
	outline: none; background: var(--paper);
	border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 22%, transparent);
}
/* Off-screen rather than display:none — enough bots skip hidden inputs that a
   honeypot they can't see but can find is worth the two lines. */
.rsm-form__hp {
	position: absolute !important; width: 1px; height: 1px;
	overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.rsm-form__route {
	margin: 1rem 0 0; min-height: 1.5rem;
	font-family: var(--font-head); font-weight: 700; font-size: .9rem; color: var(--ink);
}
.rsm-form__route:empty { margin: 0; min-height: 0; }
.rsm-form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: .85rem 1.25rem; margin-top: 1.25rem; }
.rsm-form__privacy { font-size: .82rem; color: var(--charcoal); }
.rsm-form .cf-turnstile { margin-top: 1.25rem; }
@media (max-width: 700px) {
	.rsm-form__grid { grid-template-columns: 1fr; }
}

/* ---- FAQs ----
   Native <details>/<summary>, so questions open with JavaScript off and the
   expanded state is announced without any ARIA of our own. Grouped because the
   client's copy arrives in named sets; the set heading sticks alongside its
   questions on wide screens.

   Linen rather than mist or white: this section can follow either, and a third
   near-neutral keeps it separate from both. */
.faqs { padding: var(--section-y) 0; background: var(--linen); }
.faqs__group { display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 2fr); gap: clamp(1.25rem, 3vw, 3rem); }
.faqs__group + .faqs__group { margin-top: clamp(2rem, 4vw, 3.25rem); }
.faqs__group-title {
	margin: 0; align-self: start; position: sticky; top: 6.5rem;
	font-size: clamp(1.15rem, 1.8vw, 1.45rem);
}
.faqs__list { display: grid; gap: .75rem; }
.faq {
	background: var(--paper); border: 1px solid rgba(28,28,28,.09);
	border-radius: var(--radius); overflow: hidden;
	transition: box-shadow .3s var(--ease), border-color .3s var(--ease);
}
.faq[open], .faq:hover { box-shadow: var(--shadow-sm); border-color: rgba(28,28,28,.16); }
.faq__q {
	display: flex; align-items: center; justify-content: space-between; gap: 1rem;
	padding: 1.05rem clamp(1rem, 2vw, 1.5rem); cursor: pointer;
	font-family: var(--font-head); font-weight: 700; font-size: 1rem;
	line-height: 1.4; letter-spacing: -.01em; list-style: none;
}
/* Safari/Chrome still paint their own marker without these. */
.faq__q::-webkit-details-marker { display: none; }
.faq__q::marker { content: ""; }
.faq__q:hover { color: var(--red); }
.faq[open] .faq__q { color: var(--red); }
.faq__icon { flex: 0 0 auto; transition: transform .3s var(--ease); }
.faq[open] .faq__icon { transform: rotate(180deg); }
.faq__a {
	padding: 0 clamp(1rem, 2vw, 1.5rem) 1.25rem;
	max-width: 68ch; line-height: 1.7;
}
.faq__a > *:last-child { margin-bottom: 0; }
/* Some answers list facilities (warehouses, addresses) — the global reset strips
   list styling, so give it back here rather than sitewide. */
.faq__a ul { margin: .35rem 0 1rem; padding-left: 1.1rem; list-style: disc; }
.faq__a li { margin-bottom: .35rem; }
.faq__a li::marker { color: color-mix(in srgb, var(--red) 60%, transparent); }
.faq__a p + p { margin-top: .85rem; }
@media (max-width: 860px) {
	.faqs__group { grid-template-columns: 1fr; }
	.faqs__group-title { position: static; }
}

/* ---- closing CTA band ---- */
.cta-band { background: var(--cream); padding: clamp(2.25rem, 5vw, 3.75rem) 0; }
.cta-band__inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.25rem 2.5rem; }
.cta-band__title { margin: 0; max-width: 26ch; font-size: clamp(1.35rem, 2.5vw, 2rem); }

/* =====================================================================
   PRODUCT CATEGORY PAGES
   The layout from the client's marketing-manager concepts: photo banner with
   the category name over it → "About our…" copy beside photography → the item
   grid with pack specs and spec-sheet links → a full-bleed strip of the product
   in use → "you might also like". One template serves every category.
   ===================================================================== */
.cat-banner {
	position: relative; isolation: isolate;
	min-height: clamp(190px, 26vw, 320px);
	display: flex; align-items: center;
	background: var(--sand); overflow: hidden;
}
.cat-banner__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
/* The category name sits on photography that we don't control the tone of, so
   the scrim is not optional — it is what guarantees the contrast ratio. */
.cat-banner::after {
	content: ""; position: absolute; inset: 0; z-index: -1;
	background: linear-gradient(180deg, rgba(20,20,20,.15) 0%, rgba(20,20,20,.55) 100%);
}
.cat-banner--plain { background: var(--cream); }
.cat-banner--plain::after { display: none; }
/* DESIGN NOTE: the banner name is CENTRED over the photo, as in the client's
   concepts (Black (Ripe) Olives, Specialty Olives, Quinoa are all centred on
   their banner). Same rule as the catalogue header above: a band with nothing
   beside it centres; a band paired with an image or a map keeps its copy on the
   content edge.
   `padding-block`, NOT the padding shorthand, and no `width` — both would beat
   `.wrap` on specificity order and cost the gutter, which is what put this text
   hard against the left edge of the screen (fixed 2026-08-11). Anything that
   also carries `.wrap` must leave width and inline padding alone. */
.cat-banner__inner { position: relative; padding-block: clamp(2rem, 5vw, 3.5rem); text-align: center; }
.cat-banner .cat-crumbs { justify-content: center; }
.cat-banner__title {
	margin: .35rem 0 0; color: #fff;
	font-size: clamp(1.9rem, 4.4vw, 3rem); letter-spacing: -.03em;
	text-shadow: 0 2px 20px rgba(0,0,0,.35);
}
.cat-banner--plain .cat-banner__title { color: var(--ink); text-shadow: none; }
/* Breadcrumbs default to ink-on-light with the brand red on hover, like every
   other link on the site. They only go white where they sit ON a photo — the
   white was previously the default, which made the hover state invisible
   wherever the crumbs run on a white page (client spotted it on a product
   page, 2026-08-11). Red on the photo scrim is not readable enough, so that
   one case keeps white. */
.cat-crumbs { display: flex; flex-wrap: wrap; gap: .5rem; font-family: var(--font-head); font-size: .78rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.cat-crumbs a { color: var(--charcoal); text-decoration: none; }
.cat-crumbs a:hover { color: var(--red); text-decoration: underline; }
.cat-crumbs span { color: var(--beige); }
.cat-banner:not(.cat-banner--plain) .cat-crumbs a { color: rgba(255,255,255,.9); }
.cat-banner:not(.cat-banner--plain) .cat-crumbs a:hover { color: #fff; }
.cat-banner:not(.cat-banner--plain) .cat-crumbs span { color: rgba(255,255,255,.55); }

.cat-about { padding: var(--section-y) 0; background: var(--paper); }
.cat-about__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .85fr); gap: clamp(1.5rem, 4vw, 3.5rem); align-items: start; }
/* No photos on this category yet — so the copy has no partner column and the
   rule applies again: constrained + alone → centre it. Left in a 1fr column
   next to an empty one it reads as a layout that failed to load. */
.cat-about--solo .cat-about__grid { grid-template-columns: 1fr; max-width: 56rem; margin-inline: auto; text-align: center; }
.cat-about--solo .cat-about__body { margin-inline: auto; }
.cat-about__copy h2 { margin-top: 0; font-size: clamp(1.5rem, 2.6vw, 2.1rem); }
.cat-about__body { max-width: 60ch; }
.cat-about__body p { margin-bottom: 1rem; }
.cat-about__media { display: grid; gap: 1rem; }
.cat-about__media[data-count="3"] { grid-template-columns: 1fr 1fr; }
.cat-about__media[data-count="3"] .cat-about__img:first-child { grid-column: 1 / -1; }
.cat-about__img { width: 100%; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); aspect-ratio: 3 / 2; object-fit: cover; }

.cat-items, .cat-children { padding: var(--section-y) 0; background: var(--mist); }
.cat-items__heading { margin: 0 0 clamp(1.25rem, 3vw, 2rem); font-size: clamp(1.5rem, 2.8vw, 2.15rem); }
.cat-items__grid, .cat-children__grid {
	display: grid; gap: clamp(1rem, 2.2vw, 1.75rem);
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	list-style: none; margin: 0; padding: 0;
}

/* One SKU. The pack shot sits on white and is CONTAINED, never cropped — some
   of these are transparent cut-outs and some are shot on white, and a cover
   crop would slice the top off a gallon jar. */
.spec-card {
	display: flex; flex-direction: column;
	background: var(--paper); border: 1px solid rgba(28,28,28,.09);
	border-radius: var(--radius); overflow: hidden;
	transition: box-shadow .3s var(--ease), transform .3s var(--ease);
}
.spec-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
/* DESIGN NOTE (client, 2026-08-11): every pack shot gets the SAME fixed-height
   stage and is contained inside it, so a 4/1 gallon jar and a squat 14oz can
   line up across a row instead of each card sizing itself to its own photo.
   Two things had to change to get there:
     · an `aspect-ratio` box does NOT hold inside a flex column — the flex item's
       default `min-height: auto` lets a tall portrait image push straight past
       it, which is what made the jars twice the height of the cans;
     · `max-width/max-height` rather than `width/height: 100%`, so a small source
       image is never upscaled into a blurry mess to fill the stage.
   The stage is deliberately shallower than the tallest jar: contained shots read
   as a set, and the dead space above a short can is the price of that. */
.spec-card__media {
	display: grid; place-items: center; overflow: hidden;
	height: clamp(170px, 17vw, 220px); flex: 0 0 auto; min-height: 0;
	padding: .9rem; background: var(--paper); border-bottom: 1px solid rgba(28,28,28,.07);
}
/* `height: 100%` + `object-fit: contain`, NOT `max-height: 100%`. A grid or
   flex item's automatic minimum size is its intrinsic height, so max-height
   cannot shrink a 1500px-tall jar — it just overflowed the stage and ran over
   the card text. Resolving against the stage's now-definite height is what
   actually clamps it; `min-height: 0` disables that automatic minimum, and the
   overflow rule is the backstop. */
.spec-card__img { width: 100%; height: 100%; min-width: 0; min-height: 0; object-fit: contain; }
.spec-card__placeholder { display: block; width: 100%; height: 100%; background: var(--mist); border-radius: var(--radius); }
.spec-card__body { display: flex; flex-direction: column; flex: 1; padding: 1rem clamp(1rem, 1.6vw, 1.25rem) 1.15rem; }
.spec-card__title { margin: 0; font-size: .98rem; line-height: 1.35; letter-spacing: -.01em; }
.spec-card__title a { color: var(--ink); text-decoration: none; }
.spec-card__title a:hover { color: var(--red); }
.spec-card__id {
	margin: .4rem 0 .7rem; display: flex; flex-wrap: wrap; gap: .4rem;
	font-family: var(--font-head); font-weight: 700; font-size: .82rem; color: var(--red);
}
.spec-card__id span[aria-hidden] { color: var(--beige); }
.spec-card__pack { color: var(--charcoal); }
.spec-card__specs { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .28rem; font-size: .82rem; color: color-mix(in srgb, var(--ink) 74%, transparent); }
.spec-card__specs li { padding-left: .85rem; position: relative; }
.spec-card__specs li::before { content: ""; position: absolute; left: 0; top: .55em; width: 4px; height: 4px; border-radius: 50%; background: var(--beige); }
/* Brand is identity, not a spec — same bullet, but it reads at full ink so the
   eye lands on it first in a mixed category (Mandarins and Pears carry both
   Ambrosia and Horn of Plenty; 14 of the 48 sub-categories are mixed). */
.spec-card__brand { color: var(--ink); font-weight: 600; }
.spec-card__brand::before { background: var(--red); }
.spec-card__spec {
	margin-top: auto; display: inline-flex; align-items: center; gap: .45rem;
	font-family: var(--font-head); font-weight: 700; font-size: .78rem;
	letter-spacing: .07em; text-transform: uppercase; color: var(--red); text-decoration: none;
}
.spec-card__spec .sfi-icon { width: 16px; height: 16px; }
.spec-card__spec:hover { color: var(--red-dark); text-decoration: underline; }
.spec-card__spec--soon { color: var(--charcoal); text-transform: none; letter-spacing: .02em; font-weight: 500; }

.cat-child__link { display: grid; gap: .6rem; text-decoration: none; color: var(--ink); }
/* position:relative is LOAD-BEARING. The placeholder inside is .cat-card__placeholder,
   which is position:absolute;inset:0 — written for .cat-card__media, which is
   positioned. Without it the placeholder resolved against .cat-child instead
   (`.reveal` sets `will-change: transform`, and that alone makes an element a
   containing block for absolutely positioned descendants, permanently — even
   once the transform is `none`), so the tile art painted over the label and the
   item count on every sub-category without a photo. Found 2026-08-24 on the
   Fruits page: eight tiles, no captions. */
.cat-child__media { position: relative; display: block; aspect-ratio: 1; border-radius: var(--radius-lg); overflow: hidden; background: var(--paper); }
.cat-child__img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.cat-child__link:hover .cat-child__img { transform: scale(1.05); }
.cat-child__label { font-family: var(--font-head); font-weight: 800; font-size: 1.05rem; }
.cat-child__link:hover .cat-child__label { color: var(--red); }
.cat-child__count { font-size: .8rem; color: var(--charcoal); }

/* ---- parent category browse: copy + tiles as ONE section ----
   Client, 2026-08-20: the standalone copy band below the olives hero "looked by
   itself" — make it read like the home page's "Our Products / Browse the
   Product Catalogue" block. So it reuses .categories wholesale and only
   re-states what differs: the head carries a paragraph of real copy rather than
   home's single line, so it needs a reading measure and a little more air under
   it, and the grid is auto-fill (three sub-categories, not ten categories) so a
   short row does not stretch into three enormous tiles. */
.cat-browse .categories__head { align-items: flex-end; }
.cat-browse__intro {
	max-width: 68ch; margin: 1rem 0 0;
	font-size: clamp(1rem, 1.2vw, 1.08rem); line-height: 1.7;
	color: color-mix(in srgb, var(--ink) 80%, transparent);
}
.cat-browse__intro p { margin: 0 0 .9rem; }
.cat-browse__intro p:last-child { margin-bottom: 0; }
.cat-browse__grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
/* A lifestyle photo in the tile row is a picture, not a destination: same square
   media box so the row stays level, no label weight, no hover lift. */
.cat-child__figure { margin: 0; display: grid; gap: .6rem; }
.cat-child--photo .cat-child__media { box-shadow: var(--shadow-sm); }
.cat-child__caption { font-size: .82rem; line-height: 1.5; color: var(--charcoal); }

/* Edge to edge, exactly as drawn: the dishes are the payoff, not a gallery. */
.cat-uses__strip { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; list-style: none; margin: 0; padding: 0; }
.cat-uses__item { margin: 0; }
.cat-uses__img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
@media (max-width: 700px) {
	.cat-uses__strip { grid-auto-columns: 62%; overflow-x: auto; scroll-snap-type: x mandatory; }
	.cat-uses__item { scroll-snap-align: start; }
}

/* DESIGN NOTE (client, 2026-08-11): the footer curve is filled with the colour
   of the section ABOVE it — that is what makes it read as a valley cut out of
   that section rather than a white shape floating on top of it. The default
   fill is paper, which is only right when the page ends on white; these pages
   end on linen or mist depending on which sections rendered. Rather than
   hard-code a fill per template, match on whichever section actually ends the
   page, so a category with no related terms or a product with no siblings still
   lines up. Add a rule here whenever a new section can end a page.
   The existing per-template cases are `.front` (mist) and `.audience` (cream). */
/* ---- section rhythm on a category page ----
   The warm tints are deliberately close together — cream #F7F1E8 and mist
   #F5F2EE differ by SIX of 255, linen sits between them — so any two of them
   touching reads as a smudge rather than as two sections, and the curve
   divider between them disappears. White is the only real step in the palette.
   Hence the rule the approved pages already follow: NEVER let two tints touch,
   put white between them.

   Positional rather than per-component, because the same sections appear in
   different slots — .cat-items is the first band on a leaf category and the
   second on a parent. First band under the cream hero is always white, the
   second tinted, the third white again. */
.category-page .hero-anchor + section { background: var(--paper); }
.category-page .hero-anchor + section + section { background: var(--mist); }
.category-page .hero-anchor + section + section + section { background: var(--paper); }
/* Extended 2026-08-19: the category's copy moved out of the hero into a section
   of its own, so a parent page can now run to five bands — copy, tiles, items,
   also-bought, photography. Alternating white/tint by POSITION is what keeps
   two tints from ever touching whatever shape the page takes, and a category
   with no copy simply starts the chain one step earlier. */
.category-page .hero-anchor + section + section + section + section { background: var(--linen); }
.category-page .hero-anchor + section + section + section + section + section { background: var(--paper); }
/* First band is white, so the hero's curve keeps the paper default. */

/* A page that ENDS on the full-bleed dish photos gets NO footer curve. The
   valley is filled with whatever sits above it, and above it is photography —
   there is no flat colour to match, so any fill reads as a stray white shape
   floating over the pictures. A full-bleed image meeting the dark footer wants
   a hard edge, not a divider. */
.category-page:has(> .cat-uses:last-child) + .site-footer .sfi-curve--footer { display: none; }

/* The footer valley is filled with the last band, so it follows the same
   positional rhythm rather than naming components that move between slots. */
.category-page:has(> .hero-anchor + section:last-child) + .site-footer,
.category-page:has(> .hero-anchor + section + section + section:last-child) + .site-footer,
.category-page:has(> .hero-anchor + section + section + section + section + section:last-child) + .site-footer { --footer-curve-fill: var(--paper); }
.category-page:has(> .hero-anchor + section + section:last-child) + .site-footer { --footer-curve-fill: var(--mist); }
.category-page:has(> .hero-anchor + section + section + section + section:last-child) + .site-footer { --footer-curve-fill: var(--linen); }
.product-single:has(> .cat-items:last-child) + .site-footer { --footer-curve-fill: var(--mist); }

.cat-empty { padding: var(--section-y) 0; background: var(--mist); }
/* Same rule as the banner above it — constrained and alone, so centred. */
.cat-empty__inner { max-width: 46rem; margin-inline: auto; text-align: center; }
.cat-empty h2 { margin-top: 0; font-size: clamp(1.4rem, 2.6vw, 2rem); }
.cat-empty p { color: color-mix(in srgb, var(--ink) 80%, transparent); }
.cat-empty__actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 1rem 1.75rem; margin-top: 1.5rem; }

/* "Customers Also Bought" (client, 2026-08-19 — was "You might also like").
   It points at single PRODUCTS now, and the client asked for the images to be
   "a bit bigger". Bigger meant a change of shape as well as size: a 140px
   roundel is a category token, and cropping a gallon jar into a circle is not
   a product photograph. So these are square cards at roughly the item grid's
   own tile size, with the pack shot CONTAINED on white — the same treatment,
   and the same reasoning, as .spec-card__media. */
.cat-related { padding: var(--section-y) 0; background: var(--linen); }
.cat-related__heading { margin: 0 0 clamp(1.25rem, 3vw, 2rem); text-align: center; font-size: clamp(1.1rem, 2vw, 1.4rem); letter-spacing: .04em; text-transform: uppercase; }
.cat-related__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: clamp(1.25rem, 3vw, 2.25rem); list-style: none; margin: 0; padding: 0; }
.cat-related__item a { display: grid; justify-items: center; gap: .7rem; text-decoration: none; color: var(--ink); text-align: center; }
.cat-related__media {
	display: grid; place-items: center; width: 100%; max-width: 260px; aspect-ratio: 1;
	padding: 1rem; border-radius: var(--radius-lg); overflow: hidden;
	background: var(--paper); box-shadow: var(--shadow-sm);
	transition: box-shadow .3s var(--ease), transform .3s var(--ease);
}
.cat-related__item a:hover .cat-related__media { box-shadow: var(--shadow-md); transform: translateY(-3px); }
/* contain, not cover: these are cut-outs and shots-on-white of wildly different
   proportions, and a cover crop slices the lid off the tall ones. */
.cat-related__media img { width: 100%; height: 100%; min-width: 0; min-height: 0; object-fit: contain; }
.cat-related__media .spec-card__placeholder { border-radius: var(--radius); }

/* ---------- photography placeholder ----------
   Sits on TOP of each component's own placeholder box (it keeps that class, so
   the box keeps its size, radius and — for .cat-card__placeholder — its
   absolute positioning). All this adds is what goes inside: the Ambrosia mark
   for Ambrosia's own items, the brand's name for the fifty-one items that are
   somebody else's. Muted rather than full strength: at full red, a grid of
   twelve of these reads as twelve copies of one product. */
.spec-card__placeholder.sfi-ph,
.card__placeholder.sfi-ph,
.cat-card__placeholder.sfi-ph {
	display: grid; place-items: center; padding: 14%;
	background: linear-gradient(135deg, var(--sand), var(--mist));
}
.sfi-ph__mark {
	width: 100%; max-width: 210px; height: auto;
	opacity: .34; mix-blend-mode: multiply;
}
.sfi-ph__brand {
	font-family: var(--font-head); font-weight: 700;
	font-size: clamp(.78rem, 1.5vw, .98rem); letter-spacing: .08em;
	text-transform: uppercase; text-align: center; text-wrap: balance;
	color: color-mix(in srgb, var(--charcoal) 70%, transparent);
}
/* The single-product stage is the one place a placeholder gets a lot of room. */
.product-single__media .sfi-ph__mark { max-width: 260px; }
.cat-related__label { font-family: var(--font-head); font-weight: 700; font-size: .9rem; line-height: 1.35; letter-spacing: .02em; }
.cat-related__item a:hover .cat-related__label { color: var(--red); }
.cat-related__sku { font-family: var(--font-head); font-weight: 700; font-size: .78rem; color: var(--red); }

@media (max-width: 900px) {
	.cat-about__grid { grid-template-columns: 1fr; }
	.cat-about__media { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
	.cat-about__media[data-count="3"] .cat-about__img:first-child { grid-column: auto; }
}

/* ---- catalogue overview + search ----
   The client asked for search to be "really sophisticated and prominent", so on
   the catalogue it is the first thing under the headline rather than an icon in
   the corner. */
/* DESIGN NOTE (client, 2026-08-11): this header is CENTRED, not left-aligned.
   The rest of the site aligns copy to the content edge because it always has a
   second element to sit against — a hero photo, a map, an image column. This
   band has nothing beside it: it is a headline, a line of intro and a search
   field, capped at 54rem inside a 1200px wrap. Left-aligned, that cap reads as
   a column that lost its partner, with dead space to the right of everything.
   Centred, the cap reads as deliberate. So the rule is: constrained + alone →
   centre it; constrained + paired with something → keep it on the content edge.
   If this band ever gains a right-hand element, take the centring back off. */
.catalogue-hero { position: relative; background: var(--cream); padding: clamp(2.25rem, 5vw, 4rem) 0 clamp(3rem, 6vw, 4.5rem); }
.catalogue-hero__inner { max-width: 54rem; margin-inline: auto; text-align: center; }
.catalogue-hero h1 { margin: .35rem 0 .75rem; font-size: clamp(1.9rem, 4vw, 2.9rem); letter-spacing: -.03em; }
.catalogue-hero__intro { font-size: clamp(1.02rem, 1.35vw, 1.2rem); line-height: 1.6; max-width: 60ch; margin-inline: auto; color: color-mix(in srgb, var(--ink) 82%, transparent); }
.catalogue-hero__count { margin: 0 0 1.25rem; color: var(--charcoal); font-family: var(--font-head); font-weight: 600; }

/* The field itself keeps left-aligned input text — centred text in a search box
   fights the cursor — but the box and its hint centre with the rest. */
.cat-search { position: relative; margin: 1.5rem auto 0; max-width: 44rem; text-align: left; }
.cat-search__row {
	display: flex; align-items: center; gap: .5rem;
	background: var(--paper); border: 2px solid rgba(28,28,28,.14);
	border-radius: 999px; padding: .35rem .35rem .35rem 1rem;
	transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.cat-search__row:focus-within { border-color: var(--red); box-shadow: 0 0 0 4px color-mix(in srgb, var(--red) 16%, transparent); }
.cat-search__icon { flex: 0 0 auto; color: var(--charcoal); }
.cat-search__row input[type="search"] {
	flex: 1; min-width: 0; border: 0; background: none; outline: none;
	font-family: var(--font-body); font-size: 1.02rem; padding: .65rem .25rem; color: var(--ink);
}
.cat-search__row input[type="search"]::-webkit-search-cancel-button { cursor: pointer; }
.cat-search__submit { flex: 0 0 auto; padding: .7rem 1.5rem; min-height: 44px; font-size: .9rem; }
.cat-search__hint { margin: .55rem 0 0 1rem; font-size: .82rem; color: var(--charcoal); }

/* Suggestions. Positioned over the page, so the list can be long without the
   layout jumping every keystroke. */
.cat-search__results {
	position: absolute; top: calc(100% + .4rem); left: 0; right: 0; z-index: 20;
	list-style: none; margin: 0; padding: .35rem;
	background: var(--paper); border: 1px solid rgba(28,28,28,.12);
	border-radius: var(--radius); box-shadow: var(--shadow-md);
	max-height: 22rem; overflow-y: auto;
}
.cat-search__result a { display: grid; grid-template-columns: 40px 1fr auto; align-items: center; gap: .75rem; padding: .5rem .6rem; border-radius: 10px; text-decoration: none; color: var(--ink); }
.cat-search__result a:hover, .cat-search__result[aria-selected="true"] a { background: var(--mist); }
.cat-search__result img, .cat-search__blank { width: 40px; height: 40px; object-fit: contain; border-radius: 6px; background: var(--mist); }
.cat-search__name { font-family: var(--font-head); font-weight: 700; font-size: .88rem; line-height: 1.3; }
.cat-search__meta { font-size: .78rem; color: var(--charcoal); white-space: nowrap; }

/* ---- dropdowns ----
   One look for every <select> on the site — the catalogue facets, the contact
   form, anything added later. Native selects are styled inconsistently across
   platforms and the default chevron is the giveaway, so `appearance: none` plus
   our own chevron (inline SVG data URI — no extra request, and it inherits
   nothing so the colour is baked in). Padding-right leaves room for it. The
   OPTION list is still drawn by the OS; that part cannot be styled, which is
   the tradeoff for keeping a real, accessible, keyboard-native control. */
.sfi-select,
.rsm-form__field select,
.filter-bar select {
	appearance: none; -webkit-appearance: none;
	font-family: var(--font-head); font-weight: 600; font-size: .9rem; color: var(--ink);
	padding: .7rem 2.6rem .7rem 1rem;
	border: 1.5px solid rgba(28,28,28,.16); border-radius: 999px;
	background-color: var(--paper);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2363696D' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 9l7 7 7-7'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right .85rem center;
	background-size: 16px 16px;
	cursor: pointer; max-width: 100%;
	transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.sfi-select:hover, .filter-bar select:hover { border-color: rgba(28,28,28,.3); }
.sfi-select:focus-visible,
.rsm-form__field select:focus-visible,
.filter-bar select:focus-visible {
	outline: none; border-color: var(--red);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 20%, transparent);
}
/* The form's selects sit in a column of text inputs, so they take that shape
   rather than the pill used in the filter bar. */
.rsm-form__field select { border-radius: 10px; background-color: var(--linen); font-family: var(--font-body); font-weight: 400; font-size: 1rem; padding: .7rem 2.6rem .7rem .85rem; }

.filter-bar { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; margin-bottom: clamp(1.25rem, 3vw, 2rem); }
.filter-bar__group { border: 0; padding: 0; margin: 0; min-width: 0; }

/* ---- results + pagination ---- */
.catalogue-results { transition: opacity .18s var(--ease); }
.catalogue-results.is-loading { opacity: .45; pointer-events: none; }
.cat-pager {
	display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
	gap: .75rem 1.5rem;
}
.cat-pager--top { margin-bottom: 1.25rem; padding-bottom: .85rem; border-bottom: 1px solid rgba(28,28,28,.1); }
.cat-pager--bottom { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.cat-pager--bottom .cat-pager__count { order: 2; }
.cat-pager__count { margin: 0; font-size: .84rem; color: var(--charcoal); font-family: var(--font-head); font-weight: 600; }
.cat-pager__list { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; list-style: none; margin: 0 0 0 auto; padding: 0; }
.cat-pager__list .page-numbers {
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 38px; height: 38px; padding: 0 .6rem; border-radius: 999px;
	font-family: var(--font-head); font-weight: 700; font-size: .86rem;
	color: var(--ink); text-decoration: none; border: 1.5px solid transparent;
	transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.cat-pager__list a.page-numbers:hover { background: var(--paper); border-color: rgba(28,28,28,.16); color: var(--red); }
.cat-pager__list .page-numbers.current { background: var(--red); color: #fff; }
.cat-pager__list .page-numbers.dots { min-width: 1.5rem; color: var(--charcoal); }
.cat-pager__list .sfi-icon { width: 17px; height: 17px; }

/* ---------- category pages (2026-08-12 consolidation) ----------
   The category hero is the same component as everywhere else; only the copy
   block differs — it holds the category's marketing paragraph rather than a
   one-line sub, so it needs prose spacing and a cap on how far it can run
   before the panel stops being a hero. */
.hero--category .cat-hero__body { max-width: 52ch; margin-bottom: 1.75rem; }
.hero--category .cat-hero__body p { margin: 0 0 .7rem; }
.hero--category .cat-hero__body p:last-child { margin-bottom: 0; }
.hero--category .hero__title { margin-bottom: .85rem; }
/* Breadcrumbs sit above the H1 inside the copy panel now that the full-bleed
   banner is gone. */
.hero--category .cat-crumbs { margin: 0 0 .85rem; color: var(--charcoal); font-size: .82rem; }
.hero--category .cat-crumbs a { color: inherit; }
.hero--category .cat-crumbs a:hover { color: var(--red); }
.hero--category .cat-crumbs span { margin: 0 .4rem; opacity: .5; }

/* Grouped item listing: every SKU in the parent category, under its
   sub-category. */
.cat-items__head {
	display: flex; align-items: baseline; justify-content: space-between;
	gap: .5rem 1.5rem; flex-wrap: wrap; margin-bottom: clamp(1.25rem, 3vw, 2rem);
}
.cat-items--grouped .cat-items__heading { margin: 0; }
.cat-items__count { margin: 0; color: var(--charcoal); font-family: var(--font-head); font-weight: 600; font-size: .88rem; }
.cat-group + .cat-group { margin-top: clamp(2rem, 4.5vw, 3.25rem); }
.cat-group__head {
	display: flex; align-items: baseline; justify-content: space-between;
	gap: .5rem 1.5rem; flex-wrap: wrap;
	margin-bottom: clamp(.85rem, 2vw, 1.25rem);
	padding-bottom: .6rem; border-bottom: 2px solid color-mix(in srgb, var(--red) 22%, transparent);
}
.cat-group__title { margin: 0; font-size: clamp(1.15rem, 2vw, 1.45rem); }
.cat-group__all { white-space: nowrap; font-size: .86rem; }

/* ---------- one block per brand inside a sub-category ----------
   Client, 2026-08-27: Horn of Plenty must not sit shoulder to shoulder with
   Ambrosia — HoP is the cheaper line and the adjacency invites a price
   comparison. Sorting cannot do it: the grid is auto-fill, so the brand
   boundary lands wherever the column count puts it. Each brand therefore gets
   its own grid, and the gap between them is the separation.

   The label is quiet on purpose ("not too prominent"): a small caps line, not a
   second heading competing with the sub-category above it. Only sub-categories
   carrying more than one brand render this at all — the other 34 are a single
   unlabelled grid, exactly as before. */
.cat-brand + .cat-brand { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.cat-brand__title {
	margin: 0 0 clamp(.65rem, 1.4vw, .9rem);
	font-family: var(--font-body, inherit);
	font-size: .78rem; font-weight: 700;
	letter-spacing: .09em; text-transform: uppercase;
	color: var(--charcoal, #63696D);
}
.cat-brand__title::after {
	content: ""; display: block;
	width: 2.25rem; height: 2px; margin-top: .45rem;
	background: color-mix(in srgb, var(--red) 45%, transparent);
}

/* The spec-sheet disclaimer. "Not too prominent but enough for CYA" (client,
   2026-08-27) — so: small, muted, left where the eye lands after the listing,
   and deliberately not boxed. It sits below a grid of white cards on --mist,
   which is enough separation without a rule above it. */
.spec-disclaimer {
	margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
	font-size: .8rem; line-height: 1.5;
	color: color-mix(in srgb, var(--charcoal) 88%, transparent);
}
.product-single__actions + .spec-disclaimer { margin-top: 1.25rem; }

.catalogue-all { padding: var(--section-y) 0; background: var(--paper); }

/* ---------- catalogue overview (the /products/ page) ----------
   Rebuilt 2026-08-12: the site's split hero, then the categories, then a
   smaller repeat of the search. Rhythm is the homepage's — hero CREAM → cards
   WHITE → strip MIST — so the two pages read as the same site. */
.catalogue-cats { background: var(--paper); }

/* The search field standing in for the hero's CTA button. Left-aligned on the
   copy panel's own edge, and narrower than the standalone version (the panel is
   half the page) — .cat-search's own max-width would otherwise centre it. */
/* The desktop slot is close to square while the photo is 4:3, so ~20% of the
   width is cropped. Biased slightly right: it keeps both cans clear of the edge
   and trims the dead window frame on the left. Re-derive if the photo changes. */
.hero--catalogue .hero__img { object-position: 55% center; }

.hero__search { margin-top: .35rem; }
.hero__search .cat-search { margin: 0; max-width: 34rem; }
.hero__search .cat-search__hint { margin-left: 1rem; }
/* The type-ahead panel drops well past the foot of the hero, and .hero clips
   its overflow (it is what keeps the photography inside the split). Opened up
   here only — nothing in this hero can spill: the photo is absolutely
   positioned inside .hero__media and the curve divider is meant to overlap the
   join. z-index keeps the panel over the categories section it lands on, and
   stays under the sticky header (100). */
.hero--catalogue { overflow: visible; z-index: 5; }
.hero__search .cat-search__results { max-height: min(56vh, 380px); overflow-y: auto; }

/* The hero copy has to paint ABOVE the curve divider, or the arc covers the
   search field and its suggestions. The z-index on .cat-search__results alone
   could not do it: .hero__content carries .reveal, whose `will-change:
   opacity, transform` makes it a STACKING CONTEXT — so every z-index inside it
   is sealed in, and the whole block sat below the curve's z-index 3. Raising
   the context itself is the fix. Applies to all heroes: the arc should never
   cover hero copy, it just never reached far enough down to show before. */
.hero__content { position: relative; z-index: 4; }

/* Same trap at the other end of the page: the repeat search sits in the last
   band, its .reveal wrapper seals the suggestion panel's z-index in, and the
   footer — position: relative, later in the DOM — would paint over it. */
.cat-search-band { position: relative; z-index: 2; }

/* Two rows of five, matching the homepage grid exactly (client, 2026-08-12).
   Scoped to the overview: the same card grid renders sub-categories on a
   category page, where auto-fill is the right behaviour for 3–4 of them. */
.catalogue-cats .cat-children__grid { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1040px) { .catalogue-cats .cat-children__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px)  { .catalogue-cats .cat-children__grid { grid-template-columns: repeat(2, 1fr); } }

/* The repeat search band. Quieter than the hero field by design — same
   component, smaller type and a tighter row, on the mist strip. */
.cat-search-band { padding: clamp(2.25rem, 5vw, 3.5rem) 0; background: var(--paper); }
.cat-search-band__inner { max-width: 46rem; text-align: center; }
.cat-search-band__title {
	margin: 0 0 1rem; font-size: clamp(1.15rem, 2vw, 1.5rem); letter-spacing: -.02em;
}
.cat-search-band .cat-search { margin-top: 0; max-width: 38rem; }
.cat-search--band .cat-search__row { border-width: 1.5px; padding-left: .85rem; }
.cat-search--band .cat-search__row input[type="search"] { font-size: .95rem; padding-top: .5rem; padding-bottom: .5rem; }
.cat-search--band .cat-search__submit { padding: .55rem 1.2rem; min-height: 40px; font-size: .84rem; }
.cat-search--band .cat-search__hint { text-align: center; margin-left: 0; }

/* Last section on the page is the search band, so the footer's curve fills with
   it — white since 2026-08-19, when the full list took the mist. */
.catalogue-overview:has(> .cat-search-band:last-child) + .site-footer { --footer-curve-fill: var(--paper); }

@media (max-width: 600px) {
	.cat-search__row { flex-wrap: wrap; border-radius: var(--radius); padding: .5rem; }
	.cat-search__submit { width: 100%; }
	.cat-search__hint { margin-left: .25rem; }
}

/* ---------- category copy section (2026-08-19) ----------
   The paragraph the hero used to carry, now a band of its own between the hero
   and the products. No photo column beside it and a hard cap on measure, so by
   the site's own rule — constrained and alone → centre it. */
.cat-intro { padding: clamp(2.5rem, 5.5vw, 4rem) 0; }
.cat-intro__inner { max-width: 58rem; margin-inline: auto; text-align: center; }
.cat-intro__heading { margin: 0 0 .9rem; font-size: clamp(1.35rem, 2.4vw, 1.9rem); }
.cat-intro__body { max-width: 68ch; margin-inline: auto; font-size: clamp(1rem, 1.25vw, 1.1rem); line-height: 1.7; color: color-mix(in srgb, var(--ink) 84%, transparent); }
.cat-intro__body p { margin: 0 0 1rem; }
.cat-intro__body p:last-child { margin-bottom: 0; }

/* …and the same band WITH photography (2026-08-20). Two or three shots of the
   product itself beside the copy, so the screen below the fold is not a wall of
   text on white. Photos left / copy right, against the hero's copy-left order
   directly above. The copy stops being centred here — it is no longer alone, so
   the site's rule flips it back to flush left. */
.cat-intro--media .cat-intro__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
	gap: clamp(1.5rem, 4vw, 3.25rem);
	align-items: center;
}
.cat-intro--media .cat-intro__inner { max-width: none; margin-inline: 0; text-align: left; }
.cat-intro--media .cat-intro__body { margin-inline: 0; max-width: 62ch; }
.cat-intro__media { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(.7rem, 1.5vw, 1.1rem); order: -1; }
.cat-intro__img {
	width: 100%;
	aspect-ratio: 4 / 5;
	object-fit: cover;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	display: block;
}
/* A pair sits staggered rather than square-on — the second shot is the detail
   (sliced rings, a single variety) and reads as a note against the first. */
.cat-intro__media[data-count="2"] .cat-intro__img:first-child { margin-top: clamp(.9rem, 2.6vw, 2.25rem); }
.cat-intro__media[data-count="1"] { grid-template-columns: 1fr; }
.cat-intro__media[data-count="1"] .cat-intro__img { aspect-ratio: 3 / 2; }
.cat-intro__media[data-count="3"] .cat-intro__img:first-child { grid-column: 1 / -1; aspect-ratio: 3 / 2; }
@media (max-width: 900px) {
	.cat-intro--media .cat-intro__grid { grid-template-columns: 1fr; gap: clamp(1.5rem, 5vw, 2.25rem); }
	/* Copy first on a phone: the heading names the category the reader just
	   tapped, and the photos read as its illustration, not as a lead-in. */
	.cat-intro__media { order: 0; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
	.cat-intro__media[data-count="2"] .cat-intro__img:first-child { margin-top: 0; }
	.cat-intro__media[data-count="3"] .cat-intro__img:first-child { grid-column: auto; aspect-ratio: 4 / 5; }
}

/* "See All Olives" at the foot of a leaf category's grid, and under the
   siblings on a product page. Centred and on its own line: it is the end of the
   list, not an item in it. */
.cat-items__up { margin: clamp(1.75rem, 3.5vw, 2.75rem) 0 0; text-align: center; }

/* Kosher, on a single product. One badge, so it is a line rather than a row. */
.product-single__badges { margin: 0 0 1.25rem; }
.product-badge {
	display: inline-flex; align-items: center; padding: .3rem .8rem;
	border: 1px solid color-mix(in srgb, var(--green) 45%, transparent);
	border-radius: 999px; background: color-mix(in srgb, var(--green) 8%, transparent);
	font-family: var(--font-head); font-weight: 700; font-size: .76rem;
	letter-spacing: .06em; text-transform: uppercase;
	/* The brand green is a 3:1 colour on white — fine for the map's large fills,
	   short of AA for .76rem uppercase. Darkened to ~5.9:1 for the text only;
	   the badge still reads as brand green. */
	color: color-mix(in srgb, var(--green) 70%, #000);
}

/* ---------- the complete product list (2026-08-19) ----------
   Client: "add the full product list to the main product page under the
   categories… they like it as PDF download and regular web page." So: a real
   TABLE, one row per SKU, every column off their own sheet — not more cards.
   Cards are a browse device and there are ten category tiles above doing that
   job; this is the reference document, and a distributor reads it the way they
   read the printed list, or hits ⌘F. */
/* BAND COLOUR — the /products/ rhythm is now hero CREAM → categories WHITE →
   full list MIST → search band WHITE. The list took the tint because it is the
   page's longest section and needed to read as its own thing rather than as
   more of the categories above it; the search band gave its tint up in the same
   move, since two tints touching is the one thing the palette cannot do (cream
   #F7F1E8 and mist #F5F2EE are six of 255 apart). */
.catalogue-list { padding: var(--section-y) 0; background: var(--mist); }
.catalogue-list__head {
	display: flex; align-items: flex-end; justify-content: space-between;
	gap: 1.25rem 2.5rem; flex-wrap: wrap;
	padding-bottom: clamp(1rem, 2vw, 1.5rem);
	border-bottom: 2px solid color-mix(in srgb, var(--red) 22%, transparent);
}
.catalogue-list__intro { max-width: 60ch; }
.catalogue-list__head .cat-items__heading { margin: 0; }
.catalogue-list__lede { margin: .6rem 0 0; color: color-mix(in srgb, var(--ink) 80%, transparent); }
.catalogue-list__count { margin: .5rem 0 0; color: var(--charcoal); font-family: var(--font-head); font-weight: 600; font-size: .88rem; }
.catalogue-list__pdf { flex: 0 0 auto; }
.catalogue-list__pdf .sfi-icon { width: 18px; height: 18px; }

/* Jump list. 265 rows is a long scroll and the alternative is finding "Peppers"
   by eye. Chips rather than a bulleted column: ten of them fit on one or two
   lines and read as a control strip, which is what they are. */
/* ---- the full list is collapsed until asked for ----
   Client, 2026-08-20. A native <details>, so the marker has to be removed by
   hand (::-webkit-details-marker for older Safari, list-style for everyone
   else) before <summary> can be styled as the button it reads as. */
.catalogue-list__disclosure { margin: clamp(1.5rem, 3.5vw, 2.25rem) 0 0; }
.catalogue-list__toggle {
	display: inline-flex; align-items: center; gap: .55rem;
	cursor: pointer; list-style: none;
}
.catalogue-list__toggle::-webkit-details-marker { display: none; }
.catalogue-list__toggle-icon { display: inline-flex; transition: transform .25s var(--ease); }
.catalogue-list__toggle-icon .sfi-icon { width: 18px; height: 18px; }
.catalogue-list__toggle-close { display: none; }
[open] > .catalogue-list__toggle .catalogue-list__toggle-open { display: none; }
[open] > .catalogue-list__toggle .catalogue-list__toggle-close { display: inline; }
[open] > .catalogue-list__toggle .catalogue-list__toggle-icon { transform: rotate(180deg); }
/* The first category block sets its own top margin; with the list open the
   toggle needs the same air beneath it as the head above has. */
.catalogue-list__disclosure > .catalogue-list__jump { margin-top: clamp(1.5rem, 3.5vw, 2.25rem); }

.catalogue-list__jump { margin: clamp(1.25rem, 3vw, 1.75rem) 0 0; }
.catalogue-list__jump ul { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; margin: 0; padding: 0; }
.catalogue-list__jump a {
	display: inline-block; padding: .4rem .9rem; border-radius: 999px;
	border: 1px solid rgba(28,28,28,.14); background: var(--mist);
	font-family: var(--font-head); font-weight: 700; font-size: .8rem;
	color: var(--ink); text-decoration: none;
}
.catalogue-list__jump a:hover { background: var(--red); border-color: var(--red); color: #fff; }

.catalogue-list__cat { margin-top: clamp(2.5rem, 5vw, 4rem); scroll-margin-top: 120px; }
.catalogue-list__cathead {
	display: flex; align-items: baseline; justify-content: space-between;
	gap: .5rem 1.5rem; flex-wrap: wrap; margin-bottom: 1rem;
}
.catalogue-list__catname { margin: 0; font-size: clamp(1.3rem, 2.4vw, 1.8rem); }
.catalogue-list__subname {
	margin: clamp(1.5rem, 3vw, 2.25rem) 0 .6rem;
	font-size: clamp(.95rem, 1.5vw, 1.08rem); letter-spacing: .06em; text-transform: uppercase;
	color: var(--red);
}
.catalogue-list__subname a { color: inherit; text-decoration: none; }
.catalogue-list__subname a:hover { text-decoration: underline; }

/* The table is wider than a phone. It scrolls INSIDE this box — the page body
   must never scroll sideways — and the box is focusable so that scroll is
   reachable without a pointer. */
.catalogue-table__scroll {
	overflow-x: auto; -webkit-overflow-scrolling: touch;
	background: var(--paper); border: 1px solid rgba(28,28,28,.09);
	border-radius: var(--radius);
}
.catalogue-table__scroll:focus-visible { outline: 3px solid var(--red); outline-offset: 2px; }
.catalogue-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.catalogue-table th, .catalogue-table td { padding: .55rem .75rem; text-align: left; vertical-align: top; }
/* No sticky header: `overflow-x: auto` on the wrapper computes overflow-y to
   auto as well, so `position: sticky` would resolve against a box with no
   vertical scroll and do nothing but risk clipping. It is not needed anyway —
   the list is 48 small tables, each with its own header a few rows away. */
.catalogue-table thead th {
	background: var(--mist); border-bottom: 1px solid rgba(28,28,28,.16);
	font-family: var(--font-head); font-weight: 700; font-size: .74rem;
	letter-spacing: .06em; text-transform: uppercase; color: var(--charcoal);
	white-space: nowrap;
}
.catalogue-table tbody tr { border-bottom: 1px solid rgba(28,28,28,.08); }
.catalogue-table tbody tr:last-child { border-bottom: 0; }
.catalogue-table tbody tr:hover { background: color-mix(in srgb, var(--cream) 75%, var(--paper)); }
.catalogue-table .is-num { white-space: nowrap; }
.catalogue-table__sku { font-family: var(--font-head); font-weight: 700; color: var(--red); }
/* The description is the row's header cell — it is what identifies the row to a
   screen reader reading the pallet figure three columns over. Normal weight,
   because a table of 265 bold rows is a table with no emphasis left. */
.catalogue-table__desc { font-weight: 500; min-width: 18rem; }
.catalogue-table__desc a { color: var(--ink); text-decoration: none; }
.catalogue-table__desc a:hover { color: var(--red); text-decoration: underline; }
.catalogue-table__kosher { font-family: var(--font-head); font-weight: 700; color: color-mix(in srgb, var(--green) 70%, #000); }

@media (max-width: 700px) {
	.catalogue-list__head { align-items: flex-start; }
	.catalogue-list__pdf { width: 100%; }
	.catalogue-table { font-size: .82rem; }
	.catalogue-table__desc { min-width: 14rem; }
}

/* ---------- motion ---------- */
@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
	.hero__video { display: none; }
	.sfi-js .reveal { opacity: 1 !important; transform: none !important; }
	.benefit-card:hover { transform: none; }
	.benefit-card:hover .benefit-card__img { transform: none; }
}

/* ---------- product label (ingredients & nutrition) ----------
   A second picture in the same column as the pack shot, and deliberately NOT
   the same kind of object: the pack shot is the product, the label is a
   document about it. So it reads as a document — squared corners inside a
   hairline frame, a caption under it, and a link affordance rather than a
   silent image. It is only ever on the single-product page; the browse grids
   keep showing the pack shot, which is what a label at card size cannot do.

   The client's scans run from about 850px to 1500px on the long edge, which is
   readable when opened but not at panel size, so the thumbnail is explicitly a
   way IN to the full image, never the place anyone reads an ingredient list. */
.product-single__gallery { align-self: start; display: grid; gap: 1rem; }
.product-label { margin: 0; }
.product-label__link {
	display: block; position: relative; text-decoration: none;
	background: var(--paper); border: 1px solid rgba(28,28,28,.12); border-radius: var(--radius);
	overflow: hidden; transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.product-label__link:hover,
.product-label__link:focus-visible { border-color: var(--red); box-shadow: var(--shadow-sm, 0 4px 14px rgba(0,0,0,.08)); }
.product-label__img { display: block; width: 100%; height: auto; }
.product-label__cta {
	display: flex; align-items: center; gap: .4rem;
	padding: .6rem .9rem; border-top: 1px solid rgba(28,28,28,.08);
	font-family: var(--font-head); font-weight: 600; font-size: .85rem;
	text-transform: uppercase; letter-spacing: .04em; color: var(--red);
}
.product-label__link:hover .link-arrow__icon { transform: translateX(3px); }
.product-label__note { margin: .5rem 0 0; font-size: .8rem; color: var(--charcoal); }

/* The dialog is an enhancement — the <a> underneath it opens the same file on
   its own if the script never runs. */
.label-dialog {
	width: min(92vw, 1100px); max-width: none; max-height: 92vh; padding: 0;
	border: 0; border-radius: var(--radius-lg); background: var(--paper);
	overflow: auto;
}
.label-dialog::backdrop { background: rgba(21,24,27,.72); }
.label-dialog__img { display: block; width: 100%; height: auto; }
.label-dialog__close-form { position: sticky; top: 0; z-index: 2; display: flex; justify-content: flex-end; }
.label-dialog__close {
	margin: .5rem; width: 2.25rem; height: 2.25rem; line-height: 1; font-size: 1.4rem;
	border: 0; border-radius: 999px; cursor: pointer;
	background: rgba(21,24,27,.82); color: #fff;
}
.label-dialog__close:hover { background: var(--red); }
.label-dialog__cap {
	display: flex; flex-wrap: wrap; gap: .25rem .75rem;
	margin: 0; padding: .75rem 1rem 1rem; font-size: .85rem; color: var(--charcoal);
}

@media (max-width: 760px) {
	.label-dialog { width: 96vw; }
}

/* ---------- browse card falling back to the label ----------
   A label is a flat scan with white margins and a different shape to a pack
   shot, so left alone it would sit awkwardly small inside a card stage built
   for a jar. It gets the stage's full width instead and a hairline, which
   reads as "this is a document standing in", not as a badly cropped photo. */
.spec-card__img.is-label,
.card__img.is-label {
	object-fit: contain; background: #fff;
	border: 1px solid rgba(28,28,28,.07); border-radius: calc(var(--radius) / 2);
}

/* ---------- the serving photograph, below the specs ----------
   The only picture on a product page that is of food rather than of packaging,
   and the widest thing on the page. Aspect ratios in the client's set run from
   3:2 landscape through square to 3:4 portrait, so the frame is capped by
   HEIGHT and the image is contained inside it — a portrait shot sits centred
   rather than being cropped through the middle of the dish. */
.product-food { padding: clamp(1rem, 3vw, 2rem) 0 clamp(2rem, 5vw, 3.5rem); }
.product-food__heading {
	margin: 0 0 1rem; font-size: clamp(1.15rem, 2.2vw, 1.5rem);
}
.product-food__figure {
	margin: 0; padding: clamp(.75rem, 2vw, 1.25rem);
	background: var(--paper); border: 1px solid rgba(28,28,28,.08);
	border-radius: var(--radius-lg); overflow: hidden;
}
.product-food__img {
	display: block; width: 100%; height: auto;
	max-height: min(62vh, 560px); object-fit: contain;
	border-radius: var(--radius);
}
.product-food__cap {
	margin: .85rem .25rem 0; font-size: .85rem; color: var(--charcoal);
}
