/**
 * Art Division Repeatables — Front-end Styles
 * BEM methodology, art-rep- prefix.
 *
 * Shared module block styles and the testimonials module.
 * Module-specific styles use the --{type} modifier on .art-rep-module.
 */

/* ── Custom properties ──────────────────────────────────────────────────────── */

:root {
	--art-rep-color-primary:    #1a1a1a;
	--art-rep-color-secondary:  #ffffff;
	--art-rep-color-accent:     #e63946;
	--art-rep-color-bg-subtle:  #f5f5f5;

	--art-rep-spacing-xs:  0.5rem;
	--art-rep-spacing-sm:  1rem;
	--art-rep-spacing-md:  2rem;
	--art-rep-spacing-lg:  4rem;

	--art-rep-radius:      var(--art-radius, 0);
	--art-rep-transition:  0.25s ease;
}

/* ── Shared module block ────────────────────────────────────────────────────── */

.art-rep-module {
	padding: var(--art-rep-spacing-lg) var(--art-rep-spacing-md);
}

/* Compound selector so this reliably wins over the single-class overrides
   below (e.g. --cta--image-left) regardless of source order. Suppresses
   top padding when the previous Page Modules sibling shares this block's
   Background Colour - see modules/repeatables/template.php in Page Modules. */
.art-rep-module.art-rep-module--no-pad-top {
	padding-top: 0;
}

/* ── Shared module header ───────────────────────────────────────────────────── */

.art-rep-module__header {
	text-align: center;
	/* Theme's own "Content Text Max Width" setting (Customizer > Spacing
	   Scale) - the same reading-width cap body copy uses sitewide, so an
	   intro paragraph here wraps the same as everywhere else instead of
	   stretching edge-to-edge across the module. */
	max-width: var(--art-pm-content-max-width, 720px);
	margin: 0 auto var(--art-rep-spacing-md);
}

.art-rep-module__title {
	margin: 0 0 var(--art-rep-spacing-sm);
	font-size: var(--art-text-2xl, 2rem);
}

/* No font-size/colour rule here - Page Modules' own .art-pm-module__intro
   (the equivalent header intro paragraph everywhere else on the site)
   doesn't set either, it just inherits the theme's normal body copy
   styling. This used to override both (a larger --art-text-lg size and a
   hardcoded #555 grey), which is why Repeatables' intros read differently
   from every other module's. */

.art-rep-module__intro > *:first-child { margin-top: 0; }
.art-rep-module__intro > *:last-child  { margin-bottom: 0; }

/* ── Shared module inner grid ───────────────────────────────────────────────── */

.art-rep-module__inner {
	display: grid;
	gap: var(--art-rep-spacing-md);
	grid-template-columns: repeat( auto-fill, minmax( 280px, 1fr ) );
}

/* ── Testimonials module ─────────────────────────────────────────────────────── */
/* Two layouts, chosen via the layout field:
   cards  (default) — carousel, profile photo + name + star rating, clipped
                       text with a read-more trigger. No tagline or job title.
   single            — one full-width quote at a time, no photo/rating,
                        pagination dots instead of arrows, optional
                        background image + colour overlay. See the
                        "Single layout" rules further below. */

