/*
Theme Name: Cuba Maison v2
Theme URI: https://cubafragrancesusa.com/
Author: Cuba Fragrances USA
Description: Review copy of Cuba Maison, carrying the team's feedback. Identical to the live theme except where that feedback changes something, so a diff against cuba-maison is an exact list of what is different. Function prefixes and the text domain are deliberately left as cuba-maison: only one theme is ever loaded, so nothing can collide, and the diff stays about the design rather than about renamed symbols. A fragrance-house storefront for Cuba Fragrances USA — serif display type, a bronze accent, a full-bleed hero and a calm four-across catalogue. Built as a classic theme with one stylesheet and no framework, and designed to sit alongside the Cuba B2B plugin without duplicating any of its pricing or gating logic.
Version: 0.10.3
Requires at least: 6.4
Tested up to: 6.7
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: cuba-maison
Tags: e-commerce, custom-menu, custom-logo, featured-images, translation-ready, block-styles, wide-blocks
*/

/* ==========================================================================
   CONTENTS
   1.  Tokens
   2.  Fonts
   3.  Reset and base
   4.  Typography
   5.  Layout
   6.  Buttons
   7.  Header
   8.  Hero
   9.  Assurance bar
   10. Section heads
   11. Product cards and grids
   12. Editorial feature blocks
   13. Brand grid
   14. Footer
   15. WooCommerce
   16. Trade screens
   17. Blocks and prose
   18. Utilities and motion
   19. Category mega menu
   20. Quick view and the saved list
   21. Top bar
   22. Gated prices
   23. Size selector
   24. Catalogue filters
   25. Product page
   26. Recommendation rows
   27. Ratings and reviews
   28. The trade sign-in gate
   29. Touch screens
   30. Contact
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */

:root {
	/* Neutral ramp. The reference design is built almost entirely from one
	 * grey scale, which is why it reads as expensive rather than busy — the
	 * bronze is the only hue in the whole palette and it appears at hover
	 * and almost nowhere else. */
	--ink: #171717;
	--ink-85: #262626;
	--ink-60: #525252;
	--ink-45: #737373;
	/* Careful: --ink-30 carries 2.5:1 against the page and fails AA for text.
	 * It is for the dark footer, for rules and for borders. Muted text on a
	 * light ground uses --fg-muted (--ink-45, 4.7:1). */
	--ink-30: #a3a3a3;
	--ink-15: #d4d4d4;
	--rule: #efe8d8;
	--shell: #faf6ea;

	/* The photography ground and the purchase panel. Three near-whites rather
	 * than one, because a packshot cut out on white needs a frame that is
	 * visibly not the page, and a panel that groups the buy controls needs to
	 * be visibly not the frame.
	 *
	 * v2: the grounds are warmed towards the gold in the crest. The shift is
	 * deliberately small — a page that is actually gold reads as a cheap
	 * template, and the packshots are photographed on white, so a strong
	 * ground would fight every product on the site. These sit two or three
	 * points of saturation off neutral: enough that the page is visibly not
	 * white next to the logo, not enough to tint the merchandise. */
	--stone: #f2ecdd;
	--panel: #fdfaf2;
	--panel-edge: #e6ddc6;
	--cream: #fbf5e7;
	--paper: #fdfbf5;

	/* The header's own two grounds. The masthead is the one place on the site
	 * that can carry the crest's gold as a surface rather than as an accent,
	 * because nothing is photographed on it — the caution about tinting the
	 * merchandise does not apply above the content.
	 *
	 * A pair, not one colour: the wordmark band is the deeper of the two and
	 * the crest band the lighter, so the masthead steps down from the near
	 * black utility bar to the paper the page is written on instead of
	 * dropping to it in one jump. Both are still only about six points of
	 * saturation — far enough from neutral to read as gold beside the logo,
	 * nowhere near enough to read as a gold template. */
	--gold-deep: #efe3c6;
	--gold-tint: #faf3e1;
	/* The rules inside the masthead. --rule is mixed for the paper ground and
	 * all but disappears on --gold-tint. */
	--gold-rule: #e4d7b6;

	/* The single accent, taken off the crest itself rather than the muted
	 * bronze the first version used. --bronze stays the token name so the
	 * ~40 places that reference it are unchanged and the diff stays readable.
	 *
	 * Contrast against the new page ground, measured: this gold is 3.38:1
	 * where the old bronze was 2.71:1 — so it now clears the 3:1 that a
	 * non-text UI boundary needs, which the old one did not. It still does
	 * not carry small body text; that is what --bronze-dark is for. On the
	 * dark footer it reads 5.12:1, comfortably past AA. */
	--bronze: #a8842c;

	/* The one masked icon in the stylesheet: WooCommerce's show-password
	 * button has no markup inside it to hang an inline SVG on. */
	--eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cpath d='M2 12s3.6-6 10-6 10 6 10 6-3.6 6-10 6-10-6-10-6Z'/%3E%3Ccircle cx='12' cy='12' r='2.5'/%3E%3C/svg%3E");
	/* The text-safe gold: 5.9:1 on the page ground, against 3.8:1 for the old
	 * bronze-dark. This one actually passes AA for small type — the version
	 * it replaces did not. */
	--bronze-dark: #7a5e14;

	/* Semantic aliases so components never name a raw colour. */
	--bg: var(--paper);
	--fg: var(--ink);
	--fg-muted: var(--ink-45);
	--border: var(--rule);

	/* Type.
	 *
	 * Lexend carries the whole interface — body, headings, navigation and
	 * every label. It is the face on the reference site, and it is a good
	 * fit here for a reason beyond matching: it was drawn for reading ease
	 * at small sizes, which is what a catalogue of 197 near-identical
	 * product names actually needs.
	 *
	 * Cormorant Garamond is kept for the wordmark and pull quotes only.
	 * The lockup is the closest thing this store has to a logo, and a
	 * display serif is what makes it read as one rather than as a heading. */
	--font-display: "Cormorant Garamond", "Cormorant", Georgia, "Times New Roman", serif;
	--font-sans: "Lexend", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

	/*
	 * Fluid display sizes. The reference jumps 42px -> 64px at the md
	 * breakpoint; a clamp covers the same range continuously, so a 414px
	 * phone is not served the 375px size with 39px of slack.
	 */
	--text-hero: clamp(2.125rem, 3.4vw, 3rem);      /* 34px -> 48px */
	--text-h2: clamp(1.625rem, 2.4vw, 2.125rem);    /* 26px -> 34px */
	--text-h3: clamp(1.25rem, 1.6vw, 1.5rem);       /* 20px -> 24px */
	--text-h4: 1.125rem;                            /* 18px */
	--text-lead: clamp(1rem, 1.1vw, 1.0625rem);     /* 16px -> 17px */
	--text-body: 1rem;                              /* 16px */
	--text-sm: 0.9375rem;                           /* 15px */
	--text-xs: 0.8125rem;                           /* 13px */
	--text-2xs: 0.75rem;                            /* 12px */

	--track-wide: 0.25em;
	--track-wider: 0.5em;
	--leading-tight: 1.05;
	--leading-snug: 1.25;
	--leading-body: 1.7;

	/* Space. A 4px base, but only these steps are used — an ad-hoc 26px is
	 * how a rhythm stops being a rhythm. */
	--s-1: 0.25rem;
	--s-2: 0.5rem;
	--s-3: 0.75rem;
	--s-4: 1rem;
	--s-5: 1.25rem;
	--s-6: 1.5rem;
	--s-8: 2rem;
	--s-10: 2.5rem;
	--s-12: 3rem;
	--s-16: 4rem;
	--s-20: 5rem;

	--container: 1400px;
	--gutter: 1.5rem;
	--section-y: var(--s-20);
	--grid-gap: 2rem;

	--speed: 300ms;
	--speed-slow: 500ms;
	--ease: cubic-bezier(0.4, 0, 0.2, 1);

	--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}

@media (min-width: 768px) {
	:root {
		--gutter: 3rem;
	}
}

/* --------------------------------------------------------------------------
   2. FONTS

   Both faces are variable and self-hosted as a single latin-subset woff2
   each. Three files, 103 KB total, and no connection to a font CDN — which
   is a privacy improvement as well as a speed one, since a third-party font
   request leaks every visitor's IP and referrer.

   Plain format("woff2"), not format("woff2-variations"): every engine that
   can render a variable font accepts the plain string and reads the axis
   from the file, whereas the -variations keyword is an older proposal that
   some engines treat as unknown and skip — silently dropping the @font-face.
   -------------------------------------------------------------------------- */

@font-face {
	font-family: "Cormorant Garamond";
	src: url("assets/fonts/cormorant-garamond-normal.woff2") format("woff2");
	font-weight: 300 700;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Cormorant Garamond";
	src: url("assets/fonts/cormorant-garamond-italic.woff2") format("woff2");
	font-weight: 300 700;
	font-style: italic;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Lexend";
	src: url("assets/fonts/lexend-normal.woff2") format("woff2");
	font-weight: 300 700;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------------
   3. RESET AND BASE
   -------------------------------------------------------------------------- */

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

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	/* The header is sticky, so an in-page anchor would otherwise land with
	 * its target hidden underneath it. */
	scroll-padding-top: 6rem;
}

body {
	background: var(--bg);
	color: var(--fg);
	font-family: var(--font-sans);
	font-size: var(--text-body);
	font-weight: 400;
	line-height: var(--leading-body);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

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

button,
input,
select,
textarea {
	font: inherit;
	color: inherit;
}

a {
	color: inherit;
	text-decoration: none;
	transition: color var(--speed) var(--ease);
}

a:hover,
a:focus-visible {
	color: var(--bronze);
}

/* One visible focus style everywhere. Removing outlines without replacing
 * them is the single most common keyboard-accessibility failure, so the ring
 * is defined once here and never overridden. */
:focus-visible {
	outline: 2px solid var(--bronze);
	outline-offset: 3px;
}

::selection {
	background: var(--ink);
	color: var(--paper);
}

hr {
	border: 0;
	border-top: 1px solid var(--border);
}

/* --------------------------------------------------------------------------
   4. TYPOGRAPHY
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4,
h5,
h6,
.t-serif {
	font-family: var(--font-sans);
	font-weight: 500;
	line-height: var(--leading-snug);
	letter-spacing: -0.01em;
	color: var(--ink);
}

h1,
.t-hero {
	font-size: var(--text-hero);
	line-height: var(--leading-tight);
	letter-spacing: -0.01em;
}

h2,
.t-h2 {
	font-size: var(--text-h2);
}

h3,
.t-h3 {
	font-size: var(--text-h3);
}

h4 {
	font-size: var(--text-h4);
}

/* The uppercase, wide-tracked micro-label. This one class does more work
 * than any other in the design — it is the eyebrow above every section, the
 * label on every button and the meta line under every product. */
.t-eyebrow {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	font-weight: 400;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	line-height: 1.4;
	color: var(--ink-45);
}

.t-kicker {
	font-family: var(--font-display);
	font-style: italic;
	font-size: var(--text-lead);
	letter-spacing: 0.02em;
	color: var(--ink-85);
}

.t-lead {
	font-size: var(--text-lead);
	color: var(--ink-60);
	line-height: var(--leading-body);
}

.t-muted {
	color: var(--fg-muted);
}

/* Money and quantities line up column-to-column. Proportional figures in a
 * price column make two numbers of the same magnitude look different
 * lengths, which is exactly the wrong signal on an order. */
.t-num {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
}

/* --------------------------------------------------------------------------
   5. LAYOUT
   -------------------------------------------------------------------------- */

.wrap {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.wrap--narrow {
	max-width: 720px;
}

.wrap--prose {
	max-width: 42rem;
}

.section {
	padding-block: var(--section-y);
}

.section--tight {
	padding-block: var(--s-12);
}

.section--cream {
	background: var(--cream);
}

.section--shell {
	background: var(--shell);
}

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

.section--ink h1,
.section--ink h2,
.section--ink h3 {
	color: var(--paper);
}

.section--ruled {
	border-bottom: 1px solid var(--border);
}

.stack > * + * {
	margin-block-start: var(--s-4);
}

.stack-lg > * + * {
	margin-block-start: var(--s-8);
}

.site-main {
	display: block;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link {
	position: absolute;
	top: -100px;
	left: var(--s-4);
	z-index: 999;
	background: var(--ink);
	color: var(--paper);
	padding: var(--s-3) var(--s-6);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
}

.skip-link:focus {
	top: var(--s-4);
	color: var(--paper);
}

/* --------------------------------------------------------------------------
   6. BUTTONS
   -------------------------------------------------------------------------- */

.btn {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	line-height: 1;
	padding: 1rem 2rem;
	border: 1px solid transparent;
	background: var(--ink);
	color: var(--paper);
	cursor: pointer;
	transition: background-color var(--speed) var(--ease), color var(--speed) var(--ease), border-color var(--speed) var(--ease);
}

/* The bronze appears on hover, not at rest. Holding the accent back until
 * interaction is what keeps a nearly monochrome page from looking flat —
 * the colour is a reward for pointing at something. */
.btn:hover,
.btn:focus-visible {
	background: var(--bronze);
	color: var(--paper);
	border-color: var(--bronze);
}

.btn--outline {
	background: transparent;
	color: var(--ink);
	border-color: var(--ink);
}

.btn--outline:hover,
.btn--outline:focus-visible {
	background: var(--ink);
	color: var(--paper);
}

.btn--light {
	background: var(--paper);
	color: var(--ink);
}

/* --bronze at 4.0:1 against paper is fine behind a heading and thin under
 * 12px uppercase type with 0.1em tracking. The darker bronze is the token kept
 * for exactly this: it holds 6.1:1, so the label stays as readable pressed as
 * it is at rest. */
.btn--light:hover,
.btn--light:focus-visible {
	background: var(--bronze-dark);
	color: var(--paper);
}

.btn--ghost {
	background: transparent;
	color: var(--ink);
	padding-inline: 0;
	border-bottom: 1px solid var(--ink-15);
}

.btn--ghost:hover,
.btn--ghost:focus-visible {
	background: transparent;
	color: var(--bronze);
	border-bottom-color: var(--bronze);
}

.btn--sm {
	padding: 0.75rem 1.5rem;
	font-size: var(--text-2xs);
}

.btn--block {
	display: block;
	width: 100%;
	text-align: center;
}

/* --------------------------------------------------------------------------
   7. HEADER
   -------------------------------------------------------------------------- */

.site-header {
	position: sticky;
	top: 0;
	z-index: 50;
	background: var(--gold-tint);
	border-bottom: 1px solid var(--gold-rule);
}

/*
 * The navigation band.
 *
 * A plain block, deliberately unpositioned — .site-header is sticky and is
 * therefore the containing block the mega panels are measured against, and
 * they span it with inset-inline: 0. Positioning this wrapper would re-anchor
 * every panel to the band. It carries the wrap's own measure and gutters
 * itself rather than using the class, because the nav inside it becomes a
 * fixed drawer below the breakpoint and must not be padded by a wrapper that
 * is no longer wrapping anything.
 */
/*
 * No rule along the top. With the crest row removed this band sits directly
 * under the wordmark, and the wordmark deliberately carries no divider of its
 * own — the hairline inside the lockup is the design's signature and a second
 * line an inch below it competes. The two bands already part on their grounds.
 */
.site-header__nav {
	display: flex;
	align-items: center;
}

.site-header__nav > .main-nav {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
	padding-block: var(--s-3);
}

.site-header__nav > .main-nav > ul {
	justify-content: center;
	flex-wrap: nowrap;
}

/*
 * The wordmark band — the sticky header's first line.
 *
 * It carries its own, deeper gold against the header's tint so the name and
 * the navigation still read as two bands rather than one tall one. No divider
 * between them for the same reason — the only rule in the group is the
 * hairline inside the wordmark itself, which is the design's signature and
 * would be competing with a second one directly below it.
 *
 * Shallower than it was, because it is now on screen for the whole page
 * rather than only at the top of it: every pixel here is a pixel of catalogue
 * the buyer does not see while scrolling.
 */
.site-wordmark {
	background: var(--gold-deep);
}

.site-wordmark__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding-block: var(--s-4) var(--s-3);
}

/*
 * The wordmark is the link home, and it says so quietly: the display line
 * holds still — bronze on this gold ground is a long way down in contrast for
 * type that size — and the hairline under the second line takes the colour
 * instead, with the line above it darkening to full ink. The focus ring is the
 * global one.
 */
a.site-wordmark__inner:hover .site-brand__sub,
a.site-wordmark__inner:focus-visible .site-brand__sub {
	color: var(--ink);
	border-top-color: var(--bronze);
}

/* The stacked wordmark: a wide-tracked serif line over a hairline-ruled,
 * very small, very wide second line. It is the reference design's signature
 * and it survives being reproduced at any size. */
.site-brand {
	display: flex;
	flex-direction: column;
	align-items: center;
	flex-shrink: 0;
}

.site-brand__name {
	font-family: var(--font-display);
	font-size: var(--text-h4);
	line-height: 1;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink);
	white-space: nowrap;
}

.site-brand__sub {
	font-family: var(--font-sans);
	font-size: 0.5625rem;
	letter-spacing: var(--track-wider);
	text-transform: uppercase;
	color: var(--ink-60);
	margin-top: var(--s-1);
	padding-top: var(--s-1);
	padding-inline: var(--s-2);
	border-top: 1px solid var(--ink-85);
	white-space: nowrap;
}

.site-brand img {
	max-height: 84px;
	width: auto;
}

/*
 * The crest is a wide, shallow badge (2.49:1), so it is sized by height and
 * left to take whatever width that gives it. 68px tall puts the header at
 * about 100px, which is as much as a sticky bar can take before it starts
 * eating the page on a laptop. The explicit width/height attributes on the
 * <img> hold the space while it loads, so the nav beside it does not jump.
 */
.site-brand img.site-brand__crest {
	display: block;
	/* v2 — the crest is half again as large: 68px → 102px, and the custom-logo
	 * cap above moves with it so an uploaded logo is not left at the old
	 * size. The header grows with it rather than clipping, since the row is
	 * sized by its contents. */
	height: 102px;
	width: auto;
	/* The element selector is deliberate: `.site-brand img` above sets
	 * max-height: 56px for a custom logo uploaded in the Customizer, and a
	 * bare class loses to a class-plus-element. Without it the crest was
	 * clamped to 56px and this rule's `height` silently did nothing. */
	max-height: none;
	max-width: 100%;
}

.site-brand picture {
	display: block;
	line-height: 0;
}

/* Navigation. Medium weight and a hair of tracking: Lexend at 400 in a
 * header reads as body copy that happens to be at the top of the page. */
.main-nav ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--s-8);
}

/*
 * Uppercase and tracked, matching the wordmark and the actions either side of
 * it. Before this the header spoke in three voices at once — a tracked serif
 * wordmark, sentence-case nav, and uppercase micro-type in the actions — and
 * the nav was the one that read as body copy that had wandered upwards.
 */
.main-nav a {
	position: relative;
	display: inline-block;
	padding-block: var(--s-2);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--ink-85);
	white-space: nowrap;
}

/*
 * The current item is marked with a rule rather than by turning the text
 * bronze. Bronze text at this size sits at 2.9:1 on white, and it also read as
 * a disabled item rather than the current one.
 */
.main-nav > ul > li > a::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	height: 1px;
	background: var(--bronze);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--speed) var(--ease);
}

.main-nav > ul > li:hover > a::after,
.main-nav > ul > li:focus-within > a::after,
.main-nav > ul > .current-menu-item > a::after,
.main-nav > ul > .current-menu-ancestor > a::after,
.main-nav > ul > .current_page_item > a::after {
	transform: scaleX(1);
}

.main-nav > ul > li:hover > a,
.main-nav > ul > .current-menu-item > a,
.main-nav > ul > .current-menu-ancestor > a,
.main-nav > ul > .current_page_item > a {
	color: var(--ink);
}

/* Submenus open on hover for pointers and on focus-within for keyboards.
 * focus-within is what makes a hover menu usable by tab alone without any
 * JavaScript at all. */
.main-nav li {
	position: relative;
}

