/* ==========================================================================
   Our Gallery - collection pages (/our-gallery/<model>/)
   ==========================================================================

   Shared layout for the five collection story pages. The CONTENT lives in each
   page's own _elementor_data (built by deploy-our-gallery/); everything here
   targets the generic .mm-gc-* classes that build emits, so this file is
   deployed once and is not touched again per collection.

   Loaded only on those pages - see mm-gallery-collection.php.

   TWO BREAKPOINT SYSTEMS, DELIBERATELY
     Page layout  1024 / 767  - what the sibling .mm-gal-* mosaic block uses.
                                The landing page and these pages are one visual
                                set and must break together.
     Sticky bar    921 / 544  - Astra's own values, copied verbatim at the
                                bottom of this file. "Matching the product
                                page" means matching where it reflows, too.

   TYPOGRAPHY: no font-family is set ANYWHERE in this file, on purpose. Astra
   sets Lato for body and h1-h6 site-wide, so inheriting guarantees Lato by
   construction and it cannot drift. Only size, weight, tracking and case are
   set here.

   Per-model colour and focus tokens are injected as custom properties on
   <body> by the loader, from postmeta. Defaults below keep the page sane if a
   meta is ever missing.

   HOW COLUMN WIDTHS ARE SET. Never with the `flex` shorthand - Elementor ships
       .e-con.e-flex { --flex-basis:auto; --flex-grow:0; --flex-shrink:1;
                       flex: var(--flex-grow) var(--flex-shrink) var(--flex-basis) }
   at specificity (0,2,0). Feed ITS variables instead - --flex-basis /
   --flex-grow / --flex-shrink, and --flex-direction for row vs column - and
   Elementor's own `flex` shorthand does the work, which also means the values
   still read correctly in the Elementor editor.

   Custom properties cascade like any other declaration, so a bare
   `.mm-gc-editorial { --flex-direction: row }` at (0,1,0) STILL loses to that
   rule. Every selector below that sets one of those four variables is
   therefore qualified `.e-con.e-flex...`, giving (0,3,0) - deterministic,
   rather than a (0,2,0) tie decided by enqueue order.

   Knock-on: once a base rule is qualified, ANY modifier of it must carry the
   same qualifier or it silently stops applying - `.mm-gc-cap-cell:first-child`
   at (0,2,0) lost to `.e-con.e-flex.mm-gc-cap-cell` at (0,3,0), which put a
   divider back on the first capability column. If you add a modifier here,
   qualify it.

   FONT WEIGHTS. This site loads Lato in 100, 400 and 700 ONLY (Astra's
   enqueue: family=Lato:400,100,700). Ask for 300 and the browser snaps to 100
   - Lato Thin - which is why a display headline can render as a ghost. Use
   400 or 700 here, nothing else.
   ========================================================================== */

body.mm-gc-page {
	--mm-gc-bg: #F5F1E8;
	--mm-gc-accent: #977E55;
	--mm-gc-accent-ink: #756242;
	--mm-gc-tint: #DDE6EB;

	--mm-gc-focus-hero: 50% 50%;
	--mm-gc-focus-worn: 50% 50%;
	--mm-gc-focus-signature: 50% 50%;

	--mm-gc-ink: #16161A;
	--mm-gc-muted: #6B6B72;
	--mm-gc-radius: 12px;
	--mm-gc-gap: 92px;

	background-color: var(--mm-gc-bg);
}

/* Astra's boxed article card would paint white over the page ground and add
   its own padding. The deploy script sets this page's Astra layout meta to
   page-builder / full-width-container, which is the real fix; these two rules
   are the belt-and-braces so the page still reads correctly if that meta is
   ever cleared from the admin. */
.mm-gc-page .ast-separate-container .ast-article-single,
.mm-gc-page .ast-separate-container .site-content > .ast-container {
	background: transparent;
	padding: 0;
	box-shadow: none;
}

/* Width is NOT set here. Elementor already owns it:
     :is(.elementor-section-wrap,[data-elementor-id])>.e-con
       { max-width: min(100%, var(--width)) }
   at (0,2,0), which outranks a plain .mm-gc-root rule. The build sets the
   container's real Elementor Width setting instead, so the cap stays editable
   in Layout > Width. */
.mm-gc-root {
	width: 100%;
	color: var(--mm-gc-ink);
	/* Page padding is NOT set here - it is the root container's own Elementor
	   Padding control, set by the build, so it stays adjustable in the editor
	   and does not fight Elementor's own .e-con-full rule at equal
	   specificity. See build_collection_page.py. */
}

