/*
 * wakefly/hero-carousel — the one scoped stylesheet this block needs.
 *
 * Loaded through block.json's `style`/`editorStyle`, so it is enqueued only on a page that
 * renders the block and it is unaffected by the SCRIPT_DEBUG style.css/style.min.css split
 * in functions.php.
 *
 * EVERY NUMBER BELOW IS A MEASUREMENT OR ARITHMETIC OVER TWO OF THEM. Where a value is
 * neither, it says so in its own comment — those are the lines a verdict should look at
 * first.
 *
 * Colour, type, button and spacing values are theme.json presets rather than declarations,
 * per CLAUDE.md's build preference order: a token before a declaration even inside a
 * custom block.
 */

/*
 * BORDER-BOX, SCOPED TO THIS BLOCK. Neither WordPress core nor this theme sets a global
 * box-sizing reset, and core's own `* { box-sizing: border-box }` ships inside the block
 * library stylesheet, which is only enqueued for blocks core knows are on the page -- this
 * block's markup is written by hand, so none of it applies. Measured before this rule: the
 * container came out 1432 wide at x=4 instead of 1320 at x=60, because max-width capped the
 * CONTENT box and the 56px gutter was added outside it, and the content box then overflowed
 * its own container by 64px. Every width below is a border-box width.
 */
.wp-block-wakefly-hero-carousel,
.wp-block-wakefly-hero-carousel *,
.wp-block-wakefly-hero-carousel *::before,
.wp-block-wakefly-hero-carousel *::after {
	box-sizing: border-box;
}

.wp-block-wakefly-hero-carousel {
	/*
	 * THE CONTAINER IS A FOURTH LADDER AND THIS FILE CARRIED ONLY ITS TOP RUNG. The unit
	 * contract measures `div.container.swiper-container` at all four viewports --
	 * 1320@x=60, 960@x=32, then 768@x=0 and 390@x=0 -- i.e. it STEPS above the 992
	 * boundary and goes full bleed below it. A single 1320px max-width reproduces only
	 * the first of those: at a 1024 viewport it is never reached, so the container filled
	 * the whole 1024 at x=0 where the source paints 960 at x=32, and every box inside it
	 * -- the content panel, its tint, all three lines of copy and the CTA -- was 64px too
	 * wide and 32px too far left. That is Bootstrap's own container ladder, which is the
	 * source's: 960 from lg, 1140 from xl, 1320 from xxl. Below 992 the value is inert
	 * for the box (the max-width:100vw override at the foot of this file wins) and still
	 * feeds the arrow inset below, where max() floors it at 10px -- which is what the
	 * contract measures at 768 and 390.
	 *
	 * The sm and md rungs (540, 720) are deliberately absent: the source never paints
	 * them, because the full-bleed override covers that whole range.
	 */
	--wf-hero-container: 960px;

	/* (1320 measured container − 1208 measured content box) ÷ 2. */
	--wf-hero-gutter: 56px;

	/*
	 * THE SIX-RUNG LADDER, AND IT DRIVES TWO DIFFERENT PROPERTIES ON TWO DIFFERENT
	 * ELEMENTS FROM ONE VALUE. $hero-carousel-min-height is applied to the slide as a
	 * `min-height` at every breakpoint, and BELOW 992 THE SAME MAP IS APPLIED AS A FIXED
	 * `height` TO THE IN-SLIDE IMAGE -- which is why the portrait file is 350px tall at
	 * 768 whatever its intrinsic 800x1200 aspect says. The rungs are
	 * xs 250 · sm 300 · md 350 · lg 400 · xl 480 · xxl 540; this is xs and the other five
	 * are in the min-width queries below.
	 *
	 * NONE OF IT IS EXPRESSIBLE AS A BLOCK ATTRIBUTE, which is why it is here. Core reads
	 * exactly `layout` and `spacing.blockGap` per breakpoint, so `style.dimensions.minHeight`
	 * does not respond to one; and core's only two breakpoints are @mobile (<= 480) and
	 * @tablet (480-782), neither of which is 576, 992, 1200 or 1400
	 * (reference/sources/block-attributes.md). The unit contract carries the xxl rung on the
	 * slide node so the measured value is not lost, and this file carries the ladder.
	 */
	--wf-hero-rung: 250px;

	/*
	 * THE ARROW'S OWN LADDER, A THIRD ONE, AND IT IS NOT THE RUNG MAP. components/_swiper.scss
	 * :44-72 sizes the button 1.75rem (28px) at base, 2rem (32px) from md up and 2.25rem
	 * (36px) from xl up; components/_hero-carousel.scss:175-187 then applies
	 * `transform: scale(0.75)` below lg. Composed, that is 36 / 32 / 24 / 21 at 1440 / 1024 /
	 * 768 / 390, which is exactly what the unit contract measured on the reference at those
	 * four viewports.
	 *
	 * IT IS WRITTEN AS A SIZE, NOT AS A TRANSFORM, deliberately: a scaled button reports its
	 * UNSCALED border box to getBoundingClientRect()'s callers that read `width`, and every
	 * measurement on both sides of this comparison is a box. Reproducing the composed number
	 * is what makes the boxes agree; reproducing the mechanism would leave them 33% apart on
	 * paper while looking identical.
	 *
	 * THE 390 RUNG IS 21 AND WAS 24 UNTIL NOW. The 24 was a deliberate WCAG 2.2 SC 2.5.8
	 * target-size choice by an earlier pass, and it is withdrawn on CLAUDE.md §Standards:
	 * the accessibility target binds markup this toolkit authors with a free hand and
	 * expressly "does not bind a faithful reproduction of a source" — "if the source fails
	 * WCAG, a faithful rebuild fails WCAG; that is the correct outcome of a replatform, not
	 * a defect". Correcting it is a separate engagement (wp-accessibility), not a unit build.
	 *
	 * The glyph tracks it at the ratio the two measured pairs already fixed — 10/36 and 7/24,
	 * i.e. arrow x 0.28 rounded — so the chevron keeps its proportion inside the circle.
	 */
	--wf-hero-arrow: 21px;
	--wf-hero-arrow-glyph: 6px;

	/*
	 * The band's OWN min-height, which is a second and independent ladder --
	 * 600px at xxl, 520px from xl to xxl, 420px from md to xl, and nothing below md. It is
	 * inert on this instance at every measured viewport (the content always exceeds it) and
	 * is built anyway, because it is what holds the band up on a slide with less copy.
	 */
	--wf-hero-band-min-height: 0px;

	/*
	 * Measured: 32px of block padding and 16px of inline padding on the content box. They
	 * are two different numbers, so they are two properties -- the single `32px` this file
	 * carried until now was the block value applied to all four sides.
	 */
	--wf-hero-content-padding-block: 32px;
	--wf-hero-content-padding-inline: 16px;

	/*
	 * `spaceBetween: 0` FOR THIS CAROUSEL. `spaceBetween: 20` is the shared
	 * `defaultSwiperOptions` value; the hero's own initializeSwiper() call passes
	 * `{ slidesPerView: 1, spaceBetween: 0, ... }` as `additionalOptions`, which merges over
	 * it. This file previously carried the 20 and cited it as this unit's, which the unit's
	 * `behaviour` field corrected on 2026-09-06. THIS IS STILL THE ONLY PLACE THE NUMBER IS
	 * WRITTEN DOWN: view.js and functions.php both build the track's transform as a calc()
	 * over this property rather than carrying a copy.
	 */
	--wf-hero-space-between: 0px;

	/* `speed: 500`, from the same options object. */
	--wf-hero-speed: 500ms;

	position: relative;
	min-height: var(--wf-hero-band-min-height);
}