.main-nav .sub-menu {
	position: absolute;
	top: 100%;
	left: 0;
	min-width: 15rem;
	flex-direction: column;
	align-items: stretch;
	gap: 0;
	background: var(--paper);
	border: 1px solid var(--border);
	box-shadow: var(--shadow-lg);
	padding: var(--s-3) 0;
	opacity: 0;
	visibility: hidden;
	transform: translateY(6px);
	transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease), visibility var(--speed);
}

.main-nav li:hover > .sub-menu,
.main-nav li:focus-within > .sub-menu {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.main-nav .sub-menu a {
	display: block;
	padding: var(--s-2) var(--s-6);
	font-size: var(--text-sm);
	letter-spacing: 0.01em;
	text-transform: none;
	color: var(--ink-85);
}

/*
 * A dropdown that is a panel of columns.
 *
 * The gendered items carry three levels: Women → New Brand → NB Prestige. A
 * 15rem list would put nineteen links in one column and hide the structure
 * that makes them findable, so the second level becomes a column heading and
 * the third the links under it — the shape of the reference storefront's
 * menu, built from the menu itself rather than from a plugin.
 *
 * Desktop only. Below the drawer breakpoint the whole navigation is a stacked
 * list where every level is already open and indented, and a grid there would
 * fight it — hence the min-width query rather than a max-width undo further
 * down the file.
 */
@media (min-width: 1260px) {
	/* Taken out of the positioning chain so the panel spans the header rather
	 * than the menu item, the same trick the picture-tile mega uses. */
	.main-nav .menu-item-has-columns {
		position: static;
	}

	.main-nav .menu-item-has-columns > .sub-menu {
		/* `inset-inline` sets both physical sides, so the `left: 0` the plain
		 * dropdown carries is already overwritten. Following it with
		 * `left: auto` — which an earlier pass did — silently unsets the start
		 * inset again and the panel shrink-wraps back to the menu item. */
		inset-inline: 0;
		min-width: 0;
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
		gap: var(--s-8) var(--s-12);
		/* The panel is full-bleed but its contents line up with the wrap, so
		 * the first column starts under the logo rather than against the
		 * window edge. Same expression the hero split is built from. */
		padding: var(--s-10) max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter)));
		border-inline: 0;
		border-block-end: 1px solid var(--border);
		/* Shop's panel is 672px tall — taller than the space under the header
		 * on a 768px laptop, where the last group would be cut off by the
		 * bottom of the window with nothing to say so. It scrolls in that
		 * case; on a taller screen the max-height is never reached.
		 *
		 * The half-rem is not padding: `top: 100%` resolves against the
		 * header's padding box and a percentage max-height against its content
		 * box, and the 6px between the two left the panel hanging that far
		 * past the bottom of a 768px window. */
		max-height: calc(100vh - 100% - 0.5rem);
		max-height: calc(100dvh - 100% - 0.5rem);
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	/* Second level: the heading of a column, not a link in a list — though it
	 * is still a link, because "Women → New Brand" is a page worth reaching. */
	.main-nav .menu-item-has-columns > .sub-menu > li > a {
		padding: 0 0 var(--s-2);
		margin-block-end: var(--s-3);
		border-block-end: 1px solid var(--border);
		font-size: var(--text-2xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		color: var(--ink);
	}

	.main-nav .menu-item-has-columns > .sub-menu > li > a:hover,
	.main-nav .menu-item-has-columns > .sub-menu > li > a:focus-visible {
		color: var(--bronze-dark);
	}

	/*
	 * Third level: always open. It is inside a panel that is itself revealed
	 * on hover, so hiding it behind a second hover would mean pointing at a
	 * heading to see the four links that are the reason the panel opened.
	 *
	 * `visibility: inherit`, not `visible`. An explicitly visible child stays
	 * visible inside a hidden parent, and a visible element is hit-tested and
	 * tabbed to: these links sat unseen over the middle of the page, down to
	 * 848px on a 900px window, and a mouse travelling up from the bottom
	 * crossed one, hovered its ancestor and opened the whole panel hundreds of
	 * pixels away from the menu. They were in the tab order the whole time
	 * too. Inheriting ties them to the panel that owns them.
	 */
	.main-nav .menu-item-has-columns .sub-menu .sub-menu {
		position: static;
		display: block;
		opacity: 1;
		visibility: inherit;
		transform: none;
		min-width: 0;
		padding: 0;
		border: 0;
		box-shadow: none;
		background: none;
	}

	.main-nav .menu-item-has-columns .sub-menu .sub-menu a {
		padding: var(--s-1) 0;
		color: var(--ink-60);
	}

	/*
	 * Fourth level. Shop holds the genders, a gender is a column, and inside
	 * a column the houses group the collections — so the third level is a
	 * label over a group rather than a link among links. Without this the
	 * column read as one undifferentiated run of thirteen links and the
	 * grouping the menu was built to show was invisible.
	 */
	.main-nav .menu-item-has-columns > .sub-menu > li > .sub-menu > li + li {
		margin-block-start: var(--s-5);
	}

	.main-nav .menu-item-has-columns > .sub-menu > li > .sub-menu > li > a {
		padding: 0 0 var(--s-1);
		font-size: var(--text-2xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		color: var(--ink-85);
	}

	.main-nav .menu-item-has-columns > .sub-menu > li > .sub-menu > li > a:hover,
	.main-nav .menu-item-has-columns > .sub-menu > li > .sub-menu > li > a:focus-visible {
		color: var(--bronze-dark);
	}

	.main-nav .menu-item-has-columns .sub-menu .sub-menu a:hover,
	.main-nav .menu-item-has-columns .sub-menu .sub-menu a:focus-visible {
		color: var(--ink);
	}

	/* The chevron belongs on the item that opens the panel. On a column
	 * heading it would promise a second panel that does not exist. */
	.main-nav .menu-item-has-columns .sub-menu .nav-caret {
		display: none;
	}
}

.header-actions {
	display: flex;
	align-items: center;
	gap: var(--s-6);
	flex-shrink: 0;
}

.header-actions a,
.header-actions button {
	display: inline-flex;
	align-items: center;
	gap: var(--s-2);
	background: none;
	border: 0;
	padding: 0;
	color: var(--ink-85);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.12em;
	text-transform: uppercase;
	cursor: pointer;
}

.header-actions svg {
	width: 20px;
	height: 20px;
	stroke: currentColor;
	fill: none;
	stroke-width: 1.15;
}

/* A fingertip is ~44px across and the icons are 20. The padding supplies the
 * difference and the negative margin hands it straight back to the layout, so
 * the targets grow without moving anything around them. The apply button is
 * excluded: it draws a padded border of its own and a negative margin would
 * visibly shift it. */
.header-actions a:not(.header-actions__apply),
.header-actions button {
	padding: var(--s-3);
	margin: calc(-1 * var(--s-3));
}

.header-actions .count {
	font-variant-numeric: tabular-nums;
}

/*
 * Applying for an account is the one thing a new visitor to a wholesale-only
 * store is meant to do, so it is a button in the header rather than the fifth
 * text link in a nav bar, which is where it was and where nothing is ever
 * read. Outlined, not filled: it is the second action after signing in, and
 * two filled buttons side by side would compete.
 */
.header-actions__apply {
	padding: var(--s-2) var(--s-4) !important;
	/* Gold at rest, not grey. It is the one thing a new visitor is here to do
	 * and the crest is the only other gold on the page, so the two read as the
	 * same invitation. The text is --bronze-dark rather than --bronze: 5.9:1
	 * on the page ground where the lighter gold is 3.4:1, and this is small
	 * type. */
	border: 1px solid var(--bronze) !important;
	color: var(--bronze-dark) !important;
	transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

/* Hover fills rather than darkens. Ink on gold measures 5.2:1, so the label
 * stays readable at the moment it matters most. */
.header-actions__apply:hover,
.header-actions__apply:focus-visible {
	background: var(--bronze) !important;
	border-color: var(--bronze) !important;
	color: var(--ink) !important;
}

/* Below the drawer breakpoint the theme prints an apply link as the drawer's
 * first item, so this one would be a second copy of the same invitation on
 * the same screen. */
@media (max-width: 1259px) {
	.header-actions__apply {
		display: none !important;
	}
}

/*
 * v2: the toggle now sits outside .header-actions (see cuba_maison_header_actions),
 * so it no longer inherits that block's button styling and carries its own.
 * The padding-and-negative-margin trick is the same one the icons use: a 44px
 * target that gives its extra space straight back to the layout.
 */
.site-header__nav > .nav-toggle {
	display: none;
	align-items: center;
	background: none;
	border: 0;
	color: var(--ink-85);
	cursor: pointer;
	padding: var(--s-3);
	margin: calc(-1 * var(--s-3));
}

.site-header__nav > .nav-toggle svg {
	width: 20px;
	height: 20px;
	stroke: currentColor;
	fill: none;
	stroke-width: 1.15;
}

/* The row is brand + six nav items + actions, all of them nowrap, and below
 * about 1240px they no longer fit however the space is divided. The drawer
 * takes over there rather than at 1024, where the header had been overflowing
 * for the whole band in between. 1260 leaves the desktop nav on a 1280 screen,
 * scrollbar included. */
@media (min-width: 1260px) and (max-width: 1399px) {
	.main-nav ul {
		gap: var(--s-6);
	}
}

/* The drawer-only trade button. Above the breakpoint the header carries its
 * own, so this one would be a duplicate. */
.nav-drawer-apply {
	display: none;
}

/* Drawer furniture. Both are rendered on every page and shown only at the
 * drawer breakpoint: the bar because a panel over the page must always carry
 * its own way out, the chevron buttons because the script adds them once and
 * the desktop menu opens on hover instead. */
.nav-drawer__bar,
.nav-drawer__expand {
	display: none;
}

/* Insurance, not layout: if a menu item is ever added the nav takes a second
 * line inside the header instead of pushing the actions off the screen. */
.main-nav {
	min-width: 0;
}

.main-nav > ul {
	flex-wrap: wrap;
	row-gap: var(--s-2);
}

@media (max-width: 1259px) {
	/* Below this width the drawer is the navigation, and the burger is the
	 * only way into it — so in this band the burger is the whole of what is
	 * in flow. The drawer itself is fixed and never competes for the space.
	 *
	 * The button carries 12px of padding and hands it straight back with a
	 * negative margin, which is how it stays a 44px target without taking
	 * 44px of layout; the start margin adds the gutter the wrap would have
	 * given it, less that same 12. */
	.site-header__nav > .nav-toggle {
		display: inline-flex;
		margin-inline-start: calc(var(--gutter) - var(--s-3));
	}

	.site-header__nav {
		padding-block: var(--s-3);
	}

	.site-header__nav > .main-nav {
		max-width: none;
		padding-inline: 0;
		padding-block: 0;
	}

	/*
	 * The drawer flies in from the left over the page, rather than dropping
	 * out of the header.
	 *
	 * The dropped list had no way out of its own — the burger that opened it
	 * ends up behind the scrim — and it grew with the menu: with the houses
	 * and collections under Shop it was 53 links stacked open, a wall that had
	 * to be scrolled past to reach the account rows at the bottom. A panel has
	 * a fixed frame, its own close button in the same place every time, and
	 * levels that stay shut until they are asked for.
	 *
	 * It is hidden with `visibility` rather than `display`, because a panel
	 * that is only translated off-screen is still in the tab order — a
	 * keyboard user would have tabbed through the whole menu before reaching
	 * the page. `visibility` is also the one property here that animates, so
	 * the panel is still in the layout for the slide and gone for the tab
	 * order afterwards.
	 */
	.main-nav {
		display: block;
		position: fixed;
		inset-block: 0;
		inset-inline-start: 0;
		z-index: 60;
		width: min(88vw, 22.5rem);
		background: var(--paper);
		box-shadow: var(--shadow-lg);
		overflow-y: auto;
		overscroll-behavior: contain;
		visibility: hidden;
		transform: translateX(-100%);

		/*
		 * Visibility is switched, never interpolated, and the two directions
		 * are not symmetric. Closing waits the length of the slide, so the
		 * drawer is still drawn while it leaves. Opening flips it at once —
		 * with a duration here instead of a delay the drawer still computed
		 * as hidden a frame after the class landed, and focus() on the close
		 * button silently did nothing, leaving the keyboard behind the scrim.
		 * Measured, not guessed.
		 */
		transition: transform var(--speed) var(--ease), visibility 0s var(--speed);
	}

	.main-nav.is-open {
		visibility: visible;
		transform: translateX(0);
		transition: transform var(--speed) var(--ease), visibility 0s;
	}

	/* The bar: the drawer's title and its close button, held at the top while
	 * the list under it scrolls. */
	.nav-drawer__bar {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: var(--s-4);
		position: sticky;
		top: 0;
		z-index: 1;
		padding: var(--s-3) var(--s-3) var(--s-3) var(--gutter);
		background: var(--paper);
		border-bottom: 1px solid var(--border);
	}

	.nav-drawer__title {
		font-family: var(--font-sans);
		font-size: var(--text-2xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		color: var(--ink-60);
	}

	.nav-drawer__close {
		display: grid;
		place-items: center;
		/* 44px: the smallest thing a thumb should be asked to hit. */
		width: 44px;
		height: 44px;
		padding: 0;
		border: 0;
		background: none;
		color: var(--ink);
		cursor: pointer;
	}

	.nav-drawer__close svg {
		width: 20px;
		height: 20px;
		fill: none;
		stroke: currentColor;
		stroke-width: 1.5;
		stroke-linecap: round;
	}

	/*
	 * Each row is a flex line: the link takes the width it can and the
	 * chevron sits at the end of it, with the submenu wrapping onto the next
	 * line. Done with wrapping rather than by wrapping the two in a new
	 * element, because every desktop rule in this file is written `li > a` and
	 * a wrapper would silently unhook all of them.
	 */
	.main-nav li {
		display: flex;
		flex-wrap: wrap;
		align-items: stretch;
	}

	.main-nav li > a {
		flex: 1 1 auto;
		min-width: 0;
	}

	.nav-drawer__expand {
		display: grid;
		place-items: center;
		flex: 0 0 3.25rem;
		padding: 0;
		border: 0;
		border-bottom: 1px solid var(--border);
		background: none;
		color: var(--ink-60);
		cursor: pointer;
	}

	.nav-drawer__expand svg {
		width: 16px;
		height: 16px;
		fill: none;
		stroke: currentColor;
		stroke-width: 1.5;
		stroke-linecap: round;
		stroke-linejoin: round;
		transition: transform var(--speed) var(--ease);
	}

	.main-nav .is-expanded > .nav-drawer__expand {
		color: var(--ink);
	}

	.main-nav .is-expanded > .nav-drawer__expand svg {
		transform: rotate(180deg);
	}

	/* The chevron inside the link is the desktop affordance; here the button
	 * beside it is the one that does something. */
	.main-nav .nav-caret {
		display: none;
	}

	/* Under the header (z-50) so the drawer itself stays lit, over everything
	 * else so the page reads as inert. It is also the tap target that closes
	 * the drawer — see site.js. */
	.nav-open::before {
		content: "";
		position: fixed;
		inset: 0;
		z-index: 49;
		background: rgba(23, 23, 23, 0.4);
	}

	/* Scoped to the drawer breakpoint so that a rotation into the desktop
	 * layout can never leave the document frozen. */
	.nav-open,
	.nav-open body {
		overflow: hidden;
	}

	.main-nav ul {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
	}

	.main-nav a {
		display: block;
		padding: var(--s-4) var(--gutter);
		border-bottom: 1px solid var(--border);
		font-size: var(--text-sm);
		letter-spacing: 0.1em;
	}

	/* The underline is a header device; in a stacked drawer every item would
	 * carry a rule under it and the marker would stop marking anything. */
	.main-nav > ul > li > a::after {
		display: none;
	}

	.nav-drawer-apply {
		display: block;
	}

	/* Gold, for the reason the desktop button is gold — and because black was
	 * a full-width slab directly under the drawer's own bar, which read as a
	 * gap in the menu rather than as the invitation it is. Ink on gold, 5.2:1;
	 * the press state goes darker gold with light type, 5.9:1, so there is no
	 * point at which this turns black. */
	.main-nav .nav-drawer-apply a {
		background: var(--bronze);
		color: var(--ink);
		border-bottom: 0;
		font-weight: 600;
	}

	.main-nav .nav-drawer-apply a:hover,
	.main-nav .nav-drawer-apply a:active,
	.main-nav .nav-drawer-apply a:focus-visible {
		background: var(--bronze-dark);
		color: var(--paper);
	}

	/*
	 * Submenus are closed until the chevron opens them. On a touch screen
	 * there is no hover to hide them behind, so the button is the interaction
	 * — and with four levels in the menu, opening every one of them at once
	 * put 53 links in a column nobody would read.
	 *
	 * `visibility: inherit`, not `visible`: an explicitly visible child stays
	 * visible inside a hidden parent, which would have left the whole closed
	 * drawer tabbable off-screen.
	 */
	.main-nav .sub-menu {
		display: none;
		flex: 0 0 100%;
		position: static;
		opacity: 1;
		visibility: inherit;
		transform: none;
		border: 0;
		box-shadow: none;
		padding: 0;
		min-width: 0;
		background: var(--shell);
	}

	.main-nav .is-expanded > .sub-menu,
	.main-nav .is-expanded > .mega {
		display: block;
	}

	/* One step of indent per level, so depth is legible without a rule or a
	 * bullet to draw it. */
	.main-nav .sub-menu a {
		padding-inline-start: calc(var(--gutter) + var(--s-6));
	}

	.main-nav .sub-menu .sub-menu a {
		padding-inline-start: calc(var(--gutter) + var(--s-12));
	}

	.main-nav .sub-menu .sub-menu .sub-menu a {
		padding-inline-start: calc(var(--gutter) + var(--s-16) + var(--s-2));
	}
}

/*
 * Phones.
 *
 * The header was overflowing the viewport by ~150px: the wordmark does not
 * wrap (by design) and the "Trade login" label sat beside it, so the two
 * together were wider than a 390px screen and the whole document scrolled
 * sideways. The label goes — the person icon says the same thing — and the
 * wordmark steps down a size.
 */
@media (max-width: 767px) {
	.site-brand {
		min-width: 0;
	}

	.site-brand__name {
		font-size: 1.0625rem;
		letter-spacing: 0.18em;
	}

	/*
	 * Phones: the crest is competing with the burger on one side and two or
	 * three account icons on the other. 46px tall is the size that leaves it
	 * legible; height:auto with a max-height means that if a narrow screen
	 * (or a signed-in header, which carries an extra icon) squeezes the middle
	 * column, the badge scales down in proportion instead of being crushed
	 * horizontally, which is what a fixed height plus max-width would do.
	 */
	.site-brand img.site-brand__crest {
		height: auto;
		/* v2 — 42px → 63px, the same half again the desktop crest gained. It
		 * is still a ceiling rather than a height, so a 320px screen scales
		 * the badge down in proportion instead of overflowing. */
		max-height: 63px;
		max-width: 100%;
	}

	/* Was 8px, which is below the size at which a tracked-out uppercase line is
	 * legible at arm's length. The tracking pays for the extra pixel, so the
	 * subline occupies the same width beside the wordmark as before. */
	.site-brand__sub {
		font-size: 0.5625rem;
		letter-spacing: 0.22em;
	}

	.header-actions {
		gap: var(--s-4);
	}

	/* Small phones: five controls, a centred crest and a 320px screen. The
	 * icons keep their 44px targets — the padding overlaps, the ink does not. */
	@media (max-width: 400px) {
		.header-actions {
			gap: var(--s-3);
		}
	}

	.header-actions__label {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}
}

/* --------------------------------------------------------------------------
   8. HERO
   -------------------------------------------------------------------------- */

.hero {
	position: relative;
	width: 100%;
	overflow: hidden;
	/*
	 * v2 — item 8: the band gives the copy a narrow column and the image
	 * everything else, with the warm pool of light sitting over the bottle.
	 *
	 * A fifth of the band is copy and the rest is picture. The split is the
	 * number given, and the copy column is derived from it — the other way
	 * round from the first version, where the column was fixed and the split
	 * followed. That version measured from the *wrap*, which is why it cannot
	 * survive here: on a 1920 screen the wrap's own left offset is already
	 * 13.5% of the band, so a 20% break would have left the headline about
	 * 100px of column. Inside the hero the copy therefore starts at the page
	 * gutter rather than at the wrap — a full-bleed band, aligned to the
	 * window instead of to the grid, which is what makes the fifth a fifth at
	 * any width.
	 *
	 * The 14rem floor is what stops the fifth collapsing on a small laptop:
	 * measured at 1024 the column came out 119px and set "Cuba Authentic
	 * Crystal" wider than its own box. Above about 1200px the fifth is the
	 * larger of the two and takes over on its own, so the two rules meet
	 * without a breakpoint between them.
	 */
	--hero-copy: max(14rem, calc(20% - var(--gutter) - var(--s-4)));
	--hero-split: calc(var(--gutter) + var(--hero-copy) + var(--s-4));
	/* How far the scene backdrop reaches past the band before being clipped
	 * back to it — comfortably more than the blur radius. */
	--hero-bleed: 4rem;
	background:
		radial-gradient(110% 95% at 62% 46%, rgba(184, 151, 120, 0.14) 0%, rgba(184, 151, 120, 0) 64%),
		linear-gradient(90deg, var(--cream) 0 var(--hero-split), var(--paper) var(--hero-split) 100%);
	min-height: clamp(32rem, 50vw, 44rem);
}

.hero__slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	pointer-events: none;
	transition: opacity 1s var(--ease);
}

.hero__slide.is-active {
	opacity: 1;
	pointer-events: auto;
}

/* The first slide is also laid out in normal flow so it establishes the
 * hero's height. Absolutely positioning every slide would collapse the
 * section to zero and require a fixed height in every breakpoint. */
.hero__slide:first-child {
	position: relative;
	min-height: inherit;
}

/*
 * Packshots, not lifestyle photography.
 *
 * The catalogue is square studio imagery shot on white. `object-fit: cover`
 * on a 1:1 source stretched into a 16:9 band enlarges the bottle until the
 * headline lands on top of it — which is exactly what the hero was doing.
 * The image is instead *contained* inside its own half of the band, so the
 * bottle is shown whole at a sane size and the type has clear air beside it.
 *
 * multiply blending dissolves the white studio background into the cream
 * panel behind it, so there is no visible photo rectangle. It is safe here
 * precisely because every source is a white-backed packshot.
 */
.hero__media {
	position: absolute;
	inset-block: 0;
	inset-inline-end: 0;
	/* v2 — item 8: everything the copy column does not use, up from 46%. The
	 * image is still contained, so a square packshot is bound by the height
	 * rather than the width; the band grew taller and lost most of its
	 * vertical padding so the bottle actually gets bigger rather than just
	 * gaining empty gutters. object-position sits it left of centre in its
	 * box, which keeps it beside the copy instead of drifting toward the
	 * right edge.
	 *
	 * The width is derived from the split rather than given its own number,
	 * so the image can never be laid out over the headline however wide the
	 * screen gets. It has to be stated: an absolutely positioned *replaced*
	 * element with `width: auto` takes its intrinsic width and ignores the
	 * second inset, which sized the box to the photograph instead of to the
	 * band. */
	inset-inline-start: var(--hero-split);
	width: calc(100% - var(--hero-split));
	height: 100%;
	min-height: 0;
	/*
	 * v2 — the image fills its share of the band.
	 *
	 * `contain` was leaving the picture floating in white: a 4:3 render inside
	 * a box nearer 1.4:1 is bound by the height, so it took about 60% of the
	 * width it was given and the rest stayed empty — which is what made three
	 * quarters of the band look like half of it. `cover` gives the whole
	 * region to the picture. The crop is vertical and modest (the sources are
	 * 1:1 and 4:3 scene renders, not tight packshots), and sitting the frame
	 * slightly above centre keeps the bottle, which is always in the lower
	 * half, out of it. The padding goes with it — a full-bleed image has no
	 * use for a gutter it would only crop into.
	 */
	/*
	 * v2 — nothing in the hero is cropped any more.
	 *
	 * `cover` filled the band, but the sources are square (1:1) and the
	 * picture half is about 1.6:1 at 1440 and 2.2:1 at 1920 — so cover was
	 * throwing away nearly two fifths of every frame's height, and on a
	 * packshot that lands on the one thing the slide exists to show: the
	 * bottle was cut off at the foot, and on the Altus scene at the cap.
	 * No object-position can fix that; the frame is simply taller than the
	 * hole. `contain` shows each photograph whole. A packshot's white ground
	 * multiplies into the cream panel, so the space either side of it is
	 * invisible; a scene gets the backdrop below instead of empty cream.
	 *
	 * The bottle is smaller than it was — that is the price of showing all of
	 * it, and it disappears the moment the imagery is supplied at the band's
	 * own proportion: the picture half is 1140x704 at 1440 and 1524x704 at
	 * 1920, so a landscape frame near 16:10 fills it edge to edge.
	 */
	object-fit: contain;
	object-position: center center;
	padding: 0;
	mix-blend-mode: multiply;
	/* v2 — item 8: a light golden cast over imagery shot on neutral white.
	 * Kept low: sepia at full strength turns a silver cap brass. Because the
	 * layer multiplies into the cream panel, the tinted white ground still
	 * disappears and no photo rectangle appears. */
	filter: sepia(0.2) saturate(1.06);
}

/*
 * A slide carrying its own commercial photograph rather than the catalogue
 * packshot. Everything above is tuned for a bottle cut out on white: multiply
 * dissolves that white into the cream panel and the sepia warms it. A scene
 * shot on a dark gold ground has no white to dissolve — multiplied it goes
 * muddy and the bottle disappears into it. So the blend and the tint come off,
 * and the picture keeps its own edges.
 */
.hero__media--scene {
	mix-blend-mode: normal;
	filter: none;
}

/*
 * What fills the band around an uncropped scene.
 *
 * A packshot needs nothing here: its white ground multiplies away and the
 * cream panel simply continues past the bottle. A photograph has real edges,
 * and contained on cream it reads as a snapshot pasted into the page. The
 * same image, covering the whole half and blurred well past legibility,
 * gives the band the scene's own light — dusk orange behind Altus, warm gold
 * behind Crystal — with the photograph sitting whole on top of it.
 *
 * Deliberately the medium file, not the full one: it is scaled up and blurred
 * to 32px, so the pixels are thrown away anyway, and the browser is already
 * fetching the full size for the layer above.
 */
.hero__backdrop {
	position: absolute;
	/*
	 * Bled past the band on all four sides and then clipped back to it. A
	 * blur samples transparency beyond the element's own edge, so a backdrop
	 * sized to the band fades out into a pale rim; scaling it up instead —
	 * the first thing tried — pushed the blur sideways over the copy column,
	 * where it showed as a smear behind the headline. Bleeding and clipping
	 * gives a hard edge exactly on the split with no rim anywhere.
	 *
	 * Both the width and the height are stated: an absolutely positioned
	 * *replaced* element with `auto` takes its intrinsic size and ignores the
	 * opposite inset.
	 */
	inset-block: calc(var(--hero-bleed) * -1);
	inset-inline-start: calc(var(--hero-split) - var(--hero-bleed));
	width: calc(100% - var(--hero-split) + var(--hero-bleed) * 2);
	height: calc(100% + var(--hero-bleed) * 2);
	clip-path: inset(var(--hero-bleed));
	object-fit: cover;
	object-position: center 40%;
	filter: blur(32px) saturate(1.08) brightness(0.92);
}

/* Kept in the markup for the fallback hero, which may still be a wide
 * lifestyle image; with a contained packshot there is nothing to scrim. */
.hero__scrim {
	display: none;
}

.hero__body {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
}

/* A quarter of the band is a narrow measure, so the display size drops with
 * it — at 48px the site name would set three ragged lines in this column.
 * The same variable the split is built from, so the column and the colour
 * break are one measurement rather than two that agree by hand. */
.hero__content {
	max-width: var(--hero-copy);
}

/* The copy is inside a `.wrap`, which centres itself on the container width.
 * The hero is the one band where that must not happen: see --hero-split. */
.hero__body .wrap {
	max-width: none;
}

.hero__content .t-hero {
	font-size: clamp(1.75rem, 2.2vw, 2.375rem);
}

.hero__content > * + * {
	margin-block-start: var(--s-3);
}

.hero__content .btn {
	margin-block-start: var(--s-8);
}

/*
 * v2 — item 4: arrows, not dots.
 *
 * The dots were two-pixel bars on a photograph: on a light slide they
 * disappeared, and nothing about them said which way they moved. A pair of
 * arrows says "there is another one, this way" without a legend, and gives the
 * eye something big enough to aim at. They sit inside the image half of the
 * band, hard against its two edges, so they never cross the copy column.
 */
.hero__nav {
	position: absolute;
	inset-block: 0;
	inset-inline: var(--hero-split) 0;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding-inline: var(--s-4);
	/* The strip spans the picture; only the buttons in it are clickable, or it
	 * would swallow every click on the slide behind it. */
	pointer-events: none;
}

.hero__arrow {
	pointer-events: auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border-radius: 50%;
	border: 1px solid var(--ink-15);
	/* Translucent paper rather than a flat swatch: over a dark render it reads
	 * as a control resting on the picture, and over a pale one it still has an
	 * edge. The blur is what keeps the chevron legible on a busy photograph. */
	background: rgba(253, 251, 245, 0.82);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	color: var(--ink);
	cursor: pointer;
	box-shadow: var(--shadow-sm);
	transition: background-color var(--speed) var(--ease), color var(--speed) var(--ease), transform var(--speed) var(--ease);
}

.hero__arrow svg {
	width: 20px;
	height: 20px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.hero__arrow:hover,
.hero__arrow:focus-visible {
	background: var(--ink);
	color: var(--paper);
}

.hero__arrow:hover {
	transform: scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
	.hero__arrow:hover {
		transform: none;
	}
}

@media (max-width: 1023px) {
	.hero {
		min-height: clamp(28rem, 52vw, 34rem);
	}

	/* Tablets keep a readable column instead of the fifth. A fifth of 1024px
	 * is 205px, and a fifth of 768 is 154 — at the hero's display size that
	 * sets two or three characters to the line. The picture still takes
	 * everything the copy does not, so the proportion moves with the screen
	 * rather than being a second, contradictory number. */
	.hero {
		--hero-copy: clamp(14rem, 22vw, 18rem);
		--hero-split: calc(var(--gutter) + var(--hero-copy) + var(--s-4));
	}

	.hero__media {
		padding: var(--s-6) var(--s-4);
	}

	/* The backdrop is not padded with it — it is the ground, and a gutter
	 * would show as a cream frame around the blur. */
	.hero__backdrop {
		padding: 0;
	}
}

/*
 * Below 768px there is no room for two columns, so the band stacks: the
 * packshot takes the top half against cream, the copy sits centred beneath
 * it on white. The slides stay absolutely positioned — only the first is in
 * flow — so the carousel keeps working without a fixed pixel height.
 */
@media (max-width: 767px) {
	.hero {
		min-height: 0;
		background: linear-gradient(180deg, var(--cream) 0%, var(--cream) 52%, var(--paper) 52%, var(--paper) 100%);
	}

	.hero__slide:first-child {
		min-height: clamp(35rem, 125vw, 44rem);
	}

	/* Stacked, the split does not apply — there are no columns to split. The
	 * packshot keeps the generous top band it already had, and the left inset
	 * the wide layout set has to be unwound explicitly. */
	.hero__media {
		inset-block: 0 auto;
		inset-inline: 0;
		width: 100%;
		height: 52%;
		padding: 0;
	}

	/* Stacked, the picture is the top band and there is no split to clip to,
	 * so the backdrop bleeds only downward — under the copy, where it is
	 * covered by the paper half anyway. */
	.hero__backdrop {
		inset-block: 0 auto;
		inset-inline-start: calc(var(--hero-bleed) * -1);
		width: calc(100% + var(--hero-bleed) * 2);
		height: calc(52% + var(--hero-bleed));
		clip-path: inset(0 var(--hero-bleed) var(--hero-bleed));
		padding: 0;
	}

	.hero__body {
		align-items: flex-end;
		padding-block-end: var(--s-16);
	}

	/* Stacked, the arrows belong over the picture at the top, not over the
	 * copy beneath it. They also shrink: 48px is a comfortable target and
	 * anything larger starts covering the bottle on a 375px screen. */
	.hero__nav {
		inset-block: 0 auto;
		inset-inline: 0;
		height: 52%;
		padding-inline: var(--s-3);
	}

	.hero__arrow {
		width: 44px;
		height: 44px;
	}

	.hero__content {
		max-width: none;
		text-align: center;
	}

	.hero__content .t-hero {
		font-size: var(--text-hero);
	}

	.hero__content .btn {
		margin-block-start: var(--s-6);
	}
}

/*
 * The tally under a category tile — see cuba_maison_subcategory_count().
 *
 * Its own line under the name, in the small-caps register the shop head counts
 * in, rather than a bracketed figure trailing a display serif.
 */
.cat-count {
	display: block;
	margin-block-start: var(--s-2);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 400;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink-45);
	font-variant-numeric: tabular-nums;
}

/* Belt and braces. The filter above replaces WooCommerce's <mark> wherever it
 * runs through it; anything that prints one another way would otherwise land
 * on the browser's default highlighter yellow, which no ground on this site
 * survives. */
mark.count {
	background: none;
	color: inherit;
}

/* --------------------------------------------------------------------------
   8b. BRANDMARK

   The front page's opening image: the crest at the width of the window, in
   place of the hero carousel.

   Full-bleed rather than inside the wrap. It is the one element on the site
   that is the house itself rather than something the house sells, and a
   gutter either side would make it look like a picture of a logo instead.
   -------------------------------------------------------------------------- */

.brandmark {
	/* The same paper as the header above it, so the crest sits in one
	 * continuous field rather than on a panel of its own. The art has a
	 * transparent ground, which is what lets that read. */
	background: var(--gold-tint);
	border-bottom: 1px solid var(--gold-rule);

	/*
	 * Room around the badge. Bled to all four edges it read as a crop of a
	 * bigger picture rather than as a mark on paper — a maker's mark is
	 * printed with a margin, and the margin is most of what says it is one.
	 *
	 * The inline figure is the page's own gutter, so the crest starts where
	 * every other line on the site starts instead of at the edge of the
	 * glass. It buys sharpness as well: the art tops out at 1120px, and
	 * every pixel not asked for is one less pixel of upscaling.
	 */
	padding-block: var(--s-10);
	padding-inline: var(--gutter);
}

/*
 * line-height: 0 because the h1 is a picture — a heading's leading under an
 * image is a strip of empty paper nothing put there.
 *
 * The ceiling is the art's own width. Above 1120px the badge was being scaled
 * up, which softens filigree this fine before it softens anything else, and it
 * was reaching within a gutter of both edges on a wide screen, which read as a
 * crop rather than as a mark. Held at its native size it is pixel-exact on
 * every desktop and takes about four fifths of a 1440 screen, with paper
 * either side. Narrower than that it fills the measure as before.
 *
 * If a wider export of the crest ever lands in assets/img, raise this to match
 * it — that and the file are the only two things standing between here and a
 * genuinely full-bleed mark.
 */
.brandmark__title {
	margin: 0;
	line-height: 0;
	max-width: 1120px;
	margin-inline: auto;
}

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

/* A phone has a quarter of the width to give away, and the badge is the whole
 * of the band, so the vertical margin narrows with the screen. The inline one
 * does not — it is the gutter, and the gutter is already smaller here. */
@media (max-width: 767px) {
	.brandmark {
		padding-block: var(--s-6);
	}
}

/* The typographic fallback, for an install with no crest in assets/img. */
.brandmark--type .brandmark__title {
	line-height: 1.1;
	padding-block: var(--s-16);
	text-align: center;
	font-size: var(--text-hero);
	letter-spacing: var(--track-wide);
}

/* --------------------------------------------------------------------------
   9. ASSURANCE BAR
   -------------------------------------------------------------------------- */

.assurance {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--grid-gap);
	padding-block: var(--s-16);
	border-block-start: 1px solid var(--border);
}

.assurance__item {
	display: flex;
	align-items: flex-start;
	gap: var(--s-4);
}

.assurance__icon {
	flex-shrink: 0;
	width: 36px;
	height: 36px;
	stroke: var(--bronze);
	fill: none;
	stroke-width: 1.15;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.assurance__title {
	font-family: var(--font-sans);
	font-size: 1.125rem;
	font-weight: 500;
	color: var(--ink);
	line-height: 1.25;
}

.assurance__text {
	font-size: var(--text-sm);
	color: var(--fg-muted);
	line-height: 1.65;
	margin-block-start: var(--s-2);
}

@media (max-width: 1023px) {
	.assurance {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--s-8);
	}
}

@media (max-width: 479px) {
	.assurance {
		grid-template-columns: 1fr;
	}
}

/* --------------------------------------------------------------------------
   10. SECTION HEADS
   -------------------------------------------------------------------------- */

.section-head {
	text-align: center;
	max-width: 42rem;
	margin-inline: auto;
	margin-block-end: var(--s-12);
}

.section-head > * + * {
	margin-block-start: var(--s-3);
}

/*
 * Set in caps — Trending Products, New Arrivals, Our Brands, Contact Us — so
 * the four section heads carry the same register as the wordmark above them
 * and the small-caps labels through the rest of the page.
 *
 * Uppercased here rather than in the four strings, so what a screen reader
 * announces stays "Trending products" rather than an initialism, and a
 * translation is not forced into a case its language may not use.
 *
 * Tracked at 0.08em, not the --track-wide the small labels use: tracking is
 * a correction for the tight fit of small type and caps at 26–34px do not
 * need it. At a quarter-em TRENDING PRODUCTS is wider than a 390px phone and
 * breaks over two lines.
 */
.section-head__title {
	--head-track: 0.08em;

	font-size: var(--text-h2);
	text-transform: uppercase;
	letter-spacing: var(--head-track);
}

/*
 * A little tighter on a phone. TRENDING PRODUCTS is the longest of the four
 * and at 0.08em it came to about 330px in the 327px a 390px screen leaves
 * after the gutters — three pixels over, and a two-word heading broke into
 * two lines for them. The tracking is the part of the line that can give.
 */
@media (max-width: 767px) {
	.section-head__title {
		--head-track: 0.045em;
	}
}

/*
 * Letter-spacing is applied after every character including the last, so a
 * centred line sits half its tracking left of true centre. The indent puts
 * that back. Not on --start, which is left-aligned: there the trailing space
 * falls off the end of the line where nobody can see it.
 */
.section-head:not(.section-head--start) .section-head__title {
	text-indent: var(--head-track);
}

/* A short bronze rule under the section title. It is the only place the
 * accent appears at rest anywhere on the page, which is what makes it read
 * as punctuation rather than decoration. */
.section-head__title::after {
	content: "";
	display: block;
	width: 48px;
	height: 1px;
	background: var(--bronze);
	margin: var(--s-4) auto 0;
}

.section-head--start {
	text-align: left;
	margin-inline: 0;
	max-width: none;
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--s-6);
	flex-wrap: wrap;
}