/* Every section is a flex container; Elementor's own 20px --widgets-spacing is
   additive on top of child widths and silently wraps the last item onto its
   own line. The build zeroes it too (so the editor preview matches), but
   belt-and-braces here. */
.mm-gc-root > .e-con { gap: 0 !important; }
.mm-gc-root > .e-con + .e-con { margin-top: var(--mm-gc-gap); }

/* Shared eyebrow treatment: every small uppercase label on the page. Reached
   structurally - a css_classes on a widget is silently dropped by Elementor,
   so these are "the span-tag heading directly inside section X". */
.mm-gc-crumb .elementor-widget-heading span.elementor-heading-title,
.mm-gc-purpose > .elementor-widget-heading span.elementor-heading-title,
.mm-gc-capability > .elementor-widget-heading span.elementor-heading-title,
.mm-gc-ed > .elementor-widget-heading span.elementor-heading-title,
.mm-gc-next-body > .elementor-widget-heading:first-child span.elementor-heading-title {
	display: block;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.17em;
	text-transform: uppercase;
	line-height: 1.5;
}

/* --- 00 breadcrumb ------------------------------------------------------- */
.e-con.e-flex.mm-gc-crumb {
	--flex-direction: row;
	align-items: baseline;
	flex-wrap: wrap;
	padding: 0 !important;
}
/* The breadcrumb is a LABEL for the page, not a section of it, so it must not
   take the full inter-section gap. Left to the generic rule above it collected
   var(--mm-gc-gap) - 92px - plus its own margin, and read as an orphan
   stranded above the hero. Qualified with `.mm-gc-root >` so it beats that
   rule outright at (0,3,0) instead of tying at (0,2,0) and being decided by
   enqueue order. */
.mm-gc-root > .mm-gc-crumb + .e-con { margin-top: 22px; }

.mm-gc-crumb .elementor-widget-heading { width: auto !important; }
.mm-gc-crumb .elementor-widget-heading span.elementor-heading-title {
	color: var(--mm-gc-muted);
	font-weight: 500;
}
/* The model name carries the weight - it is where you are. "GALLERY" stays
   quiet, because it is only the way back. */
.mm-gc-crumb .elementor-widget-heading:last-child span.elementor-heading-title {
	color: var(--mm-gc-ink);
	font-weight: 700;
}
.mm-gc-crumb .elementor-widget-heading a { color: inherit; text-decoration: none; }
.mm-gc-crumb .elementor-widget-heading a:hover,
.mm-gc-crumb .elementor-widget-heading a:focus-visible { color: var(--mm-gc-accent-ink); }
/* Separator as CSS, so retyping either label in Elementor cannot lose it.
   Margins rather than spaces inside content: HTML collapses whitespace between
   inline elements, which rendered "GALLERY /MIRAGE". */
.mm-gc-crumb .elementor-widget-heading:first-child span.elementor-heading-title::after {
	content: "/";
	margin: 0 0.45em;
	color: var(--mm-gc-muted);
}

/* --- 01 campaign hero ---------------------------------------------------- */

.mm-gc-hero {
	position: relative;
	border-radius: var(--mm-gc-radius);
	overflow: hidden;
	padding: 0 !important;
	/* So the scroll cue's glyph can scale with the HERO's width rather than the
	   viewport's - the hero is capped at 1120px, so vw would drift. */
	container-type: inline-size;
}
.mm-gc-hero > .elementor-widget-image { width: 100%; }
.mm-gc-hero > .elementor-widget-image .elementor-widget-container,
.mm-gc-hero > .elementor-widget-image figure,
.mm-gc-hero > .elementor-widget-image a { display: block; margin: 0; }
.mm-gc-hero > .elementor-widget-image img {
	display: block;
	width: 100%;
	height: auto;
	/* No fixed height, ever. A fixed height against a fixed source ratio makes
	   the crop change AXIS with viewport width - the "shrinking crop window"
	   that cost four rounds of hand-tuned object-position on the home hero.
	   aspect-ratio + object-fit keeps the crop stable at every width. */
	/* --mm-gc-ar-desktop is written onto the <img> by the mu-plugin from the
	   attachment's REAL dimensions, so on desktop the hero is never cropped -
	   it is exactly the shape of whatever artwork is there. The supplied crops
	   are 2.91:1 because they stop above the campaign title the mockup had
	   painted in; drop in a taller text-free photograph and the band grows to
	   match, with no CSS change. 2.18 is only a fallback. */
	aspect-ratio: var(--mm-gc-ar-desktop, 2.18);
	object-fit: cover;
	object-position: var(--mm-gc-focus-hero);
}
/* A <picture> is an inline element by default and would add a baseline gap
   under the photograph. */
.mm-gc-picture { display: block; }

