/*
 * hwd-carousel.css  —  styles for the theme's single carousel engine
 * ===========================================================================
 * Pairs with js/hwd-carousel.js. Read that file's header first: it documents
 * the markup contract, the data-* behaviour attributes, the caption variant
 * classes and the public init API.
 *
 * STRUCTURE OF THIS FILE
 *   1. Engine       — viewport, track, slides, fade mode. Every carousel.
 *   2. Navigation   — arrows and dots. Every carousel.
 *   3. Variants     — cap-none / right / below / hover / overlay / side.
 *   4. Site uses    — the few per-placement overrides that genuinely differ.
 *
 * Anything not in section 4 should be true of EVERY carousel on the site. If
 * a change only suits one placement, it belongs in section 4, or in that
 * page's own stylesheet — not in sections 1-3.
 *
 * THE ARTIST BASE'S COPY IS CANONICAL. Sections 1-3 are byte-identical to it
 * apart from the LEGACY selectors in the gallery-source block, which are
 * HWD-only. Section 4 is entirely HWD's own. Make an engine change in the
 * artist base first, then bring it across, so the diff stays down to those
 * two parts. (Sections 1-3 gained fade mode, the cap-overlay and cap-side
 * variants and the reduced-motion fade rule on 2026-08-12, back-ported from
 * the base along with the JS. All are opt-in: no carousel on this site takes
 * any of them, so nothing here changed.)
 *
 * --- TUNABLE SETTINGS ------------------------------------------------------
 *   --hwdc-arrow-color / --hwdc-arrow-bg   chevron colour and button backing
 *   --hwdc-dot-color / --hwdc-dot-active   dot nav colours
 *   --hwdc-panel-rgb + the two alpha values  cap-right panel colour/opacity
 *   --hwdc-transition                      slide animation
 *   --hwdc-fade                            fade-mode crossfade duration
 *   --hwdc-side-split                      cap-side column ratio
 * Set any of them on .hwd-carousel, or on one variant, to retune.
 *
 * The 768px breakpoint used for cap-right must stay in sync with
 * CAP_RIGHT_BREAKPOINT in hwd-carousel.js.
 * -------------------------------------------------------------------------
 */

/* ==========================================================================
   1. ENGINE
   ========================================================================== */

.hwd-carousel {
	--hwdc-gap: 0px;                  /* set inline by the JS from data-gap */
	--hwdc-show: 1;                   /* set inline by the JS, responsive */
	--hwdc-slide-w: calc((100% - var(--hwdc-show) * var(--hwdc-gap)) / var(--hwdc-show));
	--hwdc-transition: transform 0.45s ease;
	--hwdc-fade: 1.2s;

	--hwdc-arrow-color: #666;
	--hwdc-arrow-hover: #000;
	--hwdc-arrow-bg: transparent;
	--hwdc-dot-color: #999;
	--hwdc-dot-active: #333;

	position: relative;
	box-sizing: border-box;
}

/* Before the JS runs the slides are still plain stacked children. Hide them
   to avoid a flash of the unbuilt layout; .hwdc-ready is added at build. */
.hwd-carousel:not(.hwdc-ready) {
	visibility: hidden;
}

/* The stage is the same box as the viewport but does not clip, so arrows can
   be positioned outside the slide area. Arrows are positioned against this. */
.hwdc-stage {
	position: relative;
	width: 100%;
}

.hwdc-viewport {
	position: relative;
	width: 100%;
	overflow: hidden;
}

.hwdc-track {
	display: flex;
	width: 100%;
	transition: var(--hwdc-transition);
	will-change: transform;
}

.hwdc-slide {
	position: relative;
	box-sizing: border-box;
	flex: 0 0 var(--hwdc-slide-w);
	max-width: var(--hwdc-slide-w);
	margin-right: var(--hwdc-gap);
}

/* Used by the gallery source adapter; harmless elsewhere. */
.hwdc-imgwrap {
	position: relative;
	width: 100%;
	line-height: 0;
}