.section-head--start .section-head__title::after {
	margin-inline: 0;
}

/* --------------------------------------------------------------------------
   11. PRODUCT CARDS AND GRIDS
   -------------------------------------------------------------------------- */

.card-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--grid-gap);
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (max-width: 1023px) {
	.card-grid {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--s-6);
	}
}

@media (max-width: 767px) {
	.card-grid {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--s-6);
	}
}

.product-card {
	position: relative;
	display: flex;
	flex-direction: column;
}

/* A square frame on a light ground. Wholesale catalogue photography arrives
 * at every aspect ratio there is; a fixed square with object-fit is what
 * stops one tall bottle shot from making its row twice as deep as the rest. */
.product-card__frame {
	position: relative;
	display: block;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: var(--shell);
}

.product-card__frame img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity var(--speed-slow) var(--ease), transform 700ms var(--ease);
}

.product-card__frame .is-secondary {
	opacity: 0;
}

/* WooCommerce's archive item is li.product and carries no .product-card class,
 * so every hover rule for a card has to name both. Without the li.product half
 * the cross-fade fires on the front page and silently does nothing on the shop
 * and category archives, which is where most of the browsing happens. */
.product-card:hover .is-secondary,
.product-card:focus-within .is-secondary,
li.product:hover .is-secondary,
li.product:focus-within .is-secondary {
	opacity: 1;
}