/* A BAKED hero would carry its campaign title IN THE PIXELS, so it must never
   be cropped: any narrower frame slices the type. It therefore keeps the
   artwork's own ratio at EVERY width. Nothing uses this today - all five
   heroes are text-free and live - but it stays for artwork that ever arrives
   pre-composed, and it is why the responsive ratios below are scoped to
   .mm-gc-hero-live. */
.mm-gc-hero-baked > .elementor-widget-image img {
	aspect-ratio: var(--mm-gc-ar-desktop, 2.18) !important;
}
/* ...unless a per-breakpoint variant has been set on the image, in which case
   that artwork's own ratio wins at that breakpoint - a portrait mobile hero
   gets a portrait frame, and only then does the hero go tall on a phone. */
@media (max-width: 1024px) {
	.mm-gc-hero-baked > .elementor-widget-image img {
		aspect-ratio: var(--mm-gc-ar-tablet, var(--mm-gc-ar-desktop, 2.18)) !important;
	}
}
@media (max-width: 767px) {
	.mm-gc-hero-baked > .elementor-widget-image img {
		aspect-ratio: var(--mm-gc-ar-mobile, var(--mm-gc-ar-desktop, 2.18)) !important;
	}
}

/* Live-overlay mode - what all five heroes use. The eyebrow and campaign
   title are real Elementor widgets sitting over a CSS scrim, so they are
   edited on the page like any other text. That is only possible because the
   extractor crops each hero ABOVE the title the mockup had painted into the
   photograph; see extract_collection_images.py. */
/* The scrim has to carry white text over FIVE unrelated photographs, three of
   which are bright (a white wall, a sunlit street, pale marble). It is
   therefore deliberately strong and starts high: measured against the rendered
   pixels behind each title, every model clears 7:1. A gentler gradient tuned
   on one photo left the Matrix title almost invisible against his shirt. */
.mm-gc-hero-live::after {
	content: "";
	position: absolute;
	inset: 22% 0 0;
	background: linear-gradient(to bottom,
		rgba(10,10,12,0) 0%,
		rgba(10,10,12,0.30) 42%,
		rgba(10,10,12,0.66) 72%,
		rgba(10,10,12,0.86) 100%);
	pointer-events: none;
	/* The scrim is a ::after on .mm-gc-hero, so in DOM order it comes AFTER
	   the caption. Among positioned elements with z-index:auto, paint order IS
	   DOM order - so without this it painted straight over the title, and the
	   brightest glyph pixel measured (92,92,93) instead of white. */
	z-index: 1;
}

/* ...and the caption and scroll cue must sit ABOVE it. A plain `z-index: 2` on
   these is (0,1,0), which Elementor's own container rule ties with - it
   silently computed to `auto`, which is how the scrim got on top in the first
   place. Feed Elementor's variable from a qualified selector, exactly as the
   flex and padding rules elsewhere in this file have to. */
.e-con.e-flex.mm-gc-hero-caption,
.e-con.e-flex.mm-gc-hero-cue { --z-index: 3; z-index: 3; }
.mm-gc-hero-caption {
	position: absolute !important;
	left: 46px;
	bottom: 38px;
	width: auto !important;
	max-width: 78%;
	padding: 0 !important;
}
.mm-gc-hero-caption span.elementor-heading-title {
	display: block;
	color: rgba(255,255,255,0.92);
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	margin-bottom: 10px;
	/* Belt and braces over an arbitrary photograph an admin may swap in. */
	text-shadow: 0 1px 12px rgba(0,0,0,0.55);
}
.mm-gc-hero-caption h1.elementor-heading-title {
	color: #fff;
	font-size: clamp(34px, 4.4vw, 62px);
	font-weight: 400;
	letter-spacing: 0.002em;
	line-height: 1.04;
	margin: 0;
	text-shadow: 0 2px 18px rgba(0,0,0,0.5);
	/* Astra sets overflow-wrap: break-word globally, which at 320px split
	   "TRANSFORMS." across two lines as "TRANSFORM" / "S.". A campaign title
	   wraps between words or not at all. */
	overflow-wrap: normal;
	word-break: keep-all;
}
/* THE SCROLL CUE.
   Once the hero crop moved above the campaign title it also cut away the white
   disc the mockup had painted into the corner, so this button no longer has to
   line up with anything - it IS the cue. Which is a good thing: the old
   centre-anchored percentages, tuned to that painted disc, pushed the button
   3px past the hero's right edge at 375px once the 44px minimum tap size
   kicked in, and `overflow: hidden` quietly clipped it.

   So: plain insets, and a size that scales with the hero but never drops below
   a 44px tap target or grows past 60px. */
