/* =====================================================================
   Detail King — global.css
   Design tokens, type scale, project spacing utilities and shared
   components. Loaded on every page, after Bootstrap.

   The comp has NO Figma variables (get_variable_defs → {}), so every
   token below is *derived by measurement* from the 1920px frames, not
   declared by the design system. Treat them as the single source of
   truth and never hard-code a hex inline.

   Bootstrap first: reach for a utility class before adding a rule here.
   The utilities in §4 exist only for comp values Bootstrap's 0.25rem
   scale (which stops at 3rem/48px) genuinely cannot express.
   ===================================================================== */

/* ---------------------------------------------------------------
   1. Design tokens
   --------------------------------------------------------------- */
:root {
	/* Laptop scale. The comps are 1920 and every size is fixed px, so large
	   type and spacing are written as calc(N * var(--fs|--sp)) by
	   tools/laptop-scale.py. Both are exactly 1px on phones/tablets and at
	   >= 1920, and shrink linearly in between: --fs 0.78 / --sp 0.74 at 1440,
	   floored at 0.70 / 0.65 from 1280 down to 992. */
	--fs: 1px;
	--sp: 1px;

	/* Backgrounds */
	--bg-dark: #0B0B0C;
	--bg-dark-alt: #0E0E10;
	--bg-dark-card: #131315;
	--bg-light: #F6F4EF;
	--bg-light-alt: #EDEAE2;

	/* Gold accent system */
	--gold-primary: #E9C97C;
	--gold-dark: #A87D2E;
	--gold-mid: #C9A14A;
	--gold-pale: #F6E4AB;
	--gold-gradient: linear-gradient(135deg, #A87D2E 0%, #E9C97C 40%, #F6E4AB 50%, #E9C97C 60%, #A87D2E 100%);
	--gold-gradient-btn: linear-gradient(115deg, #A87D2E 0%, #E9C97C 39%, #F6E4AB 50%, #E9C97C 61%, #A87D2E 100%);

	/* Text */
	--text-white: #FFFFFF;
	--text-white-94: rgba(255, 255, 255, .94);
	--text-white-82: rgba(255, 255, 255, .82);
	--text-white-75: rgba(255, 255, 255, .75);
	--text-white-70: rgba(255, 255, 255, .70);
	--text-white-60: rgba(255, 255, 255, 0.60);
	--text-white-65: rgba(255, 255, 255, .65);
	--text-white-55: rgba(255, 255, 255, .55);
	--text-white-45: rgba(255, 255, 255, .45);
	--text-white-35: rgba(255, 255, 255, .35);
	--text-dark: #0B0B0C;
	--text-muted: #6C6C71;
	--text-muted-dark: #3A3A3E;

	/* Hairlines */
	--line-dark: #3C3C40;
	--line-white-08: rgba(255, 255, 255, .08);
	--line-white-12: rgba(255, 255, 255, .12);
	--line-gold-22: rgba(233, 201, 124, .22);

	/* Glass surfaces */
	--glass-dark-93: rgba(11, 11, 12, .93);
	--glass-dark-82: rgba(11, 11, 12, .82);
	--glass-white-04: rgba(255, 255, 255, .04);
	--glass-white-05: rgba(255, 255, 255, .05);
	--glass-white-08: rgba(255, 255, 255, .08);
	--glass-white-10: rgba(255, 255, 255, .10);
	--glass-white-12: rgba(255, 255, 255, .12);
	--glass-white-15: rgba(255, 255, 255, .15);
	--glass-white-25: rgba(255, 255, 255, .25);

	/* Gold overlays */
	--gold-06: rgba(233, 201, 124, .06);
	--gold-08: rgba(233, 201, 124, .08);
	--gold-16: rgba(233, 201, 124, .16);
	--gold-20: rgba(233, 201, 124, .20);
	--gold-25: rgba(233, 201, 124, .25);
	--gold-30: rgba(233, 201, 124, .30);
	--gold-35: rgba(233, 201, 124, .35);
	--gold-40: rgba(233, 201, 124, .40);
	--gold-45: rgba(233, 201, 124, .45);
	--gold-70: rgba(233, 201, 124, .70);

	/* Shadows */
	--shadow-gold: 0 10px 32px rgba(201, 161, 74, .35);
	--shadow-gold-btn: 0 10px 28px rgba(201, 161, 74, .40);
	--shadow-gold-sm: 0 8px 22px rgba(201, 161, 74, .40);
	--shadow-nav: 0 20px 60px rgba(0, 0, 0, .40);
	--shadow-dark: 0 16px 26px rgba(0, 0, 0, .50);
	--shadow-dark-xl: 0 60px 140px rgba(0, 0, 0, .50);
	--shadow-card: 0 24px 60px rgba(11, 11, 12, .07);
	--shadow-section: 0 40px 100px rgba(11, 11, 12, .18);

	/* Radii — the comp uses three, consistently */
	--radius-md: 16px;
	--radius-lg: 24px;
	--radius-xl: 34px;
	--radius-pill: 100px;

	/* Misc */
	--star-yellow: #FBBC05;
	--badge-muted: #BDB9B0;

	/* Type families */
	--font-display: 'Bebas Neue', 'Arial Narrow', sans-serif;
	--font-body: 'Poppins', system-ui, -apple-system, sans-serif;

	/* The comp's content column, measured: 225 … 1695 = 1470px.
	   The section frames declare a 185px gutter, but every inner Container adds
	   40px on top, and the sum lands on 225 whether the frame said 185 or 225.
	   Verified independently on the footer, the services grid, before/after,
	   testimonials, booking and FAQ. The nav pill is the one exception — it uses
	   the bare 185px gutter and is 1550px wide. */
	--content-max: 1470px;
	--nav-max: 1550px;

	/* Bootstrap overrides so its own components inherit the palette */
	--bs-body-font-family: var(--font-body);
	--bs-body-font-size: 18px;
	--bs-body-font-weight: 300;
	--bs-body-line-height: 1.65;
	--bs-body-color: var(--text-dark);
	--bs-body-bg: var(--bg-light);
	--bs-link-color: var(--gold-dark);
	--bs-link-hover-color: var(--gold-mid);
	--bs-border-color: var(--line-dark);
}

@media (min-width: 992px) and (max-width: 1919.98px) {
	:root {
		--fs: clamp(.7px, .046875vw + .1px, 1px);
		--sp: clamp(.65px, .0547vw - .05px, 1px);
	}
}

/* ---------------------------------------------------------------
   2. Base
   --------------------------------------------------------------- */

/* The pill nav is fixed (see layout/header.css), so anything scrolled to by an
   in-page anchor — the Our Services jump pills, a `#id` in the address bar, a
   future FAQ deep link — would land underneath it. Declaring the offset once on
   the scroll container fixes every one of them, now and later, instead of each
   target carrying its own `scroll-margin-top`.

   `--dk-nav-height` is measured and published by initStickyNav() because a fixed
   number does not survive the ≤991px breakpoint, where the pill wraps to roughly
   124px tall and an anchor target ends up *behind* the nav. The fallback is the
   desktop pill (86px) so the offset is still correct before JS runs; the +44px is
   the nav's own top offset plus breathing room. */
html {
	scroll-padding-block-start: calc(var(--dk-nav-height, 86px) + 44px);
}

body {
	font-family: var(--font-body);
	font-size: 18px;
	font-weight: 300;
	line-height: 1.65;
	color: var(--text-dark);
	background: var(--bg-light);
	-webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
h5,
h6,
.font-display {
	font-family: var(--font-display);
	font-weight: 400;
	text-transform: uppercase;
	line-height: 1;
	margin: 0;
}

p {
	margin: 0 0 1rem;
}

p:last-child {
	margin-bottom: 0;
}

a {
	text-decoration: none;
}

img {
	max-width: 100%;
	height: auto;
}

/* Long words must never push a card wider than its grid track. */
.faq-answer,
.review-text,
.card-text {
	overflow-wrap: anywhere;
}

/* Dark sections: invert the text colours in one place, not per component. */
.section--dark {
	background: var(--bg-dark);
	color: var(--text-white-75);
}

.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4,
.section--dark h5,
.section--dark h6 {
	color: var(--text-white);
}

.section--light {
	background: var(--bg-light);
	color: var(--text-dark);
}

/* --bg-light-alt already existed for this — About's Our Approach is the first
   section to actually use it. */
.section--beige {
	background: var(--bg-light-alt);
	color: var(--text-dark);
}

.section--beige .eyebrow {
	color: var(--gold-dark);
}

/* The 89px the comp puts between the last section and the footer (see
   footer.css for where it comes from and why it is no longer the footer's
   margin). Added as a block inside the last section so it is painted with
   that section's own background — a margin here would show the body colour
   and put a cream bar between two dark bands. Scoped to a direct child of
   the page's own <main>, so a nested last element never picks it up. */
.layout--site> :last-child::after {
	content: "";
	display: block;
	block-size: 89px;
}

/* ---------------------------------------------------------------
   3. Type scale
   --------------------------------------------------------------- */

/* Bebas Neue — display & headings.
   NOTE on line-height: the Figma dump reports many single-line Bebas nodes
   with a line box of exactly 1.65x the font size (80/132, 50/82.5, 36/59.4,
   28/46.2, 22/36.3). That is Figma's AUTO line box, not intended leading —
   it is invisible on a one-line node and would look broken the moment the
   text wraps. Only the multi-line nodes carry a real, tight value
   (120/112.8, 96/96, 64/64). So every Bebas class below uses the tight
   ratio, and the extra vertical space those AUTO boxes occupy in the comp
   is reproduced with padding on the section, where it belongs. */
.display-mega {
	font: 400 calc(320 * var(--fs))/.8 var(--font-display);
}

.display-xxl {
	font: 400 calc(120 * var(--fs))/.94 var(--font-display);
	letter-spacing: .03em;
}

.display-xl {
	font: 400 calc(96 * var(--fs))/1 var(--font-display);
}

.display-lg {
	font: 400 calc(92 * var(--fs))/1 var(--font-display);
}

.display-md {
	font: 400 calc(88 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
}

.display-sm {
	font: 400 calc(80 * var(--fs))/1 var(--font-display);
}

.heading-xl {
	font: 400 calc(64 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
}

.heading-lg {
	font: 400 calc(60 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
}

.heading-md {
	font: 400 calc(54 * var(--fs))/1 var(--font-display);
}

.heading-sm {
	font: 400 calc(50 * var(--fs))/1 var(--font-display);
}

.heading-xs {
	font: 400 calc(46 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
}

.heading-xxs {
	font: 400 calc(44 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
}

.subheading-lg {
	font: 400 36px/1 var(--font-display);
}

.subheading-md {
	font: 400 34px/1 var(--font-display);
	letter-spacing: .03em;
}

.subheading-sm {
	font: 400 32px/1 var(--font-display);
	letter-spacing: .03em;
}

.subheading-xs {
	font: 400 30px/1 var(--font-display);
	letter-spacing: .03em;
}

.label-lg {
	font: 400 28px/1.1 var(--font-display);
	letter-spacing: .02em;
}

.label-md {
	font: 400 26px/1.1 var(--font-display);
	letter-spacing: .06em;
}

.label-sm {
	font: 400 22px/1.1 var(--font-display);
	letter-spacing: .15em;
}

.label-xs {
	font: 400 20px/1.1 var(--font-display);
}

/* Poppins — body & UI. Here 1.65 IS the real line-height. */
.body-xl {
	font: 600 20px/1.65 var(--font-body);
}

.body-lg {
	font: 300 20px/1.65 var(--font-body);
}

.body-md {
	font: 300 19px/1.65 var(--font-body);
}

.body-base {
	font: 300 18px/1.65 var(--font-body);
}

.body-base-reg {
	font: 400 18px/1.65 var(--font-body);
}

.body-base-med {
	font: 500 18px/1.65 var(--font-body);
}

.body-base-semi {
	font: 600 18px/1.65 var(--font-body);
}

.body-sm {
	font: 300 16px/1.65 var(--font-body);
}

.text-gold {
	color: var(--gold-primary);
}

.text-gold-dark {
	color: var(--gold-dark);
}

/* Gold gradient applied to text — used on the second line of every hero. */
.text-gold-gradient {
	background: var(--gold-gradient);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: var(--gold-primary);
}

/* ---------------------------------------------------------------
   4. Project spacing utilities
   Bootstrap's scale stops at 3rem (48px) in 0.25rem steps. The comp
   asks for 110/120/130px section padding, 185px gutters and 70px
   gaps. Named Bootstrap-style, defined once, reused everywhere —
   rather than a bespoke measurement inside each component.
   --------------------------------------------------------------- */
.py-section {
	padding-block: calc(120 * var(--sp));
}

.py-section-sm {
	padding-block: calc(110 * var(--sp));
}

.py-section-lg {
	padding-block: calc(130 * var(--sp));
}

.pt-section {
	padding-top: calc(120 * var(--sp));
}

.pb-section {
	padding-bottom: calc(120 * var(--sp));
}

.px-section {
	padding-inline: 185px;
}

.px-section-sm {
	padding-inline: 90px;
}

.px-section-lg {
	padding-inline: 225px;
}

.gap-section {
	gap: calc(70 * var(--sp));
}

.gap-70 {
	gap: calc(70 * var(--sp));
}

.gap-64 {
	gap: calc(64 * var(--sp));
}

.gap-54 {
	gap: calc(54 * var(--sp));
}

.gap-46 {
	gap: calc(46 * var(--sp));
}

.gap-40 {
	gap: calc(40 * var(--sp));
}

.gap-22 {
	gap: 22px;
}

.rounded-md {
	border-radius: var(--radius-md);
}

.rounded-lg {
	border-radius: var(--radius-lg);
}

.rounded-xl {
	border-radius: var(--radius-xl);
}

.rounded-pill-lg {
	border-radius: var(--radius-pill);
}

/* The comp's content column, centred. Used instead of a bespoke .wrap.
   No horizontal padding at desktop — the 1470px max-width already produces the
   comp's 225px gutter at 1920. Padding appears at narrow widths only, where the
   column would otherwise touch the viewport edge. */
.container-dk {
	position: relative;
	z-index: 1;
	width: 100%;
	max-width: var(--content-max);
	margin-inline: auto;
}

@media (max-width: 1550px) {
	.container-dk {
		padding-inline: 40px;
	}
}

@media (max-width: 767.98px) {
	.container-dk {
		padding-inline: 20px;
	}
}

/* ---------------------------------------------------------------
   5. Shared components
   Grep here before building anything — these are reused across most
   pages and inventing a parallel class beside one is the single most
   common avoidable error in this build.
   --------------------------------------------------------------- */

/* Eyebrow — the "— OUR EXPERTISE —" label above most section headings. */
.eyebrow {
	display: inline-block;
	font: 400 18px/1.65 var(--font-body);
	letter-spacing: .22em;
	text-transform: uppercase;
	color: var(--gold-primary);
}

.eyebrow-wide {
	font-weight: 500;
	letter-spacing: .30em;
}

.section--light .eyebrow {
	color: var(--gold-dark);
}

/* Eyebrow rendered as a bordered pill with a leading dot — the hero /
   page-banner variant. page-banner.php already calls this class. */
.eyebrow--badge {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 10px 22px;
	border: 1px solid var(--line-gold-22);
	border-radius: var(--radius-pill);
	background: var(--gold-06);
	font-size: 16px;
	letter-spacing: .18em;
}

.eyebrow--badge::before {
	content: "";
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--gold-primary);
	flex: 0 0 7px;
}

/* Eyebrow with a flanking rule. Most sections have a rule on the leading side
   only; the centred ones (why-us, membership) have both. */
.eyebrow--line,
.eyebrow--rule-start {
	display: inline-flex;
	align-items: center;
	gap: 14px;
}

.eyebrow--line::before,
.eyebrow--line::after,
.eyebrow--rule-start::before {
	content: "";
	width: 40px;
	height: 1px;
	background: currentColor;
	opacity: .5;
	flex: 0 0 40px;
}

/* Shared section-heading block (template-parts/components/section-heading.php). */
.section-heading__title {
	margin-block: 18px 0;
}

.section-heading__text {
	max-width: 620px;
	margin-block: 22px 0;
	color: var(--text-muted);
}

.section--dark .section-heading__text {
	color: var(--text-white-70);
}

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

.section-heading--center .section-heading__text {
	margin-inline: auto;
}

/* Big outlined wordmark used behind several sections. */
.dk-watermark {
	position: absolute;
	z-index: 0;
	font-family: var(--font-display);
	font-weight: 400;
	line-height: .82;
	white-space: nowrap;
	color: transparent;
	pointer-events: none;
	user-select: none;
}

.dk-watermark--dark {
	-webkit-text-stroke: 1px var(--gold-16);
}

.dk-watermark--light {
	-webkit-text-stroke: 1px rgba(11, 11, 12, .07);
}

/* Buttons. The gold pill is the primary CTA on every page. */
.btn-gold,
.btn-dark,
.btn-outline-light-dk {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: 18px 34px;
	border-radius: var(--radius-pill);
	font: 600 18px/1 var(--font-body);
	letter-spacing: .04em;
	border: 1px solid transparent;
	transition: transform .25s ease, box-shadow .25s ease, background-color .25s ease;
	cursor: pointer;
}

.btn-gold {
	background: var(--gold-gradient-btn);
	color: var(--text-dark);
	box-shadow: var(--shadow-gold-btn);
}

.btn-gold:hover,
.btn-gold:focus-visible {
	color: var(--text-dark);
	transform: translateY(-5px);
	box-shadow: var(--shadow-gold);
}

/* Dark pill — the secondary CTA on every light section ("View All Services",
   "Shop All Products", the non-featured plan buttons). */
.btn-dark {
	background: var(--bg-dark);
	color: var(--text-white);
}

.btn-dark:hover,
.btn-dark:focus-visible {
	background: var(--bg-dark-card);
	color: var(--gold-primary);
	transform: translateY(-5px);
}

.btn-outline-light-dk {
	background: var(--glass-white-05);
	border-color: var(--glass-white-25);
	color: var(--text-white);
}

.btn-outline-light-dk:hover,
.btn-outline-light-dk:focus-visible {
	background: var(--glass-white-12);
	color: var(--text-white);
	transform: translateY(-5px);
}

.section--light .btn-outline-light-dk {
	background: transparent;
	border-color: var(--text-dark);
	color: var(--text-dark);
}

.btn-arrow::after {
	content: "→";
	font-family: var(--font-body);
}

/* Card surfaces — glassmorphism on dark, soft shadow on light. */
.card-glass {
	background: var(--glass-white-04);
	border: 1px solid var(--line-white-08);
	border-radius: var(--radius-lg);
	backdrop-filter: blur(8px);
}

.card-light {
	background: #fff;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
}

/* Never let a long word or a wide child stretch a grid track. */
.card-glass,
.card-light {
	min-width: 0;
}

/* Radial gold glow used behind most dark sections. */
.glow-gold {
	position: relative;
	isolation: isolate;
}

.glow-gold::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		radial-gradient(circle at 72% 18%, rgba(40, 34, 15, 1) 0%, rgba(40, 34, 15, 0) 58%),
		radial-gradient(circle at 10% 95%, rgba(25, 21, 7, 1) 0%, rgba(25, 21, 7, 0) 55%);
	pointer-events: none;
}

/* Inner-page hero banner (global/page-banner.php). Dark bg + optional photo,
   breadcrumb, two-tone title, optional lead paragraph. First real consumer:
   the About page — unstyled until then. */
.page-banner {
	position: relative;
	overflow: hidden;
	/* Bottom padding covers the marquee's -75.6px pull-up (see .dk-marquee)
	   plus its own 55px breathing room, so the ticker never overlaps the
	   banner's own text when a page follows the banner with one. */
	padding-block: calc(210 * var(--sp)) calc(131 * var(--sp));
	background: var(--bg-dark);
	color: var(--text-white-75);
	isolation: isolate;
}

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

.page-banner__bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

/* Same scrim recipe as the homepage hero (home.css .home-hero__bg::after) —
   dark-to-transparent left-weighted scrim plus a warm radial glow. Reused
   rather than the comp's mask-SVG machinery, which draws the identical
   result. */
.page-banner__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(90deg, rgba(11, 11, 12, .96) 0%, rgba(11, 11, 12, .82) 60%, rgba(11, 11, 12, .58) 100%),
		radial-gradient(circle at 75% 10%, rgba(40, 34, 15, .85) 0%, rgba(40, 34, 15, 0) 58%),
		linear-gradient(180deg, rgba(255, 255, 255, .02) .91%, rgba(255, 255, 255, 0) .91%),
		linear-gradient(90deg, rgba(255, 255, 255, .02) .91%, rgba(255, 255, 255, 0) .91%);
}

.page-banner__inner {
	position: relative;
	z-index: 1;
}

/* !important: ThemeHelper::get_breadcrumbs() hard-codes Bootstrap's `mb-0` on
   the <ul> (needed by its other, non-banner call sites), whose own
   `!important` otherwise wins over this rule's higher specificity and zeroes
   the gap before the eyebrow badge. */
.page-banner__breadcrumb .breadcrumb {
	display: flex;
	align-items: center;
	list-style: none;
	margin: 0 0 22px !important;
	padding: 0;
	font: 500 18px/1.65 var(--font-body);
	letter-spacing: .18em;
	text-transform: uppercase;
}

/* Figma's banner container is a column auto-layout with one 22px gap between
   every child (breadcrumb, eyebrow, title, text) — the other three get it via
   margin already; the eyebrow badge is inline-flex with no margin of its own. */
.page-banner__inner .eyebrow--badge {
	margin-bottom: 22px;
}

.page-banner__breadcrumb .breadcrumb__link {
	color: var(--gold-primary);
	text-decoration: none;
}

.page-banner__breadcrumb .breadcrumb__current,
.page-banner__breadcrumb .breadcrumb__separator {
	color: var(--text-white-55);
}

.page-banner__title {
	font: 400 calc(94 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
	color: var(--text-white);
}

.page-banner__text {
	max-width: 620px;
	margin-block-start: 22px;
	color: var(--text-white-70);
}

/* Framed photo card (components/framed-photo.php) — rounded frame + shadow,
   inset gold hairline, optional glass badge over the bottom-left corner.
   Recurs 3x on the About page; only the outer border colour changes. */
.dk-framed-photo {
	position: relative;
	border-radius: var(--radius-lg);
	overflow: hidden;
	box-shadow: 0 40px 100px rgba(11, 11, 12, .18);
}

.dk-framed-photo--neutral {
	border: 1px solid var(--line-white-08);
}

.dk-framed-photo--gold {
	border: 1px solid var(--line-gold-22);
}

.section--light .dk-framed-photo--neutral,
.section--beige .dk-framed-photo--neutral {
	border-color: rgba(11, 11, 12, .1);
}

.dk-framed-photo__media {
	aspect-ratio: 555 / 560;
}

.dk-framed-photo__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.dk-framed-photo::after {
	content: "";
	position: absolute;
	inset: 14px;
	border: 1px solid var(--line-gold-22);
	border-radius: var(--radius-md);
	pointer-events: none;
}

.dk-framed-photo__badge {
	position: absolute;
	inset-block-end: 24px;
	inset-inline-start: 24px;
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 19px 27px;
	background: rgba(11, 11, 12, .82);
}

.dk-framed-photo__badge-year {
	font: 400 calc(40 * var(--fs))/1 var(--font-display);
	letter-spacing: .04em;
	color: var(--gold-primary);
}

.dk-framed-photo__badge-text {
	color: var(--text-white-70);
}

/* Two-column split grid (copy + framed photo). Recurs 3x on the About page
   alone (Who We Are, Our Story, Our Approach) at identical proportions —
   which side the photo lands on is just markup order, not a CSS switch. */
.dk-split {
	display: grid;
	grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
	align-items: center;
	gap: calc(80 * var(--sp));
}

@media (max-width: 991.98px) {
	.dk-split {
		grid-template-columns: 1fr;
		gap: calc(40 * var(--sp));
	}

	/* Media above copy on mobile regardless of desktop column order — same
	   convention as .home-why__figure. */
	.dk-split .dk-framed-photo {
		order: -1;
	}
}

/* Shared dark CTA card (global/cta-banner.php). Recurs on About, Services,
   Gallery and Blog with different copy each time. */

/* The card carries data-animate="zoom", so it sits at scale(1.08) — 8% wider
   than its own box — for as long as it is below the fold and unrevealed. At
   1920 that growth (59px a side) fits inside the container's own gutter; on a
   narrower viewport the gutter shrinks past it and the page picks up a
   horizontal scrollbar that disappears the moment the section reveals — a
   transient overflow, which is exactly the kind an automated check catches and
   a human never does. Clipped on the container rather than the card (the card
   is the thing being scaled) and on the x axis only, so nothing vertical —
   shadows, the reveal's own lift — is cut. `:has()` keeps this attached to the
   component instead of to a list of page-specific section classes that a new
   page would forget to join; the whole rule is inert on any container without
   a CTA card in it.

   `clip visible` (x, then y) is deliberate: `hidden` on one axis forces the
   other to `auto`, which would make this a scroll container and break the
   sticky header's scroll-padding maths. `clip` does not. */
.container-dk:has(> .dk-cta) {
	overflow: clip visible;
}

.dk-cta {
	position: relative;
	overflow: hidden;
	border: 1px solid var(--line-gold-22);
	border-radius: var(--radius-xl);
	padding: calc(110 * var(--sp)) calc(90 * var(--sp));
	text-align: center;
	background: var(--bg-dark);
}

.dk-cta__title {
	font: 400 calc(90 * var(--fs))/1 var(--font-display);
	letter-spacing: .03em;
	color: var(--text-white);
}

.dk-cta__text {
	max-width: 600px;
	margin: 20px auto 0;
	color: var(--text-white-65);
}

.dk-cta__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 22px;
	margin-block-start: calc(44 * var(--sp));
}

/* Product card (components/product-card.php) — moved from home.css: no
   longer homepage-rail-only, the same card now builds the Shop category grid
   and Product Detail's "Related Products" rail (--dark variant, bg
   --bg-dark-card). One card everywhere means the badge, save button and
   Add-to-Cart treatment can never drift between pages. */
.prod-card {
	position: relative;
	display: flex;
	flex-direction: column;
	height: 100%;
	min-width: 0;
	border: 1px solid rgba(11, 11, 12, .1);
	border-radius: 20px;
	overflow: hidden;
	background: #fff;
	transition: transform .3s cubic-bezier(.2, .7, .3, 1), box-shadow .3s ease;
}

.prod-card--dark {
	background: var(--bg-dark-card);
	border-color: var(--line-white-12);
}

/* §15 asks for an image-only zoom, but the recording scales the WHOLE card:
   at t 44.25 the hovered card measures ~7% wider than its neighbours and its
   type is proportionally larger, and its shadow falls over the card beside it.
   So the card scales (which zooms its photo with it) and lifts above the row.
   The scale is kept at 1.05 — 1.08 starts to reflow the eye at four across. */
.prod-card:hover,
.prod-card:focus-within {
	z-index: 2;
	transform: scale(1.05);
	box-shadow: var(--shadow-section);
}

@media (prefers-reduced-motion: reduce) {
	.prod-card {
		transition: none;
	}

	.prod-card:hover,
	.prod-card:focus-within {
		transform: none;
	}
}

.prod-card__media {
	position: relative;
	display: block;
	aspect-ratio: 265.5 / 230;
	overflow: hidden;
	background: linear-gradient(150deg, #15151A 0%, #0B0B0D 100%);
}

.prod-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.prod-card__badge {
	position: absolute;
	inset-block-start: 14px;
	inset-inline-start: 14px;
	padding: 5px 14px;
	border-radius: var(--radius-pill);
	background: var(--gold-gradient-btn);
	color: var(--text-dark);
	font-size: 15px;
	font-weight: 600;
}

/* Sale/New share the Best Seller pill treatment. Only Best Seller's fill was
   readable in the export (the other two badges' backgrounds rendered as
   generic "Background" nodes with no colour data) — deliberate default until
   a residual pass against the live comp confirms a different colour per
   badge type. */

.prod-card__save {
	position: absolute;
	inset-block-start: 14px;
	inset-inline-end: 14px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border: 0;
	border-radius: 50%;
	background: rgba(255, 255, 255, .9);
	color: var(--text-dark);
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
}

.prod-card--dark .prod-card__save {
	background: rgba(255, 255, 255, .12);
	color: var(--text-white);
}

.prod-card__save[aria-pressed="true"] {
	color: var(--gold-dark);
}

.prod-card--dark .prod-card__save[aria-pressed="true"] {
	color: var(--gold-primary);
}

.prod-card__body {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	flex: 1 1 auto;
	gap: 6px;
	padding: 22px;
}

.prod-card__eyebrow {
	font: 400 18px/1.65 var(--font-body);
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--gold-dark);
}

.prod-card--dark .prod-card__eyebrow {
	color: var(--gold-primary);
}

.prod-card__title {
	margin: 0;
	font: 600 22px/1.2 var(--font-body);
	letter-spacing: .03em;
}

.prod-card__title a {
	color: var(--text-dark);
}

.prod-card--dark .prod-card__title a {
	color: var(--text-white);
}

.prod-card__title a:hover {
	color: var(--gold-dark);
}

.prod-card--dark .prod-card__title a:hover {
	color: var(--gold-primary);
}

.prod-card__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 14px;
	margin-block-start: auto;
	padding-block-start: 8px;
}

.prod-card__price {
	font: 400 34px/1 var(--font-display);
	color: var(--text-dark);
}

.prod-card--dark .prod-card__price {
	color: var(--gold-primary);
}

.prod-card__price del {
	font-family: var(--font-body);
	font-size: 15px;
	font-weight: 400;
	color: var(--text-muted);
}

.prod-card__price .woocommerce-Price-currencySymbol {
	font-size: .7em;
	vertical-align: top;
}

.prod-card__price ins {
	text-decoration: none;
}

.prod-card__add:disabled {
	opacity: .4;
	pointer-events: none;
}

.prod-card__add {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	padding: 0;
	/* The cross-sell rail's add button is a real <button> (the AJAX case),
	   everywhere else this is an <a> — without an explicit reset the button
	   variant keeps the browser's default grey "buttonface" fill and padding
	   behind the icon, which is what made the --dark variant's white "+"
	   unreadable (white on light grey, not white on the dark card). */
	appearance: none;
	background: transparent;
	border: 1px solid var(--text-dark);
	border-radius: 50%;
	color: var(--text-dark);
	font: 22px/1 var(--font-body);
	cursor: pointer;
}

.prod-card__add:hover {
	background: var(--text-dark);
	color: var(--text-white);
}

.prod-card--dark .prod-card__add {
	border-color: rgba(255, 255, 255, .35);
	color: var(--text-white);
}

.prod-card--dark .prod-card__add:hover {
	background: var(--text-white);
	color: var(--text-dark);
}

.prod-card__add[aria-disabled="true"] {
	opacity: .4;
	pointer-events: none;
}

/* Stat rows — base + the --craft variant (moved from home.css: it's now used
   on the About page's stats section too, not just the homepage's video
   section). The --hero variant stays homepage-only, in home.css. */
.dk-stats {
	display: flex;
	flex-wrap: wrap;
	margin: 0;
	padding: 0;
	list-style: none;
}

.dk-stats__item {
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.dk-stats__value {
	display: block;
}

.dk-stats__label {
	color: var(--text-white-55);
}

.dk-stats--craft {
	position: relative;
	z-index: 1;
	gap: 0;
}

/* Measured: the homepage's craft numerals are 70px of cap height = a ~100px
   Bebas. About's own stats (about.css) override this to its own measured
   92px — a different comp value, not the same one re-measured. */
.dk-stats--craft .dk-stats__value {
	font-size: calc(100 * var(--fs));
}

.dk-stats--craft .dk-stats__item {
	flex: 1 1 0;
	padding-inline: 46px;
	border-inline-start: 1px solid var(--line-white-12);
}

.dk-stats--craft .dk-stats__item:first-child {
	padding-inline-start: 0;
	border-inline-start: 0;
}

@media (max-width: 1399.98px) {
	.dk-stats--craft .dk-stats__item {
		padding-inline: 30px;
	}
}

@media (max-width: 991.98px) {
	.dk-stats--craft {
		gap: 26px 0;
	}

	.dk-stats--craft .dk-stats__item {
		flex: 1 0 40%;
	}

	.dk-stats--craft .dk-stats__item:nth-child(odd) {
		padding-inline-start: 0;
		border-inline-start: 0;
	}
}

@media (max-width: 575.98px) {
	.dk-stats--craft .dk-stats__item {
		flex: 1 0 100%;
		padding-inline: 0;
		border-inline-start: 0;
	}
}

/* Gold marquee ticker (sections/home/marquee.php). Overlaps the base of
   whatever dark hero precedes it — the homepage's hero, the About page's
   page-banner, and (per the part's own doc comment) every service page.
   Moved here from home.css: it was built home-page-scoped even though it
   was already documented as a shared, multi-page component. */
.dk-marquee {
	position: relative;
	z-index: 2;
	display: flex;
	overflow: hidden;
	min-height: 75.6px;
	align-items: center;
	background: var(--gold-gradient);
	/* Pull up over the preceding section's base, as the comp overlaps it. */
	margin-block-start: calc(-75.6 * var(--sp));
}

.dk-marquee__track {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	gap: calc(54 * var(--sp));
	margin: 0;
	padding: 0 27px;
	list-style: none;
	/* Speed is the thing to match here, not duration: the reference recording
	   moves the ticker left at 57px/s (measured by cross-correlating the band
	   between frames over a stretch where the page itself was still). The track
	   holds 4096px of content, so 72s lands on ~57px/s. The first pass ran 42s
	   = 98px/s, nearly twice the reference and busy next to the rest of the page. */
	animation: dk-marquee 72s linear infinite;
}

.dk-marquee__item {
	display: flex;
	align-items: center;
	gap: calc(54 * var(--sp));
	white-space: nowrap;
	color: var(--bg-dark);
}

/* The separator is a pseudo-element, so the editor's field holds words not glyphs. */
.dk-marquee__item::after {
	content: "◆";
	font-size: 30px;
	opacity: .8;
}

@keyframes dk-marquee {
	from {
		transform: translateX(0);
	}

	to {
		transform: translateX(-100%);
	}
}

.dk-marquee:hover .dk-marquee__track {
	animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
	.dk-marquee__track {
		animation: none;
	}
}

@media (max-width: 767.98px) {
	.dk-marquee {
		min-height: 60px;
		margin-block-start: calc(-60 * var(--sp));
	}

	.dk-marquee__track {
		gap: 34px;
	}

	.dk-marquee__item {
		gap: 34px;
	}
}

/* Form fields (`.dk-field`/`.dk-form__*`) — used by the homepage's short booking
   form and every service page's full booking widget. Moved here from home.css
   for the same reason `.dk-marquee`/`.dk-stats--craft` were: a shared part's CSS
   has to actually live where every consumer's stylesheet loads it, not just
   wherever it was first written. `.home-booking__card`/`__cardtitle` (the dark
   card chrome around the homepage's own form) stay in home.css — those really
   are homepage-only. */
.dk-form__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 20px 24px;
}

/* Pre-existing gap, not new here: this grid never had a mobile column
   override, so every 2-up field (already true for the homepage's short
   booking form) squeezed to ~half of an already-narrow viewport. Adding the
   booking widget's three contact fields made it materially worse — fixing
   it here since it's shared CSS, not page-specific. */
@media (max-width: 575.98px) {
	.dk-form__grid {
		grid-template-columns: 1fr;
	}
}

.dk-field {
	display: flex;
	flex-direction: column;
	gap: 9px;
	min-width: 0;
}

.dk-field__label {
	color: var(--text-white-70);
}

.dk-field__input {
	width: 100%;
	min-height: 56px;
	padding: 14px 18px;
	border: 1px solid var(--line-white-12);
	border-radius: 12px;
	background: var(--glass-white-04);
	color: var(--text-white);
	font: 300 17px/1.4 var(--font-body);
	transition: border-color .2s ease, background-color .2s ease;
}

.dk-field__input::placeholder {
	color: var(--text-white-35);
}

.dk-field__input:focus {
	outline: none;
	border-color: var(--gold-45);
	background: var(--glass-white-08);
}

/* Dark UI needs this or the native date/time pickers render black-on-black. */
.dk-field__input[type="date"],
.dk-field__input[type="time"] {
	color-scheme: dark;
}

select.dk-field__input {
	appearance: none;
	padding-inline-end: 44px;
	background-image: linear-gradient(45deg, transparent 50%, var(--gold-primary) 50%), linear-gradient(135deg, var(--gold-primary) 50%, transparent 50%);
	background-position: calc(100% - 22px) calc(50% + 2px), calc(100% - 16px) calc(50% + 2px);
	background-size: 6px 6px, 6px 6px;
	background-repeat: no-repeat;
}

/* The native option popup ignores the select's own dark background (and
   color-scheme: dark is not honoured for it on every platform) — it renders
   its own light surface regardless, so the options need their own explicit
   dark-on-light colors rather than inheriting the white text meant for the
   closed field. */
select.dk-field__input option {
	color: var(--text-dark);
	background-color: #fff;
}

.dk-form__submit {
	width: 100%;
	margin-block-start: 28px;
}

.dk-form__status {
	margin-block: 14px 0;
	color: var(--text-white-70);
}

.dk-form__status:empty {
	display: none;
}

.dk-form__status[data-state="error"] {
	color: #E2574C;
}

.dk-form__status[data-state="success"] {
	color: #6FCF97;
}

.dk-field__input[aria-invalid="true"] {
	border-color: #E2574C;
}

/* Honeypot — off-screen rather than display:none, which some bots detect. */
.dk-form__trap {
	position: absolute;
	inset-inline-start: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ---------------------------------------------------------------
   6. Mobile navigation ([data-sp-toggle] toggles `.is-open`)

   The open/close animation (grid-template-rows 0fr -> 1fr) lives entirely
   in header.css's `.dk-nav__menu` rule, not here — `.dk-nav__menu` and
   `.primary-nav` are the same element (nav-header.php), and dk-header loads
   after sp-global, so a plain `.primary-nav{display:grid}` here would only
   win the cascade by accident of specificity; putting it all in one file
   avoids that trap.
   --------------------------------------------------------------- */

/* ---------------------------------------------------------------
   7. Scroll-reveal ([data-animate]) — house convention, put it on
   every section. Respects reduced-motion.

   THIS is the reveal animation, all of it. GSAP + ScrollTrigger (116KB of
   vendor JS) were removed 17 Aug 2026 and replaced by these transitions plus
   `assets/js/motion.js`, which is now ~4KB and does nothing per frame for a
   reveal: it toggles `.is-visible` from an IntersectionObserver and the
   compositor runs the interpolation. The per-variant from-states below are the
   contract — motion.js writes no transforms at all any more, so a CSS transform
   on one of these elements no longer "fights the tween", it *is* the tween.

   `aos-ready` is added by AssetsService::printMotionGate() — a synchronous
   <head> script, not motion.js, which is deferred and so cannot beat the first
   paint (the first screen was painted visible, then snapped hidden: a flash
   before every above-the-fold reveal). It applies the class only where motion.js
   will also run: not under prefers-reduced-motion, and not without
   IntersectionObserver. If motion.js then fails to boot at all, the gate's own
   3s watchdog takes the class back off, so the hiding rule can never strand
   content at opacity 0 with nothing left to reveal it — the failure mode this
   build has already been bitten by (HISTORY.md §9).

   Distances/durations follow animation-implementation-spec.md §3/§12/§28/§29:
   images are slower than UI (1.0-1.1s vs 0.7s), travel shrinks on small
   viewports (§23), easing is power3.out expressed as its bezier.
   --------------------------------------------------------------- */
:root {
	--dk-rv-y: 40px;
	/* §28 default reveal travel */
	--dk-rv-x: 30px;
	/* §12 directional reveal travel */
	--dk-rv-dur: .7s;
	/* §3 small UI / headings */
	--dk-rv-ease: cubic-bezier(.215, .61, .355, 1);
	/* = GSAP power3.out */
}

/* §23: 40px of travel on a 375px-wide screen reads as jitter, not elegance. */
@media (max-width: 767.98px) {
	:root {
		--dk-rv-y: 20px;
		--dk-rv-x: 15px;
	}
}

/* The from-state carries NO transition, and that is load-bearing rather than
   tidiness. While the transition was declared here, adding `aos-ready` did not
   *set* an element hidden — it animated it toward hidden over --dk-rv-dur, and
   `.is-visible` then reversed a fade that had only just started. Below the fold
   that is invisible (the class lands hundreds of ms before the scroll crossing,
   so the fade-out has long finished), but for anything on the first screen the
   observer's initial callback arrives ~100-200ms after `aos-ready` and the
   reveal came out as a stub of its real duration — or nothing at all when both
   landed in one style flush. Measured on the homepage h1: opacity 1 -> 0.93 ->
   back to 1, i.e. 7% of a 40px rise, and it looked different on every reload
   because the whole effect was the size of that gap. The transition therefore
   belongs on the reveal below, where the before-change style is the hidden
   state and the after-change style is the visible one. */
.aos-ready [data-animate] {
	opacity: 0;
	transform: translate3d(0, var(--dk-rv-y), 0);
}

.aos-ready [data-animate="fade"] {
	transform: none;
	/* opacity only */
}

.aos-ready [data-animate="fade-left"] {
	transform: translate3d(calc(-1 * var(--dk-rv-x)), 0, 0);
}

.aos-ready [data-animate="fade-right"] {
	transform: translate3d(var(--dk-rv-x), 0, 0);
}

/* §29 image reveal. 1.08 is load-bearing beyond the animation: two sections
   clip horizontally *because* of it (see the cta-banner container rule above
   and `.home-seam` in pages/home.css). Change it and re-check both. */
.aos-ready [data-animate="zoom"] {
	--dk-rv-dur: 1.1s;
	transform: scale(1.08);
}

.aos-ready [data-animate="zoom-in"] {
	--dk-rv-dur: 1s;
	transform: scale(.8);
}

.aos-ready [data-animate].is-visible {
	opacity: 1;
	transform: none;
	transition:
		opacity var(--dk-rv-dur) var(--dk-rv-ease),
		transform var(--dk-rv-dur) var(--dk-rv-ease);
	/* Stagger. motion.js sets this inline, in ms, per element in a batch (§8,
	   §14, §15: 100ms between siblings) and clears it once the reveal lands.
	   Staying on this rule keeps it applying to the reveal itself, and — since
	   `.is-visible` is never removed — leaves the transition in place afterwards
	   for the hover states that share the transform property. */
	transition-delay: var(--dk-rv-delay, 0ms);
}

/* ---------------------------------------------------------------
   7b. Hero sequence (§6) — the one place the spec asks for a real
   sequence rather than a single reveal. Selectors are the home
   hero's, but this lives with the rest of the motion layer rather
   than in pages/home.css, because motion.js's `[data-hero]` hook is
   what turns it on and the two have to be read together.
   `[data-hero]` deliberately is not `[data-animate]`, so the generic
   batch above leaves these nodes alone and cannot double-animate them.
   --------------------------------------------------------------- */
/* Backdrop settles from 1.05 — long enough to read as a settle, not a zoom.
   [data-hero-bg] is the generic hook: the homepage hero, every inner page's
   page-banner and the blog single hero all share it rather than each getting
   their own copy of this rule. */
.aos-ready [data-hero] [data-hero-bg] {
	transform: scale(1.05);
	transition: transform 1.6s cubic-bezier(.25, .46, .45, .94);
}

.aos-ready [data-hero].is-hero-in [data-hero-bg] {
	transform: none;
}

/* Badge/title/text timing is shared across every [data-hero] instance via
   these class groups — page-banner (every inner page) and the blog single
   hero reuse the same entrance rather than each hand-rolling one. */
.aos-ready [data-hero] .home-hero__badge,
.aos-ready [data-hero] .home-hero__title,
.aos-ready [data-hero] .home-hero__text,
.aos-ready [data-hero] .home-hero__actions>*,
.aos-ready [data-hero] .eyebrow--badge,
.aos-ready [data-hero] .page-banner__title,
.aos-ready [data-hero] .page-banner__text,
.aos-ready [data-hero] .single-hero__badge-wrap,
.aos-ready [data-hero] .single-hero__title,
.aos-ready [data-hero] .single-hero__meta {
	opacity: 0;
	transform: translate3d(0, 30px, 0);
	transition:
		opacity .8s var(--dk-rv-ease),
		transform .8s var(--dk-rv-ease);
	transition-delay: var(--dk-hero-at, 0s);
}

.aos-ready [data-hero] .home-hero__badge,
.aos-ready [data-hero] .eyebrow--badge,
.aos-ready [data-hero] .single-hero__badge-wrap {
	--dk-hero-at: .15s;
}

.aos-ready [data-hero] .home-hero__title,
.aos-ready [data-hero] .page-banner__title,
.aos-ready [data-hero] .single-hero__title {
	--dk-hero-at: .25s;
}

.aos-ready [data-hero] .home-hero__text,
.aos-ready [data-hero] .page-banner__text,
.aos-ready [data-hero] .single-hero__meta {
	--dk-hero-at: .4s;
}

/* §6 CTAs land after the heading, with a small stagger between buttons. */
.aos-ready [data-hero] .home-hero__actions>* {
	--dk-hero-at: .55s;
	transform: translate3d(0, 20px, 0);
	transition-duration: .6s;
}

.aos-ready [data-hero] .home-hero__actions> :nth-child(2) {
	--dk-hero-at: .65s;
}

.aos-ready [data-hero] .home-hero__actions> :nth-child(3) {
	--dk-hero-at: .75s;
}

.aos-ready [data-hero].is-hero-in .home-hero__badge,
.aos-ready [data-hero].is-hero-in .home-hero__title,
.aos-ready [data-hero].is-hero-in .home-hero__text,
.aos-ready [data-hero].is-hero-in .home-hero__actions>*,
.aos-ready [data-hero].is-hero-in .eyebrow--badge,
.aos-ready [data-hero].is-hero-in .page-banner__title,
.aos-ready [data-hero].is-hero-in .page-banner__text,
.aos-ready [data-hero].is-hero-in .single-hero__badge-wrap,
.aos-ready [data-hero].is-hero-in .single-hero__title,
.aos-ready [data-hero].is-hero-in .single-hero__meta {
	opacity: 1;
	transform: none;
}

/* Once settled, the CTAs revert to a normal button transition rather than
   the entrance choreography's .6-.8s duration + up-to-.75s stagger delay —
   without this, a hover after reveal would still animate on the reveal's
   timing (visibly sluggish) because nothing else ever resets it.

   Keyed on `.is-hero-settled`, NOT `.is-hero-in`: `.is-hero-in` is added on
   the very first frame and stays for the rest of the page's life, so a rule
   scoped to it alone is already active *during* the entrance transition
   itself — its higher specificity (one extra class) than the entrance rule
   above clobbered the .6s/staggered-delay timing from frame one, and the
   CTAs snapped in over .25s with no stagger instead of fading up like
   everything else. motion.js adds `.is-hero-settled` after the entrance
   choreography's own last transition genuinely finishes. */
.aos-ready [data-hero].is-hero-settled .home-hero__actions>* {
	transition-duration: .25s;
	transition-delay: 0s;
}

/* The settle rule above also pins transform: none on every child of
   .home-hero__actions with more specificity than a plain :hover — chaining
   the full ancestry here is what lets the hero's own CTAs still lift on
   hover/focus (§31) instead of being stuck flat forever after reveal. */
.aos-ready [data-hero].is-hero-settled .home-hero__actions>.btn-gold:hover,
.aos-ready [data-hero].is-hero-settled .home-hero__actions>.btn-gold:focus-visible,
.aos-ready [data-hero].is-hero-settled .home-hero__actions>.btn-outline-light-dk:hover,
.aos-ready [data-hero].is-hero-settled .home-hero__actions>.btn-outline-light-dk:focus-visible {
	transform: translateY(-5px);
}

/* ---------------------------------------------------------------
   7c. Scroll-linked motion (§30 parallax, §17 pinned h-scroll).
   motion.js writes the transform on these per frame; everything
   here is only the setup that makes that cheap and safe.
   --------------------------------------------------------------- */
[data-parallax] {
	will-change: transform;
}

/* Pin scaffold for [data-hscroll]. The two wrappers are created by motion.js
   only when the track actually overflows, so on any layout where it fits (the
   Instagram row is a 1fr grid today, so: always) neither element exists and
   these rules match nothing. */
.dk-pin {
	position: sticky;
	inset-block-start: 0;
	overflow: hidden;
}

/* An ancestor with `overflow: hidden` silently defeats that sticky — `hidden`
   makes the ancestor the nearest scroll container, and since it never itself
   scrolls, the pin never engages. Measured with the row forced to overflow:
   `.home-instagram { overflow: hidden }` left the pin travelling with the page
   (top -447 where it should have been 0) while the track still translated,
   i.e. the gallery slid sideways and off screen instead of holding still.
   `clip` clips identically without creating a scroll container — the same
   distinction the cta-banner container rule in §5 above depends on. The type
   selector is there only to out-specify `.home-instagram`, which sets `hidden`
   in pages/home.css, a stylesheet that loads after this one. */
section:has(> .dk-pin-scope),
div:has(> .dk-pin-scope) {
	overflow: clip;
}

.dk-pin [data-hscroll] {
	will-change: transform;
}

/* ---------------------------------------------------------------
   8. Header live-search overlay (rendered by SearchService)
   --------------------------------------------------------------- */
.search-overlay {
	position: fixed;
	inset: 0;
	z-index: 1080;
	background: rgba(11, 11, 12, .82);
	backdrop-filter: blur(4px);
	opacity: 0;
	transition: opacity .25s ease;
}

.search-overlay.is-open {
	opacity: 1;
}

.search-overlay[hidden] {
	display: none;
}

.search-panel {
	background: var(--bg-dark-card);
	border-bottom: 1px solid var(--line-white-08);
	padding: 2rem 0;
}

.search-form {
	display: flex;
	gap: .5rem;
}

.search-results {
	margin-top: 1rem;
}

.search-result {
	display: block;
	padding: .5rem 0;
	border-bottom: 1px solid var(--line-white-08);
	color: var(--text-white-82);
}

.search-result:hover {
	color: var(--gold-primary);
}

.search-result__type {
	font-size: .8rem;
	color: var(--text-white-45);
}

body.search-open {
	overflow: hidden;
}

/* ---------------------------------------------------------------
   8b. Recommendation popup / cross-sell modal (rendered by CrossSellService)
   --------------------------------------------------------------- */
.cross-sell-overlay {
	position: fixed;
	inset: 0;
	z-index: 1090;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background: rgba(11, 11, 12, .82);
	backdrop-filter: blur(4px);
	opacity: 0;
	transition: opacity .25s ease;
}

.cross-sell-overlay.is-open {
	opacity: 1;
}

.cross-sell-overlay[hidden] {
	display: none;
}

.cross-sell-panel {
	position: relative;
	width: 100%;
	max-width: 720px;
	max-height: min(680px, 90dvh);
	overflow-y: auto;
	padding: calc(40 * var(--sp));
	background: var(--bg-dark-card);
}

.cross-sell-panel__close {
	position: absolute;
	top: 16px;
	right: 16px;
	width: 36px;
	height: 36px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--line-white-08);
	border-radius: 50%;
	color: var(--text-white-82);
	font-size: 20px;
	line-height: 1;
	background: transparent;
}

.cross-sell-panel__close:hover {
	color: var(--text-white);
	border-color: var(--gold-primary);
}

.cross-sell-panel__head {
	margin-block-end: 24px;
}

.cross-sell-panel__title {
	font: 400 clamp(28px, 3vw, 36px)/1.1 var(--font-display);
	color: var(--text-white);
	margin-block-start: 8px;
}

.cross-sell-panel__text {
	color: var(--text-white-45);
	margin-block-start: 8px;
}

.cross-sell-panel__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: 20px;
	margin-block-end: 24px;
}

.cross-sell-panel__cart-link {
	display: block;
	text-align: center;
}

@media (max-width: 575.98px) {
	.cross-sell-panel {
		padding: 28px 20px;
	}

	.cross-sell-panel__grid {
		grid-template-columns: 1fr;
	}
}

/* ---------------------------------------------------------------
   8c. Snackbar / toast (window.dkSnackbar, global.js) — add/remove-from-cart
   confirmations. Highest z-index on the page on purpose: it has to read
   over the cross-sell modal too (8b, 1090) if an add-to-cart toast fires
   right as that modal opens.
   --------------------------------------------------------------- */
.dk-snackbar {
	position: fixed;
	inset-block-end: 28px;
	inset-inline: 0;
	z-index: 1200;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	pointer-events: none;
}

.dk-snackbar__item {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 14px 26px;
	border-radius: var(--radius-pill);
	background: var(--bg-dark-card);
	border: 1px solid var(--line-white-08);
	color: var(--text-white);
	font-weight: 500;
	box-shadow: 0 20px 60px rgba(0, 0, 0, .4);
	opacity: 0;
	transform: translateY(12px);
	transition: opacity .25s ease, transform .25s ease;
}

.dk-snackbar__item.is-visible {
	opacity: 1;
	transform: translateY(0);
}

.dk-snackbar__item--error {
	border-color: rgba(220, 90, 90, .4);
}

@media (max-width: 575.98px) {
	.dk-snackbar {
		inset-inline: 16px;
	}

	.dk-snackbar__item {
		width: 100%;
		justify-content: center;
		text-align: center;
	}
}

/* ---------------------------------------------------------------
   9. Motion — hover states (animation-implementation-spec.md §31)
   The scroll-driven work lives in assets/js/motion.js; these are the
   pointer-driven counterparts, kept in CSS because they are state, not
   choreography, and should survive with JS off.

   The spec is emphatic that hover stays restrained: image scale(1.05),
   card -4px, icon +2px, over 400-600ms. Explicitly not scale(1.2), not
   rotation, not bounce. Button lift is a deliberate exception, raised
   from the spec's -1px to -5px client-side 21 Aug 2026 to match the
   filter-pill hover lift.

   Guarded on (hover: hover) so a touch device never sticks in a hover
   state after a tap, and neutralised under reduced motion.
   --------------------------------------------------------------- */
@media (hover: hover) {

	.plan-card,
	.svc-card,
	.prod-card,
	.review-card {
		transition: transform .45s cubic-bezier(.22, .61, .36, 1);
	}

	.plan-card:hover,
	.svc-card:hover,
	.prod-card:hover,
	.review-card:hover {
		transform: translateY(-4px);
	}

	.btn-gold,
	.btn-dark,
	.btn-outline-light-dk {
		transition: transform .4s cubic-bezier(.22, .61, .36, 1),
			background-color .4s ease,
			border-color .4s ease,
			color .4s ease;
	}

	.btn-gold:hover,
	.btn-dark:hover,
	.btn-outline-light-dk:hover {
		transform: translateY(-5px);
	}

	/* §8/§15: the card stays put, the image zooms inside its clipped frame. */
	.svc-card__media,
	.prod-card__media {
		overflow: hidden;
	}

	.svc-card__media img,
	.prod-card__media img {
		transition: transform .6s cubic-bezier(.22, .61, .36, 1);
	}

	.svc-card:hover .svc-card__media img,
	.prod-card:hover .prod-card__media img {
		transform: scale(1.05);
	}

	.btn-arrow:hover span[aria-hidden="true"] {
		transform: translateX(2px);
	}

	.btn-arrow span[aria-hidden="true"] {
		display: inline-block;
		transition: transform .4s cubic-bezier(.22, .61, .36, 1);
	}
}

@media (prefers-reduced-motion: reduce) {

	.plan-card,
	.svc-card,
	.prod-card,
	.review-card,
	.btn-gold,
	.btn-dark,
	.btn-outline-light-dk,
	.svc-card__media img,
	.prod-card__media img,
	.btn-arrow span[aria-hidden="true"] {
		transition: none;
	}

	.plan-card:hover,
	.svc-card:hover,
	.prod-card:hover,
	.review-card:hover,
	.btn-gold:hover,
	.btn-dark:hover,
	.btn-outline-light-dk:hover,
	.svc-card:hover .svc-card__media img,
	.prod-card:hover .prod-card__media img {
		transform: none;
	}
}

/* ═══════════════════ MEMBERSHIP CARDS & GRID ═══════════════════ */
.home-membership {
	position: relative;
	overflow: hidden;
	padding-block: calc(130 * var(--sp)) calc(79 * var(--sp));
}

.home-membership__watermark {
	inset-block-start: 10px;
	inset-inline-start: -40px;
	font-size: calc(200 * var(--fs));
}

.home-membership__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	align-items: center;
	gap: 30px;
	margin-block-start: calc(54 * var(--sp));
}

.plan-card {
	position: relative;
	display: flex;
	flex-direction: column;
	min-height: calc(660 * var(--sp));
	min-width: 0;
	padding: calc(42 * var(--sp)) 38px 38px;
	border-radius: var(--radius-lg);
	background: #fff;
	box-shadow: var(--shadow-card);
	overflow-wrap: anywhere;
	transition: transform .3s cubic-bezier(.2, .7, .3, 1), box-shadow .3s ease;
}

.plan-card:hover {
	transform: translateY(-10px) !important;
	box-shadow: var(--shadow-section);
}

@media (prefers-reduced-motion: reduce) {
	.plan-card {
		transition: none;
	}

	.plan-card:hover {
		transform: none;
	}
}

.plan-card--featured {
	min-height: calc(700 * var(--sp));
	padding-block: calc(56 * var(--sp)) calc(46 * var(--sp));
	background: var(--bg-dark);
	color: var(--text-white-75);
	box-shadow: var(--shadow-dark);
}

.plan-card--featured .plan-card__title {
	color: var(--text-white);
}

.plan-card__badge {
	position: absolute;
	inset-block-start: -20px;
	inset-inline-start: 50%;
	transform: translateX(-50%);
	padding: 10px 26px;
	border-radius: var(--radius-pill);
	background: var(--gold-gradient-btn);
	color: var(--bg-dark);
	white-space: nowrap;
	box-shadow: var(--shadow-gold-sm);
}

.plan-card__head {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.plan-card__tagline {
	color: var(--text-muted);
}

.plan-card--featured .plan-card__tagline {
	color: var(--text-white-55);
}

.plan-card__price {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin-block: 30px 30px;
}

.plan-card__currency {
	font: 400 22px/1 var(--font-body);
	color: var(--gold-dark);
}

.plan-card--featured .plan-card__currency {
	color: var(--gold-primary);
}

.plan-card__period {
	color: var(--text-muted);
}

.plan-card--featured .plan-card__period {
	color: var(--text-white-55);
}

.plan-card__features {
	display: flex;
	flex-direction: column;
	gap: 15px;
	margin: 0 0 34px;
	padding: 0;
	list-style: none;
}

.plan-card__features li {
	display: flex;
	align-items: flex-start;
	gap: 13px;
	min-width: 0;
}

.plan-card__tick {
	position: relative;
	flex: 0 0 22px;
	width: 22px;
	height: 22px;
	margin-block-start: 4px;
	border: 1px solid var(--gold-45);
	border-radius: 50%;
}

.plan-card__tick::before {
	content: "";
	position: absolute;
	inset-block-start: 6px;
	inset-inline-start: 6px;
	width: 8px;
	height: 4px;
	border-inline-start: 1.5px solid var(--gold-dark);
	border-block-end: 1.5px solid var(--gold-dark);
	transform: rotate(-45deg);
}

.plan-card--featured .plan-card__tick::before {
	border-color: var(--gold-primary);
}

.plan-card__cta {
	margin-block-start: auto;
	width: 100%;
}

/* ---- Grouped plan card (Silver / Gold): icon + titled feature groups ----
   Scoped to --grouped so the flat-list card and the account card keep their
   look. (0,2,0) selectors also clear home.css's copy of the base rules. */
.home-membership__grid:has(.plan-card--grouped) {
	align-items: stretch;
	max-width: 1140px;
	margin-inline: auto;
}

.plan-card.plan-card--grouped {
	min-height: 0;
	padding: calc(40 * var(--sp)) 34px 34px;
	color: var(--text-dark);
}

.plan-card--grouped.plan-card--featured {
	border: 1px solid var(--gold-mid);
	color: var(--text-white-82);
	box-shadow: var(--shadow-dark), 0 0 40px var(--gold-16);
}

.plan-card--grouped .plan-card__head-row {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
}

.plan-card--grouped .plan-card__title {
	display: flex;
	flex-direction: column;
	margin: 0;
	font: 400 calc(48 * var(--fs))/.95 var(--font-display);
	letter-spacing: .01em;
}

.plan-card--grouped .plan-card__title-accent {
	font-size: 36px;
}

/* The icon sits beside title + tagline, so it must not set the row height. */
.plan-card--grouped .plan-card__head {
	position: relative;
}

.plan-card--grouped .plan-card__head:has(.plan-card__head-icon) {
	padding-inline-end: 110px;
}

.plan-card--grouped .plan-card__head-icon {
	position: absolute;
	inset-block-start: 0;
	inset-inline-end: 0;
}

.plan-card--grouped .plan-card__head-icon img {
	display: block;
	width: 96px;
	height: 96px;
}

.plan-card__badge--inline {
	position: static;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
	padding: 10px 20px;
	transform: none;
	font-weight: 600;
	letter-spacing: .03em;
}

.plan-card--grouped .plan-card__tagline {
	margin: 6px 0 0;
	color: var(--text-muted-dark);
}

.plan-card--grouped.plan-card--featured .plan-card__tagline {
	color: var(--text-white-82);
}

.plan-card--grouped .plan-card__price {
	align-items: center;
	gap: 6px;
	margin-block: 18px 12px;
}

.plan-card--grouped .plan-card__currency {
	align-self: flex-end;
	margin-block-end: 12px;
	font: 400 calc(44 * var(--fs))/1 var(--font-display);
}

.plan-card--grouped .plan-card__amount {
	flex-shrink: 0;
	overflow-wrap: normal;
	font: 400 calc(96 * var(--fs))/.9 var(--font-display);
}

.plan-card__period-wrap {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin-inline-start: 12px;
}

.plan-card--grouped .plan-card__period {
	font-size: 20px;
	color: var(--text-dark);
}

.plan-card--grouped.plan-card--featured .plan-card__period {
	color: var(--gold-primary);
}

.plan-card__price-note {
	color: var(--text-muted);
}

.plan-card--featured .plan-card__price-note {
	color: var(--text-white-82);
}

.plan-card__groups {
	margin: 0 0 30px;
	padding: 0;
	list-style: none;
}

.plan-card__group {
	display: grid;
	grid-template-columns: 70px minmax(0, 1fr);
	gap: 20px;
	padding-block: 22px;
}

/* The rule sits over the text column only, as in the comp. */
.plan-card__group-body {
	position: relative;
}

.plan-card__group-body::before {
	content: "";
	position: absolute;
	inset-block-start: -22px;
	inset-inline: 0;
	border-block-start: 1px solid rgba(11, 11, 12, .08);
}

.plan-card--featured .plan-card__group-body::before {
	border-color: var(--line-white-08);
}

.plan-card__group-icon img {
	display: block;
	width: 70px;
	height: 70px;
}

.plan-card__group-title {
	margin: 4px 0 10px;
	font: 400 24px/1.1 var(--font-display);
	letter-spacing: .02em;
	color: inherit;
}

.plan-card--featured .plan-card__group-title {
	color: var(--text-white);
}

.plan-card__items,
.plan-card__subitems {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.plan-card__items > li {
	position: relative;
	padding-inline-start: 18px;
}

.plan-card__items > li::before {
	content: "";
	position: absolute;
	inset-block-start: .6em;
	inset-inline-start: 0;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--gold-mid);
}

.plan-card__subitems {
	margin-block-start: 4px;
}

.plan-card__subitems > li {
	position: relative;
	padding-inline-start: 20px;
}

.plan-card__subitems > li::before {
	content: "-";
	position: absolute;
	inset-inline-start: 2px;
	color: var(--gold-mid);
	font-weight: 600;
}

.plan-card__items strong {
	font-weight: inherit;
	color: var(--gold-dark);
}

.plan-card--featured .plan-card__items strong {
	color: var(--gold-primary);
}

@media (max-width: 575.98px) {
	.plan-card.plan-card--grouped {
		padding: 30px 22px 26px;
	}

	.plan-card--grouped .plan-card__title {
		font-size: calc(40 * var(--fs));
	}

	.plan-card--grouped .plan-card__title-accent {
		font-size: 30px;
	}

	.plan-card--grouped .plan-card__head:has(.plan-card__head-icon) {
		padding-inline-end: 80px;
	}

	.plan-card--grouped .plan-card__head-icon img {
		width: 72px;
		height: 72px;
	}

	.plan-card--grouped .plan-card__amount {
		font-size: calc(76 * var(--fs));
	}

	.plan-card__group {
		grid-template-columns: 52px minmax(0, 1fr);
		gap: 14px;
	}

	.plan-card__group-icon img {
		width: 52px;
		height: 52px;
	}
}

.home-membership__footnote {
	margin-block-start: 34px;
	text-align: center;
	color: var(--text-muted);
}

@media (max-width: 1399.98px) {
	.home-membership {
		padding-block: calc(100 * var(--sp)) calc(80 * var(--sp));
	}
}

@media (max-width: 991.98px) {
	.home-membership__grid {
		grid-template-columns: minmax(0, 1fr);
		max-width: 480px;
		margin-inline: auto;
	}

	.plan-card--featured {
		padding-block: calc(46 * var(--sp)) calc(40 * var(--sp));
	}
}

@media (max-width: 767.98px) {
	.home-membership {
		padding-block: calc(70 * var(--sp));
	}
}

@media (max-width: 575.98px) {
	.plan-card {
		padding: 32px 24px 30px;
	}
}