.art-rep-module--testimonials .art-rep-module__inner--slider {
	--swiper-navigation-color: var(--art-color-text, #111111);
	--swiper-navigation-size: 28px;
	display: block;
	margin-inline: auto;
	max-width: var(--art-max-width, 75rem);
	padding-left: 55px;
	padding-right: 55px;
}

.art-rep-module--testimonials .swiper-slide {
	display: flex;
	height: auto;
}

.art-rep-testimonial {
	display: flex;
	flex-direction: column;
	gap: var(--art-rep-spacing-sm);
	background: var(--art-rep-color-secondary);
	border-radius: var(--art-rep-radius);
	padding: var(--art-rep-spacing-md);
	width: 100%;
}

.art-rep-testimonial__head {
	align-items: center;
	display: flex;
	gap: var(--art-rep-spacing-sm);
}

.art-rep-testimonial__photo {
	border-radius: 50%;
	flex-shrink: 0;
	height: 48px;
	object-fit: cover;
	width: 48px;
}

.art-rep-testimonial__name {
	font-size: var(--art-text-lg);
	margin: 0;
}

.art-rep-testimonial__content {
	flex: 1;
	font-size: var(--art-text-base, 1rem);
}

.art-rep-testimonial__content > *:first-child { margin-top: 0; }
.art-rep-testimonial__content > *:last-child  { margin-bottom: 0; }

/* ── Star rating ────────────────────────────────────────────────────────────── */

.art-rep-testimonial__rating {
	align-items: center;
	display: inline-flex;
	gap: 2px;
	line-height: 1;
}

/* Logo before the stars: Google's on Google reviews, the Art Division icon
   (or the theme's own uploaded logo) on testimonials added directly. */
.art-rep-testimonial__source-logo {
	display: block;
	flex-shrink: 0;
	height: 1.5rem;
	margin-right: 0.375rem;
	width: 1.5rem;
}

/* A client's own logo may not be square - keep the height, let the width
   follow its proportions (capped so a very wide logo can't crowd the stars). */
.art-rep-testimonial__source-logo--custom {
	max-width: 6rem;
	object-fit: contain;
	width: auto;
}

/* Only when rating follows the photo+name block (default card style and the
   "read more" modal, both via $art_rep_testimonial_render_head()) - not the
   Reviews Panel card, where rating is the first element in the card and
   already has the card's own top padding above it. */
.art-rep-testimonial__head + .art-rep-testimonial__rating {
	margin-top: var(--art-rep-spacing-xs);
}

.art-rep-testimonial__star {
	font-size: 2rem;
	color: var(--art-color-muted, #b5b2be);
	line-height: 1;
}

.art-rep-testimonial__star--filled {
	color: var(--art-pm-star-color, #f2c40f);
}

.art-rep-testimonial__more {
	background: none;
	border: 0;
	color: var(--art-color-accent, #0073aa);
	cursor: pointer;
	display: inline;
	font: inherit;
	padding: 0;
	text-decoration: underline;
}

.art-rep-testimonial__more:hover {
	text-decoration: none;
}

.art-rep-testimonial__more:focus-visible {
	outline: 2px solid var(--art-color-accent, #0073aa);
	outline-offset: 2px;
}

.art-rep-module__cta {
	margin: var(--art-rep-spacing-md) auto 0;
	text-align: center;
}

/* Card contrast only — no background-color of its own here. The section's
   actual background comes from the wrapping Page Modules ".art-pm-module"
   layout's own Background Colour; these bg-{colour} modifier classes just
   mirror that resolved colour (passed in as $args['bg_colour'], see
   modules/testimonials/template.php) so cards stay visible against whichever
   of the four choices ends up showing through this section. */

.art-rep-module--testimonials--bg-white .art-rep-testimonial {
	background: var(--art-color-alternate, #f5f5f5);
}

.art-rep-module--testimonials--bg-alternate .art-rep-testimonial {
	background: var(--art-color-bg, #ffffff);
}

.art-rep-module--testimonials--bg-primary .art-rep-testimonial,
.art-rep-module--testimonials--bg-secondary .art-rep-testimonial {
	background: var(--art-color-bg, #ffffff);
}

/* ── Testimonials module — AI-Generated Summary ────────────────────────────────── */
/* Replaces .art-rep-module__intro when the use_ai_summary field is on (any
   card style/layout - not panel-specific). Icon/title use the theme's own
   accent colour (gradient between accent and accent-hover) rather than a
   fixed "AI purple", so it still reads as this site's own colour scheme,
   not a hardcoded brand borrowed from a reference design. */

.art-rep-testimonial-ai-summary {
	margin-top: var(--art-rep-spacing-sm);
	text-align: left;
}

.art-rep-testimonial-ai-summary__head {
	align-items: center;
	display: flex;
	gap: var(--art-rep-spacing-sm);
	margin-bottom: var(--art-rep-spacing-xs);
}

.art-rep-testimonial-ai-summary__icon {
	align-items: center;
	background: linear-gradient(135deg, var(--art-color-accent, #7c3aed), var(--art-color-accent-hover, #6d28d9));
	border-radius: 50%;
	color: var(--art-color-on-accent, #ffffff);
	display: inline-flex;
	flex-shrink: 0;
	font-size: 1.125rem;
	height: 36px;
	justify-content: center;
	line-height: 1;
	width: 36px;
}

.art-rep-testimonial-ai-summary__heading {
	display: flex;
	flex-direction: column;
}

.art-rep-testimonial-ai-summary__title {
	color: var(--art-color-accent, #6d28d9);
	font-size: 1rem;
	font-weight: 700;
}

.art-rep-testimonial-ai-summary__subtitle {
	color: var(--art-color-muted, #767676);
	font-size: 0.8125rem;
}

.art-rep-testimonial-ai-summary .art-rep-testimonial__rating {
	margin-bottom: var(--art-rep-spacing-xs);
}

.art-rep-testimonial-ai-summary .art-rep-testimonial__star {
	font-size: 1.125rem;
}

.art-rep-testimonial-ai-summary__text {
	margin: 0;
}

.art-rep-testimonial-ai-summary__regenerate {
	background: none;
	border: 0;
	color: var(--art-color-accent, #0073aa);
	cursor: pointer;
	display: inline-block;
	font: inherit;
	font-size: 0.8125rem;
	margin-top: var(--art-rep-spacing-xs);
	padding: 0;
	text-decoration: underline;
}

.art-rep-testimonial-ai-summary__regenerate:hover {
	text-decoration: none;
}

.art-rep-testimonial-ai-summary__regenerate:focus-visible {
	outline: 2px solid var(--art-color-accent, #0073aa);
	outline-offset: 2px;
}

.art-rep-testimonial-ai-summary__regenerate:disabled {
	cursor: default;
	opacity: 0.6;
}

.art-rep-testimonial-ai-summary__regenerate--standalone {
	display: block;
	margin-top: var(--art-rep-spacing-sm);
}

/* ── Testimonials module — Cards layout, Reviews Panel card style ─────────────── */
/* Overrides on top of the default Cards layout above: an inset panel (NOT
   the whole full-bleed section, which has no width cap of its own and would
   otherwise stretch the panel edge-to-edge on wide screens) sized to match
   the site's normal content column, cards with their own shadow (ignoring
   the bg-{colour} contrast rules above), a quote-badge icon instead of a
   photo, the name pinned to the card bottom via the card's own flex column,
   and bare arrow nav buttons repositioned below the carousel (via the
   .art-rep-testimonial-nav wrapper - display: contents for the default style
   above, so this is the only place that wrapper does anything). Colours all
   come from the Theme's --art-color-* custom properties (see art-division
   /style.css) rather than fixed hex, so this style follows each site's own
   colour scheme instead of the reference mockup's cream/near-black palette. */

.art-rep-testimonial-panel {
	background: var(--art-color-alternate, var(--art-rep-color-bg-subtle));
	border-radius: calc(var(--art-rep-radius, 0) * 2);
	margin-inline: auto;
	max-width: var(--art-max-width, 75rem);
	padding: var(--art-rep-spacing-md);
}

.art-rep-testimonial-panel .art-rep-module__header {
	margin-top: 20px;
}

/* No side-overlaid arrows to reserve room for in this card style, and the
   panel above already supplies its own padding - the default layout's 55px
   side padding (above) would just add an unwanted extra indent on top of it. */
.art-rep-testimonial-panel .art-rep-module__inner--slider {
	padding-left: 0;
	padding-right: 0;
}

/* --art-color-bg (the page's own base background, typically white) rather
   than --art-color-surface - on sites where "surface" is mapped to the same
   value as --art-color-alternate (the panel's own background above), a
   --color-surface card would be visually indistinguishable from the panel
   it sits on. --color-bg is guaranteed to contrast with --color-alternate
   already, by the same convention the bg-{colour} rules above rely on. The
   shadow alone isn't a reliable enough separator if a site's bg/alternate
   values ever end up close in tone, so a subtle border backs it up. */
.art-rep-module--testimonials--card-style-panel .art-rep-testimonial {
	background: var(--art-color-bg, var(--art-rep-color-secondary));
	border: 1px solid var(--art-color-border, rgba(0, 0, 0, 0.06));
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.art-rep-module--testimonials--card-style-panel .art-rep-testimonial__star {
	font-size: 1.75rem;
}

/* Wrapper around the Reviews Panel card's text. It used to pair a quote-badge
   icon with the text; the icon was removed, so it now just holds the content. */
.art-rep-testimonial__quote-row {
	align-items: flex-start;
	display: flex;
	gap: var(--art-rep-spacing-sm);
}

.art-rep-testimonial__quote-row .art-rep-testimonial__content {
	flex: 1;
	min-width: 0;
}

.art-rep-module--testimonials--card-style-panel .art-rep-testimonial__name {
	border-top: 1px solid var(--art-color-border, rgba(0, 0, 0, 0.08));
	font-size: var(--art-text-base, 1rem);
	font-weight: 600;
	margin: auto 0 0;
	padding-top: var(--art-rep-spacing-sm);
}

.art-rep-testimonial-nav {
	display: contents;
}

.art-rep-module--testimonials--card-style-panel .art-rep-testimonial-nav {
	display: flex;
	gap: var(--art-rep-spacing-sm);
	justify-content: flex-start;
	margin-top: var(--art-rep-spacing-md);
}

/* Swiper's own core CSS absolutely-positions .swiper-button-prev/-next to
   overlay the slide edges by default (with left/right/top/margin-top all
   set) - position: static here is higher specificity so it wins, but the
   leftover left/right/top/margin-top values would still apply once this
   becomes a normal in-flow flex item unless explicitly reset too. Bare
   arrow icons only - no circle/background/border - just repositioned below
   the carousel instead of overlaid on the slide edges. */
.art-rep-module--testimonials--card-style-panel .swiper-button-prev,
.art-rep-module--testimonials--card-style-panel .swiper-button-next {
	--swiper-navigation-color: var(--art-color-primary, var(--art-rep-color-primary));
	--swiper-navigation-size: 20px;
	background: none;
	border: 0;
	bottom: auto;
	flex-shrink: 0;
	/* An explicit size, not auto: Swiper 12 draws the arrow as an <svg>
	   sized to 100% of this button, so an auto-sized button left the two
	   sizing each other. Chrome fell back to the svg's own 11x20; Safari
	   stretched it to the full available width - the giant arrow. The svg's
	   object-fit: contain keeps its 11x20 shape inside this square. */
	height: var(--swiper-navigation-size);
	left: auto;
	margin: 0;
	position: static;
	right: auto;
	top: auto;
	width: var(--swiper-navigation-size);
}

.art-rep-module--testimonials--card-style-panel .swiper-button-disabled {
	cursor: default;
	opacity: 0.35;
}

/* ── Testimonials module — Google Reviews card style ─────────────────────────── */
/* A summary bar (average, stars, count, "Review us on Google") above cards
   with an initial/photo avatar carrying a small source badge, name, date,
   stars and the clipped text. Cards and bar share --art-color-alternate with
   a hairline border, so they still read as cards on sites where alternate is
   close to the page colour. Arrows are round buttons half over the card
   edges, outside the .swiper root (see template.php for why); phones swipe
   and use the dots instead. */

.art-rep-greviews-bar {
	align-items: center;
	background: var(--art-color-alternate, var(--art-rep-color-bg-subtle));
	border: 1px solid var(--art-color-border, rgba(0, 0, 0, 0.08));
	border-radius: var(--art-rep-radius);
	display: flex;
	flex-wrap: wrap;
	gap: var(--art-rep-spacing-sm);
	justify-content: space-between;
	margin: 0 auto var(--art-rep-spacing-sm);
	max-width: var(--art-max-width, 75rem);
	padding: var(--art-rep-spacing-sm) var(--art-rep-spacing-md);
}

.art-rep-greviews-bar__brand,
.art-rep-greviews-bar__rating {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin: 0;
}

.art-rep-greviews-bar__brand {
	font-size: var(--art-text-lg, 1.125rem);
	font-weight: 600;
}

/* The Google wordmark is coloured artwork - give it a white chip so it stays
   legible on dark site colours as well as light. */
.art-rep-greviews-bar__logo {
	background: #fff;
	border-radius: 4px;
	display: inline-flex;
	padding: 4px 6px;
}

.art-rep-greviews-bar__logo svg {
	display: block;
	height: 20px;
	width: auto;
}

.art-rep-greviews-bar__average {
	font-size: var(--art-text-xl, 1.5rem);
	font-weight: 700;
	line-height: 1;
}

.art-rep-greviews-bar__count {
	font-size: var(--art-text-sm, 0.875rem);
	opacity: 0.75;
}

.art-rep-greviews-bar__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

/* Five-star meter: a dim row of stars with a gold copy over it, clipped to
   the rating's width, so 4.7 shows a partly filled fifth star. */
.art-rep-greview-stars {
	display: inline-block;
	font-size: 1.25rem;
	letter-spacing: 0.1em;
	line-height: 1;
	position: relative;
	white-space: nowrap;
}

.art-rep-greview-stars__base {
	opacity: 0.25;
}

.art-rep-greview-stars__fill {
	color: #fbbc04;
	inset: 0 auto 0 0;
	overflow: hidden;
	position: absolute;
}

.art-rep-greviews-frame {
	margin-inline: auto;
	max-width: var(--art-max-width, 75rem);
	position: relative;
}

.art-rep-greview {
	background: var(--art-color-alternate, var(--art-rep-color-bg-subtle));
	border: 1px solid var(--art-color-border, rgba(0, 0, 0, 0.08));
	gap: 0.75rem;
	padding: 1.75rem;
}

/* A <dialog> doesn't inherit the page's text colour (browsers give it
   their own default, usually black), so on a dark site a review read in
   the dialog came out dark on the dark dialog. Take the colour of the card
   it was opened from instead. */
dialog.art-modal:has( .art-rep-greview--modal ) {
	color: inherit;
}

/* Inside the Read more dialog the dialog is already the box - no card
   fill, outline or padding of its own (3 classes, so a site's own card
   fill override doesn't reach in here either). */
.art-modal .art-rep-greview.art-rep-greview--modal {
	background: none;
	border: 0;
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	padding: 0;
}

.art-rep-greview--modal .art-rep-testimonial__content p + p {
	margin-top: 0.75em;
}

.art-rep-greview__head {
	align-items: center;
	display: flex;
	gap: 0.75rem;
}

.art-rep-greview__avatar {
	background: hsl(var(--art-rep-avatar-hue, 210) 35% 42%);
	border-radius: 50%;
	color: #fff;
	display: grid;
	flex-shrink: 0;
	height: 44px;
	place-items: center;
	position: relative;
	width: 44px;
}

.art-rep-greview__photo {
	border-radius: 50%;
	height: 100%;
	object-fit: cover;
	width: 100%;
}

.art-rep-greview__initial {
	font-size: 1.25rem;
	font-weight: 600;
	line-height: 1;
}

.art-rep-greview__badge {
	background: #fff;
	border-radius: 50%;
	bottom: -4px;
	display: grid;
	height: 22px;
	padding: 2px;
	place-items: center;
	position: absolute;
	right: -4px;
	width: 22px;
}

.art-rep-greview__badge svg,
.art-rep-greview__badge img {
	display: block;
	height: 100%;
	width: 100%;
}

/* The default Art Division logo is a speech bubble (round body + tail) in a
   40x40 box, so fitted whole it sat small inside the white badge. Instead the
   badge takes the logo's navy and the logo is scaled so its round body (centre
   20,17.85, radius ~16.2) slightly overfills the badge, its white outer ring and tail clipped by the
   circle - a solid round badge like the Google one. A site's own uploaded logo
   (an <img>, --custom) keeps the plain fit above. */
.art-rep-greview__badge--direct {
	background: #102b3c;
	border: 1px solid #fff;
	box-sizing: border-box;
	overflow: hidden;
	padding: 0;
}

.art-rep-greview__badge--direct svg.art-rep-testimonial__source-logo {
	height: 127%;
	left: -13.5%;
	max-width: none;
	position: absolute;
	top: -6.75%;
	width: 127%;
}

.art-rep-greview__who {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.art-rep-greview .art-rep-testimonial__name {
	font-family: inherit;
	font-size: var(--art-text-base, 1rem);
	font-weight: 600;
	line-height: 1.3;
	margin: 0;
}

.art-rep-greview__date {
	font-size: var(--art-text-sm, 0.875rem);
	opacity: 0.7;
}

.art-rep-greview .art-rep-testimonial__content p {
	margin: 0;
}

/* "Read more" on its own line, sentence case, no underline - as Google's own widget. */
.art-rep-greview .art-rep-testimonial__more {
	display: block;
	margin-top: 0.25rem;
	text-decoration: none;
}

.art-rep-greview .art-rep-testimonial__more::first-letter {
	text-transform: uppercase;
}

.art-rep-greview .art-rep-testimonial__more:hover,
.art-rep-greview .art-rep-testimonial__more:focus-visible {
	text-decoration: underline;
}

/* The dots row sits inside the .swiper root, below the slides, so the
   arrows centre on the card row only: half of the dots row's height (its
   20px top margin + ~8px bullets) is taken back off top:50%. */
.art-rep-greviews-frame > .swiper-button-prev,
.art-rep-greviews-frame > .swiper-button-next {
	--swiper-navigation-color: var(--art-color-text, #111);
	--swiper-navigation-size: 14px;
	background: var(--art-color-bg, #fff);
	border: 1px solid var(--art-color-border, rgba(0, 0, 0, 0.08));
	border-radius: 50%;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
	height: 40px;
	margin-top: 0;
	top: calc(50% - 14px);
	transform: translateY(-50%);
	width: 40px;
}

.art-rep-greviews-frame > .swiper-button-prev {
	left: -14px;
}

.art-rep-greviews-frame > .swiper-button-next {
	right: -14px;
}

.art-rep-greviews-frame > .swiper-button-prev svg,
.art-rep-greviews-frame > .swiper-button-next svg {
	height: 14px;
	width: auto;
}

.art-rep-greviews-frame > .swiper-button-disabled {
	opacity: 0.35;
}

@media (max-width: 767px) {
	.art-rep-greviews-bar {
		padding: var(--art-rep-spacing-sm);
	}

	.art-rep-greviews-bar__actions {
		flex-direction: column;
		width: 100%;
	}

	.art-rep-greviews-bar__button {
		text-align: center;
		width: 100%;
	}

	.art-rep-greview {
		padding: 1.25rem;
	}

	.art-rep-greviews-frame > .swiper-button-prev,
	.art-rep-greviews-frame > .swiper-button-next {
		display: none;
	}
}

/* ── Testimonials module — Single (Quote Slider) layout ───────────────────────── */
/* Section itself carries the optional background image (inline style, set in
   template.php). No colour fallback of its own to paint when there's no
   image - the section is left transparent, revealing the wrapping Page
   Modules layout's own Background Colour underneath. */

.art-rep-module--testimonials--layout-single {
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
	position: relative;
}

.art-rep-testimonial-single__overlay {
	inset: 0;
	pointer-events: none;
	position: absolute;
}

.art-rep-module--testimonials--layout-single .art-rep-module__header,
.art-rep-module--testimonials--layout-single .art-rep-module__inner--single-slider,
.art-rep-module--testimonials--layout-single .art-rep-module__cta {
	position: relative;
	z-index: 1;
}

.art-rep-module__inner--single-slider {
	margin-inline: auto;
	max-width: 720px;
	padding-left: 15px;
	padding-right: 15px;
	text-align: center;
}

.art-rep-testimonial-single__quote {
	color: var(--art-rep-testimonial-single-color, var(--art-rep-color-primary));
	font-size: clamp( 1.25rem, 2.5vw, 1.75rem );
	font-style: italic;
	margin: 0;
	quotes: '\201C' '\201D';
}

.art-rep-testimonial-single__quote::before {
	content: open-quote;
}

.art-rep-testimonial-single__quote::after {
	content: close-quote;
}

.art-rep-testimonial-single__quote p {
	margin: 0;
}

.art-rep-testimonial-single__more {
	background: none;
	border: 0;
	color: inherit;
	cursor: pointer;
	display: inline;
	font: inherit;
	padding: 0;
	text-decoration: underline;
}

.art-rep-testimonial-single__more:hover {
	text-decoration: none;
}

.art-rep-testimonial-single__more:focus-visible {
	outline: 2px solid var(--art-rep-color-accent);
	outline-offset: 2px;
}

.art-rep-testimonial-single__name {
	color: var(--art-rep-testimonial-single-color, var(--art-rep-color-primary));
	display: block;
	font-size: 0.8125rem;
	font-style: normal;
	letter-spacing: 0.1em;
	margin-top: var(--art-rep-spacing-md);
	opacity: 0.55;
	text-transform: uppercase;
}

.art-rep-module--testimonials--layout-single .swiper-pagination {
	margin-top: var(--art-rep-spacing-md);
	position: static;
}

.art-rep-module--testimonials--layout-single .swiper-pagination-bullet {
	background: var(--art-rep-color-primary);
	opacity: 0.3;
}

.art-rep-module--testimonials--layout-single .swiper-pagination-bullet-active {
	opacity: 1;
}

/* ── CTA module — default style ─────────────────────────────────────────────── */

.art-rep-module--cta {
	align-items: center;
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding-left: 0;
	padding-right: 0;
	position: relative;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
}

.art-rep-module--cta--parallax {
	background-attachment: fixed;
}

/* Lazy CTA background (modules/cta/template.php): the image URL sits in
   --art-rep-lazy-bg and only becomes a real background-image once
   art-division-repeatables-lazy-bg.js adds .is-bg-loaded near the viewport. */
.art-rep-lazy-bg.is-bg-loaded {
	background-image: var( --art-rep-lazy-bg );
}

/* Mobile browsers don't composite a fixed background reliably - iOS Safari
   and most mobile Chromium recalculate its position against the viewport
   on every scroll event, and the dynamic toolbar (URL bar collapsing/
   expanding as you scroll) keeps changing that viewport height, so the
   background visibly snaps/jumps instead of staying put. True
   fixed-attachment parallax is a desktop-only technique in practice -
   fall back to normal scroll below the breakpoint where the row layout
   itself already switches to stacked (.art-rep-cta__row above). */
@media ( max-width: 768px ) {
	.art-rep-module--cta--parallax {
		background-attachment: scroll;
	}
}

/* Background Colour palette — matches the bg_colour convention used by other
   Page Modules (e.g. Content Cards' art-pm-module--bg-{colour}), reusing the
   same theme customizer variables so a CTA section stays visually consistent
   with the rest of the page. Always applied to the section itself (never the
   image column) so it's visible regardless of whether Image is set - same as
   Content Cards / Image & Text. Primary/Secondary also override the
   title/text colour custom properties for contrast; an explicit Title Colour /
   Text Colour field value is set inline on the same element and always wins. */
.art-rep-module--cta--bg-white {
	background-color: var(--art-color-bg, #ffffff);
}

.art-rep-module--cta--bg-alternate {
	background-color: var(--art-color-alternate, #f5f5f5);
}

.art-rep-module--cta--bg-primary {
	background-color: var(--art-color-primary, #1a1a2e);
	--art-rep-cta-title-color: var(--art-pm-on-primary, #ffffff);
	--art-rep-cta-text-color: var(--art-pm-on-primary, #ffffff);
}

/* Inside a Page Modules Accent section, --art-color-accent is remapped to the
   readable on-accent colour on this element, so take the section's stashed
   real accent first (--art-pm-accent-bg). */
.art-rep-module--cta--bg-secondary {
	background-color: var(--art-pm-accent-bg, var(--art-color-accent, #1a1a2e));
	--art-rep-cta-title-color: var(--art-pm-on-accent, #ffffff);
	--art-rep-cta-text-color: var(--art-pm-on-accent, #ffffff);
}

/* Overlay — sits above the background image, below the content. */
.art-rep-cta__overlay {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/* Content wrapper — keeps text above the overlay via z-index. Width/gutter
   match the .art-pm-module__inner pattern used by Page Modules, rather than
   the theme's .container (different padding), so the inner content column
   stays visually consistent across all module types. */
.art-rep-cta__inner {
	position: relative;
	z-index: 1;
	width: 100%;
	text-align: center;
	margin-inline: auto;
	max-width: var(--art-max-width, 75rem);
	padding-left: 15px;
	padding-right: 15px;
}

.art-rep-cta__title {
	margin: 0 0 var(--art-rep-spacing-sm);
	font-size: var(--art-text-2xl, 2rem);
	color: var(--art-rep-cta-title-color, var(--art-rep-color-primary));
}

.art-rep-cta__intro {
	font-size: var(--art-text-lg, 1.125rem);
	color: var(--art-rep-cta-text-color, #555);
}

.art-rep-cta__intro > *:first-child { margin-top: 0; }
.art-rep-cta__intro > *:last-child  { margin-bottom: 0; }

.art-rep-cta__action {
	margin-top: var(--art-rep-spacing-md);
}

/* No title/intro above it (both fields left blank) - it's the first thing
   in .art-rep-cta__inner / .art-rep-cta__col--content, so there's nothing
   for the margin-top to create a gap from. */
.art-rep-cta__action:first-child {
	margin-top: 0;
}

/* ── CTA module — inline style ─────────────────────────────────────────────── */
/* Title and button share one row instead of stacking; content (if set) still
   renders full-width below, same position as the Default style. Title grows
   to fill the row, the action stays its natural width so long titles don't
   push the button off balance. */
.art-rep-cta__row {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	gap: var(--art-rep-spacing-md);
	text-align: left;
}

.art-rep-cta__row .art-rep-cta__title {
	margin: 0;
	flex: 1 1 auto;
}

.art-rep-cta__row .art-rep-cta__action {
	margin-top: 0;
	flex: 0 0 auto;
}

@media ( max-width: 768px ) {
	.art-rep-cta__row {
		flex-direction: column;
		text-align: center;
	}
}

/* Second CTA button / embedded form sits beside the first. Both buttons are
   inline-block (or, for an embedded form, a block-level .gform_wrapper) so
   they wrap naturally like text - text-align on the parent (centred by
   default, left in the image_* and fullwidth_image_* content column) already
   positions them; this just adds the gap between them. */
.art-rep-cta__action > * + * {
	margin-left: var(--art-rep-spacing-sm);
}

/* Visual button styles are handled by art-btn--primary defined in the Art Division AI theme. */
.art-rep-cta__button {
	display: inline-block;
}

/* Embed-mode Gravity Form has no button/link element of its own to carry
   art-btn--{style}, so the CTA's Button Style pick is applied to the
   embedded form's own submit button instead, via GF's --gf-ctrl-btn-*
   custom properties (same mechanism Page Modules uses for its own embedded
   forms). 'primary' needs no rule here - Page Modules' site-wide GF colour
   defaults (a hard dependency of this plugin) already map to primary.
   GF's own "secondary" role variables are its Previous/page-nav button, not
   related to our style picker, so both our secondary and link picks remap
   the "primary" role - the only role a single-page embedded form's submit
   button actually uses. !important is required to beat GF's own per-form
   ID-scoped <style> block. */
.art-rep-cta__action--btn-secondary .gform-theme--framework,
.art-rep-cta__action--btn-secondary .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: var(--color-btn-secondary-bg, #666666) !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-secondary-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-secondary-border, #666666) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-secondary-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-secondary-text, #ffffff) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-secondary-text-hover, #ffffff) !important;
}

.art-rep-cta__action--btn-link .gform-theme--framework,
.art-rep-cta__action--btn-link .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: transparent !important;
	--gf-ctrl-btn-border-color-primary: transparent !important;
	--gf-ctrl-btn-border-color-hover-primary: transparent !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-primary-bg, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-primary-bg-hover, #16213e) !important;
	--gf-ctrl-btn-text-decoration: underline !important;
}

.art-rep-cta__action--btn-outline .gform-theme--framework,
.art-rep-cta__action--btn-outline .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-outline-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-outline-border, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-outline-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-outline-text, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-outline-text-hover, #ffffff) !important;
}

/* Content Cards module — same embed-mode Gravity Form submit-button remap
   as the CTA module above, just a different BEM root (art-rep-card__action
   instead of art-rep-cta__action) since each card's CTA is its own single
   optional slot rather than the CTA module's up-to-two-buttons system. */
.art-rep-card__action--btn-secondary .gform-theme--framework,
.art-rep-card__action--btn-secondary .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: var(--color-btn-secondary-bg, #666666) !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-secondary-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-secondary-border, #666666) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-secondary-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-secondary-text, #ffffff) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-secondary-text-hover, #ffffff) !important;
}

.art-rep-card__action--btn-link .gform-theme--framework,
.art-rep-card__action--btn-link .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: transparent !important;
	--gf-ctrl-btn-border-color-primary: transparent !important;
	--gf-ctrl-btn-border-color-hover-primary: transparent !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-primary-bg, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-primary-bg-hover, #16213e) !important;
	--gf-ctrl-btn-text-decoration: underline !important;
}

.art-rep-card__action--btn-outline .gform-theme--framework,
.art-rep-card__action--btn-outline .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-outline-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-outline-border, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-outline-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-outline-text, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-outline-text-hover, #ffffff) !important;
}

/* List module — same embed-mode Gravity Form submit-button remap as the CTA/
   Content Cards modules above, just a different BEM root (art-rep-list__item-cta
   instead of art-rep-cta__action / art-rep-card__action). List's Button Style
   is a single module-level field (not per-item), applied uniformly to every
   item's Link/Form CTA. */
.art-rep-list__item-cta--btn-secondary .gform-theme--framework,
.art-rep-list__item-cta--btn-secondary .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: var(--color-btn-secondary-bg, #666666) !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-secondary-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-secondary-border, #666666) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-secondary-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-secondary-text, #ffffff) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-secondary-text-hover, #ffffff) !important;
}

.art-rep-list__item-cta--btn-link .gform-theme--framework,
.art-rep-list__item-cta--btn-link .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: transparent !important;
	--gf-ctrl-btn-border-color-primary: transparent !important;
	--gf-ctrl-btn-border-color-hover-primary: transparent !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-primary-bg, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-primary-bg-hover, #16213e) !important;
	--gf-ctrl-btn-text-decoration: underline !important;
}

.art-rep-list__item-cta--btn-outline .gform-theme--framework,
.art-rep-list__item-cta--btn-outline .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-outline-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-outline-border, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-outline-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-outline-text, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-outline-text-hover, #ffffff) !important;
}

.art-rep-list__item-cta-heading {
	font-size: 1rem;
	margin: 0 0 var(--art-rep-spacing-xs);
}

/* End CTA — own element rendered after all items (not one of them), so it's
   centred beneath the list rather than following an item's left-aligned body
   layout. */
.art-rep-list__end-cta {
	margin-top: var(--art-rep-spacing-lg);
	text-align: center;
}

/* Same embed-mode Gravity Form submit-button remap as .art-rep-list__item-cta
   above, just a different BEM root (art-rep-list__end-cta-cta instead of
   art-rep-list__item-cta) since the End CTA is its own element, not an item. */
.art-rep-list__end-cta-cta--btn-secondary .gform-theme--framework,
.art-rep-list__end-cta-cta--btn-secondary .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: var(--color-btn-secondary-bg, #666666) !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-secondary-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-secondary-border, #666666) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-secondary-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-secondary-text, #ffffff) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-secondary-text-hover, #ffffff) !important;
}

.art-rep-list__end-cta-cta--btn-link .gform-theme--framework,
.art-rep-list__end-cta-cta--btn-link .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: transparent !important;
	--gf-ctrl-btn-border-color-primary: transparent !important;
	--gf-ctrl-btn-border-color-hover-primary: transparent !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-primary-bg, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-primary-bg-hover, #16213e) !important;
	--gf-ctrl-btn-text-decoration: underline !important;
}

.art-rep-list__end-cta-cta--btn-outline .gform-theme--framework,
.art-rep-list__end-cta-cta--btn-outline .gform-theme--api {
	--gf-ctrl-btn-bg-color-primary: transparent !important;
	--gf-ctrl-btn-bg-color-hover-primary: var(--color-btn-outline-bg-hover, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-primary: var(--color-btn-outline-border, #1a1a2e) !important;
	--gf-ctrl-btn-border-color-hover-primary: var(--color-btn-outline-border-hover, #1a1a2e) !important;
	--gf-ctrl-btn-color-primary: var(--color-btn-outline-text, #1a1a2e) !important;
	--gf-ctrl-btn-color-hover-primary: var(--color-btn-outline-text-hover, #ffffff) !important;
}

.art-rep-list__end-cta-heading {
	font-size: 1rem;
	margin: 0 0 var(--art-rep-spacing-xs);
}

/* ── CTA module — image-left style ─────────────────────────────────────────── */
/* The two columns sit inside the same bounded .art-rep-cta__inner used by the
   Default style (max-width + 15px gutter, centered) instead of running
   edge-to-edge - matching the Image & Text module's convention where the
   whole 2-column block is inset, not just the text side, AND where the image
   sits within the section's normal padding rather than touching its top/
   bottom edges. Only the horizontal padding is zeroed here (.art-rep-cta__inner
   supplies its own gutter instead) - vertical padding is left to inherit
   .art-rep-module's own top/bottom padding uncontested, same as every other
   module, so this style now participates normally in the same-Background-
   Colour auto-collapse (art_division_page_modules_padding_top_enabled()) like
   everything else. Fullwidth (below) keeps the old zero-padding/edge-to-edge
   behaviour, since its image column is a real full-bleed box, not just an
   inset one - adding section padding there would visibly pull the image in
   from the edge, defeating the point of "Fullwidth". */
.art-rep-module--cta--image-left {
	padding-left: 0;
	padding-right: 0;
}

.art-rep-module--cta--image-left .art-rep-cta__inner {
	display: grid;
	grid-template-columns: 1fr 1fr;
	/* Single explicit row filling .art-rep-cta__inner's full (flex-grown)
	   height, so both columns - including the image column, which has no
	   content of its own to size against - stretch to fill it rather than
	   collapsing to 0. */
	grid-template-rows: minmax(0, 1fr);
	align-items: stretch;
	/* .art-rep-module--cta is a column flex container (Default style); grow
	   along that main axis to fill the section's (min-)height instead of
	   collapsing to content height. */
	flex: 1 1 auto;
	text-align: initial;
}

/* Left column: background image, shown at its natural size (not
   stretched/cropped to fill) by default - overridden to cover for the
   fullwidth styles below, since that column runs edge-to-edge. */
.art-rep-cta__col--image {
	position: relative;
	background-size: auto;
	background-position: center;
	background-repeat: no-repeat;
}

/* Overlay inside the image column. */
.art-rep-cta__col--image .art-rep-cta__overlay {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/* Right column: content + CTA, vertically centred. */
.art-rep-cta__col--content {
	padding: var(--art-rep-spacing-lg) var(--art-rep-spacing-md);
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.art-rep-cta__col--content .art-rep-cta__title {
	text-align: left;
}

.art-rep-cta__col--content .art-rep-cta__intro {
	text-align: left;
}

.art-rep-cta__col--content .art-rep-cta__action {
	text-align: left;
}

/* Inset styles only (image_left/image_right, not fullwidth), side-by-side
   layout only: .art-rep-cta__inner already supplies the page's standard
   15px/max-width gutter on the column's OUTER edge (the side away from the
   image). Zero the column's own matching side so that gutter isn't stacked
   on top of the column's regular left/right padding, which was pushing the
   text ~32px further in than the rest of the page's content and putting it
   visibly out of line with it. The INNER edge (next to the image) keeps its
   normal padding for breathing room. Scoped to the same breakpoint as the
   side-by-side grid (see Responsive section below) so the mobile stacked
   layout keeps its own symmetric padding on both sides. */
@media ( min-width: 769px ) {
	.art-rep-module--cta--image-left:not( .art-rep-module--cta--fullwidth ):not( .art-rep-module--cta--image-right ) .art-rep-cta__col--content {
		padding-right: 0;
	}

	.art-rep-module--cta--image-left:not( .art-rep-module--cta--fullwidth ).art-rep-module--cta--image-right .art-rep-cta__col--content {
		padding-left: 0;
	}
}

/* ── CTA module — image-right style ────────────────────────────────────────── */
/* Shares the image-left grid layout above; this just swaps the visual order
   of the two columns (DOM/markup order is identical for both styles). */

.art-rep-module--cta--image-right .art-rep-cta__col--image {
	order: 2;
}

.art-rep-module--cta--image-right .art-rep-cta__col--content {
	order: 1;
}

/* ── CTA module — column ratio ─────────────────────────────────────────────── */
/* Matches Page Modules' Image & Text Column Ratio field. Sizes apply to
   grid-template-columns (track 1 / track 2), not to the image/content
   columns directly - so for image-right, where the order rules above swap
   which column each item lands in, the sizes must be swapped too (track 1
   here is where .art-rep-cta__col--content ends up, not the image). Applies
   to both the inset grid (.art-rep-cta__inner) and the fullwidth grid
   (the section itself); 'even' needs no rule, the base 1fr/1fr covers it.
   Scoped to the same min-width: 769px breakpoint as the mobile stacking rule
   below (not left unscoped) - these selectors are more specific than that
   rule's grid-template-columns: 1fr, so an unscoped version would have kept
   winning under 768px and stopped the columns from stacking on mobile. */
@media ( min-width: 769px ) {
	.art-rep-module--cta--ratio-image-larger:not( .art-rep-module--cta--image-right ) .art-rep-cta__inner,
	.art-rep-module--cta--fullwidth.art-rep-module--cta--ratio-image-larger:not( .art-rep-module--cta--image-right ) {
		grid-template-columns: 60% 40%;
	}

	.art-rep-module--cta--ratio-image-larger.art-rep-module--cta--image-right .art-rep-cta__inner,
	.art-rep-module--cta--fullwidth.art-rep-module--cta--ratio-image-larger.art-rep-module--cta--image-right {
		grid-template-columns: 40% 60%;
	}

	.art-rep-module--cta--ratio-image-smaller:not( .art-rep-module--cta--image-right ) .art-rep-cta__inner,
	.art-rep-module--cta--fullwidth.art-rep-module--cta--ratio-image-smaller:not( .art-rep-module--cta--image-right ) {
		grid-template-columns: 40% 60%;
	}

	.art-rep-module--cta--ratio-image-smaller.art-rep-module--cta--image-right .art-rep-cta__inner,
	.art-rep-module--cta--fullwidth.art-rep-module--cta--ratio-image-smaller.art-rep-module--cta--image-right {
		grid-template-columns: 60% 40%;
	}
}

/* ── CTA module — fullwidth image-left / image-right style ───────────────────── */
/* Same 50/50 grid as image-left/image-right, but the section itself is the
   grid container instead of .art-rep-cta__inner (template.php omits that
   wrapper entirely for this style) - so the image column runs edge-to-edge,
   like Default's background does. Order-swap for the *-right variant is
   handled by the shared .art-rep-module--cta--image-right rules above.
   Unlike the inset image-left/image-right style above, this style's image
   column is a real box filling the section (not a background layered under
   padding), so the section keeps zero padding here - any top/bottom padding
   would visibly pull the image in from the edge, defeating "Fullwidth".
   Because there's no real outer padding to auto-collapse, the module AFTER a
   Fullwidth Image CTA always gets its own normal padding-top regardless of
   Background Colour match - see art_division_page_modules_render() in Page
   Modules for that rule; it's the only side of the gap that can carry real,
   collapsible spacing here. */
.art-rep-module--cta--fullwidth {
	display: grid;
	grid-template-columns: 1fr 1fr;
	/* Single explicit row filling the section's full (min-)height, so both
	   columns - including the image column, which has no content of its own
	   to size against - stretch to fill it rather than collapsing to 0. */
	grid-template-rows: minmax(0, 1fr);
	align-items: stretch;
	padding: 0;
}

/* .art-rep-cta__col--image defaults to background-size: auto (shown at its
   natural size) for the inset styles, where the column is a modest, fixed-
   ish box. Fullwidth's column is the full edge-to-edge section height/width
   instead, so auto would show the image at native resolution with empty
   space around it rather than filling the column - cover it instead, same
   as the Default style's full-bleed background. */
.art-rep-module--cta--fullwidth .art-rep-cta__col--image {
	background-size: cover;
}

/* Content column sits flush against the section, which is intentionally
   full-bleed here. On wide viewports, grow the outer-edge padding (the side
   away from the image column) so the content lines up with the site's normal
   15px gutter (matches .art-rep-cta__inner / Page Modules' .art-pm-module__inner)
   instead of the browser edge. */
@media ( min-width: 769px ) {
	.art-rep-module--cta--fullwidth:not( .art-rep-module--cta--image-right ) .art-rep-cta__col--content {
		padding-right: max( 15px, calc( ( 100vw - var(--art-max-width, 75rem) ) / 2 ) );
	}

	.art-rep-module--cta--fullwidth.art-rep-module--cta--image-right .art-rep-cta__col--content {
		padding-left: max( 15px, calc( ( 100vw - var(--art-max-width, 75rem) ) / 2 ) );
	}
}

/* ── Responsive ─────────────────────────────────────────────────────────────── */

@media ( max-width: 768px ) {
	.art-rep-module--cta--image-left .art-rep-cta__inner,
	.art-rep-module--cta--fullwidth {
		grid-template-columns: 1fr;
	}

	.art-rep-cta__col--image {
		min-height: 300px;
	}

	.art-rep-cta__col--content {
		padding: var(--art-rep-spacing-md) var(--art-rep-spacing-sm);
	}

	/* Stack in natural (image-on-top) order on mobile regardless of style. */
	.art-rep-module--cta--image-right .art-rep-cta__col--image,
	.art-rep-module--cta--image-right .art-rep-cta__col--content {
		order: initial;
	}
}

/* ── List module ────────────────────────────────────────────────────────────── */

/* Every List style wraps its content in the theme's .container, which has
   its own side padding - on top of the base .art-rep-module side padding
   that doubled it (e.g. 16px + 15px each side on a phone, 32px + 15px on
   desktop), squeezing the content narrower than every other module.
   Compound selector so it outranks the base .art-rep-module rule
   regardless of source order. */
.art-rep-module.art-rep-module--list {
	padding-left: 0;
	padding-right: 0;
}

.art-rep-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The item text is WYSIWYG content, so its last paragraph carried the
   default bottom margin - empty space under the last line of every item. */
.art-rep-list__item-text > p:last-child {
	margin-bottom: 0;
}

.art-rep-list__media {
	flex-shrink: 0;
}

/* Anchor around the media when a link is set; keep icon colour, don't inherit link styling. */
.art-rep-list__media-link {
	color: inherit;
	display: block;
	text-decoration: none;
}

.art-rep-list__icon {
	display: block;
	fill: currentColor;
	height: 4.125rem;
	object-fit: contain;
	width: 4.125rem;
}
.art-rep-list__img {
	max-width: fit-content;	
}
/* Feature Grid: items sit side-by-side and wrap, each column centred */
.art-rep-module--list--feature-grid .art-rep-list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--art-rep-spacing-md);
	justify-content: center;
}

.art-rep-module--list--feature-grid .art-rep-list__item {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	flex: 1 1 min(100%, 220px);
}

/* Body fills the (equal-height) item so the CTA link can sit on a common
   bottom line across columns even when text wraps to fewer lines. */
.art-rep-module--list--feature-grid .art-rep-list__body {
	display: flex;
	flex-direction: column;
	align-items: center;
	flex-grow: 1;
}

.art-rep-module--list--feature-grid .art-rep-list__item-link {
	margin-top: auto;
}

/* Split: header (title + intro) fixed to the left column, items laid out as a
   divided link list in the right column - e.g. a services list beside intro
   copy and a CTA, rather than a grid of equal cards below it. */
.art-rep-module--list--split .container {
	align-items: start;
	display: grid;
	gap: var(--art-rep-spacing-lg);
	grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.2fr );
}

.art-rep-module--list--split .art-rep-module__header {
	margin: 0;
	max-width: none;
	text-align: left;
}

.art-rep-module--list--split .art-rep-list__item {
	--art-rep-list-arrow-color: rgba( 0, 0, 0, 0.35 );
	align-items: center;
	border-bottom: 1px solid var(--art-color-border, #e5e5e5);
	display: flex;
	gap: var(--art-rep-spacing-sm);
	padding: var(--art-rep-spacing-sm) 0;
}

.art-rep-module--list--split .art-rep-list__item:first-child {
	padding-top: 0;
}

.art-rep-module--list--split .art-rep-list__item:last-child {
	border-bottom: none;
}

.art-rep-module--list--split .art-rep-list__icon,
.art-rep-module--list--split .art-rep-list__img {
	max-height: 2.5rem;
	max-width: 2.5rem;
}

.art-rep-module--list--split .art-rep-list__body {
	flex: 1 1 auto;
}

.art-rep-module--list--split .art-rep-list__item-title {
	font-size: 1rem;
	letter-spacing: 0.05em;
	margin: 0 0 0.25rem;
	text-transform: uppercase;
}

.art-rep-module--list--split .art-rep-list__item-text {
	margin: 0;
}

/* Decorative trailing arrow - purely visual, so it's a ::after rather than a
   focusable element; the item_link anchor already carries the accessible
   name/destination. Colour is a local custom property so hover/focus can
   swap it to the accent colour without a second selector list. */
.art-rep-module--list--split .art-rep-list__item:hover,
.art-rep-module--list--split .art-rep-list__item:focus-within {
	--art-rep-list-arrow-color: var(--art-rep-color-accent);
}

.art-rep-module--list--split .art-rep-list__item::after {
	color: var(--art-rep-list-arrow-color);
	content: '\2192';
	flex-shrink: 0;
	font-size: 1.25rem;
	transition: color var(--art-rep-transition);
}

@media ( max-width: 768px ) {
	.art-rep-module--list--split .container {
		grid-template-columns: 1fr;
	}
}

/* Split (2-Column Items): same left-hand header as Split, but the items sit
   in a 2-column grid on the right instead of a single divided list - e.g.
   Integrity/Passion on one row, Service/Efficient on the next, so the
   section as a whole reads as header + two item columns. */
.art-rep-module--list--split-grid .container {
	align-items: start;
	display: grid;
	gap: var(--art-rep-spacing-lg);
	grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.6fr );
}

.art-rep-module--list--split-grid .art-rep-module__header {
	margin: 0;
	max-width: none;
	text-align: left;
}

.art-rep-module--list--split-grid .art-rep-list {
	column-gap: var(--art-rep-spacing-lg);
	display: grid;
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	row-gap: var(--art-rep-spacing-md);
}

.art-rep-module--list--split-grid .art-rep-list__item {
	display: flex;
	flex-direction: column;
	gap: var(--art-rep-spacing-xs);
}

.art-rep-module--list--split-grid .art-rep-list__icon,
.art-rep-module--list--split-grid .art-rep-list__img {
	max-height: 2.25rem;
	max-width: 2.25rem;
}

.art-rep-module--list--split-grid .art-rep-list__item-title {
	font-size: 1rem;
	letter-spacing: 0.05em;
	margin: 0;
	text-transform: uppercase;
}

.art-rep-module--list--split-grid .art-rep-list__item-text {
	margin: 0;
}

@media ( max-width: 900px ) {
	.art-rep-module--list--split-grid .art-rep-list {
		grid-template-columns: 1fr;
	}
}

@media ( max-width: 768px ) {
	.art-rep-module--list--split-grid .container {
		grid-template-columns: 1fr;
	}
}

/* ── Stats module ───────────────────────────────────────────────────────────── */

.art-rep-stats {
	display: grid;
	gap: var(--art-rep-spacing-md);
	grid-template-columns: repeat( auto-fit, minmax( 180px, 1fr ) );
	margin-inline: auto;
	max-width: var(--art-max-width, 860px);
	text-align: center;
}

.art-rep-stats__item {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--art-rep-spacing-xs);
}

/* Inline wrapper keeps pre-text, number, and post-text on one baseline. */
.art-rep-stats__value-wrap {
	display: flex;
	align-items: baseline;
	gap: 0.15em;
	line-height: 1;
}

.art-rep-stats__number {
	font-size: clamp( 2.5rem, 6vw, 3.5rem );
	color: var(--art-rep-color-primary);
	line-height: 1;
	/* Prevent layout reflow as digits change width during animation. */
	font-variant-numeric: tabular-nums;
}

/* Fraction glyph (½, ¾ …) sits tight against the number at the same size and
   colour so "1½" reads as one value. Pulled in slightly to cancel the wrap's
   gap. While the count-up runs, JS adds --counting to the wrap and the
   fraction waits hidden, then fades in as the number lands. */
.art-rep-stats__fraction {
	font-size: clamp( 2.5rem, 6vw, 3.5rem );
	color: var(--art-rep-color-primary);
	line-height: 1;
	margin-inline-start: -0.1em;
	transition: opacity 0.4s ease-out;
}

.art-rep-stats__value-wrap--counting .art-rep-stats__fraction {
	opacity: 0;
}

@media ( prefers-reduced-motion: reduce ) {
	.art-rep-stats__fraction {
		transition: none;
	}
}

.art-rep-stats__pre,
.art-rep-stats__post {
	font-size: clamp( 1.25rem, 3vw, 1.75rem );
	color: var(--art-rep-color-primary);
	line-height: 1;
}

.art-rep-stats__text {
	margin: 0;
	font-size: 1rem;
	color: #555;
}

/* Stats placed on a Page Modules Primary or Accent background. Page Modules
   already switches the section's theme text colours to the readable "on"
   colour there; the stat figures use this plugin's own --art-rep-color-primary
   and the label a fixed grey, so both are switched here to match. */
.art-pm-module--bg-primary .art-rep-module--stats {
	--art-rep-color-primary: var(--art-pm-on-primary, #ffffff);
}

.art-pm-module--bg-secondary .art-rep-module--stats {
	--art-rep-color-primary: var(--art-pm-on-accent, #ffffff);
}

.art-pm-module--bg-primary .art-rep-stats__text,
.art-pm-module--bg-secondary .art-rep-stats__text {
	color: inherit;
}

/* ── Content Cards module ───────────────────────────────────────────────────── */

/* Fullwidth option: cards run edge-to-edge. .art-rep-module__header keeps its
   own independent 720px max-width (see "Shared module header" above) so the
   title/intro stay readable regardless of this override. The base
   .art-rep-module rule (see "Shared module" above) carries its own
   horizontal padding on top of .container's, so both have to be zeroed here
   for the cards to actually reach the browser edge, not just .container's. */
.art-rep-module--content-cards.art-rep-module--fullwidth {
	padding-left: 0;
	padding-right: 0;
}

.art-rep-module--content-cards.art-rep-module--fullwidth .container {
	max-width: none;
	padding-left: 0;
	padding-right: 0;
}

.art-rep-cards {
	display: grid;
	gap: 1.5rem;
	grid-template-columns: repeat( var(--art-rep-cards-columns, 3), 1fr );
}

@media ( max-width: 900px ) {
	.art-rep-cards {
		grid-template-columns: repeat( 2, 1fr );
	}
}

@media ( max-width: 560px ) {
	.art-rep-cards {
		grid-template-columns: 1fr;
	}

	/* One card per row on phones: the module's Card Min Height (338.8px by
	   default, sized for a grid of cards) left a tall, mostly empty card, so
	   cap it at 280px here - a smaller setting still applies. */
	.art-rep-card {
		min-height: min( var(--art-rep-cards-min-height, 280px), 280px );
	}
}

.art-rep-card {
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
	border: 1px solid var(--art-color-border, #e5e5e5);
	display: flex;
	flex-direction: column;
	min-height: var(--art-rep-cards-min-height, 280px);
	overflow: hidden;
	position: relative;
}

.art-rep-card--image {
	flex-direction: row;
}

.art-rep-card__image {
	flex-shrink: 0;
	height: 100%;
	object-fit: cover;
	width: fit-content;
}

.art-rep-card__overlay {
	inset: 0;
	pointer-events: none;
	position: absolute;
}

/* Content sits above the overlay via z-index. */
.art-rep-card__body {
	color: var(--art-rep-card-text, #fff);
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: 20px;
	justify-content: var(--art-rep-card-content-position, flex-end);
	padding: var(--art-rep-spacing-md);
	position: relative;
	z-index: 1;
}

/* 1.375rem floor (was 1.125rem): at 2vw the floor is what phones get, and
   1.125rem sat barely above the card's 0.9375rem text, so the title read as
   the same size. Desktop still reaches the 1.5rem cap. */
.art-rep-card__title {
	color: inherit;
	font-size: clamp( 1.375rem, 2vw, 1.5rem );
	margin: 0;
}

.art-rep-card__text {
	color: inherit;
	font-size: 0.9375rem;
}

.art-rep-card__text > *:first-child { margin-top: 0; }
.art-rep-card__text > *:last-child  { margin-bottom: 0; }

.art-rep-card__action {
	margin: 0;
}

.art-rep-card__form-heading {
	color: inherit;
	font-size: 1rem;
	margin: 0 0 var(--art-rep-spacing-xs);
}

.art-rep-card__button {
	display: inline-block;
}

/* ── Responsive ─────────────────────────────────────────────────────────────── */

@media ( max-width: 640px ) {
	.art-rep-module {
		padding: var(--art-rep-spacing-md) var(--art-rep-spacing-sm);
	}

	/* Modules that wrap their content in the theme's .container (Content
	   Cards, List) already get its side gutter, so the module's own side
	   padding doubled it (16px + 15px) - the cards sat well in from the
	   edge compared with everything else on the page. */
	.art-rep-module:has( > .container ) {
		padding-left: 0;
		padding-right: 0;
	}

	.art-rep-module__inner {
		grid-template-columns: 1fr;
	}

	.art-rep-module--testimonials .art-rep-module__inner--slider {
		padding-left: 15px;
		padding-right: 15px;
	}

	.art-rep-module--testimonials .swiper-button-prev,
	.art-rep-module--testimonials .swiper-button-next {
		display: none;
	}

	/* Reviews Panel's fixed --art-rep-spacing-md (32px) padding on both the
	   panel wrapper and the card itself, plus the quote-row's icon+gap, was
	   never reduced for mobile like the rest of this block - stacked four
	   layers deep it left barely 100px for the actual quote text on a phone
	   width, wrapping one word per line. Panel and card padding both drop to
	   -sm here; the default (non-panel) card keeps its own padding since it
	   has no icon+gap stealing extra width to compound the problem. */
	.art-rep-testimonial-panel {
		padding: var(--art-rep-spacing-sm);
	}

	.art-rep-module--testimonials--card-style-panel .art-rep-testimonial {
		padding: var(--art-rep-spacing-sm);
	}

	.art-rep-testimonial__quote-row {
		gap: var(--art-rep-spacing-xs);
	}

	/* Reviews Panel nav sits below the carousel, not overlaid on the slide
	   content, so it isn't fighting for space on small screens - keep it. */
	.art-rep-module--testimonials--card-style-panel .swiper-button-prev,
	.art-rep-module--testimonials--card-style-panel .swiper-button-next {
		display: flex;
	}

}

/* ── Title alignment ────────────────────────────────────────────────────────── */
/* Per-instance custom properties (set via inline style on each module's section),
   same mobile/768/1024 breakpoints and inherit-fallback convention as Page
   Modules' --art-pm-title-align-* (see art-division-page-modules.css):
     --art-rep-title-align-mobile    title text-align at ≤ 767 px
     --art-rep-title-align-tablet    title text-align at 768 – 1023 px
     --art-rep-title-align-desktop   title text-align at ≥ 1024 px
   The CTA selectors are repeated to match .art-rep-cta__col--content
   .art-rep-cta__title's specificity (image_left/image_right styles) — see the
   base "text-align: left" rule higher up in this file.

   .art-rep-module__header is itself a centred box, capped to the theme's
   Content Text Max Width (see "Shared module header" above); text-align
   alone only shifts text within that box, not the box itself, so
   --art-rep-title-header-inline-{bp} (computed server-side from the same
   title_alignment choice: '0 auto' for left, 'auto 0' for right,
   unset/auto for centre) overrides its inline margin so it hugs the
   chosen edge instead of staying centred - the box keeps its own reading
   width either way, only its position changes. CTA doesn't need this —
   .art-rep-cta__inner is already effectively full-width.

   .art-rep-module__intro inherits .art-rep-module__header's own text-align
   (centred by default) rather than the title's - the title's explicit
   override below only ever touched the title, so switching Title Alignment
   away from centre only moved the heading and left the intro paragraph
   behind, still centred, hence text-align is also set directly on
   .art-rep-module__intro at each breakpoint below. */

@media ( max-width: 767px ) {
	.art-rep-module__header {
		margin-inline: var(--art-rep-title-header-inline-mobile, auto);
	}

	.art-rep-module__title,
	.art-rep-module__intro,
	.art-rep-cta__title,
	.art-rep-cta__col--content .art-rep-cta__title {
		text-align: var(--art-rep-title-align-mobile, inherit);
	}
}

@media ( min-width: 768px ) and ( max-width: 1023px ) {
	.art-rep-module__header {
		margin-inline: var(--art-rep-title-header-inline-tablet, auto);
	}

	.art-rep-module__title,
	.art-rep-module__intro,
	.art-rep-cta__title,
	.art-rep-cta__col--content .art-rep-cta__title {
		text-align: var(--art-rep-title-align-tablet, inherit);
	}
}

@media ( min-width: 1024px ) {
	.art-rep-module__header {
		margin-inline: var(--art-rep-title-header-inline-desktop, auto);
	}

	.art-rep-module__title,
	.art-rep-module__intro,
	.art-rep-cta__title,
	.art-rep-cta__col--content .art-rep-cta__title {
		text-align: var(--art-rep-title-align-desktop, inherit);
	}
}

/* ── Shared modal (CTA: ValPal Instant Valuation, etc.) ───────────────────────── */

dialog.art-modal {
	background: var(--art-rep-color-secondary);
	border: none;
	border-radius: var(--art-rep-radius);
	box-shadow: 0 8px 40px rgba(0, 0, 0, 0.2);
	max-width: min(600px, calc(100vw - 2rem));
	padding: 0;
	width: 100%;
}

/* The open/close animation (opacity+transform) and scroll clipping
   (max-height/overflow-y) live on .art-modal__inner, NOT the <dialog>
   element itself. `transform` on an ancestor makes it the containing block
   for any `position: fixed` descendant (e.g. a Google Places Autocomplete
   .pac-container an address field appends inside the dialog) - paired with
   overflow-y:auto that then clips/mispositions that dropdown against the
   dialog's own box instead of the viewport. Keeping <dialog> itself
   transform-free avoids creating that containing block at all. Also fixes
   a cross-plugin collision: this dialog often carries a second class too
   (e.g. Page Modules' art-pm-module__form-modal), whose own CSS targets
   the same element at equal specificity - whichever plugin's stylesheet
   happened to load last was winning and silently reintroducing this bug
   regardless of which single copy got fixed, so every copy needs it. */
dialog.art-modal .art-modal__inner {
	max-height: 90dvh;
	opacity: 0;
	overflow-y: auto;
	scrollbar-color: var(--art-rep-color-accent, #999999) transparent;
	scrollbar-width: thin;
	transform: translateY(16px) scale(0.96);
	/* Closing state's duration - deliberately quicker than opening's below,
	   a slow fade-out on dismiss reads as sluggish rather than smooth. */
	transition: opacity 0.1s ease, transform 0.1s ease;
}

/* Firefox picks up thin/coloured scrollbars from scrollbar-color above;
   Chromium/Safari need the ::-webkit- pseudo-elements instead. */
dialog.art-modal .art-modal__inner::-webkit-scrollbar {
	width: 8px;
}

dialog.art-modal .art-modal__inner::-webkit-scrollbar-track {
	background: transparent;
}

dialog.art-modal .art-modal__inner::-webkit-scrollbar-thumb {
	background-color: var(--art-rep-color-accent, #999999);
	border-radius: 9999px;
}

/* Locks the underlying page's own scrollbar while a modal is open (toggled
   by modal.js) - without this, opening a modal left two scrollbars visible
   (the page's and the dialog's own), and the page behind could still be
   wheel-scrolled despite the dialog being modal/inert. */
body.art-modal-locked {
	overflow: hidden;
}

/* The page root too: when <html> has its own overflow set (e.g. Page
   Modules' slide animations clip it sideways), it - not body - scrolls the
   page, so locking body alone let the page keep scrolling behind a popup. */
html:has(body.art-modal-locked) {
	overflow: hidden;
}

dialog.art-modal.art-modal--visible .art-modal__inner {
	opacity: 1;
	transform: translateY(0) scale(1);
	transition: opacity 0.22s ease, transform 0.22s ease;
}

dialog.art-modal::backdrop {
	backdrop-filter: blur(2px);
	background: rgba(0, 0, 0, 0.5);
	opacity: 0;
	transition: opacity 0.1s ease;
}

dialog.art-modal.art-modal--visible::backdrop {
	opacity: 1;
	transition: opacity 0.22s ease;
}

@media (prefers-reduced-motion: reduce) {
	dialog.art-modal .art-modal__inner,
	dialog.art-modal::backdrop {
		transition: none;
	}
}

.art-modal__inner {
	padding: var(--art-rep-spacing-md);
	position: relative;
}

.art-modal__close {
	background: transparent;
	border: none;
	color: var(--art-rep-color-primary);
	cursor: pointer;
	font-size: 1.5rem;
	line-height: 1;
	min-height: 44px;
	min-width: 44px;
	padding: var(--art-rep-spacing-xs);
	position: absolute;
	right: var(--art-rep-spacing-sm);
	top: var(--art-rep-spacing-sm);
}

.art-modal__close:focus-visible {
	border-radius: var(--art-rep-radius);
	outline: 2px solid var(--art-rep-color-accent);
	outline-offset: 2px;
}

.art-modal__content {
	padding-top: var(--art-rep-spacing-xs);
	text-align: left;
}
