/*
Theme Name: Texofil
Theme URI: https://www.texofil.com/
Author: Texofil
Author URI: https://www.texofil.com/
Description: Custom classic theme for Texofil — yarn supply to knitters and manufacturers since 1940, Beirut. Four pages, bilingual English/Arabic, no page builder, no jQuery.
Version: 1.0.0
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: texofil
Tags: custom-menu, translation-ready, rtl-language-support, one-column
*/

/* ==========================================================================
   0. FONTS — IBM Plex, self-hosted. Zero external requests.
   SIL Open Font License 1.1; see assets/fonts/LICENSE-IBMPlex.txt.

   Latin is a single VARIABLE file covering every weight from 300 to 600 in
   68KB — one request for the whole typographic system. The Latin-1 subset is
   deliberate: it carries everything the English copy needs, accents included
   (é, í, ñ and the like), without the Cyrillic and Greek we will never set.

   Arabic ships as four static weights matching the Latin scale. Browsers only
   download a face they actually render, and Arabic is referenced solely from
   rtl.css — so an English visitor never fetches a single byte of it.
   ========================================================================== */

@font-face {
	font-family: "IBM Plex Sans";
	src: url("assets/fonts/IBMPlexSansVar-Roman-Latin1.woff2") format("woff2");
	font-weight: 300 600;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "IBM Plex Sans Arabic";
	src: url("assets/fonts/IBMPlexSansArabic-Light.woff2") format("woff2");
	font-weight: 300;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "IBM Plex Sans Arabic";
	src: url("assets/fonts/IBMPlexSansArabic-Regular.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "IBM Plex Sans Arabic";
	src: url("assets/fonts/IBMPlexSansArabic-Medium.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: "IBM Plex Sans Arabic";
	src: url("assets/fonts/IBMPlexSansArabic-SemiBold.woff2") format("woff2");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}

/* ==========================================================================
   1. DESIGN TOKENS
   Values come from the Stripe UI/UX spec (§2 grid, §4 colour, §5 elevation).
   ONE accent: the gold sampled from the Texofil logo (#74612F). Secondary
   actions use the navy ink ramp, not a second hue. Bordeaux survives only as
   the error colour. Never introduce another accent.
   ========================================================================== */

:root {
	/* The site is light-only by decision. Declaring this stops browsers on a
	   dark-mode phone from auto-inverting form controls and select menus. */
	color-scheme: only light;

	/* --- Accent: gold, sampled from the logo lockup (#74612F).
	       It is DARK (hsl 43° 42% 32%), so filled gold surfaces carry WHITE text
	       at 6.0:1. Dark ink on it would be 2.6:1 and fail. Hover goes DARKER,
	       not lighter: lightening a dark fill under white text loses contrast. --- */
	--brand: #74612f;          /* white on it 6.01:1 */
	--brand-hover: #69582b;    /* white on it 6.93:1 */
	--brand-press: #5e4f26;    /* white on it 8.01:1 */
	--brand-subtle: #f8f6ef;   /* pale wash; gold text on it 5.56:1 */
	--brand-tint: #e6e0d1;     /* hairlines on gold-tinted surfaces */
	--on-brand: #ffffff;

	/* --- Secondary: the navy ink ramp, not a second hue. Navy outline buttons
	       recede behind the gold primary, so hierarchy comes from fill versus
	       outline. (A bordeaux secondary sat only 1.9:1 from the logo gold in
	       lightness and read as two competing browns.) --- */
	--secondary: #0d253d;
	--secondary-hover: #273951;
	--secondary-press: #061b31;
	--secondary-subtle: #f0f2f3;

	/* --- THIRD-PARTY BRAND COLOUR, NOT PART OF THE TEXOFIL PALETTE ---
	       WhatsApp's own green, used ONLY on the floating WhatsApp button so it
	       reads as WhatsApp at a glance. Kept separate on purpose: a future
	       palette change must never alter it, and it must never be used for
	       anything else. White glyph on it: 1.98:1 (see contact-widgets.php). --- */
	--whatsapp-green: #25d366;
	--whatsapp-green-hover: #1ebe5b;

	/* --- Danger: error states only. Never on buttons, links or tags. --- */
	--danger: #6d1b2c;         /* 11.39:1 on white */
	--danger-subtle: #f7e8ea;

	/* --- Ink. Never pure black; navy-tinted for "soft but authoritative". --- */
	--ink: #0d253d;
	--ink-secondary: #273951;
	--ink-muted: #586780; /* 5.40:1 on the warm tint; #64748d measured 4.47 and failed */

	/* --- Surfaces. Alternating white / pale tint creates the page's
	       "chapters" without ever drawing a horizontal rule. --- */
	--surface: #ffffff;
	/* Warm off-white, chosen to sit with the earthy logo gold. The spec's cool
	   #f6f9fc read slightly "tech" against it. */
	--surface-alt: #faf8f3;
	--border: #e3e8ee;

	/* --- Spacing scale. Use these only; never arbitrary pixel values. --- */
	--sp-4: 4px;
	--sp-8: 8px;
	--sp-12: 12px;
	--sp-16: 16px;
	--sp-20: 20px;
	--sp-24: 24px;
	--sp-32: 32px;
	--sp-40: 40px;
	--sp-44: 44px;
	--sp-64: 64px;
	--sp-96: 96px;

	/* Section vertical rhythm. Tightened at the owner's request from the spec's
	   96–160px: the old clamp(48px, 8vw, 120px) left over 200px of empty space
	   between the content of adjacent sections on a desktop. */
	--section-y: clamp(40px, 5.5vw, 80px);
	--section-y-lg: clamp(48px, 7vw, 104px);

	/* --- Radius --- */
	--radius-sm: 6px;
	--radius-card: 12px;
	--radius-pill: 100px;

	/* --- Elevation. Flat-to-minimal: hairline borders do most of the
	       separating; shadows are only for things genuinely above the page. --- */
	--shadow-card: 0 3px 6px rgba(0, 0, 0, 0.06);
	--shadow-lift: 0 15px 35px rgba(0, 0, 0, 0.08);
	--shadow-menu: 0 16px 32px rgba(50, 50, 93, 0.12);
	/* Focus: a SOLID 2px gold ring with a 2px gap. A translucent gold halo, as
	   the spec describes, measures 1.67:1 against white and fails WCAG 1.4.11.
	   Solid gold measures 5.56 to 6.01:1 on every surface it appears on. */
	--focus-width: 2px;
	--focus-offset: 2px;

	/* --- Layout --- */
	--container: 1280px;
	--gutter: 24px;
	--measure: 68ch; /* body copy capped at 60–70 characters */

	/* --- Motion. Micro-interactions only: no ambient animation anywhere. --- */
	--t-fast: 150ms;
	--t-med: 200ms;
	--ease: cubic-bezier(0.2, 0.6, 0.35, 1);

	/* --- Type. One family for headings and body. The Arabic companion is
	       metrically harmonised with the Latin, so the two can share a stack. --- */
	--font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
		Roboto, Helvetica, Arial, sans-serif;
	--font-arabic: "IBM Plex Sans Arabic", "IBM Plex Sans", -apple-system,
		BlinkMacSystemFont, "Segoe UI", Tahoma, Arial, sans-serif;
}

@media (min-width: 940px) {
	:root {
		--gutter: 32px;
	}
}

/* ==========================================================================
   2. RESET
   ========================================================================== */

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

* {
	margin: 0;
}

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

body {
	/* Set explicitly rather than inherited: a transparent body would borrow
	   the host's colour on a dark-mode device. */
	background-color: var(--surface);
	color: var(--ink);
	font-family: var(--font-sans);
	font-size: 16px;
	line-height: 1.5;
	font-weight: 400;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	min-height: 100vh;
}

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

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

button {
	background: none;
	border: 0;
	cursor: pointer;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
	overflow-wrap: break-word;
}

ul,
ol {
	padding: 0;
}

/* ==========================================================================
   3. TYPOGRAPHY
   Two rules matter as much as the sizes: tracking tightens as size grows and
   loosens as size shrinks, and weight — not only size — marks hierarchy. The
   hero is the largest text on the page *and* the lightest.
   ========================================================================== */

h1,
h2,
h3,
h4 {
	color: var(--ink);
	text-wrap: balance; /* stops multi-line headings orphaning a short word */
}

.t-display {
	font-size: clamp(34px, 5vw, 56px);
	font-weight: 300;
	line-height: 1.03;
	letter-spacing: -0.02em;
}

.t-h1 {
	font-size: clamp(26px, 3.2vw, 32px);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.t-h2 {
	font-size: clamp(22px, 2.6vw, 26px);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.t-h3 {
	font-size: clamp(19px, 2vw, 22px);
	font-weight: 400;
	line-height: 1.3;
}

.t-body {
	font-size: 16px;
	line-height: 1.5;
}

.t-lead {
	font-size: clamp(17px, 1.6vw, 19px);
	line-height: 1.5;
	color: var(--ink-secondary);
}

.t-small {
	font-size: 14px;
	line-height: 1.3;
}

/* Micro label / eyebrow — tracking pushed looser, the opposite of headings. */
.t-eyebrow {
	font-size: 11px;
	font-weight: 500;
	line-height: 1.4;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--ink-muted);
}

/* Any stat, price or counter: stops digits jittering between values. */
.t-tabular {
	font-variant-numeric: tabular-nums;
}

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

.t-secondary {
	color: var(--ink-secondary);
}

/* Long-form prose: capped measure, comfortable leading. */
.prose {
	max-width: var(--measure);
	color: var(--ink-secondary);
}

.prose > * + * {
	margin-top: var(--sp-20);
}

.prose strong {
	color: var(--ink);
	font-weight: 600;
}

/* ==========================================================================
   4. LINKS
   Links are gold, the single accent: 6.01:1 on white and 5.66:1 on the warm
   section tint. Underlined, so colour is never the only cue.
   ========================================================================== */

a {
	color: var(--brand);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
	transition: color var(--t-fast) var(--ease);
}

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

a:active {
	color: var(--brand-press);
}

/* ==========================================================================
   5. FOCUS
   Always visible, never suppressed for mouse users.
   ========================================================================== */

:focus-visible {
	outline: var(--focus-width) solid var(--brand);
	outline-offset: var(--focus-offset);
	border-radius: var(--radius-sm);
}

/* The offset gap means the ring sits on the page, not on the button's own
   fill, so a gold ring stays visible around a gold button. */
.btn:focus-visible {
	outline: var(--focus-width) solid var(--brand);
	outline-offset: var(--focus-offset);
}

/* ==========================================================================
   6. LAYOUT PRIMITIVES
   ========================================================================== */

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

/* Alternating full-bleed background colour is the site's only chapter
   divider — never a horizontal rule. */
.section {
	padding-block: var(--section-y);
}

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

.section--alt {
	background-color: var(--surface-alt);
}

.section__head {
	max-width: var(--measure);
	margin-bottom: var(--sp-32);
}

.section__head > * + * {
	margin-top: var(--sp-16);
}

.stack > * + * {
	margin-top: var(--sp-16);
}

.stack-lg > * + * {
	margin-top: var(--sp-24);
}

.cluster {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-16);
}

/* ==========================================================================
   7. BUTTONS
   Three tiers. One primary per visual band — never two competing side by side.
   Contrast rules are inverted between the two accents and both are enforced
   here: dark ink on gold fills, white on bordeaux fills.
   ========================================================================== */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-8);
	padding: var(--sp-12) var(--sp-24);
	min-height: 44px; /* comfortable tap target */
	border: 1px solid transparent;
	border-radius: var(--radius-pill);
	font-size: 15px;
	font-weight: 500;
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--t-fast) var(--ease),
		border-color var(--t-fast) var(--ease),
		color var(--t-fast) var(--ease),
		box-shadow var(--t-fast) var(--ease);
}

