/*
Theme Name: Kadence Child - Elite Digital Services
Theme URI: http://elite-digital-services.local
Description: Child theme for Elite Digital Services. Dark, premium design system for the AI / digital services brand. Colors, typography, container widths and header/footer structure are configured in the Customizer; everything the Customizer cannot express lives here.
Author: Elite Digital Services
Template: kadence
Version: 2.35.0
Text Domain: kadence-child
*/

/* ==========================================================================
   1. Tokens
   Kadence owns --global-palette1..9 (Customizer > Colors). On this site:
     palette1 accent      #4D93FF     palette6 muted text  #7F92AD
     palette2 accent hover#6FA7FF     palette7 raised bg   #0C1526
     palette3 headings    #F4F7FB     palette8 panel bg    #101A2D
     palette4 strong text #E6EDF7     palette9 site bg     #070C16
     palette5 body text   #B4C0D3
   ========================================================================== */

:root {
	--eds-bg: #070C16;
	--eds-bg-2: #0B1220;
	--eds-bg-3: #0F1A2E;
	--eds-ink: #0B1220;

	--eds-accent: #4D93FF;
	--eds-accent-2: #38C6F4;   /* cyan hint, used sparingly */
	--eds-accent-3: #7B8CFF;   /* indigo hint, gradients only */
	--eds-accent-deep: #2563EB;
	--eds-accent-on-dark: var(--eds-accent);
	--eds-accent-soft: rgba(77, 147, 255, .12);

	/*
	 * The divider blue, as components so the pieces that ride the cut — the
	 * service cards, the process cards, the cursor follower — can build their
	 * border, fill and glow from the same value at whatever alpha they need.
	 * rgb(77, 147, 255) is #4D93FF, the palette accent.
	 */
	--eds-tilt-blue-rgb: 77, 147, 255;
	--eds-tilt-blue: rgb(var(--eds-tilt-blue-rgb));
	--eds-tilt-fill: linear-gradient(90deg, #38C6F4 0%, var(--eds-tilt-blue) 55%, #2563EB 100%);

	--eds-text-strong: #F4F7FB;
	--eds-text-on-dark: #B4C0D3;
	--eds-text-on-dark-muted: #7F92AD;

	--eds-line: rgba(255, 255, 255, .07);
	--eds-line-strong: rgba(255, 255, 255, .12);
	--eds-line-accent: rgba(77, 147, 255, .45);
	--eds-border-dark: #24344F;

	/* Glass surfaces. */
	--eds-glass: linear-gradient(180deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .025));
	--eds-glass-hover: linear-gradient(180deg, rgba(255, 255, 255, .075), rgba(255, 255, 255, .035));
	--eds-glass-soft: linear-gradient(180deg, rgba(255, 255, 255, .03), rgba(255, 255, 255, .012));

	/* Spacing scale: 4px base, 8px rhythm. */
	--eds-s1: 4px;
	--eds-s2: 8px;
	--eds-s3: 12px;
	--eds-s4: 16px;
	--eds-s5: 24px;
	--eds-s6: 32px;
	--eds-s7: 48px;
	--eds-s8: 64px;
	--eds-s9: 80px;
	--eds-s10: 96px;
	--eds-s11: 128px;
	--eds-s12: 160px;

	--eds-radius-card: 16px;
	--eds-radius-panel: 20px;
	--eds-radius-tile: 12px;

	--eds-shadow-card:
		0 1px 0 0 rgba(255, 255, 255, .04) inset,
		0 12px 32px -16px rgba(0, 0, 0, .6);
	--eds-shadow-card-hover:
		0 1px 0 0 rgba(255, 255, 255, .06) inset,
		0 0 0 1px rgba(77, 147, 255, .18),
		0 24px 56px -24px rgba(77, 147, 255, .35),
		0 24px 48px -20px rgba(0, 0, 0, .7);
	--eds-shadow-btn:
		0 1px 0 0 rgba(255, 255, 255, .18) inset,
		0 8px 24px -8px rgba(37, 99, 235, .55);
	--eds-shadow-btn-hover:
		0 1px 0 0 rgba(255, 255, 255, .22) inset,
		0 0 0 1px rgba(77, 147, 255, .35),
		0 14px 36px -10px rgba(77, 147, 255, .65);

	--eds-ease: cubic-bezier(.2, 0, 0, 1);
	--eds-ease-out: cubic-bezier(.22, 1, .36, 1);
	--eds-dur-color: 140ms;
	--eds-dur-btn: 200ms;
	--eds-dur-card: 260ms;
	--eds-dur-enter: 640ms;

	/* Visual layer: every authored SVG scene draws from these tokens only. */
	--eds-viz-frame: rgba(255, 255, 255, .13);
	--eds-viz-panel: rgba(255, 255, 255, .045);
	--eds-viz-surface: rgba(255, 255, 255, .03);
	--eds-viz-bar: rgba(255, 255, 255, .12);
	--eds-viz-bar-2: rgba(255, 255, 255, .26);
	--eds-viz-accent: #4D93FF;
	--eds-viz-accent-soft: rgba(77, 147, 255, .18);
	--eds-viz-cyan: #38C6F4;

	/* Section rhythm: 128 / 80 / 48. */
	--eds-section-y: var(--eds-s11);
	--eds-section-head-gap: 72px;
	--eds-grid-gap: var(--eds-s6) var(--eds-s6);
}

@media (max-width: 1024px) {
	:root {
		--eds-section-y: var(--eds-s9);
		--eds-section-head-gap: var(--eds-s7);
		--eds-grid-gap: var(--eds-s5);
	}
}

@media (max-width: 767px) {
	:root {
		--eds-section-y: var(--eds-s8);
		--eds-section-head-gap: 40px;
		--eds-grid-gap: var(--eds-s4);
	}
}

/* ==========================================================================
   2. Base
   ========================================================================== */

html {
	background-color: var(--eds-bg);
}

body {
	background-color: var(--eds-bg);
	color: var(--eds-text-on-dark);
	-webkit-font-smoothing: antialiased;
}

::selection {
	background-color: rgba(77, 147, 255, .35);
	color: #FFFFFF;
}

/*
 * Ambient page glow. One fixed pseudo-layer behind everything: a soft accent
 * bloom top-left and an indigo one bottom-right. It is what stops the long
 * dark pages reading as one flat slab. Fixed-position, no scroll repaint.
 */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-image:
		radial-gradient(60% 45% at 8% 0%, rgba(77, 147, 255, .09), transparent 60%),
		radial-gradient(50% 40% at 100% 100%, rgba(123, 140, 255, .07), transparent 60%);
}

.entry-content h1,
.entry-content h2,
.entry-content h3,
.eds-hero__title,
.eds-section__head h2 {
	text-wrap: balance;
	color: var(--eds-text-strong);
}

.entry-content p,
.eds-lead,
.eds-section__intro {
	text-wrap: pretty;
}

.eds-hero__title {
	letter-spacing: -.03em;
}

/* Kadence sets .entry-content{word-break:break-word}, which lets a flex column
   shrink narrower than its longest word and split it mid-character. */
.entry-content,
.entry-content h1,
.entry-content h2,
.entry-content h3,
.entry-content h4,
.entry-content h5,
.entry-content h6,
.entry-content p,
.entry-content li,
.entry-content a {
	word-break: normal;
	overflow-wrap: break-word;
	hyphens: manual;
}

.entry-content a:not(.wp-element-button):not(.wp-block-button__link):not(.eds-link) {
	color: var(--eds-accent);
	text-decoration-color: rgba(77, 147, 255, .4);
	text-underline-offset: 3px;
	transition: color var(--eds-dur-color) var(--eds-ease), text-decoration-color var(--eds-dur-color) var(--eds-ease);
}

.entry-content a:not(.wp-element-button):not(.wp-block-button__link):not(.eds-link):hover {
	color: #FFFFFF;
	text-decoration-color: currentColor;
}

/* The homepage opens on a full-bleed hero and closes on a full-bleed CTA. */
.home .content-area,
.page .content-area {
	margin-top: 0;
	margin-bottom: 0;
}

/* ==========================================================================
   3. Sections
   ========================================================================== */

.eds-section {
	position: relative;
	padding-top: var(--eds-section-y);
	padding-bottom: var(--eds-section-y);
}

/* Full-bleed sections keep their background edge to edge; the inner container
   matches the 1200px box the header and footer use. */
.eds-section > .wp-block-group__inner-container {
	position: relative;
	max-width: var(--global-content-width);
	margin: 0 auto;
	padding-left: var(--global-content-edge-padding);
	padding-right: var(--global-content-edge-padding);
}

/* Hairline between sections: gradient so it fades at both edges. */
.eds-section + .eds-section::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 1px;
	pointer-events: none;
	background-image: linear-gradient(to right, transparent, var(--eds-line-strong) 25%, var(--eds-line-strong) 75%, transparent);
}

/* Raised band: a step lighter, with a faint 64px grid that only shows near the
   top edge so it reads as texture rather than a pattern. */
.eds-section--tint {
	background-color: var(--eds-bg-2);
	background-image:
		linear-gradient(to bottom, rgba(7, 12, 22, 0) 0%, rgba(7, 12, 22, .55) 100%),
		linear-gradient(to right, rgba(255, 255, 255, .028) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .028) 1px, transparent 1px);
	background-size: 100% 100%, 64px 64px, 64px 64px;
}

/*
 * Hero bands (dark): deepest surface, two wide accent glows, a 72px technical
 * grid that fades out towards the bottom, and a hairline foot.
 */
.eds-section--dark {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	background-color: var(--eds-bg);
	color: var(--eds-text-on-dark);
}

.eds-section--dark::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-image:
		radial-gradient(55% 70% at 14% 0%, rgba(77, 147, 255, .18), transparent 62%),
		radial-gradient(40% 55% at 92% 100%, rgba(123, 140, 255, .14), transparent 66%),
		radial-gradient(30% 40% at 70% 20%, rgba(56, 198, 244, .07), transparent 70%),
		linear-gradient(to right, rgba(255, 255, 255, .035) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .035) 1px, transparent 1px);
	background-size: 100% 100%, 100% 100%, 100% 100%, 72px 72px, 72px 72px;
	-webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
	mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
}

.eds-section--dark::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 1px;
	pointer-events: none;
	background-image: linear-gradient(to right, transparent, rgba(77, 147, 255, .35) 30%, rgba(77, 147, 255, .35) 70%, transparent);
}

/* Node-network canvas, injected by motion.js into the homepage and AI heroes. */
.eds-net {
	position: absolute;
	inset: 0;
	z-index: -1;
	width: 100%;
	height: 100%;
	pointer-events: none;
	opacity: .9;
	/*
	 * The mask is what decides how much of the hero the network actually
	 * reaches. Widened and re-centred so the field carries further left and
	 * further down — more of the section is alive — while still going to
	 * nothing at every edge. It stays weighted right of centre, over the
	 * figure rather than over the headline, which is what keeps the copy
	 * reading against flat navy.
	 */
	-webkit-mask-image: radial-gradient(95% 105% at 56% 42%, #000 38%, transparent 100%);
	mask-image: radial-gradient(95% 105% at 56% 42%, #000 38%, transparent 100%);
}

/* ==========================================================================
   4. Type utilities
   ========================================================================== */

.eds-eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 var(--eds-s4);
	font-size: 12.5px;
	font-weight: 600;
	line-height: 1.4;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--eds-accent);
}

.eds-eyebrow::before {
	content: "";
	width: 22px;
	height: 1px;
	background-image: linear-gradient(to right, var(--eds-accent), var(--eds-accent-2));
	opacity: .9;
}

.eds-section:not(.eds-section--dark) .eds-section__head--center .eds-eyebrow::before,
.eds-cta__panel .eds-eyebrow::before {
	display: none;
}

/* Heroes upgrade the eyebrow to a glass status pill with a live dot. */
.eds-section--dark .eds-eyebrow {
	gap: 9px;
	padding: 8px 16px 8px 13px;
	border: 1px solid rgba(255, 255, 255, .12);
	border-radius: 999px;
	background-color: rgba(255, 255, 255, .04);
	box-shadow: 0 1px 0 0 rgba(255, 255, 255, .05) inset, 0 8px 24px -12px rgba(0, 0, 0, .8);
	color: #DCE6F5;
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
}

.eds-section--dark .eds-eyebrow::before {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background-image: none;
	background-color: var(--eds-accent);
	box-shadow: 0 0 0 3px rgba(77, 147, 255, .2), 0 0 12px rgba(77, 147, 255, .8);
	opacity: 1;
}

/* Inside a flex column the pill must not stretch to the column width. */
.wp-block-column > .eds-eyebrow {
	align-self: flex-start;
}

.eds-lead {
	font-size: 20px;
	line-height: 1.6;
	max-width: 56ch;
	margin: 0 0 var(--eds-s6);
	color: var(--eds-text-on-dark);
}

@media (max-width: 767px) {
	.eds-lead {
		font-size: 18px;
	}
}

.eds-section__head {
	margin-bottom: var(--eds-section-head-gap);
}

.eds-section__head h2 {
	margin: 0 0 var(--eds-s4);
	max-width: 22ch;
}

.eds-section__head .eds-section__intro {
	margin: 0;
	max-width: 58ch;
	font-size: 18px;
	color: var(--eds-text-on-dark-muted);
}

.eds-section__head--center {
	text-align: center;
}

.eds-section__head--center h2,
.eds-section__head--center .eds-section__intro {
	margin-left: auto;
	margin-right: auto;
}

/* ==========================================================================
   5. Hero
   ========================================================================== */

/*
 * Measured, not guessed. The sticky header is 89px, so padding-top is the only
 * thing between it and the top of the composition: at 176 that left an 87px
 * band of nothing, which is wider than the pill is tall. 136 brings it to 47px
 * — still clear of the header by more than a pill's height, and no longer the
 * first thing the eye lands on.
 *
 * It cannot go below --eds-narrative-top (110px) without the pill starting
 * above the line it sticks at, which would have it jump up on first scroll
 * rather than travel. 136 keeps 26px of travel before it parks.
 *
 * padding-top is also the line the narrative pill starts on. --eds-narrative-
 * start in section 19 mirrors all three values and has to move with them, or
 * the pill stops sitting level with the eyebrow it replaces.
 */
.eds-hero {
	padding-top: 136px;
	padding-bottom: var(--eds-s8);
}

@media (max-width: 1024px) {
	.eds-hero {
		padding-top: 124px;
		padding-bottom: var(--eds-s7);
	}
}

