/* ============================================================================
 * STRUXA — DESIGN SYSTEM
 * ---------------------------------------------------------------------------
 * One authoritative layer for type, spacing, material and motion.
 *
 * WHY THIS FILE EXISTS
 * The site had grown five parallel styling systems: WoodMart's own CSS, an
 * Elementor footer, a Tailwind Play-CDN layer, per-template inline <style>
 * blocks, and a handful of global !important rules in style.css. Nothing
 * agreed on a radius, a shadow, a gold, or a body size — which is what made
 * an otherwise well-photographed site read as assembled rather than designed.
 *
 * This file does not change the palette, the copy, the page structure or the
 * section order. It changes the *values* those sections are drawn with, and
 * it makes them agree.
 *
 * LOAD ORDER
 * Enqueued from functions.php at priority 9999 so it lands after WoodMart,
 * WooCommerce, Elementor and every per-page stylesheet. Because it wins on
 * order, it almost never needs !important; where WoodMart hard-codes a value
 * inline (a handful of places, all marked) it does.
 *
 * CONVENTIONS
 *   --s-*      surface ladder (black -> lifted)
 *   --t-*      text on dark        --ink-* text on cream
 *   --line-*   hairlines           --e-*    elevation
 *   --r-*      radius ladder       --sp-*   spacing ladder
 * ========================================================================= */

/* ==========================================================================
   1. TOKENS
   The palette is unchanged: gold #C5A059, cream #E3D7C8, ink #0D0D0D, black.
   Everything else here is derived from those four, or is neutral.
   ========================================================================== */

:root {
	/* ---- Brand (unchanged) ---- */
	--struxa-gold: #C5A059;
	--struxa-gold-hi: #D8BB83;	/* same hue, lifted — hover / active only */
	--struxa-gold-lo: #A98A48;	/* same hue, dropped — pressed / rules */
	--struxa-cream: #E3D7C8;
	--struxa-ink: #0D0D0D;

	/* ---- Surface ladder ----------------------------------------------
	 * Flat #000 everywhere is why cards used to need a gold border to be
	 * visible at all. A four-step near-black ladder lets a card separate
	 * from the page by *material* instead of by outline. */
	--s-0: #000000;
	--s-1: #07080A;
	--s-2: #0D0F11;
	--s-3: #14171A;
	--s-4: #1B1F23;
	--s-cream: #E3D7C8;
	--s-cream-2: #DACCB9;

	/* ---- Hairlines ----------------------------------------------------
	 * Apple's separators are light-on-dark at very low alpha, never a
	 * coloured outline. Gold is kept only for genuinely accented edges. */
	--line-1: rgba(255, 255, 255, 0.07);
	--line-2: rgba(255, 255, 255, 0.12);
	--line-3: rgba(255, 255, 255, 0.18);
	--line-gold: rgba(197, 160, 89, 0.30);
	--line-gold-strong: rgba(197, 160, 89, 0.55);
	--line-ink: rgba(13, 13, 13, 0.12);

	/* ---- Text on dark ---- */
	--t-1: rgba(255, 255, 255, 0.96);
	--t-2: rgba(255, 255, 255, 0.74);
	--t-3: rgba(255, 255, 255, 0.55);
	--t-4: rgba(255, 255, 255, 0.40);

	/* ---- Text on cream ---- */
	--ink-1: #0D0D0D;
	--ink-2: rgba(13, 13, 13, 0.74);
	--ink-3: rgba(13, 13, 13, 0.52);

	/* ---- Radius ladder -------------------------------------------------
	 * Apple's corners are large and consistent; a pill is a true pill
	 * (they literally ship 980px), not an arbitrary 30px. */
	--r-xs: 8px;
	--r-sm: 12px;
	--r-md: 14px;
	--r-lg: 16px;
	--r-xl: 22px;
	--r-2xl: 28px;
	--r-pill: 980px;

	/* ---- Elevation -----------------------------------------------------
	 * Layered, neutral, low-opacity. The half-pixel ring is the "material
	 * edge" that replaces a hard 1px border. Coloured glows are gone. */
	--e-1: 0 1px 2px rgba(0, 0, 0, 0.30), 0 0 0 0.5px rgba(255, 255, 255, 0.05);
	--e-2: 0 2px 6px rgba(0, 0, 0, 0.30), 0 10px 28px -14px rgba(0, 0, 0, 0.60), 0 0 0 0.5px rgba(255, 255, 255, 0.06);
	--e-3: 0 4px 12px rgba(0, 0, 0, 0.32), 0 20px 52px -20px rgba(0, 0, 0, 0.66), 0 0 0 0.5px rgba(255, 255, 255, 0.08);
	--e-4: 0 8px 24px rgba(0, 0, 0, 0.34), 0 36px 88px -30px rgba(0, 0, 0, 0.72), 0 0 0 0.5px rgba(255, 255, 255, 0.10);
	/* On cream, shadows have to be warm or they turn the section grey. */
	--e-cream-2: 0 2px 6px rgba(60, 46, 26, 0.08), 0 12px 32px -16px rgba(60, 46, 26, 0.18);
	--e-cream-3: 0 4px 14px rgba(60, 46, 26, 0.10), 0 24px 56px -22px rgba(60, 46, 26, 0.24);

	/* ---- Inner light ---------------------------------------------------
	 * The 1px top highlight that makes a dark surface read as a physical
	 * material catching light from above. Used on cards, bars and buttons. */
	--sheen: inset 0 1px 0 rgba(255, 255, 255, 0.07);
	--sheen-strong: inset 0 1px 0 rgba(255, 255, 255, 0.13);

	/* ---- Motion --------------------------------------------------------
	 * --ease-ui   interaction feedback (hover, press, open)
	 * --ease-out  entrances — the curve the site already used, kept so the
	 *             reveals still feel like this site
	 * --ease-soft cross-fades and colour */
	--ease-ui: cubic-bezier(0.32, 0.72, 0, 1);
	--ease-out: cubic-bezier(0.16, 1, 0.30, 1);
	--ease-soft: cubic-bezier(0.40, 0, 0.20, 1);
	--d-fast: 180ms;
	--d-base: 300ms;
	--d-slow: 520ms;
	--d-reveal: 820ms;

	/* ---- Spacing ladder ---- */
	--sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
	--sp-5: 20px;  --sp-6: 24px;  --sp-7: 28px;  --sp-8: 32px;  --sp-10: 40px;
	--sp-12: 48px; --sp-14: 56px; --sp-16: 64px; --sp-20: 80px;
	--sp-24: 96px; --sp-28: 112px; --sp-32: 128px; --sp-40: 160px;

	/* ---- Rhythm ---------------------------------------------------------
	 * Sections used to breathe at 64–96px, which is a content-site rhythm.
	 * A premium marketing page needs 120–160px at desktop and it has to
	 * scale continuously, not jump at one breakpoint. */
	--gutter: clamp(20px, 4.2vw, 48px);
	--section-y: clamp(76px, 9.5vw, 152px);
	--section-y-tight: clamp(56px, 6.5vw, 104px);
	--shell: 1240px;
	--shell-wide: 1440px;
	--measure: 66ch;

	/* ---- Glass ---- */
	--glass-blur: saturate(180%) blur(20px);
	--glass-blur-strong: saturate(180%) blur(30px);

	/* ---- Type ramp (fluid) ----------------------------------------------
	 * High contrast between display and body is the whole trick: the
	 * headline is genuinely large with negative tracking, the label is
	 * genuinely small with positive tracking, and there is very little in
	 * between. Line heights tighten as size grows. */
	--fs-display: clamp(2.75rem, 6.6vw, 6rem);
	--fs-h1: clamp(2.25rem, 4.4vw, 4rem);
	--fs-h2: clamp(1.875rem, 3.3vw, 2.875rem);
	--fs-h3: clamp(1.5rem, 2.1vw, 2rem);
	--fs-h4: clamp(1.1875rem, 1.45vw, 1.4375rem);
	--fs-lede: clamp(1.0625rem, 1.2vw, 1.3125rem);
	--fs-body: 1.0625rem;	/* 17px — Apple's reading size */
	--fs-sm: 0.9375rem;	/* 15px */
	--fs-cap: 0.8125rem;	/* 13px */
	--fs-eyebrow: 0.6875rem;	/* 11px */

	--lh-display: 0.98;
	--lh-head: 1.08;
	--lh-sub: 1.22;
	--lh-body: 1.62;

	--tr-display: -0.028em;
	--tr-head: -0.021em;
	--tr-sub: -0.012em;
	--tr-body: -0.011em;
	--tr-label: 0.3em;	/* was 0.5em — see §2 */

	--font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
	--font-display: "Cormorant Garamond", "Iowan Old Style", "Palatino Linotype", ui-serif, Georgia, serif;
}

/* ==========================================================================
   2. TYPOGRAPHY — the foundation
   --------------------------------------------------------------------------
   THE BUG THIS FIXES
   style.css carried two global rules with !important:
       p, span            { font-family:'Arboria-Book', sans-serif !important }
       h1,h2,h3,h4,h5,h6  { font-family:'Poppins',      sans-serif !important }
   Arboria-Book's @font-face pointed at ../fonts/ — one directory above the
   child theme — so the file 404'd and every paragraph on the site fell back
   to the browser's generic sans (Arial on Windows). And the !important on
   the heading rule beat every .font-serif in the design, so Cormorant
   Garamond — the brand's display face — never rendered once, anywhere.
   Verified in the live DOM: .font-serif computed to "Poppins, sans-serif".

   Those rules are removed in style.css. This section is what replaces them.
   ========================================================================== */

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

/* WoodMart drives its own typography through six custom properties set on
   :root from Theme Settings, and its component rules read those properties
   rather than a literal font name. Overriding `body` alone therefore leaves
   product titles, widget titles, tab labels and header elements on whatever
   the theme settings happen to say (Quicksand, on this install).
   Repointing the properties themselves is what makes the WooCommerce and
   WoodMart chrome speak the same type as the marketing pages — and it means
   the Theme Settings panel stays the single place to change it back. */
:root {
	--wd-text-font: var(--font-ui);
	--wd-title-font: var(--font-ui);
	--wd-entities-title-font: var(--font-ui);
	--wd-widget-title-font: var(--font-ui);
	--wd-header-el-font: var(--font-ui);
	--wd-alternative-font: var(--font-display);
}

body,
.wd-page-content,
.wd-entry-content {
	font-family: var(--font-ui);
	font-size: var(--fs-body);
	line-height: var(--lh-body);
	letter-spacing: var(--tr-body);
	font-weight: 400;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-optical-sizing: auto;
	/* Proportional lining figures + real quotes/ligatures. Tabular numerals
	   are switched on locally for prices and stats, where columns matter. */
	font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "cv11" 1;
	font-variant-numeric: proportional-nums;
}

/* Paragraphs get a measure and the browser's better ragging. No global
   font-family here — inheriting from body is what lets a cream section or a
   card override the face in one place. */
p {
	font-family: inherit;
	text-wrap: pretty;
}

/* --- Display faces -------------------------------------------------------
 * Every heading that the Struxa design intends to be serif. Listed
 * explicitly rather than as a blanket h1-h6 rule, so WoodMart's and
 * WooCommerce's own UI headings (widget titles, tab labels, cart headings)
 * stay in the UI face where a serif would look accidental. */