/* With only one photograph there is nothing to cross-fade to, so the single
 * image takes a slow push-in instead. The card still responds; it just does
 * it with the assets that exist. */
.product-card:hover .is-primary:only-child,
.product-card:focus-within .is-primary:only-child,
li.product:hover .is-primary:only-child,
li.product:focus-within .is-primary:only-child {
	transform: scale(1.04);
}

.product-card__actions {
	position: absolute;
	top: var(--s-3);
	right: var(--s-3);
	display: flex;
	flex-direction: column;
	gap: var(--s-2);
	opacity: 0;
	/* Invisible has to mean unclickable. Opacity alone leaves both buttons
	 * hit-testable, so on any device that never fires the hover rule below
	 * they sat unseen over the corner of the photograph and swallowed the tap
	 * that was meant for the product. */
	pointer-events: none;
	transform: translateX(8px);
	transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease);
}

/* li.product for the same reason the cross-fade above needs it: the archive
 * renders WooCommerce's loop item, which carries no .product-card class. Named
 * only once, the controls stayed hidden on the shop and category pages even
 * with a mouse. */
.product-card:hover .product-card__actions,
.product-card:focus-within .product-card__actions,
li.product:hover .product-card__actions,
li.product:focus-within .product-card__actions {
	opacity: 1;
	pointer-events: auto;
	transform: translateX(0);
}

/* A touch screen never fires the rule above, so a reveal-on-hover control is
 * simply a control that does not exist. Both are permanently visible there
 * instead — saving a product and opening a quick view are the two things the
 * card offers. */
@media (hover: none), (pointer: coarse) {
	.product-card__actions {
		opacity: 1;
		pointer-events: auto;
		transform: none;
	}
}

.product-card__actions a,
.product-card__actions button {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	border: 0;
	border-radius: 9999px;
	background: rgba(255, 255, 255, 0.92);
	color: var(--ink);
	box-shadow: var(--shadow-sm);
	cursor: pointer;
}

.product-card__actions svg {
	width: 16px;
	height: 16px;
	stroke: currentColor;
	fill: none;
	stroke-width: 1.5;
}

.product-card__actions a:hover,
.product-card__actions button:hover {
	background: var(--ink);
	color: var(--paper);
}

/* The "read more" label the reference slides up from the bottom edge of the
 * image on hover. */
.product-card__reveal {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	padding: var(--s-3);
	text-align: center;
	background: rgba(23, 23, 23, 0.88);
	color: var(--paper);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	transform: translateY(100%);
	transition: transform var(--speed) var(--ease);
}

.product-card:hover .product-card__reveal,
.product-card:focus-within .product-card__reveal,
li.product:hover .product-card__reveal,
li.product:focus-within .product-card__reveal {
	transform: translateY(0);
}

.product-card__body {
	text-align: center;
	padding-block-start: var(--s-4);
}

.product-card__title {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	line-height: 1.4;
	color: var(--ink);
}

.product-card__meta {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: 0.08em;
	color: var(--fg-muted);
	margin-block-start: var(--s-2);
}

.product-card__price {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	color: var(--ink);
	margin-block-start: var(--s-2);
	font-variant-numeric: tabular-nums;
}

.product-card__price del {
	color: var(--fg-muted);
	margin-inline-end: var(--s-2);
}

/* --------------------------------------------------------------------------
   12. EDITORIAL FEATURE BLOCKS
   -------------------------------------------------------------------------- */

.feature {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--s-12);
	align-items: center;
	padding-block: var(--s-16);
}

.feature + .feature {
	border-top: 1px solid rgba(23, 23, 23, 0.07);
}

/* The image side alternates. Two identical blocks stacked read as a
 * template; mirrored, they read as a spread. */
.feature--reverse .feature__media {
	order: 2;
}

.feature__media {
	background: var(--cream);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--s-10);
}

.feature__media img {
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: contain;
	mix-blend-mode: multiply;
}

.feature__body > * + * {
	margin-block-start: var(--s-4);
}

.feature__title {
	font-size: var(--text-h3);
}

.feature__body p {
	color: var(--ink-60);
	line-height: var(--leading-body);
}

@media (max-width: 1023px) {
	.feature {
		grid-template-columns: 1fr;
		gap: var(--s-8);
		padding-block: var(--s-12);
	}

	.feature--reverse .feature__media {
		order: 0;
	}
}

/* --------------------------------------------------------------------------
   13. BRAND GRID
   -------------------------------------------------------------------------- */

.brand-grid {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: var(--s-6);
	list-style: none;
	margin: 0;
	padding: 0;
}

.brand-card {
	display: block;
	text-align: center;
}

.brand-card__frame {
	position: relative;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: var(--cream);
}

/* Contained, not cropped: the thumbnails are packshots, and `cover` clipped
 * the cap off the taller bottles. The padding gives each one the same air. */
.brand-card__frame img {
	width: 100%;
	height: 100%;
	padding: var(--s-6);
	object-fit: contain;
	mix-blend-mode: multiply;
	transition: transform 700ms var(--ease);
}

.brand-card:hover .brand-card__frame img {
	transform: scale(1.05);
}

.brand-card__name {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ink);
	margin-block-start: var(--s-3);
}

@media (max-width: 1023px) {
	.brand-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

@media (max-width: 599px) {
	.brand-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* --------------------------------------------------------------------------
   14. FOOTER
   -------------------------------------------------------------------------- */

.site-footer {
	background: var(--ink);
	color: var(--ink-30);
	font-size: var(--text-sm);
}

/*
 * Every link in the footer is grey on the dark ground — except a button, which
 * brings its own pair of colours. Without the :not() the two rules collided on
 * specificity and the button lost: `.site-footer a` (0,2,0) outranks
 * `.btn--light` (0,1,0), so the label was drawn in --ink-30 on near-white
 * paper, and on hover `.site-footer a:hover` painted it bronze on a bronze
 * background — invisible, which is exactly how it was reported.
 */
.site-footer a:not(.btn) {
	color: var(--ink-30);
}

.site-footer a:not(.btn):hover,
.site-footer a:not(.btn):focus-visible {
	color: var(--bronze);
}

/*
 * Three columns: the house, the brand list and the trade invitation.
 *
 * There were four, but the fourth — Company — only renders when a menu is
 * assigned to the footer location, and none is. A fixed four-track template
 * therefore left a quarter of the footer as blank ground and squeezed the
 * three columns that do exist into three quarters of it. Equal thirds now,
 * where the first column used to be weighted at 1.4: that weight was paying
 * for a three-line description which is now four words. If a Company menu is
 * ever assigned, its column wraps onto a second row — untidy, but visible,
 * which an implicit min-content track squeezed onto the end would not be.
 */
.site-footer__top {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--s-12);
	padding-block: var(--s-16);
}

.site-footer__title {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--paper);
	margin-block-end: var(--s-6);
}

.site-footer ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.site-footer li + li {
	margin-block-start: var(--s-3);
}

.site-footer .site-brand__name,
.site-footer .site-brand__sub {
	color: var(--paper);
}

.site-footer .site-brand {
	align-items: flex-start;
}

.site-footer .site-brand__sub {
	border-top-color: var(--ink-60);
	padding-inline: 0;
	color: var(--ink-30);
}

.site-footer__bottom {
	border-top: 1px solid rgba(255, 255, 255, 0.1);
	padding-block: var(--s-6);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-4);
	flex-wrap: wrap;
	font-size: var(--text-xs);
	color: var(--ink-45);
}

.social {
	display: flex;
	gap: var(--s-4);
	list-style: none;
	margin: 0;
	padding: 0;
}

.social a {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	border: 1px solid rgba(255, 255, 255, 0.18);
	border-radius: 9999px;
	transition: border-color var(--speed) var(--ease), background-color var(--speed) var(--ease);
}

.social a:hover {
	background: var(--bronze);
	border-color: var(--bronze);
	color: var(--paper);
}

.social svg {
	width: 16px;
	height: 16px;
	fill: currentColor;
}

@media (max-width: 1023px) {
	.site-footer__top {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--s-10);
	}
}

@media (max-width: 599px) {
	.site-footer__top {
		grid-template-columns: 1fr;
	}
}

/* --------------------------------------------------------------------------
   15. WOOCOMMERCE
   -------------------------------------------------------------------------- */

.woocommerce-breadcrumb {
	font-size: var(--text-xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--fg-muted);
	padding-block: var(--s-5) 0;
}

/*
 * The catalogue's page head: one band carrying the name of the view, how many
 * are in it, and the order they are in.
 *
 * It used to be a centred heading with a hand's depth of air above and below
 * it, and then a second bordered strip inside the results column repeating the
 * same register of small caps. Three horizontal bands to say one thing, and on
 * a laptop the first row of products started below the fold.
 *
 * Left-aligned because everything under it is — the breadcrumb, the filter
 * panel, the grid. A centred heading over a left-aligned catalogue is the one
 * thing on the page not lining up with anything else.
 */
.woocommerce-products-header {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	column-gap: var(--s-8);
	text-align: start;
	padding-block: var(--s-4) var(--s-5);
	margin-block-end: var(--s-6);
	border-block-end: 1px solid var(--border);
}

/* The description and the search prompt both render in here too, and neither
 * belongs beside the sort. Everything spans by default; the three that make
 * up the band are placed. */
.woocommerce-products-header > * {
	grid-column: 1 / -1;
}

.woocommerce-products-header__title {
	grid-column: 1;
	grid-row: 1;
	font-size: var(--text-h3);
	margin: 0;
}

.shop-head__count {
	grid-column: 1;
	grid-row: 2;
	margin: var(--s-2) 0 0;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-45);
	font-variant-numeric: tabular-nums;
}

.shop-head__sort {
	grid-column: 2;
	grid-row: 1 / span 2;
	align-self: center;
	justify-self: end;
}

/*
 * The sort, in the same register as the count beside it and the chips below
 * it: small caps, hairline border, the theme's own chevron. A browser-default
 * select was the only undesigned control in the band.
 */
.shop-head__sort .woocommerce-ordering {
	position: relative;
	display: inline-block;
	margin: 0;
	float: none;
}

.shop-head__sort .woocommerce-ordering::after {
	content: "";
	position: absolute;
	inset-inline-end: var(--s-4);
	top: 50%;
	width: 0.4rem;
	height: 0.4rem;
	border-inline-end: 1px solid currentColor;
	border-block-end: 1px solid currentColor;
	transform: translateY(-70%) rotate(45deg);
	color: var(--ink-45);
	pointer-events: none;
}

.shop-head__sort select {
	width: auto;
	min-width: 11rem;
	appearance: none;
	background: var(--paper);
	border: 1px solid var(--ink-15);
	padding: var(--s-2) var(--s-8) var(--s-2) var(--s-4);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink-60);
	cursor: pointer;
	transition: border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.shop-head__sort select:hover,
.shop-head__sort select:focus-visible {
	border-color: var(--ink);
	color: var(--ink);
}

.term-description {
	max-width: 42rem;
	color: var(--fg-muted);
	margin-block-start: var(--s-4);
}

/*
 * In the shop head the description takes the heading's column rather than the
 * band's full width, so its left and right edges line up with the title
 * directly above it instead of running out under the sort control.
 *
 * The 42rem measure above is a reading width and is right anywhere else this
 * class renders; here the column is the measure.
 */
.woocommerce-products-header .term-description {
	grid-column: 1;
	max-width: none;
}

/* WooCommerce emits its loop as ul.products with its own column classes.
 * Overriding it to the theme's grid in one place is less fragile than
 * filtering the markup, and it means a third-party shortcode that outputs a
 * product loop inherits the same layout for free. */
.woocommerce ul.products,
ul.products {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--grid-gap);
	list-style: none;
	margin: 0 0 var(--s-12);
	padding: 0;
}

.woocommerce ul.products::before,
.woocommerce ul.products::after {
	content: none;
}

.woocommerce ul.products li.product {
	width: auto !important;
	margin: 0 !important;
	float: none !important;
	clear: none !important;
	text-align: center;
}

.woocommerce ul.products li.product .woocommerce-loop-product__title {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	line-height: 1.3;
	padding: 0;
	margin-block-start: var(--s-4);
}

.woocommerce ul.products li.product .price {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	color: var(--ink);
	font-variant-numeric: tabular-nums;
	display: block;
	margin-block-start: var(--s-2);
}

@media (max-width: 1023px) {
	.woocommerce ul.products,
	ul.products {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--s-6);
	}
}

@media (max-width: 767px) {
	.woocommerce ul.products,
	ul.products {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--s-6);
	}
}

.woocommerce-result-count,
.woocommerce-ordering {
	font-size: var(--text-xs);
	letter-spacing: 0.06em;
	color: var(--fg-muted);
}

.woocommerce-ordering select {
	border: 1px solid var(--ink-15);
	background: var(--paper);
	padding: var(--s-2) var(--s-4);
	font-size: var(--text-xs);
}

/* Single product. The two-column layout, the gallery and everything else
 * specific to that screen is section 25; what follows is the WooCommerce
 * furniture the theme restyles wherever it appears. */
.single-product div.product .product_title {
	font-size: var(--text-h2);
	margin-block-end: var(--s-4);
}

.single-product div.product .price {
	font-family: var(--font-sans);
	font-size: var(--text-h4);
	color: var(--ink);
	font-variant-numeric: tabular-nums;
	display: block;
	margin-block-end: var(--s-6);
}

.single-product .woocommerce-product-details__short-description {
	color: var(--ink-60);
	margin-block-end: var(--s-8);
}

.single-product .product_meta {
	font-size: var(--text-xs);
	letter-spacing: 0.06em;
	color: var(--fg-muted);
	border-top: 1px solid var(--border);
	padding-block-start: var(--s-6);
	margin-block-start: var(--s-8);
}

.single-product .product_meta > span {
	display: block;
	margin-block-end: var(--s-2);
}

.woocommerce-tabs {
	grid-column: 1 / -1;
	border-top: 1px solid var(--border);
	padding-block-start: var(--s-12);
}

.woocommerce-tabs ul.tabs {
	list-style: none;
	margin: 0 0 var(--s-8);
	padding: 0;
	display: flex;
	gap: var(--s-8);
	flex-wrap: wrap;
}

.woocommerce-tabs ul.tabs a {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	padding-block-end: var(--s-2);
	border-bottom: 1px solid transparent;
	display: block;
}

.woocommerce-tabs ul.tabs li.active a {
	border-bottom-color: var(--bronze);
	color: var(--ink);
}

/* Quantity and add to cart */
.quantity input[type="number"],
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
input[type="search"],
input[type="number"],
select,
textarea {
	width: 100%;
	border: 1px solid var(--ink-15);
	background: var(--paper);
	padding: var(--s-3) var(--s-4);
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	transition: border-color var(--speed) var(--ease);
}

input:focus,
select:focus,
textarea:focus {
	border-color: var(--bronze);
	outline: none;
}

.quantity input[type="number"] {
	width: 6rem;
	text-align: center;
	font-variant-numeric: tabular-nums;
}

form.cart {
	display: flex;
	align-items: center;
	gap: var(--s-4);
	flex-wrap: wrap;
	margin-block-end: var(--s-6);
}

.woocommerce .button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce a.button,
.woocommerce #respond input#submit {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	line-height: 1;
	padding: 1rem 2rem;
	border: 1px solid var(--ink);
	border-radius: 0;
	background: var(--ink);
	color: var(--paper);
	cursor: pointer;
	transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease);
}

.woocommerce .button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover,
.woocommerce a.button:hover,
.woocommerce #respond input#submit:hover {
	background: var(--bronze);
	border-color: var(--bronze);
	color: var(--paper);
}

/* Notices. Deliberately not green and red — the palette has one accent and
 * a hue that appears nowhere else would look like a mistake. Rank is carried
 * by the border weight and a leading word instead, which also survives
 * greyscale printing and the commoner forms of colour blindness. */
.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.woocommerce-notice {
	list-style: none;
	background: var(--shell);
	border-left: 3px solid var(--ink-30);
	padding: var(--s-4) var(--s-6);
	margin-block-end: var(--s-6);
	font-size: var(--text-sm);
}

.woocommerce-message {
	border-left-color: var(--bronze);
}

.woocommerce-error {
	border-left-color: var(--ink);
	background: var(--ink);
	color: var(--paper);
}

.woocommerce-error a {
	color: var(--paper);
	text-decoration: underline;
}

/* Field-level validation. woocommerce-general is dequeued in
 * inc/performance.php, and it carried the only rule that marked a failing
 * field — so checkout was printing "Billing postcode is a required field" at
 * the top of the page with nothing on the page saying which box it meant.
 *
 * Not red, for the reason given above the notices: rank is carried by weight.
 * The doubled stroke comes from an inset shadow rather than a wider border so
 * that a field marked mid-typing does not shift the form under the cursor. */
.woocommerce form .form-row.woocommerce-invalid input.input-text,
.woocommerce form .form-row.woocommerce-invalid select,
.woocommerce form .form-row.woocommerce-invalid textarea,
.woocommerce-checkout .form-row.woocommerce-invalid input.input-text,
.woocommerce-checkout .form-row.woocommerce-invalid select {
	border-color: var(--ink);
	box-shadow: inset 0 0 0 1px var(--ink);
}

/* The label carries the same mark, because a screenful of fields scrolled so
 * the box is off-screen still shows its name. */
.woocommerce form .form-row.woocommerce-invalid > label,
.woocommerce-checkout .form-row.woocommerce-invalid > label {
	color: var(--ink);
	font-weight: 600;
}

/* --------------------------------------------------------------------------
   16. TRADE SCREENS

   Cart, checkout and account are a working ordering tool, not a shop window.
   The type gets smaller, the rhythm tightens and tables get rules — the same
   palette and the same two faces, used at a different density.
   -------------------------------------------------------------------------- */

.woocommerce table.shop_table,
.woocommerce-account table,
table.cuba-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-sm);
	margin-block-end: var(--s-8);
}

.woocommerce table.shop_table th,
.woocommerce-account table th,
table.cuba-table th {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 400;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--fg-muted);
	text-align: left;
	padding: var(--s-3) var(--s-4);
	border-bottom: 1px solid var(--ink-15);
}

.woocommerce table.shop_table td,
.woocommerce-account table td,
table.cuba-table td {
	padding: var(--s-4);
	border-bottom: 1px solid var(--border);
	vertical-align: middle;
}

.woocommerce table.shop_table .amount,
.woocommerce table.shop_table td.product-total,
.woocommerce table.shop_table td.product-subtotal,
table.cuba-table .amount {
	font-variant-numeric: tabular-nums;
	text-align: right;
	white-space: nowrap;
}

.woocommerce table.shop_table th.product-total,
.woocommerce table.shop_table th.product-subtotal {
	text-align: right;
}

.woocommerce table.shop_table img {
	width: 64px;
	height: 64px;
	object-fit: cover;
	background: var(--shell);
}

.cart_totals,
.woocommerce-checkout-review-order {
	background: var(--shell);
	padding: var(--s-8);
}

.cart_totals h2,
.woocommerce-checkout-review-order h3 {
	font-size: var(--text-h3);
	margin-block-end: var(--s-6);
}

.woocommerce-checkout .col2-set {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--s-12);
}

.woocommerce form .form-row {
	margin-block-end: var(--s-4);
}

.woocommerce form .form-row label {
	display: block;
	font-size: var(--text-xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--fg-muted);
	margin-block-end: var(--s-2);
}

/* Status pills. Same reasoning as the notices: fill, outline and rule carry
 * the state, not hue. */
.status {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.12em;
	text-transform: uppercase;
	padding: 0.35rem 0.75rem;
	line-height: 1;
	white-space: nowrap;
}

.status--pending {
	background: var(--ink);
	color: var(--paper);
}

.status--processing {
	background: transparent;
	color: var(--ink);
	box-shadow: inset 0 -2px 0 var(--bronze);
}

.status--complete {
	border: 1px solid var(--ink-15);
	color: var(--ink-45);
}