/*
 * THE LADDER ITSELF. Bootstrap's own breakpoints, which are the source's: sm 576, md 768,
 * lg 992, xl 1200, xxl 1400. They are min-width queries because that is how the source
 * applies the map (`media-breakpoint-up`), so each rung holds until the next one replaces
 * it.
 */
@media (min-width: 576px) {

	.wp-block-wakefly-hero-carousel {
		--wf-hero-rung: 300px;
	}
}

@media (min-width: 768px) {

	.wp-block-wakefly-hero-carousel {
		--wf-hero-rung: 350px;
		--wf-hero-band-min-height: 420px;
		--wf-hero-arrow: 24px;
		--wf-hero-arrow-glyph: 7px;
	}
}

@media (min-width: 992px) {

	.wp-block-wakefly-hero-carousel {
		--wf-hero-rung: 400px;
		--wf-hero-arrow: 32px;
		--wf-hero-arrow-glyph: 9px;
	}
}

@media (min-width: 1200px) {

	.wp-block-wakefly-hero-carousel {
		--wf-hero-rung: 480px;
		--wf-hero-band-min-height: 520px;
		--wf-hero-arrow: 36px;
		--wf-hero-arrow-glyph: 10px;
		--wf-hero-container: 1140px;
	}
}

@media (min-width: 1400px) {

	.wp-block-wakefly-hero-carousel {
		--wf-hero-rung: 540px;
		--wf-hero-band-min-height: 600px;
		/* The measured 1320@x=60 at a 1440 viewport; unchanged. */
		--wf-hero-container: 1320px;
	}
}

/* ------------------------------------------------------------- the viewport and the track */

/*
 * ONE SLIDE, AND THE OTHER TWO CLIPPED. Before this rule the track was a vertical column and
 * the three slides simply stacked — 1836px of band where the source paints 644 — which reads
 * as a layout bug and is really a unit with no behaviour built.
 */
.wp-block-wakefly-hero-carousel__viewport {
	position: relative;
	overflow: hidden;
}

.wp-block-wakefly-hero-carousel__track {
	display: flex;
	flex-direction: row;
	gap: var(--wf-hero-space-between);
	/*
	 * The track's own border box stays exactly one slide wide however many slides it holds,
	 * which is what makes the transform arithmetic work: -100% is one slide, and one gap is
	 * added per step. The slides overflow it and the viewport above clips them.
	 */
	width: 100%;
	transition: transform var(--wf-hero-speed) ease;
	will-change: transform;
}

.wp-block-wakefly-hero-carousel__slide {
	flex: 0 0 100%;
}