/* Primary — gold fill, WHITE text. The logo gold is dark: white measures
   6.01:1 on it; the old dark-ink rule would measure 2.59:1 and fail. */
.btn--primary {
	background-color: var(--brand);
	color: var(--on-brand);
	border-color: var(--brand);
}

.btn--primary:hover {
	background-color: var(--brand-hover);
	border-color: var(--brand-hover);
	color: var(--on-brand);
}

.btn--primary:active {
	background-color: var(--brand-press);
	border-color: var(--brand-press);
	color: var(--on-brand);
}

/* Secondary — transparent fill, navy border and text. It recedes behind the
   gold primary: hierarchy comes from filled versus outlined. */
.btn--secondary {
	background-color: transparent;
	color: var(--secondary);
	border-color: var(--secondary);
}

.btn--secondary:hover {
	background-color: var(--secondary-subtle);
	color: var(--secondary-press);
	border-color: var(--secondary);
}

.btn--secondary:active {
	background-color: var(--secondary-subtle);
	color: var(--secondary-press);
	border-color: var(--secondary-press);
}

/* Ghost / text — tertiary inline actions. */
.btn--ghost {
	padding-inline: 0;
	background: none;
	border-color: transparent;
	color: var(--brand);
	min-height: 0;
}

.btn--ghost:hover {
	color: var(--brand-hover);
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

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

/* ==========================================================================
   8. TAGS / CHIPS
   Pale gold wash, gold text (5.56:1) and a tinted hairline.
   ========================================================================== */

.tag {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-8);
	padding: var(--sp-4) var(--sp-12);
	border-radius: var(--radius-pill);
	background-color: var(--brand-subtle);
	color: var(--brand);
	border: 1px solid var(--brand-tint);
	font-size: 13px;
	font-weight: 500;
	line-height: 1.3;
}

/* ==========================================================================
   9. ACCESSIBILITY HELPERS
   ========================================================================== */

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