.font-serif,
.struxa-tw :where(h1, h2, h3),
.masthead__title,
.tile-title,
.svc-title,
.value-card h4,
.team-name,
.plan-title,
.shop-card h3,
.woocommerce-products-header__title,
.product_title.entry-title,
.wd-page-content .page-title {
	font-family: var(--font-display);
	font-weight: 500;
	letter-spacing: var(--tr-head);
	line-height: var(--lh-head);
	text-wrap: balance;
	font-synthesis-weight: none;
}

/* Size + optical tracking per level. Tracking tightens as size grows —
   this is the single detail that separates a set headline from a scaled
   one, and it is what Apple's marketing type does at every step. */
/* SPECIFICITY NOTE — why :where() is used for the element selectors here.
 *
 * `.struxa-tw h2` is specificity (0,1,1). A component rule further down
 * this file like `.tile-title { font-size: … }` is (0,1,0) — LOWER — so the
 * generic heading size would keep beating the specific one, and every card
 * title on the site would silently take the section-heading size instead of
 * its own. (The masthead headline hit exactly this: it was setting at the
 * page-headline size rather than the display size.)
 *
 * :where() contributes zero specificity, so these generic rules land at
 * (0,1,0) — the same weight as a component class — and the component rule
 * wins on source order, which is what "a default underneath" should mean.
 * Do not drop the :where(). */
.struxa-tw :where(h1):not(.masthead__title) {
	font-size: var(--fs-h1);
	line-height: var(--lh-display);
	letter-spacing: var(--tr-display);
}

/* The hero headline. The largest type on the site by a clear margin —
   high typographic contrast is the whole trick, and it only reads as
   deliberate if nothing else comes close. */
.struxa-tw .masthead__title,
.masthead__title {
	font-size: var(--fs-display);
	font-weight: 500;
	line-height: var(--lh-display);
	letter-spacing: var(--tr-display);
}

.struxa-tw :where(h2) {
	font-size: var(--fs-h2);
	letter-spacing: var(--tr-head);
}

.struxa-tw :where(h3) {
	font-size: var(--fs-h3);
	line-height: var(--lh-sub);
	letter-spacing: var(--tr-sub);
}

.struxa-tw :where(h4, h5, h6) {
	font-family: var(--font-ui);
	font-weight: 550;
	letter-spacing: var(--tr-sub);
	line-height: var(--lh-sub);
}

/* Where a template has already chosen an explicit size utility
   (text-2xl, md:text-5xl, …) that utility still wins — it is defined later
   in the cascade inside struxa-tw.css. These are the defaults underneath. */

/* --- Lede ---------------------------------------------------------------
 * The sentence under a headline. It is not body copy and should not be set
 * at body size; one clear step up, lighter colour, wider measure. */
.masthead__lede,
.struxa-lede {
	font-size: var(--fs-lede);
	line-height: 1.55;
	letter-spacing: var(--tr-sub);
	color: var(--t-2);
	max-width: 58ch;
	text-wrap: pretty;
}

/* --- Eyebrow / label ----------------------------------------------------
 * The small gold uppercase line above most headings.
 *
 * It was set at 10px with 0.5em tracking. Half an em is roughly double
 * what any typographer would use for a caps line: the word stops reading
 * as a word and becomes a row of letters, and at 10px it is below the size
 * where that is legible at arm's length. Moderated — not removed, because
 * the wide caps line *is* part of this brand's voice — to 11px / 0.3em,
 * with a weight bump so it holds colour against the photography. */
.struxa-tw .tracking-\[0\.5em\],
.struxa-tw .sm\:tracking-\[0\.5em\],
.tile-eyebrow,
.svc-eyebrow,
.struxa-eyebrow {
	letter-spacing: var(--tr-label);
	font-weight: 500;
	font-feature-settings: "kern" 1, "liga" 1, "cpsp" 1;
}

.struxa-tw .text-\[10px\] {
	font-size: var(--fs-eyebrow);
}

/* A caps line's trailing letter-space pushes centred text off-centre by
   half its tracking. Standard fix, applied wherever the label is centred. */
.text-center .tracking-\[0\.5em\],
.text-center .tracking-\[0\.4em\],
.text-center .tracking-\[0\.3em\],
.struxa-eyebrow.text-center {
	text-indent: var(--tr-label);
}

/* --- Numerals -----------------------------------------------------------
 * Prices, stats and counters use tabular figures so digits line up in a
 * column and a changing number doesn't shift the layout beside it. */
.price,
.amount,
.woocommerce-Price-amount,
[data-stat],
.shop-price,
.masthead__proof,
.plan-readout {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1, "kern" 1;
}

/* Cormorant Garamond ships OLD-STYLE figures by default, so "100%" set in
   the display face came out as a row of x-height zeros with a full-height
   1 — correct for running prose, wrong for a statistic, where the number
   IS the thing being read. Lining figures for anything set large in the
   display face; prose keeps the old-style default. */
[data-stat],
.bg-cream [data-stat],
.font-serif .price,
.single-product .summary .price {
	font-variant-numeric: lining-nums tabular-nums;
	font-feature-settings: "lnum" 1, "tnum" 1, "kern" 1;
}

/* --- Selection ---- */
::selection { background: var(--struxa-gold); color: var(--struxa-ink); }
::-moz-selection { background: var(--struxa-gold); color: var(--struxa-ink); }

/* ==========================================================================
   3. RHYTHM — whitespace, gutters, measure
   --------------------------------------------------------------------------
   Sections were padded at py-16/py-24 (64px / 96px) with a flat px-6 (24px)
   gutter at every width. On a 1440px screen that reads as a content page,
   not a product page: the content touches the edges and the sections run
   into each other. Both now scale continuously with the viewport.
   ========================================================================== */

/* Side gutter. Applied to the shells the Struxa templates actually use, so
   it cannot leak into WooCommerce's own containers. */
.struxa-tw .max-w-7xl,
.struxa-tw .max-w-6xl,
.struxa-tw .max-w-5xl,
.struxa-tw .max-w-4xl,
.struxa-tw .max-w-3xl,
.struxa-tw .max-w-\[1400px\],
.struxa-tw .max-w-\[87\.5rem\] {
	padding-left: max(var(--gutter), env(safe-area-inset-left));
	padding-right: max(var(--gutter), env(safe-area-inset-right));
}

/* …which means the px-6 those wrappers already carry would double up. */
.struxa-tw .max-w-7xl.px-6,
.struxa-tw .max-w-6xl.px-6,
.struxa-tw .max-w-5xl.px-6,
.struxa-tw .max-w-4xl.px-6,
.struxa-tw .max-w-3xl.px-6,
.struxa-tw .max-w-\[1400px\].px-6,
.struxa-tw .max-w-\[87\.5rem\].px-6 {
	padding-left: max(var(--gutter), env(safe-area-inset-left));
	padding-right: max(var(--gutter), env(safe-area-inset-right));
}

/* Vertical rhythm. Every section-level padding utility maps onto one of two
   fluid values, so the page has one rhythm instead of eight. */
.struxa-tw section.py-16,
.struxa-tw section.py-20,
.struxa-tw section.py-24,
.struxa-tw section.py-28 {
	padding-top: var(--section-y);
	padding-bottom: var(--section-y);
}

.struxa-tw section.py-10,
.struxa-tw section.py-12 {
	padding-top: var(--section-y-tight);
	padding-bottom: var(--section-y-tight);
}

.struxa-tw section.pt-24 { padding-top: var(--section-y); }
.struxa-tw section.pb-20,
.struxa-tw section.pb-24 { padding-bottom: var(--section-y); }

/* The breakpoint variants that used to step these up are now redundant —
   the clamp already covers the range — and if left alone they would undo
   the fluid value at 768px. Neutralised for sections only. */
/* min-width blocks are cumulative, so they go smallest first — at 1200px
   all three are live and source order is the only tie-break. */
@media (min-width: 640px) {
	.struxa-tw section.sm\:py-16,
	.struxa-tw section.sm\:py-24 {
		padding-top: var(--section-y);
		padding-bottom: var(--section-y);
	}
}

@media (min-width: 768px) {
	.struxa-tw section.md\:py-24,
	.struxa-tw section.md\:py-28 {
		padding-top: var(--section-y);
		padding-bottom: var(--section-y);
	}
	.struxa-tw section.md\:pb-24 { padding-bottom: var(--section-y); }
}

/* Section headers: the eyebrow / headline / sub block that opens most
   sections. Tightens the eyebrow-to-headline gap (they belong together)
   and opens the headline-to-content gap (they do not). */
.struxa-tw section > .text-center.mb-10,
.struxa-tw section > * > .text-center.mb-10,
.struxa-tw section > .text-center.mb-14,
.struxa-tw section > * > .text-center.mb-14 {
	margin-bottom: clamp(40px, 5vw, 72px);
}

.struxa-tw .text-center > .tracking-\[0\.5em\] + h2,
.struxa-tw .text-center > .tracking-\[0\.5em\] + h1 {
	margin-top: var(--sp-4);
}

/* Reading measure. A 15px line running the full width of a 1240px shell is
   ~140 characters; nothing reads comfortably past ~75. */
.struxa-tw p:not([class*="max-w"]):not(.tile-desc):not(.svc-desc) {
	max-width: var(--measure);
}

.struxa-tw .text-center p:not([class*="max-w"]) {
	margin-left: auto;
	margin-right: auto;
}

/* ==========================================================================
   4. MATERIAL — surfaces, hairlines, glass
   --------------------------------------------------------------------------
   The old vocabulary was "1px solid rgba(197,160,89,.16)" plus a gold glow
   on hover. A gold outline on every card makes the gold meaningless — by
   the time it reaches a button it is no longer an accent. Cards now
   separate by surface and a neutral edge; gold is reserved for action.
   ========================================================================== */

.struxa-surface {
	background: var(--s-2);
	border-radius: var(--r-lg);
	box-shadow: var(--e-2), var(--sheen);
}

.struxa-glass {
	background: rgba(20, 23, 26, 0.62);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--e-2), var(--sheen-strong);
}

/* Gold hairlines are demoted to neutral wherever they were used as plain
   structure (section rules, grid dividers) rather than as emphasis. */
.struxa-tw .border-gold\/15,
.struxa-tw .border-gold\/25 {
	border-color: var(--line-1);
}

.struxa-tw .border-white\/5,
.struxa-tw .border-white\/10 { border-color: var(--line-1); }
.struxa-tw .border-white\/15,
.struxa-tw .border-white\/20 { border-color: var(--line-2); }
.struxa-tw .border-white\/25,
.struxa-tw .border-white\/30 { border-color: var(--line-3); }
.struxa-tw .border-ink\/15 { border-color: var(--line-ink); }

/* A hairline should be a hairline. On a 2x display a 1px border is two
   device pixels and reads as a drawn line; 0.5px reads as a seam. */
@media (min-resolution: 2dppx) {
	.struxa-tw .border-t,
	.struxa-tw .border-b,
	.struxa-tw .divide-y > * + * {
		border-top-width: 0.5px;
		border-bottom-width: 0.5px;
	}
}

/* The homepage inline stylesheet hijacked the bare .border utility
   (background:transparent; border-radius:0; border:1px solid !important).
   That made every bordered element on the page square and hard-edged,
   including ones that should be neither. Restored to a real utility. */