.mm-gc-hero-cue {
	position: absolute !important;
	right: 26px;
	bottom: 24px;
	width: clamp(44px, 5%, 60px) !important;
	aspect-ratio: 1;
	padding: 0 !important;
}
.mm-gc-hero-cue .elementor-button-wrapper,
.mm-gc-hero-cue .elementor-widget-button,
.mm-gc-hero-cue .elementor-widget-container { width: 100%; height: 100%; }
.mm-gc-hero-cue .elementor-button {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	padding: 0;
	border-radius: 50%;
	background: #FBF9F5;
	font-size: max(1.9cqw, 15px);
	line-height: 1;
	box-shadow: 0 2px 14px rgba(0,0,0,0.18);
	transition: transform .25s ease, background-color .25s ease;
}
/* Astra colours BOTH .elementor-button and .elementor-button:visited from its
   global palette, and the :visited half lands at (0,3,0) - so once a visitor
   has been to the target page the label turns black on black and disappears.
   Out-specify it on every state. Same trap applies to the CONTINUE button. */
/* Astra also styles .elementor-widget-button .elementor-button at (0,2,0),
   which tied with a plain .mm-gc-hero-cue .elementor-button and won on enqueue
   order - so the cue rendered as a hard-edged SQUARE sitting on top of the
   round painted disc. Radius and colour are both pinned at (0,3,0) here. */
