/**
 * The hero.
 *
 * One picture at a time, filling the screen, cross-fading. Every slide is stacked
 * in the same place and only opacity moves, which is what keeps the fade cheap
 * enough to run on a phone and what lets the picture underneath be a real element
 * the parallax can take hold of.
 *
 * The turn on a portrait phone is the whole reason this file exists rather than a
 * few more rules in frontend.css. See the media query at the foot.
 */

.airline-hero {
	--airline-hero-height: 100svh;
	--airline-hero-slide: 800ms;
	--airline-hero-dim: 0;

	/*
	 * A decelerating curve, so a picture arrives rather than coasting to a stop.
	 * The mask in airline-transition uses a near-symmetrical one because a wipe is
	 * a shape crossing the screen; this is a photograph being brought in and set
	 * down, and it wants the weight at the start.
	 */
	--airline-hero-ease: cubic-bezier( 0.22, 1, 0.36, 1 );

	/*
	 * How far the picture hangs past the slide at each end, which is the room the
	 * parallax has to move it in. It wants to be a little over half the distance
	 * the scrub travels — the site's ScrollTrigger shifts by 11% of the picture's
	 * own height — so that an edge never comes into view at either extreme.
	 */
	--airline-hero-overhang: 6%;

	/*
	 * The arrows, matched to the carousel's so a site restyling one restyles both,
	 * but light-on-dark by default: a hero is a photograph, and a white disc in the
	 * corner of a photograph is a sticker.
	 */
	--airline-hero-arrow: #ffffff;
	--airline-hero-arrow-bg: rgba( 0, 0, 0, 0.28 );
	--airline-hero-arrow-size: 3rem;
	--airline-hero-arrow-icon: 1.4rem;

	position: relative;
	height: var(--airline-hero-height);

	/*
	 * The pictures are bigger than the box on purpose — that is what covering
	 * means, and on a phone the turned picture is very much bigger. Clipping here
	 * is what stops the page growing a horizontal scrollbar because of it.
	 */
	overflow: hidden;
}

.airline-hero__viewport {
	position: relative;
	width: 100%;
	height: 100%;
}

/*
 * Every slide in the same place, stacked, and moved sideways rather than faded.
 *
 * At rest a slide sits one full width off to the right, which is where it comes in
 * from and where it returns to once it has left. Only the picture that is showing,
 * and the one on its way out, are anywhere near the screen.
 *
 * Sliding rather than cross-fading is not only a matter of taste here: a fade shows
 * both photographs at once, at half strength, through each other — which on two
 * aerial shots of concrete reads as neither. A slide shows one at a time and gives
 * the movement a direction.
 *
 * `visibility` rather than `display`: a display change cannot be transitioned, and
 * a slide that is merely off-screen still holds its pictures in the accessibility
 * tree and in the tab order. It is hidden when it is neither showing nor moving,
 * and the script takes `is-moving` off once the movement is done.
 */
.airline-hero__slide {
	position: absolute;
	inset: 0;
	transform: translateX( 100% );
	visibility: hidden;
	transition: transform var(--airline-hero-slide) var(--airline-hero-ease);
}

.airline-hero__slide.is-active {
	transform: translateX( 0 );
}

.airline-hero__slide.is-active,
.airline-hero__slide.is-moving {
	visibility: visible;
}

/*
 * For the one frame in which an arriving picture is put on the edge it will come
 * in from. Without it the browser has no starting point to animate away from and
 * the picture simply appears where it was going.
 */
.airline-hero__slide.is-instant {
	transition: none;
}

/*
 * The element the parallax moves.
 *
 * Taller than the slide, and pulled up by the overhang's half, so that the site's
 * ScrollTrigger can scrub it up and down without ever showing an edge. The 11% it
 * shifts is a share of this element's own height, which is why the overhang is
 * expressed the same way.
 */
.airline-hero__media {
	position: absolute;
	inset: calc( -1 * var(--airline-hero-overhang) ) 0;

	/*
	 * A size container, so that the turned picture below can be measured against
	 * this element rather than against the screen. It is the only way to say
	 * "as wide as this box is tall": percentages resolve width against width and
	 * height against height, which is exactly the swap a quarter turn needs and
	 * exactly what they cannot express.
	 */
	container-type: size;

	will-change: transform;
}

.airline-hero__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The wash over the photograph, painted only when it has been asked for. At zero
 * the element is still in the markup — it is one div, and having it always present
 * means a theme can reach it — but it costs nothing to composite.
 */
.airline-hero__overlay {
	position: absolute;
	inset: 0;
	background: #000;
	opacity: var(--airline-hero-dim);
	pointer-events: none;
}

/* ----------------------------------------------------------------- arrows */

.airline-hero__step {
	position: absolute;
	top: 50%;
	transform: translateY( -50% );
	z-index: 2;

	display: flex;
	align-items: center;
	justify-content: center;
	width: var(--airline-hero-arrow-size);
	height: var(--airline-hero-arrow-size);
	padding: 0;

	color: var(--airline-hero-arrow);
	background: var(--airline-hero-arrow-bg);
	border: 0;
	border-radius: 50%;
	cursor: pointer;

	transition: background-color 0.2s ease;
}

.airline-hero__step:hover {
	background: rgba( 0, 0, 0, 0.5 );
}

.airline-hero__step:focus-visible {
	outline: 2px solid var(--airline-hero-arrow);
	outline-offset: 3px;
}

.airline-hero__step[ hidden ] {
	display: none;
}