.struxa-tw .border {
	border-width: 1px;
	border-style: solid;
	border-color: var(--line-1);
	border-radius: inherit;
	background: transparent;
}

/* ==========================================================================
   5. HEADER & NAVIGATION
   --------------------------------------------------------------------------
   The header is two stacked WoodMart rows: a dark bar with the logo, and a
   glass bar with the menu. The structure is kept — only the material, the
   type and the scrolled state change.

   The previous version applied a full-strength blur plus five stacked
   highlight layers from the first pixel of scroll. Apple's chrome is thin,
   and its material only densifies once there is content behind it.
   ========================================================================== */

/* Logo row — a plain dark bar, no gradient. A vertical gradient across a
   60px strip reads as a rendering artefact, not as depth. */
.whb-header .whb-general-header {
	background: rgba(8, 9, 10, 0.92) !important;
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: none;
	border-bottom: 1px solid var(--line-1);
	transition: background-color var(--d-base) var(--ease-soft);
}

/* Menu row — the glass bar. Kept, but calmed: one translucent base, one
   material blur, one hairline. The old version stacked a white gradient, a
   ::before white gradient, an inset highlight, a drop shadow and two
   borders onto a 48px strip. */
.whb-header .whb-header-bottom {
	position: relative;
	background: rgba(13, 15, 17, 0.58) !important;
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	border-top: 1px solid var(--line-1);
	border-bottom: 1px solid var(--line-1) !important;
	box-shadow: var(--sheen);
	transition: background-color var(--d-base) var(--ease-soft);
}

/* One highlight, fading out at both ends so it reads as a lit edge rather
   than a drawn line. */
.whb-header .whb-header-bottom::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 1px;
	background: linear-gradient(to right,
		rgba(255, 255, 255, 0) 0%,
		rgba(255, 255, 255, 0.10) 22%,
		rgba(255, 255, 255, 0.10) 78%,
		rgba(255, 255, 255, 0) 100%);
	pointer-events: none;
}

/* Once WoodMart's own sticky class lands, the bar densifies: more opaque,
   stronger blur, a real shadow. That is the moment the chrome separates
   from the page — and the only moment it should. */
.whb-header.whb-sticked .whb-general-header,
.whb-header.whb-sticked .whb-header-bottom {
	background: rgba(8, 9, 10, 0.82) !important;
	-webkit-backdrop-filter: var(--glass-blur-strong);
	backdrop-filter: var(--glass-blur-strong);
}

.whb-header.whb-sticked {
	box-shadow: 0 1px 0 var(--line-1), 0 12px 32px -20px rgba(0, 0, 0, 0.8);
}

/* --- Nav links ----------------------------------------------------------
 * Were uppercase at wide tracking in Poppins, with colour as the only hover
 * signal. Now a real UI face at a readable size, with a hit target that
 * meets the 44px minimum and a pill that fills on hover. */
.whb-header .woodmart-nav-link,
.whb-header .wd-nav > li > a {
	position: relative;
	font-family: var(--font-ui);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	color: var(--t-2) !important;
	border-radius: var(--r-pill);
	transition: color var(--d-fast) var(--ease-soft),
	            background-color var(--d-fast) var(--ease-soft);
}

.whb-header .whb-header-bottom .wd-nav > li > a {
	padding-inline: var(--sp-4);
}

.whb-header .whb-header-bottom .menu-item:hover > .woodmart-nav-link,
.whb-header .whb-header-bottom .menu-item:focus-within > .woodmart-nav-link {
	color: var(--t-1) !important;
	background-color: rgba(255, 255, 255, 0.06);
}

/* Current page: gold text plus a short gold rule. Colour alone at 13px is a
   weak signal, and it is no signal at all for anyone who reads gold-on-dark
   as low contrast. */
.whb-header .whb-header-bottom .current-menu-item > .woodmart-nav-link,
.whb-header .whb-header-bottom .current_page_item > .woodmart-nav-link {
	color: var(--struxa-gold) !important;
}

.whb-header .whb-header-bottom .current-menu-item > .woodmart-nav-link::after,
.whb-header .whb-header-bottom .current_page_item > .woodmart-nav-link::after {
	content: "";
	position: absolute;
	left: var(--sp-4);
	right: var(--sp-4);
	bottom: 8px;
	height: 1.5px;
	border-radius: var(--r-pill);
	background: var(--struxa-gold);
}

/* Header icon buttons (search, account, cart, mobile menu) — one shape. */
.whb-header .wd-tools-element > a {
	border-radius: var(--r-pill);
	transition: background-color var(--d-fast) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft);
}

.whb-header .wd-tools-element > a:hover {
	background-color: rgba(255, 255, 255, 0.06);
	color: var(--t-1);
}

/* Cart count — a proper badge, ringed against the bar behind it. */
.whb-header .wd-cart-number {
	background: var(--struxa-gold) !important;
	color: var(--struxa-ink) !important;
	font-family: var(--font-ui);
	font-size: 10px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	border-radius: var(--r-pill);
	box-shadow: 0 0 0 2px var(--s-1);
}

/* Mobile menu panel.
 *
 * NO backdrop-filter here, deliberately — an earlier version had one and it
 * was a mistake.
 *
 * This panel is full height, position:fixed, and WoodMart opens it by
 * transitioning `transform` over 500ms. A 30px backdrop blur on an element
 * that size means the phone has to re-sample and re-blur everything behind
 * it on every frame of that animation. On a mid-range handset that is enough
 * to drop the animation to a crawl or skip it altogether — which from the
 * visitor's side looks exactly like "I tapped the menu and nothing
 * happened". The panel is 94% opaque anyway, so the blur was buying a few
 * pixels of translucency at the edges and nothing else.
 *
 * If this ever gets a blur again, put it on a non-animating child, never on
 * the element carrying the transform. */
.wd-side-hidden {
	background: rgba(8, 9, 10, 0.97) !important;
	border-right: 1px solid var(--line-1);
	/* Hand the panel its own layer up front so the slide is composited
	   rather than repainted. */
	will-change: transform;
}

.wd-side-hidden .wd-nav-mobile > li > a {
	font-family: var(--font-ui);
	font-size: 1.0625rem;
	font-weight: 500;
	letter-spacing: var(--tr-body);
	padding-block: var(--sp-4);
	border-bottom: 1px solid var(--line-1);
}

/* --- Search inside the mobile menu --------------------------------------
 *
 * The panel is 340px. The field sits at 339px with 16px of padding each
 * side, and the submit button is position:absolute at right:0 and 56px
 * wide — so it lies ON TOP of the last 56px of the field. The placeholder
 * and anything typed both ran underneath the magnifier.
 *
 * Two separate problems, two fixes:
 *
 * 1. Reserve the button's width as padding, so typed text can never slide
 *    under the icon. This is the one that actually matters — it was
 *    affecting real input, not just the placeholder.
 * 2. Drop the visible placeholder. "Search for projects" needs more room
 *    than this panel has, and a magnifier in an empty field says the same
 *    thing without the text. The input keeps its aria-label="Search", so
 *    screen readers are unaffected — this hides the text, it does not
 *    remove the label.
 *
 * Scoped to the panel: the header's own search field has the full width of
 * the page and keeps its placeholder. */
.wd-side-hidden .searchform input.s,
.wd-side-hidden .wd-search-form input[type="text"] {
	padding-right: 60px !important;
	text-overflow: ellipsis;
}

.wd-side-hidden .searchform input.s::placeholder,
.wd-side-hidden .wd-search-form input[type="text"]::placeholder {
	color: transparent;
}

/* The magnifier is the only affordance left, so it has to read clearly. */
.wd-side-hidden .searchform button.searchsubmit {
	color: var(--t-2);
	transition: color var(--d-fast) var(--ease-soft);
}

.wd-side-hidden .searchform button.searchsubmit:hover,
.wd-side-hidden .searchform input.s:focus ~ button.searchsubmit {
	color: var(--struxa-gold);
}

/* WoodMart's floating sidebar opener has no sidebar to open on the Struxa
   templates, and its fixed mobile toolbar overlays content. Both were being
   hidden per page; hidden site-wide here instead. */
.wd-sidebar-opener,
.wd-toolbar { display: none !important; }

/* ==========================================================================
   6. BUTTONS
   --------------------------------------------------------------------------
   Five button shapes existed side by side: a gold pill, a glass pill, a
   square .border outline, a 30px-radius WooCommerce pill and a 10px-radius
   add-to-cart. One system now — three variants, one geometry.

   Apple's buttons are not uppercase and not tracked out: the label reads as
   a word, at reading size, in the UI face. The shape carries the emphasis.
   ========================================================================== */

.struxa-btn,
.masthead__cta,
.tile-cta,
.lg-btn,
.plan-cta {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-2);
	min-height: 44px;
	padding: 0 var(--sp-6);
	border: 0;
	border-radius: var(--r-pill);
	font-family: var(--font-ui);
	font-size: 0.9375rem;
	font-weight: 550;
	letter-spacing: -0.008em;
	text-transform: none;
	white-space: nowrap;
	cursor: pointer;
	isolation: isolate;
	-webkit-tap-highlight-color: transparent;
	transition: transform var(--d-fast) var(--ease-ui),
	            background-color var(--d-fast) var(--ease-soft),
	            box-shadow var(--d-base) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft);
}

.struxa-btn:active,
.masthead__cta:active,
.lg-btn:active,
.tile-cta:active,
.plan-cta:active {
	transform: scale(0.97);
	transition-duration: 80ms;
}

/* --- Primary: gold fill ------------------------------------------------- */
.struxa-btn--primary,
.masthead__cta,
.tile-cta {
	background: var(--struxa-gold);
	color: var(--struxa-ink);
	box-shadow: var(--e-1), inset 0 1px 0 rgba(255, 255, 255, 0.24);
}

.struxa-btn--primary:hover,
.masthead__cta:hover,
.collection-tile:hover .tile-cta {
	background: var(--struxa-gold-hi);
	color: var(--struxa-ink);
	transform: translateY(-1px);
	box-shadow: var(--e-2), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

/* The hero CTA used to lift 2px and throw a 38px gold glow on hover. The
   lift stays, at 1px — enough to register, not enough to look detached. */
.masthead__cta {
	padding: 0 var(--sp-8);
	min-height: 52px;
	font-size: 1rem;
}

.masthead__cta:hover {
	box-shadow: var(--e-3), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

/* --- Secondary: glass ---------------------------------------------------
 * The liquid-glass button stays — it is a signature of this site and it
 * belongs on photography. What goes is the SVG turbulence displacement
 * layer: it is a no-op in Chrome and Edge, so most visitors never saw it,
 * and where it does run it warps the backdrop enough to read as a glitch.
 * Replaced with the material Apple actually ships: blur, saturation, and a
 * rim that is bright at the top and dim at the bottom. */
.lg-btn {
	min-height: 52px;
	padding: 0 var(--sp-8);
	font-size: 1rem;
	color: var(--t-1);
}

.lg-btn__glass {
	background: rgba(255, 255, 255, 0.10);
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
}

/* Neutralised rather than removed — the markup still ships the layer, so
   nothing has to change in nine templates for this to take effect. */
.lg-btn__distort {
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}

.lg-btn__rim {
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.34),
		inset 0 -1px 0 rgba(255, 255, 255, 0.08),
		inset 0 0 0 1px rgba(255, 255, 255, 0.12),
		0 1px 2px rgba(0, 0, 0, 0.24);
}

.lg-btn:hover {
	transform: translateY(-1px);
	box-shadow: var(--e-2);
}

.lg-btn:hover .lg-btn__glass { background: rgba(255, 255, 255, 0.16); }

.lg-btn__label {
	font-size: inherit;
	font-weight: inherit;
	letter-spacing: inherit;
	text-transform: none;
	gap: var(--sp-2);
}

.lg-btn--ghost .lg-btn__glass { background: rgba(197, 160, 89, 0.10); }
.lg-btn--ghost .lg-btn__label { color: var(--struxa-gold); }
.lg-btn--ghost:hover .lg-btn__glass { background: rgba(197, 160, 89, 0.18); }
.lg-btn--ghost:hover .lg-btn__label { color: var(--t-1); }

.lg-btn--ghost .lg-btn__rim {
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.16),
		inset 0 0 0 1px var(--line-gold),
		0 1px 2px rgba(0, 0, 0, 0.2);
}