.skip-link {
	position: absolute;
	inset-inline-start: var(--sp-16);
	top: -100px;
	z-index: 999;
	padding: var(--sp-12) var(--sp-20);
	background-color: var(--surface);
	color: var(--ink);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-menu);
	text-decoration: none;
	transition: top var(--t-fast) var(--ease);
}

.skip-link:focus {
	top: var(--sp-16);
}

/* Motion is micro-interaction only, but honour the preference regardless. */
@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;
	}
}

/* ==========================================================================
   10. SITE HEADER
   Slim, white, with a hairline bottom border. Logo left, menu centre-left,
   the two-tier CTA pair far right — one loud gold, one quiet bordeaux.
   ========================================================================== */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background-color: var(--surface);
	border-bottom: 1px solid var(--border);
}

.site-header__inner {
	display: flex;
	align-items: center;
	gap: var(--sp-24);
	min-height: 68px;
}

.site-header__brand {
	flex-shrink: 0;
}

.site-brand {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	color: var(--ink);
}

.site-brand__name {
	font-size: 21px;
	font-weight: 600;
	letter-spacing: -0.01em;
	text-transform: uppercase;
}

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

.custom-logo {
	max-height: 44px;
	width: auto;
}

/* --- The nav panel: a flex row on desktop, a slide-down sheet on mobile --- */

.site-nav {
	display: flex;
	flex: 1;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-24);
}

.site-nav__list {
	display: flex;
	align-items: center;
	gap: var(--sp-32);
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-nav__list a {
	display: inline-block;
	padding-block: var(--sp-8);
	color: var(--ink-secondary);
	font-size: 15px;
	text-decoration: none;
	border-bottom: 2px solid transparent;
	transition: color var(--t-fast) var(--ease),
		border-color var(--t-fast) var(--ease);
}

.site-nav__list a:hover {
	color: var(--ink);
}

/* Gold underline marks the current page — one of the few places gold is
   allowed outside a primary button. */
.site-nav__list .current-menu-item > a,
.site-nav__list .current_page_item > a {
	color: var(--ink);
	border-bottom-color: var(--brand);
}

.site-nav__cta {
	display: flex;
	align-items: center;
	gap: var(--sp-16);
}


/* --- Mobile toggle --- */

.nav-toggle {
	display: none;
	margin-inline-start: auto;
	padding: var(--sp-12);
	border-radius: var(--radius-sm);
}

.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
	display: block;
	width: 22px;
	height: 2px;
	background-color: var(--ink);
	border-radius: 2px;
	transition: transform var(--t-med) var(--ease),
		opacity var(--t-fast) var(--ease);
}

.nav-toggle__bars {
	position: relative;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
	content: "";
	position: absolute;
	inset-inline-start: 0;
}

.nav-toggle__bars::before {
	top: -7px;
}

.nav-toggle__bars::after {
	top: 7px;
}

.nav-open .nav-toggle__bars {
	background-color: transparent;
}

.nav-open .nav-toggle__bars::before {
	transform: translateY(7px) rotate(45deg);
}

.nav-open .nav-toggle__bars::after {
	transform: translateY(-7px) rotate(-45deg);
}

@media (max-width: 939px) {
	.nav-toggle {
		display: block;
	}

	/*
	 * Only collapse the panel once JavaScript has confirmed it can reopen it.
	 * With scripts blocked the menu stays visible rather than becoming a
	 * button that does nothing.
	 */
	.has-js .site-nav {
		display: none;
	}

	.has-js .nav-open .site-nav,
	.nav-open .site-nav {
		display: flex;
		position: absolute;
		inset-inline: 0;
		top: 100%;
		flex-direction: column;
		align-items: stretch;
		gap: var(--sp-24);
		padding: var(--sp-24) var(--gutter) var(--sp-32);
		background-color: var(--surface);
		border-bottom: 1px solid var(--border);
		box-shadow: var(--shadow-menu);
	}

	.site-nav__list {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
	}

	.site-nav__list li + li {
		border-top: 1px solid var(--border);
	}

	.site-nav__list a {
		padding-block: var(--sp-16);
		font-size: 17px;
		border-bottom: 0;
	}

	.site-nav__list .current-menu-item > a,
	.site-nav__list .current_page_item > a {
		color: var(--brand);
		font-weight: 500;
	}

	/* CTAs stack full-width at the bottom of the mobile sheet. */
	.site-nav__cta {
		flex-direction: column-reverse;
		align-items: stretch;
		gap: var(--sp-12);
	}

	.site-nav__cta .btn {
		width: 100%;
	}

}

@media (max-width: 939px) {
	.site-header__inner {
		position: relative;
		justify-content: space-between;
	}
}

/* ==========================================================================
   11. CARDS
   Hairline border, faint resting shadow, a small lift on hover.
   ========================================================================== */

.card {
	display: flex;
	flex-direction: column;
	padding: var(--sp-32);
	background-color: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-card);
	box-shadow: var(--shadow-card);
	transition: transform var(--t-med) var(--ease),
		box-shadow var(--t-med) var(--ease);
}

.card > * + * {
	margin-top: var(--sp-12);
}

.card--link:hover {
	transform: translateY(-3px);
	box-shadow: var(--shadow-lift);
}

.card__title {
	font-size: 20px;
	font-weight: 500;
	line-height: 1.3;
	color: var(--ink);
}

.card__desc {
	color: var(--ink-secondary);
	font-size: 15px;
	line-height: 1.5;
}

/* ==========================================================================
   12. SITE FOOTER
   Three columns, not Stripe's six — there is no link directory to fill.
   ========================================================================== */

.site-footer {
	padding-block: var(--sp-44) var(--sp-24);
	background-color: var(--surface-alt);
	border-top: 1px solid var(--border);
}

.site-footer__grid {
	display: grid;
	gap: var(--sp-40);
	grid-template-columns: 1fr;
}

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

@media (min-width: 940px) {
	.site-footer__grid {
		grid-template-columns: 1.4fr 1fr 1.2fr;
		gap: var(--sp-64);
	}
}

.site-footer__heading {
	margin-bottom: var(--sp-16);
	font-size: 11px;
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--ink-muted);
}

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

.site-footer__list li + li {
	margin-top: var(--sp-12);
}

.site-footer__list a,
.site-footer address a {
	color: var(--ink-secondary);
	font-size: 15px;
	text-decoration: none;
}

.site-footer__list a:hover,
.site-footer address a:hover {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.site-footer address {
	font-style: normal;
	font-size: 15px;
	line-height: 1.6;
	color: var(--ink-secondary);
}

.site-footer address > * + * {
	margin-top: var(--sp-12);
}

.site-footer__tel {
	font-variant-numeric: tabular-nums;
}

.site-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-16);
	margin-top: var(--sp-40);
	padding-top: var(--sp-24);
	border-top: 1px solid var(--border);
}

