/*
 * The homepage keeps the older, larger section heading.
 *
 * The rest of the site stepped down to 24px when the page title came down to
 * 34, so that a heading still reads as smaller than the title above it. The
 * homepage has no 34px title to sit under — its headline is 64px and is the
 * composition rather than a label on it — so the argument for the smaller
 * heading does not apply here.
 *
 * Done by redefining the token rather than by listing the components: every
 * section heading on this page reads --sx-title-section, so one line covers
 * the problem block, the solutions block, the clients row, the testimonials
 * and the closing card, and it keeps covering anything added later.
 */
.home {
	--sx-title-section: clamp( 1.375rem, 1rem + 1.2vw, 1.75rem );
}

/* Scroll-reveal */

/*
 * Nothing is hidden unless the root says so.
 *
 * The hidden state used to be unconditional, which meant the page depended on
 * a script to become visible at all: if home-effects.js were blocked or failed
 * to load, every revealed section stayed at opacity 0 for good. The class on
 * <html> is set by a few inline lines in the head — early enough that nothing
 * flashes — and armed with a timer that takes it off again if the observer
 * never arrives. Content that cannot animate is content that is simply there.
 *
 * The delay is what turns a row of cards into a cascade rather than a single
 * pop: the script numbers the elements it reveals together, and each waits
 * 80ms longer than the one before it.
 */
html.sx-reveal-on .sx-reveal {
	opacity: 0;
	transform: translateY( 28px );
	transition: opacity 0.7s var( --sx-ease-reveal ), transform 0.7s var( --sx-ease-reveal );
	transition-delay: calc( var( --sx-reveal-i, 0 ) * 80ms );
}

html.sx-reveal-on .sx-reveal.is-visible {
	opacity: 1;
	transform: translateY( 0 );
}

@media ( prefers-reduced-motion: reduce ) {
	html.sx-reveal-on .sx-reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* Stats row: space-between only looks right on a full, unwrapped line — once it
   wraps on narrow screens, a leftover row of 1-2 items gets stretched to the
   edges with a big empty gap. Center everything once it's likely to wrap. */
@media ( max-width: 700px ) {
	.sx-stats-row {
		justify-content: center !important;
		row-gap: 2rem !important;
	}
}

/*
 * The homepage used to float a transparent header with a white logo over a
 * dark hero video. The hero is light now and the brief asks for one header
 * treatment site-wide, so that whole block is gone — every page gets the same
 * white sticky header.
 */

/* Hero — light, two columns, geometry on the right. */

.sx-hero {
	position: relative;
	/*
	 * The still version of the same ramp, under the moving layer. It is what
	 * shows if the pseudo-element never paints, so the hero is never bare.
	 */
	background: var( --sx-gradient-drift );
	/* The layer is three panels wider than this one and has to be cut off at
	   the edges; without this it paints across the rest of the page. */
	overflow: hidden;
	/* Keeps the layer's negative z-index inside this section rather than
	   letting it fall behind whatever is underneath. */
	isolation: isolate;
}

/*
 * The moving ground. Behind the words, above the section's own background.
 *
 * A pseudo-element rather than the section itself because what moves has to be
 * bigger than what shows — four panels wide, of which one is in view.
 */
.sx-hero::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	z-index: -1;
	width: 400%;
	height: 100%;
	background: var( --sx-gradient-drift );
	animation: sx-gradient-drift 8s ease infinite;
	will-change: transform;
	pointer-events: none;
}

/*
 * Still, and showing the end of the ramp it would have started from.
 *
 * Written here rather than beside the keyframes in tokens.css, which is loaded
 * first: both selectors are a single class, so whichever file comes later wins,
 * and a reduced-motion rule that loses is worse than none — it reads as
 * honoured and is not.
 */
@media ( prefers-reduced-motion: reduce ) {
	.sx-hero::before {
		animation: none;
		transform: none;
		/* Nothing left to promote, and a layer this size held on the
		   compositor for no reason is memory spent on nothing. */
		will-change: auto;
	}
}

.sx-hero__grid {
	display: grid;
	grid-template-columns: minmax( 0, 55fr ) minmax( 0, 45fr );
	align-items: center;
	gap: clamp( 32px, 5vw, 64px );
}