/* --- Tertiary: quiet ---------------------------------------------------- */
.struxa-btn--quiet {
	background: rgba(255, 255, 255, 0.06);
	color: var(--t-1);
	box-shadow: inset 0 0 0 1px var(--line-1);
}

.struxa-btn--quiet:hover {
	background: rgba(255, 255, 255, 0.11);
	transform: translateY(-1px);
}

/* Arrow glyphs travel 2px, once, on the parent's hover — not 3px on their
   own transition with a different duration, which is what made the old
   buttons feel like two elements moving separately. */
.struxa-btn svg,
.masthead__cta svg,
.lg-btn svg,
.cta-arrow,
.lg-btn__label span {
	transition: transform var(--d-base) var(--ease-ui);
}

.struxa-btn:hover svg,
.masthead__cta:hover svg,
.lg-btn:hover svg,
.lg-btn:hover .lg-btn__label span,
.collection-tile:hover .cta-arrow {
	transform: translateX(2px);
}

/* ==========================================================================
   7. CARDS
   --------------------------------------------------------------------------
   Every card type now shares one geometry — radius, padding, edge, lift —
   so a page of mixed components reads as one grid of one material.

   What changes across all of them: the 1px gold outline becomes a surface
   plus a neutral material edge, and the gold drop-glow on hover becomes a
   neutral elevation with a gold rim. A gold outline on every card is what
   made gold stop meaning anything by the time it reached a button.
   ========================================================================== */

/* --- Collection tiles (homepage) ---------------------------------------- */
.collection-grid {
	gap: clamp(12px, 1.4vw, 20px);
}

.collection-tile {
	border-radius: var(--r-lg);
	border: 0;
	background: var(--s-2);
	box-shadow: var(--e-2);
	transition:
		opacity var(--d-reveal) var(--ease-out),
		transform var(--d-slow) var(--ease-ui),
		box-shadow var(--d-slow) var(--ease-soft);
}

.collection-tile:hover,
.collection-tile:focus-visible {
	border-color: transparent;
	transform: translateY(-3px);
	box-shadow: var(--e-4), inset 0 0 0 1px var(--line-gold);
}

/* The tile photograph sat at brightness(.82) saturate(.95) — dark enough to
   grey the subject out, but flat enough that a bright patch (the LED-wall
   tile, the blueprint banner) still swallowed the title. Contrast is the
   scrim's job now, so the photograph can stay closer to a photograph. */
.tile-img {
	filter: brightness(0.88) saturate(1.02);
	transition: transform 900ms var(--ease-ui), filter var(--d-slow) var(--ease-soft);
}

.collection-tile:hover .tile-img,
.collection-tile:focus-visible .tile-img {
	transform: scale(1.04);
	filter: brightness(0.7) saturate(1.04);
}

/* Two gradients, not one.
   - A bottom-up ramp, six stops rather than three: three stops over a
     photograph bands visibly, a six-stop ramp reads as light falling off.
   - A left-to-right wash, the same trick the masthead uses, so the column
     the type actually occupies is guaranteed dark no matter what the
     photograph is doing. Without it, a title sitting over a bright subject
     (the LED wall, the lit blueprint) is legible only by luck. */
.tile-scrim {
	background:
		linear-gradient(to top,
			rgba(0, 0, 0, 0.90) 0%,
			rgba(0, 0, 0, 0.76) 14%,
			rgba(0, 0, 0, 0.50) 34%,
			rgba(0, 0, 0, 0.24) 55%,
			rgba(0, 0, 0, 0.07) 76%,
			rgba(0, 0, 0, 0) 100%),
		linear-gradient(to right,
			rgba(0, 0, 0, 0.55) 0%,
			rgba(0, 0, 0, 0.28) 45%,
			rgba(0, 0, 0, 0) 80%);
}

@media (hover: hover) and (pointer: fine) {
	/* At rest on desktop only the title shows, so the ramp can sit lower —
	   but the left wash stays, because that is what is holding the title. */
	.tile-scrim {
		background:
			linear-gradient(to top,
				rgba(0, 0, 0, 0.84) 0%,
				rgba(0, 0, 0, 0.64) 18%,
				rgba(0, 0, 0, 0.34) 42%,
				rgba(0, 0, 0, 0.10) 68%,
				rgba(0, 0, 0, 0) 100%),
			linear-gradient(to right,
				rgba(0, 0, 0, 0.50) 0%,
				rgba(0, 0, 0, 0.24) 45%,
				rgba(0, 0, 0, 0) 80%);
	}
	.collection-tile:hover .tile-scrim,
	.collection-tile:focus-visible .tile-scrim {
		background:
			linear-gradient(to top,
				rgba(0, 0, 0, 0.93) 0%,
				rgba(0, 0, 0, 0.82) 20%,
				rgba(0, 0, 0, 0.58) 46%,
				rgba(0, 0, 0, 0.26) 72%,
				rgba(0, 0, 0, 0.08) 100%),
			linear-gradient(to right,
				rgba(0, 0, 0, 0.45) 0%,
				rgba(0, 0, 0, 0.20) 50%,
				rgba(0, 0, 0, 0) 85%);
	}
}

/* The wide services banner is short, so its content sits high in the box
   where a bottom-up ramp has barely started. It gets a heavier left wash
   instead — the type is left-aligned there, and the right two thirds of
   the photograph stay clear. */
.collection-banner .tile-scrim,
.collection-banner:hover .tile-scrim {
	background: linear-gradient(to right,
		rgba(0, 0, 0, 0.86) 0%,
		rgba(0, 0, 0, 0.70) 24%,
		rgba(0, 0, 0, 0.40) 48%,
		rgba(0, 0, 0, 0.12) 74%,
		rgba(0, 0, 0, 0) 100%);
}

.tile-base { padding: clamp(18px, 2vw, 30px); }

.tile-number {
	font-family: var(--font-ui);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.22em;
	color: rgba(255, 255, 255, 0.55);
	top: clamp(16px, 1.8vw, 26px);
	left: clamp(18px, 2vw, 30px);
	/* Four independent infinite opacity loops were repainting behind static
	   content on every homepage load, for a decorative pulse. */
	animation: none;
	opacity: 1;
}

.tile-eyebrow {
	font-size: var(--fs-eyebrow);
	letter-spacing: 0.24em;
	color: var(--struxa-gold);
	margin-bottom: var(--sp-2);
}

.tile-title {
	font-size: clamp(1.25rem, 1.7vw, 1.75rem);
	font-weight: 500;
	letter-spacing: var(--tr-sub);
	line-height: 1.14;
}

.tile-desc {
	font-size: var(--fs-sm);
	line-height: 1.52;
	color: var(--t-2);
	margin-top: var(--sp-3);
}

.tile-cta {
	min-height: 40px;
	font-size: 0.875rem;
	margin-top: var(--sp-5);
	padding: 0 var(--sp-5);
}

/* The "Ken Burns" ambient zoom ran on all four tiles, forever, waiting for
   a hover payoff a touch screen never delivers. */
.tile-media { animation: none; }

@media (max-width: 639px) {
	/* Tiles are half-width here, so the desktop title size runs to three
	   lines and fills the card. One step down, tighter leading. */
	.tile-title { font-size: 1.0625rem; line-height: 1.2; }
	.tile-base { padding: 14px; }
	.tile-number { top: 12px; left: 14px; font-size: 0.625rem; }
	.tile-eyebrow { font-size: 0.625rem; letter-spacing: 0.18em; }

	/* The pill has no room for its label beside two other controls — it
	   becomes the arrow alone, still a full 36px target. */
	.tile-cta {
		width: 36px;
		height: 36px;
		min-height: 36px;
		padding: 0;
	}

	/* The wide services banner keeps the full title: it has the whole
	   width to itself. */
	.collection-banner .tile-title { font-size: 1.25rem; }
}

/* --- Service cards ------------------------------------------------------ */
.svc-card {
	border: 0;
	border-radius: var(--r-lg);
	background: var(--s-2);
	box-shadow: var(--e-2);
	transition: transform var(--d-slow) var(--ease-ui),
	            box-shadow var(--d-slow) var(--ease-soft);
}

.svc-card:hover,
.svc-card:focus-within {
	transform: translateY(-3px);
	box-shadow: var(--e-4), inset 0 0 0 1px var(--line-gold);
	border-color: transparent;
}

.svc-img {
	filter: brightness(0.86) saturate(1);
	transition: transform 900ms var(--ease-ui), filter var(--d-slow) var(--ease-soft);
}

.svc-card:hover .svc-img,
.svc-card:focus-within .svc-img {
	transform: scale(1.04);
	filter: brightness(0.64) saturate(1.03);
}

.svc-scrim {
	background: linear-gradient(to top,
		rgba(0, 0, 0, 0.90) 0%,
		rgba(0, 0, 0, 0.72) 16%,
		rgba(0, 0, 0, 0.44) 38%,
		rgba(0, 0, 0, 0.16) 62%,
		rgba(0, 0, 0, 0) 100%);
}

.svc-body { padding: clamp(18px, 2vw, 30px); }

.svc-num {
	font-family: var(--font-ui);
	font-size: 0.6875rem;
	letter-spacing: 0.22em;
	color: rgba(255, 255, 255, 0.55);
}

.svc-eyebrow {
	font-size: var(--fs-eyebrow);
	letter-spacing: 0.24em;
	color: var(--struxa-gold);
}

.svc-title {
	font-size: clamp(1.25rem, 1.7vw, 1.75rem);
	font-weight: 500;
	line-height: 1.14;
	letter-spacing: var(--tr-sub);
}

.svc-desc {
	font-size: var(--fs-sm);
	line-height: 1.52;
	color: var(--t-2);
}

/* --- Value cards (Design. Build. Inspire.) ------------------------------ */
.value-card {
	border-color: var(--line-1) !important;
	transition: background-color var(--d-slow) var(--ease-soft);
}

.value-card h4 {
	font-family: var(--font-display);
	font-size: clamp(1.25rem, 1.6vw, 1.625rem);
	font-weight: 500;
	letter-spacing: var(--tr-sub);
	line-height: 1.16;
}

.value-card .card-desc p {
	font-size: var(--fs-sm);
	line-height: 1.55;
	color: var(--t-2);
}