/* Polylang language switcher, rendered by the plugin as a plain <ul>. */
.site-footer__lang ul {
	display: flex;
	gap: var(--sp-16);
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-footer__lang a {
	color: var(--ink-muted);
	font-size: 14px;
	text-decoration: none;
}

.site-footer__lang a:hover,
.site-footer__lang .current-lang a {
	color: var(--brand);
}

/* ==========================================================================
   13. THREAD MOTIF
   The site's one decorative device: fine yarn strands, reused everywhere a
   flourish is needed. Never introduce a second illustration style.
   ========================================================================== */

.thread-motif {
	display: block;
	width: 100%;
	height: 100%;
}

.thread-motif__strand {
	stroke-width: 1.25;
	vector-effect: non-scaling-stroke;
}

/* The logo gold is dark, so the strands sit well back: a faint trace of
   thread behind the copy, not a drawing competing with it. */
.thread-motif__strand--gold {
	stroke: var(--brand);
	opacity: 0.32;
}

.thread-motif__strand--ink {
	stroke: var(--secondary);
	opacity: 0.1;
}

/* Behind hero copy: sits low, never competing with the text above it. */
.thread-motif--hero {
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	height: 62%;
	pointer-events: none;
	z-index: 0;
}

/* ==========================================================================
   14. FORMS
   Deliberately plain and short. Every extra field costs an enquiry, and this
   form is the point of the entire site.
   ========================================================================== */

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

.form-grid {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

@media (min-width: 640px) {
	.form-grid {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--sp-24);
	}

	.field-row--full {
		grid-column: 1 / -1;
	}
}

.field-row {
	display: flex;
	flex-direction: column;
	gap: var(--sp-8);
	margin: 0;
}

.field-label {
	font-size: 14px;
	font-weight: 500;
	color: var(--ink);
}

.field-req {
	color: var(--brand);
}

.field {
	width: 100%;
	padding: var(--sp-12) var(--sp-16);
	background-color: var(--surface);
	color: var(--ink);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-size: 16px; /* 16px stops iOS zooming the page on focus */
	line-height: 1.4;
	transition: border-color var(--t-fast) var(--ease),
		box-shadow var(--t-fast) var(--ease);
}

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

.field:hover {
	border-color: var(--ink-muted);
}

.field:focus {
	outline: none;
	border-color: var(--brand);
	box-shadow: 0 0 0 1px var(--brand); /* 2px solid gold edge in total */
}

.field--textarea {
	min-height: 150px;
	resize: vertical;
}

.field--error {
	border-color: var(--danger);
}

.field-error {
	color: var(--danger);
	font-size: 14px;
	font-weight: 500;
}

.field-hint {
	color: var(--ink-muted);
	font-size: 14px;
	line-height: 1.4;
}

.form-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-16);
	margin-top: var(--sp-32);
}

/*
 * Honeypot. Moved off-screen rather than display:none — some bots skip fields
 * that are explicitly hidden, but happily fill one that is merely positioned
 * away.
 */
.form-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.form-message {
	margin-bottom: var(--sp-32);
	padding: var(--sp-20) var(--sp-24);
	border: 1px solid var(--border);
	border-radius: var(--radius-card);
}

.form-message > * + * {
	margin-top: var(--sp-8);
}

.form-message--success {
	background-color: var(--brand-subtle);
	border-color: var(--brand);
}

.form-message--error {
	background-color: var(--danger-subtle);
	border-color: var(--danger);
	color: var(--danger);
}

/* ==========================================================================
   15. PAGE HERO + CONTACT CARDS
   ========================================================================== */

.page-hero {
	padding-block: clamp(32px, 4.5vw, 64px) clamp(24px, 3vw, 40px);
}

.contact-grid {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

@media (min-width: 640px) {
	.contact-grid {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--sp-24);
	}
}

@media (min-width: 940px) {
	.contact-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

.contact-card {
	gap: var(--sp-8);
	text-decoration: none;
	color: var(--ink);
}

a.contact-card:hover {
	color: var(--ink);
}

.contact-card__value {
	font-size: 21px;
	font-weight: 400;
	line-height: 1.3;
	color: var(--ink);
	word-break: break-word;
}

a.contact-card:hover .contact-card__value {
	color: var(--brand);
}

.contact-card__alt {
	font-size: 15px;
	color: var(--ink-muted);
	line-height: 1.5;
}

.contact-card address {
	display: flex;
	flex-direction: column;
	gap: var(--sp-8);
	font-style: normal;
	font-size: 15px;
	line-height: 1.6;
	color: var(--ink-secondary);
}

.contact-card--address {
	align-items: flex-start;
}

/* ==========================================================================
   16. HERO
   Left-aligned, light-weight display type, the thread motif sitting low
   behind it at an opacity that never competes with the copy.
   ========================================================================== */

.hero {
	position: relative;
	overflow: hidden;
	padding-block: clamp(48px, 7vw, 96px);
	background-color: var(--surface);
}

.hero__inner {
	position: relative;
	z-index: 1;
}

.hero__title {
	max-width: 18ch;
	margin-top: var(--sp-20);
}

.hero__lead {
	max-width: 58ch;
	margin-top: var(--sp-24);
}

.hero__actions {
	margin-top: var(--sp-40);
}

/* ==========================================================================
   17. KPI BAND
   No icons. A medium-weight figure with tight tracking over a short label,
   a hairline rule above each stat with a 32px gold accent at its leading
   edge, and every stat left-aligned on the page grid — the same left edge as
   every heading on the page.
   ========================================================================== */

.stat-band {
	padding-block: clamp(36px, 4.5vw, 64px);
}

.stat-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--sp-32) var(--sp-24);
	margin: 0;
}

@media (min-width: 940px) {
	.stat-grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: var(--sp-32);
	}
}

.stat {
	position: relative;
	padding-top: var(--sp-20);
	border-top: 1px solid var(--border);
}

/* The short gold accent sitting on the rule. */
.stat::before {
	content: "";
	position: absolute;
	top: -1px;
	inset-inline-start: 0;
	width: 32px;
	height: 2px;
	background-color: var(--brand);
}

.stat__figure {
	font-size: clamp(36px, 4.2vw, 56px);
	font-weight: 500;
	line-height: 1;
	letter-spacing: -0.035em;
	color: var(--ink);
	white-space: nowrap;
}

.stat__suffix {
	margin-inline-start: 0.02em;
	color: var(--brand);
	font-weight: 400;
}

.stat__label {
	margin: var(--sp-12) 0 0;
	max-width: 26ch;
	color: var(--ink-secondary);
	font-size: 15px;
	font-weight: 400;
	line-height: 1.4;
	text-wrap: balance;
}

/* ==========================================================================
   18. BENTO GRID
   Asymmetric: one tall feature card beside two stacked smaller ones.
   ========================================================================== */

.bento {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

@media (min-width: 940px) {
	.bento {
		grid-template-columns: 1.35fr 1fr;
		gap: var(--sp-24);
	}

	.bento__feature {
		grid-row: span 2;
	}
}

.bento__more {
	margin-top: auto;
	padding-top: var(--sp-20);
}

.fibre-chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-8);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* ==========================================================================
   19. PARTNER GRID (suppliers)
   Flag, name, what the mill is known for, country. The flag is a quiet signal
   beside the name — small, hairline-edged so its white stripes hold on a pale
   background — never decoration. The country is always also there as text.
   ========================================================================== */