@media (max-width: 767px) {
	.eds-hero {
		padding-top: 104px;
		padding-bottom: var(--eds-s7);
	}
}

/*
 * The gap between the pill and the headline was 128px: 32px off the foot of
 * the eyebrow the pill sits on, and 96px of margin-top on the h1 — which is
 * Kadence's heading rhythm resolving 1.5em against a 64px hero headline. That
 * rhythm is right for a heading that follows body copy and wrong for one that
 * follows its own eyebrow, so it comes off here and the eyebrow's own 32px is
 * left to do the spacing. The pill now reads as part of the headline block.
 *
 * Scoped to the hero title, so headings everywhere else keep the rhythm.
 */
.entry-content .eds-hero .eds-hero__title {
	margin-top: 0;
}

/* Large headings: white with a cool sheen towards the bottom. Subtle enough
   to read as paper-white, rich enough to feel lit. */
.eds-hero__title,
.eds-page-hero h1 {
	background-image: linear-gradient(180deg, #FFFFFF 0%, #FFFFFF 55%, #B9CDEE 130%);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: #FFFFFF;
}

.eds-hero__title {
	max-width: 16ch;
	margin: 0 0 var(--eds-s5);
	font-size: clamp(40px, 4.5vw, 64px);
	line-height: 1.04;
}

.eds-hero__capabilities {
	margin: 40px 0 0;
	font-size: 15px;
	color: var(--eds-text-on-dark-muted);
}

/* Capability chips under the hero CTA. */
.entry-content .eds-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin: 44px 0 0;
	padding: 0;
	padding-inline-start: 0;
	list-style: none;
}

.eds-chips li {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 8px 14px;
	border: 1px solid var(--eds-line);
	border-radius: 999px;
	background-color: rgba(255, 255, 255, .03);
	font-size: 13.5px;
	font-weight: 500;
	color: var(--eds-text-on-dark);
	transition: border-color var(--eds-dur-color) var(--eds-ease), background-color var(--eds-dur-color) var(--eds-ease);
}

.eds-chips li::before {
	content: "";
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background-color: var(--eds-accent);
	box-shadow: 0 0 8px rgba(77, 147, 255, .9);
}

.eds-chips li:hover {
	border-color: var(--eds-line-accent);
	background-color: rgba(77, 147, 255, .07);
}

/*
 * One horizontal row in the hero.
 *
 * Measured at 1440: the four pills come to 614.8px including their gaps, and
 * the copy column is 586.7px. 28px short — which is why the fourth one kept
 * dropping, and why widening the column by a ratio nudge was never going to be
 * reliable: a column wide enough in English is not wide enough in German.
 *
 * So the row stops being bound by the column instead. `width: max-content`
 * sizes it to whatever one line of pills actually needs and lets it run on to
 * the right, past the paragraph's measure and under the figure. Nothing is in
 * the way there: at 1440 the figure ends 300px above where this row starts, so
 * the space it grows into is empty in every language.
 *
 * The left edge is untouched, so the row still lines up with the headline, the
 * copy and the buttons above it — which is the alignment that actually reads.
 */
.entry-content .eds-hero .eds-chips {
	gap: var(--eds-s2);

	/* 44px was set for a wrapped two-row block. One row needs less above it,
	   and this is the dead space the hero can most afford to lose. */
	margin-top: var(--eds-s6);
}

@media (min-width: 1025px) {
	.entry-content .eds-hero .eds-chips {
		flex-wrap: nowrap;
		width: max-content;
		max-width: none;
	}
}

/* Inner-page hero. Sits below a solid dark header, so ordinary padding. */
.eds-page-hero {
	padding-top: var(--eds-s10);
	padding-bottom: var(--eds-s10);
}

@media (max-width: 1024px) {
	.eds-page-hero {
		padding-top: var(--eds-s9);
		padding-bottom: var(--eds-s9);
	}
}

@media (max-width: 767px) {
	.eds-page-hero {
		padding-top: var(--eds-s7);
		padding-bottom: var(--eds-s7);
	}
}

.eds-page-hero h1 {
	max-width: 20ch;
	margin: 0 0 var(--eds-s5);
	font-size: clamp(34px, 4vw, 56px);
	line-height: 1.06;
}

.eds-page-hero .eds-lead {
	max-width: 60ch;
}

/* Hero figures float on an accent halo. */
.eds-hero .eds-figure,
.eds-page-hero .eds-figure {
	position: relative;
}

.eds-hero .wp-block-column:has(> .eds-figure),
.eds-page-hero .wp-block-column:has(> .eds-figure) {
	position: relative;
}

.eds-hero .wp-block-column:has(> .eds-figure)::before,
.eds-page-hero .wp-block-column:has(> .eds-figure)::before {
	content: "";
	position: absolute;
	inset: -12% -8%;
	z-index: -1;
	pointer-events: none;
	background-image: radial-gradient(50% 50% at 50% 50%, rgba(77, 147, 255, .22), transparent 70%);
	filter: blur(20px);
}

/* ==========================================================================
   6. Buttons and links
   ========================================================================== */

.wp-block-button__link,
.wp-element-button,
.button {
	position: relative;
	overflow: hidden;
	background-image: linear-gradient(180deg, #4D93FF 0%, #2563EB 100%);
	box-shadow: var(--eds-shadow-btn);
	letter-spacing: .005em;
	transition:
		background-color var(--eds-dur-btn) var(--eds-ease),
		border-color var(--eds-dur-btn) var(--eds-ease),
		color var(--eds-dur-color) var(--eds-ease),
		transform var(--eds-dur-btn) var(--eds-ease),
		box-shadow var(--eds-dur-btn) var(--eds-ease);
}

/* Light sweep across the primary button on hover. */
.wp-block-button__link::before,
.wp-element-button::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: -60%;
	width: 40%;
	background-image: linear-gradient(100deg, transparent, rgba(255, 255, 255, .28), transparent);
	transform: skewX(-18deg);
	transition: left 520ms var(--eds-ease);
	pointer-events: none;
}

.wp-block-button__link:hover::before,
.wp-element-button:hover::before {
	left: 130%;
}

.wp-block-button__link:hover,
.wp-element-button:hover,
.button:hover {
	transform: translateY(-2px);
	box-shadow: var(--eds-shadow-btn-hover);
}

.wp-block-button__link:active,
.wp-element-button:active,
.button:active {
	transform: translateY(0);
	box-shadow: var(--eds-shadow-btn);
}

/* Secondary: glass outline. Label is at full contrast at rest. */
.eds-btn-secondary > .wp-block-button__link,
.eds-btn-secondary > .wp-element-button {
	color: #FFFFFF;
	background-color: rgba(255, 255, 255, .04);
	background-image: none;
	border: 1px solid rgba(255, 255, 255, .22);
	box-shadow: 0 1px 0 0 rgba(255, 255, 255, .06) inset;
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
}

.eds-btn-secondary > .wp-block-button__link::before,
.eds-btn-secondary > .wp-element-button::before {
	display: none;
}

.eds-btn-secondary > .wp-block-button__link:hover,
.eds-btn-secondary > .wp-block-button__link:focus,
.eds-btn-secondary > .wp-element-button:hover,
.eds-btn-secondary > .wp-element-button:focus {
	color: #FFFFFF;
	background-color: rgba(77, 147, 255, .10);
	border-color: rgba(77, 147, 255, .6);
	box-shadow: 0 1px 0 0 rgba(255, 255, 255, .08) inset, 0 0 0 1px rgba(77, 147, 255, .2), 0 12px 32px -14px rgba(77, 147, 255, .5);
}

.eds-hero .wp-block-buttons,
.eds-page-hero .wp-block-buttons {
	gap: var(--eds-s4);
}

/* Text link with arrow. */
.eds-link {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	font-weight: 600;
	font-size: 15px;
	text-decoration: none;
	color: var(--eds-accent);
	transition: color var(--eds-dur-color) var(--eds-ease);
}

.eds-link::after {
	content: "\2192";
	display: inline-block;
	transition: transform var(--eds-dur-btn) var(--eds-ease);
}

.eds-link:hover,
.eds-link:focus {
	color: #FFFFFF;
	text-decoration: none;
}

.eds-link:hover::after,
.eds-link:focus::after {
	transform: translateX(5px);
}

/* ==========================================================================
   7. Cards
   Glass panels. Flex (not height:100%) so a card after a figure fills only the
   remainder of its column and never overflows the row.
   ========================================================================== */

.eds-card {
	position: relative;
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	padding: 36px;
	background-image: var(--eds-glass);
	border: 1px solid var(--eds-line);
	border-radius: var(--eds-radius-card);
	box-shadow: var(--eds-shadow-card);
	transition:
		transform var(--eds-dur-card) var(--eds-ease),
		box-shadow var(--eds-dur-card) var(--eds-ease),
		border-color var(--eds-dur-card) var(--eds-ease),
		background-image var(--eds-dur-card) var(--eds-ease);
}

@media (max-width: 767px) {
	.eds-card {
		padding: var(--eds-s5);
	}
}

/* Pointer spotlight: --mx/--my are set by motion.js on pointermove. */
.eds-card::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	background-image: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), rgba(77, 147, 255, .13), transparent 60%);
	opacity: 0;
	transition: opacity var(--eds-dur-card) var(--eds-ease);
}

.eds-card:hover::before,
.eds-card:focus-within::before {
	opacity: 1;
}

.eds-card:hover,
.eds-card:focus-within {
	transform: translateY(-4px);
	border-color: var(--eds-line-accent);
	box-shadow: var(--eds-shadow-card-hover);
}

/* Accent hairline along the top edge, revealed on hover. */
.eds-card::after {
	content: "";
	position: absolute;
	top: -1px;
	left: 24px;
	right: 24px;
	height: 1px;
	background-image: linear-gradient(to right, transparent, var(--eds-accent), var(--eds-accent-2), transparent);
	opacity: 0;
	transition: opacity var(--eds-dur-card) var(--eds-ease);
}

.eds-card:hover::after,
.eds-card:focus-within::after {
	opacity: .9;
}

.eds-card__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 52px;
	height: 52px;
	margin: 0 0 var(--eds-s5);
	border-radius: var(--eds-radius-tile);
	background-image: linear-gradient(145deg, rgba(77, 147, 255, .22) 0%, rgba(77, 147, 255, .06) 100%);
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .28), 0 1px 0 0 rgba(255, 255, 255, .08) inset;
	color: #9CC3FF;
	transition:
		box-shadow var(--eds-dur-card) var(--eds-ease),
		transform var(--eds-dur-card) var(--eds-ease),
		color var(--eds-dur-card) var(--eds-ease);
}

.eds-card:hover .eds-card__icon {
	color: #FFFFFF;
	transform: translateY(-2px);
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .6), 0 10px 24px -10px rgba(77, 147, 255, .7);
}

.eds-card__icon svg {
	display: block;
	width: 24px;
	height: 24px;
}

/* Gutenberg's inner container sits between the card and its content; re-establish
   the flex column at both levels so CTAs pin to the bottom. */
.eds-card > .wp-block-group__inner-container,
.eds-card__body > .wp-block-group__inner-container {
	position: relative;
	display: flex;
	flex: 1;
	flex-direction: column;
}

.eds-card--media .eds-card__body {
	flex: 1;
}

.eds-card > *:first-child {
	margin-top: 0;
}

.eds-card h3 {
	margin: 0 0 var(--eds-s3);
	font-size: 24px;
	color: var(--eds-text-strong);
}

.eds-card p {
	margin: 0 0 var(--eds-s5);
	font-size: 16px;
	color: var(--eds-text-on-dark);
}

.eds-card p:last-child {
	margin-bottom: 0;
}

.eds-card .eds-card__cta {
	margin: auto 0 0;
	padding-top: var(--eds-s2);
}

/*
 * Feature tile: an icon card rendered as a lighter row (icon left, copy right)
 * rather than a stacked box. Applied automatically to any card that carries an
 * icon, which is exactly the set that was producing "too many frames" when six
 * of them sat in a grid.
 */
.eds-card:has(.eds-card__icon) {
	padding: 28px 30px;
	background-image: var(--eds-glass-soft);
}

.eds-card:has(.eds-card__icon) > .wp-block-group__inner-container {
	display: grid;
	grid-template-columns: 52px minmax(0, 1fr);
	column-gap: 22px;
	align-content: start;
}

.eds-card:has(.eds-card__icon) .eds-card__icon {
	grid-row: 1 / span 6;
	margin: 0;
}

.eds-card:has(.eds-card__icon) h3 {
	margin-top: 10px;
	font-size: 21px;
}

.eds-card:has(.eds-card__icon) p {
	font-size: 15.5px;
	color: var(--eds-text-on-dark-muted);
}

@media (max-width: 480px) {
	.eds-card:has(.eds-card__icon) > .wp-block-group__inner-container {
		grid-template-columns: minmax(0, 1fr);
	}

	.eds-card:has(.eds-card__icon) .eds-card__icon {
		grid-row: auto;
		margin-bottom: var(--eds-s4);
	}
}

/* --- card with a visual header ------------------------------------------ */

.eds-card--media {
	padding: 0;
	overflow: hidden;
}

.eds-card__media {
	position: relative;
	display: block;
	border-bottom: 1px solid var(--eds-line);
	background-color: rgba(7, 12, 22, .5);
	background-image:
		radial-gradient(60% 80% at 50% 110%, rgba(77, 147, 255, .16), transparent 70%),
		linear-gradient(to right, rgba(255, 255, 255, .03) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .03) 1px, transparent 1px);
	background-size: 100% 100%, 32px 32px, 32px 32px;
}

.eds-card__media > svg,
.eds-card__media > img {
	display: block;
	width: 100%;
	height: auto;
	transition: transform 600ms var(--eds-ease-out);
}

.eds-card--media:hover .eds-card__media > svg,
.eds-card--media:hover .eds-card__media > img {
	transform: translateY(-4px) scale(1.015);
}

.eds-card--media .eds-card__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	padding: 32px 36px 36px;
}

@media (max-width: 767px) {
	.eds-card--media .eds-card__body {
		padding: var(--eds-s5);
	}
}

.eds-card--media::after {
	display: none;
}

/* ==========================================================================
   8. Lists, placeholders, media slots
   ========================================================================== */

.eds-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.eds-list li {
	position: relative;
	margin: 0 0 var(--eds-s3);
	padding-left: 30px;
	font-size: 16px;
	color: var(--eds-text-on-dark);
}