.hwdc-imgwrap img {
	display: block;
	width: 100%;
	height: auto;
	margin: 0;
}

/* --- Fade mode (data-mode="fade") ----------------------------------------
   Every slide occupies the SAME grid cell, so they stack without absolute
   positioning and the track keeps an intrinsic height — the height of the
   tallest slide. That is the whole reason for grid here rather than the
   obvious `position: absolute; inset: 0`: absolute slides are out of flow, so
   the viewport would collapse to nothing and every fade carousel would need
   its height hardcoded. Only the hero actually wants a fixed height, and it
   sets one in home.css.

   .is-visible is applied by the JS. Non-visible slides stay in the layout at
   zero opacity, so they must not be clickable or reachable by tab.

   THE HEIGHT CHAIN. The three wrappers take height: 100% here and ONLY here.
   A fade carousel is often given a fixed height by its placement — the hero is
   100svh, .image-container is min(800px, 70vh) — and the slides then have to
   be able to fill it. The hero's slides make that non-negotiable: they are
   empty divs carrying nothing but a background image, so with an auto-height
   chain the grid row measures zero and the whole hero collapses. Scoped to
   fade mode deliberately: in slide mode with data-auto-height the JS writes an
   explicit pixel height onto the viewport, and a track at height: 100% of that
   would clip instead of following the slides. */
.hwd-carousel.hwdc-fade .hwdc-stage,
.hwd-carousel.hwdc-fade .hwdc-viewport {
	height: 100%;
}

.hwd-carousel.hwdc-fade .hwdc-track {
	display: grid;
	height: 100%;
	transition: none;         /* nothing translates in fade mode */
	will-change: auto;
}

.hwd-carousel.hwdc-fade .hwdc-slide {
	grid-area: 1 / 1;
	width: 100%;
	max-width: 100%;
	margin-right: 0;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity var(--hwdc-fade) ease-in-out, visibility 0s linear var(--hwdc-fade);
}

.hwd-carousel.hwdc-fade .hwdc-slide.is-visible {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity var(--hwdc-fade) ease-in-out, visibility 0s linear 0s;
}

/* --- Gallery source ------------------------------------------------------
   When the slides come from a WP block gallery, the block's own grid and
   figure spacing have to be neutralised before the engine's layout can take.
   To use: on the Gallery block, Advanced > Additional CSS class(es), add
   `hwd-carousel` plus a caption variant, eg `hwd-carousel cap-right`.

   LEGACY — HWD-ONLY, no counterpart in the artist base:
   gallerycarousel1col / gallerycarousel3col are the retired pre-engine gallery
   classes, aliased to `hwd-carousel cap-none` by the JS. They still sit in post
   content across the blog. The alias is applied at runtime, so these selectors
   must name the old classes directly — otherwise the pre-init hide rule would
   not apply until after the JS had run, which is exactly the flash of raw grid
   it exists to prevent. */
.wp-block-gallery.hwd-carousel,
.wp-block-gallery.gallerycarousel1col,
.wp-block-gallery.gallerycarousel3col {
	display: block !important;    /* override the block gallery's grid */
	box-sizing: border-box;
	margin: 0 auto 12px;          /* centre like the body paragraphs */
	max-width: 100%;
}

.wp-block-gallery.hwd-carousel figure,
.wp-block-gallery.hwd-carousel figure.wp-block-image,
.wp-block-gallery.gallerycarousel1col figure,
.wp-block-gallery.gallerycarousel3col figure {
	margin: 0 !important;
	width: auto;
}

.wp-block-gallery.gallerycarousel1col:not(.hwdc-ready),
.wp-block-gallery.gallerycarousel3col:not(.hwdc-ready) {
	visibility: hidden;
}

/* --- Auto height (data-auto-height="true") -------------------------------
   Without this the viewport is as tall as the tallest slide in the whole set,
   because that is how a flex row sizes — so one long thumbnail leaves dead
   space beneath every other slide. With it, the JS sets an explicit viewport
   height from the slides currently on screen and animates between values.
   `align-items: flex-start` stops the shorter slides stretching to match the
   tallest, which is what makes the measurement meaningful. */