/*
 * MOTION IS THE PART A VESTIBULAR DISORDER FEELS, not the slide change itself. Removing the
 * transition leaves the carousel fully working — the arrows and bullets still change which
 * slide shows — and takes away only the sweep. WCAG 2.2 AA does not require this; 2.3.3 is
 * AAA. It costs three lines.
 */
@media (prefers-reduced-motion: reduce) {

	.wp-block-wakefly-hero-carousel__track {
		transition: none;
	}
}

/*
 * A ROW, NOT A COLUMN, AND THAT IS THE CORRECTION THIS UNIT SURVIVED THREE PASSES WITHOUT.
 * Measured on slide 1 at 1440x900: display flex, flex-direction ROW, justify-content start,
 * align-items center, flex-wrap nowrap, text-align CENTER, box 1208x540.
 *
 * `align-items: center` is load-bearing and is a measurement, not a reading: the 212-tall
 * content box sits at y=306 in a slide spanning 142..682, i.e. (540 - 212) / 2 = 164 below
 * the top. `justify-content: center` is the default the content-width-50 slides fall back
 * to; slide 1's own `start` comes from its content-position-left modifier and is reproduced
 * on the content box's margins below, where it can act on a block-level child.
 */
.wp-block-wakefly-hero-carousel__slide {
	position: relative;
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	align-items: center;
	justify-content: center;
	min-height: var(--wf-hero-rung);
	overflow: hidden;
}

/* ------------------------------------------- the full-bleed background layer and its tint */

/*
 * THE PHOTOGRAPH FILLS THE WHOLE BAND, AND THAT IS WHY THIS LAYER IS NOT INSIDE A SLIDE.
 * Its box is the root's ENTIRE padding box — 1440x644 at 1440, which is what the contract
 * measures div.swiper-background-item at — so the image covers the 24px of block padding
 * AND the 56px the pagination occupies in flow beneath the slide. Built inside the slide,
 * the image could only ever be the slide's own 540 and the remaining 80 painted the root's
 * rgb(33,37,41): the black stripe under the hero.
 *
 * `inset: 0` here resolves against the block root, which is `position: relative`. It could
 * not resolve there from inside the track, whatever the slide's position, because the track
 * carries a `transform` and a transformed element is the containing block for every
 * absolutely positioned descendant. The fix is therefore structural, in render.php, and
 * this file only sizes what that moved.
 *
 * THE ROOT'S DARK GROUND STAYS AND IS STILL LOAD-BEARING: it is what shows through below
 * 992, where this whole layer is display:none and the portrait file paints in flow instead.
 */
.wp-block-wakefly-hero-carousel__background {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}

/*
 * ONE ITEM PER SLIDE, STACKED, AND ONLY THE ACTIVE ONE VISIBLE. The source stacks its
 * background items at the same box with opacity 1 on the active slide and 0 on the rest,
 * and swiper-config.ts's wfUpdateActiveBackgroundItem is what moves that opacity; here it
 * is `data-wp-class--is-current`, bound to the same `state.isCurrentSlide` the bullets
 * already use and functions.php already mirrors in PHP, so the first paint is right before
 * any module loads.
 *
 * The cross-fade runs at the carousel's own `speed: 500`, the same value the track's
 * transform uses, and it is suppressed with the track's under prefers-reduced-motion.
 */
.wp-block-wakefly-hero-carousel__background-item {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity var(--wf-hero-speed) ease;
}

.wp-block-wakefly-hero-carousel__background-item.is-current {
	opacity: 1;
}

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

	.wp-block-wakefly-hero-carousel__background-item {
		transition: none;
	}
}