.partner-grid {
	display: grid;
	gap: 0;
	grid-template-columns: 1fr;
	margin: 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid var(--border);
}

@media (min-width: 640px) {
	.partner-grid {
		grid-template-columns: repeat(2, 1fr);
		column-gap: var(--sp-40);
	}
}

@media (min-width: 940px) {
	.partner-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

.partner {
	--flag-w: 21px;
	--flag-gap: var(--sp-12);
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	padding-block: var(--sp-20);
	border-bottom: 1px solid var(--border);
}

.partner__head {
	display: flex;
	align-items: baseline;
	gap: var(--flag-gap);
}

.flag {
	flex-shrink: 0;
	width: var(--flag-w);
	height: 14px;
	border-radius: 2px;
	box-shadow: 0 0 0 1px rgba(13, 37, 61, 0.16);
	/* Sit on the name's first line rather than its baseline. */
	transform: translateY(1px);
}

.partner__name {
	font-size: 17px;
	font-weight: 500;
	color: var(--ink);
	line-height: 1.3;
}

/* Description and country align under the name, not under the flag. */
.partner__desc,
.partner__country {
	padding-inline-start: calc(var(--flag-w) + var(--flag-gap));
}

.partner__desc {
	color: var(--ink-secondary);
	font-size: 15px;
	line-height: 1.4;
}

.partner__country {
	color: var(--ink-muted);
	font-size: 13px;
	line-height: 1.4;
}

.partner--more {
	justify-content: center;
}

.partner--more .partner__name {
	padding-inline-start: calc(var(--flag-w) + var(--flag-gap));
	color: var(--ink-muted);
	font-weight: 400;
	font-style: italic;
}

/* ==========================================================================
   20. PROCESS
   ========================================================================== */

.process {
	display: grid;
	gap: var(--sp-32);
	grid-template-columns: 1fr;
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: step;
}

@media (min-width: 768px) {
	.process {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--sp-40);
	}
}

.process__step {
	padding-top: var(--sp-20);
	border-top: 2px solid var(--brand);
}

.process__num {
	display: block;
	font-size: 13px;
	font-weight: 600;
	color: var(--brand);
	letter-spacing: 0.08em;
}

.process__title {
	margin-top: var(--sp-12);
	font-size: 19px;
	font-weight: 500;
	line-height: 1.3;
}

.process__desc {
	margin-top: var(--sp-8);
	color: var(--ink-secondary);
	font-size: 15px;
	line-height: 1.5;
}

/* ==========================================================================
   21. CLOSING CTA BAND
   ========================================================================== */

.cta-band {
	background-color: var(--surface-alt);
	border-top: 1px solid var(--border);
	padding-block: clamp(40px, 5vw, 72px);
}

.cta-band__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-32);
}

.cta-band__copy {
	max-width: 46ch;
}

.cta-band__copy > * + * {
	margin-top: var(--sp-16);
}

.cta-band__actions {
	flex-shrink: 0;
}

/* ==========================================================================
   22. CARD ROW / FIBRE GRID / COUNTRY LIST
   ========================================================================== */

.card-row {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

@media (min-width: 768px) {
	.card-row {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--sp-24);
	}
}

.fibre-grid {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

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

@media (min-width: 940px) {
	.fibre-grid {
		grid-template-columns: repeat(4, 1fr);
		gap: var(--sp-24);
	}
}

.fibre {
	padding: var(--sp-24);
}

.fibre__name {
	font-size: 18px;
	font-weight: 500;
	line-height: 1.3;
	color: var(--ink);
}

.country-list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-12);
	margin: 0;
	padding: 0;
	list-style: none;
}

.country {
	padding: var(--sp-12) var(--sp-20);
	background-color: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-pill);
	font-size: 16px;
	color: var(--ink);
}


/* Sticky header would otherwise cover the target of an anchor link. */
[id="range"],
[id="mills"],
[id="contact-form"] {
	scroll-margin-top: 88px;
}

/* The approved hero line is one <h1>; its last sentence is set as a quieter
   second line so the display size can stay large without wrapping to five
   lines. Same heading, same words — only the typographic weight differs. */
.hero__title-sub {
	display: block;
	margin-top: var(--sp-12);
	font-size: 0.5em;
	font-weight: 400;
	line-height: 1.25;
	letter-spacing: -0.005em;
	color: var(--ink-secondary);
}

/* ==========================================================================
   23. LOGO
   The horizontal lockup, served at 600px wide so it stays sharp on high-
   density screens while displaying at around 180px.
   ========================================================================== */

.site-logo {
	display: block;
	max-width: none;
	width: auto;
}

.site-logo--header {
	height: 34px;
}

@media (min-width: 640px) {
	.site-logo--header {
		height: 40px;
	}
}

.site-logo--footer {
	height: 30px;
}

/* ==========================================================================
   24. DARK SECTIONS (.on-dark)
   The hero photographs and the CTA band image are dark navy. Inside them:
   - text is white;
   - the navy secondary button would vanish, so it becomes a white outline;
   - the gold focus ring measures only 2.9:1 against navy, so it becomes white
     (over 15:1);
   - gold link text would fail on navy, so links use the pale gold tint.
   ========================================================================== */

.on-dark {
	--on-dark-muted: #d3d8de;
	color: #ffffff;
}

.on-dark h1,
.on-dark h2,
.on-dark h3 {
	color: #ffffff;
}

.on-dark .t-eyebrow {
	color: var(--brand-tint);
}

.on-dark .t-lead,
.on-dark .hero__title-sub {
	color: var(--on-dark-muted);
}

.on-dark a:not(.btn) {
	color: var(--brand-tint);
}

.on-dark .btn--secondary {
	color: #ffffff;
	border-color: #ffffff;
	background-color: transparent;
}

.on-dark .btn--secondary:hover,
.on-dark .btn--secondary:active {
	color: #ffffff;
	border-color: #ffffff;
	background-color: rgba(255, 255, 255, 0.14);
}

.on-dark :focus-visible,
.on-dark .btn:focus-visible {
	outline-color: #ffffff;
}

/* ==========================================================================
   25. IMAGE HERO (homepage)
   Headline over the left third; the photograph's subject sits right. A navy
   gradient guarantees the white text's contrast wherever the image crops.
   ========================================================================== */

.hero--image {
	display: flex;
	align-items: center;
	min-height: clamp(540px, 78vh, 760px);
	background-color: #0b1623; /* shown while the photo loads */
}

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

.hero__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 72% center;
}

.hero__media::after {
	content: "";
	position: absolute;
	inset: 0;
	/* Small screens: the photo crops under the text, so darken it evenly. */
	background: rgba(8, 18, 30, 0.74);
}

@media (min-width: 940px) {
	.hero__media::after {
		background: linear-gradient(
			90deg,
			rgba(8, 18, 30, 0.92) 0%,
			rgba(8, 18, 30, 0.85) 34%,
			rgba(8, 18, 30, 0.3) 62%,
			rgba(8, 18, 30, 0) 82%
		);
	}
}