.hwd-carousel.has-auto-height .hwdc-track {
	align-items: flex-start;
}

.hwd-carousel.has-auto-height .hwdc-viewport {
	transition: height 0.45s ease;
}

@media (prefers-reduced-motion: reduce) {
	.hwdc-track { transition: none; }
	.hwd-carousel.has-auto-height .hwdc-viewport { transition: none; }
	/* The JS already declines to autoplay under this preference; this covers
	   the crossfade on a manual advance. */
	.hwd-carousel.hwdc-fade .hwdc-slide { transition: none; }
}

/* ==========================================================================
   2. NAVIGATION
   The JS always builds arrows and dots (unless data-arrows/data-dots="false")
   and leaves it to CSS to decide what is visible at what width. That is why a
   carousel can show arrows on desktop and dots on mobile with no JS config.
   ========================================================================== */

.hwdc-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 35px;
	height: 45px;
	padding: 5px 3px;
	border: 0;
	cursor: pointer;
	background: var(--hwdc-arrow-bg);
	color: var(--hwdc-arrow-color);
	transition: color 0.2s ease, opacity 0.2s ease;
}

.hwdc-arrow:hover { color: var(--hwdc-arrow-hover); }
.hwdc-prev { left: 0; }
.hwdc-next { right: 0; }

/* Chevron paths are inlined by the JS rather than referenced from a sprite
   with <use> — a <use> shadow DOM blocks this stroke rule from reaching them. */
.hwdc-arrow svg {
	width: 100%;
	height: 100%;
	fill: none;
	stroke: currentColor;
	stroke-width: 2px;
	stroke-miterlimit: 10;
}

.hwdc-arrow[disabled] {
	opacity: 0.25;
	cursor: default;
}

.hwdc-dots {
	display: flex;
	justify-content: center;
	gap: 10px;
	margin: 0.9rem 0;
	padding: 12px;
}

.hwdc-dots:empty { display: none; }

.hwdc-dot {
	width: 10px;
	height: 10px;
	padding: 0;
	border: 1px solid var(--hwdc-dot-color);
	border-radius: 50%;
	background: transparent;
	cursor: pointer;
	transition: background 0.2s ease, border-color 0.2s ease;
}

.hwdc-dot.is-active {
	background: var(--hwdc-dot-active);
	border-color: var(--hwdc-dot-active);
}

/* Everything fits on screen — nothing to navigate to. */
.hwd-carousel.hwdc-static .hwdc-arrow,
.hwd-carousel.hwdc-static .hwdc-dots { display: none; }

/* ==========================================================================
   3. CAPTION VARIANTS
   Independent of slide count and of fade/slide mode — combine any variant
   with any data-show and either mode.
   ========================================================================== */

/* --- cap-none: the default. Nothing to do. ------------------------------- */
.hwd-carousel.cap-none .hwdc-caption { display: none; }

/* --- cap-right ----------------------------------------------------------
   Caption in a panel overlaid on the right of the image on wide screens,
   dropping below the image at 768px. Font-size is set inline by the JS from
   the caption's character count; the rule here is only a fallback. */
.hwd-carousel.cap-right {
	--hwdc-panel-rgb: 22, 32, 28;
	--hwdc-panel-alpha-mid: 0.82;
	--hwdc-panel-alpha-edge: 0.55;
	--hwdc-panel-color: #fff;
	--hwdc-arrow-color: #fff;
	--hwdc-arrow-hover: #fff;
	--hwdc-arrow-bg: rgba(0, 0, 0, 0.35);
}

.hwd-carousel.cap-right .hwdc-imgwrap img {
	border: 1px solid #ccc;
}

.hwd-carousel.cap-right .hwdc-arrow {
	width: 44px;
	height: 60px;
	padding: 0;
}

.hwd-carousel.cap-right .hwdc-arrow svg {
	width: 16px;
	height: 30px;
}

