/* Pages CMS — public block styles. Blocks lean on Bootstrap (grid, cards,
   accordion, ratio, utilities); this file carries only what Bootstrap can't:
   the full-bleed breakout, the hero, the lightbox and Swiper accents.
   Color-mode aware — use --bs-* variables, not hard-coded colors. */
/* Full-bleed breakout: a block escapes the container by going 100vw wide and pulling
   itself back by half. 100vw INCLUDES the scrollbar gutter, so the block overhangs the
   viewport by the scrollbar width and something has to absorb it.

   body{overflow-x:hidden} alone does not: the ROOT element still scrolls, so the user
   can drag right into a white gutter (12px on a desktop Chrome). Both elements need it.

   clip rather than hidden, deliberately: overflow:hidden makes an element a scroll
   container, and a scroll-container root breaks position:sticky for everything inside
   it. clip has no such side effect. The hidden line stays FIRST as the fallback for
   engines predating clip (Safari < 16) — they keep exactly today's behaviour, and
   everything newer gets the complete version. */
body { overflow-x: hidden; }
html, body { overflow-x: clip; }
.cms-page .cms-block { width: 100vw; position: relative; left: 50%; margin-left: -50vw; }

/* ── Hero banner (full-viewport media + overlay — no Bootstrap equivalent) ── */
.cms-hero { height: 100vh; min-height: 420px; overflow: hidden; background: #111; }
.cms-hero--half { height: 55vh; }
.cms-hero__media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cms-hero picture { position: absolute; inset: 0; display: block; }
.cms-hero__swiper { position: absolute; inset: 0; height: 100%; }
.cms-hero .swiper-slide { position: relative; }
/* The overlay paints above the slider but must not swallow clicks meant for
   the arrows/dots underneath — only its own content stays interactive. */
.cms-hero__overlay { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center;
	justify-content: center; text-align: center; background: rgba(0,0,0,.28); padding: 0 20px;
	pointer-events: none; }
.cms-hero__overlay .cms-hero__inner { pointer-events: auto; }
.cms-hero .swiper-button-prev, .cms-hero .swiper-button-next { color: #fff; z-index: 10;
	--swiper-navigation-size: 34px; text-shadow: 0 2px 8px rgba(0,0,0,.5); }
.cms-hero .swiper-button-prev { left: clamp(20px, 4.5vw, 80px); }
.cms-hero .swiper-button-next { right: clamp(20px, 4.5vw, 80px); }
.cms-hero .swiper-pagination { z-index: 10; }
.cms-hero__heading { color: #fff; font-size: clamp(28px, 5vw, 56px); font-weight: 800; margin: 0 0 10px; }
.cms-hero__sub { color: #fff; opacity: .92; font-size: clamp(15px, 2vw, 22px); margin: 0 0 22px; }
.cms-hero .swiper-pagination-bullet { background: #fff; opacity: .55; }
.cms-hero .swiper-pagination-bullet-active { opacity: 1; }

/* ── Rich content body (authored HTML needs guardrails) ── */
.cms-rich__body { line-height: 1.75; }
.cms-rich__body img { max-width: 100%; height: auto; border-radius: var(--bs-border-radius); }
.cms-rich__body table { border-collapse: collapse; width: 100%; }
.cms-rich__body td, .cms-rich__body th { border: 1px solid var(--bs-border-color); padding: 8px 12px; }

/* ── Gallery lightbox ── */
.cms-lb-overlay { position: fixed; inset: 0; z-index: 9999; background: rgba(0,0,0,.88);
	display: flex; align-items: center; justify-content: center; cursor: zoom-out; }
.cms-lb-overlay img { max-width: 94vw; max-height: 92vh; border-radius: 8px; }

/* ── Carousel (Swiper accents) ── */
.cms-car__swiper { padding-bottom: 34px; }
.cms-car .swiper-button-prev, .cms-car .swiper-button-next { color: var(--bs-primary); --swiper-navigation-size: 26px; }
.cms-car__box { position: relative; }
/* Arrows beside the slides. They are siblings of .swiper here, positioned against
   .cms-car__box — padding the slider itself would let neighbouring slides show
   through in the padding, because .swiper clips to its padding box. */
@media (min-width: 992px) {
	.cms-car--navout .cms-car__box { padding-inline: 64px; }
	.cms-car--navout .swiper-button-prev { left: 0; }
	.cms-car--navout .swiper-button-next { right: 0; }
	.cms-car--navout .swiper-button-prev, .cms-car--navout .swiper-button-next { margin-top: 0; transform: translateY(-50%); }
}
/* Wide enough that the container's own margin can absorb the arrows: pull the box
   into the gutter so the slides keep full container width and the arrows sit
   completely clear of them. Below this the arrows stay inside the container edge
   (still outside the slides) rather than risking horizontal overflow. */
@media (min-width: 1450px) {
	.cms-car--navout .cms-car__box { margin-inline: -64px; }
}
.cms-car .swiper-pagination-bullet-active { background: var(--bs-primary); }

/* ── Embed (raw HTML can't be wrapped in .ratio reliably) ── */
.cms-embed__inner iframe { width: 100%; aspect-ratio: 16/9; height: auto; border: 0; border-radius: var(--bs-border-radius); }

/* ── Hero variants (page banners) ── */
.cms-hero--short { height: 46vh; min-height: 360px; max-height: 560px; }
.cms-hero__overlay--left { justify-content: flex-start; text-align: left;
	padding-left: clamp(24px, 9vw, 160px); padding-right: 24px;
	background: linear-gradient(90deg, rgba(0,0,0,.45) 0%, rgba(0,0,0,.15) 55%, rgba(0,0,0,0) 100%); }

/* ── Icon features ── */
/* FA7 gives icons a fixed box (width:1.25em), so text-align can't center them
   in the column — the box itself must center via auto margins. */
.cms-if__icon { height: 72px; width: auto; display: block; margin-left: auto; margin-right: auto; }
.cms-if__fa { font-size: 56px; display: block; margin-left: auto; margin-right: auto; }
.cms-if--left .cms-if__icon, .cms-if--left .cms-if__fa { margin-left: 0; margin-right: 0; }

/* ── Career tiles ── */
.cms-career__tile { background: #3d454e; color: #fff; border-radius: 4px; min-height: 130px;
	transition: transform .15s, box-shadow .15s; }
.cms-career__tile:hover { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(0,0,0,.25); background: #454e58; }

/* ── Hero image-fit variants (after the height rules so they win) ── */
.cms-hero--contain .cms-hero__media { object-fit: contain; }
/* "Match image": banner height follows the artwork — desktop 1920x900, mobile 1080x1350. */
.cms-hero--ratio { height: auto; min-height: 0; max-height: none; aspect-ratio: 1920 / 900; }
@media (max-width: 767px) { .cms-hero--ratio { aspect-ratio: 1080 / 1350; } }

/* ── Per-block spacing overrides (Renderer wraps blocks that set them) ── */
.cms-pad[style*="--cms-pt"] > .cms-block { padding-top: var(--cms-pt) !important; }
.cms-pad[style*="--cms-pb"] > .cms-block { padding-bottom: var(--cms-pb) !important; }
/* Section width: the block keeps its full-bleed background; only the inner container narrows.
   Beats Bootstrap's breakpoint max-widths on specificity, never on !important. */
.cms-pad[style*="--cms-max"] .cms-block .container { max-width: min(var(--cms-max), 100%); }

/* ── Album gallery ── */
.cms-alb__cover { cursor: pointer; }
.cms-alb__title { position: absolute; inset: auto 0 0 0; padding: 40px 16px 14px; color: #fff;
	font-weight: 600; font-size: 14px; letter-spacing: .02em;
	background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.75) 100%);
	opacity: 0; transition: opacity .2s; }
.cms-alb__cover:hover .cms-alb__title, .cms-alb__cover:focus .cms-alb__title { opacity: 1; }
@media (hover: none) { .cms-alb__title { opacity: 1; } }
.cms-alb__modal .modal-content { background: #23262b; color: #fff; }
/* Album covers: name + tagline + count as one label; centred variant is always visible over a tint. */
.cms-alb__title { display: flex; flex-direction: column; gap: 2px; }
.cms-alb__tag { font-weight: 400; font-size: 12px; letter-spacing: .04em; opacity: .9; }
.cms-alb__count { font-weight: 400; font-size: 11px; letter-spacing: .04em; opacity: .75; }
.cms-alb__title--center { inset: 0; padding: 16px; align-items: center; justify-content: center; text-align: center; opacity: 1;
	background: rgba(0, 0, 0, .28); transition: background .25s; }
.cms-alb__title--center .cms-alb__name { font-size: clamp(1.05rem, .8rem + .9vw, 1.5rem); letter-spacing: .08em; }
.cms-alb__cover:hover .cms-alb__title--center, .cms-alb__cover:focus .cms-alb__title--center { background: rgba(0, 0, 0, .42); }
.cms-alb__cover img { transition: transform .5s ease; }
.cms-alb__cover:hover img { transform: scale(1.04); }
/* Natural-height album grid: CSS columns keep portraits and landscapes at their own shape. */
.cms-alb__masonry { column-count: 2; column-gap: 8px; }
.cms-alb__masonry--3 { column-count: 3; } .cms-alb__masonry--4 { column-count: 4; }
.cms-alb__photo { break-inside: avoid; margin: 0 0 8px; }
@media (max-width: 767px) { .cms-alb__masonry, .cms-alb__masonry--3, .cms-alb__masonry--4 { column-count: 2; } }

/* lightbox chrome (counter, arrows, close) */
.cms-lb-count { position: fixed; left: 24px; bottom: 18px; color: #cfd3d9; font-size: 13px; }
.cms-lb-close { position: fixed; right: 20px; bottom: 10px; background: none; border: 0; color: #fff;
	font-size: 34px; line-height: 1; cursor: pointer; }
.cms-lb-nav { position: fixed; top: 50%; transform: translateY(-50%); background: rgba(0,0,0,.35);
	border: 0; color: #fff; font-size: 26px; width: 48px; height: 64px; cursor: pointer; border-radius: 6px; }
.cms-lb-prev { left: 14px; }
.cms-lb-next { right: 14px; }
.cms-lb-nav:hover { background: rgba(0,0,0,.6); }
.cms-lb-cap { position: fixed; left: 50%; transform: translateX(-50%); bottom: 16px; color: #fff;
	font-size: 14px; max-width: 70vw; text-align: center; text-shadow: 0 1px 6px rgba(0,0,0,.7); }

/* ── Heading-to-body gap: per-block "Space under heading" setting (--cms-hg) ── */
.cms-block .cms-heading, .cms-block h2.cms-heading { margin-bottom: var(--cms-hg, 24px); }

/* ── Icon features: optional narrower feature columns (2-3 item bands) ── */
.cms-if--w-md .cms-if__cell { max-width: 420px; }
.cms-if--w-sm .cms-if__cell { max-width: 320px; }

/* ── Heading color: per-block override (--cms-hc), hero overlay included ──
   BlockRegistry::SPACING_FIELDS appends heading_color to EVERY block's schema and
   applySpacing() faithfully emits --cms-hc, so the picker appears on all of them. It
   therefore has to MATCH on all of them, or the operator sets a colour, sees no change
   and concludes they picked the wrong one — a control that is present and does nothing.
   Two heading classes were missing: .cms-shead__title (PageListing, ShopProducts,
   ShopCategories, Testimonials) and .cms-band__title (CtaBand).
   The `.cms-heading h2` descendant clause already covers the blocks that wrap a bare
   <h2 class="mb-2">, IconFeatures' .text-white variant included — this rule's
   specificity beats Bootstrap's utility even though both are !important. */
.cms-pad[style*="--cms-hc"] .cms-heading, .cms-pad[style*="--cms-hc"] .cms-heading h2,
.cms-pad[style*="--cms-hc"] h2.cms-heading, .cms-pad[style*="--cms-hc"] .cms-hero__heading,
.cms-pad[style*="--cms-hc"] .cms-shead__title,
.cms-pad[style*="--cms-hc"] .cms-band__title { color: var(--cms-hc) !important; }

/* ── Enquiry form styles: underline + material variants; intl-tel full width ── */
.cms-form .iti { width: 100%; }
.cms-form--line .form-control { border: 0; border-bottom: 1px solid var(--bs-border-color);
	border-radius: 0; background: transparent; padding-left: 0; }
.cms-form--line .form-control:focus { box-shadow: none; border-bottom-color: var(--bs-primary); }
.cms-form--line .form-label { font-size: 13px; color: var(--bs-secondary-color); }
.cms-form--material .form-floating > .form-control { border-radius: var(--bs-border-radius); }

/* ── Image Marquee ────────────────────────────────────────────────────────────
   A strip that slides forever. The track holds the images twice and travels
   exactly one copy's width, so the restart lands on an identical frame and the
   loop has no seam. Everything tunable arrives as a custom property on the
   element, set inline by the block from its settings. */
.cms-marq {
	--marq-duration: 30s;
	--marq-height: 60px;
	--marq-gap: 48px;

	display: flex;
	overflow: hidden;
	width: 100%;
	gap: var(--marq-gap);
	/* The two tracks must not shrink to fit, or the 50% travel stops matching. */
	align-items: center;
}

.cms-marq__track {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	gap: var(--marq-gap);
	margin: 0;
	padding: 0;
	list-style: none;
	/* Deliberately NOT stretched to the strip width. Stretching (min-width:100% with
	   space-around) makes the spacing between items differ from the spacing at the join
	   between the two copies, and that uneven beat is visible every loop. Uniform gap
	   everywhere is worth more; the block repeats the set instead when there are few
	   images, so the strip still fills. */
	animation: cms-marq-scroll var(--marq-duration) linear infinite;
	will-change: transform;
}

.cms-marq__item { flex: 0 0 auto; display: flex; align-items: center; }

.cms-marq__img {
	height: var(--marq-height);
	width: auto;
	max-width: none;                       /* Bootstrap's img{max-width:100%} would squash it */
	object-fit: contain;
	display: block;
}

/* One copy's width plus the gap that follows it — the second track is exactly
   one gap away, so travelling 100%+gap puts it where the first one started. */
@keyframes cms-marq-scroll {
	from { transform: translateX(0); }
	to   { transform: translateX(calc(-100% - var(--marq-gap))); }
}

.cms-marq--reverse .cms-marq__track { animation-direction: reverse; }
.cms-marq--pause:hover .cms-marq__track { animation-play-state: paused; }

.cms-marq--grey .cms-marq__img {
	filter: grayscale(1);
	opacity: .65;
	transition: filter .25s ease, opacity .25s ease;
}
.cms-marq--grey .cms-marq__item:hover .cms-marq__img { filter: grayscale(0); opacity: 1; }

/* Soft edges so images enter and leave rather than being cut off mid-logo. */
.cms-marq--fade {
	-webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
	mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

/* Constant motion nobody can stop is exactly what this setting is for. Hold the
   strip still and let it scroll horizontally instead. */
@media (prefers-reduced-motion: reduce) {
	.cms-marq { overflow-x: auto; }
	.cms-marq__track { animation: none; }
	.cms-marq__track[aria-hidden="true"] { display: none; }
}

/* ---- showcase section head (kicker / title / intro), shared by the 2026-08 blocks ---- */
.cms-shead { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1.75rem; }
.cms-shead__kicker { font-size: .8rem; letter-spacing: .14em; text-transform: uppercase; color: var(--brand, #b46bd8); font-weight: 600; margin-bottom: .35rem; }
.cms-shead__title { font-size: clamp(1.5rem, 3vw, 2.1rem); font-weight: 700; margin: 0; }
.cms-shead__intro { color: var(--bs-secondary-color); max-width: 46rem; margin: .5rem 0 0; }
.cms-shead__more { white-space: nowrap; font-weight: 600; text-decoration: none; }

/* ---- product / category / post cards ---- */
/* Caption over the image. A real base treatment, not just a hook for themed
   instances: shipping a setting whose only effect is on somebody else's stylesheet is
   the "control that does nothing" trap again. --cms-cat-tint carries the operator's
   choice as a 0-1 alpha, so an instance theme can read the same variable rather than
   hardcode a second gradient. */
.cms-cat--overlay .cms-cat__card { position: relative; overflow: hidden; }
.cms-cat--overlay .cms-cat__body {
	position: absolute; inset: auto 0 0 0; margin: 0;
	background: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,var(--cms-cat-tint,.4)));
	padding-top: 2.5rem !important;
}
.cms-cat--overlay .cms-cat__name,
.cms-cat--overlay .cms-cat__tag { color: #fff !important; }

.cms-prod__card, .cms-cat__card, .cms-post__card { transition: transform .18s ease, box-shadow .18s ease; }
.cms-prod__card:hover, .cms-cat__card:hover, .cms-post__card:hover { transform: translateY(-3px); box-shadow: 0 .75rem 1.5rem rgba(0,0,0,.09); }
.cms-post__more { color: var(--brand, #b46bd8); }

/* ---- testimonials ---- */
.cms-quote { border: 1px solid var(--bs-border-color); }
.cms-quote__mark { font-size: 2.6rem; line-height: 1; color: var(--brand, #b46bd8); font-family: Georgia, serif; }
.cms-quote__stars { color: #f6b73c; margin-bottom: .5rem; letter-spacing: .1em; }
.cms-quote__text { font-size: .95rem; color: var(--bs-body-color); }
/* Attribution row: round avatar beside the name. Structure only — a client restyles
   .cms-quote__avatar in brand.css. object-fit keeps a non-square upload from squashing,
   and flex-shrink stops a long name collapsing the circle into an oval. */
.cms-quote__avatar { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; margin-bottom: .75rem; display: block; }
/* Long quotes, collapsed (block setting). --cms-clamp carries the line count from the block;
   .is-open (cms.js) releases it in place. Slightly smaller type is what keeps a 260-character
   quote from dwarfing the 40-character ones beside it even once opened. The toggle is a real
   <button> styled as a link, and cms.js hides it when nothing was actually cut off. */
.cms-quote__text--long { font-size: .88rem; line-height: 1.6; }
.cms-clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--cms-clamp, 4); line-clamp: var(--cms-clamp, 4); overflow: hidden; }
.cms-clamp.is-open { display: block; -webkit-line-clamp: unset; line-clamp: none; overflow: visible; }
.cms-quote__more { display: inline-block; background: none; border: 0; padding: 0; margin: -.5rem 0 .85rem; font: inherit; font-size: .85rem; font-weight: 600; color: var(--brand, #b46bd8); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.cms-quote__more[hidden] { display: none; }
/* "View all" under the deck, and the pop-up that lists every quote in full. */
.cms-quote__all { text-align: center; margin-top: 1.5rem; }
.cms-quote-modal .cms-quote__text { font-size: .95rem; }

/* ---- CTA band ---- */
.cms-band { color: #fff; }
/* Band background, art-directed. A background-image cannot use <picture>, so the block
   emits the layer as a custom property and the media query swaps it. --cms-band-bg-mobile
   always resolves — the block falls it back to the desktop layer when no mobile crop was
   uploaded — so there is no per-instance <style> and no empty-variable case. A band with
   no photo sets background-color instead and neither variable exists, which is why these
   are guarded on the variable rather than applied to .cms-band unconditionally. */
.cms-band[style*="--cms-band-bg"] { background-image: var(--cms-band-bg); background-size: cover; background-position: center; }
@media (max-width: 767px) {
	.cms-band[style*="--cms-band-bg"] { background-image: var(--cms-band-bg-mobile, var(--cms-band-bg)); }
}
.cms-band--band { padding: 3.5rem 0; }
.cms-band--tall { padding: 7rem 0; }
.cms-band__kicker { color: rgba(255,255,255,.85); }
.cms-band__title { font-size: clamp(1.6rem, 3.4vw, 2.4rem); font-weight: 700; }
.cms-band__text { max-width: 44rem; margin: .5rem auto 0; color: rgba(255,255,255,.9); }
.cms-band .text-start .cms-band__text { margin-left: 0; }

@media (max-width: 575.98px) {
	.cms-shead { flex-direction: column; align-items: flex-start; }
}

/* -------------------------------------------------- promo_split
   The two-column promo band: photo one side, message the other. Neutral by
   design — even columns, covered image, stacked on phones. Themes reshape it
   (arch masks, serif accents) via these hooks or a variant_class slug; the
   heading's *accent* renders as <em> for the theme to style. */
.cms-psplit { overflow: hidden; }
.cms-psplit__grid { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; gap: 0; }
.cms-psplit__media { min-height: 320px; }
.cms-psplit__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cms-psplit__body { position: relative; display: flex; align-items: center; }
.cms-psplit__inner { width: 100%; padding: clamp(2rem, 5vw, 4.5rem); }
.cms-psplit__title { font-size: clamp(1.6rem, 3.4vw, 2.4rem); font-weight: 700; margin: 0 0 .75rem; }
.cms-psplit__text { margin: 0 0 1.5rem; }
.cms-psplit__actions { display: flex; flex-wrap: wrap; gap: .75rem; }
.cms-psplit__decor { position: absolute; right: 1.25rem; bottom: 1.25rem; max-width: 96px; max-height: 96px; opacity: .5; pointer-events: none; }
.cms-pad[style*="--cms-hc"] .cms-psplit__title { color: var(--cms-hc) !important; }
@media (max-width: 767.98px) {
	.cms-psplit__grid { grid-template-columns: 1fr; }
	.cms-psplit__grid--right { display: flex; flex-direction: column; }
	.cms-psplit__grid--right .cms-psplit__media { order: -1; }
	.cms-psplit__media { min-height: 240px; }
}