.status--cancelled {
	color: var(--fg-muted);
	text-decoration: line-through;
}

/*
 * Below 768px a data table cannot keep its columns without either scrolling
 * sideways or setting type at a size nobody can read. Each row becomes a
 * stacked block and the header text is restored per cell from data-title,
 * which WooCommerce already writes on every td.
 */
@media (max-width: 767px) {
	.woocommerce table.shop_table thead,
	.woocommerce-account table thead {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		clip-path: inset(50%);
	}

	.woocommerce table.shop_table tr,
	.woocommerce-account table tr {
		display: block;
		border-bottom: 1px solid var(--ink-15);
		padding-block: var(--s-4);
	}

	/* overflow-wrap because the value is an anonymous flex item with nothing to
	 * break on: a long address or a work email at a long domain grew the row
	 * past the screen and took the whole page sideways with it. */
	.woocommerce table.shop_table td,
	.woocommerce-account table td {
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: var(--s-4);
		border: 0;
		padding: var(--s-2) 0;
		text-align: right;
		min-width: 0;
		overflow-wrap: anywhere;
	}

	/* The label is short and known; it keeps its width and the value wraps. */
	.woocommerce table.shop_table td::before,
	.woocommerce-account table td::before {
		flex: 0 0 auto;
		content: attr(data-title);
		font-family: var(--font-sans);
		font-size: var(--text-2xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		color: var(--fg-muted);
		text-align: left;
	}

	.woocommerce-checkout .col2-set {
		grid-template-columns: 1fr;
		gap: var(--s-8);
	}
}

.woocommerce-account .woocommerce {
	display: grid;
	grid-template-columns: 16rem 1fr;
	gap: var(--s-12);
	padding-block: var(--s-8) var(--s-16);
}

.woocommerce-MyAccount-navigation ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.woocommerce-MyAccount-navigation a {
	display: block;
	padding: var(--s-3) 0;
	border-bottom: 1px solid var(--border);
	font-size: var(--text-xs);
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.woocommerce-MyAccount-navigation .is-active a {
	color: var(--bronze);
}

@media (max-width: 899px) {
	.woocommerce-account .woocommerce {
		grid-template-columns: 1fr;
		gap: var(--s-8);
	}
}

/* Quantity-break table, if the Cuba B2B plugin renders one on the product
 * page. Styled here so it inherits the theme rather than the plugin having
 * to ship presentation of its own. */
.qty-breaks {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-xs);
	margin-block: var(--s-6);
}

.qty-breaks th,
.qty-breaks td {
	padding: var(--s-2) var(--s-3);
	border-bottom: 1px solid var(--border);
	text-align: left;
	font-variant-numeric: tabular-nums;
}

.qty-breaks th {
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--fg-muted);
	font-weight: 400;
}

/* --------------------------------------------------------------------------
   17. BLOCKS AND PROSE
   -------------------------------------------------------------------------- */

.prose {
	max-width: 42rem;
}

.prose > * + * {
	margin-block-start: var(--s-6);
}

.prose p,
.prose li {
	color: var(--ink-60);
	line-height: var(--leading-body);
}

.prose h2,
.prose h3 {
	margin-block-start: var(--s-12);
}

.prose a {
	color: var(--ink);
	border-bottom: 1px solid var(--ink-15);
}

.prose a:hover {
	color: var(--bronze);
	border-bottom-color: var(--bronze);
}

.prose blockquote {
	border-left: 2px solid var(--bronze);
	padding-inline-start: var(--s-6);
	font-family: var(--font-display);
	font-size: var(--text-h3);
	color: var(--ink);
}

.prose img {
	width: 100%;
}

.prose ul,
.prose ol {
	padding-inline-start: var(--s-6);
}

.prose li + li {
	margin-block-start: var(--s-2);
}

.alignwide {
	max-width: min(1100px, 100%);
	margin-inline: auto;
}

.alignfull {
	width: 100vw;
	max-width: 100vw;
	margin-inline: calc(50% - 50vw);
}

.aligncenter {
	margin-inline: auto;
}

.wp-caption-text,
figcaption {
	font-size: var(--text-xs);
	color: var(--fg-muted);
	margin-block-start: var(--s-2);
}

.entry-header {
	text-align: center;
	padding-block: var(--s-16) var(--s-8);
}

.entry-title {
	font-size: var(--text-h2);
}

.pagination,
.woocommerce-pagination ul {
	display: flex;
	justify-content: center;
	/* Nine page links plus prev/next is wider than a phone. Wrapping keeps
	 * the page from scrolling sideways, which is what it was doing. */
	flex-wrap: wrap;
	gap: var(--s-2);
	list-style: none;
	margin: var(--s-12) 0;
	padding: 0;
}

.woocommerce-pagination a,
.woocommerce-pagination span,
.pagination a,
.pagination span {
	display: grid;
	place-items: center;
	min-width: 40px;
	height: 40px;
	padding-inline: var(--s-2);
	border: 1px solid var(--border);
	font-size: var(--text-xs);
	font-variant-numeric: tabular-nums;
}

.woocommerce-pagination .current,
.pagination .current {
	background: var(--ink);
	color: var(--paper);
	border-color: var(--ink);
}

/* --------------------------------------------------------------------------
   18. UTILITIES AND MOTION
   -------------------------------------------------------------------------- */

.text-center {
	text-align: center;
}

.mt-8 {
	margin-block-start: var(--s-8);
}

.hidden {
	display: none;
}

/* Everything above animates opacity or transform only, both of which the
 * compositor handles without laying the page out again. Nothing here
 * animates width, height, top or left. */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

@media print {
	.site-header,
	.site-footer,
	.brandmark,
	.product-card__actions,
	.product-card__reveal {
		display: none;
	}

	body {
		color: #000;
		background: #fff;
	}
}

/* --------------------------------------------------------------------------
   19. CATEGORY MEGA MENU

   A full-width panel of picture tiles under a top-level category item. It is
   opened by :hover and :focus-within, with no JavaScript at all — which is
   what lets it work before the deferred script has parsed, and keeps it
   working if the script ever fails to load.

   The panel is a child of the <li>, but it spans the header rather than the
   link: the li is taken out of the positioning chain with position: static so
   that inset-inline: 0 resolves against .site-header, which is sticky and
   therefore already a containing block.
   -------------------------------------------------------------------------- */

.nav-caret {
	/* The reset at the top of this file sets every svg to display: block, which
	 * is right for photographs and wrong for an icon that sits in a line of
	 * type — it put the chevron on its own line under the menu item. This is
	 * the one place an svg is a word rather than a picture, so it says so. */
	display: inline-block;
	width: 14px;
	height: 14px;
	margin-inline-start: 5px;
	vertical-align: -2px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
	transition: transform var(--speed) var(--ease);
}

.main-nav li:hover > a .nav-caret,
.main-nav li:focus-within > a .nav-caret {
	transform: rotate(180deg);
}

.main-nav .menu-item-has-mega {
	position: static;
}

.mega {
	position: absolute;
	inset-inline: 0;
	top: 100%;
	z-index: 60;
	/* The header's ground, not the page's. A panel is the navigation band
	 * extending downwards, and on paper it read as a separate card that had
	 * appeared over the page rather than as the header opening. */
	background: var(--gold-tint);
	border-block-start: 1px solid var(--gold-rule);
	box-shadow: var(--shadow-lg);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-6px);
	transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease), visibility var(--speed);
}

.menu-item-has-mega:hover > .mega,
.menu-item-has-mega:focus-within > .mega {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.mega__inner {
	padding-block: var(--s-10);
}

/* Scoped to .main-nav so it outranks .main-nav ul, which is a class plus a
 * type selector and would otherwise keep the panel a flex row on desktop and a
 * flex column inside the phone panel. */
.main-nav .mega__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
	gap: var(--s-8);
	list-style: none;
	margin: 0;
	padding: 0;
}

.mega__tile {
	display: block;
	text-align: center;
}

/* The tiles are list items inside the navigation, so every rule written for a
 * nav link reaches them — including the tap padding the phone panel gives its
 * rows, which is wide enough to push a three-column grid past the viewport.
 * The tile is its own control and takes none of it. */
.main-nav a.mega__tile {
	display: block;
	padding: 0;
	border: 0;
	min-height: 0;
	letter-spacing: normal;
	text-transform: none;
	font-size: inherit;
}

/* The same contained-packshot treatment as the brand grid: catalogue
 * photography here is a bottle on white, and multiply dissolves that white
 * into the cream panel so there is no visible photo rectangle. */
.mega__frame {
	display: block;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: var(--cream);
	border: 1px solid var(--border);
}

.mega__frame img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	padding: var(--s-4);
	mix-blend-mode: multiply;
	transition: transform var(--speed-slow) var(--ease);
}

.mega__tile:hover .mega__frame img {
	transform: scale(1.05);
}

.mega__name {
	display: block;
	margin-block-start: var(--s-3);
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	/* A nav link is nowrap, and the tile is a nav link. Inherited into the
	 * caption that rule turns a two-word category into one line wider than its
	 * column, which on the phone panel drew the names of three tiles over each
	 * other. overflow-wrap alone cannot answer it: nowrap forbids the break
	 * before anything gets to choose where it falls. */
	white-space: normal;
	color: var(--ink-60);
	transition: color var(--speed) var(--ease);
}

.mega__tile:hover .mega__name {
	color: var(--bronze-dark);
}

/* The grouped panel is two nameplates side by side. Wide rather than tall so
 * the whole thing clears the fold on a laptop, and capped so two houses do not
 * stretch into two billboards on a wide screen. */
/* Left as the flex row .main-nav ul already makes it, rather than switched to
 * a grid: auto-fit lays down a third empty track for two cards and throws the
 * pair off centre by half a gap. Capped at 22rem so two houses do not stretch
 * into two billboards on a wide screen. */
.main-nav .mega__brands {
	flex-wrap: wrap;
	align-items: stretch;
	gap: var(--s-10);
}

.main-nav .mega__brands > li {
	flex: 0 1 22rem;
}

/* A card is a list item inside the navigation, so every rule written for a nav
 * link reaches it — the drawer's tap padding and bottom rule included. Same
 * reset the picture tile takes, for the same reason. */
.main-nav a.mega__brand {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--s-4);
	padding: 0;
	border: 0;
	min-height: 0;
	white-space: normal;
	text-decoration: none;
	color: var(--ink);
}

/* The two marks are nothing alike — one a wide gold cartouche, the other a
 * round black seal — so the frame is what makes them a pair: same box, same
 * ground, each contained inside it at whatever shape it happens to be. */
.mega__brand-frame {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	/* A set height, not an aspect ratio: the marks are sized against it with
	 * max-height, and a height derived from a ratio is indefinite — the
	 * percentage would resolve to auto and the round seal would draw itself at
	 * 625px, dragging the box square. */
	height: 10rem;
	padding: var(--s-5);
	/* Lighter than the panel it sits on, not warmer. --cream was chosen when
	 * the panel was paper; against the header's gold it lands within a point
	 * of the ground and the frame stops reading as a frame - which is the one
	 * thing it is for, since it is what makes a wide gold cartouche and a
	 * round black seal look like a pair. */
	background: var(--panel);
	border: 1px solid var(--gold-rule);
	transition: border-color var(--speed) var(--ease);
}

/* The Cuba mark ships a WebP, so it arrives wrapped in a <picture>. Left
 * inline that wrapper is the img's containing block with no height of its own,
 * max-height: 100% resolves against nothing, and the mark spills out of the
 * frame on the phone. Sized to the frame, it becomes the box the img measures
 * itself against. */
.mega__brand-frame picture {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	min-width: 0;
}

.mega__brand-frame img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	mix-blend-mode: multiply;
}

.mega__brand:hover .mega__brand-frame,
.mega__brand:focus-visible .mega__brand-frame {
	border-color: var(--bronze);
}

.mega__brand-name {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	font-weight: 500;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	text-align: center;
}

.mega__brand:hover .mega__brand-name,
.mega__brand:focus-visible .mega__brand-name {
	color: var(--bronze-dark);
}

/* The shelves under a house. A ruled list rather than a row of links: the
 * three are a set to choose from, and a list is what says that. The rules are
 * --gold-rule because the panel sits on --gold-tint, where --rule vanishes. */
.main-nav .mega__shelves {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 0;
	margin: var(--s-5) 0 0;
	padding: 0;
	list-style: none;
	border-block-start: 1px solid var(--gold-rule);
}

/*
 * Held back until the house is pointed at. The panel's job on opening is the
 * choice between two houses, and six shelf rows competing with the two marks
 * is what made that choice slower to read; hovering a house is already the
 * buyer saying which one they mean.
 *
 * The card is a two-row grid whose second track opens from 0fr to 1fr, so the
 * panel grows to the rows rather than standing at full height with a hand's
 * width of nothing under the nameplates. Holding the space instead was the
 * first attempt and looked broken — most of an open panel was empty.
 *
 * visibility rides along for the keyboard: a clipped link is still a tab stop,
 * and tabbing into something no one can see is worse than not reaching it.
 * :focus-within is what makes it reachable — the nameplate link takes focus
 * first, which opens the rows, and the next Tab lands on one.
 */
.mega__house {
	display: grid;
	grid-template-rows: auto 0fr;
	transition: grid-template-rows var(--speed) var(--ease);
}

.mega__shelves {
	overflow: hidden;
	visibility: hidden;
	opacity: 0;
	transition: opacity var(--speed) var(--ease), visibility var(--speed);
}

.mega__house:hover,
.mega__house:focus-within {
	grid-template-rows: auto 1fr;
}

.mega__house:hover .mega__shelves,
.mega__house:focus-within .mega__shelves {
	visibility: visible;
	opacity: 1;
}

/* The panel resizes under the pointer, so anyone who asked for less movement
 * gets the rows without the travel. */
@media (prefers-reduced-motion: reduce) {
	.mega__house {
		transition: none;
	}
}

.main-nav a.mega__shelf {
	display: flex;
	align-items: center;
	gap: var(--s-4);
	padding: var(--s-2) var(--s-2);
	border: 0;
	border-block-end: 1px solid var(--gold-rule);
	min-height: 0;
	white-space: normal;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 500;
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	text-decoration: none;
	color: var(--ink-60);
	transition: color var(--speed) var(--ease), background-color var(--speed) var(--ease);
}

/* The last rule would double the panel's own bottom edge. */
.mega__shelves li:last-child .mega__shelf {
	border-block-end: 0;
}

.main-nav a.mega__shelf:hover,
.main-nav a.mega__shelf:focus-visible {
	color: var(--bronze-dark);
	background: var(--panel);
}

/*
 * A bottle standing in the row rather than a pictogram of a man or a woman:
 * the catalogue's own photography is what the buyer is here for, and the
 * symbols would have been the only drawn icons anywhere in the design.
 *
 * Fixed square with the photograph contained inside it, because the shots are
 * portrait and cropping them to fill would cut the bottle off at the neck.
 */
.mega__shelf-thumb {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 2.5rem;
	height: 2.5rem;
	padding: var(--s-1);
	background: var(--panel);
	border: 1px solid var(--gold-rule);
	transition: border-color var(--speed) var(--ease);
}

.mega__shelf-thumb img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	mix-blend-mode: multiply;
}

.main-nav a.mega__shelf:hover .mega__shelf-thumb,
.main-nav a.mega__shelf:focus-visible .mega__shelf-thumb {
	border-color: var(--bronze);
}

.mega__all {
	margin-block-start: var(--s-8);
	text-align: center;
}

.mega__all a {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink-60);
	border-bottom: 1px solid var(--ink-15);
	padding-bottom: 2px;
}

.mega__all a:hover {
	color: var(--bronze-dark);
	border-bottom-color: var(--bronze);
}

/*
 * Below the desktop breakpoint the header collapses to a tap-to-open panel,
 * and there is no hover to open a second layer with. The tiles are simply
 * always visible inside that panel, three across and smaller — a tap opens
 * the category, which on a phone is the only interaction that makes sense.
 */
@media (max-width: 1259px) {
	/*
	 * Shut until the chevron is tapped, exactly as a .sub-menu is.
	 *
	 * The tiles used to be always-on here — there is no hover on a phone, so
	 * "always visible" was the way to make them reachable. That was written
	 * before the chevron existed. With it, the drawer opened on Fragrances
	 * already expanded: two houses, six shelves and their thumbnails between
	 * the burger and every other item in the menu, and a collapsed-looking
	 * chevron beside a heading that was plainly not collapsed. The button
	 * toggles .is-expanded and nothing was listening for it.
	 */
	.mega {
		display: none;
		position: static;
		/* A third child of the flex row that .main-nav li becomes in the
		 * drawer, after the link and the expand button. Wrapping puts it on
		 * its own line but does not widen it, so it was sizing itself to its
		 * contents and taking about 227px of a 390px drawer. */
		flex: 1 0 100%;
		min-width: 0;
		opacity: 1;
		/* Inherit, for the reason the columns panel does: the drawer holding
		 * this is hidden, and an explicitly visible child of it would stay in
		 * the tab order while the drawer is shut. */
		visibility: inherit;
		transform: none;
		box-shadow: none;
		border-block-start: 0;
		background: transparent;
	}

	/* The nav rows carry 24px of inline padding of their own; without the
	 * same here the tiles run flush to both screen edges. */
	.mega__inner {
		padding: 0 var(--s-6) var(--s-4);
		max-width: none;
	}

	/*
	 * Two across, not three. The drawer is 22.5rem at its widest, so a third
	 * of it is a 98px column — narrower than the single word DESTINATIONS in
	 * tracked uppercase, which then broke mid-word into a hanging S. Halves
	 * give the caption 155px, which every category name in the catalogue
	 * fits on one or two whole words, and the packshots are bigger for it.
	 *
	 * minmax(0, 1fr), not 1fr: a bare fr floors at the item's min-content, so
	 * a long name would push the grid past the panel instead of wrapping.
	 */
	.main-nav .mega__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--s-4);
		margin-block-start: var(--s-4);
	}

	.mega__name {
		font-size: var(--text-2xs);
		letter-spacing: 0.06em;
		overflow-wrap: anywhere;
	}

	/* One house per row, not two across as the picture tiles are. Two columns
	 * in a 22.5rem drawer leave about ten rems each: CUBA FRAGRANCES wraps to
	 * two lines there and New Brand does not, which starts the two shelf lists
	 * at different heights and stops them reading as the same three choices
	 * offered twice. Full width fixes both, and costs only scrolling.
	 *
	 * nowrap is load-bearing: the panel has a bounded height, and a wrapping
	 * column lays down a second column of its own accord. */
	.main-nav .mega__brands {
		flex-direction: column;
		flex-wrap: nowrap;
		gap: var(--s-6);
		margin-block-start: var(--s-4);
	}

	/* .main-nav li is a flex row in the drawer, so a nav row can carry its link
	 * and its expand button side by side. A house card is not that shape — left
	 * as a row it puts the shelf list beside the nameplate instead of under it,
	 * so this one points down. */
	.main-nav .mega__brands > li {
		flex: 0 0 auto;
		flex-direction: column;
		min-width: 0;
	}

	/* Stacked, the cards need the break between them said outright — the gap
	 * alone stops reading as one once each card carries a list of its own. */
	.main-nav .mega__brands > li + li {
		padding-block-start: var(--s-6);
		border-block-start: 1px solid var(--border);
	}

	/* The desktop panel opens its shelves on hover, which a phone never fires,
	 * so the clipping and the fade have to be undone here or the drawer would
	 * show two nameplates and nothing else. What replaces hover is the chevron
	 * below, not "always open": laid out in full, one tap on Fragrances
	 * produced two logos and six shelf rows before the buyer had said which
	 * house they wanted. */
	.mega__shelves {
		overflow: visible;
		visibility: inherit;
		opacity: 1;
	}

	/* Beats `.main-nav .mega__shelves`, which sets display: flex. */
	.main-nav .mega__shelves {
		display: none;
	}

	.main-nav .mega__house.is-expanded > .mega__shelves {
		display: flex;
	}

	/*
	 * The house chevron, in the top corner of the card.
	 *
	 * Not a row of its own under the nameplate: the card is a picture with its
	 * name centred beneath, and a full-width button between that name and the
	 * shelves it opens would read as a third thing rather than as the handle on
	 * the second. Absolute, so the whole card stays the link to the house
	 * archive and only the corner opens the list.
	 *
	 * .mega__house is safe to position — it is the panel, .mega, that must stay
	 * static for the header to remain its containing block.
	 */
	.mega__house {
		position: relative;
	}

	.mega__house > .nav-drawer__expand {
		position: absolute;
		inset-block-start: 0;
		inset-inline-end: 0;
		z-index: 1;
		flex: none;
		width: 2.75rem;
		height: 2.75rem;
		border: 0;
	}

	/* Every card but the first carries the separating rule as its own top
	 * padding, and the chevron is anchored to the box, not to the frame inside
	 * it — left at 0 the second one floats above its card and sits on the rule.
	 * Anchored below the top edge, not above it: the shelves open downwards, so
	 * an inset-block-end would ride to the bottom of the opened list. */
	.main-nav .mega__brands > li + li > .nav-drawer__expand {
		inset-block-start: var(--s-6);
	}

	/* The drawer is thumbs, not a pointer: the 12px ruled rows that suit a
	 * hover panel are under the tap target a phone needs. */
	.main-nav a.mega__shelf {
		padding-block: var(--s-2);
		min-height: 3rem;
		font-size: var(--text-xs);
	}

	.mega__shelves {
		margin-block-start: var(--s-4);
	}

	.mega__brand-frame {
		height: 5.5rem;
		padding: var(--s-4);
	}

	.mega__all {
		margin-block-start: var(--s-4);
		text-align: start;
	}

	.nav-caret {
		display: none;
	}
}