.hwd-carousel.cap-right .hwdc-arrow:hover { background: rgba(0, 0, 0, 0.6); }

.hwd-carousel.cap-right .hwdc-caption {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	justify-content: flex-start;
	box-sizing: border-box;
	padding: clamp(1rem, 2.5vw, 2.25rem);
	/* Vertical gradient — full opacity through the centre, fading at top and
	   bottom so more of the image shows through there. For a flat band across
	   the middle, move the mid stops in from 50% (eg 35% and 65%). */
	background: linear-gradient(
		to bottom,
		rgba(var(--hwdc-panel-rgb), var(--hwdc-panel-alpha-edge)) 0%,
		rgba(var(--hwdc-panel-rgb), var(--hwdc-panel-alpha-mid)) 50%,
		rgba(var(--hwdc-panel-rgb), var(--hwdc-panel-alpha-edge)) 100%
	);
	color: var(--hwdc-panel-color);
	overflow: hidden;
}

.hwd-carousel.cap-right .hwdc-caption-inner {
	width: 100%;
	line-height: 1.3;
	overflow-wrap: break-word;
	font-size: 1rem;
}

@media (min-width: 769px) {
	.hwd-carousel.cap-right .hwdc-caption { width: 32%; }
	/* Tidier ragging, but only in the narrow overlay panel — on mobile the
	   full-width panel wants the greedy default so the text fills the line. */
	.hwd-carousel.cap-right .hwdc-caption-inner { text-wrap: balance; }
}

@media (max-width: 768px) {
	.hwd-carousel.cap-right {
		--hwdc-panel-alpha-edge: 0.82;   /* flat, no gradient, below the image */
	}
	.hwd-carousel.cap-right .hwdc-caption {
		position: static;
		width: 100%;
		align-items: flex-start;
		padding: 1rem 1.1rem;
	}
	.hwd-carousel.cap-right .hwdc-caption-inner {
		font-size: 1rem !important;      /* JS clears its inline size here */
	}
	.hwd-carousel.cap-right .hwdc-arrow { width: 38px; height: 50px; }
}

/* --- cap-below: caption always under the image, in flow ------------------ */
.hwd-carousel.cap-below .hwdc-slide {
	display: flex;
	flex-direction: column;
}

.hwd-carousel.cap-below .hwdc-caption {
	padding: 0.9rem 0 0;
	font-size: 0.95rem;
	line-height: 1.45;
}

/* --- cap-hover: caption revealed as an overlay on hover ------------------
   The overlay sizes to the slide's link (or the slide itself if there is no
   link) so it matches the image exactly, independent of any slide padding. */
.hwd-carousel.cap-hover {
	--hwdc-hover-bg: rgba(0, 15, 15, 0.93);
	--hwdc-hover-color: #fff;
}

.hwd-carousel.cap-hover .hwdc-slide a {
	display: block;
	position: relative;
}

.hwd-carousel.cap-hover .hwdc-caption {
	position: absolute;
	top: 50%;
	left: 0;
	right: 0;
	transform: translateY(-50%);
	box-sizing: border-box;
	padding: 34px 30px 22px;
	background: var(--hwdc-hover-bg);
	border: 1px solid #999;
	color: var(--hwdc-hover-color);
	opacity: 0;
	transition: opacity 0.3s ease;
	pointer-events: none;
}

.hwd-carousel.cap-hover .hwdc-slide a:hover .hwdc-caption,
.hwd-carousel.cap-hover .hwdc-slide:hover .hwdc-caption {
	opacity: 1;
}

.hwd-carousel.cap-hover .hwdc-caption p {
	margin: 0 auto 12px;
	font-size: 0.8em;
	line-height: 1.6;
	color: inherit;
}