.eds-list li::before {
	content: "";
	position: absolute;
	top: .55em;
	left: 0;
	width: 16px;
	height: 16px;
	border-radius: 50%;
	background-color: rgba(77, 147, 255, .12);
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .4);
}

.eds-list li::after {
	content: "";
	position: absolute;
	top: calc(.55em + 5px);
	left: 5px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background-color: var(--eds-accent);
	box-shadow: 0 0 8px rgba(77, 147, 255, .8);
}

.eds-list li:last-child {
	margin-bottom: 0;
}

/* Placeholder: a region still waiting on a form or contact details. Reads as
   a deliberate, premium "reserved" panel rather than a broken one. */
.eds-placeholder {
	position: relative;
	overflow: hidden;
	padding: var(--eds-s7) var(--eds-s6);
	border: 1px solid var(--eds-line);
	border-radius: var(--eds-radius-panel);
	background-image:
		radial-gradient(50% 60% at 50% 0%, rgba(77, 147, 255, .12), transparent 70%),
		var(--eds-glass-soft);
	text-align: center;
}

.eds-placeholder::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image:
		linear-gradient(to right, rgba(255, 255, 255, .03) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .03) 1px, transparent 1px);
	background-size: 40px 40px;
	-webkit-mask-image: radial-gradient(60% 80% at 50% 0%, #000, transparent);
	mask-image: radial-gradient(60% 80% at 50% 0%, #000, transparent);
}

.eds-placeholder > .wp-block-group__inner-container {
	position: relative;
	max-width: 60ch;
	margin: 0 auto;
}

.eds-placeholder__label {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 var(--eds-s4);
	padding: 6px 14px;
	border: 1px solid rgba(77, 147, 255, .3);
	border-radius: 999px;
	background-color: rgba(77, 147, 255, .08);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: #9CC3FF;
}

.eds-placeholder p {
	color: var(--eds-text-on-dark-muted);
}

.eds-placeholder p:last-child {
	margin-bottom: 0;
}

/* Media slot: a reserved frame for a real screenshot. */
.eds-media-slot {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
	overflow: hidden;
	aspect-ratio: 16 / 10;
	padding: var(--eds-s5);
	border: 1px solid var(--eds-line);
	border-radius: var(--eds-radius-panel);
	background-image:
		radial-gradient(70% 70% at 50% 120%, rgba(77, 147, 255, .18), transparent 65%),
		var(--eds-glass-soft);
	text-align: center;
	transition: border-color var(--eds-dur-card) var(--eds-ease), box-shadow var(--eds-dur-card) var(--eds-ease);
}

.eds-media-slot::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image:
		linear-gradient(to right, rgba(255, 255, 255, .035) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .035) 1px, transparent 1px);
	background-size: 36px 36px;
	-webkit-mask-image: radial-gradient(70% 70% at 50% 50%, #000 20%, transparent 100%);
	mask-image: radial-gradient(70% 70% at 50% 50%, #000 20%, transparent 100%);
}

/* An abstract browser frame drawn in CSS, so the slot looks like a mockup
   waiting for content rather than an empty box. */
.eds-media-slot::after {
	content: "";
	position: absolute;
	left: 12%;
	right: 12%;
	top: 16%;
	bottom: -6%;
	border: 1px solid rgba(255, 255, 255, .1);
	border-bottom: 0;
	border-radius: 12px 12px 0 0;
	background-image:
		linear-gradient(to bottom, rgba(255, 255, 255, .05) 0, rgba(255, 255, 255, .05) 28px, transparent 28px),
		linear-gradient(180deg, rgba(255, 255, 255, .02), rgba(255, 255, 255, 0));
	pointer-events: none;
}

.eds-media-slot:hover {
	border-color: var(--eds-line-accent);
	box-shadow: 0 0 0 1px rgba(77, 147, 255, .12), 0 24px 48px -24px rgba(77, 147, 255, .35);
}

.eds-media-slot__role,
.eds-media-slot__spec {
	position: relative;
	z-index: 1;
}

.eds-media-slot__role {
	margin: 0;
	padding: 6px 14px;
	border: 1px solid rgba(255, 255, 255, .12);
	border-radius: 999px;
	background-color: rgba(7, 12, 22, .7);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--eds-text-strong);
}

.eds-media-slot__spec {
	margin: 0;
	max-width: 34ch;
	font-size: 12.5px;
	line-height: 1.5;
	color: var(--eds-text-on-dark-muted);
}

/* ==========================================================================
   9. Figures
   ========================================================================== */

.eds-figure {
	position: relative;
	margin: 0;
	overflow: hidden;
	border: 1px solid var(--eds-line-strong);
	border-radius: var(--eds-radius-panel);
	background-color: rgba(11, 18, 32, .7);
	background-image:
		radial-gradient(70% 60% at 50% 110%, rgba(77, 147, 255, .14), transparent 70%),
		linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, .012));
	box-shadow:
		0 1px 0 0 rgba(255, 255, 255, .08) inset,
		0 2px 6px rgba(0, 0, 0, .35),
		0 40px 80px -32px rgba(0, 0, 0, .8);
	/*
	 * Near-opaque, not glass: anything that holds its place in the viewport
	 * passes over the copy scrolling under it, and at the hero eyebrow's .04
	 * white the body text read straight through the pill. The blur only has to
	 * soften what little shows at the edges now.
	 */
	-webkit-backdrop-filter: blur(12px);
	backdrop-filter: blur(12px);
	transform-style: preserve-3d;
	will-change: transform;
}

.eds-figure > svg,
.eds-figure > img {
	display: block;
	width: 100%;
	height: auto;
}

.eds-figure__caption {
	margin: 0;
	padding: 14px 20px;
	border-top: 1px solid var(--eds-line);
	background-color: rgba(255, 255, 255, .025);
	font-size: 13px;
	color: var(--eds-text-on-dark-muted);
}

/* Columns are flex containers so children distribute the column's height. */
.eds-cols-2 > .wp-block-column,
.eds-cols-3 > .wp-block-column,
.eds-cols-4 > .wp-block-column {
	display: flex;
	flex-direction: column;
}

.eds-figure,
.eds-media-slot {
	flex: 0 0 auto;
}

/* Stacked figure + card in one column: give them air. */
.wp-block-column > .eds-figure + .eds-card {
	margin-top: var(--eds-s5);
}

.eds-align-center > .wp-block-column,
.eds-cols-2:has(> .wp-block-column > .eds-eyebrow) > .wp-block-column {
	align-self: center;
}

/* Full-width figure (AI workflow band). */
.eds-figure--wide {
	max-width: 1040px;
	margin: 0 auto;
}

/* ==========================================================================
   10. Reasons, process, CTA
   ========================================================================== */

.eds-reason {
	position: relative;
	padding: 22px 0 22px 64px;
	border-top: 1px solid var(--eds-line);
	counter-increment: eds-reason;
}

.eds-reason:last-child {
	border-bottom: 1px solid var(--eds-line);
}

.eds-reason + .eds-reason {
	margin-top: 0;
}

.eds-reason::before {
	content: counter(eds-reason, decimal-leading-zero);
	position: absolute;
	top: 24px;
	left: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 12px;
	background-image: linear-gradient(145deg, rgba(77, 147, 255, .2), rgba(77, 147, 255, .05));
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .3);
	font-family: var(--global-heading-font-family);
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .06em;
	color: #9CC3FF;
	transition: box-shadow var(--eds-dur-card) var(--eds-ease), color var(--eds-dur-card) var(--eds-ease);
}

.eds-reason:hover::before {
	color: #FFFFFF;
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .6), 0 8px 20px -10px rgba(77, 147, 255, .8);
}

.eds-reason h3 {
	margin: 0 0 var(--eds-s2);
	font-size: 20px;
	color: var(--eds-text-strong);
}

.eds-reason p {
	margin: 0;
	font-size: 16px;
	color: var(--eds-text-on-dark-muted);
}

/* Process. */
.eds-step__num {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 var(--eds-s4);
	font-family: var(--global-heading-font-family);
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .14em;
	font-variant-numeric: tabular-nums;
	color: var(--eds-accent);
}

.eds-step h3 {
	margin: 0 0 var(--eds-s3);
	font-size: 21px;
	color: var(--eds-text-strong);
}

.eds-step p {
	margin: 0;
	font-size: 16px;
	color: var(--eds-text-on-dark-muted);
}

@media (min-width: 1025px) {
	.eds-process.wp-block-columns {
		position: relative;
	}

	.eds-process.wp-block-columns::before {
		content: "";
		position: absolute;
		top: 9px;
		left: 0;
		right: 0;
		height: 1px;
		background-image: linear-gradient(to right, rgba(77, 147, 255, .5), rgba(255, 255, 255, .12) 40%, rgba(255, 255, 255, .12) 60%, rgba(77, 147, 255, .5));
	}

	.eds-process > .wp-block-column {
		position: relative;
		padding-top: var(--eds-s6);
	}

	.eds-process > .wp-block-column::before {
		content: "";
		position: absolute;
		top: 4px;
		left: 0;
		width: 11px;
		height: 11px;
		border-radius: 50%;
		background-color: var(--eds-accent);
		box-shadow: 0 0 0 4px rgba(77, 147, 255, .18), 0 0 14px rgba(77, 147, 255, .9);
	}
}

@media (max-width: 1024px) {
	.eds-process > .wp-block-column {
		position: relative;
		padding-left: 32px;
	}

	.eds-process > .wp-block-column::before {
		content: "";
		position: absolute;
		top: var(--eds-s2);
		bottom: calc(var(--eds-s7) * -1);
		left: 5px;
		width: 1px;
		background-image: linear-gradient(to bottom, rgba(77, 147, 255, .5), rgba(255, 255, 255, .12));
	}

	.eds-process > .wp-block-column:last-child::before {
		display: none;
	}

	.eds-process > .wp-block-column::after {
		content: "";
		position: absolute;
		top: 6px;
		left: 0;
		width: 11px;
		height: 11px;
		border-radius: 50%;
		background-color: var(--eds-accent);
		box-shadow: 0 0 0 4px rgba(77, 147, 255, .18), 0 0 14px rgba(77, 147, 255, .9);
	}
}

/* CTA panel. */
.eds-cta__panel {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	padding: var(--eds-s10) var(--eds-s7);
	border: 1px solid rgba(77, 147, 255, .22);
	border-radius: var(--eds-radius-panel);
	background-color: rgba(11, 18, 32, .6);
	background-image:
		linear-gradient(to right, rgba(255, 255, 255, .03) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .03) 1px, transparent 1px),
		linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, 0));
	background-size: 48px 48px, 48px 48px, 100% 100%;
	box-shadow:
		0 1px 0 0 rgba(255, 255, 255, .08) inset,
		0 0 0 1px rgba(77, 147, 255, .06),
		0 48px 96px -48px rgba(77, 147, 255, .35);
	text-align: center;
}

/* Accent bloom from the top edge and a conic glint that drifts slowly. */
.eds-cta__panel::before {
	content: "";
	position: absolute;
	inset: -45% -10% auto -10%;
	z-index: -1;
	height: 90%;
	background-image: radial-gradient(45% 100% at 50% 100%, rgba(77, 147, 255, .35), transparent 72%);
	pointer-events: none;
}

.eds-cta__panel::after {
	content: "";
	position: absolute;
	inset: -1px;
	z-index: -1;
	border-radius: inherit;
	padding: 1px;
	background-image: conic-gradient(from var(--eds-angle, 0deg), transparent 0 70%, rgba(77, 147, 255, .8) 85%, rgba(56, 198, 244, .8) 92%, transparent 100%);
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	opacity: .8;
	pointer-events: none;
}

@property --eds-angle {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0deg;
}

@media (prefers-reduced-motion: no-preference) {
	.eds-cta__panel::after {
		animation: eds-orbit 9s linear infinite;
	}
}

@keyframes eds-orbit {
	to { --eds-angle: 360deg; }
}

@media (max-width: 767px) {
	.eds-cta__panel {
		padding: var(--eds-s8) var(--eds-s5);
	}
}

.eds-cta__panel h2 {
	margin: 0 auto var(--eds-s4);
	max-width: 20ch;
	color: var(--eds-text-strong);
}

.eds-cta__panel p {
	margin: 0 auto var(--eds-s6);
	max-width: 56ch;
	color: var(--eds-text-on-dark);
}

.eds-cta__panel .eds-cta__note {
	margin: var(--eds-s5) auto 0;
	font-size: 14px;
	color: var(--eds-text-on-dark-muted);
}

/* ==========================================================================
   11. Responsive grids
   CSS Grid rather than core's flex columns so core's !important flex rules are
   inert and the column count is decided here alone.
   ========================================================================== */

.eds-cols-2.wp-block-columns,
.eds-cols-3.wp-block-columns,
.eds-cols-4.wp-block-columns {
	display: grid;
	gap: var(--eds-grid-gap);
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 768px) {
	.eds-cols-2.wp-block-columns,
	.eds-cols-3.wp-block-columns,
	.eds-cols-4.wp-block-columns {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1025px) {
	.eds-cols-3.wp-block-columns {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.eds-process.eds-cols-4.wp-block-columns {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

@media (max-width: 1024px) {
	.eds-process.eds-cols-4.wp-block-columns {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--eds-s7);
	}
}

/* Text + figure sections: the hero pair gets a wider gutter. */
@media (min-width: 1025px) {
	.eds-hero .eds-cols-2.wp-block-columns,
	.eds-page-hero .eds-cols-2.wp-block-columns {
		gap: var(--eds-s8);
	}

	/*
	 * Copy column takes a little more room than the figure so the headline
	 * breathes — and, at 1.25, so the four capability chips below it finish on
	 * one row with space to spare rather than a few pixels short of it. The
	 * figure loses about 35px at 1440 and is an SVG on preserveAspectRatio, so
	 * it scales down to fit rather than being cropped.
	 */
	.eds-hero .eds-cols-2.wp-block-columns {
		grid-template-columns: 1.25fr minmax(0, 1fr);
	}
}

/* ==========================================================================
   12. Header, navigation, dropdown
   ========================================================================== */

/* Frosted dark header everywhere. Background colour comes from the Customizer;
   the blur and hairline live here. */
#masthead .site-header-row-container-inner {
	-webkit-backdrop-filter: blur(16px) saturate(140%);
	backdrop-filter: blur(16px) saturate(140%);
}

.transparent-header #masthead .site-main-header-wrap:not(.item-is-fixed) .site-header-row-container-inner {
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}

#masthead .kadence-sticky-header.item-is-fixed:not(.item-at-start) > .site-header-row-container-inner {
	background-color: rgba(7, 12, 22, .78);
	box-shadow: 0 1px 0 0 rgba(255, 255, 255, .06), 0 12px 32px -16px rgba(0, 0, 0, .8);
}