/* The zoom overlay. Built once by site.js on the first click and reused; a
 * dialog over the page, not a page. The ground is the paper colour at near
 * enough full strength that the page behind it reads as gone: a fragrance
 * label is fine print on foil, and it is read against quiet, not against a
 * dimmed shop. */
.pdp-zoom {
	position: fixed;
	inset: 0;
	z-index: 200;
	background: rgba(250, 250, 250, 0.97);
}

.pdp-zoom[hidden] {
	display: none;
}

.pdp-zoom__stage {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	overflow: hidden;
	padding: var(--s-6);
}

.pdp-zoom__img {
	max-width: min(1100px, 88vw);
	max-height: 86vh;
	width: auto;
	height: auto;
	cursor: zoom-in;
}

/* Clicked again, the photograph opens to the file's own pixels and the stage
 * becomes a pan surface. place-items stays: when the file is smaller than
 * the screen it simply sits centred, and zooming has honestly run out. */
.pdp-zoom--zoomed .pdp-zoom__stage {
	display: block;
	overflow: auto;
	padding: 0;
}

.pdp-zoom--zoomed .pdp-zoom__img {
	max-width: none;
	max-height: none;
	margin: auto;
	cursor: zoom-out;
}

.pdp-zoom__close,
.pdp-zoom__prev,
.pdp-zoom__next {
	position: absolute;
	z-index: 2;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 1px solid var(--panel-edge);
	background: var(--paper);
	color: var(--ink);
	font-family: var(--font-sans);
	font-size: 1.25rem;
	line-height: 1;
	cursor: pointer;
	transition: border-color var(--speed) var(--ease);
}

.pdp-zoom__close:hover,
.pdp-zoom__prev:hover,
.pdp-zoom__next:hover {
	border-color: var(--ink);
}

.pdp-zoom__close {
	top: var(--s-4);
	inset-inline-end: var(--s-4);
}

.pdp-zoom__prev,
.pdp-zoom__next {
	top: 50%;
	transform: translateY(-50%);
}

.pdp-zoom__prev {
	inset-inline-start: var(--s-4);
}

.pdp-zoom__next {
	inset-inline-end: var(--s-4);
}

.pdp-zoom__count {
	position: absolute;
	z-index: 2;
	bottom: var(--s-4);
	inset-inline: 0;
	margin: 0;
	text-align: center;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.14em;
	color: var(--ink-60);
}

/* The page must not scroll behind the dialog. */
html.pdp-zoom-lock,
html.pdp-zoom-lock body {
	overflow: hidden;
}

/* --------------------------------------------------------------------------
   20. QUICK VIEW AND THE SAVED LIST

   One panel, two contents. Both are built by the script from cards that are
   already in the document — see assets/js/site.js — so nothing here styles a
   response that had to be fetched.
   -------------------------------------------------------------------------- */

.header-actions__saved {
	position: relative;
	border: 0;
	background: none;
	padding: 0;
	color: inherit;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
}

.header-actions__saved[hidden] {
	display: none;
}

.modal[hidden] {
	display: none;
}

.modal {
	position: fixed;
	inset: 0;
	z-index: 200;
	display: grid;
	place-items: center;
	padding: var(--gutter);
}

.modal__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(23, 23, 23, 0.55);
}

.modal__panel {
	position: relative;
	width: min(52rem, 100%);
	max-height: min(80vh, 44rem);
	overflow-y: auto;
	background: var(--paper);
	box-shadow: var(--shadow-lg);
	padding: var(--s-10);
}

.modal__close {
	position: absolute;
	top: var(--s-4);
	right: var(--s-4);
	width: 36px;
	height: 36px;
	display: grid;
	place-items: center;
	border: 0;
	background: none;
	color: var(--ink-45);
	cursor: pointer;
}

.modal__close svg {
	width: 18px;
	height: 18px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
	stroke-linecap: round;
}

.modal__close:hover {
	color: var(--ink);
}

.modal__title {
	font-size: var(--text-h3);
	margin-block-end: var(--s-6);
}

.modal__empty {
	color: var(--fg-muted);
}

/* The page behind a modal must not scroll under it — on a phone especially,
 * where the panel is short and the momentum scroll runs straight through. */
.has-modal,
.has-modal body {
	overflow: hidden;
}

.qv {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--s-10);
	align-items: center;
}

.qv__media {
	background: var(--cream);
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--s-6);
}

.qv__media img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	mix-blend-mode: multiply;
}

.qv__title {
	font-size: var(--text-h3);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.qv__meta {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	color: var(--fg-muted);
	margin-block-start: var(--s-3);
}

.qv__price {
	font-family: var(--font-sans);
	font-size: var(--text-lead);
	color: var(--ink);
	margin-block-start: var(--s-4);
}

.qv .btn {
	margin-block-start: var(--s-8);
}

@media (max-width: 767px) {
	.modal__panel {
		padding: var(--s-8) var(--s-6);
	}

	.qv {
		grid-template-columns: 1fr;
		gap: var(--s-6);
		text-align: center;
	}
}

.saved-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.saved-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-4);
	padding-block: var(--s-4);
	border-bottom: 1px solid var(--border);
}

.saved-row__link {
	display: flex;
	align-items: center;
	gap: var(--s-4);
	min-width: 0;
}

.saved-row__link img,
.saved-row__blank {
	width: 64px;
	height: 64px;
	object-fit: contain;
	background: var(--cream);
	mix-blend-mode: multiply;
	flex-shrink: 0;
}

.saved-row__text {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.saved-row__title {
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--ink);
}

.saved-row__meta {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	color: var(--fg-muted);
	margin-block-start: var(--s-1);
}

.saved-row__remove {
	border: 0;
	background: none;
	padding: 0;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink-45);
	cursor: pointer;
	flex-shrink: 0;
}

.saved-row__remove:hover {
	color: var(--ink);
}

/* A saved card keeps its heart filled and dark after the pointer leaves, so
 * the state is visible on a later visit rather than only under a hover. */
.product-card__actions [data-save].is-saved {
	background: var(--ink);
	color: var(--paper);
}

.product-card__actions [data-save].is-saved svg {
	fill: currentColor;
}

.product-card:hover .product-card__actions,
.product-card:focus-within .product-card__actions,
li.product:hover .product-card__actions,
li.product:focus-within .product-card__actions,
.product-card__actions:has([data-save].is-saved) {
	opacity: 1;
	transform: translateX(0);
}

/* WooCommerce's own loop item is the positioning context for the controls on
 * the shop archive, exactly as .product-card is on the front page. */
.woocommerce ul.products li.product {
	position: relative;
}

/* --------------------------------------------------------------------------
   21. TOP BAR

   The slim line the header opens with. It is the first band inside
   .site-header, so it stays at the top of the window with the rest of it — the
   phone number, the account controls and the search are what a buyer reaches
   for mid-page, and scrolling a whole catalogue back to the top to find them
   was the cost of leaving it outside.

   Unpositioned, like every other band in there: .site-header is sticky and is
   the containing block the mega panels measure themselves against.
   -------------------------------------------------------------------------- */

.top-bar {
	background: var(--ink);
	color: var(--paper);
}

.top-bar__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-4);
	padding-block: var(--s-2);
	flex-wrap: wrap;
}

.top-bar p {
	margin: 0;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
}

/* Contact on the left, accounts on the right; .top-bar__inner already sets
 * space-between, so this only has to keep the number and the social row
 * together as one side. */
.top-bar__reach {
	display: flex;
	align-items: center;
	gap: var(--s-6);
	flex-wrap: wrap;
}

.top-bar__contact {
	display: flex;
	gap: var(--s-6);
}

.top-bar__call {
	display: inline-flex;
	gap: var(--s-2);
}

.top-bar a {
	color: var(--paper);
}

.top-bar a:hover,
.top-bar a:focus-visible {
	color: var(--bronze);
}

.top-bar__social {
	display: flex;
	align-items: center;
	gap: var(--s-4);
}

/* Filled marks, not stroked: these are brand glyphs, each drawn as one solid
 * shape, unlike the line icons the header actions use. */
.top-bar__social svg {
	width: 15px;
	height: 15px;
	fill: currentColor;
	stroke: none;
	display: block;
}

/*
 * The account controls in the utility bar.
 *
 * The block was written for the paper header and hard-codes ink on cream,
 * apply button included — hence the !important this has to answer. Only the
 * colours change: the sizing, the 44px targets and the layout are the same
 * controls, on a dark ground.
 */
.top-bar .header-actions {
	gap: var(--s-5);
}

.top-bar .header-actions a,
.top-bar .header-actions button {
	color: rgba(255, 255, 255, 0.82);
}

.top-bar .header-actions a:hover,
.top-bar .header-actions a:focus-visible,
.top-bar .header-actions button:hover {
	color: var(--paper);
}

/* On cream the label is --bronze-dark for contrast; on ink that is 1.9:1.
 * The lighter gold measures 6.7:1 here, so the two grounds swap which of the
 * pair is the readable one. */
.top-bar .header-actions__apply {
	color: var(--bronze) !important;
}

.top-bar .header-actions__apply:hover,
.top-bar .header-actions__apply:focus-visible {
	color: var(--ink) !important;
}

.top-bar .header-actions svg {
	width: 17px;
	height: 17px;
}

/* The field the search icon drops. A row of its own under the bar's contents,
 * on the same ink, so it reads as the bar opening rather than as a dialog. */
.top-bar__search {
	border-block-start: 1px solid rgba(255, 255, 255, 0.14);
	padding-block: var(--s-4);
}

.top-bar__search form {
	max-width: 34rem;
}

.top-bar__search input[type="search"] {
	flex: 1 1 auto;
	min-width: 0;
	background: rgba(255, 255, 255, 0.06);
	border: 1px solid rgba(255, 255, 255, 0.22);
	color: var(--paper);
}

.top-bar__search input[type="search"]::placeholder {
	color: rgba(255, 255, 255, 0.5);
}

.top-bar__search input[type="search"]:focus {
	border-color: var(--bronze);
	outline: none;
}

/* The submit is .btn, which is ink on cream — invisible on ink. */
.top-bar__search .btn {
	background: var(--paper);
	color: var(--ink);
	border-color: var(--paper);
	flex: 0 0 auto;
}

.top-bar__search .btn:hover,
.top-bar__search .btn:focus-visible {
	background: var(--bronze);
	border-color: var(--bronze);
	color: var(--ink);
}

/* At phone width the submit was eating 40% of the row and clipping the
 * placeholder. The field is the point; the button only has to be reachable. */
@media (max-width: 599px) {
	.top-bar__search .btn {
		padding-inline: var(--s-4);
		font-size: var(--text-2xs);
	}
}

/* The same field on the search page itself, for anyone without the script. */
.search-prompt {
	max-width: 34rem;
	margin: 0 auto var(--s-8);
}

@media (max-width: 767px) {
	.top-bar__inner {
		justify-content: center;
		text-align: center;
	}

	/* Three rows of small print above the logo is most of a phone's first
	 * screen. The number is the reason anyone looks at this bar and the
	 * account controls are the reason anyone uses it; the social row is
	 * neither, and the footer carries the same links. */
	.top-bar__social {
		display: none;
	}

	.top-bar__reach {
		justify-content: center;
		width: 100%;
	}

	.top-bar .header-actions {
		width: 100%;
		justify-content: center;
	}
}

/* --------------------------------------------------------------------------
   22. GATED PRICES

   The Cuba B2B plugin replaces every price with a prompt while the visitor is
   signed out. It is styled here rather than in the plugin so the store still
   works, unstyled but intact, with this theme deactivated.
   -------------------------------------------------------------------------- */

.cuba-b2b-hidden-price {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--ink-45);
}

.cuba-b2b-hidden-price a {
	color: var(--ink-60);
	border-bottom: 1px solid var(--ink-15);
	padding-bottom: 1px;
}

.cuba-b2b-hidden-price a:hover {
	color: var(--bronze-dark);
	border-bottom-color: var(--bronze);
}


/* --------------------------------------------------------------------------
   23. SIZE SELECTOR

   A fragrance that ships in two bottle sizes is one product page varied by
   size. WooCommerce renders that choice as a <select> in a table; a bottle
   size is a two-option choice, and two options are quicker to read and
   quicker to hit as a pair of pills than as a menu that has to be opened
   first. site.js builds the pills from the select's own options and writes
   the answer back to it, so the select stays the single source of truth and
   the page still works with JavaScript off.
   -------------------------------------------------------------------------- */

.single-product table.variations {
	border: 0;
	margin: 0 0 var(--s-6);
	width: 100%;
}

.single-product table.variations th,
.single-product table.variations td {
	border: 0;
	padding: 0;
	text-align: start;
	vertical-align: middle;
}

.single-product table.variations th.label {
	display: block;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--fg-muted);
	font-weight: 400;
	padding-block-end: var(--s-3);
}

.single-product table.variations td.value {
	display: block;
}

.variation-pills {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-3);
}

/* Clipped rather than display:none. The select is still the control that is
 * submitted and the one a screen reader announces the label for; removing it
 * from the layout is a presentation change, removing it from the page is not. */
.variation-pills__select,
.rating-stars__select {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.variation-pill {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	line-height: 1;
	min-width: 5.5rem;
	padding: 0.9rem 1.4rem;
	border: 1px solid var(--ink-15);
	background: var(--paper);
	color: var(--ink-60);
	cursor: pointer;
	transition: border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.variation-pill:hover {
	border-color: var(--ink-45);
	color: var(--ink);
}

.variation-pill.is-active {
	border-color: var(--ink);
	background: var(--ink);
	color: var(--paper);
}

/* A size the store cannot sell in any combination. Left on the page rather
 * than removed: a buyer looking for the 35ML needs to see that it exists and
 * is unavailable, not be left wondering whether they misremembered. */
.variation-pill:disabled {
	border-style: dashed;
	color: var(--fg-muted);
	cursor: not-allowed;
	text-decoration: line-through;
}

.single-product .reset_variations {
	display: inline-block;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--fg-muted);
	margin-block-start: var(--s-3);
}

.woocommerce-variation {
	margin-block-end: var(--s-4);
}

.woocommerce-variation-price .price {
	margin-block-end: var(--s-2);
}

.woocommerce-variation-availability .stock {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--fg-muted);
	margin: 0;
}

.woocommerce-variation-availability .out-of-stock {
	color: var(--ink);
}

/* --------------------------------------------------------------------------
   24. CATALOGUE FILTERS

   A sidebar on a desktop and a drawer on a phone, from one set of markup.
   The panel is the same element in both: at the narrow end it leaves the
   grid, covers the viewport and is opened by the bar fixed to the bottom of
   the screen — which is where a thumb is, and where every other shopping app
   has already trained buyers to look.
   -------------------------------------------------------------------------- */

.shop-layout {
	display: grid;
	grid-template-columns: 250px minmax(0, 1fr);
	gap: var(--s-10);
	align-items: start;
}

.shop-results {
	min-width: 0;
}

.shop-filters {
	position: sticky;
	top: 7rem;
	max-height: calc(100vh - 9rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	border-right: 1px solid var(--border);
	padding-right: var(--s-6);
}

.shop-filters__head {
	display: flex;
	align-items: baseline;
	gap: var(--s-3);
	padding-block-end: var(--s-4);
	border-bottom: 1px solid var(--border);
}

.shop-filters__title {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	margin: 0;
	margin-right: auto;
}

.shop-filters__clear {
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--bronze-dark);
	border: 0;
}

/* The drawer controls. They are in the document at every width so the panel
 * stays one thing; below 1024px the media query gives them back. */
.shop-filters__close,
.shop-filters__foot {
	display: none;
}

.facet {
	padding-block: var(--s-6);
	border-bottom: 1px solid var(--border);
}

.facet__title {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin: 0 0 var(--s-3);
}

.facet__search {
	width: 100%;
	border: 1px solid var(--ink-15);
	background: var(--paper);
	padding: var(--s-2) var(--s-3);
	font-size: var(--text-2xs);
	margin-block-end: var(--s-3);
}

.facet__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s-1);
}

/* A collapsed facet hides its overflow rather than having PHP cut the list:
 * the search box has to be able to reach an option the button is hiding, and
 * a list the server already truncated cannot be searched. */
.facet.is-collapsed .facet__item:nth-child(n + 9) {
	display: none;
}

.facet.is-collapsed .facet__item.is-match {
	display: block;
}

.facet__item--hidden {
	display: none !important;
}

.facet__option {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	font-size: var(--text-xs);
	color: var(--ink-85);
	padding-block: 0.3rem;
	border: 0;
	line-height: 1.3;
}

.facet__item--child .facet__option {
	padding-left: var(--s-6);
}

/* The box is the only thing showing an unchecked filter exists, so its edge is
 * a control boundary rather than decoration and needs 3:1 like any other. */
.facet__box {
	flex: 0 0 auto;
	width: 15px;
	height: 15px;
	border: 1px solid var(--ink-45);
	background: var(--paper);
	position: relative;
}

.facet__option.is-checked .facet__box {
	background: var(--ink);
	border-color: var(--ink);
}

.facet__option.is-checked .facet__box::after {
	content: "";
	position: absolute;
	left: 4px;
	top: 1px;
	width: 4px;
	height: 8px;
	border: solid var(--paper);
	border-width: 0 1.5px 1.5px 0;
	transform: rotate(45deg);
}

.facet__name {
	flex: 1 1 auto;
	min-width: 0;
}

.facet__count {
	color: var(--fg-muted);
	font-size: var(--text-2xs);
	font-variant-numeric: tabular-nums;
}

.facet__option:hover,
.facet__option:focus-visible {
	color: var(--bronze-dark);
}

.facet__more {
	background: none;
	border: 0;
	padding: var(--s-2) 0 0;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--bronze-dark);
	cursor: pointer;
}

/* Two range inputs on one track. The pair is transparent to the pointer
 * except at the thumbs, or the upper one would swallow every click meant for
 * the lower. */
.facet-price__track {
	position: relative;
	height: 2rem;
	margin-block: var(--s-2);
}

.facet-price__track::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	height: 2px;
	background: var(--ink-15);
	transform: translateY(-50%);
}

.facet-price__range {
	position: absolute;
	inset: 0;
	width: 100%;
	margin: 0;
	background: none;
	pointer-events: none;
	appearance: none;
	-webkit-appearance: none;
}

.facet-price__range::-webkit-slider-thumb {
	pointer-events: auto;
	appearance: none;
	-webkit-appearance: none;
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: var(--ink);
	border: 2px solid var(--paper);
	box-shadow: var(--shadow-sm);
	cursor: pointer;
}