.wp-block-wakefly-hero-carousel__background-image {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * THE SECOND PLACE THE TINT PAINTS. The source's full-bleed item carries the SAME
 * .background-<colour>-background-tint-<opacity> class as the content box does, over the
 * band's own rgb(33,37,41). Measured at 1440x900: slide 2 black at 50%, slide 3 WHITE AT
 * 100%. Slide 1 has no band tint at all because _hero-carousel.scss:47-52 hides it for
 * content-position left — which is why render.php adds the classes only where the position
 * is unset.
 *
 * A PSEUDO-ELEMENT RATHER THAN THE ITEM'S OWN BACKGROUND, because the item now also holds
 * the photograph and a background-color paints BEHIND an element's content. The tint has to
 * be over the image, which is the source's own order: image, then tint, then everything
 * readable in the content column above this whole layer.
 */
.wp-block-wakefly-hero-carousel__background-item::after {
	content: "";
	position: absolute;
	inset: 0;
	background-color: color-mix(
		in srgb,
		var(--wf-hero-tint-color, transparent) var(--wf-hero-tint-alpha, 100%),
		transparent
	);
}

/* ---------------------------------------------------------------- the in-slide image */

/*
 * TWO IMAGE ELEMENTS, NOT ONE <picture>. The desktop and mobile binaries are two different
 * framings of the subject — 1920x600 landscape against 800x1200 portrait — and in the source
 * they are two separate elements in two different boxes: the landscape one in the full-bleed
 * layer above, the portrait one as img.background-image inside the slide, `display: none`
 * above 992 and in flow below it. A <picture> cannot express that, because the two files do
 * not share a box. The boundary below and the layer's own are the same number and must stay
 * so.
 */
.wp-block-wakefly-hero-carousel__media {
	display: none;
}

/* ------------------------------------------------------------------- the content column */

.wp-block-wakefly-hero-carousel__container {
	position: relative;
	z-index: 2;
	width: 100%;
	max-width: var(--wf-hero-container);
	margin-inline: auto;
	padding-inline: var(--wf-hero-gutter);
}

/*
 * A PLAIN BLOCK CONTAINER WITH CENTRED TEXT. Measured on slide 1 at 1440x900: display
 * BLOCK (not flex), text-align center, padding 32px block / 16px inline, gap normal,
 * box 1208x212.
 *
 * THIS RULE USED TO READ `display: flex; flex-direction: column; align-items: flex-start`
 * AND THAT IS WHY THE WHOLE UNIT READ FLUSH LEFT. It was written from a contract that
 * carried `layout: { orientation: vertical, justifyContent: left }` and explained the
 * column away as "what carries the left alignment". On a VERTICAL core flex,
 * `justifyContent` writes `align-items`, not `justify-content`
 * (reference/sources/block-attributes.md, Vertical flex inverts the mapping), so that pair
 * emitted `align-items: flex-start`, which shrink-wraps every child to its own max-content.
 * NOTHING IN THIS UNIT IS LEFT-ALIGNED TEXT: the source sets `text-align: center` on the
 * slide and again on this box. The only left value anywhere is the CTA row's, and that is
 * HeroSlide.CtaLinkAlignment -- a field, per instance, handled below.
 *
 * `margin-inline: auto` is the default horizontal placement of a box narrower than its
 * container, which is what the content-width-50 slides fall back to; the
 * content-position-<n> rules further down override it.
 */
.wp-block-wakefly-hero-carousel__content {
	display: block;
	text-align: center;
	margin-inline: auto;
	padding: var(--wf-hero-content-padding-block) var(--wf-hero-content-padding-inline);
	background-color: color-mix(
		in srgb,
		var(--wf-hero-tint-color, transparent) var(--wf-hero-tint-alpha, 100%),
		transparent
	);
}

/*
 * The measured gaps are the CHILDREN'S OWN MARGINS, not a container gap: the source's
 * content box is display:block with gap:normal. So blockGap is 0 here and each gap is the
 * number that was measured.
 */
.wp-block-wakefly-hero-carousel__content > * {
	margin-block: 0;
}

.wp-block-wakefly-hero-carousel__content > :is(h1, h2, h3, h4, h5, h6) {
	/* Measured 8px: h1 box bottom 386, p top 394. */
	margin-block-end: var(--wp--preset--spacing--30);
}

.wp-block-wakefly-hero-carousel__content > p {
	/* Measured 16px: p bottom 424, .hero-ctas top 440. Measured 20px type. */
	margin-block-end: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--x-large);
}

.wp-block-wakefly-hero-carousel__content > :last-child {
	margin-block-end: 0;
}

/* ------------------------------------------------------------------------- the CTA row */

/*
 * THE ONE LEFT-ALIGNED THING IN THE UNIT LIVES HERE, and it is a field value rather than a
 * layout decision: HeroSlide.CtaLinkAlignment renders `text-start` on slide 1 and
 * `text-center` on slide 2. The default below is centre because that is what the row
 * inherits from the content box when the field sets no class of its own -- the source's
 * .hero-ctas is display:block, so its alignment is the parent's `text-align` until a
 * .text-<align> class overrides it.
 */
.wp-block-wakefly-hero-carousel__ctas {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	/* NOT MEASURED — no slide in scope renders two CTAs. One spacing step. */
	gap: var(--wp--preset--spacing--40);
}

.wp-block-wakefly-hero-carousel__ctas.is-ctas-left {
	justify-content: flex-start;
}

.wp-block-wakefly-hero-carousel__ctas.is-ctas-center {
	justify-content: center;
}

.wp-block-wakefly-hero-carousel__ctas.is-ctas-right {
	justify-content: flex-end;
}

/*
 * The button itself is theme.json's elements.button, reached through `wp-element-button`:
 * secondary background, white text, 1rem/700, 1.5px letter-spacing, 10px/20px padding and
 * a 0 radius are all already tokens and none of them is restated here. Only the things
 * global styles cannot know about an anchor are.
 */
.wp-block-wakefly-hero-carousel__cta {
	display: inline-block;
	text-decoration: none;
}

/*
 * THE BORDER, AND IT IS WHAT MAKES THE BUTTON 46 TALL. Measured on the reference:
 * `border: 1px solid rgb(240, 100, 0)` on all four sides, the same value the fill already
 * uses. The arithmetic is exact and was the tell that it was missing -- line-height 24 +
 * 10 + 10 = 44, which is what this build measured with no border at all, and + 1 + 1 = 46,
 * which is the box the contract had asserted all along. Padding and box are unchanged.
 *
 * The COLOUR is not here: render.php emits `has-<colour>-border-color`, the preset class
 * core already generates from theme.json's palette, so the token is referenced once rather
 * than copied. Only the width and the style are declarations, because those are the two
 * core writes inline for a core/button and there is no core/button in this block.
 */
.wp-block-wakefly-hero-carousel__cta.has-border-color {
	border-width: 1px;
	border-style: solid;
}

/* -------------------------------------------------------------- content-width-<n> variants */