/*
 * The chevron, said in CSS rather than left to the SVG's presentation attributes,
 * for the reason the carousel's arrows are: a stylesheet beats a presentation
 * attribute, and themes very commonly ship `svg { fill: currentColor }` for their
 * icon sets — which turns an open path into a filled wedge — or `svg path { stroke:
 * none }`, which erases it.
 */
.airline-hero__step svg {
	display: block;
	width: var(--airline-hero-arrow-icon);
	height: var(--airline-hero-arrow-icon);
	fill: none;
	stroke: currentColor;
	overflow: visible;
}

.airline-hero__step svg path {
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.airline-hero__step--prev {
	left: 1rem;
}

.airline-hero__step--next {
	right: 1rem;
}

/* ------------------------------------------------- the turn, on a phone held up */

/*
 * A skatepark photographed from the air is a wide, shallow thing. On a screen that
 * is twice as tall as it is wide, covering with it means throwing away most of its
 * width — the picture stops being a picture of a skatepark and becomes a picture of
 * some concrete. Turned a quarter to the left it covers the same screen using its
 * whole length, and reads.
 *
 * Rotating swaps the axes, so the box before the turn has to be as wide as its
 * container is tall and as tall as its container is wide; after the turn it is
 * exactly the container again.
 *
 * `cqh` and `cqw` are that swap said out loud, measured against
 * `.airline-hero__media` — see the `container-type` on it above. The obvious
 * spelling, `100svh` and `100vw`, was wrong in a way that only showed once the page
 * was scrolled: the wrapper deliberately hangs past the slide at each end to give
 * the parallax somewhere to travel, so a picture sized to the *screen* is shorter
 * than the box that carries it, and the first scrub brings its edge into view.
 * Sized to the container it inherits that headroom for free, whatever the hero's
 * height is set to and whether or not it runs full width.
 *
 * Only `.is-landscape`. A portrait photograph is already the right way up on a
 * portrait screen, and turning it would be the same mistake in the other
 * direction. A square is neither and is left alone — see slides() in the renderer.
 *
 * On the <img> and never on .airline-hero__media, because that element is what the
 * site's ScrollTrigger scrubs `yPercent` on, and `yPercent` resolves along the
 * element's own axes: turn the wrapper and the parallax drifts the picture sideways
 * instead of up. The two transforms are kept one level apart so they compose.
 */
@media ( orientation: portrait ) and ( max-width: 782px ) {
	.airline-hero--turns .airline-hero__slide.is-landscape .airline-hero__media img {
		position: absolute;
		top: 50%;
		left: 50%;
		width: 100cqh;
		height: 100cqw;

		/*
		 * And the caps taken off, or none of the above survives.
		 *
		 * WordPress ships `img { max-width: 100% }` in the block library, every
		 * theme ships it again, and it is right for every image on a page except
		 * one that has been turned on its side. A picture as wide as its container
		 * is tall is, by definition, wider than its container — so `max-width:
		 * 100%` clamped the 945px width back to the container's 354 and left the
		 * height at 354 too. The result was an exactly square photograph in the
		 * middle of a tall screen, which is what this looked like on a phone while
		 * every other measurement said it was correct.
		 */
		max-width: none;
		max-height: none;

		transform: translate( -50%, -50% ) rotate( -90deg );
	}
}

/* ------------------------------------------------------------- the drift */

/*
 * Ken Burns: the picture being shown grows, slowly, for exactly as long as it is
 * shown (the length is the slideshow's pace, worked out in PHP), and the next one
 * starts again from rest because `is-active` is a fresh class on a fresh element.
 * Every second slide drifts the other way, so two pictures in a row never make
 * the same move.
 *
 * On .airline-hero__media, not on the <img>, for two reasons that are the same
 * reason: this element is the one the parallax already transforms, and the turned
 * <img> inside it carries a transform of its own. `scale` is an individual
 * transform property, so it composes with both — GSAP's translate on this element
 * and the rotation one level down — instead of overwriting either. Scaling the
 * <img> would also have scaled its centring translate and drifted it off-centre.
 *
 * It only ever makes the picture bigger than its box, which is more headroom for
 * the parallax, never less.
 */
@keyframes airline-hero-drift {
	from {
		scale: 1;
	}
	to {
		scale: var(--airline-hero-zoom, 1.12);
	}
}

.airline-hero--drifts .airline-hero__slide.is-active .airline-hero__media {
	animation: airline-hero-drift var(--airline-hero-kenburns, 10800ms) linear both;
}

.airline-hero--drifts .airline-hero__slide:nth-child( even ).is-active .airline-hero__media {
	animation-direction: reverse;
}

/* -------------------------------------------------------- reduced motion */

@media ( prefers-reduced-motion: reduce ) {
	.airline-hero__slide,
	.airline-hero__slide.is-active,
	.airline-hero__step {
		transition: none;
	}

	.airline-hero--drifts .airline-hero__slide.is-active .airline-hero__media {
		animation: none;
	}

	/* The pictures still change when the arrows are pressed — they just do not
	   travel to do it. Autoplay is off entirely; see hero.js. */

	/* The parallax is the site's, not this plugin's, and it declines for itself —
	   but a transform left mid-scrub by a script that stopped is still a transform,
	   so the offset is taken back here as well. */
	.airline-hero__media {
		inset: 0;
	}
}

@media ( max-width: 600px ) {
	.airline-hero {
		--airline-hero-arrow-size: 2.5rem;
		--airline-hero-arrow-icon: 1.1rem;
	}

	.airline-hero__step--prev {
		left: 0.5rem;
	}

	.airline-hero__step--next {
		right: 0.5rem;
	}
}