.hero--image .hero__inner {
	position: relative;
	z-index: 1;
}

.hero--image .hero__title,
.hero--image .hero__lead {
	max-width: 30rem;
}

@media (min-width: 940px) {
	.hero--image .hero__title {
		max-width: 34rem;
	}
}

/* ==========================================================================
   26. PAGE HEROES WITHOUT A PHOTO
   Carry the thread motif, so the signature device appears on every page.
   ========================================================================== */

.page-hero {
	position: relative;
	overflow: hidden;
}

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

.page-hero .thread-motif--hero {
	height: 70%;
}

/* ==========================================================================
   27. CARDS WITH PHOTOGRAPHS
   ========================================================================== */

.card--media {
	padding: 0;
	overflow: hidden;
}

.card--media > * + * {
	margin-top: 0;
}

.card__media {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	background-color: var(--surface-alt);
}

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

.card__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.card__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: var(--sp-12);
	padding: var(--sp-24) var(--sp-24) var(--sp-32);
}

@media (min-width: 940px) {
	.card__body {
		padding: var(--sp-32);
	}

	/* The feature card fills its two rows; let its photo take the slack. */
	.bento__feature .card__media--wide {
		aspect-ratio: auto;
		flex: 1;
		min-height: 260px;
	}
}

.fibre-grid {
	grid-template-columns: 1fr;
}

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

@media (min-width: 940px) {
	.fibre-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

.fibre.card--media {
	padding: 0;
}

/* ==========================================================================
   28. SPLIT LAYOUT (About)
   ========================================================================== */

.split {
	display: grid;
	gap: var(--sp-40);
	grid-template-columns: 1fr;
}

@media (min-width: 940px) {
	.split {
		grid-template-columns: 1.15fr 0.85fr;
		align-items: center;
		gap: var(--sp-64);
	}

	.split--media-first {
		grid-template-columns: 0.9fr 1.1fr;
	}
}

.split__media {
	margin: 0;
	overflow: hidden;
	border-radius: var(--radius-card);
	aspect-ratio: 1 / 1;
}

.split__media--portrait {
	aspect-ratio: 4 / 3;
}

@media (min-width: 940px) {
	.split__media--portrait {
		aspect-ratio: 4 / 5;
	}
}

.split__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.diff-list {
	border-top: 1px solid var(--border);
}

.diff {
	padding-block: var(--sp-24);
	border-bottom: 1px solid var(--border);
}

.diff__title {
	font-size: 20px;
	font-weight: 500;
	line-height: 1.3;
}

.diff__desc {
	margin-top: var(--sp-8);
	max-width: 52ch;
	color: var(--ink-secondary);
	font-size: 16px;
	line-height: 1.55;
}

/* ==========================================================================
   29. WIDE PHOTO BAND ("How we work")
   ========================================================================== */

.media-band {
	margin: 0 0 var(--sp-40);
	overflow: hidden;
	border-radius: var(--radius-card);
	aspect-ratio: 16 / 9;
}

@media (min-width: 940px) {
	.media-band {
		aspect-ratio: 21 / 8;
	}
}

.media-band__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 45%;
}

/* ==========================================================================
   30. END USE (Yarns page)
   ========================================================================== */

.enduse {
	display: grid;
	gap: var(--sp-20);
	grid-template-columns: 1fr;
}

@media (min-width: 940px) {
	.enduse {
		grid-template-columns: 1.7fr 1fr;
		gap: var(--sp-24);
	}
}

.enduse__item {
	margin: 0;
	overflow: hidden;
	border-radius: var(--radius-card);
	aspect-ratio: 4 / 3;
}

@media (min-width: 940px) {
	.enduse__item {
		aspect-ratio: auto;
		height: 440px;
	}
}

.enduse__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ==========================================================================
   31. CTA BAND, DARK
   ========================================================================== */

.cta-band.on-dark {
	position: relative;
	overflow: hidden;
	background-color: #060d17;
	border-top: 0;
}

.cta-band__media {
	position: absolute;
	inset: 0;
}

.cta-band__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: right center;
}

.cta-band__media::after {
	content: "";
	position: absolute;
	inset: 0;
	/* Small screens crop the photo so its gold thread runs behind the text:
	   a 0.45 overlay measured 3.49:1 for white there. 0.74 restores it. */
	background: rgba(6, 13, 23, 0.74);
}

@media (min-width: 940px) {
	/* On wide screens the thread sits clear of the copy, so it can show. */
	.cta-band__media::after {
		background: rgba(6, 13, 23, 0.45);
	}
}

.cta-band.on-dark .cta-band__inner {
	position: relative;
	z-index: 1;
}

/* ==========================================================================
   32. WECHAT POPOVER
   Written fallback-first. A browser WITHOUT the Popover API ignores the
   [popover] attribute, so the panel renders inline inside the card and the
   trigger (which would do nothing) is hidden. Everything floating lives
   inside @supports selector(:popover-open), which only a supporting browser
   understands.

   CAUTION: never set `display` on .wechat-panel outside :popover-open or the
   fallback block. It would override the browser's own display:none for a
   closed popover and leave the panel permanently visible.
   ========================================================================== */

.wechat-trigger {
	display: none;
	gap: var(--sp-8);
	margin-top: var(--sp-4);
	text-align: start;
}

.wechat-trigger__icon {
	flex-shrink: 0;
}

.wechat-panel__close {
	display: none;
}

@supports not selector(:popover-open) {
	.wechat-panel {
		display: flex;
		flex-direction: column;
		gap: var(--sp-20);
		margin-top: var(--sp-16);
		padding-top: var(--sp-16);
		border-top: 1px solid var(--border);
	}
}

@supports selector(:popover-open) {
	.wechat-trigger {
		display: inline-flex;
	}

	.wechat-panel__close {
		display: inline-flex;
	}

	.wechat-panel {
		width: min(360px, calc(100vw - 24px));
		padding: var(--sp-20) var(--sp-24) var(--sp-24);
		border: 1px solid var(--border);
		border-radius: var(--radius-card);
		background-color: var(--surface);
		color: var(--ink);
		box-shadow: var(--shadow-menu);
		overflow: auto;
		overscroll-behavior: contain;
	}

	/* With script, the panel is placed beside its button (see site.js).
	   Without it, the browser's default centres it on screen — still usable. */
	.has-js .wechat-panel {
		position: fixed;
		inset: auto;
		margin: 0;
	}

	.wechat-panel:popover-open {
		display: flex;
		flex-direction: column;
		gap: var(--sp-20);
		opacity: 1;
		transform: none;
		transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
	}

	/* A subtle entrance only; switched off entirely for reduced motion below. */
	@starting-style {
		.wechat-panel:popover-open {
			opacity: 0;
			transform: translateY(4px);
		}
	}

	.wechat-panel::backdrop {
		background: transparent;
	}
}