.facet-price__range::-moz-range-thumb {
	pointer-events: auto;
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: var(--ink);
	border: 2px solid var(--paper);
	cursor: pointer;
}

.facet-price__readout {
	font-size: var(--text-xs);
	color: var(--ink-60);
	font-variant-numeric: tabular-nums;
	margin: 0 0 var(--s-3);
}

.facet-price__go {
	background: none;
	border: 1px solid var(--ink-15);
	padding: var(--s-2) var(--s-4);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	cursor: pointer;
}

.facet-price__go:hover,
.facet-price__go:focus-visible {
	border-color: var(--ink);
}

.shop-chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-2);
	margin-block-end: var(--s-6);
}

.shop-chip {
	display: inline-flex;
	align-items: center;
	gap: var(--s-2);
	border: 1px solid var(--ink-15);
	padding: 0.35rem var(--s-3);
	font-size: var(--text-2xs);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--ink-60);
}

.shop-chip:hover,
.shop-chip:focus-visible {
	border-color: var(--ink);
	color: var(--ink);
}

.shop-chip--clear {
	border-color: transparent;
	color: var(--bronze-dark);
}

/* The phone bar and the sort sheet: absent until the panel becomes a drawer. */
.shop-bar,
.shop-sort {
	display: none;
}

@media (max-width: 1023px) {
	.shop-layout {
		display: block;
	}

	.shop-filters {
		position: fixed;
		inset: 0 0 0 auto;
		z-index: 80;
		width: min(88vw, 24rem);
		max-height: none;
		background: var(--paper);
		border-right: 0;
		padding: var(--s-4) var(--s-4) 0;
		display: flex;
		flex-direction: column;
		transform: translateX(100%);
		visibility: hidden;
		transition: transform var(--speed) var(--ease), visibility var(--speed);
	}

	.filters-open .shop-filters {
		transform: translateX(0);
		visibility: visible;
	}

	.shop-filters__body {
		flex: 1 1 auto;
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	.shop-filters__close {
		display: grid;
		place-items: center;
		min-width: 44px;
		min-height: 44px;
		margin-inline-end: calc(-1 * var(--s-2));
		background: none;
		border: 0;
		font-size: 1.5rem;
		line-height: 1;
		padding: 0 var(--s-2);
		cursor: pointer;
	}

	.shop-filters__foot {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--s-3);
		align-items: center;
		padding-block: var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom, 0px));
		border-top: 1px solid var(--border);
	}

	.shop-filters__foot .btn {
		padding: 0.9rem 1rem;
		text-align: center;
	}

	.filters-open::before {
		content: "";
		position: fixed;
		inset: 0;
		z-index: 79;
		background: rgba(23, 23, 23, 0.4);
	}

	/* The drawer and the sort sheet both scroll inside themselves; without
	 * this the momentum carried straight through into the results behind, and
	 * a buyer who flicked the facet list found the catalogue had moved on
	 * under it. Set from site.js, which knows which of the two is open. */
	.panel-open,
	.panel-open body {
		overflow: hidden;
	}

	/* Below the header's 50 rather than above it. At 60 the bar painted over
	 * the open navigation drawer, which drops down from the header and can
	 * reach the bottom of a short screen. */
	.shop-bar {
		display: grid;
		grid-template-columns: 1fr 1fr;
		position: fixed;
		inset: auto 0 0 0;
		z-index: 40;
		background: var(--paper);
		border-top: 1px solid var(--ink-15);
		box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
		/* The bar's own ground runs under the home indicator; the buttons stop
		 * above it. Anything anchored to the bottom edge on this site does the
		 * same, and the fallback keeps it at nought everywhere else. */
		padding-block-end: env(safe-area-inset-bottom, 0px);
	}

	.shop-bar__button {
		background: none;
		border: 0;
		border-left: 1px solid var(--border);
		padding: var(--s-4);
		font-family: var(--font-sans);
		font-size: var(--text-xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		cursor: pointer;
	}

	.shop-bar__button:first-child {
		border-left: 0;
	}

	.shop-bar__count {
		display: inline-block;
		margin-left: var(--s-2);
		min-width: 1.25rem;
		padding: 0.1rem 0.3rem;
		background: var(--ink);
		color: var(--paper);
		border-radius: 999px;
		font-size: 0.6875rem;
		letter-spacing: 0;
	}

	/* The bar covers the last row of products, so the page ends above it. */
	.shop-results {
		padding-block-end: calc(4rem + env(safe-area-inset-bottom, 0px));
	}

	.shop-sort {
		display: block;
		position: fixed;
		inset: auto 0 0 0;
		z-index: 81;
		background: var(--paper);
		padding: var(--s-4) 0 calc(var(--s-2) + env(safe-area-inset-bottom, 0px));
		box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.15);
	}

	.shop-sort[hidden] {
		display: none;
	}

	.shop-sort__title {
		font-size: var(--text-2xs);
		letter-spacing: var(--track-wide);
		text-transform: uppercase;
		color: var(--ink-45);
		margin: 0 0 var(--s-2);
		padding-inline: var(--s-4);
	}

	.shop-sort ul {
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.shop-sort a {
		display: block;
		padding: var(--s-3) var(--s-4);
		font-size: var(--text-sm);
		color: var(--ink-85);
		border: 0;
	}

	.shop-sort a.is-current {
		color: var(--bronze-dark);
		font-weight: 500;
	}

	/* The desktop select would be a second sort control on the same page. */
	.shop-head__sort {
		display: none;
	}

	/* Apply carries the price with everything else the drawer collected, so
	 * a button that submitted the price alone would drop the rest. */
	.facet-price__go {
		display: none;
	}
}

@media (min-width: 1024px) and (max-width: 1279px) {
	.shop-layout {
		grid-template-columns: 210px minmax(0, 1fr);
		gap: var(--s-6);
	}
}

/* --------------------------------------------------------------------------
   25. PRODUCT PAGE

   Two columns: photography on the left, and on the right one bordered panel
   holding everything a buyer touches to place an order.

   The photography column sticks. That is the opposite of what this section
   said a version ago, and the reason is worth writing down. The original bug
   was a *stacked* gallery — four photographs one under another, taller than
   the screen — pinned with position: sticky, so scrolling dragged the picture
   through the viewport while the text stood still. The fix was to stop
   stacking. But the frame that replaced it is a single square, and a square
   that is shorter than the viewport can be pinned without any of that: it
   arrives, it stays, it leaves with the grid. What makes sticky safe is the
   height cap below, which keeps the frame smaller than the screen on every
   viewport rather than only on tall ones.

   Without it the left column ended 800 pixels above the right one and the
   page was half empty from the size pills down.
   -------------------------------------------------------------------------- */

.single-product div.product {
	display: grid;
	grid-template-columns: minmax(0, 1.18fr) minmax(0, 1fr);
	gap: var(--s-12);
	align-items: start;
	padding-block: var(--s-6) var(--s-16);
}

/* Everything hooked in after the summary is one more item in that grid, which
 * is how a recommendations row once rendered four cards wide inside the left
 * column. */
.single-product div.product > .woocommerce-tabs,
.single-product div.product > .cuba-row,
.single-product div.product > .pdp-details,
.single-product div.product > .pdp-reviews,
.single-product div.product > .related,
.single-product div.product > .upsells {
	grid-column: 1 / -1;
}

/* The frame ---------------------------------------------------------------- */

.pdp-media {
	/* The cap that makes sticking safe. 11rem is the header, the top bar and
	 * the breathing room above and below; whatever is left of the screen is
	 * the most the frame may ever be. */
	--frame-max: calc(100vh - 11rem);

	display: grid;
	grid-template-columns: 5.5rem minmax(0, 1fr);
	gap: var(--s-3);
	align-items: start;
	align-content: start;

	/* The fence the sticky children are locked inside. This element is NOT
	 * sticky itself, and must never be again: it is a grid item, and Chrome
	 * bounds a sticky grid item by the grid CONTAINER, not by its row — and
	 * div.product's grid also contains the details, the reviews and the
	 * recommendation rows, so the frame kept pinning for the whole page and
	 * painted over every section below the fold. Stretching this box to the
	 * row and making its children the sticky ones gives them a containing
	 * block that ends where the summary ends. */
	align-self: stretch;
}

.pdp-media > .pdp-rail,
.pdp-media > .woocommerce-product-gallery {
	position: sticky;
	top: var(--s-8);
}

/* One photograph, so inc/single-product.php never built a rail and the frame
 * would otherwise sit in the empty rail's column. */
.pdp-media--solo {
	display: block;
}

.single-product div.product .woocommerce-product-gallery {
	/* WooCommerce writes opacity: 0 into the gallery's style attribute and
	 * fades it back in from single-product.js. That script is dequeued in
	 * inc/performance.php — it exists for the lightbox and the slider, and
	 * this theme uses neither — so nothing ever faded it back, and every
	 * product page in the store was serving its images invisible. An inline
	 * style is why this one needs the flag. */
	opacity: 1 !important;
	min-width: 0;
}

/* One frame wide, swiped or scrolled sideways. Scroll snapping is the whole
 * mechanism: the thumbnails only set scrollLeft, so the gallery still works on
 * a touch screen with the script disabled. */
.single-product .woocommerce-product-gallery__wrapper {
	display: flex;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	scrollbar-width: none;

	/* A frame, not a void. These packshots are cut out on white with a
	 * generous margin baked into the file, so on a white page the bottle
	 * floats in nothing and the column reads as empty space rather than as a
	 * photograph.
	 *
	 * A tinted ground was the first attempt and it was worse: the photograph's
	 * own white rectangle sat inside the tint with a hard edge, so the frame
	 * read as two frames. A hairline draws the same edge and lets the file's
	 * white run to it. */
	background: #fff;
	border: 1px solid var(--panel-edge);
	margin: 0;
}

.single-product .woocommerce-product-gallery__wrapper::-webkit-scrollbar {
	display: none;
}

.single-product .woocommerce-product-gallery__image {
	flex: 0 0 100%;
	scroll-snap-align: center;
	min-width: 0;

	/* The clip for the hover magnifier below: the photograph scales up under
	 * the cursor and the slide is the frame it may not leave. Clipping here
	 * also keeps the scaled image out of the track's scrollable overflow. */
	overflow: hidden;
}

.single-product .woocommerce-product-gallery__image a {
	display: block;
	cursor: zoom-in;
}

/* The packshots are square. Saying so keeps the frame on its baseline while a
 * photograph is still loading, and stops a portrait crop stretching it. The
 * cap is what keeps the square inside the viewport on a laptop screen; below
 * it the box letterboxes on the ground rather than growing. */
.single-product .woocommerce-product-gallery__image img {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	max-height: var(--frame-max);
	object-fit: contain;
	padding: var(--s-4);
	transition: transform 0.2s var(--ease);
}

/* The magnifier. site.js sets the class and steers transform-origin under
 * the cursor, so the part of the label being pointed at is the part that
 * grows — reading the fine print without leaving the page. Mouse only; the
 * script checks for a fine pointer before it ever adds the class. */
.single-product .woocommerce-product-gallery__image.is-zooming img {
	transform: scale(2.1);
}

/* The rail is built by site.js from the gallery's own items, so it mirrors
 * whatever is in there — including the plugin hiding the photographs that
 * belong to the size the buyer did not pick. */
.pdp-rail {
	display: flex;
	flex-direction: column;
	gap: var(--s-2);
	min-width: 0;
}

.pdp-rail__thumb {
	display: block;
	padding: 0;
	border: 1px solid var(--panel-edge);
	background: #fff;
	cursor: pointer;
	transition: border-color var(--speed) var(--ease);
}

.pdp-rail__thumb img {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	object-fit: contain;
}

.pdp-rail__thumb:hover {
	border-color: var(--ink-30);
}

.pdp-rail__thumb.is-active {
	border-color: var(--ink);
}

.pdp-rail__thumb[hidden] {
	display: none;
}

/* The head of the summary -------------------------------------------------- */

.pdp-eyebrow {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	color: var(--fg-muted);
	margin: 0 0 var(--s-2);
}

.pdp-eyebrow a {
	color: inherit;
	border: 0;
}

.pdp-eyebrow a:hover {
	color: var(--bronze-dark);
}

.single-product div.product .product_title {
	margin-block-end: var(--s-2);
	font-size: var(--text-h2);
	line-height: 1.15;
}

.pdp-rating {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	margin: 0 0 var(--s-3);
}

.pdp-rating__count {
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	color: var(--fg-muted);
	border: 0;
}

.pdp-rating__count:hover {
	color: var(--bronze-dark);
}

/* The one-line specification, moved up to sit under the rating as a subtitle. */
.single-product .woocommerce-product-details__short-description {
	font-size: var(--text-sm);
	color: var(--ink-60);
	margin: 0 0 var(--s-6);
}

.single-product .woocommerce-product-details__short-description p {
	margin: 0;
}

/* The purchase panel ------------------------------------------------------- */

.pdp-buy {
	border: 1px solid var(--panel-edge);
	background: var(--panel);
	padding: var(--s-6);
}

/* Signed out, the plugin says the same thing twice inside the panel — a
 * heading-sized "Log in for wholesale pricing" link and a boxed notice with
 * the same sentence and no button. Both are hidden and the theme's own CTA
 * block (cuba_maison_guest_cta) carries the message once, with the two
 * actions a visiting retailer actually has. Scoped to the panel: the same
 * plugin strings on catalogue cards are untouched. */
.single-product .pdp-buy .cuba-b2b-hidden-price,
.single-product .pdp-buy > .cuba-b2b-notice--guest {
	display: none;
}

.pdp-cta__eyebrow {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin: 0 0 var(--s-2);
}

.pdp-cta__copy {
	font-size: var(--text-sm);
	color: var(--ink-60);
	margin: 0 0 var(--s-5);
	max-width: 46ch;
}

.pdp-cta__actions {
	display: grid;
	gap: var(--s-3);
}

.pdp-cta__actions .button {
	width: 100%;
	text-align: center;
	height: 3.25rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

.pdp-cta__actions .button--ghost {
	background: transparent;
	color: var(--ink);
	border: 1px solid var(--ink);
}

.pdp-cta__actions .button--ghost:hover {
	background: var(--ink);
	color: var(--paper);
}

/* The headline price. On a variable product WooCommerce prints the range here
 * and the chosen variation's price again inside the form, which is two prices
 * for one product. Once a size is chosen the range has nothing left to say,
 * so it goes; until then it is the only price there is. */
.single-product .pdp-buy > .price {
	font-family: var(--font-sans);
	font-size: 1.75rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--ink);
	margin: 0;
}

/* The signal is the variation's own price node, which WooCommerce empties
 * again when the buyer clears the size. Keying off an inline display style was
 * wrong: the form shows the block by adding and then removing that style, so
 * the attribute is gone by the time the price is on screen. */
.pdp-buy:has(.woocommerce-variation-price .price) > .price {
	display: none;
}

/* The tier table.
 *
 * A single row is not a table. When a product has one price for every quantity
 * — which is most of this catalogue until the owner sets breaks — the heading,
 * the two column headers and the footnote say nothing the price above them has
 * not already said, and they were the tallest block in the panel. */
.pdp-buy .cuba-b2b-price-breaks {
	margin-block: var(--s-5) 0;
}

.pdp-buy .cuba-b2b-price-breaks:not(:has(tbody tr:nth-child(2))) {
	display: none;
}

.pdp-buy .cuba-b2b-price-breaks__title {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin: 0 0 var(--s-3);
}

.pdp-buy .cuba-b2b-price-breaks__note {
	font-size: var(--text-2xs);
	color: var(--ink-45);
	margin: var(--s-3) 0 0;
}

/* The form ----------------------------------------------------------------- */

.pdp-buy .variations_form {
	margin: 0;
}

.pdp-buy table.variations {
	margin: var(--s-5) 0 0;
	border: 0;
}

.pdp-buy table.variations th.label {
	display: block;
	padding: 0 0 var(--s-2);
	border: 0;
	text-align: start;
}

.pdp-buy table.variations th.label label {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
}

.pdp-buy table.variations td.value {
	display: block;
	padding: 0;
	border: 0;
}

/* "Clear" was set at the same size and tracking as the section headings, so a
 * reset link read as a title for the block under it. */
.pdp-buy .reset_variations {
	display: inline-block;
	margin-block-start: var(--s-3);
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0;
	text-transform: none;
	color: var(--ink-45);
	border: 0;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.pdp-buy .reset_variations:hover {
	color: var(--bronze-dark);
}

/* The chosen variation's price is the headline once there is one. */
.pdp-buy .woocommerce-variation-price {
	margin-block-start: var(--s-5);
}

.single-product .pdp-buy .woocommerce-variation-price .price {
	font-family: var(--font-sans);
	font-size: 1.75rem;
	font-weight: 600;
	letter-spacing: -0.01em;
	color: var(--ink);
}

.pdp-buy .woocommerce-variation-availability {
	margin-block-start: var(--s-1);
}

.pdp-buy .woocommerce-variation-availability .stock {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ink-45);
	margin: 0;
}

/* Unit and quantity side by side, then the running total, then the button
 * across the full width of the panel. */
.pdp-buy .woocommerce-variation-add-to-cart,
.pdp-buy form.cart:not(.variations_form) {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 6.5rem;
	gap: var(--s-3) var(--s-4);
	align-items: end;
	margin-block-start: var(--s-6);
}

.pdp-buy .cuba-b2b-unit-selector {
	min-width: 0;
}

.pdp-buy .cuba-b2b-unit-selector__label,
.pdp-buy .quantity::before {
	display: block;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin-block-end: var(--s-2);
}

/* The quantity box arrived with no label at all — a bare square beside a
 * labelled dropdown. */
.pdp-buy .quantity::before {
	content: "Qty";
}

.pdp-buy .cuba-b2b-unit-selector__select,
.pdp-buy .quantity .qty {
	width: 100%;
	height: 3rem;
	padding-inline: var(--s-3);
	border: 1px solid var(--ink-15);
	background: var(--paper);
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	color: var(--ink);
}

.pdp-buy .cuba-b2b-unit-selector__select:focus-visible,
.pdp-buy .quantity .qty:focus-visible {
	outline: 0;
	border-color: var(--bronze);
	box-shadow: 0 0 0 1px var(--bronze);
}

.pdp-buy .cuba-b2b-line-total {
	grid-column: 1 / -1;
	font-size: var(--text-sm);
	color: var(--ink-60);
}

.pdp-buy .cuba-b2b-line-total__value {
	color: var(--ink);
	font-weight: 600;
}

.pdp-buy .cuba-b2b-line-total__detail {
	font-weight: 400;
	color: var(--ink-45);
}

.single-product .pdp-buy .single_add_to_cart_button {
	grid-column: 1 / -1;
	width: 100%;
	height: 3.25rem;
	margin: 0;
}

/* The three things a wholesale buyer asks after the price ------------------- */

.pdp-assurances {
	list-style: none;
	margin: var(--s-6) 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s-3);
}

.pdp-assurances li {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	font-size: var(--text-xs);
	color: var(--ink-60);
}

.pdp-assurances__icon {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	fill: none;
	stroke: var(--bronze);
	stroke-width: 1.2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* Sections below the fold -------------------------------------------------- */

.pdp-section__title {
	font-size: var(--text-h4);
	margin: 0 0 var(--s-6);
}

/* The description, the pyramid and the specification, across the full width.
 * These used to be a tab strip whose panels all rendered open at once, because
 * the script that switches them is dequeued. */
.pdp-details {
	display: grid;
	grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
	gap: var(--s-12);
	align-items: start;
	border-top: 1px solid var(--border);
	padding-block-start: var(--s-12);
	margin-block-start: var(--s-8);
}

.pdp-details__prose {
	max-width: 60ch;
	color: var(--ink-60);
}

.pdp-details__prose p {
	margin: 0 0 var(--s-4);
}

/* The pyramid -------------------------------------------------------------- */

.pdp-notes {
	margin-block-start: var(--s-10);
}

.pdp-notes__title {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin: 0 0 var(--s-4);
}

.pdp-notes__list {
	margin: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s-3);
}

.pdp-notes__tier {
	display: grid;
	grid-template-columns: 4.5rem minmax(0, 1fr);
	gap: var(--s-3);
	align-items: baseline;
}