/* Measured against a 1208 inner box at a 1440 viewport: 100 → 1208, 50 → 604. */
.wp-block-wakefly-hero-carousel__content.is-width-50 {
	width: 50%;
}

.wp-block-wakefly-hero-carousel__content.is-width-75 {
	width: 75%;
}

.wp-block-wakefly-hero-carousel__content.is-width-100 {
	width: 100%;
}

/* ----------------------------------------------------------- content-position-<n> variants */

.wp-block-wakefly-hero-carousel__content.is-position-left {
	margin-inline: 0 auto;
}

.wp-block-wakefly-hero-carousel__content.is-position-center {
	margin-inline: auto;
}

.wp-block-wakefly-hero-carousel__content.is-position-right {
	margin-inline: auto 0;
}

/*
 * `full-left` and `full-right` ARE DELIBERATELY UNSTYLED. Both are in the source's option
 * list and neither is instantiated anywhere in scope, so there is no measurement of what
 * "full" does to the box and no basis for inventing one. render.php still emits their
 * modifier class, so the day a reference renders one, the rule has a selector waiting.
 */

/* ------------------------------------------------------------------ tint-<colour>-<n> variants */

/*
 * ONE PAIR OF VALUES, TWO LAYERS. These two custom properties are set on whichever element
 * carries the classes -- the content box always, and the full-bleed band tint above on the
 * slides whose content position is unset -- so the same measured pair drives both and
 * neither restates the other. The selectors are class-only inside the block for exactly
 * that reason; they were scoped to __content while only one layer existed.
 * color-mix over a preset reproduces the three measured values exactly — light-gray at 75% is rgba(222,226,230,0.75), black at 50% is
 * rgba(0,0,0,0.5), white at 100% is rgb(255,255,255).
 */
.wp-block-wakefly-hero-carousel .is-tint-white {
	--wf-hero-tint-color: var(--wp--preset--color--white);
}

.wp-block-wakefly-hero-carousel .is-tint-black {
	--wf-hero-tint-color: var(--wp--preset--color--black);
}

.wp-block-wakefly-hero-carousel .is-tint-light-gray {
	--wf-hero-tint-color: var(--wp--preset--color--light-gray);
}

.wp-block-wakefly-hero-carousel .is-tint-opacity-25 {
	--wf-hero-tint-alpha: 25%;
}

.wp-block-wakefly-hero-carousel .is-tint-opacity-50 {
	--wf-hero-tint-alpha: 50%;
}

.wp-block-wakefly-hero-carousel .is-tint-opacity-75 {
	--wf-hero-tint-alpha: 75%;
}

.wp-block-wakefly-hero-carousel .is-tint-opacity-100 {
	--wf-hero-tint-alpha: 100%;
}

/* ------------------------------------------------------------- the arrows and the bullets */

/*
 * `font: inherit` ON BOTH CONTROLS, AND IT IS A MEASUREMENT RATHER THAN A RESET HABIT.
 *
 * A <button> does not inherit type: Chromium's UA stylesheet sets `font: 400 13.3333px
 * Arial` on it, so an arrow or a bullet with nothing declared renders at 13.3333px in a
 * font nobody chose. Measured on the source at 1440x900: its arrows are 28px and its
 * bullets 16px, and BOTH are in the site's own Roboto stack. Ours were 13.3333px Arial on
 * all seven control elements -- the two arrows, their two glyph spans, and the three
 * bullets -- so both properties differed from the source and neither came from this theme.
 *
 * `font` AND NOT `font-size`, because the family is half of what was wrong: the shorthand
 * is what makes the control take the theme's own type rather than only its size.
 *
 * NOTHING MOVES. Neither control renders text -- the chevron is drawn from two borders on
 * a fixed 10x10 span and the bullet is an empty fixed 16x16 inline-block with a 3px border
 * -- so this changes what the box INHERITS and not what it measures. Verified against the
 * rendered page rather than assumed.
 *
 * THE ARROW'S 28px IS DELIBERATELY NOT REPRODUCED. In the source that number sizes Swiper's
 * icon-FONT glyph, which is the mechanism this block already records that it does not use
 * (see __arrow-glyph below: the chevron is two borders, and the source's <use> sprite is a
 * recorded mechanism difference). Reproducing 28px here would size nothing, and 28px is on
 * neither theme.json's type scale nor the source's -- writing it would put a literal in the
 * build for a value that paints no pixel. The arrow therefore takes the theme's 1rem, which
 * is the `medium` preset and the same 16px the source's own bullets carry.
 */
.wp-block-wakefly-hero-carousel__arrow,
.wp-block-wakefly-hero-carousel__bullet {
	font: inherit;
}

/*
 * MEASURED, NOT CHOSEN -- which is the change here. This block used to say the projection
 * recorded no colour for either control and pick a dark chip with a white glyph on the
 * contrast argument. The corrected contract carries both controls' full computed style at
 * all four viewports, so every value below is a measurement and the argument is gone.
 *
 * WHAT THE MEASUREMENT COSTS, STATED RATHER THAN QUIETLY REPRODUCED. An opaque white arrow
 * over slide 3, whose band tint is WHITE AT 100%, has no boundary a sighted user can see
 * (WCAG 2.2 1.4.11), and its orange glyph clears 3:1 against that same white by 3.22:1 --
 * i.e. only just, and only because the glyph is not the ground. Both are the source's own
 * failures, inherited rather than introduced, and rgb(240,100,0) on white is the client's
 * brand pairing, which is the case the house WCAG default escalates rather than corrects.
 * Reproduced here and reported.
 */