.sx-hero__copy > * {
	margin-block: 0;
}


.sx-hero__title {
	/* The brief caps the hero headline so it breaks into three lines rather
	   than running the full column width. */
	max-width: 650px;
	margin-block: 16px 24px;
	color: var( --sx-text );
	/*
	 * No font-size here on purpose. The homepage headline is the one heading on
	 * the site that is the composition rather than a label on it, and it keeps
	 * the 64px it was designed at: the stored heading carries
	 * has-xx-large-font-size, so leaving the size unset is what lets it through.
	 *
	 * The line height and tracking are written out because theme.json's h1 now
	 * carries the values that suit a 34px title, and at 64px they read loose.
	 * These two are the numbers this headline was drawn with.
	 */
	line-height: 1.05;
	letter-spacing: -0.028em;
}

.sx-hero__lead {
	max-width: 520px;
	color: var( --sx-text-secondary );
}

.sx-hero__actions {
	margin-top: 32px;
}

.sx-hero__cta-primary .wp-block-button__link {
	min-height: var( --sx-control-height-lg );
	padding-inline: 28px;
	font-size: 0.9375rem;
	border-radius: 10px;
}

/* Text button: the arrow slides on hover, nothing else moves. */
.sx-hero__more {
	margin-top: 16px;
}

.sx-hero__more a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var( --sx-neutral-800 );
	font-weight: 500;
	text-decoration: none;
}

.sx-hero__more a span {
	transition: transform var( --sx-transition-fast ) var( --sx-ease );
}

.sx-hero__more a:hover {
	color: var( --sx-brand-text );
}

.sx-hero__more a:hover span {
	transform: translateX( 4px );
}

.sx-hero__visual {
	justify-self: center;
	width: 100%;
	max-width: 520px;
}

.sx-hero__tiles {
	display: block;
	width: 100%;
	height: auto;
}

@media ( max-width: 1023px ) {
	/* Text first, then the buttons, then the graphic — the brief's mobile
	   order, applied from tablet down where the two columns stop fitting. */
	.sx-hero__grid {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-hero__visual {
		order: 2;
		max-width: 420px;
	}
}

/*
 * Two layers per plate on purpose. The idle drift lives on the inner group and
 * the hover lift on the outer one: a running animation wins over any static
 * transform on the same element, so keeping both on one <g> meant the hover
 * never showed.
 */
.sx-hero__tile,
.sx-hero__tile-float,
.sx-cta-tile,
.sx-cta-tile__float {
	transform-box: fill-box;
	transform-origin: center;
}

.sx-hero__tile,
.sx-cta-tile {
	transition: transform var( --sx-transition-base ) var( --sx-ease ),
		opacity var( --sx-transition-base ) var( --sx-ease );
}

/* Hovering one plate dims the others so the pointed-at one comes forward. */
.sx-hero__tiles:hover .sx-hero__tile,
.sx-cta-tiles:hover .sx-cta-tile {
	opacity: 0.7;
}

.sx-hero__tile:hover,
.sx-cta-tile:hover {
	transform: translateY( -6px ) scale( 1.03 );
	opacity: 1 !important;
}

/* A very slow drift, staggered per plate so the group breathes instead of
   pulsing in unison. Well inside the brief's 5–10px cap. */
@keyframes sx-tile-float {
	from { transform: translateY( 0 ); }
	to   { transform: translateY( -7px ); }
}

.sx-hero__tile-float,
.sx-cta-tile__float {
	animation: sx-tile-float 5s calc( var( --sx-tile-i, 0 ) * 0.6s ) ease-in-out infinite alternate;
}

.sx-hero__tile:hover .sx-hero__tile-float,
.sx-cta-tile:hover .sx-cta-tile__float {
	animation-play-state: paused;
}

@media ( prefers-reduced-motion: reduce ) {
	.sx-hero__tile-float,
	.sx-cta-tile__float {
		animation: none;
	}

	.sx-hero__tile,
	.sx-cta-tile {
		transition: none;
	}

	.sx-hero__tile:hover,
	.sx-cta-tile:hover {
		transform: none;
	}

	.sx-hero__tiles:hover .sx-hero__tile,
	.sx-cta-tiles:hover .sx-cta-tile {
		opacity: inherit;
	}
}