.site-branding a.brand,
.site-branding .site-title {
	letter-spacing: -.02em;
}

/* Top-level nav: underline grows from the centre; current page keeps it. */
.header-navigation .header-menu-container > ul > li.menu-item > a {
	position: relative;
	transition: color var(--eds-dur-color) var(--eds-ease);
}

.header-navigation .header-menu-container > ul > li.menu-item > a::after {
	content: "";
	position: absolute;
	left: 50%;
	right: 50%;
	bottom: .1em;
	height: 2px;
	border-radius: 2px;
	background-image: linear-gradient(to right, var(--eds-accent), var(--eds-accent-2));
	box-shadow: 0 0 10px rgba(77, 147, 255, .6);
	transition:
		left var(--eds-dur-btn) var(--eds-ease),
		right var(--eds-dur-btn) var(--eds-ease);
}

.header-navigation .header-menu-container > ul > li.menu-item > a:hover::after,
.header-navigation .header-menu-container > ul > li.menu-item.current-menu-item > a::after,
.header-navigation .header-menu-container > ul > li.menu-item.current-menu-ancestor > a::after {
	left: 0;
	right: 0;
}

/* Header CTA button: same treatment as page buttons. */
#masthead .header-button {
	background-image: linear-gradient(180deg, #4D93FF 0%, #2563EB 100%);
	box-shadow: var(--eds-shadow-btn);
}

#masthead .header-button:hover {
	box-shadow: var(--eds-shadow-btn-hover);
}

/* Dropdown reveal: opacity + rise + slight scale, compositor-only. */
.header-navigation[class*="header-navigation-dropdown-animation-fade"] ul ul.sub-menu,
.header-navigation[class*="header-navigation-dropdown-animation-fade"] ul ul.submenu {
	transition:
		opacity 220ms var(--eds-ease-out),
		transform 260ms var(--eds-ease-out),
		visibility 220ms linear;
}

.header-navigation.header-navigation-dropdown-animation-fade-down ul ul.sub-menu,
.header-navigation.header-navigation-dropdown-animation-fade-down ul ul.submenu {
	transform: translate3d(0, -8px, 0) scale(.985);
	transform-origin: top center;
}

.header-navigation.header-navigation-dropdown-animation-fade-down ul li:hover > ul.sub-menu,
.header-navigation.header-navigation-dropdown-animation-fade-down ul li:focus-within > ul.sub-menu,
.header-navigation.header-navigation-dropdown-animation-fade-down ul li:hover > ul.submenu,
.header-navigation.header-navigation-dropdown-animation-fade-down ul li:focus-within > ul.submenu {
	transform: translate3d(0, 0, 0) scale(1);
}

/*
 * Kadence only un-hides the panel for :hover and li:focus -- neither matches
 * when focus sits on a link *inside* the submenu, so keyboard users got the
 * transform but a clipped, invisible panel. Mirror the open state for
 * :focus-within.
 */
.header-navigation[class*="header-navigation-dropdown-animation-fade"]:not(.click-to-open) ul li:focus-within > ul.sub-menu,
.header-navigation[class*="header-navigation-dropdown-animation-fade"]:not(.click-to-open) ul li:focus-within > ul.submenu {
	opacity: 1;
	visibility: visible;
	clip: auto;
	height: auto;
	overflow: visible;
}

/*
 * Desktop Services dropdown: dark glass panel. Surface colour, item colour,
 * width and typography come from the Kadence dropdown controls; the frame,
 * blur, glow, item motion and stagger live here.
 */
@media (min-width: 1024px) {

	/* Single source of truth for the panel offset and the bridge that spans it. */
	.header-navigation .header-menu-container {
		--eds-nav-gap: 10px;
	}

	/*
	 * Hover bridge. The panel is offset by --eds-nav-gap, which used to be dead
	 * space: the pointer left the <li> before it reached the panel and the
	 * dropdown closed mid-travel. This transparent pseudo-element extends the
	 * item's hit area across exactly that offset, so hover is continuous.
	 * It lives on the <li> (not the panel, which is clipped while closed).
	 */
	.header-navigation .header-menu-container > ul > li.menu-item-has-children {
		position: relative;
	}

	.header-navigation .header-menu-container > ul > li.menu-item-has-children::after {
		content: "";
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		height: var(--eds-nav-gap);
	}

	.header-navigation .header-menu-container ul ul.sub-menu {
		margin-top: var(--eds-nav-gap);
		padding: 10px;
		border: 1px solid rgba(255, 255, 255, .1);
		border-radius: 16px;
		overflow: hidden;
		background-color: rgba(12, 20, 36, .82);
		background-image:
			linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, 0) 40%),
			radial-gradient(70% 40% at 50% 0%, rgba(77, 147, 255, .16), transparent 70%);
		-webkit-backdrop-filter: blur(20px) saturate(150%);
		backdrop-filter: blur(20px) saturate(150%);
		box-shadow:
			inset 0 1px 0 0 rgba(255, 255, 255, .09),
			0 0 0 1px rgba(77, 147, 255, .08),
			0 24px 56px -16px rgba(0, 0, 0, .75),
			0 12px 40px -20px rgba(77, 147, 255, .35);
	}

	/* Accent hairline along the panel's top edge. */
	.header-navigation .header-menu-container ul ul.sub-menu::before {
		content: "";
		position: absolute;
		top: 0;
		left: 16px;
		right: 16px;
		height: 1px;
		background-image: linear-gradient(to right, transparent, rgba(77, 147, 255, .7), rgba(56, 198, 244, .6), transparent);
		pointer-events: none;
	}

	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a {
		position: relative;
		display: flex;
		align-items: center;
		gap: 12px;
		white-space: nowrap;
		padding: 12px 40px 12px 20px;
		border-radius: 10px;
		font-weight: 500;
		letter-spacing: .005em;
		transition:
			background-color 180ms var(--eds-ease),
			color 180ms var(--eds-ease),
			padding-left 180ms var(--eds-ease);
	}

	/* Node dot on the left, lights up on hover / current. */
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a::before {
		content: "";
		flex: 0 0 auto;
		width: 6px;
		height: 6px;
		border-radius: 50%;
		background-color: rgba(255, 255, 255, .22);
		box-shadow: 0 0 0 0 rgba(77, 147, 255, 0);
		transition: background-color 180ms var(--eds-ease), box-shadow 180ms var(--eds-ease);
	}

	/* Arrow on the right that slides in. */
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a::after {
		content: "\2192";
		position: absolute;
		right: 16px;
		top: 50%;
		display: block;
		height: auto;
		width: auto;
		background: none;
		opacity: 0;
		transform: translate(-6px, -50%);
		transition: opacity 180ms var(--eds-ease), transform 180ms var(--eds-ease);
		color: var(--eds-accent);
	}

	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:hover,
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:focus-visible {
		padding-left: 24px;
	}

	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:hover::before,
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:focus-visible::before,
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item.current-menu-item > a::before {
		background-color: var(--eds-accent);
		box-shadow: 0 0 0 3px rgba(77, 147, 255, .2), 0 0 10px rgba(77, 147, 255, .9);
	}

	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:hover::after,
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:focus-visible::after,
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item.current-menu-item > a::after {
		opacity: 1;
		transform: translate(0, -50%);
	}

	/* Items cascade in behind the panel. */
	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item {
		opacity: 0;
		transform: translateY(-4px);
		transition: opacity 240ms var(--eds-ease-out), transform 240ms var(--eds-ease-out);
	}

	.header-navigation .header-menu-container ul li:hover > ul.sub-menu > li.menu-item,
	.header-navigation .header-menu-container ul li:focus-within > ul.sub-menu > li.menu-item {
		opacity: 1;
		transform: none;
	}

	.header-navigation .header-menu-container ul li:hover > ul.sub-menu > li.menu-item:nth-child(2),
	.header-navigation .header-menu-container ul li:focus-within > ul.sub-menu > li.menu-item:nth-child(2) { transition-delay: 40ms; }
	.header-navigation .header-menu-container ul li:hover > ul.sub-menu > li.menu-item:nth-child(3),
	.header-navigation .header-menu-container ul li:focus-within > ul.sub-menu > li.menu-item:nth-child(3) { transition-delay: 80ms; }
	.header-navigation .header-menu-container ul li:hover > ul.sub-menu > li.menu-item:nth-child(4),
	.header-navigation .header-menu-container ul li:focus-within > ul.sub-menu > li.menu-item:nth-child(4) { transition-delay: 120ms; }
	.header-navigation .header-menu-container ul li:hover > ul.sub-menu > li.menu-item:nth-child(5),
	.header-navigation .header-menu-container ul li:focus-within > ul.sub-menu > li.menu-item:nth-child(5) { transition-delay: 160ms; }

	.header-navigation .header-menu-container ul ul.sub-menu > li.menu-item > a:focus-visible {
		outline: 2px solid rgba(120, 170, 255, .75);
		outline-offset: -2px;
	}

	/* Kadence's .hide-focus-outline rule outranks the global a:focus-visible. */
	.header-navigation .header-menu-container > ul > li.menu-item > a:focus-visible {
		outline: 2px solid rgba(120, 170, 255, .75);
		outline-offset: 2px;
		border-radius: 6px;
	}
}

/* Mobile drawer. */
#mobile-drawer .drawer-inner,
.popup-drawer .drawer-inner {
	background-color: rgba(9, 15, 27, .96);
	-webkit-backdrop-filter: blur(20px);
	backdrop-filter: blur(20px);
}

#mobile-drawer .mobile-navigation a,
#mobile-drawer .drawer-header .drawer-toggle {
	color: var(--eds-text-strong);
}

#mobile-drawer .mobile-navigation ul li a {
	border-color: var(--eds-line);
}

/* ==========================================================================
   13. Footer
   ========================================================================== */

.site-footer {
	position: relative;
}

.site-footer::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 1px;
	background-image: linear-gradient(to right, transparent, rgba(77, 147, 255, .45) 30%, rgba(77, 147, 255, .45) 70%, transparent);
}

.site-footer .footer-widget-area .widget-title {
	margin-bottom: var(--eds-s4);
	font-size: 15px;
	letter-spacing: .02em;
	text-transform: none;
}

.site-footer .footer-widget-area ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-footer .footer-widget-area li + li {
	margin-top: var(--eds-s3);
}

.site-footer a {
	transition: color var(--eds-dur-color) var(--eds-ease);
}

.site-footer .site-top-footer-wrap a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/*
 * Language switcher (GTranslate).
 * Rendered into the footer1 widget area by functions.php as a <details>
 * disclosure holding every configured language; the <a data-gt-lang> links are
 * the plugin's own markup and base.js rewrites their href, moves
 * .gt-current-lang and performs the switch, so only presentation lives here.
 */
.eds-lang {
	margin-top: var(--eds-s5);
}

.eds-lang__menu {
	position: relative;
	display: inline-block;
	max-width: 100%;
}

/* The compact trigger: one dark inset field showing the active language. */
.eds-lang__toggle {
	display: flex;
	align-items: center;
	gap: var(--eds-s3);
	min-height: 42px;
	padding: 0 var(--eds-s4);
	border: 1px solid var(--eds-line-accent);
	border-radius: var(--eds-radius-tile);
	background-color: rgba(11, 18, 32, .9);
	background-image: var(--eds-glass-soft);
	box-shadow:
		inset 0 1px 0 0 rgba(255, 255, 255, .06),
		0 8px 24px -14px rgba(0, 0, 0, .8),
		0 6px 20px -16px rgba(77, 147, 255, .5);
	cursor: pointer;
	list-style: none;
	user-select: none;
	transition:
		border-color 180ms var(--eds-ease),
		box-shadow 180ms var(--eds-ease);
}

/* Both spellings: WebKit still needs the pseudo-element to drop the triangle. */
.eds-lang__toggle::-webkit-details-marker {
	display: none;
}

.eds-lang__toggle::marker {
	content: "";
}

.eds-lang__toggle:hover,
.eds-lang__menu[open] > .eds-lang__toggle {
	border-color: rgba(77, 147, 255, .55);
	box-shadow:
		inset 0 1px 0 0 rgba(255, 255, 255, .08),
		0 0 16px -4px rgba(77, 147, 255, .6);
}

.eds-lang__toggle:focus-visible {
	outline: 2px solid rgba(120, 170, 255, .85);
	outline-offset: 2px;
}

.eds-lang__label {
	font-size: 12px;
	font-weight: 600;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--eds-text-on-dark-muted);
}