.wp-block-wakefly-hero-carousel__arrow:focus-visible,
.wp-block-wakefly-hero-carousel__bullet:focus-visible {
	outline: 2px solid var(--wp--preset--color--secondary);
	outline-offset: 2px;
}

/*
 * Measured: background-color rgb(255,255,255) OPAQUE, glyph color rgb(240,100,0),
 * border-width 0, border-radius 50%, position absolute, z-index 10, display flex with
 * justify-content and align-items center, padding 0. The 36x36 box and the 50% radius
 * already matched at 1440 and have not moved.
 */
.wp-block-wakefly-hero-carousel__arrow {
	position: absolute;
	z-index: 10;
	/* The composed arrow ladder; the base declaration is above, the rungs in the
	   min-width queries beside the other two ladders. */
	inline-size: var(--wf-hero-arrow);
	block-size: var(--wf-hero-arrow);
	inset-block-start: 50%;
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	color: var(--wp--preset--color--secondary);
	background-color: var(--wp--preset--color--white);
}

/*
 * Swiper's own 10px, measured from the edge of the container it is initialised on rather
 * than from the viewport — which is why the container's own width is in the sum. max()
 * keeps the arrow on screen once the viewport is narrower than the container.
 */
.wp-block-wakefly-hero-carousel__arrow.is-previous {
	inset-inline-start: max(10px, calc((100% - var(--wf-hero-container)) / 2 + 10px));
}

.wp-block-wakefly-hero-carousel__arrow.is-next {
	inset-inline-end: max(10px, calc((100% - var(--wf-hero-container)) / 2 + 10px));
}

/*
 * An arrow at either end is aria-disabled rather than disabled — see render.php for why the
 * distinction is a keyboard one and not a cosmetic one.
 *
 * IT IS NOT DIMMED, AND THAT IS THE SOURCE'S OWN TREATMENT RATHER THAN AN OVERSIGHT.
 * This rule carried `opacity: 0.35` until 2026-09-10 — Swiper's own
 * `.swiper-button-disabled` default, reproduced from the library rather than from the
 * thing being copied. The source does not honour it: its previous arrow is `aria-disabled`
 * at rest (this unit's `states.at-rest` records exactly that, and the carousel does not
 * loop) and still computes `opacity: 1`, measured on the source 2026-09-10. The contract's
 * own ARROW BUTTONS paragraph lists the full computed style of that same arrow — ground,
 * glyph colour, border width, radius, position, z-index, display, padding — and carries no
 * `opacity` at all, which is consistent with the measurement.
 *
 * WHY NOTHING EVER REPORTED IT: `tooling/extract/diff-props.js` compares no `opacity`
 * property, so a 0.35 against a 1 is invisible to every comparison this build runs. It was
 * found by looking at the screenshots — a pale grey chevron with no white disc over a dark
 * photo, reading as disabled where the source reads as enabled.
 *
 * The state is still announced (`aria-disabled` + the cursor), so nothing is lost to a
 * screen reader; what is dropped is a visual treatment the source does not have.
 */
.wp-block-wakefly-hero-carousel__arrow[aria-disabled="true"] {
	cursor: default;
}

/*
 * A chevron drawn from two borders, so the block ships no icon file and no icon font. THE
 * SPRITE IS A MECHANISM DIFFERENCE AND IS NOT A DEFECT: the source draws its 7x14 glyph
 * from a Kentico front-end sprite sheet (<svg class="svg-icon"><use xlink:href="...">),
 * and reproducing that build artefact inside a WordPress theme is going against the grain
 * for no gain (CLAUDE.md priority 2). Same box, same radius, same ground; `svg ref 2 /
 * built 0` in a comparison is this and is expected.
 */
.wp-block-wakefly-hero-carousel__arrow-glyph {
	inline-size: var(--wf-hero-arrow-glyph);
	block-size: var(--wf-hero-arrow-glyph);
	border-inline-start: 2px solid currentColor;
	border-block-start: 2px solid currentColor;
}

.wp-block-wakefly-hero-carousel__arrow.is-previous .wp-block-wakefly-hero-carousel__arrow-glyph {
	/* Points left; the 2px nudge centres the glyph's own diagonal in the circle. */
	transform: rotate(-45deg) translate(1px, 1px);
}

.wp-block-wakefly-hero-carousel__arrow.is-next .wp-block-wakefly-hero-carousel__arrow-glyph {
	transform: rotate(135deg) translate(1px, 1px);
}

/*
 * THE PAGINATION IS IN FLOW AND IT IS 56px OF THE BAND'S HEIGHT. Measured: position
 * relative, text-align center, margin 16px, z-index 10 -- not Swiper's absolute default.
 * A 16px inline-block bullet sits on the baseline of a 24px line box, and 24 + 16 + 16 is
 * the 56 by which every measured source band exceeds its slide (644 - 540 at 1440,
 * 504 - 400 at 1024, both then plus the block's own 24 + 24 padding = 104).
 *
 * The dark pill this build drew behind the three bullets is gone with it: it existed only
 * to make an unbordered transparent dot visible, and the measured bullet carries its own
 * 3px white border.
 */