.wechat-panel__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-12);
}

.wechat-panel__title {
	font-size: 17px;
	font-weight: 500;
	line-height: 1.3;
}

.wechat-panel__close {
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 40px;
	height: 40px;
	margin-inline-end: calc(var(--sp-8) * -1);
	border-radius: 50%;
	color: var(--ink-secondary);
	transition: background-color var(--t-fast) var(--ease);
}

.wechat-panel__close:hover {
	background-color: var(--secondary-subtle);
	color: var(--ink);
}

.wechat-panel__copy {
	display: flex;
	flex-direction: column;
	gap: var(--sp-12);
}

.wechat-panel__hint {
	color: var(--ink-secondary);
	font-size: 14px;
	line-height: 1.45;
}

.wechat-panel__idrow {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-8);
}

.wechat-panel__id {
	flex: 1 1 8rem;
	min-width: 0;
	padding: var(--sp-12) var(--sp-12);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	background-color: var(--surface-alt);
	color: var(--ink);
	font-size: 18px;
	font-weight: 500;
	letter-spacing: 0.08em;
	text-align: center;
}

.wechat-panel__id:focus {
	outline: var(--focus-width) solid var(--brand);
	outline-offset: 1px;
}

/* On phones and touch screens, copying the ID is THE action: gold primary. */
.wechat-panel__copybtn {
	flex: 1 1 10rem;
	border-radius: var(--radius-sm);
	background-color: var(--brand);
	border-color: var(--brand);
	color: var(--on-brand);
}

.wechat-panel__copybtn:hover {
	background-color: var(--brand-hover);
	border-color: var(--brand-hover);
	color: var(--on-brand);
}

.wechat-panel__checkicon,
.wechat-panel__copybtn.is-copied .wechat-panel__copyicon {
	display: none;
}

.wechat-panel__copybtn.is-copied .wechat-panel__checkicon {
	display: block;
}

.wechat-panel__status {
	min-height: 1.4em;
	color: var(--brand);
	font-size: 14px;
	font-weight: 500;
	line-height: 1.4;
}

.wechat-panel__status:empty {
	min-height: 0;
}

.wechat-panel__qr {
	margin: 0;
	text-align: center;
}

.wechat-panel__qr img {
	width: 160px;
	margin-inline: auto;
	border-radius: var(--radius-sm);
}

.wechat-panel__qr figcaption {
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	margin-top: var(--sp-8);
	color: var(--ink-secondary);
	font-size: 14px;
}

/* Phone layout: the ID is already in the copy field, and a scan instruction
   would be misleading on the device showing the code. */
.wechat-panel__scan,
.wechat-panel__idline {
	display: none;
}

/*
 * Desktop and laptop — wide screen AND a precise pointer (mouse or trackpad).
 * Keying on the pointer as well as width means a large tablet, which also
 * cannot scan its own screen, keeps the copy-first layout.
 * The QR leads here, at 240px: comfortably above the ~200px needed to scan
 * reliably, and a size at which this particular code was verified to decode.
 */
@media (min-width: 640px) and (pointer: fine) {
	.wechat-panel__qr {
		order: 1;
	}

	.wechat-panel__copy {
		order: 2;
	}

	.wechat-panel__qr img {
		width: 240px;
	}

	.wechat-panel__scan,
	.wechat-panel__idline {
		display: block;
	}

	.wechat-panel__scan {
		color: var(--ink);
		font-weight: 500;
	}

	.wechat-panel__idline strong {
		color: var(--ink);
		letter-spacing: 0.08em;
	}

	.wechat-panel__hint {
		display: none;
	}

	/* Copying becomes the secondary action beside a scannable code. */
	.wechat-panel__copybtn {
		background-color: transparent;
		border-color: var(--secondary);
		color: var(--secondary);
	}

	.wechat-panel__copybtn:hover {
		background-color: var(--secondary-subtle);
		border-color: var(--secondary);
		color: var(--secondary);
	}

	.wechat-panel__id {
		font-size: 16px;
	}
}

.contact-card--wechat {
	align-items: flex-start;
}

/* ==========================================================================
   33. FLOATING WHATSAPP BUTTON
   ========================================================================== */

.wa-fab {
	position: fixed;
	z-index: 90;
	inset-inline-end: max(16px, env(safe-area-inset-right));
	bottom: max(16px, env(safe-area-inset-bottom));
	transition: opacity var(--t-med) var(--ease), transform var(--t-med) var(--ease), visibility 0s linear 0s;
}

.wa-fab[hidden] {
	display: none;
}

/* The subtle entrance: a short fade and 8px rise on first paint. No bounce,
   no pulse, nothing that repeats. */
@starting-style {
	.wa-fab {
		opacity: 0;
		transform: translateY(8px);
	}
}

.wa-fab__link {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border-radius: 50%;
	background-color: var(--whatsapp-green);
	color: #ffffff;
	box-shadow: 0 6px 16px rgba(13, 37, 61, 0.24);
	transition: background-color var(--t-fast) var(--ease);
}

.wa-fab__link:hover {
	background-color: var(--whatsapp-green-hover);
	color: #ffffff;
}

/* A ring that shows on ANY background: navy, white, navy. The button floats
   over white sections, the warm tint and the dark navy photographs alike. */
.wa-fab__link:focus-visible,
.wa-fab__dismiss:focus-visible {
	outline: 2px solid #ffffff;
	outline-offset: 2px;
	box-shadow: 0 0 0 5px var(--ink);
}

.wa-fab__dismiss {
	position: absolute;
	top: -6px;
	inset-inline-start: -6px;
	display: none;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	border: 2px solid #ffffff;
	border-radius: 50%;
	background-color: var(--ink);
	color: #ffffff;
}

/* A larger invisible hit area than the visible 24px dot, for fingers. */
.wa-fab__dismiss::before {
	content: "";
	position: absolute;
	inset: -10px;
}

.has-js .wa-fab__dismiss {
	display: flex;
}

/* Out of the way whenever something else needs the corner. */
.wa-fab.is-tucked,
.nav-open .wa-fab,
body:has(.wechat-panel:popover-open) .wa-fab {
	opacity: 0;
	transform: translateY(12px);
	visibility: hidden;
	pointer-events: none;
	transition: opacity var(--t-med) var(--ease), transform var(--t-med) var(--ease), visibility 0s linear var(--t-med);
}

/* Without script the button cannot tuck away from the contact form, so on
   that one page it stays hidden rather than risk covering a field. */
html:not(.has-js) .page-template-template-contact .wa-fab {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.wa-fab,
	.wa-fab.is-tucked,
	.wechat-panel:popover-open {
		transition: none;
	}
}


/* ==========================================================================
   34. FOOTER CONTACT LIST
   One pattern for every line: a small uppercase label on its own line, the
   value beneath it. Previously WhatsApp and WeChat had an inline label that
   ran into the value, while phone and email had none at all.
   Label: --ink-muted on the warm tint, 5.40:1. Value: --ink-secondary, 11.05:1.
   ========================================================================== */