/* --- Shared hover behaviour, NOT a shared surface -----------------------
 *
 * An earlier version of this file gave .value-mini-card, .sv-card,
 * .team-card and .faq-item a blanket card treatment — surface, radius,
 * shadow. That was wrong, and the About page showed exactly why.
 *
 * "Why Clients Choose Struxa" is not four cards. It is ONE ruled band
 * divided into four cells: the container carries border-t/border-b and each
 * cell carries border-r. Dropping a grey rounded box inside each cell of a
 * ruled band gives you a box with a line around it, and because the surface
 * (#0D0F11) is lighter than the section behind it (#000), the whole row
 * reads as dull grey rather than as black with hairlines.
 *
 * The same applies to the others: .sv-card is a photo tile with its own
 * border, .team-card sets its own .85rem radius, .faq-item has its own
 * styling in single-product.php. All four already knew what they were.
 *
 * So: no shared surface. Only the hover lift is shared, because THAT is
 * the thing that should feel identical everywhere on the site.
 */
.value-mini-card,
.sv-card,
.team-card,
.faq-item {
	transition: transform var(--d-base) var(--ease-ui),
	            box-shadow var(--d-base) var(--ease-soft),
	            border-color var(--d-base) var(--ease-soft),
	            background-color var(--d-base) var(--ease-soft);
}

/* A cell in a ruled band lifts by warming its own ground, not by casting a
   shadow — a shadow needs an edge to fall from, and a cell has none.
 *
 * transform and box-shadow are explicitly cleared: template-about-us.php's
 * own stylesheet gives .value-mini-card:hover a 6px lift and a gold glow,
 * which pulls the cell up out of the band it is ruled into and leaves the
 * divider lines behind it. That rule is left in the template untouched;
 * this is where it is overridden. */
.value-mini-card:hover {
	background-color: rgba(255, 255, 255, 0.025);
	transform: none;
	box-shadow: none;
	border-color: var(--line-2);
}

.sv-card:hover,
.team-card:hover {
	transform: translateY(-2px);
}

/* Photography inside a rounded card has to be clipped by the card, or the
   square corners of the image show through the radius. */
.collection-tile,
.svc-card,
.value-mini-card,
.team-card,
.shop-card {
	overflow: hidden;
	isolation: isolate;
}

/* ==========================================================================
   8. THE CREAM SECTION
   --------------------------------------------------------------------------
   The one light section on the site. It was carrying dark-section values —
   14px body, 60%-alpha ink, a neutral shadow — which on cream reads as grey
   rather than as a second, warmer surface.
   ========================================================================== */

.bg-cream {
	background-color: var(--s-cream);
	color: var(--ink-1);
}

.bg-cream p,
.text-ink\/70,
.text-ink\/80 { color: var(--ink-2); }

.text-ink\/60 { color: var(--ink-3); }

.bg-cream .font-serif,
.bg-cream h2,
.bg-cream h3 { color: var(--ink-1); }

/* Stat figures in the About block. They are the largest type in the section
   and were set at the same size as a card heading. */
.bg-cream [data-stat] {
	font-family: var(--font-display);
	font-size: clamp(2rem, 3.2vw, 3rem);
	font-weight: 500;
	letter-spacing: var(--tr-head);
	line-height: 1;
}

.bg-cream [data-stat] + p {
	font-size: var(--fs-eyebrow);
	letter-spacing: 0.22em;
	color: var(--ink-3);
	margin-top: var(--sp-3);
}

/* Captions bottom-align across the row.
   The figures are different heights by nature — "3" is one line, "Statement
   Decor" is two — so a caption that simply follows its figure ends up at a
   different height from the caption beside it. Pushing the caption to the
   floor of its cell gives the row one baseline whatever the figures do,
   which also means the rotating figure can reserve two lines (see
   .stat-cycle) without knocking the row out of alignment.

   Matched on the grid, not on [data-stat]: the fourth cell ("Nationwide /
   Shipping") is a static value with no data-stat attribute, so keying off
   that attribute aligned three cells out of four and left the odd one 65px
   high — which is worse than not doing it at all. */
.bg-cream .grid-cols-2.gap-x-6.gap-y-8 > div {
	display: flex;
	flex-direction: column;
	height: 100%;
}

.bg-cream .grid-cols-2.gap-x-6.gap-y-8 > div > p:last-child {
	margin-top: auto;
	padding-top: var(--sp-3);
}

/* The About photograph sits on cream with no edge at all, so it reads as a
   pasted rectangle. A radius and a warm shadow make it an object on a
   surface. */
.bg-cream img:not([data-reveal="circle"]) {
	border-radius: var(--r-lg);
	box-shadow: var(--e-cream-3);
}

/* --- The rotating stat ("What We Deliver") -------------------------------
 *
 * THE PROBLEM THIS SOLVES
 * The stat cell is 207px wide and the figure is set at 42px serif. At that
 * size "Pergolas" fits on one line and "LED Displays", "Smart Glass" and
 * "Statement Decor" all wrap to two. So every time the word changed, the
 * element doubled in height and back — and the entire page below it jumped
 * 42px, four times a minute, forever. Measured on the live page.
 *
 * The box is now sized once, to two lines, and never changes. The word is
 * taken out of flow inside it and crossfades in place, so the swap moves
 * nothing at all. The script that drives it is in the page templates.
 */
/* The ghost alone sizes this box — it holds the longest word at whatever
   height that word actually renders to, which is correct by construction.
   A min-height here would only add dead space under the shorter words
   (measured: 102px of box for a 96px word). */
.stat-cycle {
	position: relative;
	display: block;
}

.stat-cycle__ghost {
	visibility: hidden;
	pointer-events: none;
	user-select: none;
}

.stat-cycle__word {
	position: absolute;
	inset: 0;
	opacity: 1;
	transform: translateY(0);
	transition: opacity 560ms var(--ease-soft), transform 560ms var(--ease-out);
}

.stat-cycle__word.is-out {
	opacity: 0;
	/* A 4px drift reads as the word being replaced rather than flickering.
	   Any further and it becomes an animation you have to watch. */
	transform: translateY(-4px);
}

@media (prefers-reduced-motion: reduce) {
	.stat-cycle__word { transition: none; }
	.stat-cycle__word.is-out { opacity: 1; transform: none; }
}

/* ==========================================================================
   9. FORMS & INPUTS
   --------------------------------------------------------------------------
   Inputs across the site were inheriting WoodMart's light-theme form styles
   onto a black page: a hard 1px grey border, a 0–4px radius, 14px text and
   no visible focus state. Apple's fields are the opposite — no outline at
   rest, a filled translucent surface, a large radius, reading-size text,
   and an unmissable focus ring.
   ========================================================================== */

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="search"],
input[type="password"],
input[type="date"],
select,
textarea,
.wpcf7 input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]),
.wpcf7 textarea,
.wpcf7 select,
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select,
.select2-container--default .select2-selection--single {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-body) !important;
	line-height: 1.4 !important;
	letter-spacing: var(--tr-body);
	color: var(--t-1) !important;
	background: rgba(255, 255, 255, 0.05) !important;
	border: 0 !important;
	border-radius: var(--r-sm) !important;
	box-shadow: inset 0 0 0 1px var(--line-2) !important;
	padding: 13px 16px !important;
	min-height: 48px;
	width: 100%;
	transition: box-shadow var(--d-fast) var(--ease-soft),
	            background-color var(--d-fast) var(--ease-soft);
	-webkit-appearance: none;
	appearance: none;
}

textarea,
.wpcf7 textarea,
.woocommerce form .form-row textarea {
	min-height: 132px;
	resize: vertical;
}

input::placeholder,
textarea::placeholder {
	color: var(--t-4);
	opacity: 1;
}

/* Focus: a 3px gold ring at 0 offset, drawn with box-shadow so it follows
   the radius. This is the single most-missing state on the old site. */
input:focus,
select:focus,
textarea:focus,
.wpcf7 input:focus,
.wpcf7 textarea:focus,
.woocommerce form .form-row input.input-text:focus,
.woocommerce form .form-row textarea:focus,
.woocommerce form .form-row select:focus {
	outline: none !important;
	background: rgba(255, 255, 255, 0.08) !important;
	box-shadow:
		inset 0 0 0 1px var(--struxa-gold),
		0 0 0 3px rgba(197, 160, 89, 0.26) !important;
}

/* Native select needs its own chevron once appearance is stripped. */
select,
.woocommerce form .form-row select,
.woocommerce-ordering select {
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%23C5A059' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
	background-repeat: no-repeat !important;
	background-position: right 16px center !important;
	padding-right: 42px !important;
}

/* Labels */
.wpcf7 label,
.woocommerce form .form-row label,
.struxa-field-label {
	display: block;
	font-family: var(--font-ui);
	font-size: var(--fs-cap);
	font-weight: 500;
	letter-spacing: 0.02em;
	color: var(--t-2);
	margin-bottom: var(--sp-2);
}

/* Checkbox and radio — WoodMart ships the browser default on a black page,
   which renders as a white square.
 *
 * :not(.sr-only) matters. The Build configurator and the pergola product
 * configurator both hide their real radios with .sr-only and draw the
 * selected state on a sibling card instead. Restyling a visually-hidden
 * input would give it a size and a background again, and it would reappear
 * as a stray dot on top of the card art. */
input[type="checkbox"]:not(.sr-only),
input[type="radio"]:not(.sr-only) {
	-webkit-appearance: none;
	appearance: none;
	width: 20px;
	height: 20px;
	min-height: 0;
	flex: 0 0 20px;
	padding: 0 !important;
	background: rgba(255, 255, 255, 0.06) !important;
	box-shadow: inset 0 0 0 1px var(--line-2) !important;
	border-radius: 6px !important;
	transition: background-color var(--d-fast) var(--ease-soft),
	            box-shadow var(--d-fast) var(--ease-soft);
	display: inline-grid;
	place-content: center;
}

input[type="radio"]:not(.sr-only) { border-radius: var(--r-pill) !important; }

input[type="checkbox"]:not(.sr-only):checked,
input[type="radio"]:not(.sr-only):checked {
	background: var(--struxa-gold) !important;
	box-shadow: inset 0 0 0 1px var(--struxa-gold) !important;
}

input[type="checkbox"]:not(.sr-only):checked::before {
	content: "";
	width: 11px;
	height: 7px;
	border-left: 2px solid var(--struxa-ink);
	border-bottom: 2px solid var(--struxa-ink);
	transform: translateY(-1px) rotate(-45deg);
}

input[type="radio"]:not(.sr-only):checked::before {
	content: "";
	width: 8px;
	height: 8px;
	border-radius: var(--r-pill);
	background: var(--struxa-ink);
}

/* Submit buttons inherit the primary button — matched semantically
   (type="submit") as well as by plugin class, so a form anywhere on the
   site gets the right button without needing a class added to it. */
input[type="submit"],
button[type="submit"]:not(.wd-tools-icon):not([class*="wd-"]),
.wpcf7 input[type="submit"],
.woocommerce button.button,
.woocommerce a.button,
.woocommerce input.button,
.woocommerce #respond input#submit,
.woocommerce .button.alt {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-2);
	min-height: 48px;
	padding: 0 var(--sp-7, 28px) !important;
	border: 0 !important;
	border-radius: var(--r-pill) !important;
	background: var(--struxa-gold) !important;
	color: var(--struxa-ink) !important;
	font-family: var(--font-ui) !important;
	font-size: 0.9375rem !important;
	font-weight: 600 !important;
	letter-spacing: -0.006em !important;
	text-transform: none !important;
	box-shadow: var(--e-1), inset 0 1px 0 rgba(255, 255, 255, 0.24);
	transition: transform var(--d-fast) var(--ease-ui),
	            background-color var(--d-fast) var(--ease-soft),
	            box-shadow var(--d-base) var(--ease-soft);
}