/* --- cap-overlay: caption always visible, positioned over the image -------
   Placed with data-cap-pos on the container: a vertical word, a hyphen and a
   horizontal word, eg data-cap-pos="bottom-left". Defaults to bottom-centre
   when the attribute is absent or unrecognised.

   Built as a full-cover flex box whose alignment moves the panel, rather than
   as an absolutely positioned panel with nine sets of top/left values. The
   flex version is nine one-line rules instead of nine three-line ones, and the
   panel keeps shrink-to-fit sizing in every position. .hwdc-caption-inner is
   the visible panel here; .hwdc-caption is only the positioning frame, so it
   must not paint or catch clicks. */
.hwd-carousel.cap-overlay {
	--hwdc-overlay-bg: rgba(0, 0, 0, 0.55);
	--hwdc-overlay-color: #fff;
	--hwdc-overlay-inset: 1.25rem;
}

.hwd-carousel.cap-overlay .hwdc-caption {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: flex;
	align-items: flex-end;        /* default: bottom … */
	justify-content: center;      /* … centre */
	box-sizing: border-box;
	padding: var(--hwdc-overlay-inset);
	pointer-events: none;
}

.hwd-carousel.cap-overlay .hwdc-caption-inner {
	max-width: 100%;
	padding: 0.7em 1em;
	background: var(--hwdc-overlay-bg);
	color: var(--hwdc-overlay-color);
	font-size: 0.95rem;
	line-height: 1.45;
	pointer-events: auto;
}

.hwd-carousel.cap-overlay[data-cap-pos^="top"]    .hwdc-caption { align-items: flex-start; }
.hwd-carousel.cap-overlay[data-cap-pos^="center"] .hwdc-caption { align-items: center; }
.hwd-carousel.cap-overlay[data-cap-pos^="bottom"] .hwdc-caption { align-items: flex-end; }

.hwd-carousel.cap-overlay[data-cap-pos$="-left"]   .hwdc-caption { justify-content: flex-start; }
.hwd-carousel.cap-overlay[data-cap-pos$="-center"] .hwdc-caption { justify-content: center; }
.hwd-carousel.cap-overlay[data-cap-pos$="-right"]  .hwdc-caption { justify-content: flex-end; }

/* --- cap-side: two-column slide, image left and caption right ------------
   In flow, not overlaid — this is the variant for a slide that is as much
   text as picture. Stacks below 768px, image first. Retune the ratio with
   --hwdc-side-split, eg `--hwdc-side-split: 2fr 1fr` for a wider image.

   Grid rather than flex so the two columns are set by the ratio alone and
   neither can be pushed out of it by a long unbroken word in the caption. */
.hwd-carousel.cap-side {
	--hwdc-side-split: 1fr 1fr;
	--hwdc-side-gap: clamp(1rem, 3vw, 2.5rem);
}

.hwd-carousel.cap-side .hwdc-slide {
	display: grid;
	grid-template-columns: var(--hwdc-side-split);
	align-items: center;
	gap: var(--hwdc-side-gap);
}

.hwd-carousel.cap-side .hwdc-caption {
	font-size: 1rem;
	line-height: 1.5;
}

@media (max-width: 768px) {
	.hwd-carousel.cap-side .hwdc-slide {
		grid-template-columns: 1fr;
		gap: 1rem;
	}
}

/* ==========================================================================
   4. SITE USES — per-placement overrides only
   HWD-ONLY. Nothing in this section has a counterpart in the artist base,
   which has its own § 4 for its own placements.
   ========================================================================== */

/* Blog posts — "More topics to explore" related-post cards (.blogsByTag).
   Three cards maximum, so above 768px they all show and the engine adds
   .hwdc-static, hiding the nav. Only the 1-up mobile view has arrows, and
   there they sit over the card thumbnail — hence the light backing so the
   chevron stays legible against any image. */
.youMayAlsoLike .hwd-carousel .hwdc-arrow {
	background: rgba(255, 255, 255, 0.75);
}

/* Portfolio category and tag archives — "What Clients Say" testimonials
   (section.testimonials > .container > .centerslide). One testimonial at a
   time, no dots, arrows outside the text column. The arrows can sit outside
   because they hang off .hwdc-stage, which does not clip; -25px matches where
   Slick's default arrow CSS put them. Colours match the theme's old .chevrons
   rule in style.css. */