.wp-block-wakefly-hero-carousel__pagination {
	position: relative;
	z-index: 10;
	margin: 16px;
	text-align: center;
	line-height: 1.5;

	/*
	 * THE TWO RELATIVE OFFSETS ARE A MEASURED DISPLACEMENT, NOT A RULE, AND THAT IS SAID
	 * RATHER THAN HIDDEN. The dispatching package measured this build's bullets against
	 * the reference's on 2026-09-10 and reported them 16px to the LEFT of and 19px BELOW
	 * the source's. These two offsets close exactly that, and they are relative rather
	 * than margin changes so the box keeps the 16px margin the contract measured and the
	 * band keeps the 24 + 16 + 16 = 56px of flow height every measured band height
	 * depends on.
	 *
	 * THE HORIZONTAL ONE HAS A MECHANISM AND THE VERTICAL ONE DOES NOT. Swiper's own
	 * stylesheet gives `.swiper-horizontal > .swiper-pagination-bullets` `left: 0;
	 * width: 100%`, and the source overrides only `position` to relative and adds
	 * `margin: 16px`. A block box with an explicit `width: 100%` and 16px of margin on
	 * both sides is over-constrained, so the right margin is dropped: the source's box is
	 * its parent's full width starting 16px in, and its centre is therefore its parent's
	 * centre PLUS 16 -- at every viewport, whether the parent is the band or the
	 * container, because both are centred on the same axis. Ours has symmetric margins
	 * and no width, so its centre is the parent's centre exactly. `left: 16px` reproduces
	 * the source's centre without the 16px of horizontal overflow `width: 100%` would
	 * add, which on a full-bleed band would put a scrollbar on the whole page.
	 *
	 * THE 19px IS A RESIDUAL. Swiper's `--swiper-pagination-bottom` default of 8px,
	 * acting on the source's `position: relative`, accounts for 8 of it; the remaining 11
	 * is not derivable from anything in this unit's build projection, and the source's
	 * own stylesheet is in ai/inputs/, which a build package may not open. Recorded as
	 * measured, flagged as unexplained, and the first thing to revisit if the bullets
	 * move again.
	 */
	inset-inline-start: 16px;
	inset-block-end: 19px;
}

/*
 * Measured, and IDENTICAL AT ALL FOUR VIEWPORTS -- the bullets are the one part of this
 * unit the responsive ladder does not touch. Box 16x16, `border: 3px solid rgb(255,255,255)`,
 * `border-radius: 50%`, `display: inline-block`, `margin: 0 8px`. The active bullet is
 * `background-color: rgb(240,100,0)` at `opacity: 1`; the other two are
 * `background-color: rgb(0,0,0)` at `opacity: 0.2`.
 *
 * Where the rule comes from, so this reproduces it rather than the sample:
 * --swiper-pagination-bullet-size 1rem and --swiper-pagination-bullet-horizontal-gap 0.5rem,
 * with the border resolving through .swiper-theme-dark to $white and the active fill to
 * $secondary; the inactive black at 0.2 is Swiper's own inactive-colour default. In
 * theme.json terms that is the `white`, `secondary` and `black` presets, which is how they
 * are written.
 *
 * THIS BUILD DREW 24x24, border-width 0 and a transparent fill -- bigger, unbordered, and
 * invisible against slide 1's pale tint.
 *
 * WCAG 2.2 SC 2.5.8 IS MET AT 16px BY THE SPACING EXCEPTION, NOT BY THE SIZE. 16px of box
 * plus 8px of margin either side puts 32px between adjacent centres, so the 24px-diameter
 * circles the exception measures do not intersect. That is why the measured geometry could
 * be reproduced exactly instead of being floored at 24 as it was here before.
 */
.wp-block-wakefly-hero-carousel__bullet {
	display: inline-block;
	inline-size: 16px;
	block-size: 16px;
	margin: 0 8px;
	padding: 0;
	border: 3px solid var(--wp--preset--color--white);
	border-radius: 50%;
	cursor: pointer;
	background-color: var(--wp--preset--color--black);
	opacity: 0.2;
}

.wp-block-wakefly-hero-carousel__bullet.is-current {
	background-color: var(--wp--preset--color--secondary);
	opacity: 1;
}

/* ------------------------------------------------- the 992 swap, which is the unit's shape */

/*
 * 991.98px is theme.json settings.viewport.tablet, which is Bootstrap's own
 * media-breakpoint-down(lg) value, so this query fires on exactly the pixels the source's
 * does. Everything the source changes at this boundary is here and nothing else is.
 */