.pdp-notes__tier dt {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ink-45);
}

.pdp-notes__tier dd {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-2);
}

.pdp-note {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.03em;
	line-height: 1;
	padding: 0.4rem 0.7rem;
	border: 1px solid var(--ink-15);
	color: var(--ink-85);
	transition: border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.pdp-note:hover,
.pdp-note:focus-visible {
	border-color: var(--bronze);
	color: var(--bronze-dark);
}

/* The specification -------------------------------------------------------- */

.single-product .pdp-details__spec .woocommerce-product-attributes {
	width: 100%;
	border: 0;
	margin: 0;
}

.single-product .pdp-details__spec .woocommerce-product-attributes tr {
	border-bottom: 1px solid var(--border);
}

.single-product .pdp-details__spec .woocommerce-product-attributes th,
.single-product .pdp-details__spec .woocommerce-product-attributes td {
	padding: var(--s-3) 0;
	border: 0;
	font-size: var(--text-xs);
	text-align: start;
	vertical-align: top;
}

.single-product .pdp-details__spec .woocommerce-product-attributes th {
	width: 40%;
	font-family: var(--font-sans);
	font-weight: 500;
	color: var(--ink-45);
}

.single-product .pdp-details__spec .woocommerce-product-attributes td,
.single-product .pdp-details__spec .woocommerce-product-attributes td p {
	color: var(--ink-85);
	margin: 0;
}

.single-product .pdp-details__spec .product_meta {
	margin-block-start: var(--s-6);
	display: flex;
	flex-direction: column;
	gap: var(--s-2);
	font-size: var(--text-2xs);
	color: var(--ink-45);
}

@media (max-width: 1023px) {
	.single-product div.product {
		gap: var(--s-8);
	}

	.pdp-details {
		gap: var(--s-8);
	}
}

@media (max-width: 899px) {
	.single-product div.product {
		grid-template-columns: 1fr;
	}

	/* Nothing sticks on a phone: the frame and the panel are one column, so
	 * pinning the picture would mean scrolling past a photograph that never
	 * leaves. */
	.pdp-media {
		align-self: auto;
		grid-template-columns: 1fr;
		gap: var(--s-3);
		--frame-max: none;
	}

	.pdp-media > .pdp-rail,
	.pdp-media > .woocommerce-product-gallery {
		position: static;
	}

	/* The rail is the first child so that it is the left-hand column on a
	 * desktop; ordering is what puts it back under the frame here. */
	.pdp-rail {
		order: 2;
		flex-direction: row;
		overflow-x: auto;
		scrollbar-width: none;
	}

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

	.pdp-rail__thumb {
		flex: 0 0 3.75rem;
	}

	/* Full-bleed photography on a phone: the frame is the strongest thing on
	 * the screen and a margin either side only makes it smaller. */
	.single-product .woocommerce-product-gallery__wrapper {
		margin-inline: calc(var(--s-4) * -1);
	}

	.pdp-buy {
		padding: var(--s-4);
	}

	.pdp-details {
		grid-template-columns: 1fr;
		padding-block-start: var(--s-8);
	}

	.pdp-notes__tier {
		grid-template-columns: 3.75rem minmax(0, 1fr);
	}
}


/* --------------------------------------------------------------------------
   26. RECOMMENDATION ROWS

   Three rows sharing one grid and one card. Each is separated by a rule
   rather than a heading alone, because three product grids in sequence read
   as one long grid otherwise.
   -------------------------------------------------------------------------- */

.cuba-row {
	margin-block-start: var(--s-12);
	padding-block-start: var(--s-10);
	border-top: 1px solid var(--border);
}

.cuba-row ul.products {
	margin-block-end: 0;
}

/* --------------------------------------------------------------------------
   27. RATINGS AND REVIEWS

   WooCommerce's star markup is a percentage-width overlay over five
   characters. Its own stylesheet draws them from a bundled icon font and is
   dequeued here, so the stars are redrawn from the character itself — no
   extra request, and it inherits the accent colour like everything else.
   -------------------------------------------------------------------------- */

.star-rating {
	position: relative;
	overflow: hidden;
	display: inline-block;
	width: 5.6em;
	height: 1.2em;
	line-height: 1.2;
	font-size: var(--text-sm);
	font-family: var(--font-sans);
	letter-spacing: 0.12em;
	flex: 0 0 auto;
}

.star-rating::before {
	content: "\2605\2605\2605\2605\2605";
	position: absolute;
	inset: 0;
	color: var(--ink-15);
}

.star-rating span {
	position: absolute;
	inset: 0;
	overflow: hidden;
	white-space: nowrap;
	/* The span holds the accessible text — "Rated 4.00 out of 5" — which has
	 * to stay in the document and out of sight. Pushing it down a line and
	 * clipping is what keeps both true. */
	text-indent: -999em;
}

.star-rating span::before {
	content: "\2605\2605\2605\2605\2605";
	position: absolute;
	inset: 0;
	text-indent: 0;
	color: var(--bronze);
}

/* Two columns: the scores on the left, the reviews and the form on the right.
 * As one column the section was a 640-pixel form against 660 pixels of empty
 * page, which is what the whole layout below the fold used to look like. */
.pdp-reviews {
	margin-block-start: var(--s-12);
	padding-block-start: var(--s-10);
	border-top: 1px solid var(--border);
	display: grid;
	grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
	gap: var(--s-6) var(--s-12);
	align-items: start;
}

.pdp-reviews > .pdp-section__title {
	grid-column: 1 / -1;
}

/*
 * WooCommerce's own heading is printed unconditionally by
 * single-product-reviews.php and reads "Reviews", which the section is already
 * titled. Two headings, one section. The filter it offers only reaches the
 * variant with a count in it, so the duplicate goes here.
 */
.pdp-reviews .woocommerce-Reviews-title {
	display: none;
}

.review-summary {
	padding: var(--s-6);
	background: var(--panel);
	border: 1px solid var(--panel-edge);
}

.review-summary--empty {
	display: block;
}

/* WooCommerce's own "There are no reviews yet." is the same sentence as the
 * panel to its left, printed twice on the one screen where there is least to
 * read. The panel always renders when the count is nought, so this can go
 * unconditionally rather than through :has(). */
.pdp-reviews .woocommerce-noreviews {
	display: none;
}

.review-summary__none {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-60);
	margin: 0 0 var(--s-3);
}

.review-summary__invite {
	font-size: var(--text-xs);
	color: var(--ink-60);
	margin: 0;
}

.review-summary__score {
	text-align: center;
}

.review-summary__average {
	font-family: var(--font-display);
	font-size: 3rem;
	line-height: 1;
	margin: 0 0 var(--s-2);
}

.review-summary__count {
	font-size: var(--text-xs);
	color: var(--fg-muted);
	margin: var(--s-2) 0 0;
}

.review-summary__score {
	padding-block-end: var(--s-5);
	margin-block-end: var(--s-5);
	border-bottom: 1px solid var(--panel-edge);
}

.review-bars {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s-2);
}

.review-bars__row {
	display: grid;
	grid-template-columns: 3.5rem minmax(0, 1fr) 2rem;
	gap: var(--s-3);
	align-items: center;
	font-size: var(--text-2xs);
	color: var(--fg-muted);
	font-variant-numeric: tabular-nums;
}

.review-bars__track {
	height: 6px;
	background: var(--ink-15);
	display: block;
}

.review-bars__fill {
	display: block;
	height: 100%;
	background: var(--bronze);
}

.review-bars__value {
	text-align: end;
}

.woocommerce-Reviews-title {
	font-size: var(--text-h4);
	margin: 0 0 var(--s-6);
}

.woocommerce-Reviews .commentlist {
	list-style: none;
	margin: 0 0 var(--s-10);
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s-6);
}

.woocommerce-Reviews .commentlist > li {
	border-top: 1px solid var(--border);
	padding-block-start: var(--s-6);
}

.woocommerce-Reviews .comment_container {
	display: grid;
	grid-template-columns: 3rem minmax(0, 1fr);
	gap: var(--s-4);
	align-items: start;
}

.woocommerce-Reviews .comment_container img.avatar {
	width: 3rem;
	height: 3rem;
	border-radius: 50%;
}

.woocommerce-Reviews .meta {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.04em;
	color: var(--fg-muted);
	margin: var(--s-2) 0 var(--s-3);
}

.woocommerce-Reviews .meta strong {
	color: var(--ink);
	text-transform: uppercase;
	letter-spacing: var(--track-wide);
}

.woocommerce-Reviews .description p:last-child {
	margin-block-end: 0;
}

.woocommerce-Reviews .woocommerce-review__verified {
	color: var(--bronze-dark);
}

/* The form ---------------------------------------------------------------- */

#review_form_wrapper {
	border-top: 1px solid var(--border);
	padding-block-start: var(--s-8);
	max-width: 40rem;
}

#review_form_wrapper .comment-reply-title {
	display: block;
	font-family: var(--font-sans);
	font-size: var(--text-xs);
	letter-spacing: var(--track-wide);
	text-transform: uppercase;
	margin-block-end: var(--s-5);
}

.review-form label,
.comment-form label {
	display: block;
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--fg-muted);
	margin-block-end: var(--s-2);
}

.review-form p,
.comment-form p {
	margin-block-end: var(--s-4);
}

.comment-form-rating {
	margin-block-end: var(--s-4);
}

/* Five buttons standing in for the rating select, built by site.js from the
 * select's own options. Same arrangement as the size pills: the select is
 * still the field that is submitted, so the form works without the script.
 *
 * The stars are in the DOM highest first and laid back out with row-reverse,
 * because CSS can select the siblings that follow an element but not the ones
 * before it — and "paint every star up to the one under the pointer" is only
 * expressible in one of those two directions. */
.rating-stars {
	display: flex;
	flex-direction: row-reverse;
	justify-content: flex-end;
	gap: 0.15rem;
}

.rating-stars__star {
	background: none;
	border: 0;
	padding: 0 0.1rem;
	font-size: 1.6rem;
	line-height: 1;
	color: var(--ink-15);
	cursor: pointer;
	transition: color var(--speed) var(--ease);
}

.rating-stars__star.is-on {
	color: var(--bronze);
}

/* While the pointer is over the row, the preview replaces the choice
 * entirely — otherwise a four-star selection would still show four while the
 * buyer is hovering over two. */
.rating-stars:hover .rating-stars__star {
	color: var(--ink-15);
}

.rating-stars__star:hover,
.rating-stars__star:hover ~ .rating-stars__star {
	color: var(--bronze);
}

.must-log-in {
	font-size: var(--text-sm);
	color: var(--fg-muted);
}

.woocommerce-verification-required {
	font-size: var(--text-sm);
	color: var(--fg-muted);
}

@media (max-width: 767px) {
	.review-summary {
		grid-template-columns: 1fr;
		gap: var(--s-6);
	}

	.pdp-reviews {
		grid-template-columns: 1fr;
	}

	.woocommerce-Reviews .comment_container {
		grid-template-columns: 2.25rem minmax(0, 1fr);
	}

	.woocommerce-Reviews .comment_container img.avatar {
		width: 2.25rem;
		height: 2.25rem;
	}
}

/* --------------------------------------------------------------------------
   28. THE TRADE SIGN-IN GATE
   -------------------------------------------------------------------------- */

/*
 * The page template wraps its content in .prose, which is measured for reading
 * body copy — 68 characters. Two panels side by side need the whole column, and
 * only on this one screen.
 */
.cuba-login .prose {
	max-width: none;
}

/* The template's "My account" heading is replaced by the panel's own, which
 * says what the screen is for rather than what it will be once you are in. */
.cuba-login .entry-header {
	display: none;
}

.cuba-login .login-gate h2:not(.login-gate__subtitle) {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.login-gate {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
	border: 1px solid var(--border);
	margin-block-start: var(--s-10);
}

.login-gate__panel {
	padding: var(--s-12);
	min-width: 0;
}

.login-gate__panel--apply {
	background: var(--shell);
	border-inline-start: 1px solid var(--border);
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}

.login-gate__eyebrow {
	font-family: var(--font-sans);
	font-size: var(--text-2xs);
	letter-spacing: var(--track-wider);
	text-transform: uppercase;
	color: var(--bronze);
	margin: 0;
}

.login-gate__title {
	font-family: var(--font-display);
	font-size: var(--text-h2);
	line-height: 1.1;
	margin: var(--s-3) 0 0;
}

.login-gate__subtitle {
	font-family: var(--font-display);
	font-size: var(--text-h4);
	line-height: 1.2;
	margin: 0;
}

.login-gate__lead {
	color: var(--fg-muted);
	font-size: var(--text-sm);
	max-width: 34ch;
	margin: var(--s-3) 0 var(--s-8);
}

/* The form itself. WooCommerce's own markup, given the panel's measure so the
 * fields do not run the full width of a 700px column — a 700px-wide password
 * field looks like a search bar. */
.login-gate .woocommerce-form-login {
	max-width: 24rem;
	margin: 0;
	padding: 0;
	border: 0;
}

.login-gate .woocommerce-form-login .form-row {
	margin-block-end: var(--s-5);
}

.login-gate input.input-text,
.login-gate .password-input input {
	width: 100%;
	padding: var(--s-3) var(--s-4);
	border: 1px solid var(--ink-15);
	background: var(--paper);
	font-family: var(--font-sans);
	font-size: var(--text-sm);
	color: var(--ink);
	transition: border-color var(--speed) var(--ease);
}

.login-gate input.input-text:focus,
.login-gate .password-input input:focus {
	outline: 0;
	border-color: var(--bronze);
}

.login-gate .password-input {
	display: block;
	position: relative;
}

/*
 * WooCommerce's show-password control is an empty button that its own
 * stylesheet fills with an eye. That stylesheet is dequeued, so the button was
 * a 0-wide invisible control — present in the tab order, doing nothing a
 * sighted user could see. Redrawn here from the same box.
 */
.login-gate .show-password-input {
	position: absolute;
	inset-block: 0;
	inset-inline-end: 0;
	width: 2.75rem;
	border: 0;
	background: none;
	cursor: pointer;
	color: var(--fg-muted);
}

.login-gate .show-password-input::after {
	content: "";
	position: absolute;
	inset: 50% auto auto 50%;
	width: 1rem;
	height: 1rem;
	transform: translate(-50%, -50%);
	background: currentColor;
	mask: var(--eye) center / contain no-repeat;
	-webkit-mask: var(--eye) center / contain no-repeat;
}

.login-gate .show-password-input:hover,
.login-gate .show-password-input.display-password {
	color: var(--ink);
}

.login-gate .woocommerce-form-login__rememberme {
	display: flex;
	align-items: center;
	gap: var(--s-2);
	font-size: var(--text-sm);
	color: var(--fg-muted);
	text-transform: none;
	letter-spacing: 0;
	margin-block-end: var(--s-5);
}

.login-gate .woocommerce-form-login__submit {
	width: 100%;
	justify-content: center;
}

.login-gate .lost_password {
	margin-block-start: var(--s-5);
	font-size: var(--text-sm);
}

.login-gate .lost_password a {
	color: var(--fg-muted);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.login-gate .lost_password a:hover {
	color: var(--bronze);
}

/* The three points. Icons at the same weight as the ones on the product page,
 * because they are the same three promises said in the same voice. */
.login-gate__points {
	list-style: none;
	margin: 0 0 var(--s-8);
	padding: 0;
	display: grid;
	gap: var(--s-4);
}

.login-gate__points li {
	display: grid;
	grid-template-columns: 1.25rem minmax(0, 1fr);
	gap: var(--s-3);
	align-items: start;
	font-size: var(--text-sm);
	color: var(--ink-85);
	max-width: 34ch;
}

.login-gate__points svg {
	width: 1.25rem;
	height: 1.25rem;
	stroke: var(--bronze);
	fill: none;
	stroke-width: 1.15;
	margin-block-start: 0.15rem;
}

.login-gate__note {
	font-size: var(--text-xs);
	color: var(--ink-45);
	margin: var(--s-4) 0 0;
}

@media (max-width: 899px) {
	.login-gate {
		grid-template-columns: minmax(0, 1fr);
	}

	.login-gate__panel {
		padding: var(--s-8) var(--s-6);
	}

	.login-gate__panel--apply {
		border-inline-start: 0;
		border-block-start: 1px solid var(--border);
	}

	.login-gate .woocommerce-form-login {
		max-width: none;
	}
}

/* --------------------------------------------------------------------------
   29. TOUCH SCREENS
   -------------------------------------------------------------------------- */

/*
 * iOS Safari zooms the whole page when a focused field's font-size is under
 * 16px, and leaves it zoomed after the keyboard goes away. Every control that
 * sets a smaller size is raised to 1rem here. The media query adds no
 * specificity of its own, so the list has to repeat every selector that
 * outranks the base input rule — a new component that styles its own inputs
 * below 1rem needs an entry here too.
 */
@media (hover: none) and (pointer: coarse) {
	.quantity input[type="number"],
	input[type="text"],
	input[type="email"],
	input[type="tel"],
	input[type="password"],
	input[type="search"],
	input[type="number"],
	select,
	textarea,
	.woocommerce-ordering select,
	.facet__search,
	.pdp-buy .cuba-b2b-unit-selector__select,
	.pdp-buy .quantity .qty,
	.login-gate input.input-text,
	.login-gate .password-input input {
		font-size: 1rem;
	}
}

/*
 * Targets that a mouse hits comfortably and a thumb does not. Everything here
 * is a size change only — the paint, the spacing rhythm and the desktop
 * density are all left as designed, because the sidebar filters and the star
 * row are meant to read as compact on a large screen.
 */
@media (hover: none), (pointer: coarse) {
	/* 27px rows in a list eight or ten long: the neighbours are what get hit. */
	.facet__option {
		padding-block: var(--s-3);
	}

	/* 25px glyphs with a tenth of a rem between them. The box grows around the
	 * star without moving it, so the row still reads as five stars in a line. */
	.rating-stars__star {
		display: grid;
		place-items: center;
		min-width: 44px;
		min-height: 44px;
		padding: 0;
	}

	/* Dismissing a modal is the one control a buyer must always be able to
	 * hit, and it sits in the corner where the thumb is least accurate. */
	.modal__close {
		width: 44px;
		height: 44px;
		top: var(--s-3);
		right: var(--s-3);
	}

	/* A 13px native checkbox. The label is the target, so the row grows too. */
	.login-gate .woocommerce-form-login__rememberme {
		padding-block: var(--s-2);
	}

	.login-gate .woocommerce-form-login__rememberme input[type="checkbox"] {
		width: 1.25rem;
		height: 1.25rem;
		flex: 0 0 auto;
	}
}

/* --------------------------------------------------------------------------
   30. CONTACT
   --------------------------------------------------------------------------
   v2 — item 7. Address on the left, map on the right, stacked on a phone.
   The map keeps a fixed aspect so the row does not jump as the iframe loads.
   -------------------------------------------------------------------------- */

.contact {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
	gap: var(--grid-gap);
	align-items: start;
}

.contact__details > * + * {
	margin-block-start: var(--s-4);
}

/* The name reads as the heading of the address block below it — heavier and
 * in full ink, where the street sits at the body colour. The margin rule on
 * .contact__details spaces the block; this only has to change the voice. */
.contact__company {
	/* 18px against the 16px address: enough to lead the block, not so much
	 * that it competes with the section heading two lines above it. */
	font-size: var(--text-h4);
	font-weight: 500;
	line-height: 1.4;
	color: var(--ink);
	letter-spacing: 0.01em;
}

.contact__details > .contact__company + .contact__address {
	margin-block-start: var(--s-2);
}

.contact__address {
	font-style: normal;
	line-height: 1.7;
}

.contact__link {
	display: inline-block;
}

.contact__map {
	position: relative;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	border: 1px solid var(--panel-edge);
	background: var(--stone);
}

.contact__map iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
	display: block;
}

@media (max-width: 767px) {
	.contact {
		grid-template-columns: 1fr;
	}

	.contact__map {
		aspect-ratio: 4 / 3;
	}
}

/* Someone who has asked for less motion gets the panel, not the slide. */
@media (max-width: 1259px) and (prefers-reduced-motion: reduce) {
	.main-nav {
		transition: none;
	}
}