input[type="submit"]:hover,
button[type="submit"]:not(.wd-tools-icon):not([class*="wd-"]):hover,
.wpcf7 input[type="submit"]:hover,
.woocommerce button.button:hover,
.woocommerce a.button:hover,
.woocommerce input.button:hover,
.woocommerce .button.alt:hover {
	background: var(--struxa-gold-hi) !important;
	color: var(--struxa-ink) !important;
	transform: translateY(-1px);
	box-shadow: var(--e-2), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.wpcf7 input[type="submit"]:active,
.woocommerce button.button:active,
.woocommerce a.button:active { transform: scale(0.97); }

/* The GoHighLevel estimate form is a cross-origin iframe, so its interior
   cannot be styled from here. What can be styled is the frame it sits in —
   giving it a card surface stops it reading as a pasted-in widget. */
iframe[src*="leadconnectorhq.com/widget/form"] {
	border-radius: var(--r-lg) !important;
	background: var(--s-1);
	box-shadow: var(--e-3), var(--sheen);
}

/* ==========================================================================
   10. SHOP — product grid
   --------------------------------------------------------------------------
   THE BUG THIS FIXES
   The shop archive shipped ~200 lines of "Premium Dark Shop" CSS targeting
   `ul.products li.product`. WoodMart does not render that markup — its grid
   is `div.products.wd-products > div.wd-product`. Every one of those rules
   was dead, which is why the live shop page shows bare WoodMart defaults on
   a black canvas: no card, no edge, no radius, no elevation.

   Separately, style.css forced `.fade-in-block` permanently visible, which
   pushed the hover panel (short description + Select Options + zoom) into
   the card's normal flow. Because every product has a description of a
   different length, no two cards were the same height and the grid had no
   baseline at all.

   Both are addressed here, against the markup WoodMart actually emits.
   ========================================================================== */

.woocommerce .products.wd-products,
.products.wd-products.wd-grid-g {
	--wd-gap: clamp(16px, 1.6vw, 24px);
	gap: clamp(16px, 1.6vw, 24px) !important;
	padding: 0 !important;
	align-items: stretch;
}

/* --- The card ----------------------------------------------------------- */
.wd-product.product-grid-item {
	position: relative;
	background: var(--s-2);
	border-radius: var(--r-lg);
	box-shadow: var(--e-2), var(--sheen);
	overflow: hidden;
	isolation: isolate;
	transition: transform var(--d-base) var(--ease-ui),
	            box-shadow var(--d-base) var(--ease-soft);
}

.wd-product.product-grid-item:hover {
	transform: translateY(-3px);
	box-shadow: var(--e-4), var(--sheen), inset 0 0 0 1px var(--line-gold);
}

/* Equal height is the whole point of a grid. The wrapper becomes a column,
   the media gets a fixed ratio, and the action row is pushed to the floor —
   so prices and buttons line up across the row no matter how long a title
   or description runs. */
.wd-product.product-grid-item > .product-wrapper {
	display: flex;
	flex-direction: column;
	height: 100%;
}

.wd-product .product-element-top {
	position: relative;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: 0;
	background: var(--s-3);
	flex: 0 0 auto;
}

.wd-product .product-element-top img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
	transition: transform 800ms var(--ease-ui);
}

.wd-product.product-grid-item:hover .product-element-top img {
	transform: scale(1.05);
}

.wd-product .product-element-bottom,
.wd-product .product-information {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	padding: clamp(16px, 1.5vw, 22px);
	gap: var(--sp-2);
	text-align: left;
}

/* --- Card typography ----------------------------------------------------
 * Title was 15px bold Poppins with +0.5px tracking; category was italic
 * gold; price was bold gold; description was 13px Arial. Four voices in a
 * 300px card. Now: one display title, one quiet category, one clear price. */
.wd-product .wd-entities-title {
	font-family: var(--font-display) !important;
	font-size: 1.1875rem !important;
	font-weight: 500 !important;
	line-height: 1.2 !important;
	letter-spacing: var(--tr-sub) !important;
	margin: 0 !important;
	text-transform: none !important;
	/* Two lines maximum. A four-line title in a grid of one-line titles is
	   what makes a shop row look broken. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.wd-product .wd-entities-title a {
	color: var(--t-1) !important;
	transition: color var(--d-fast) var(--ease-soft);
}

.wd-product.product-grid-item:hover .wd-entities-title a {
	color: var(--struxa-gold) !important;
}

.wd-product .wd-product-cats,
.wd-product .wd-product-cats a {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-eyebrow) !important;
	font-style: normal !important;
	font-weight: 500 !important;
	letter-spacing: 0.18em !important;
	text-transform: uppercase !important;
	color: var(--t-4) !important;
	margin: 0 !important;
	order: -1;	/* category reads above the title, not under it */
}

.wd-product .price,
.wd-product .price .amount {
	font-family: var(--font-ui) !important;
	font-size: 1.0625rem !important;
	font-weight: 550 !important;
	letter-spacing: var(--tr-body) !important;
	color: var(--struxa-gold) !important;
}

.wd-product .price del,
.wd-product .price del .amount {
	color: var(--t-4) !important;
	font-weight: 400 !important;
	text-decoration-thickness: 1px;
}

.wd-product .product-rating-price { margin: 0 !important; }

/* The short description (WoodMart's .hover-content-inner) was rendered at
   full length inside every card. Clamped to two lines: enough to tell two
   similar products apart, not enough to become the card. */
.wd-product .hover-content-inner,
.wd-product .wd-more-desc-inner,
.wd-product .hover-content-inner p {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-cap) !important;
	line-height: 1.5 !important;
	color: var(--t-3) !important;
	margin: 0 !important;
	padding: 0 !important;
	background: none !important;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* WoodMart's "read more description" affordance is an empty <a> that only
   makes sense when the panel is a hover overlay with a height limit. With
   the panel inline and the text clamped, it is an invisible link. */
.wd-product .wd-more-desc-btn { display: none !important; }

/* The always-visible hover panel, given a real home at the bottom of the
   card instead of wherever it happened to land in the flow. */
.wd-product.wd-hover-base .fade-in-block {
	position: relative !important;
	inset: auto !important;
	opacity: 1 !important;
	visibility: visible !important;
	display: flex;
	flex-direction: column;
	gap: var(--sp-3);
	margin-top: auto;
	padding-top: var(--sp-4);
	transform: none !important;
	background: none !important;
}

.wd-product .wd-bottom-actions {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	margin-top: auto;
}

.wd-product .wd-bottom-actions .wd-add-btn { flex: 1 1 auto; }

.wd-product .wrap-wishlist-button,
.wd-product .wrap-quickview-button { flex: 0 0 auto; }

/* The add-to-cart button is removed at the hook, not hidden here — see
   struxa_loop_view_details() in functions.php, which also prints the
   "View details" link that takes its place inside .wd-add-btn.

   What IS hidden is the quick-shop panel: it is loaded by AJAX into the
   card and would let someone configure a product without ever opening its
   page, which is the thing being removed. */
.wd-product .wd-quick-shop-2,
.wd-product .wd-add-cart-icon {
	display: none !important;
}

/* WoodMart's "replace" hover — label slides up, basket glyph slides in —
   is keyed to .add-to-cart-loop, a class the replacement link does not
   carry. Neutralised here as well so the behaviour cannot come back
   through a different loop template. */
.wd-product .wd-add-btn .button::before,
.wd-product .wd-add-btn .button::after {
	content: none !important;
}

.wd-product .struxa-loop-view span,
.wd-product .wd-add-btn .button span {
	transform: none !important;
}

/* Styling below applies to this link, to the cart and checkout buttons,
 * and to any loop button a future template part renders. */

/* Add to cart / Select options / Read more — the quiet pill, sized down one
 * step from the site's primary button.
 *
 * Matched on ANY button inside a product card, not just .add_to_cart_button.
 * A product that isn't directly purchasable renders "Read more" WITHOUT that
 * class, so it was falling through to the site-wide primary gold button —
 * which put the loudest control in the whole grid on the one card with no
 * price and nothing to add. */
.wd-product .button,
.wd-product a.button,
.wd-product .button.add_to_cart_button,
.wd-product .add_to_cart_button,
.wd-product .product_type_variable,
.wd-product .product_type_simple,
.wd-product .product_type_external,
.wd-product .product_type_grouped,
.wd-product .added_to_cart {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	flex: 1 1 auto;
	min-height: 42px;
	padding: 0 var(--sp-5) !important;
	border: 0 !important;
	border-radius: var(--r-pill) !important;
	background: rgba(255, 255, 255, 0.07) !important;
	color: var(--t-1) !important;
	box-shadow: inset 0 0 0 1px var(--line-2);
	font-family: var(--font-ui) !important;
	font-size: 0.875rem !important;
	font-weight: 550 !important;
	letter-spacing: -0.006em !important;
	text-transform: none !important;
	transition: background-color var(--d-fast) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft),
	            box-shadow var(--d-fast) var(--ease-soft);
}

.wd-product .button:hover,
.wd-product a.button:hover,
.wd-product .button.add_to_cart_button:hover,
.wd-product .add_to_cart_button:hover,
.wd-product .product_type_variable:hover,
.wd-product .product_type_simple:hover {
	background: var(--struxa-gold) !important;
	color: var(--struxa-ink) !important;
	box-shadow: inset 0 0 0 1px var(--struxa-gold);
}

/* Whatever shape a card's action takes — the full hover panel, the bottom
   action row, or a bare "Read more" link — it sits on the floor of the card.
   Only .wd-bottom-actions was pinned before, so a card using one of the
   other two ended up with its button floating mid-card while the card beside
   it had one at the bottom. */
.wd-product .product-element-bottom > .button,
.wd-product .product-information > .button,
.wd-product .product-element-bottom > .wd-add-btn,
.wd-product .product-information > .wd-add-btn {
	margin-top: auto;
	/* flex:0 0 auto matters. The card body is a flex column, so a button
	   that is a DIRECT child of it stretches to fill the leftover height —
	   and a 980px pill radius on a 90px-tall box renders as a circle, which
	   is exactly what "Read more" was doing. */
	flex: 0 0 auto;
	align-self: stretch;
}

/* Icon actions (wishlist, compare, quick view) — one 42px round shape each,
   instead of three different sizes sharing a row with the button. */
.wd-product .wd-action-btn > a,
.wd-product .wrap-wishlist-button > a,
.wd-product .wrap-wishlist-button .wd-action-btn > a,
.wd-product .wrap-quickview-button > a,
.wd-product .wrap-quickview-button .wd-action-btn > a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	flex: 0 0 42px;
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.05);
	box-shadow: inset 0 0 0 1px var(--line-1);
	color: var(--t-2);
	transition: background-color var(--d-fast) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft);
}

.wd-product .wd-action-btn > a:hover,
.wd-product .wrap-wishlist-button a:hover,
.wd-product .wrap-quickview-button a:hover {
	background: rgba(255, 255, 255, 0.11);
	color: var(--struxa-gold);
}