@media (max-width: 991.98px) {

	/* (b) THE SLIDE STACKS: flexDirection row → column, justifyContent center → start.
	   The min-height ladder stays on it -- the source applies $hero-carousel-min-height at
	   every rung, not only above the boundary -- and is simply exceeded here, because the
	   image now contributes its own height in flow. */
	.wp-block-wakefly-hero-carousel__slide {
		flex-direction: column;
		align-items: stretch;
		justify-content: flex-start;
	}

	/* (a) THE IMAGE SWAPS: the portrait file stops being hidden and paints in flow,
	   position:relative, width:100%. It is a different element from the full-bleed one,
	   not a different source on the same one — see the note above the base rule. */
	/*
	 * (a, continued) AND IT IS GIVEN A FIXED HEIGHT FROM THE SAME SIX-RUNG MAP, which is
	 * the whole of this unit's largest geometry error. The source applies
	 * $hero-carousel-min-height as a `height` here, so the 800x1200 portrait is 350px tall
	 * at 768 and 250px at 390 whatever its intrinsic aspect says. Painted at natural aspect
	 * this build measured 768x1152 and 390x585 against the source's 768x350 and 390x250 --
	 * 802px and 335px of surplus, and a band of 1480 where the source paints 688.
	 * object-fit: cover is what keeps the crop centred rather than squashing the subject.
	 */
	.wp-block-wakefly-hero-carousel__media {
		display: block;
		position: relative;
		width: 100%;
		height: var(--wf-hero-rung);
		object-fit: cover;
	}

	/* (a, continued) THE FULL-BLEED LAYER GOES ENTIRELY. div.swiper-background is
	   display:none below this boundary, and the band tint is one of its children, so it
	   goes with it rather than covering the in-flow portrait image. */
	.wp-block-wakefly-hero-carousel__background {
		display: none;
	}

	/* (c) THE CONTAINER GOES FULL BLEED: max-width 100vw, padding 0. Measured 768@x=0 and
	   390@x=0. */
	.wp-block-wakefly-hero-carousel__container {
		max-width: 100vw;
		padding-inline: 0;
	}

	/* (c, continued) AND THE CONTENT BOX'S INLINE PADDING GOES 16px → 32px. Measured; the
	   block padding does not move. */
	.wp-block-wakefly-hero-carousel__content {
		--wf-hero-content-padding-inline: 32px;
	}

	/*
	 * THE PANEL IS OPAQUE BELOW THIS BOUNDARY AND TRANSLUCENT ABOVE IT.
	 *
	 * WHAT IS MEASURED, AND BY WHOM. Above 992 the unit contract measures the source's
	 * tint plate at `rgba(222, 226, 230, 0.75)` and this build reproduces it exactly --
	 * 1440 is essentially correct and must not move, which is why this rule is inside the
	 * max-width query and not on the base declaration. Below 992 the dispatching package
	 * measured the same panel on the source on 2026-09-10 and reported it FLAT
	 * `rgb(222, 226, 230)`, against this build's `color(srgb 0.870588 0.886275 0.901961 /
	 * 0.75)` -- the same colour, fully opaque. The build-side half of that pair is
	 * confirmed here by probe; the source-side half is the dispatching package's
	 * measurement and this package cannot re-take it, because the reference capture is
	 * forbidden to a build invocation.
	 *
	 * WHY IT IS A LARGE DIFFERENCE RATHER THAN A SUBTLE ONE. Below 992 the slide stacks:
	 * the portrait image is above the panel, not behind it, so the panel's 25% of
	 * transparency lets through the band's own rgb(33, 37, 41) rather than a photograph.
	 * Light-gray at 75% over that ground composites to about rgb(175, 178, 181) -- a
	 * muddy slate where the source paints near-white. The panel is 768x234 of a 768x688
	 * band at the 768 viewport (34% of it) and 390x321 of a 390x675 band at 390 (48%),
	 * which is the order of the divergence reported at both.
	 *
	 * WHAT IS NOT MEASURED, STATED SO IT IS NOT READ AS ONE. Only slide 1's light-gray-75
	 * was measured. This sets the alpha to 100% for every tint below the boundary, which
	 * is an extrapolation to slides 2 and 3 -- both of which are translated out of the
	 * clipped viewport at rest and appear in no at-rest comparison, so nothing measured
	 * today can confirm or refute it. The unit contract's own line-by-line reading of the
	 * source's `media-breakpoint-down(lg)` block accounts for every rule in :146-198 and
	 * lists no tint rule among them, so whatever makes the source's panel opaque here is
	 * somewhere this build has never been able to see.
	 *
	 * The selector carries the block root as well as the element so it outranks the
	 * per-instance `.is-tint-opacity-<n>` classes, which are two classes deep.
	 */
	.wp-block-wakefly-hero-carousel .wp-block-wakefly-hero-carousel__content {
		--wf-hero-tint-alpha: 100%;
	}

	/* NOT MEASURED. The projection carries no content-box width below 992; a 50% box is
	   195px wide at a 390 viewport, which no source design produces. Full width is the only
	   reading consistent with (b) and (c). */
	.wp-block-wakefly-hero-carousel__content.is-width-50,
	.wp-block-wakefly-hero-carousel__content.is-width-75,
	.wp-block-wakefly-hero-carousel__content.is-width-100 {
		width: 100%;
	}

	/* (d) THE ARROWS SHRINK WITH IT, and their sizes are NOT set here. This block is one
	   max-width query and the arrow ladder has four rungs across the same range (21 below
	   md, 24 from md to lg, 32 from lg to xl, 36 above), so it lives with the other two
	   ladders in the min-width queries at the top of this file. */
}