.footer-contact {
	display: grid;
	gap: var(--sp-16) var(--sp-24);
	grid-template-columns: repeat(2, minmax(0, 1fr));
	margin: 0;
}

.footer-contact__row {
	min-width: 0;
}

/* The address is the one long value: give it the full width. */
.footer-contact__row:last-child {
	grid-column: 1 / -1;
}

.footer-contact dt {
	color: var(--ink-muted);
	font-size: 11px;
	font-weight: 500;
	line-height: 1.4;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.footer-contact dd {
	margin: var(--sp-4) 0 0;
	color: var(--ink-secondary);
	font-size: 15px;
	line-height: 1.5;
	overflow-wrap: anywhere;
}

.footer-contact a {
	color: var(--ink-secondary);
	text-decoration: none;
}

.footer-contact a:hover {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.footer-contact__ltr {
	font-variant-numeric: tabular-nums;
}

.footer-contact address {
	font-size: inherit;
	line-height: inherit;
	color: inherit;
}

.site-footer__bottom {
	margin-top: var(--sp-32);
}
/* The floating WhatsApp button rests over the footer's bottom-right corner
   once the page is scrolled to its end; keep the last row clear of it. */
.site-footer__bottom {
	padding-inline-end: 72px;
}

/* ==========================================================================
   35. SCROLLING STRIPS (homepage) — the ONLY ambient animation on the site
   Owner's decision, October 2026: the "no ambient motion" rule is lifted for
   these two strips and nothing else.

   - Motion is transform-only (translate3d), so it never triggers layout.
   - Each strip clips with overflow:hidden, so it can never make the page
     scroll sideways.
   - Four identical copies; the track slides exactly one copy (25%) and loops.
   - Speed is set per strip so both travel at the same calm ~18px/s.
   ========================================================================== */

.strips {
	overflow: hidden;
}

.strips__head {
	margin-inline: auto;
	text-align: center;
}

.strip {
	/*
	 * NO REPEAT ON SCREEN: one full set must be wider than the strip PLUS the
	 * widest item, or the tail of a logo and the head of its next copy can
	 * both peek in at opposite edges. The strip is capped at the content width
	 * (1280px) so this holds on any monitor. Widest logo: Michell, 156px.
	 * Needed: 1280 + 156 = 1436px. Six logos (708px) + 6 x 124px = 1452px.
	 * If logos are added, removed or resized, re-check this sum.
	 */
	--strip-gap: 124px;
	--strip-duration: 82s; /* 1452px / 82s = 17.7px/s */
	position: relative;
	max-width: var(--container);
	margin-inline: auto;
	overflow: hidden;
	/* The track is laid out left-to-right on both language sides; rtl.css
	   reverses the motion instead (see there for why). */
	direction: ltr;
	/* Items dissolve into the edges rather than being hard-cut. */
	-webkit-mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
	mask-image: linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%);
}

.strip + .strip {
	margin-top: var(--sp-16);
}

/* Phones: a tighter gap so about three logos show at once, not two. */
@media (max-width: 639px) {
	.strip--mills {
		--strip-gap: 56px;
		--strip-duration: 59s; /* 1044px / 59s = 17.7px/s */
	}
}

.strip--yarns {
	--strip-gap: 28px;
	/* Six tiles of 232px + 6 x 28px = 1560px per set: wider than the strip
	   plus one tile (1280 + 232 = 1512px), so no tile shows twice.
	   1560px / 88s = 17.7px/s, matching the mills strip. */
	--strip-duration: 88s;
}

.strip:focus-visible {
	outline: var(--focus-width) solid var(--brand);
	outline-offset: -4px;
	border-radius: var(--radius-sm);
}

.strip__track {
	display: flex;
	width: max-content;
	animation: texofil-strip-leftward var(--strip-duration) linear infinite;
	will-change: transform;
}

.strip--yarns .strip__track {
	animation-name: texofil-strip-rightward;
}

/* Hover or focus (keyboard, or a tap on touch screens) stops the motion. */
.strip:hover .strip__track,
.strip:focus-within .strip__track {
	animation-play-state: paused;
}

@keyframes texofil-strip-leftward {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(-25%, 0, 0); }
}

@keyframes texofil-strip-rightward {
	from { transform: translate3d(-25%, 0, 0); }
	to   { transform: translate3d(0, 0, 0); }
}

.strip__set {
	display: flex;
	flex-shrink: 0;
	align-items: center;
	gap: var(--strip-gap);
	margin: 0;
	padding: var(--sp-16) var(--strip-gap) var(--sp-16) 0;
	list-style: none;
}

/* The duplicate copies carry the `hidden` attribute so they stay hidden with
   CSS switched off; here they are shown for the loop. */
.strip__set[hidden] {
	display: flex;
}

.strip__item {
	display: flex;
	flex-shrink: 0;
	align-items: center;
}

/* Greyscale is applied here, not baked into the files: the originals stay in
   full colour, and a logo shows its own colours while pointed at. */
.strip__logo {
	display: block;
	max-width: none;
	filter: grayscale(1);
	opacity: 0.68;
	transition: filter var(--t-med) var(--ease), opacity var(--t-med) var(--ease);
}

.strip__item:hover .strip__logo {
	filter: none;
	opacity: 1;
}

.strip__item--yarn {
	/* Every tile the same width, sized to the longest name
	   ("Acrylic & Synthetics"); icon and name centred within it. */
	justify-content: center;
	width: 232px;
	gap: var(--sp-12);
	padding: var(--sp-8) var(--sp-20) var(--sp-8) var(--sp-12);
	border: 1px solid var(--border);
	border-radius: var(--radius-pill);
	background-color: var(--surface);
}

.strip__icon {
	display: block;
	max-width: none;
	filter: grayscale(1);
	opacity: 0.72;
}

.strip__label {
	color: var(--ink-secondary);
	font-size: 15px;
	font-weight: 500;
	line-height: 1.25;
	/* Fits on one line in English; a longer translation wraps inside the tile
	   rather than breaking the equal widths. */
	text-wrap: balance;
}

.strips__foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--sp-8) var(--sp-32);
	margin-top: var(--sp-32);
}


/*
 * REDUCED MOTION: no animation at all. Not a paused marquee — that would clip
 * half the items behind the edge fade. Instead the duplicate copies disappear,
 * the fade is removed, and the one real copy wraps into a centred static grid
 * with every item visible.
 */
@media (prefers-reduced-motion: reduce) {
	.strip {
		overflow: visible;
		-webkit-mask-image: none;
		mask-image: none;
	}

	.strip__track {
		display: block;
		width: auto;
		animation: none;
	}

	.strip__set[hidden] {
		display: none;
	}

	.strip__set {
		flex-wrap: wrap;
		justify-content: center;
		gap: var(--sp-24) var(--sp-40);
		max-width: var(--container);
		margin-inline: auto;
		padding: var(--sp-12) var(--gutter);
	}

	.strip--yarns .strip__set {
		gap: var(--sp-12);
	}
}