section.testimonials .hwd-carousel {
	--hwdc-arrow-color: #666;
	--hwdc-arrow-hover: #000;
}

section.testimonials .hwd-carousel .hwdc-prev { left: -25px; }
section.testimonials .hwd-carousel .hwdc-next { right: -25px; }

@media only screen and (max-width: 768px) {
	/* Was `section.testimonials .slick-prev/.slick-next { top: 40% !important }`
	   in testimonials.css — the quote runs tall on a narrow screen, so vertical
	   centre sits too low. No !important needed here: this selector already
	   outranks the base .hwdc-arrow rule. */
	section.testimonials .hwd-carousel .hwdc-arrow { top: 40%; }
}

/* Homepage "What Clients Say" — the four hardcoded cards (.testimonialCards in
   page-home.php), folded onto the engine 2026-08-11 from a hand-rolled script.
   It shares section#testimonials with the archive carousel above, so the two
   rules above apply to it too and are overridden here where it differs.

   MUST STAY BELOW the block above, including its media query: these selectors
   are the same specificity (0,3,1), so source order is what decides. That is
   deliberate rather than reached for with an ID — it keeps the whole testimonial
   group at one specificity level and readable top to bottom.

   Differences from the archives, all of them carried over verbatim from the
   retired .tCarousel-* rules so the arrows land where they always have:
     • -2.5% side offsets rather than -25px. Both put the arrow outside the
       card window (possible at all because arrows hang off .hwdc-stage, which
       does not clip); this one is proportional because .testimonialCards is
       the full wrapper width rather than the narrower text column.
     • 35% vertical, at EVERY width — the 768px rule above does not apply. The
       cards are equal height with the author line pinned to the foot, so the
       chevron reads best a little above centre whatever the slide count.
     • #555 at 0.55 opacity, going to full on hover, rather than a colour
       change. Opacity is used rather than a lighter grey because the section
       sits on a pale blue ground (#f0f7f8) that a flat hex would have to be
       recomputed against. The disabled step is set explicitly, since this
       selector outranks the base .hwdc-arrow[disabled] rule in section 2. */
section.testimonials .hwd-carousel.testimonialCards {
	--hwdc-arrow-color: #555;
	--hwdc-arrow-hover: #555;
}

section.testimonials .hwd-carousel.testimonialCards .hwdc-arrow {
	top: 35%;
	opacity: 0.55;
}

section.testimonials .hwd-carousel.testimonialCards .hwdc-arrow:hover {
	opacity: 1;
}

section.testimonials .hwd-carousel.testimonialCards .hwdc-arrow[disabled] {
	opacity: 0.18;
}

section.testimonials .hwd-carousel.testimonialCards .hwdc-prev { left: -2.5%; }
section.testimonials .hwd-carousel.testimonialCards .hwdc-next { right: -2.5%; }

/* Art Archiving (and any other single-service page): widen the caption
   carousel beyond the site-wide `figure` cap. That cap is a bare tag rule in
   css/global.css (`figure { width: min(42rem, 100%) }`, ~line 225); a
   three-class selector beats it on specificity, so no !important is needed.
   The `max-width: 100%` above still holds it in on narrow screens. */
.page-template-page-single-service .wp-block-gallery.hwd-carousel {
	width: min(56rem, 100%);
	margin: 36px auto;
}

/* Homepage "Sample Websites" (section.longThumbCarousel > .websiteCarousel).
   Each slide carries its own 10px padding-right as the gutter (see home.css),
   so data-gap stays at 0. Below 1300px the arrows give way to dots, which is
   what the Slick config it replaced did. */
.websiteCarousel { padding-top: 10px; }

@media (max-width: 1300px) {
	.websiteCarousel .hwdc-arrow { display: none; }
}

@media (min-width: 1301px) {
	.websiteCarousel .hwdc-dots { display: none; }
}

@media (max-width: 768px) {
	.websiteCarousel { padding-top: 20px; }
}