.eds-lang__current {
	flex: 1 1 auto;
	overflow: hidden;
	font-size: 13.5px;
	font-weight: 600;
	line-height: 1;
	color: var(--eds-text-strong);
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Chevron, rotated when the disclosure is open. */
.eds-lang__toggle::after {
	width: 7px;
	height: 7px;
	border-right: 1.5px solid var(--eds-text-on-dark-muted);
	border-bottom: 1.5px solid var(--eds-text-on-dark-muted);
	margin-left: auto;
	content: "";
	transform: translateY(-2px) rotate(45deg);
	transition: transform 180ms var(--eds-ease);
}

.eds-lang__menu[open] > .eds-lang__toggle::after {
	transform: translateY(1px) rotate(-135deg);
}

/*
 * Opens upward: the switcher sits in the footer. Scrolls rather than paginates,
 * so the list stays whatever length the plugin is configured for.
 */
.eds-lang__panel {
	position: absolute;
	z-index: 20;
	bottom: calc(100% + var(--eds-s2));
	left: 0;
	display: grid;
	width: max-content;
	max-width: min(420px, calc(100vw - 2 * var(--eds-s4)));
	max-height: min(340px, 50vh);
	padding: var(--eds-s2);
	border: 1px solid var(--eds-line-accent);
	border-radius: var(--eds-radius-tile);
	background-color: #080e1a;
	background-image: var(--eds-glass-soft);
	box-shadow:
		inset 0 1px 0 0 rgba(255, 255, 255, .06),
		0 24px 60px -24px rgba(0, 0, 0, .9),
		0 0 24px -10px rgba(77, 147, 255, .45);
	gap: 2px;
	grid-template-columns: repeat(2, minmax(140px, 1fr));
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* GTranslate adds .glink/.notranslate to each link at runtime. */
.eds-lang__panel a {
	display: flex;
	align-items: center;
	min-height: 32px;
	padding: 0 var(--eds-s3);
	border-radius: 8px;
	font-size: 13px;
	font-weight: 500;
	line-height: 1.2;
	color: var(--eds-text-on-dark);
	text-decoration: none;
	transition:
		background-color 160ms var(--eds-ease),
		color 160ms var(--eds-ease);
}

.site-footer .site-top-footer-wrap .eds-lang__panel a:hover {
	color: var(--eds-text-strong);
	background-color: rgba(77, 147, 255, .14);
	text-decoration: none;
}

.eds-lang__panel a:focus-visible {
	outline: 2px solid rgba(120, 170, 255, .85);
	outline-offset: -2px;
	color: var(--eds-text-strong);
}

/* Active language. base.js maintains this class on every switching path. */
.site-footer .eds-lang__panel a.gt-current-lang {
	color: var(--eds-text-strong);
	background-color: rgba(77, 147, 255, .2);
	box-shadow: inset 0 0 0 1px rgba(77, 147, 255, .55);
	font-weight: 600;
}

@media (max-width: 767px) {
	.eds-lang__menu {
		display: block;
	}

	.eds-lang__panel {
		grid-template-columns: 1fr;
		width: 100%;
	}

	.eds-lang__panel a {
		min-height: 40px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.eds-lang__toggle,
	.eds-lang__toggle::after,
	.eds-lang__panel a {
		transition: none;
	}
}

/* ==========================================================================
   14. Scroll reveal
   The class is applied by motion.js only to elements that start below the
   fold, so nothing above the fold flickers and no-JS visitors see everything.
   ========================================================================== */

.eds-reveal {
	opacity: 0;
	transform: translateY(18px);
	will-change: opacity, transform;
}

.eds-reveal.is-visible {
	opacity: 1;
	transform: none;
	will-change: auto;
	transition:
		opacity var(--eds-dur-enter) var(--eds-ease-out),
		transform var(--eds-dur-enter) var(--eds-ease-out);
}

/* ==========================================================================
   15. Scene motion
   One-shot scene animations plus two gentle loops (ping, flow) used only on
   hero and AI visuals. Everything sits inside no-preference so under reduced
   motion nothing is declared and each element renders in its final state.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {

	.eds-hero .eds-figure,
	.eds-page-hero .eds-figure {
		animation: eds-settle 820ms var(--eds-ease-out) both;
	}

	/* Hero figures drift very slowly, so the composition never feels frozen. */
	.eds-hero .eds-figure {
		animation: eds-settle 820ms var(--eds-ease-out) both, eds-float 9s ease-in-out 820ms infinite;
	}

	.eds-hero .eds-viz-bar-rise,
	.eds-page-hero .eds-viz-bar-rise,
	.eds-reveal.is-visible .eds-viz-bar-rise {
		animation: eds-bar-rise 620ms var(--eds-ease-out) both;
		animation-delay: var(--d, 0ms);
		transform-box: fill-box;
		transform-origin: bottom center;
	}

	.eds-hero .eds-viz-fill,
	.eds-page-hero .eds-viz-fill,
	.eds-reveal.is-visible .eds-viz-fill {
		animation: eds-fill 700ms var(--eds-ease-out) both;
		animation-delay: var(--d, 0ms);
		transform-box: fill-box;
		transform-origin: left center;
	}

	.eds-hero .eds-viz-seq,
	.eds-page-hero .eds-viz-seq,
	.eds-reveal.is-visible .eds-viz-seq {
		animation: eds-seq 520ms var(--eds-ease-out) both;
		animation-delay: var(--d, 0ms);
		transform-box: fill-box;
	}

	.eds-hero .eds-viz-path,
	.eds-page-hero .eds-viz-path,
	.eds-reveal.is-visible .eds-viz-path {
		animation: eds-draw 1100ms var(--eds-ease-out) both;
		animation-delay: 320ms;
	}

	/* Soft repeating pulse on node markers. */
	.eds-hero .eds-viz-ping,
	.eds-page-hero .eds-viz-ping,
	.eds-reveal.is-visible .eds-viz-ping {
		animation: eds-ping 2.8s ease-out infinite;
		animation-delay: var(--d, 0ms);
		transform-box: fill-box;
		transform-origin: center;
	}

	/* Data flowing along a connector: dashed stroke sliding. */
	.eds-viz-flow {
		stroke-dasharray: 6 10;
		animation: eds-flow 1.6s linear infinite;
	}

	.eds-viz-glow {
		animation: eds-glow 3.2s ease-in-out infinite;
		animation-delay: var(--d, 0ms);
	}

	/* Slow rotate for orbit rings. */
	.eds-viz-orbit {
		animation: eds-spin 28s linear infinite;
		transform-box: fill-box;
		transform-origin: center;
	}
}

@keyframes eds-settle {
	from { opacity: 0; transform: translateY(14px) scale(.985); }
	to   { opacity: 1; transform: none; }
}

@keyframes eds-float {
	0%, 100% { transform: translateY(0); }
	50%      { transform: translateY(-8px); }
}

@keyframes eds-bar-rise {
	from { transform: scaleY(0); }
	to   { transform: scaleY(1); }
}

@keyframes eds-fill {
	from { transform: scaleX(0); }
	to   { transform: scaleX(1); }
}

@keyframes eds-seq {
	from { opacity: 0; transform: translateY(6px); }
	to   { opacity: 1; transform: none; }
}

@keyframes eds-draw {
	from { stroke-dashoffset: 400; }
	to   { stroke-dashoffset: 0; }
}

@keyframes eds-ping {
	0%   { opacity: .5; transform: scale(.8); }
	70%  { opacity: 0;  transform: scale(1.6); }
	100% { opacity: 0;  transform: scale(1.6); }
}

@keyframes eds-flow {
	to { stroke-dashoffset: -32; }
}

@keyframes eds-glow {
	0%, 100% { opacity: .45; }
	50%      { opacity: 1; }
}

@keyframes eds-spin {
	to { transform: rotate(360deg); }
}

/* ==========================================================================
   16. Accessibility
   ========================================================================== */

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid rgba(120, 170, 255, .65);
	outline-offset: 2px;
}

@media (max-width: 767px) {
	.wp-block-button__link,
	.wp-element-button {
		min-height: 44px;
	}

	.eds-hero .wp-block-button,
	.eds-page-hero .wp-block-button,
	.eds-cta__panel .wp-block-button {
		width: 100%;
	}

	.eds-hero .wp-block-button__link,
	.eds-page-hero .wp-block-button__link,
	.eds-cta__panel .wp-block-button__link {
		display: block;
		width: 100%;
		text-align: center;
	}
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   17. Homepage light rhythm  — EXPERIMENT, scoped to .home only
   hero (dark) / services (light) / reasons (dark tint) / process (light)
   / CTA (dark tint) / footer (dark), with an angled cut at every join.

   Sections are selected by the component they contain, not by a new block
   class, so no page content changes and no other template is touched.
   Deleting this whole block restores the all-dark homepage.
   ========================================================================== */

.home {
	/* How far the cut climbs from the left edge to the right, and how thick
	   the accent that rides along it is. Declared here, outside the light
	   sections, so the accent overrides below cannot restain the divider. */
	--eds-tilt-rise: 18px;
	--eds-tilt-line: 14px;
	--eds-tilt-band: calc(var(--eds-tilt-rise) + var(--eds-tilt-line));
	/* The blue of the cut now lives in :root, so the cursor follower can be
	   filled from the same --eds-tilt-fill the divider uses. Every consumer of
	   these tokens is .home-scoped, so nothing else changed by moving them. */

	/*
	 * Shared entrance curves, used by every staged section on this page.
	 *
	 * --eds-stage-ease is a long, flat-tailed ease-out for the movement.
	 * --eds-stage-fade is gentler still, for the one case that wants the fade
	 * to trail the movement rather than track it; everything else pairs opacity
	 * with --eds-stage-ease so an element is exactly as visible as it is far
	 * along, which is what keeps a long travel actually watchable.
	 */
	--eds-stage-ease: cubic-bezier(.16, 1, .3, 1);
	--eds-stage-fade: cubic-bezier(.4, 0, .4, 1);
}

@media (max-width: 767px) {
	.home {
		/* 18px across a 390px viewport is 2.6°; 9px holds it near 1.3°. */
		--eds-tilt-rise: 9px;
		--eds-tilt-line: 8px;
	}
}

/*
 * Top-level blocks carry the 32px editor block gap. On an all-dark page that
 * gap just read as extra section padding; between a light and a dark section
 * it is a visible band of the wrong colour, and it would hold each cut away
 * from the section above it. Backgrounds have to meet.
 */
.home .entry-content > .eds-section {
	margin-bottom: 0;
}

/* --- the angled section cut ---------------------------------------------- */

/*
 * The join itself is angled, not a stripe laid over a straight join. Both
 * halves of the cut are drawn inside the LOWER section's existing top
 * padding, so every section stays in normal flow at its natural height: no
 * negative margins, no clipped content, no gaps, nothing to overlap.
 *
 * Within a band of --eds-tilt-band at the top of the section:
 *   ::before  carries the colour of the section ABOVE down past its own
 *             bottom edge, as a triangle that is --eds-tilt-rise tall on the
 *             left and zero on the right. That wedge is what moves the
 *             visible boundary off the horizontal.
 *   ::after   is the accent: a parallelogram of constant --eds-tilt-line
 *             thickness whose top edge is the same line, so the two meet with
 *             no seam and the cut reads as one continuous edge.
 * Everything below that band is the section's own background, already there.
 *
 * Slope is --eds-tilt-rise over the viewport width: 0.72° at 1440, 1.0° at
 * 1024, 1.3° at 390 — lower on the left, higher on the right, everywhere.
 */
.home .entry-content > .eds-section:not(.eds-hero)::before,
.home .entry-content > .eds-section:not(.eds-hero)::after {
	content: "";
	display: block;
	position: absolute;
	/*
	 * Section heights are fractional, so the join lands mid-device-pixel and
	 * the browser antialiases the two backgrounds into a 1px grey row there.
	 * Both layers start 1px above the join and every edge below is offset to
	 * match, which paints over that row with the colour of the section above.
	 */
	top: -1px;
	left: 0;
	right: 0;
	height: calc(var(--eds-tilt-band) + 1px);
	pointer-events: none;
}

/*
 * Carries the section above down past its own bottom edge, grid and all, so
 * the texture runs continuously across the cut instead of stopping at a
 * horizontal line. Also overrides the 1px hairline, whose job this now is.
 */
.home .entry-content > .eds-section:not(.eds-hero)::before {
	background-color: var(--eds-cut-above);
	background-image: linear-gradient(to right, var(--eds-cut-grid) 1px, transparent 1px);
	background-size: 64px 64px;
	clip-path: polygon(0 0, 100% 0, 100% 1px, 0 calc(var(--eds-tilt-rise) + 1px));
}

.home .entry-content > .eds-section:not(.eds-hero)::after {
	background-image: var(--eds-tilt-fill);
	/* Top edge runs 1px proud of the wedge so no sub-pixel seam opens up. */
	clip-path: polygon(
		0 var(--eds-tilt-rise),
		100% 0,
		100% calc(var(--eds-tilt-line) + 1px),
		0 calc(var(--eds-tilt-band) + 1px)
	);
}

/*
 * The colour each cut carries down: the flat bottom edge of the section above,
 * sampled from the rendered page. --tint darkens towards its foot, so it is
 * not the #0B1220 it starts at.
 */
.home .eds-section:has(.eds-card--media) {
	--eds-cut-above: #070C16;                 /* hero */
	--eds-cut-grid: transparent;              /* its grid is masked out by then */
}

.home .eds-section:has(.eds-step) {
	--eds-cut-above: #090F1A;                 /* reasons, .eds-section--tint */
	--eds-cut-grid: rgba(255, 255, 255, .028);
}

.home .eds-section:has(.eds-reason),
.home .eds-section:has(.eds-cta__panel) {
	--eds-cut-above: #F4F7FC;                 /* a light section */
	--eds-cut-grid: rgba(11, 18, 32, .032);
}

/* The hero's 1px accent foot sat exactly where the first cut now starts. */
.home .eds-hero::after {
	display: none;
}

/* --- the light sections -------------------------------------------------- */

/*
 * Every component in these sections already paints from the --eds-* tokens,
 * so flipping the tokens on the section flips the cards, headings, body copy
 * and accents with it. Only the few places that hardcode a colour need a rule
 * of their own, below.
 */
.home .eds-section:has(.eds-card--media),
.home .eds-section:has(.eds-step) {
	--eds-text-strong: #0B1220;
	--eds-text-on-dark: #3D4C63;        /* 8.2:1 on the section background */
	--eds-text-on-dark-muted: #55657F;  /* 5.5:1 */
	--eds-accent: #2563EB;              /* 4.8:1 — #4D93FF is only 3.0:1 here */
	--eds-accent-soft: rgba(37, 99, 235, .08);

	--eds-glass: linear-gradient(180deg, #FFFFFF 0%, #FBFCFE 100%);
	--eds-glass-hover: linear-gradient(180deg, #FFFFFF 0%, #FFFFFF 100%);

	--eds-line: rgba(11, 18, 32, .10);
	--eds-line-strong: rgba(11, 18, 32, .14);
	--eds-line-accent: rgba(37, 99, 235, .42);

	--eds-shadow-card:
		0 1px 2px 0 rgba(11, 18, 32, .05),
		0 14px 32px -20px rgba(11, 18, 32, .30);
	--eds-shadow-card-hover:
		0 0 0 1px rgba(37, 99, 235, .18),
		0 22px 48px -24px rgba(37, 99, 235, .45),
		0 18px 36px -22px rgba(11, 18, 32, .32);

	color: var(--eds-text-on-dark);

	/* Same construction as .eds-section--tint, inverted: soft blue-tinted
	   off-white with the same 64px grid, fading in from the top. */
	background-color: #F4F7FC;
	background-image:
		linear-gradient(to bottom, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, 0) 45%),
		linear-gradient(to right, rgba(11, 18, 32, .032) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(11, 18, 32, .032) 1px, transparent 1px);
	background-size: 100% 100%, 64px 64px, 64px 64px;
}

/* The eyebrow rule and both link hovers resolve to white on dark. */
.home .eds-section:has(.eds-card--media) .eds-eyebrow::before,
.home .eds-section:has(.eds-step) .eds-eyebrow::before {
	background-image: linear-gradient(to right, var(--eds-accent), rgba(37, 99, 235, .3));
}

.home .eds-section:has(.eds-card--media) .eds-link:hover,
.home .eds-section:has(.eds-card--media) .eds-link:focus,
.home .eds-section:has(.eds-card--media) .entry-content a:hover,
.home .eds-section:has(.eds-step) .eds-link:hover,
.home .eds-section:has(.eds-step) .eds-link:focus {
	color: #1D4ED8;
}

/* --- service card visual headers ----------------------------------------- */

/*
 * .eds-card__media is a 50%-opaque dark wash designed to sit on a dark glass
 * card. Over a white card body it composites to mid grey, which is what makes
 * all four headers read the same and read flat. Make it opaque hero navy
 * instead, ring it in the divider accent, and let the existing --eds-viz-*
 * illustrations sit on the background they were drawn for.
 *
 * The radius matches the card's inner corner so the ring follows the card
 * rather than being cut square by its overflow:hidden.
 */
.home .eds-section:has(.eds-card--media) .eds-card__media {
	--eds-media-glow: rgba(77, 147, 255, .20);

	border-bottom: 1px solid rgba(77, 147, 255, .7);
	border-radius: calc(var(--eds-radius-card) - 1px) calc(var(--eds-radius-card) - 1px) 0 0;
	background-color: #070C16;
	background-image:
		radial-gradient(64% 86% at 50% 112%, var(--eds-media-glow), transparent 70%),
		linear-gradient(to right, rgba(255, 255, 255, .035) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(255, 255, 255, .035) 1px, transparent 1px);
	background-size: 100% 100%, 32px 32px, 32px 32px;
	box-shadow:
		inset 0 0 0 1px rgba(77, 147, 255, .3),
		inset 0 1px 0 0 rgba(255, 255, 255, .07);
}

/*
 * One family, four temperatures: the same glow rotated through the palette so
 * each service reads as its own visual without a second illustration.
 */
.home .eds-section:has(.eds-card--media) .wp-block-column:nth-child(2) .eds-card__media {
	--eds-media-glow: rgba(56, 198, 244, .18);
}

.home .eds-section:has(.eds-card--media) .wp-block-columns:last-of-type .wp-block-column:nth-child(1) .eds-card__media {
	--eds-media-glow: rgba(123, 140, 255, .19);
}

.home .eds-section:has(.eds-card--media) .wp-block-columns:last-of-type .wp-block-column:nth-child(2) .eds-card__media {
	--eds-media-glow: rgba(37, 99, 235, .26);
}

/* --- service card photography -------------------------------------------- */

/*
 * The header art is a real 680x280 photo now, not the drawn 640x260 scene.
 * Pinning the ratio to the scene's keeps the header exactly the height it has
 * always been — letting the photo's own 680/280 through would add ~3px per
 * card and push the section down with it — and object-fit covers the 1.2%
 * difference without distorting anything. width/height on the tag plus this
 * ratio mean the box is reserved before the file arrives, so nothing shifts.
 */
.home .eds-section:has(.eds-card--media) .eds-card__media > img {
	aspect-ratio: 640 / 260;
	object-fit: cover;
	object-position: center;
}

/*
 * One family out of four stock photos: a shallow navy wash, deeper at the foot
 * where the image meets the white body. Enough to pull the brightest of the
 * four back towards the others and to soften the join; not enough to stop them
 * reading as photographs.
 */
.home .eds-section:has(.eds-card--media) .eds-card__media::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	background-image: linear-gradient(180deg, rgba(7, 12, 22, .16) 0%, rgba(7, 12, 22, .2) 55%, rgba(7, 12, 22, .34) 100%);
}

/* --- service card edge lighting ------------------------------------------ */

/*
 * A lit edge rather than an outline: the same blue as the tilted cut, thin, at
 * a third alpha, over a glow tight enough (negative spread) to read as light
 * coming off the panel instead of a halo around it. The neutral depth shadow
 * is kept underneath by composing on top of --eds-shadow-card rather than
 * replacing it, so the card keeps sitting on the page the way it did.
 *
 * These selectors out-specify .eds-card:hover, which is why the hover state
 * below has to restate the border and shadow. It deliberately does not touch
 * transform, so the -4px hover lift still comes from .eds-card:hover.
 */
.home .eds-section:has(.eds-card--media) .eds-card--media {
	/*
	 * The edge is the blue of the tilted cut above it, at full strength and a
	 * single pixel wide — the same value the glow around it is already built
	 * from, which is what this token exists for.
	 *
	 * It used to be --eds-ink doubled: a 1px border plus a 1px box-shadow ring
	 * immediately outside it, so a dark edge read as 2px. Both layers have gone
	 * blue and the ring with them. Keeping the ring would have made a 2px
	 * luminous outline, which is the neon this section must not have; one pixel
	 * lets the glow read as light coming off the panel rather than fighting an
	 * edge of the same colour.
	 */
	border-color: var(--eds-tilt-blue);
	box-shadow:
		var(--eds-shadow-card),
		0 0 14px rgba(var(--eds-tilt-blue-rgb), .3),
		0 0 30px rgba(var(--eds-tilt-blue-rgb), .18);
}

.home .eds-section:has(.eds-card--media) .eds-card--media:hover,
.home .eds-section:has(.eds-card--media) .eds-card--media:focus-within {
	/* Edge holds its colour; only the light around it comes up. */
	border-color: var(--eds-tilt-blue);
	box-shadow:
		var(--eds-shadow-card-hover),
		0 0 18px rgba(var(--eds-tilt-blue-rgb), .45),
		0 0 38px rgba(var(--eds-tilt-blue-rgb), .28);
}

/* Process rail: the neutral half of both connectors is white at .12. */
@media (min-width: 1025px) {
	.home .eds-section:has(.eds-step) .eds-process.wp-block-columns::before {
		background-image: linear-gradient(to right, rgba(37, 99, 235, .55), rgba(11, 18, 32, .14) 40%, rgba(11, 18, 32, .14) 60%, rgba(37, 99, 235, .55));
	}

	.home .eds-section:has(.eds-step) .eds-process > .wp-block-column::before {
		box-shadow: 0 0 0 4px rgba(37, 99, 235, .14);
	}
}

@media (max-width: 1024px) {
	.home .eds-section:has(.eds-step) .eds-process > .wp-block-column::before {
		background-image: linear-gradient(to bottom, rgba(37, 99, 235, .55), rgba(11, 18, 32, .14));
	}

	.home .eds-section:has(.eds-step) .eds-process > .wp-block-column::after {
		box-shadow: 0 0 0 4px rgba(37, 99, 235, .14);
	}
}

/* The global focus ring is a pale blue tuned for dark surfaces. */
.home .eds-section:has(.eds-card--media) :focus-visible,
.home .eds-section:has(.eds-step) :focus-visible {
	outline-color: rgba(29, 78, 216, .8);
}

/* ==========================================================================
   18. Narrative pill  — HOMEPAGE EXPERIMENT, scoped to .home only
   One pill that starts at the hero eyebrow and then follows the reader,
   restating where they are as each section passes behind it. assets/
   narrative.js supplies the words and the theme; everything about where it
   sits is here, so nothing about its placement depends on JavaScript.
   Deleting this block and the is_front_page() enqueue removes it entirely.
   ========================================================================== */

.home {
	/*
	 * Where the pill starts: level with the hero eyebrow, which is the first
	 * thing in the hero and therefore sits exactly at .eds-hero's padding-top.
	 * Keep these three in step with that rule (section 5) and the pill can
	 * never start anywhere but on top of the eyebrow it replaces.
	 */
	--eds-narrative-start: 136px;

	/* Where it parks: clear of the 89px sticky header. */
	--eds-narrative-top: 110px;
}

@media (max-width: 1024px) {
	.home {
		--eds-narrative-start: 124px;
		--eds-narrative-top: 96px;
	}
}

@media (max-width: 767px) {
	.home {
		--eds-narrative-start: 104px;
	}
}

/*
 * The six source messages, printed by functions.php. Visually hidden but
 * fully in the document, because this is the copy GTranslate actually
 * translates — the pill mirrors whatever it currently says, which is how the
 * pill follows the active language with no per-language strings of our own.
 *
 * Clipped rather than display:none, and absolutely positioned with no offsets,
 * so it sits out of flow at its static position: no height, no layout shift,
 * nothing to overflow.
 */
.eds-narrative-source {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

.eds-narrative-source p {
	margin: 0;
}

/* The eyebrow the pill takes over from. visibility, not display, so the hero
   keeps the exact spacing it has now. */
.home .eds-hero .eds-eyebrow {
	visibility: hidden;
}

/*
 * The rail: a pointer-transparent overlay spanning from the hero eyebrow to
 * the end of the content, with the pill sticky inside it. Because the rail is
 * absolutely positioned it is out of flow — it cannot change a section height,
 * push anything, or add scrollable width — and because the pill is sticky
 * rather than fixed, it simply sits at the top of the rail until the viewport
 * reaches it and then holds. There is no state to toggle and nothing to jump.
 *
 * z-index 3 clears the sections (which are position:relative/z-index:auto) and
 * stays far below #masthead (100), its sticky row (1200) and the mobile drawer
 * (99999), so the header, its dropdowns and the drawer all pass over the pill.
 *
 * The padding-left reproduces the content column's left edge, so the pill
 * lines up with the section eyebrows at every width.
 */
.home .entry-content {
	position: relative;
}

.eds-narrative {
	position: absolute;
	z-index: 3;
	top: var(--eds-narrative-start);
	right: 0;
	bottom: 0;
	left: 0;
	padding-right: var(--global-content-edge-padding);
	padding-left: max(
		var(--global-content-edge-padding),
		calc((100% - var(--global-content-width)) / 2 + var(--global-content-edge-padding))
	);
	pointer-events: none;
}

.eds-narrative__pill {
	position: sticky;
	top: var(--eds-narrative-top);
	display: flex;
	align-items: center;
	gap: 9px;
	width: fit-content;
	max-width: 100%;
	margin: 0;
	padding: 8px 16px 8px 13px;
	border: 1px solid var(--eds-narrative-border);
	border-radius: 999px;
	background-color: var(--eds-narrative-bg);
	box-shadow: var(--eds-narrative-shadow);
	color: var(--eds-narrative-ink);
	font-size: 12.5px;
	font-weight: 600;
	line-height: 1.4;
	letter-spacing: .14em;
	text-transform: uppercase;
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	transition:
		background-color var(--eds-dur-card) var(--eds-ease),
		border-color var(--eds-dur-card) var(--eds-ease),
		box-shadow var(--eds-dur-card) var(--eds-ease),
		color var(--eds-dur-card) var(--eds-ease);
}

/* Live status dot, as on the hero eyebrow. */
.eds-narrative__pill::before {
	content: "";
	flex: none;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background-color: var(--eds-narrative-dot);
	box-shadow: 0 0 0 3px var(--eds-narrative-dot-ring), 0 0 12px var(--eds-narrative-dot-glow);
	transition:
		background-color var(--eds-dur-card) var(--eds-ease),
		box-shadow var(--eds-dur-card) var(--eds-ease);
}

/* --- the two themes ------------------------------------------------------ */

/* Dark pill: worn over the light sections. */
.eds-narrative__pill[data-theme="dark"] {
	--eds-narrative-bg: rgba(11, 19, 35, .94);
	--eds-narrative-border: rgba(255, 255, 255, .14);
	--eds-narrative-ink: #DCE6F5;
	--eds-narrative-shadow:
		inset 0 1px 0 0 rgba(255, 255, 255, .06),
		0 10px 30px -10px rgba(0, 0, 0, .9);
	--eds-narrative-dot: #4D93FF;
	--eds-narrative-dot-ring: rgba(77, 147, 255, .2);
	--eds-narrative-dot-glow: rgba(77, 147, 255, .8);
}

/* Light pill: worn over the dark sections, and the default — the hero the
   pill starts on is dark, so this is already correct before JS runs. */
.eds-narrative__pill,
.eds-narrative__pill[data-theme="light"] {
	--eds-narrative-bg: rgba(255, 255, 255, .96);
	--eds-narrative-border: rgba(37, 99, 235, .34);
	--eds-narrative-ink: #0B1220;
	--eds-narrative-shadow:
		inset 0 1px 0 0 rgba(255, 255, 255, .9),
		0 1px 2px 0 rgba(11, 18, 32, .06),
		0 12px 28px -16px rgba(11, 18, 32, .42);
	--eds-narrative-dot: #2563EB;
	--eds-narrative-dot-ring: rgba(37, 99, 235, .16);
	--eds-narrative-dot-glow: rgba(37, 99, 235, .45);
}

/* --- the message swap ---------------------------------------------------- */

/* Out and back in, 140ms each way: the words leave downward and return. */
.eds-narrative__text {
	display: block;
	transition:
		opacity 140ms var(--eds-ease),
		transform 140ms var(--eds-ease);
}

.eds-narrative__pill.is-swapping .eds-narrative__text {
	opacity: 0;
	transform: translateY(6px);
}

/* --- mobile -------------------------------------------------------------- */

/*
 * Under 768px the messages are long enough to wrap to two lines and the pill
 * would sit over the content for the whole scroll. It reverts to an inline
 * hero label: static, in place, scrolling away with the hero. narrative.js
 * drops the observer at the same breakpoint, so it keeps the hero message.
 */
@media (max-width: 767px) {
	.eds-narrative__pill {
		position: static;
		font-size: 11.5px;
		letter-spacing: .12em;
	}
}

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

/*
 * The global reduce block already collapses every transition duration. All
 * that is left is the 6px travel, which would otherwise become a jump.
 */
@media (prefers-reduced-motion: reduce) {
	.home .eds-narrative__pill.is-swapping .eds-narrative__text {
		transform: none;
	}
}

/* ==========================================================================
   20. Services section stage  — HOMEPAGE EXPERIMENT, scoped to .home only
   The services intro flies in from beyond the right edge of the window, then
   the four cards rise from below in reading order. motion.js finds the blocks
   structurally and adds the classes, so nothing here depends on the copy and
   both effects survive translation.

   Only transform and opacity animate. Without JS, or under reduced motion,
   none of these classes is ever added and everything is simply visible.
   ========================================================================== */

/*
 * The intro starts a whole viewport to the side, so without clipping the
 * document would be that much wider. Clipping at the section — which is
 * full-bleed — means the text is hidden exactly up to the window edge and
 * enters from there, which is the point. overflow-y stays visible, so the
 * section's own tilted cut (drawn 1px above its top edge) and the cards' hover
 * shadows are untouched, and once the animation settles every transform is
 * none, so nothing is ever clipped at rest.
 */
.home .eds-stage-section {
	overflow-x: clip;
}

/* --- intro: off-screen left, in to the right ----------------------------- */

.home .eds-stage-text {
	/* -100vw clears the window at every width without a breakpoint: the block
	   starts at the content edge, so moving it a full viewport always carries
	   its right edge past the left edge of the window. */
	--eds-stage-x: -100vw;
	--eds-stage-y: 18px;
	--eds-stage-dur: 1700ms;
	--eds-stage-step: 220ms;
}

.home .eds-stage-text > .wp-block-group__inner-container > * {
	opacity: 0;
	transform: translate3d(var(--eds-stage-x), var(--eds-stage-y), 0);
	will-change: opacity, transform;
}

.home .eds-stage-text.is-staged > .wp-block-group__inner-container > * {
	opacity: 1;
	transform: none;
	will-change: auto;
	transition:
		opacity var(--eds-stage-dur) var(--eds-stage-fade),
		transform var(--eds-stage-dur) var(--eds-stage-ease);
}

/* Eyebrow leads, heading follows, paragraph last. */
.home .eds-stage-text.is-staged > .wp-block-group__inner-container > *:nth-child(2) {
	transition-delay: var(--eds-stage-step);
}

.home .eds-stage-text.is-staged > .wp-block-group__inner-container > *:nth-child(3) {
	transition-delay: calc(var(--eds-stage-step) * 2);
}

/* --- cards: rise from below ---------------------------------------------- */

/*
 * On the column, not on .eds-card: a settled `transform: none` on the card
 * would out-specify .eds-card:hover and cancel the hover lift. The column has
 * no transform of its own, so the two never meet.
 *
 * transition-delay is set inline by motion.js from each column's document
 * order, which is why the shorthand below can reset it without any effect.
 */
.home .eds-stage-card {
	/*
	 * A percentage, not a pixel count: translate resolves it against the card's
	 * own width, so the same 40% is 218px at 1440, 187px at 1024 and 136px at
	 * 768 without a breakpoint for each. The cards genuinely start gathered over
	 * the middle of the grid rather than nudged towards it.
	 */
	--eds-card-x: 40%;

	/*
	 * The slide is the effect, so the fade must not hide it. At 200ms the card
	 * is solid almost at once and the remaining 1300ms of travel is all
	 * watchable; matching the two durations is what made the movement
	 * disappear behind its own fade.
	 */
	--eds-card-fade: 150ms;
	--eds-card-dur: 1500ms;
	--eds-card-ease: cubic-bezier(.4, 0, .2, 1);

	/* Direction as a sign, not as a second distance: a custom property cannot
	   be redefined from its own value — that is a cycle, and it makes the whole
	   transform invalid rather than flipping it. */
	--eds-card-sx: 1;

	/*
	 * Not 0: the card has to be visible enough that the slide out of the centre
	 * is the thing being watched, not a fade that happens to move.
	 *
	 * Not higher either. Gathered at 40% the two columns overlap by some 400px,
	 * and while both are semi-transparent their headings read through each
	 * other. Once opaque the near card simply covers the far one and the pair
	 * look like a stack fanning open, so the fade is kept short and starts low:
	 * the see-through window is about a tenth of the slide.
	 */
	opacity: .2;
	transform: translate3d(calc(var(--eds-card-x) * var(--eds-card-sx)), 0, 0);
	will-change: opacity, transform;
}

/*
 * The four columns wrap into a 2x2, so odd is the left-hand column and even is
 * the right-hand one, on both rows. Each card starts displaced towards the
 * middle of the grid and travels straight out to its own side: the two columns
 * open away from the centre together.
 *
 * Horizontal only — no translateY, no rotation, no scale — so the path is a
 * straight line out from the middle and nothing reads as rising.
 */
.home .eds-stage-card:nth-child(even) {
	--eds-card-sx: -1;
}

/*
 * Below 768px the columns collapse into one, so there is no left and right
 * column left to open. The same odd/even split becomes a restrained alternation
 * — odd from the right, even from the left — which keeps the outward feel at a
 * distance that cannot reach the viewport edge.
 */
@media (max-width: 767px) {
	.home .eds-stage-card {
		--eds-card-x: 6%;
	}
}

.home .eds-stage-card.is-staged {
	opacity: 1;
	transform: none;
	will-change: auto;

	/*
	 * Opacity rides the movement curve, so the card is exactly as visible as it
	 * is far along and the travel is never spent behind a fade.
	 */
	transition:
		opacity var(--eds-card-fade) var(--eds-card-ease),
		transform var(--eds-card-dur) var(--eds-card-ease);

	/* All four leave together: with the motion purely horizontal there are no
	   rows to sequence, and the pair of columns opening as one is the point. */
	transition-delay: 0s;
}

/* --- why-work-with-us rows: in from the right ---------------------------- */

/*
 * One unit per row: .eds-reason carries the number badge as its ::before and
 * wraps the heading and copy, so moving it moves all three together.
 *
 * Same duration, stagger and curve as the services intro directly above, and
 * opacity rides the movement curve so the row is as visible as it is far along
 * — the travel is meant to be watched, not to finish before it can be seen.
 */
.home .eds-stage-row {
	--eds-row-x: 180px;
	--eds-row-dur: 1900ms;

	/*
	 * 500ms, not the 220ms the services intro uses. Those three elements sit
	 * together in one block, so a short stagger reads as one movement; these
	 * four rows are spread down ~600px and are scrolled past one at a time, so
	 * the gap has to be long enough that row 04 is still travelling when the
	 * reader arrives at it. Row 04 starts at 1500ms and settles at 3400ms.
	 */
	--eds-row-step: 500ms;

	opacity: 0;
	transform: translate3d(var(--eds-row-x), 0, 0);
	will-change: opacity, transform;
}

@media (max-width: 767px) {
	.home .eds-stage-row {
		--eds-row-x: 100px;
	}
}

.home .eds-stage-row.is-staged {
	opacity: 1;
	transform: none;
	will-change: auto;
	transition:
		opacity var(--eds-row-dur) var(--eds-stage-ease),
		transform var(--eds-row-dur) var(--eds-stage-ease);

	/* After the shorthand, which would otherwise reset it. */
	transition-delay: calc(var(--eds-stage-index, 0) * var(--eds-row-step));
}

/* --- process steps: a straight vertical rise with a little depth ---------- */

/*
 * The unit is .eds-step — number, title and copy in one group — never the
 * .wp-block-column around it: the timeline rail and the blue dots are
 * pseudo-elements of that column, so transforming the column would carry the
 * rail along with the step. The column is left untouched and only its child
 * moves, which is what keeps the rail perfectly static.
 *
 * The perspective lives on the column rather than in each transform, so every
 * step is projected from its own centre. A shared vanishing point on the
 * columns block would tip the outer two steps differently from the inner two
 * for the same rotateX, and the four would not settle as one row.
 */
.home .eds-process > .wp-block-column {
	perspective: 1000px;
}

/*
 * Straight up, and only straight up. The transform carries no rotateY and no
 * rotateZ, so there is nothing in it that can move a pixel horizontally: the
 * visual path is vertical from the first frame to the last.
 *
 * rotateX is the one exception and it is safe here, because it tips the block
 * about its own horizontal axis — it foreshortens the step vertically as it
 * rises and changes nothing across. 6deg is enough to read as depth, as though
 * the block were lying back slightly and coming upright, and too little to
 * register as a tilt once it has settled.
 */
.home .eds-stage-step {
	--eds-step-y: 90px;
	--eds-step-rx: 6deg;
	--eds-step-scale: .98;
	--eds-step-dur: 1900ms;

	/*
	 * Local to the steps, so the shared --eds-stage-* tokens — and the services
	 * cards, the intro and the why-work-with-us rows that ride them — are
	 * untouched. See the transition below.
	 */
	--eds-step-ease: cubic-bezier(.4, 0, .2, 1);

	opacity: 0;
	transform:
		translate3d(0, var(--eds-step-y), 0)
		rotateX(var(--eds-step-rx))
		scale(var(--eds-step-scale));
	will-change: opacity, transform;
}

/* A narrower step is a shorter box, so the same rotateX foreshortens a larger
   share of its height and starts to read as a wobble rather than as depth.
   Both the tip and the rise come down a notch; the curve and the timing are
   the same at every width. */
@media (max-width: 767px) {
	.home .eds-stage-step {
		--eds-step-y: 65px;
		--eds-step-rx: 4deg;
		--eds-step-scale: .985;
	}
}

.home .eds-stage-step.is-staged {
	opacity: 1;

	/* `none`, not a written-out identity: the settled step carries no residual
	   tip or scale at all, so nothing is left compositing it in 3D. */
	transform: none;
	will-change: auto;

	/*
	 * One curve for both properties, so the fade is synchronised with the rise
	 * by construction rather than by tuning: the step is exactly as opaque as it
	 * is far along, at every instant.
	 *
	 * .4/0/.2/1 eases in as well as out, which is what the movement needs here.
	 * The flat-tailed ease-outs used elsewhere in this file spend most of their
	 * travel in the first fifth of the duration, so the rise would be over before
	 * it could be watched and the remaining second would be an invisible creep.
	 * This curve spreads the 90px evenly across the 1900ms — no fast initial
	 * jump, no long dead tail. Its second control point sits at y=1, so it
	 * approaches the final value from below and never passes it: no overshoot,
	 * nothing to read as a bounce.
	 */
	transition:
		opacity var(--eds-step-dur) var(--eds-step-ease),
		transform var(--eds-step-dur) var(--eds-step-ease);
}

/* --- process steps: the image -> text card flip --------------------------- */

/*
 * PHASE 2, layered on top of the rise above and deliberately separate from it:
 * the rise moves .eds-step, the flip turns the two faces inside it. Nothing
 * here touches .wp-block-column, so the rail and the dots — which are that
 * column's pseudo-elements — stay put through both phases.
 *
 * No preserve-3d chain. Kadence renders a .wp-block-group__inner-container
 * inside every group block, so the faces are never direct children of the
 * element you would want to rotate, and a preserve-3d flipper would need every
 * wrapper in between to opt in as well. Counter-rotating the two faces about a
 * shared perspective gives the identical picture and depends on nothing but
 * the faces themselves: each turns 180deg the same way, and backface-visibility
 * decides which one the eye gets.
 *
 * Text is the default state, so the section is correct with the stylesheet
 * alone: without JavaScript, and under reduced motion, no class below is ever
 * added and the copy is simply there.
 */
/*
 * THE SHELL. Kadence's inner container for the .eds-step group is the one box
 * both faces share, so it is the card: it owns the size, the frame, the radius,
 * the glow and the clip, and the faces own nothing but their content. That is
 * the whole point — a frame that belonged to the image face was a frame that
 * turned away with it and left the text side bare.
 *
 * Because the shell does not rotate, the card stays framed through the entire
 * flip, including at 90deg where a rotating frame would vanish edge-on. What
 * turns is what is inside the window.
 *
 * Edge, glow and background are the WHAT WE DO cards' own tokens, so the two
 * sections resolve to the same values on this light surface and stay in step
 * if those tokens are ever retuned — including the 1px --eds-tilt-blue edge,
 * which is the blue of the tilted cut both sections sit under.
 */
.home .eds-step > .wp-block-group__inner-container {
	position: relative;
	perspective: 1000px;
	overflow: hidden;
	background-image: var(--eds-glass);
	border: 1px solid var(--eds-tilt-blue);
	border-radius: var(--eds-radius-card);
	box-shadow:
		var(--eds-shadow-card),
		0 0 14px rgba(var(--eds-tilt-blue-rgb), .3),
		0 0 30px rgba(var(--eds-tilt-blue-rgb), .18);
	transition: box-shadow var(--eds-dur-card) var(--eds-ease);
}

/*
 * Left alone, each card is only as tall as its own paragraph — 176/176/149/122
 * at 1440 — so four images of four different heights would sit along the rail
 * and never read as one set. The columns are flex items and already stretch to
 * the tallest, so passing that height down to the card squares the row up.
 * Only where the four sit side by side: once they stack they are standalone
 * cards and each should be its own height again.
 */
@media (min-width: 1025px) {
	.home .eds-step,
	.home .eds-step > .wp-block-group__inner-container {
		height: 100%;
	}
}

/*
 * Between 600px and the point the four go side by side, the card is as wide as
 * the page but only as tall as its own paragraph — 928x95 at 1024 — and an
 * image cropped into that is a sliver with its subject cut away. Capping the
 * card is what fixes it, rather than a floor on its height: a floor would pad
 * the permanent text state out with dead space to serve a four-second intro,
 * and making the floor conditional on the image face would jump the card's
 * height mid-flip. This keeps one box for both faces, so the flip stays
 * coherent, the height never changes, and the 16px copy gets a readable
 * measure instead of a 900px line.
 *
 * Below 600px nothing is capped: a phone card is already about 310x148, which
 * frames these photographs well on its own.
 */
@media (min-width: 600px) and (max-width: 1024px) {
	.home .eds-step {
		max-width: 420px;
	}
}

.home .eds-step__face {
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
}

/*
 * The text face stays in normal flow and is the only thing that sets the card's
 * height — in every state, in both phases. The image face is taken out of flow
 * on top of it, so a flip cannot change the box and there is nothing for the
 * layout to shift by. Text is also first in the DOM, so assistive technology
 * reads the copy rather than the picture regardless of which face is showing.
 */
.home .eds-step__face--text {
	transform: none;
}

/*
 * The image face carries no border, no radius and no shadow of its own: the
 * shell draws all three once, for both sides. Doubling any of them here is
 * exactly what produced the seam and the second edge.
 */
.home .eds-step__face--image {
	position: absolute;
	inset: 0;
	margin: 0;
	transform: rotateY(180deg);
}

/* The shell's overflow does the rounding, so the picture needs no radius of
   its own — and must not have one, or its outer curve would sit a pixel inside
   the shell's and leave a hairline in each corner. */
.home .eds-step__face--image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The text side of the same card. It stays in normal flow, so it is still what
 * gives the shell its height, and its padding is what stops the copy sitting
 * against the frame. No background and no border here: both belong to the
 * shell, and a second border is precisely what this rule must not add.
 */
.home .eds-step__face--text {
	padding: var(--eds-s5);
}

@media (max-width: 767px) {
	.home .eds-step__face--text {
		padding: var(--eds-s4);
	}
}

/*
 * A shallow wash from the foot of the picture, so four stock photographs of
 * different exposures read as one set. The blue hairline that used to be here
 * is gone: the real border above does that job now, on the outside of the
 * image rather than painted over it.
 *
 * The second, steeper wash down from the top is what the step tag below is
 * readable on. It is the same idea and the same colour as the foot, kept
 * short — out by 38% of the height — so it darkens the band the two lines of
 * the tag occupy and leaves the subject of every photograph untouched. Doing
 * it here rather than behind the tag is the point: a panel drawn around the
 * words would read as a second card sitting on the first, which is exactly
 * what this section must not grow.
 */
.home .eds-step__face--image::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image:
		linear-gradient(to bottom, rgba(11, 18, 32, .52), rgba(11, 18, 32, 0) 38%),
		linear-gradient(to top, rgba(11, 18, 32, .28), rgba(11, 18, 32, 0) 55%);
	pointer-events: none;
}

/* --- process steps: the step tag on the image face ------------------------ */

/*
 * Which step this picture belongs to, top-left, number over title. motion.js
 * clones both out of the card's own text face, so these rules dress nodes that
 * already carry .eds-step__num and h3 and are already translated — which is
 * why every selector here has to out-specify the text-face rules those two
 * classes normally resolve to, further up this stylesheet.
 *
 * Restrained on purpose: no box, no chip, no border. The scrim above carries
 * the contrast and the text-shadows cover the case of a pale photograph, so
 * the picture stays the thing being looked at.
 */
.home .eds-step__face--image .eds-step__tag {
	position: absolute;
	top: var(--eds-s4);
	left: var(--eds-s4);
	max-width: calc(100% - var(--eds-s4) * 2);

	/*
	 * Above the wash, not under it. ::after is generated as the last child box
	 * of the face, so being appended after it in the DOM is not enough — with
	 * both boxes positioned and neither raised, the scrim would paint over the
	 * words and take the white down with it. One step of z-index settles it.
	 */
	z-index: 1;

	/* The tag is painted, never touched: hover belongs to the card, and a
	   pointer crossing these two lines must not read as leaving it. */
	pointer-events: none;
}

.home .eds-step__face--image .eds-step__num {
	margin: 0 0 3px;
	font-size: 12px;
	letter-spacing: .18em;

	/* White, not --eds-accent: the accent is a mid blue tuned for the white
	   text face and it disappears into a photograph. */
	color: #FFFFFF;
	opacity: .78;
	text-shadow: 0 1px 6px rgba(11, 18, 32, .65);
}

.home .eds-step__face--image .eds-step__tag h3 {
	margin: 0;
	font-size: 19px;
	line-height: 1.2;
	color: #FFFFFF;
	text-shadow:
		0 1px 3px rgba(11, 18, 32, .55),
		0 2px 12px rgba(11, 18, 32, .65);
}

/* The phone card is about 310x148, so the tag comes down a notch with it and
   keeps the same share of the picture rather than crowding it. */
@media (max-width: 767px) {
	.home .eds-step__face--image .eds-step__tag {
		top: var(--eds-s3);
		left: var(--eds-s3);
		max-width: calc(100% - var(--eds-s3) * 2);
	}

	.home .eds-step__face--image .eds-step__num {
		font-size: 11px;
	}

	.home .eds-step__face--image .eds-step__tag h3 {
		font-size: 17px;
	}
}

/*
 * Transitions arrive with .eds-step--flippable, which motion.js adds a frame
 * after .is-showing-image. That order is the point: the opening switch to the
 * image face has to be instantaneous, or the visitor would see a flip before
 * the cards have even risen.
 */
.home .eds-step--flippable .eds-step__face {
	--eds-flip-dur: 1000ms;
	--eds-flip-ease: cubic-bezier(.4, 0, .2, 1);

	transition: transform var(--eds-flip-dur) var(--eds-flip-ease);
}

/* Both faces turn the same way through the same 180deg — text 0 -> -180 as the
   image goes 180 -> 0 — so the pair reads as one card turning, not as two
   elements swapping. */
.home .eds-step.is-showing-image .eds-step__face--text {
	transform: rotateY(-180deg);
}

.home .eds-step.is-showing-image .eds-step__face--image {
	transform: none;
}

/*
 * PHASE 3, the return to the pictures. motion.js adds .is-returning to the
 * block for the length of this phase only.
 *
 * Two things change, and only for these few seconds. The turn is quicker —
 * 700ms against the opening's 1000 — because the opening is revealing
 * something and the close is only putting it back. And each card carries a
 * delay off its own --eds-return-index, so the four run 220ms apart instead
 * of together: one gesture travelling down the row rather than four cards
 * flipping at once.
 *
 * Redeclaring --eds-flip-dur here is enough to retime the transition declared
 * on the lower-specificity rule above, because a custom property resolves
 * per element against whichever rule won it.
 *
 * Both come back off when the phase ends, so hover runs at the normal 1000ms
 * with nothing queued in front of it.
 */
.home .eds-process.is-returning .eds-step__face {
	--eds-flip-dur: 700ms;

	transition-delay: calc(var(--eds-return-index, 0) * 220ms);
}

/*
 * INTERACTIVE. motion.js adds .is-interactive to the process block only once
 * the whole automatic sequence has finished — including phase 3, so not until
 * every card is back on its picture — so a pointer resting on any card during
 * the choreography cannot pull it out: these rules simply do not match yet.
 *
 * The section now rests on the image, so hover turns the other way: it takes
 * the card to its text and mouseleave returns it to the picture. These are
 * the two resting transforms swapped, and they out-specify .is-showing-image
 * (six classes against four), which is what lets a hover override the state
 * the sequence left the card in and what lets it fall straight back on leave.
 */
@media (hover: hover) and (pointer: fine) {
	.home .eds-process.is-interactive .eds-step:hover .eds-step__face--text,
	.home .eds-process.is-interactive .eds-step:focus-within .eds-step__face--text {
		transform: none;
	}

	.home .eds-process.is-interactive .eds-step:hover .eds-step__face--image,
	.home .eds-process.is-interactive .eds-step:focus-within .eds-step__face--image {
		transform: rotateY(180deg);
	}

	/* Edge stays dark; only the light around it comes up — the same step the
	   service cards take on hover, from the same two tokens. On the shell, so
	   the whole card brightens rather than whichever face happens to face out. */
	.home .eds-process.is-interactive .eds-step:hover > .wp-block-group__inner-container,
	.home .eds-process.is-interactive .eds-step:focus-within > .wp-block-group__inner-container {
		box-shadow:
			var(--eds-shadow-card-hover),
			0 0 18px rgba(var(--eds-tilt-blue-rgb), .45),
			0 0 38px rgba(var(--eds-tilt-blue-rgb), .28);
	}
}

/*
 * motion.js already bails out before adding any of these classes under reduced
 * motion, so this only matters if the preference is turned on after they land:
 * everything sits at its final position, at full opacity, with no delay.
 */
@media (prefers-reduced-motion: reduce) {
	.home .eds-stage-text > .wp-block-group__inner-container > *,
	.home .eds-stage-card,
	.home .eds-stage-row,
	.home .eds-stage-step {
		opacity: 1;
		transform: none;
		transition: none;
		transition-delay: 0s !important;
	}

	/*
	 * The faces are deliberately NOT overridden here any more.
	 *
	 * They used to be forced to text-forward, because reduced motion ran no
	 * JavaScript at all and the stylesheet's own default — text forward, image
	 * turned away — was also where the sequence ended. The sequence ends on the
	 * picture now, so motion.js puts .is-showing-image on each card up front
	 * instead (see processFinal), and overriding it here would undo exactly the
	 * state this block is supposed to be showing.
	 *
	 * The rules the cards fall back on are the ordinary ones further up, so the
	 * faces still keep a resting transform each and are never flattened to none
	 * on top of one another. Killing the transition below is what makes the
	 * card simply BE on its image rather than travel there: there is no flip to
	 * see, at load or if the preference is switched on later.
	 *
	 * With .is-showing-image absent — JavaScript off entirely — the default is
	 * unchanged and the card shows its text, which is the right thing to fail
	 * to: the copy is the content, and an unlabelled photograph is not.
	 */
	.home .eds-step__face {
		transition: none;
		transition-delay: 0s !important;
	}
}

/* ==========================================================================
   21. Process opening  — opt-in, via .eds-timeline
   The four-step block opens outward from its own centre: a soft-edged mask
   grows from the middle to both edges while the block spreads the last few
   per cent of its width, and the outer columns drift out with it.

   One gesture on one element. Nothing here staggers, and nothing animates the
   rail, the dots or the steps individually — they are carried by the block.

   Opt-in by markup rather than by page: .eds-process and .eds-step also appear
   on the services, web-design, SEO and AI pages, and the homepage runs its own
   system on the same classes. Only a block carrying .eds-timeline is touched.

   Nothing applies until motion.js adds .is-armed, so without JavaScript — and
   under reduced motion, where motion.js bails before arming — the section
   renders exactly as it does today, fully open.
   ========================================================================== */

.eds-timeline {
	/*
	 * Two clocks, deliberately. The block has to be on screen almost at once,
	 * so the fade is short; the opening is what should be watched, so it runs
	 * roughly ten times longer. Sharing one duration meant a longer opening
	 * only delayed the block's arrival.
	 */
	--eds-tl-fade-dur: 150ms;
	--eds-tl-open-dur: 1400ms;

	--eds-tl-ease: cubic-bezier(0, 0, .2, 1);

	/* The spread. 7% is enough to feel the block widen and small enough that
	   the type is never meaningfully squashed on the way. */
	--eds-tl-scale: .93;

	/*
	 * The unfold. The outer pair start this far in towards the centre, the
	 * inner pair a third of it, so the four move as one opening fan rather than
	 * four objects sliding apart. 28px against a 1120px block is under 3% of
	 * the width — readable as a gesture, not as four separate slides.
	 */
	--eds-tl-drift: 28px;
}

/*
 * Stacked: the columns are full width, so lateral drift would be meaningless
 * and the spread comes right down. The mask still opens from the centre to
 * both edges, so the gesture is the same one.
 */
@media (max-width: 1024px) {
	.eds-timeline {
		--eds-tl-scale: .97;
		--eds-tl-drift: 0px;
	}
}

/*
 * The mask is a band with soft ends, grown from nothing at the centre. Because
 * the softness is part of the gradient rather than the edge of a clip, both
 * edges stay feathered at every size instead of cutting words in half.
 *
 * It finishes at 140%, not 100%: at 100% the gradient's own transparent tails
 * would sit over the first and last 8% of the block and permanently fade the
 * outside of steps 01 and 04. The band has to end up wider than the box it
 * masks for the settled state to be completely clean.
 */
.eds-timeline.is-armed {
	opacity: 0;
	transform: scaleX(var(--eds-tl-scale));
	transform-origin: 50% 50%;

	-webkit-mask-image: linear-gradient(to right, transparent 0, #000 8%, #000 92%, transparent 100%);
	        mask-image: linear-gradient(to right, transparent 0, #000 8%, #000 92%, transparent 100%);
	-webkit-mask-repeat: no-repeat;
	        mask-repeat: no-repeat;
	-webkit-mask-position: center;
	        mask-position: center;
	-webkit-mask-size: 0% 100%;
	        mask-size: 0% 100%;

	will-change: opacity, transform;
}

.eds-timeline.is-armed.is-running {
	opacity: 1;
	transform: none;
	-webkit-mask-size: 140% 100%;
	        mask-size: 140% 100%;
	will-change: auto;

	/* Opacity on its own short clock and no delay, so the block is simply
	   there; the stretch keeps the long one. */
	transition:
		opacity var(--eds-tl-fade-dur) var(--eds-tl-ease),
		transform var(--eds-tl-open-dur) var(--eds-tl-ease),
		-webkit-mask-size var(--eds-tl-open-dur) var(--eds-tl-ease),
		mask-size var(--eds-tl-open-dur) var(--eds-tl-ease);
}

/*
 * The outer pair start furthest in, the inner pair a third as far, so the
 * spacing opens out proportionally. Keyed off the column, not the step, so
 * each dot travels with its own text and the group stays intact.
 */
.eds-timeline.is-armed > .wp-block-column:nth-child(1) {
	transform: translate3d(var(--eds-tl-drift), 0, 0);
}

.eds-timeline.is-armed > .wp-block-column:nth-child(2) {
	transform: translate3d(calc(var(--eds-tl-drift) / 3), 0, 0);
}

.eds-timeline.is-armed > .wp-block-column:nth-child(3) {
	transform: translate3d(calc(var(--eds-tl-drift) / -3), 0, 0);
}

.eds-timeline.is-armed > .wp-block-column:nth-child(4) {
	transform: translate3d(calc(var(--eds-tl-drift) * -1), 0, 0);
}

.eds-timeline.is-armed.is-running > .wp-block-column {
	transform: none;
	transition: transform var(--eds-tl-open-dur) var(--eds-tl-ease);
}

/*
 * motion.js bails out before arming under reduced motion, so this only matters
 * if the preference is switched on after the section has been armed: the block
 * is open, unmasked and in place, with nothing left running.
 */
@media (prefers-reduced-motion: reduce) {
	.eds-timeline.is-armed,
	.eds-timeline.is-armed > .wp-block-column {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.eds-timeline.is-armed {
		-webkit-mask-image: none;
		        mask-image: none;
	}
}

/* ==========================================================================
   Cursor follower

   A 22px dot filled with --eds-tilt-fill, the divider's own gradient, that
   trails the pointer. motion.js creates the single element and drives it; it is never created under
   reduced motion or on a coarse pointer, so this block is only a fallback
   guard. Centring is done with a static negative margin, which keeps the
   per-frame work to one transform.
   ========================================================================== */

@media (hover: hover) and (pointer: fine) {
	.eds-cursor {
		position: fixed;
		top: 0;
		left: 0;
		width: 22px;
		height: 22px;
		margin: -11px 0 0 -11px;
		border-radius: 50%;
		background-image: var(--eds-tilt-fill);
		box-shadow: 0 0 10px rgba(var(--eds-tilt-blue-rgb), .35);
		opacity: 0;
		pointer-events: none;
		z-index: 9999;
		transition: opacity 150ms var(--eds-ease);
		will-change: transform;
	}

	.eds-cursor.is-visible {
		opacity: .85;
	}
}