.mm-gc-hero-cue .elementor-widget-button .elementor-button,
.mm-gc-hero-cue .elementor-widget-button .elementor-button:visited,
.mm-gc-hero-cue .elementor-widget-button .elementor-button:hover,
.mm-gc-hero-cue .elementor-widget-button .elementor-button:focus {
	color: #16161A;
	border-radius: 50%;
	border: 0;
}
.mm-gc-hero-cue .elementor-button:hover { background: #fff; transform: translateY(3px); }

/* --- 02 human purpose ---------------------------------------------------- */

.mm-gc-purpose { padding: 0 !important; }
/* Cleared by the sticky header when the hero's scroll cue jumps here. */
.mm-gc-purpose { scroll-margin-top: var(--mm-gc-scroll-offset, 110px); }
.mm-gc-purpose > .elementor-widget-heading span.elementor-heading-title {
	color: var(--mm-gc-accent-ink);
	margin-bottom: 26px;
}
.e-con.e-flex.mm-gc-purpose-row {
	--flex-direction: row;
	align-items: flex-start;
	padding: 0 !important;
}
/* margin instead of gap: Elementor writes its own --gap onto the element and
   fighting it needs !important on a property we would rather leave alone. */
.e-con.e-flex.mm-gc-purpose-left { --flex-basis: 52%; --flex-grow: 0; --flex-shrink: 0; padding: 0 !important; }
.e-con.e-flex.mm-gc-purpose-right { --flex-basis: 40%; --flex-grow: 0; --flex-shrink: 0; margin-left: 8%; padding: 0 !important; }

.mm-gc-purpose-left h2.elementor-heading-title {
	font-size: clamp(30px, 3.7vw, 47px);
	font-weight: 400;
	letter-spacing: -0.012em;
	line-height: 1.13;
	margin: 0;
	text-wrap: balance;
}
.mm-gc-purpose-right .elementor-widget-text-editor {
	font-size: 18px;
	font-weight: 400;
	line-height: 1.62;
	color: var(--mm-gc-muted);
	padding-top: 6px;
}
.mm-gc-purpose-right .elementor-widget-text-editor p:last-child { margin-bottom: 0; }
/* The short accent rule under the paragraph. */
.mm-gc-purpose-right::after {
	content: "";
	display: block;
	width: 224px;
	max-width: 100%;
	height: 3px;
	margin-top: 30px;
	background: var(--mm-gc-accent);
}

/* --- 03 editorial pair --------------------------------------------------- */
.e-con.e-flex.mm-gc-editorial {
	--flex-direction: row;
	align-items: flex-start;
	padding: 0 !important;
}
/* 40.2 / 55 against the two aspect-ratios below makes both frames exactly the
   same height, which is what the mockup does:
     1100 x 0.402 / 0.934 = 473    1100 x 0.55 / 1.279 = 473
   Change one and you must change the other. */
.mm-gc-ed { padding: 0 !important; }
.e-con.e-flex.mm-gc-ed-1 { --flex-basis: 40.2%; --flex-grow: 0; --flex-shrink: 0; }
.e-con.e-flex.mm-gc-ed-2 { --flex-basis: 55%;   --flex-grow: 0; --flex-shrink: 0; margin-left: 2.8%; }

.mm-gc-ed-frame {
	border-radius: var(--mm-gc-radius);
	overflow: hidden;
	padding: 0 !important;
}
.mm-gc-ed-frame .elementor-widget-image { width: 100%; }
.mm-gc-ed-frame .elementor-widget-container,
.mm-gc-ed-frame figure { margin: 0; display: block; }
.mm-gc-ed-frame img {
	display: block;
	width: 100%;
	height: auto;
	object-fit: cover;
}
.mm-gc-ed-1 .mm-gc-ed-frame img {
	aspect-ratio: 0.934;
	object-position: var(--mm-gc-focus-worn);
}
.mm-gc-ed-2 .mm-gc-ed-frame img {
	aspect-ratio: 1.279;
	object-position: var(--mm-gc-focus-signature);
}
.mm-gc-ed > .elementor-widget-heading span.elementor-heading-title {
	color: var(--mm-gc-muted);
	margin-top: 20px;
}

/* --- 04 capability strip ------------------------------------------------- */

.mm-gc-capability {
	background: var(--mm-gc-tint);
	border-radius: 14px;
	padding: 32px 44px 38px !important;
}
.mm-gc-capability > .elementor-widget-heading span.elementor-heading-title {
	color: var(--mm-gc-accent-ink);
	margin-bottom: 30px;
}
.e-con.e-flex.mm-gc-cap-row {
	--flex-direction: row;
	align-items: stretch;
	padding: 0 !important;
}
/* An equal share rather than a fixed third, so 2 or 4 labels lay out correctly
   too - an admin can duplicate a cell in Elementor and get a fourth column
   with no code change. */
.e-con.e-flex.mm-gc-cap-cell {
	--flex-basis: 0%;
	--flex-grow: 1;
	--flex-shrink: 1;
	min-width: 0;
	padding: 4px 0 4px 34px !important;
	border-left: 1px solid rgba(22,22,26,0.16);
}
.e-con.e-flex.mm-gc-cap-cell:first-child { padding-left: 0 !important; border-left: 0; }
.mm-gc-cap-cell span.elementor-heading-title {
	display: block;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	line-height: 1.45;
	color: var(--mm-gc-ink);
}

/* --- 05 next collection -------------------------------------------------- */
.e-con.e-flex.mm-gc-next {
	position: relative;
	--flex-direction: row;
	align-items: center;
	padding: 0 !important;
}
.e-con.e-flex.mm-gc-next-photo {
	--flex-basis: 40%;
	--flex-grow: 0;
	--flex-shrink: 0;
	border-radius: var(--mm-gc-radius);
	overflow: hidden;
	padding: 0 !important;
}
.mm-gc-next-photo .elementor-widget-image { width: 100%; }
.mm-gc-next-photo .elementor-widget-container,
.mm-gc-next-photo figure,
.mm-gc-next-photo a { display: block; margin: 0; }
.mm-gc-next-photo img {
	display: block;
	width: 100%;
	height: auto;
	/* Same ratio as the signature slot (.mm-gc-ed-2), deliberately: this frame
	   shows the NEXT model's signature banner, and --mm-gc-focus-next is that
	   model's signature focus. A different ratio here would move the window and
	   re-introduce the clipped banner type that focus point was chosen to
	   avoid. One ratio + one focus per image, everywhere. */
	aspect-ratio: 1.279;
	object-fit: cover;
	object-position: var(--mm-gc-focus-next, 50% 50%);
	transition: transform .6s cubic-bezier(.2,.6,.2,1);
}
.e-con.e-flex.mm-gc-next-body {
	--flex-basis: 54%;
	--flex-grow: 0;
	--flex-shrink: 0;
	margin-left: 6%;
	padding: 0 !important;
}
.mm-gc-next-body > .elementor-widget-heading:first-child span.elementor-heading-title {
	color: var(--mm-gc-muted);
}
.mm-gc-next-body h2.elementor-heading-title {
	font-size: clamp(26px, 3.2vw, 41px);
	font-weight: 400;
	letter-spacing: 0.004em;
	line-height: 1.1;
	margin: 14px 0 30px;
	text-wrap: balance;
}
.mm-gc-next-body .elementor-button {
	display: inline-flex;
	align-items: center;
	background: #16161A;
	border-radius: 999px;
	padding: 15px 34px;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.17em;
	text-transform: uppercase;
	transition: background-color .25s ease, transform .25s ease;
}
/* Astra sets `.elementor-widget-button .elementor-button:visited { color:
   var(--ast-global-color-2) }` - and that palette slot is #000000. At (0,3,0)
   it beat a plain `.mm-gc-next-body .elementor-button { color:#fff }` (0,2,0),
   so the moment a visitor had been to the next collection the label went black
   on a black pill and vanished. Every state is pinned here at (0,4,0). */
.mm-gc-next-body .elementor-widget-button .elementor-button,
.mm-gc-next-body .elementor-widget-button .elementor-button:visited,
.mm-gc-next-body .elementor-widget-button .elementor-button:hover,
.mm-gc-next-body .elementor-widget-button .elementor-button:focus { color: #fff; }

/* The arrow is CSS, so the button's editable text stays clean ("CONTINUE") and
   an admin retyping it cannot lose the arrow. */
.mm-gc-next-body .elementor-button .elementor-button-text::after { content: " \2192"; }
.mm-gc-next-body .elementor-button:hover,
.mm-gc-next-body .elementor-button:focus-visible {
	background: var(--mm-gc-accent-ink);
	transform: translateY(-2px);
}

/* Hover lift on the next-collection photo, real mice only. Headless Chrome
   reports hover:none, so this branch does not render in a default screenshot -
   pass --blink-settings=primaryHoverType=2,availableHoverTypes=2 to see it. */
@media (hover: hover) and (pointer: fine) {
	.mm-gc-next-photo:hover img,
	.mm-gc-next-photo:focus-within img { transform: scale(1.035); }
}

.mm-gc-root a:focus-visible {
	outline: 2px solid var(--mm-gc-accent-ink);
	outline-offset: 3px;
}

/* ==========================================================================
   Tablet - 1024
   ========================================================================== */

@media (max-width: 1024px) {
	body.mm-gc-page { --mm-gc-gap: 66px; }
	.mm-gc-root > .mm-gc-crumb + .e-con { margin-top: 18px; }

	/* A gentle crop only. The artwork is 2.91:1, so anything much squarer
	   throws away most of its width. */
	.mm-gc-hero > .elementor-widget-image img {
		aspect-ratio: var(--mm-gc-ar-tablet, 2.3);
	}
	/* The hero title has to stay clearly dominant. Left to the desktop clamps,
	   it and the purpose headline both bottomed out at their floors here -
	   34px against 30px - and the hierarchy flattened to nothing. Set both
	   explicitly per breakpoint rather than trusting one clamp to behave over a
	   4x range of widths. */
	.mm-gc-hero-caption h1.elementor-heading-title { font-size: clamp(34px, 5.2vw, 46px); }
	.mm-gc-purpose-left h2.elementor-heading-title { font-size: clamp(26px, 3.4vw, 32px); }

	.mm-gc-hero-caption { left: 32px; bottom: 30px; max-width: 82%; }
	.mm-gc-hero-cue { display: none !important; }
	/* 44/52 rather than 50/44: at 768 the paragraph column was down to about
	   36 characters a line. This brings it back to ~43, which is comfortable
	   for a two-line supporting sentence. */
	.e-con.e-flex.mm-gc-purpose-left { --flex-basis: 44%; }
	.e-con.e-flex.mm-gc-purpose-right { --flex-basis: 52%; margin-left: 4%; }
	.mm-gc-purpose-right .elementor-widget-text-editor { font-size: 17px; }
	/* The editorial pair keeps its DESKTOP 40.2 / 55 split here on purpose.
	   Those two numbers are what make the two frames the same height against
	   their 0.934 and 1.279 aspect-ratios; retuning them to 44 / 53 for tablet
	   silently broke that (473 vs 416 at 1024px). The split is a proportion,
	   so it needs no breakpoint of its own. */

	.mm-gc-capability { padding: 28px 32px 32px !important; }
	.mm-gc-cap-cell { padding-left: 24px !important; }
	.mm-gc-cap-cell span.elementor-heading-title { font-size: 12px; letter-spacing: 0.1em; }
	/* Held below the purpose headline at this width too - the desktop clamp's
	   floor otherwise pulled it level with it at 768. */
	.mm-gc-next-body h2.elementor-heading-title { font-size: clamp(22px, 3vw, 30px); }
	.e-con.e-flex.mm-gc-next-photo { --flex-basis: 44%; }
	.e-con.e-flex.mm-gc-next-body { --flex-basis: 51%; margin-left: 5%; }
}

/* ==========================================================================
   Mobile - 767
   ========================================================================== */

@media (max-width: 767px) {
	body.mm-gc-page { --mm-gc-gap: 50px; }
	.mm-gc-root > .mm-gc-crumb + .e-con { margin-top: 14px; }

	/* Portrait hero. A 2.18:1 band is a letterbox sliver on a phone, so the
	frame turns portrait and the per-model focus point (from postmeta)
	decides which part of the artwork survives the crop. */
	/* 1.5:1 keeps a hero worth looking at on a phone (~260px tall at 390px)
	   while still showing half the artwork's width; the per-model focus point
	   decides which half. A portrait 0.8:1 frame would show barely a quarter
	   of a 2.91:1 photograph. Set a Gallery mobile variant on the image and
	   its own ratio takes over instead. */
	.mm-gc-hero > .elementor-widget-image img {
		aspect-ratio: var(--mm-gc-ar-mobile, 1.5);
	}
	.mm-gc-hero-live::after { inset: 30% 0 0; }
	.mm-gc-hero-caption { left: 20px; right: 20px; bottom: 22px; max-width: none; }

	/* The floor has to let the longest single word ("TRANSFORMS.") fit the
	   caption's width at 320px, or it has nowhere to wrap to. */
	.mm-gc-hero-caption h1.elementor-heading-title { font-size: clamp(24px, 7.4vw, 34px); }
	.mm-gc-hero-caption span.elementor-heading-title { font-size: 10px; margin-bottom: 7px; }

	/* Purpose stacks; the accent rule follows the paragraph. */
	.e-con.e-flex.mm-gc-purpose-row { --flex-direction: column; }
	.e-con.e-flex.mm-gc-purpose-left,
	.e-con.e-flex.mm-gc-purpose-right { --flex-basis: auto; width: 100%; margin-left: 0; }
	.mm-gc-purpose-right { margin-top: 22px; }
	.mm-gc-purpose-left h2.elementor-heading-title { font-size: clamp(23px, 6vw, 27px); }
	.mm-gc-purpose-right .elementor-widget-text-editor { font-size: 16px; padding-top: 0; }
	.mm-gc-purpose-right::after { width: 150px; margin-top: 24px; }

	/* Editorial pair stacks. Deliberately NOT a swipe carousel: for two items
	a gesture hides half the content for no gain. */
	.e-con.e-flex.mm-gc-editorial { --flex-direction: column; }
	.e-con.e-flex.mm-gc-ed-1,
	.e-con.e-flex.mm-gc-ed-2 { --flex-basis: auto; width: 100%; margin-left: 0; }
	/* Qualified: a plain `.mm-gc-ed-2 { margin-top }` is (0,1,0) and Elementor's
	   own .e-con margin rule zeroed it, so the second photo sat flush against
	   the first one's caption. Same trap as the flex and padding rules. */
	.mm-gc-editorial > .mm-gc-ed-1 + .mm-gc-ed-2 { margin-top: 36px; }
	.mm-gc-ed-1 .mm-gc-ed-frame img,
	.mm-gc-ed-2 .mm-gc-ed-frame img { aspect-ratio: 1.15; }
	.mm-gc-ed > .elementor-widget-heading span.elementor-heading-title { margin-top: 14px; }

	/* Capability strip stacks; the vertical rules become horizontal. */
	.mm-gc-capability { padding: 24px 22px 26px !important; border-radius: 12px; }
	.mm-gc-capability > .elementor-widget-heading span.elementor-heading-title { margin-bottom: 18px; }
	.e-con.e-flex.mm-gc-cap-row { --flex-direction: column; }
	.e-con.e-flex.mm-gc-cap-cell {
		--flex-basis: auto;
		--flex-grow: 0;
		width: 100%;
		padding: 13px 0 !important;
		border-left: 0;
		border-top: 1px solid rgba(22,22,26,0.16);
	}
	.e-con.e-flex.mm-gc-cap-cell:first-child { padding-top: 0 !important; border-top: 0; }

	/* Next collection stacks, photo first. */
	.e-con.e-flex.mm-gc-next { --flex-direction: column; align-items: stretch; }
	.e-con.e-flex.mm-gc-next-photo,
	.e-con.e-flex.mm-gc-next-body { --flex-basis: auto; width: 100%; margin-left: 0; }
	/* Ratio deliberately NOT changed here - see .mm-gc-next-photo img above. */
	.mm-gc-next > .mm-gc-next-photo + .mm-gc-next-body { margin-top: 28px; }
	/* Below the purpose headline on purpose - this is a teaser for the next
	   page, not the subject of this one. At 375px the fixed 27px made it the
	   largest thing on the page after the hero. */
	.mm-gc-next-body h2.elementor-heading-title { font-size: clamp(21px, 5.2vw, 25px); margin: 10px 0 24px; }
}

@media (prefers-reduced-motion: reduce) {
	.mm-gc-next-photo img,
	.mm-gc-next-body .elementor-button,
	.mm-gc-hero-cue .elementor-button { transition: none !important; }
	.mm-gc-next-photo:hover img { transform: none; }
}

/* ==========================================================================
   Sticky Add to Cart / Buy Now bar
   ==========================================================================

   Section 05 of the client's master template is "PRODUCT DETAIL - persistent
   CTA -> product detail", and its mobile-logic panel calls it the "sticky
   model CTA". So this bar is a layout requirement of these pages, not a
   bolt-on.

   Astra's own bar is unreachable here: the markup renderer, the stylesheet
   enqueue (class-astra-woocommerce.php:822), the dynamic CSS (~:2660) and the
   script are each independently gated on is_product(). A collection page
   returns ZERO occurrences of ast-sticky-add-to-cart. So the rules below are
   transplanted verbatim from
     themes/astra/assets/css/minified/compatibility/woocommerce/sticky-add-to-cart.min.css
   plus the "position: bottom" block Astra prints inline, re-indented and
   scoped under .mm-gc-sticky-wrap.

   Because it IS a fork: if Astra ever redesigns its sticky bar, the product
   pages change and these do not. There is no filter on the is_product() gate,
   so this is unavoidable - treat it as a checkpoint at the next Astra major.

   BREAKPOINTS HERE ARE 921 / 544 - Astra's, not this page's 1024 / 767.
   Matching the product page means matching where it reflows too.
   ========================================================================== */

.mm-gc-sticky-wrap .ast-sticky-add-to-cart {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	top: initial;
	opacity: 0;
	z-index: 1200;
	transform: translate(0, 100%);
	transition: opacity .4s ease-in-out, transform .6s ease-in-out, outline .15s ease;
	background-color: var(--ast-global-color-primary, var(--ast-global-color-5, #fff));
	box-shadow: 0 -1px 10px rgba(0,0,0,0.1), 0 -1px 9px rgba(0,0,0,0.06);
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart.is-active {
	transform: translate(0, 0);
	opacity: 1;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart .ast-sticky-add-to-cart-content {
	display: flex;
	min-height: 60px;
	padding: 10px 0;
	color: var(--ast-global-color-2, #16161A);
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-title-wrap {
	display: flex;
	align-items: center;
	flex-grow: 1;
	min-width: 0;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-title-wrap img {
	max-height: 50px;
	width: auto;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-title {
	padding: 5px 20px;
	font-size: 18px;
	font-weight: inherit;
	line-height: 1.5;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-wrap {
	display: flex;
	align-items: center;
	justify-content: flex-end;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-wrap .cart {
	display: flex;
	align-items: center;
	margin: 0;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-price {
	font-weight: 700;
	padding-right: 20px;
	white-space: nowrap;
}
.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-price del {
	opacity: .5;
	font-weight: 400;
}
.mm-gc-sticky-wrap.woocommerce div.ast-sticky-add-to-cart-action-wrap .button.single_add_to_cart_button {
	padding: 11px 25px;
	width: 100%;
}

/* Add to Cart + Buy Now travel as one unit, so on a narrow screen the pair
   wraps together instead of Buy Now splitting onto its own line. Same class
   and intent as the product page's own pairing - carried here because that
   rule lives inside an is_product()-gated style block. */
.mm-gc-sticky-wrap .mm-cart-buttons-group {
	display: inline-flex !important;
	flex-wrap: nowrap;
	align-items: center;
	gap: 10px;
	max-width: 100%;
}
.mm-gc-sticky-wrap .mm-cart-buttons-group .single_add_to_cart_button {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
	margin: 0 !important;
	white-space: nowrap;
}

@media (max-width: 921px) {
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart-title-wrap > img { display: none; }
	.mm-gc-sticky-wrap div.ast-sticky-add-to-cart .ast-sticky-add-to-cart-content .ast-sticky-add-to-cart-title-wrap .ast-sticky-add-to-cart-title { padding-left: 0; }
}

@media (max-width: 544px) {
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart .ast-sticky-add-to-cart-content div.ast-sticky-add-to-cart-title-wrap,
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-price { display: none; }
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-wrap,
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-wrap > form { width: 100%; }
	.mm-gc-sticky-wrap .mm-cart-buttons-group { width: 100%; }
	.mm-gc-sticky-wrap .mm-cart-buttons-group .single_add_to_cart_button { flex: 1 1 0; }
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart-action-wrap .single_link_to_cart_button { width: 100%; text-align: center; }
}

/* Clearance so the bar never covers the footer's last row. Deliberately our
   own class, not Astra's ast-sticky-cart-active: the live Additional CSS rule
   for that one is scoped .single-product, so reusing the class here would be a
   confusing half-match. */
body.mm-gc-sticky-active .site-footer { padding-bottom: 100px; }

@media (prefers-reduced-motion: reduce) {
	.mm-gc-sticky-wrap .ast-sticky-add-to-cart { transition: opacity .01s linear; }
}