/* The icon buttons carry a text label ("Add to Wishlist", "Quick view")
   that WoodMart shows beside the glyph. In a 42px circle it has nowhere to
   go — it is kept for screen readers, taken out of the layout. */
.wd-product .wd-bottom-actions .wd-action-text {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}

/* --- The strip that slides up from the bottom of the photo on hover -----
 *
 * WoodMart pins a .wrapp-swatches bar to the bottom of the product image,
 * hidden at rest and revealed by .state-hover. It is meant to carry
 * variation swatches — and it draws itself with a hairline along its top
 * AND bottom edge.
 *
 * Every product in this catalogue is .product-no-swatches, so the bar has
 * nothing in it but the Compare icon (and there is no compare page linked
 * anywhere on the site). What the visitor sees on hover is therefore a grey
 * rule appearing across the bottom of the photograph and nothing else,
 * which reads as a rendering fault rather than as a control.
 *
 * Hidden where there is nothing to show. Where a product DOES have swatches
 * the bar stays, but as a proper frosted bar rather than two hairlines. */
.wd-product.product-no-swatches .wrapp-swatches {
	display: none !important;
}

.wd-product .wrapp-swatches {
	border: 0 !important;
	background: rgba(8, 9, 10, 0.68) !important;
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: var(--sheen);
}

/* Sale badge — was a bare "-41%" floating over the card with no container. */
.wd-product .product-labels .product-label,
.wd-product .onsale,
.wd-product span.onsale {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 4;
	display: inline-flex;
	align-items: center;
	min-height: 26px;
	padding: 0 10px !important;
	border-radius: var(--r-pill) !important;
	background: rgba(8, 9, 10, 0.72) !important;
	-webkit-backdrop-filter: var(--glass-blur);
	backdrop-filter: var(--glass-blur);
	box-shadow: inset 0 0 0 1px var(--line-gold);
	color: var(--struxa-gold) !important;
	font-family: var(--font-ui) !important;
	font-size: 11px !important;
	font-weight: 600 !important;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em !important;
	text-transform: none !important;
	margin: 0 !important;
}

/* --- Shop chrome --------------------------------------------------------
 * "Show : 9 / 12 / 18 / 24", the view switcher, the result count and the
 * sort dropdown are WoodMart's .shop-loop-head row. They were rendering at
 * their inherited light-theme values on a black page: 12px grey text, a
 * bare "/" between the per-page links, and a native select. Given a real
 * toolbar: one baseline, 30px targets, a separator rule under it. */
.woocommerce .shop-loop-head,
.woocommerce .wd-shop-tools,
.woocommerce .wd-products-per-page,
.woocommerce .wd-products-shop-view,
.woocommerce .woocommerce-ordering,
.woocommerce .woocommerce-result-count {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-cap) !important;
	letter-spacing: var(--tr-body);
	color: var(--t-3) !important;
}

.woocommerce .shop-loop-head {
	align-items: center;
	gap: var(--sp-4) var(--sp-6) !important;
	padding-bottom: var(--sp-5);
	margin-bottom: var(--sp-8) !important;
	border-bottom: 1px solid var(--line-1);
}

.woocommerce .wd-shop-tools { gap: var(--sp-3) var(--sp-6) !important; }

.woocommerce .wd-products-per-page .per-page-title,
.woocommerce .wd-label {
	font-size: var(--fs-eyebrow);
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--t-4) !important;
	margin-right: var(--sp-1);
}

.woocommerce .wd-products-per-page a.per-page-variation,
.woocommerce .wd-products-shop-view a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px;
	height: 32px;
	padding: 0 9px !important;
	border-radius: var(--r-xs);
	color: var(--t-3) !important;
	font-variant-numeric: tabular-nums;
	transition: background-color var(--d-fast) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft);
}

.woocommerce .wd-products-per-page a.per-page-variation:hover,
.woocommerce .wd-products-shop-view a:hover {
	background: rgba(255, 255, 255, 0.07);
	color: var(--t-1) !important;
}

.woocommerce .wd-products-per-page a.current-variation,
.woocommerce .wd-products-shop-view a.current-variation {
	background: rgba(255, 255, 255, 0.11);
	color: var(--struxa-gold) !important;
	font-weight: 550 !important;
}

/* WoodMart draws a literal "/" between the per-page links. Once each link
   is a padded pill with its own hover surface, the slash is doing the job
   the spacing already does — and it collides with the pill on hover. */
.woocommerce .wd-products-per-page .per-page-border { display: none; }

/* The sort dropdown is a native <select> inheriting the form styles above,
   which at 48px min-height would tower over a 32px toolbar. */
.woocommerce .woocommerce-ordering select {
	min-height: 36px;
	padding: 6px 38px 6px 12px !important;
	font-size: var(--fs-cap) !important;
	background-position: right 12px center !important;
	width: auto;
}

/* Archive title */
.woocommerce .woocommerce-products-header__title,
.woocommerce .page-title,
.wd-page-content .page-title {
	font-family: var(--font-display) !important;
	font-size: var(--fs-h2) !important;
	font-weight: 500 !important;
	letter-spacing: var(--tr-head) !important;
	line-height: var(--lh-head) !important;
	text-transform: none !important;
	color: var(--t-1) !important;
	text-align: left;
	margin: 0 0 var(--sp-4) !important;
}

.woocommerce .term-description,
.woocommerce .archive-description {
	font-size: var(--fs-lede);
	line-height: 1.55;
	color: var(--t-2);
	max-width: 58ch;
}

/* The mobile filter opener ("☰ Show sidebar") and the collapsed sort
   control sit loose above the grid at phone width, at WoodMart's inherited
   light-theme values. Given the same shape as every other control. */
.wd-sidebar-opener-mobile,
.woocommerce .wd-shop-tools .wd-sidebar-opener-mobile,
.wd-action-btn.wd-sidebar-opener-mobile > a {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	min-height: 40px;
	padding: 0 var(--sp-4);
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.06);
	box-shadow: inset 0 0 0 1px var(--line-1);
	font-family: var(--font-ui);
	font-size: var(--fs-cap);
	font-weight: 550;
	letter-spacing: var(--tr-body);
	color: var(--t-1) !important;
	text-transform: none;
}

.woocommerce .wd-shop-tools .wd-products-shop-view,
.woocommerce .shop-loop-head .woocommerce-ordering {
	display: inline-flex;
	align-items: center;
}

/* Breadcrumb */
.woocommerce-breadcrumb {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-cap) !important;
	letter-spacing: var(--tr-body) !important;
	color: var(--t-4) !important;
	margin-bottom: var(--sp-6) !important;
}

.woocommerce-breadcrumb a {
	color: var(--t-3) !important;
	transition: color var(--d-fast) var(--ease-soft);
}

.woocommerce-breadcrumb a:hover { color: var(--struxa-gold) !important; }

/* Pagination — 40px round targets instead of 12px text links. */
.woocommerce-pagination ul.page-numbers,
.woocommerce nav.woocommerce-pagination ul {
	display: flex;
	justify-content: center;
	gap: var(--sp-2);
	border: 0 !important;
	margin-top: var(--section-y-tight) !important;
	padding-left: 0;
	list-style: none;
}

.woocommerce-pagination ul.page-numbers li {
	border: 0 !important;
	margin: 0 !important;
	list-style: none;
}

.woocommerce-pagination .page-numbers {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	height: 40px;
	padding: 0 12px;
	border: 0 !important;
	border-radius: var(--r-pill) !important;
	background: transparent;
	color: var(--t-3) !important;
	font-family: var(--font-ui);
	font-size: var(--fs-sm);
	font-variant-numeric: tabular-nums;
	transition: background-color var(--d-fast) var(--ease-soft),
	            color var(--d-fast) var(--ease-soft);
}

.woocommerce-pagination .page-numbers:hover {
	background: rgba(255, 255, 255, 0.07) !important;
	color: var(--t-1) !important;
}

.woocommerce-pagination .page-numbers.current {
	background: var(--struxa-gold) !important;
	color: var(--struxa-ink) !important;
}

/* Price filter widget */
.widget_price_filter .price_slider_wrapper .ui-widget-content {
	background: rgba(255, 255, 255, 0.10) !important;
	height: 3px !important;
	border-radius: var(--r-pill) !important;
}

.widget_price_filter .ui-slider .ui-slider-range {
	background: var(--struxa-gold) !important;
	border-radius: var(--r-pill) !important;
}

.widget_price_filter .ui-slider .ui-slider-handle {
	width: 20px !important;
	height: 20px !important;
	top: -9px !important;
	border: 0 !important;
	border-radius: var(--r-pill) !important;
	background: #fff !important;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 0 0 0.5px rgba(0, 0, 0, 0.2) !important;
}

.widget_price_filter .price_label {
	font-family: var(--font-ui);
	font-size: var(--fs-cap);
	font-variant-numeric: tabular-nums;
	color: var(--t-3);
}

/* ==========================================================================
   11. SINGLE PRODUCT
   ========================================================================== */

.single-product .product_title.entry-title {
	font-family: var(--font-display) !important;
	font-size: var(--fs-h2) !important;
	font-weight: 500 !important;
	letter-spacing: var(--tr-head) !important;
	line-height: var(--lh-head) !important;
	text-transform: none !important;
}

.single-product .summary .price,
.single-product .summary .price .amount {
	font-family: var(--font-ui) !important;
	font-size: clamp(1.375rem, 2vw, 1.75rem) !important;
	font-weight: 550 !important;
	letter-spacing: var(--tr-sub) !important;
	color: var(--struxa-gold) !important;
}

.single-product .woocommerce-product-gallery__image img,
.single-product .wd-gallery-thumb img {
	border-radius: var(--r-lg);
}

.single-product .flex-control-thumbs li img,
.single-product .wd-gallery-thumb {
	border-radius: var(--r-sm);
	transition: box-shadow var(--d-fast) var(--ease-soft),
	            opacity var(--d-fast) var(--ease-soft);
}

.single-product .flex-control-thumbs li img.flex-active {
	box-shadow: 0 0 0 2px var(--struxa-gold);
}

.single-product .woocommerce-tabs .wc-tabs li a,
.single-product .wd-tabs .wd-nav-tabs a {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-sm) !important;
	font-weight: 550 !important;
	letter-spacing: var(--tr-body) !important;
	text-transform: none !important;
}

/* Quantity steppers (product page, cart, mini-cart) opt out of the
   full-width field rule — a quantity box is a stepper, not a text field. */
.quantity input.qty,
.woocommerce .quantity input.qty {
	text-align: center;
	font-variant-numeric: tabular-nums;
	width: auto;
	max-width: 88px;
	padding-left: 8px !important;
	padding-right: 8px !important;
}

/* The header's own search field belongs to WoodMart's header row, which
   sizes itself around it. A 48px minimum would change the header height. */
.whb-header input[type="text"],
.whb-header input[type="search"],
.whb-header .searchform input {
	min-height: 0;
	padding: 10px 14px !important;
	font-size: var(--fs-sm) !important;
}

/* ==========================================================================
   12. FOOTER
   --------------------------------------------------------------------------
   The footer is an Elementor template stored in the database, so its markup
   can't be edited from the theme — but its material can.

   Two problems: an Essential-Addons particle canvas animating a constellation
   behind the links (a permanent, decorative, CPU-burning animation with no
   relationship to the brand), and three link columns starting at the middle
   of the page with the left third empty.
   ========================================================================== */

/* The particle field stops animating and becomes a very faint static texture
   — the shape of the footer is kept, the noise is not. */
.wd-footer canvas.particles-js-canvas-el {
	opacity: 0.16;
	filter: saturate(0) brightness(1.4);
	pointer-events: none;
}

.wd-footer {
	background: var(--s-1);
	border-top: 1px solid var(--line-1);
}

.wd-footer .main-footer {
	padding-block: clamp(56px, 6vw, 88px) clamp(40px, 4vw, 64px);
}

/* Column headings */
.wd-footer .title-wrapper .liner-continer,
.wd-footer .elementor-heading-title,
.wd-footer .wd-title-color-default {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-eyebrow) !important;
	font-weight: 600 !important;
	letter-spacing: 0.22em !important;
	text-transform: uppercase !important;
	color: var(--t-4) !important;
}

/* Links — 13px bold Poppins with an icon became reading-size UI type with a
   real hover state and a 40px hit row. */
.wd-footer .elementor-icon-list-item > a,
.wd-footer .elementor-icon-list-text {
	font-family: var(--font-ui) !important;
	font-size: var(--fs-sm) !important;
	font-weight: 400 !important;
	letter-spacing: var(--tr-body) !important;
	color: var(--t-2) !important;
	transition: color var(--d-fast) var(--ease-soft),
	            transform var(--d-fast) var(--ease-ui);
}

.wd-footer .elementor-icon-list-item > a:hover {
	color: var(--struxa-gold) !important;
	transform: translateX(2px);
}

.wd-footer .elementor-icon-list-item {
	padding-block: 6px;
}

.wd-footer .elementor-icon-list-icon svg,
.wd-footer .elementor-icon-list-icon i {
	color: var(--t-4) !important;
	transition: color var(--d-fast) var(--ease-soft);
}

.wd-footer .elementor-icon-list-item:hover .elementor-icon-list-icon svg,
.wd-footer .elementor-icon-list-item:hover .elementor-icon-list-icon i {
	color: var(--struxa-gold) !important;
}

/* Copyright strip */
.wd-copyrights {
	border-top: 1px solid var(--line-1);
	background: var(--s-0);
	padding-block: var(--sp-6) !important;
	font-size: var(--fs-cap);
	color: var(--t-4);
}

.wd-copyrights a { color: var(--t-3); }
.wd-copyrights a:hover { color: var(--struxa-gold); }

/* ==========================================================================
   13. MOTION & MICRO-INTERACTIONS
   --------------------------------------------------------------------------
   The site had a lot of motion and not much timing discipline: hovers ran
   anywhere from 300ms to 1700ms, entrances from 800ms to 3300ms, and three
   decorative loops ran forever.

   The rule applied here is the one Apple follows: interaction feedback is
   fast (150–300ms) so the interface feels responsive; entrances are slower
   (600–850ms) so they feel considered; nothing loops without a reason.
   ========================================================================== */

/* The About-section circle reveal ran for 3.3 seconds. At that length the
   visitor has scrolled past before it finishes, so the effect is only ever
   seen half-done. 1.1s reads as deliberate and completes in view. */
[data-reveal="circle"] {
	transition: clip-path 1.1s var(--ease-out), -webkit-clip-path 1.1s var(--ease-out);
}

[data-reveal="wipe-up"] {
	transition: clip-path 900ms var(--ease-out),
	            -webkit-clip-path 900ms var(--ease-out),
	            transform 900ms var(--ease-out);
}

[data-reveal] {
	transition-duration: var(--d-reveal);
	transition-timing-function: var(--ease-out);
}

/* Stagger: 90ms per item meant the sixth card in a row arrived 450ms after
   the first, which reads as a queue rather than as a group. 55ms keeps the
   sense of sequence without the wait. */
.stagger > *:nth-child(1) { transition-delay: 0ms; }
.stagger > *:nth-child(2) { transition-delay: 55ms; }
.stagger > *:nth-child(3) { transition-delay: 110ms; }
.stagger > *:nth-child(4) { transition-delay: 165ms; }
.stagger > *:nth-child(5) { transition-delay: 220ms; }
.stagger > *:nth-child(6) { transition-delay: 275ms; }
.stagger > *:nth-child(n+7) { transition-delay: 320ms; }

.collection-tile { transition-delay: calc(var(--i, 0) * 55ms); }

/* The masthead photo settled from scale(1.08) over 2.6s — long enough to be
   read as the page still loading. */
.masthead__media { animation-duration: 1.6s; }

.masthead__title,
.masthead__rule,
.masthead__lede,
.masthead__actions,
.masthead__proof { animation-duration: 760ms; }

.masthead__rule { animation-delay: 80ms; }
.masthead__lede { animation-delay: 140ms; }
.masthead__actions { animation-delay: 210ms; }
.masthead__proof { animation-delay: 280ms; }

/* The masthead entrance moved 26px. Apple's content entrances move about
   half that — the motion should suggest arrival, not travel. */
@keyframes mastheadRise {
	from { opacity: 0; transform: translateY(14px); }
	to { opacity: 1; transform: translateY(0); }
}

/* Anything that lifts, lifts by the same amount, on the same curve. */
.struxa-tw .hover\:-translate-y-0\.5:hover,
.struxa-tw .hover\:scale-105:hover {
	transform: translateY(-2px);
	transition: transform var(--d-base) var(--ease-ui);
}

/* Images inside links: one zoom value site-wide. */
.struxa-tw .group:hover .group-hover\:scale-105 {
	transform: scale(1.04);
	transition: transform 800ms var(--ease-ui);
}

/* The scroll hint nudged every 2.4s, forever, including after the visitor
   had already scrolled. It now runs six times and stops. */
.masthead__scroll svg {
	animation-iteration-count: 6;
}

/* ==========================================================================
   14. FOCUS & ACCESSIBILITY
   --------------------------------------------------------------------------
   Focus was defined on four components and nowhere else, at three different
   ring widths. One ring, everywhere, visible on both dark and cream.
   ========================================================================== */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--struxa-gold);
	outline-offset: 3px;
	border-radius: var(--r-xs);
}

/* Gold on gold disappears, so the primary button's ring is cream. */
.masthead__cta:focus-visible,
.struxa-btn--primary:focus-visible,
.tile-cta:focus-visible,
.woocommerce .button:focus-visible {
	outline-color: var(--struxa-cream);
}

/* On the cream section the ring has to darken, not lighten. */
.bg-cream :where(a, button, input, select, textarea):focus-visible {
	outline-color: var(--struxa-ink);
}

/* Focus rings on a rounded card should follow the card. */
.collection-tile:focus-visible,
.svc-card:focus-visible,
.wd-product a:focus-visible {
	border-radius: var(--r-lg);
}

/* Keyboard skip target. */
.sr-only {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* The gold-on-black link colour sits at roughly 5.9:1, which passes for
   body text but not for the 11px labels it was also used on. Small gold
   labels are lifted to the brighter step. */
.text-gold.text-\[10px\],
.text-gold.text-\[11px\],
.tile-eyebrow,
.svc-eyebrow {
	color: var(--struxa-gold-hi);
}

/* ==========================================================================
   15. REDUCED MOTION
   Every animation on the site is opt-out in one place.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	[data-reveal],
	[data-reveal="grow"],
	[data-reveal="circle"],
	[data-reveal="wipe-up"],
	.collection-tile,
	.hero-intro > * {
		opacity: 1 !important;
		transform: none !important;
		clip-path: none !important;
		-webkit-clip-path: none !important;
	}
}

/* ==========================================================================
   16. SMALL SCREENS
   --------------------------------------------------------------------------
   Nothing here restructures a layout — the breakpoints in the templates
   still own that. These are the density adjustments that keep the new type
   ramp and spacing honest on a phone.
   ========================================================================== */

@media (max-width: 767px) {
	:root {
		--section-y: clamp(64px, 14vw, 96px);
		--section-y-tight: 48px;
		--tr-label: 0.24em;
	}

	/* A 52px pill is comfortable in a row of two; stacked full-width it
	   reads as a slab. */
	.masthead__cta,
	.lg-btn {
		min-height: 50px;
		width: 100%;
	}

	.masthead__actions {
		gap: var(--sp-3);
	}

	/* Wide caps tracking costs a phone roughly four characters per line,
	   which is where the proof row started wrapping mid-phrase. */
	.masthead__proof {
		font-size: 0.6875rem;
		letter-spacing: 0.16em;
	}

	/* The breadcrumb's last crumb is the product you are already looking
	   at, set in bold white — on a phone it wrapped the trail onto two
	   lines to repeat the title that appears 40px below it. Kept to one
	   line, with the trail ellipsised rather than the page reflowed. */
	.woocommerce-breadcrumb {
		display: flex;
		align-items: baseline;
		gap: 0;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		font-size: 11px !important;
	}

	.woocommerce .shop-loop-head {
		gap: var(--sp-3) !important;
		padding-bottom: var(--sp-4);
		margin-bottom: var(--sp-5) !important;
	}

	.wd-product .product-element-bottom,
	.wd-product .product-information {
		padding: var(--sp-4);
		gap: 6px;
	}

	.wd-product .wd-entities-title { font-size: 1.0625rem !important; }

	/* Two cards across a phone is roughly 165px of usable width. At that
	   size a three-line category, a wrapping price range and a two-line
	   button turn the card into a wall of text.

	   THE CATEGORY LINE GOES ENTIRELY.
	   It was being truncated to "OUTDOOR LIVING & W…" on every single tile,
	   which reads as a rendering fault rather than as information — and on a
	   category archive it is repeating the name of the page the visitor is
	   already looking at, on every card. It is the clearest case of text
	   that is costing space and returning nothing. The title and the price
	   are what someone scanning a grid on a phone actually needs. */
	.wd-product .wd-product-cats { display: none; }

	.wd-product .price,
	.wd-product .price .amount {
		font-size: 0.9375rem !important;
		line-height: 1.35 !important;
	}

	/* A price range ("$1,399.00 – $3,191.90") is the one thing here that
	   genuinely needs two lines at this width; letting it break at the dash
	   rather than mid-figure keeps it readable. */
	.wd-product .price { text-wrap: balance; }

	.wd-product .hover-content-inner,
	.wd-product .wd-more-desc-inner { display: none; }

	.wd-product .button.add_to_cart_button,
	.wd-product .add_to_cart_button,
	.wd-product .product_type_variable,
	.wd-product .product_type_simple {
		font-size: 0.8125rem !important;
		padding: 0 var(--sp-3) !important;
		white-space: nowrap;
	}

	/* Two product cards across on a phone leaves ~160px per card; the
	   action row can't hold a pill and two icon buttons at that width.
	   The add-to-cart pill keeps the row; wishlist and quick-view are both
	   available on the product page itself. */
	.wd-product .wrap-wishlist-button,
	.wd-product .wrap-quickview-button { display: none; }
}

@media (max-width: 479px) {
	.struxa-tw .grid-cols-2.gap-x-6 { gap: var(--sp-5); }
}

/* ==========================================================================
   17. PRINT
   ========================================================================== */

@media print {
	.whb-header,
	.wd-footer,
	chat-widget,
	.masthead__dots,
	.masthead__scroll { display: none !important; }

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