/* =====================================================
 * AppAgentix - motion layer
 *
 * Loads AFTER the page stylesheet, lp-components.css and the premium
 * skin, so it wins the cascade over the motion rules already in those
 * files without any of them being edited.
 *
 * Two rules govern everything here:
 *
 *   1. Only transform, opacity, clip and colour are animated. Nothing
 *      animates a property that triggers layout.
 *   2. Nothing runs off screen. Entry animations fire once and are then
 *      unobserved; the handful of continuous animations (two marquees,
 *      the CTA aurora) are gated on an .is-visible class that one shared
 *      IntersectionObserver toggles.
 *
 * Reduced motion is handled ONCE, at the foot of this file, by resetting
 * the tokens every utility reads. No section carries its own
 * reduced-motion branch.
 *
 * Remove the enqueue in inc/scripts.php to revert the whole layer.
 *
 * Contents
 *   1.  Tokens
 *   2.  Reveal engine
 *   3.  Viewport gating for continuous motion
 *   4.  Paint containment
 *   5.  Hero
 *   6.  Stats
 *   7.  Clients
 *   8.  Why Atlanta
 *   9.  Services (bento)
 *   10. Process
 *   11. Tech stack
 *   12. AI
 *   13. Pricing
 *   14. Industries
 *   15. CTA bands
 *   16. Success stories
 *   17. Why choose / Awards
 *   18. FAQ
 *   19. Reduced motion
 * ===================================================== */

/* =====================================================
 * 1. Tokens
 *
 * Deliberately namespaced --ao-m-* rather than reusing the premium
 * skin's --ao-dur / --ao-ease: those drive existing hover transitions
 * across the page, and re-pointing them would change motion this layer
 * never touched.
 * ===================================================== */

:root {
	--ao-m-dur: .62s;                              /* entry reveals            */
	--ao-m-dur-mid: .28s;                          /* state changes            */
	--ao-m-dur-fast: .18s;                         /* hover, focus             */
	--ao-m-ease: cubic-bezier(.22, 1, .36, 1);     /* fast out, long settle    */
	--ao-m-stagger: 60ms;                          /* between siblings         */
	--ao-m-y: 22px;                                /* reveal travel, vertical  */
	--ao-m-x: 26px;                                /* reveal travel, lateral   */

	/* Approved palette, referenced by name throughout this file. */
	--ao-m-orange: #FFA15C;
	--ao-m-orange-fill: #FFEEE1;
	--ao-m-blue: #8347EC;
	--ao-m-blue-fill: #DFCDFF;
}

/* =====================================================
 * 2. Reveal engine
 *
 * .lp-reveal already ships in the page stylesheet and is already wired
 * to an observer. This re-points it at the tokens and adds the
 * variants, so existing markup keeps working and new markup opts into a
 * direction with data-reveal.
 *
 * Delay comes from either --lp-delay (the existing per-element inline
 * value) or --i (a stagger index emitted by PHP). --i costs no inline
 * style bytes per element beyond the integer and needs no JavaScript.
 * ===================================================== */

.lp-reveal,
[data-reveal] {
	opacity: 0;
	transform: translate3d(0, var(--ao-m-y), 0);
	transition:
		opacity var(--ao-m-dur) var(--ao-m-ease),
		transform var(--ao-m-dur) var(--ao-m-ease);
	transition-delay: var(--lp-delay, calc(var(--i, 0) * var(--ao-m-stagger)));
}

.lp-reveal.is-in,
[data-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* Variants. Each only re-points the resting transform. */
[data-reveal="fade"]        { transform: none; }
[data-reveal="slide-left"]  { transform: translate3d(calc(var(--ao-m-x) * -1), 0, 0); }
[data-reveal="slide-right"] { transform: translate3d(var(--ao-m-x), 0, 0); }
[data-reveal="scale"]       { transform: scale(.96); }

/* "none" is a marker, not an animation: the element is observed purely
   so it receives .is-in, which its children then key off. Used by the
   stats grid, the industries diagram and the cost axis, where the
   container must stay visible while its parts arrive in sequence. */
[data-reveal="none"] {
	opacity: 1;
	transform: none;
	transition: none;
}

/* Word-level mask, used by the hero heading. The word sits inside a
   clipping span so it rises from its own baseline rather than fading in
   place. Padding on the clip keeps descenders from being sheared. */
.ao-line {
	display: inline-block;
	overflow: hidden;
	vertical-align: bottom;
	padding-bottom: .12em;
	margin-bottom: -.12em;
}

.ao-line > span {
	display: inline-block;
	transform: translate3d(0, 105%, 0);
	transition: transform var(--ao-m-dur) var(--ao-m-ease);
	transition-delay: calc(var(--i, 0) * 34ms);
}

.is-in .ao-line > span,
.ao-line.is-in > span {
	transform: none;
}

/* ---------------------------------------------------------------------
 * 2a. Without the script, nothing waits for it
 *
 * The rules above hide reveal content until the observer shows it. That
 * is only safe while the script can run, so the hidden states apply only
 * under html.ao-js - a flag set in <head> (inc/scripts.php) and withdrawn
 * at load if appagentix-motion.js never ran. Without it, every reveal
 * shows its finished state: the same list the reduced-motion block at
 * the foot of this file renders complete.
 * ------------------------------------------------------------------ */

html:not(.ao-js) .lp-reveal,
html:not(.ao-js) [data-reveal],
html:not(.ao-js) .lp-ai__node,
html:not(.ao-js) .lp-ind-node,
html:not(.ao-js) .lp-stats-band__node,
html:not(.ao-js) .lp-chain__node {
	opacity: 1 !important;
	transform: none !important;
	transition: none !important;
}

html:not(.ao-js) .ao-line > span,
html:not(.ao-js) .lp-stats-band__grid::after,
html:not(.ao-js) .lp-costaxis__bar,
html:not(.ao-js) .lp-ind-node-connector,
html:not(.ao-js) .lp-chain__link::before {
	transform: none !important;
	transition: none !important;
}

/* ---------------------------------------------------------------------
 * 2b. Homepage enrichment: data-ao-rise
 *
 * Finer steps inside homepage sections, tagged by appagentix-motion.js
 * (only below the fold, only with JavaScript and full motion). Three
 * rises, one rhythm: up (fade + 22px), fade, and scale (fade + 98%) for
 * visual panels. Siblings stagger 60ms apart, capped at five steps so a
 * long row never makes the last item wait.
 *
 * An animation, not a transition, and on the individual `translate` and
 * `scale` properties rather than `transform`: the elements tagged include
 * tab buttons and cards that already transition their own colours and
 * transform on hover, and neither is overridden. Only the "from" frame is
 * declared, so each element settles on its own opacity and position.
 * ------------------------------------------------------------------ */

[data-ao-rise]:not(.is-in) {
	opacity: 0;
}

[data-ao-rise].is-in {
	animation: ao-rise-up var(--ao-m-dur) var(--ao-m-ease) backwards;
	animation-delay: calc(min(var(--ao-rise-i, 0), 5) * var(--ao-m-stagger));
}

[data-ao-rise="fade"].is-in {
	animation-name: ao-rise-fade;
}

[data-ao-rise="scale"].is-in {
	animation-name: ao-rise-scale;
}

/* The footer is reached last and holds the links people come for:
   it settles faster than the sections above it. */
.tta-footer [data-ao-rise].is-in {
	animation-duration: .5s;
}

@keyframes ao-rise-up {
	from {
		opacity: 0;
		translate: 0 var(--ao-m-y);
	}
}

@keyframes ao-rise-fade {
	from {
		opacity: 0;
	}
}

@keyframes ao-rise-scale {
	from {
		opacity: 0;
		scale: .98;
	}
}

/* ---------------------------------------------------------------------
 * 2c. Homepage hover feedback
 *
 * The two homepage cards that had none. Pointer devices only, as the
 * page's other card hovers are; colour and shadow only - the testimonial
 * cards sit in a clipping slider, where a lift would be cut off.
 * ------------------------------------------------------------------ */

.ao-tst__card {
	transition: box-shadow var(--ao-m-dur-mid) var(--ao-m-ease);
}

@media (hover: hover) and (pointer: fine) {

	.ao-tst__card:hover {
		box-shadow: 0 26px 52px -28px rgba(74, 40, 140, .85);
	}

	.ao-cap__card:not(.is-open):hover {
		background: rgba(131, 71, 236, .04);
	}
}

/* =====================================================
 * 3. Viewport gating for continuous motion
 *
 * The three infinite animations on this page ran for the life of the
 * document regardless of whether their section was on screen. They now
 * idle until the observer marks the section visible.
 *
 * will-change is removed at rest: a permanently promoted layer costs
 * memory on every frame the page paints, not just while it moves.
 * ===================================================== */

.lp-techm__track,
.lp-clients-track {
	animation-play-state: paused;
	will-change: auto;
}

.lp-techm.is-visible .lp-techm__track,
.lp-clients.is-visible .lp-clients-track {
	animation-play-state: running;
	will-change: transform;
}

/* =====================================================
 * 4. Paint containment
 *
 * content-visibility: auto on the below-fold sections is the obvious
 * next win here and is deliberately NOT taken yet.
 *
 * It only pays off when contain-intrinsic-size is close to each
 * section's real height. Guess it, and every section snaps to its true
 * size as it is first rendered, which moves the scrollbar under the
 * reader - the exact symptom this work is meant to avoid. The sections
 * on this page range from roughly 700px to well over 2000px, so one
 * shared placeholder cannot serve them.
 *
 * To finish it: measure each section's height at 1440px and at 390px in
 * a browser, then add one rule per section with its own
 * contain-intrinsic-size. Until those numbers exist, the page is better
 * off without it.
 * ===================================================== */

/* =====================================================
 * 5. Hero
 *
 * The only section on the page with no scroll-driven behaviour at all.
 * Everything here runs from a single class the script adds on the first
 * frame, so nothing above the fold waits on an observer.
 * ===================================================== */

.lp-hero .lp-hero-copy > * {
	--ao-m-y: 18px;
}

.lp-hero-aside {
	--ao-m-x: 34px;
	transform: translate3d(var(--ao-m-x), 14px, 0);
}

.lp-hero-aside.is-in {
	transform: none;
}

/* The focused field is the only thing on the form that animates. It
   doubles as the accessible focus indicator, so the form carries no
   decorative motion at rest. */
.lp-hero-aside input,
.lp-hero-aside select,
.lp-hero-aside textarea {
	transition:
		border-color var(--ao-m-dur-fast) ease,
		box-shadow var(--ao-m-dur-fast) ease;
}

.lp-hero-aside input:focus-visible,
.lp-hero-aside select:focus-visible,
.lp-hero-aside textarea:focus-visible {
	border-color: var(--ao-m-blue);
	box-shadow: 0 0 0 4px rgba(131, 71, 236, .16);
}

/* =====================================================
 * 6. Stats
 *
 * The four figures were four separate numbers. One rule drawn beneath
 * them, with a node landing under each, binds them into a single
 * statement. scaleX on a composited layer; no width animation.
 * ===================================================== */

/* The track and its fill are the grid's own pseudo-elements: a <ul> may
   only contain list items, so the rule cannot be a real element. */
.lp-stats-band__grid {
	position: relative;
	padding-top: 30px;
}

.lp-stats-band__grid::before,
.lp-stats-band__grid::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	height: 2px;
	border-radius: 2px;
	pointer-events: none;
}

.lp-stats-band__grid::before {
	right: 0;
	background: rgba(255, 255, 255, .1);
}

.lp-stats-band__grid::after {
	width: 100%;
	background: linear-gradient(90deg, var(--ao-m-orange), var(--ao-m-blue));
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 1.15s var(--ao-m-ease);
}

.lp-stats-band__grid.is-in::after {
	transform: scaleX(1);
}

.lp-stats-band__node {
	position: relative;
	display: block;
	width: 9px;
	height: 9px;
	margin: -38px auto 20px;
	border-radius: 50%;
	background: var(--ao-m-orange);
	box-shadow: 0 0 0 5px rgba(255, 161, 92, .16);
	opacity: 0;
	transform: scale(.4);
	transition:
		opacity var(--ao-m-dur-mid) var(--ao-m-ease),
		transform var(--ao-m-dur-mid) var(--ao-m-ease);
	transition-delay: calc(260ms + var(--i, 0) * 110ms);
}

.lp-stats-band__grid.is-in .lp-stats-band__node {
	opacity: 1;
	transform: none;
}

/* Climbing digits must not re-measure the column on every frame. */
.lp-stat-num {
	font-variant-numeric: tabular-nums;
}

/* =====================================================
 * 7. Clients
 * ===================================================== */

.lp-clients-track .lp-brand {
	transition:
		transform var(--ao-m-dur-fast) var(--ao-m-ease),
		background-color var(--ao-m-dur-fast) ease,
		border-color var(--ao-m-dur-fast) ease,
		color var(--ao-m-dur-fast) ease;
}

.lp-clients-track li:hover .lp-brand {
	transform: translateY(-3px);
	background: rgba(255, 255, 255, .1);
	border-color: rgba(255, 161, 92, .55);
	color: #fff;
}

/* =====================================================
 * 8. Why Atlanta
 *
 * The copy holds while the image tiles pass it, so the two columns read
 * as one argument rather than two independent blocks. Native sticky -
 * no scroll handler, and it releases at the section end by itself.
 * ===================================================== */

@media (min-width: 1025px) {
	.lp-splitmedia__grid {
		align-items: start;
	}

	.lp-splitmedia__copy {
		position: sticky;
		top: 112px;
	}

	/* The two media columns travel at slightly different rates. A static
	   offset, not a scroll-linked one: it costs nothing and reads as
	   depth without any parallax machinery. */
	.lp-splitmedia__cols > .lp-splitmedia__item:nth-child(even) {
		transform: translateY(26px);
	}
}

/* The hover scale on these images already ships in lp-components.css and
   is left exactly as it is. What is removed is the permanent
   will-change: four promoted compositor layers held for the life of the
   page so that a hover which may never happen starts a frame sooner.
   The browser promotes on hover perfectly well by itself. */
.lp-splitmedia__item img {
	will-change: auto;
}

/* =====================================================
 * 9. Services (bento)
 *
 * Six identical cards asserted six equal services. The lead service now
 * takes a 2x2 tile and the remaining five sit around it, so the grid
 * carries the hierarchy the copy already implies.
 * ===================================================== */

.lp-cards--bento {
	grid-template-columns: repeat(3, minmax(0, 1fr));
	align-items: stretch;
}

.lp-cards--bento .lp-card--featured {
	grid-column: span 2;
	grid-row: span 2;
	padding: 40px 42px 44px;
	background: linear-gradient(140deg, var(--ao-m-blue) 0%, #6a34d4 100%);
	border-color: transparent;
	color: #fff;
	position: relative;
	overflow: hidden;
	box-shadow: 0 30px 64px -22px rgba(131, 71, 236, .55);
}

/* Warm bloom in the corner: the one place the two accents meet. */
.lp-cards--bento .lp-card--featured::after {
	content: "";
	position: absolute;
	top: -80px;
	right: -70px;
	width: 280px;
	height: 280px;
	border-radius: 50%;
	background: radial-gradient(circle, rgba(255, 161, 92, .38), rgba(255, 161, 92, 0) 68%);
	pointer-events: none;
}

.lp-cards--bento .lp-card--featured > * {
	position: relative;
}

.lp-cards--bento .lp-card--featured .lp-card__title {
	font-size: 27px;
	line-height: 1.25;
	color: #fff;
}

.lp-cards--bento .lp-card--featured .lp-card__text {
	color: rgba(255, 255, 255, .82);
	max-width: 46ch;
}

.lp-cards--bento .lp-card--featured .lp-card__icon {
	background: rgba(255, 255, 255, .14);
	border-color: rgba(255, 255, 255, .28);
	color: #fff;
}

.lp-card__flag {
	display: inline-block;
	align-self: flex-start;
	margin-bottom: 20px;
	padding: 6px 13px;
	border-radius: 999px;
	background: rgba(255, 255, 255, .16);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: .08em;
	text-transform: uppercase;
}

/* Pushed to the foot of the tile so the lead card fills its 2x2 cell
   rather than leaving the extra height as dead space. */
.lp-cards--bento .lp-card--featured .lp-card__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: auto 0 0;
	padding: 24px 0 0;
	list-style: none;
}

.lp-cards--bento .lp-card--featured .lp-card__tags li {
	padding: 6px 13px;
	border-radius: 999px;
	background: rgba(255, 255, 255, .12);
	font-size: 12px;
	font-weight: 500;
}

/* Hover raises one card and quiets the rest. Opacity on the siblings,
   transform on the target - neither touches layout. */
.lp-cards--bento .lp-card {
	transition:
		transform var(--ao-m-dur-mid) var(--ao-m-ease),
		opacity var(--ao-m-dur-mid) ease,
		border-color var(--ao-m-dur-mid) ease,
		box-shadow var(--ao-m-dur-mid) ease;
}

@media (hover: hover) and (pointer: fine) {
	.lp-cards--bento:hover .lp-card:not(:hover) {
		opacity: 1;
	}

	.lp-cards--bento .lp-card:not(.lp-card--featured):hover {
		transform: translateY(-4px);
		border-color: var(--ao-m-orange);
		box-shadow: 0 18px 42px -18px rgba(255, 161, 92, .45);
	}

	.lp-cards--bento .lp-card--featured:hover {
		transform: translateY(-4px);
	}
}

@media (max-width: 1024px) {
	.lp-cards--bento {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.lp-cards--bento .lp-card--featured {
		grid-column: span 2;
		grid-row: span 1;
		padding: 32px 30px 34px;
	}
}

@media (max-width: 720px) {
	.lp-cards--bento {
		grid-template-columns: minmax(0, 1fr);
	}

	.lp-cards--bento .lp-card--featured {
		grid-column: span 1;
	}
}

/* =====================================================
 * 10. Process
 *
 * The intro column was already sticky and already unpinned correctly at
 * the section end. What was missing was state: which phase the reader
 * is on. That is one observer with a reading-line rootMargin, plus a
 * progress line that fills to a percentage set on activation - four
 * writes over the whole section, not one per frame.
 * ===================================================== */

.lp-proc__progress {
	position: absolute;
	left: 23px;
	top: 6px;
	width: 2px;
	border-radius: 2px;
	background: linear-gradient(180deg, var(--ao-m-orange), var(--ao-m-blue));
	height: var(--lp-proc-progress, 0%);
	transition: height .45s var(--ao-m-ease);
	pointer-events: none;
}

.lp-proc__phase {
	transition: opacity var(--ao-m-dur-mid) ease;
}

.lp-proc__badge {
	transition:
		transform var(--ao-m-dur-mid) var(--ao-m-ease),
		background-color var(--ao-m-dur-mid) ease,
		border-color var(--ao-m-dur-mid) ease,
		color var(--ao-m-dur-mid) ease;
}

@media (min-width: 1025px) {
	.lp-proc__rail.is-tracking .lp-proc__phase {
		opacity: .45;
	}

	.lp-proc__rail.is-tracking .lp-proc__phase.is-on {
		opacity: 1;
	}
}

.lp-proc__phase.is-on .lp-proc__badge {
	transform: scale(1.08);
	background: linear-gradient(135deg, rgba(255, 161, 92, 1), rgba(131, 71, 236, 1));
	border-color: var(--ao-m-orange);
	color: var(--ao-m-orange);
}

/* Progressive enhancement: where scroll-driven CSS is supported the fill
   scrubs with the scroll instead of stepping between phases. Not
   Baseline (Firefox stable still has it behind a flag), so it is an
   addition on top of a mechanism that already works everywhere. */
@supports (animation-timeline: view()) {
	@media (min-width: 1025px) and (prefers-reduced-motion: no-preference) {
		.lp-proc__rail {
			view-timeline-name: --ao-proc;
			view-timeline-axis: block;
		}

		.lp-proc__progress {
			height: 100%;
			transform-origin: top center;
			transition: none;
			animation: ao-proc-fill linear both;
			animation-timeline: --ao-proc;
			/* Ends deep into the exit phase so the line is not already
			   full while the last phase is still coming up. */
			animation-range: entry 90% exit 65%;
		}
	}
}

@keyframes ao-proc-fill {
	from { transform: scaleY(0); }
	to   { transform: scaleY(1); }
}

/* =====================================================
 * 11. Tech stack
 *
 * Hover lifts one technology and drops its row-mates, which turns a
 * decorative wall into something browsable. Scoped to the row so the
 * other row keeps running at full strength.
 * ===================================================== */

.lp-tech-card {
	transition:
		transform var(--ao-m-dur-fast) var(--ao-m-ease),
		opacity var(--ao-m-dur-fast) ease,
		border-color var(--ao-m-dur-fast) ease,
		background-color var(--ao-m-dur-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
	.lp-techm__row:hover .lp-tech-card {
		opacity: .45;
	}

	.lp-techm__row .lp-tech-card:hover {
		opacity: 1;
		transform: translateY(-4px);
		border-color: var(--ao-m-orange);
		background: rgba(255, 161, 92, .12);
	}

	.lp-techm__row .lp-tech-card:hover .lp-tech-card__icon {
		color: var(--ao-m-orange);
	}
}

.lp-tech-card__icon {
	transition: color var(--ao-m-dur-fast) ease;
}

/* =====================================================
 * 12. AI
 *
 * The rail, the tablist and the scroll markers are already built and
 * are left alone. Two things are added: the pipeline nodes light in
 * sequence when a panel becomes active, and the rail dot travels to its
 * new station instead of jumping.
 * ===================================================== */

.lp-ai__raildot,
.lp-ai__railfill {
	transition: all .5s var(--ao-m-ease);
}

/*
 * Replaces lp-ai-lit, which ran infinitely for the life of the page and
 * pulsed every node whether or not anyone was looking at the section.
 * The signal now crosses the pipeline once, when a capability is
 * selected, which is when it actually means something.
 *
 * An animation rather than a transition, deliberately: a panel that is
 * not current carries the hidden attribute, so it is display: none, and
 * a transition out of that state never runs - the nodes would simply
 * appear already lit. An animation restarts every time the element is
 * rendered, which is exactly the behaviour wanted here.
 */
/* Off outright, not merely overridden on the active panel. The other
   five panels are display:none so their copy of lp-ai-lit never ticks,
   but leaving 24 infinite animations declared on the page only works
   for as long as nobody makes those panels visible another way. */
.lp-ai__node {
	animation: none;
}

.lp-ai__panel.is-on .lp-ai__node {
	animation: ao-node-in .52s var(--ao-m-ease) both;
	animation-delay: calc(var(--i, 0) * 120ms);
}

@keyframes ao-node-in {
	0% {
		opacity: .25;
		transform: translate3d(0, 5px, 0);
		color: rgba(255, 255, 255, .56);
	}
	55% {
		color: #fff;
	}
	100% {
		opacity: 1;
		transform: none;
		color: rgba(255, 255, 255, .56);
	}
}

.lp-ai__station {
	transition:
		background-color var(--ao-m-dur-mid) ease,
		border-color var(--ao-m-dur-mid) ease,
		color var(--ao-m-dur-mid) ease;
}

/* The always-on pulse competed with the real signal and ran whether or
   not the section was on screen. */
.lp-ai__station.is-on .lp-ai__stationdot {
	animation: none;
}

/* =====================================================
 * 13. Pricing
 *
 * Three prices in three boxes made the reader do the arithmetic. One
 * shared axis makes the relationship visible. Every figure stays
 * printed as text above it, so nothing is hidden behind the animation.
 *
 * Bar offsets and widths arrive from PHP as custom properties, so there
 * is no measurement and nothing to recalculate on resize.
 * ===================================================== */

.lp-costaxis {
	margin-top: 34px;
	padding: 24px 28px;
	border-radius: 16px;
	background: #fff;
	border: 1px solid rgba(131, 71, 236, .2);
}

.lp-costaxis__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 18px;
}

.lp-costaxis__title {
	margin: 0;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--ao-m-blue);
}

.lp-costaxis__note {
	margin: 0;
	font-size: 12.5px;
	color: #8a838f;
}

.lp-costaxis__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.lp-costaxis__row {
	display: flex;
	align-items: center;
	gap: 16px;
}

.lp-costaxis__label {
	flex: 0 0 auto;
	width: 140px;
	font-size: 13px;
	font-weight: 600;
	color: #3c3350;
}

.lp-costaxis__track {
	flex: 1 1 auto;
	position: relative;
	height: 14px;
	border-radius: 7px;
	background: #f4f0fb;
	overflow: hidden;
}

.lp-costaxis__bar {
	position: absolute;
	top: 0;
	left: var(--lp-bar-start, 0%);
	width: var(--lp-bar-width, 10%);
	height: 100%;
	border-radius: 7px;
	background: linear-gradient(90deg, var(--ao-m-orange), var(--ao-m-blue));
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform .85s var(--ao-m-ease);
	transition-delay: calc(var(--i, 0) * 100ms);
}

.lp-costaxis.is-in .lp-costaxis__bar {
	transform: scaleX(1);
}

.lp-costaxis__value {
	flex: 0 0 auto;
	width: 140px;
	text-align: right;
	font-size: 13px;
	font-weight: 600;
	color: #120d26;
	font-variant-numeric: tabular-nums;
}

.lp-costaxis__scale {
	display: flex;
	justify-content: space-between;
	margin: 14px 156px 0;
	padding: 0;
	list-style: none;
	font-size: 11px;
	color: #8a838f;
	font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
	.lp-costaxis__row {
		flex-wrap: wrap;
		gap: 8px;
	}

	.lp-costaxis__label,
	.lp-costaxis__value {
		width: auto;
		text-align: left;
	}

	.lp-costaxis__track {
		flex-basis: 100%;
		order: 3;
	}

	.lp-costaxis__value {
		margin-left: auto;
		text-align: right;
	}

	.lp-costaxis__scale {
		margin-inline: 0;
	}
}

.lp-tier {
	transition:
		transform var(--ao-m-dur-mid) var(--ao-m-ease),
		box-shadow var(--ao-m-dur-mid) ease,
		border-color var(--ao-m-dur-mid) ease;
}

@media (hover: hover) and (pointer: fine) {
	.lp-tier:hover {
		transform: translateY(-5px);
	}
}

/* =====================================================
 * 14. Industries
 *
 * The hub lands, then each connector draws outward and its node follows.
 * Replaces an infinite pulse ring that ran for the life of the page.
 * ===================================================== */

.lp-ind-hub-ring {
	animation: none;
}

.lp-ind-node-connector {
	transform: scaleX(0);
	transition: transform .5s var(--ao-m-ease);
	transition-delay: calc(220ms + var(--i, 0) * 70ms);
}

.lp-ind-node--left .lp-ind-node-connector  { transform-origin: right center; }
.lp-ind-node--right .lp-ind-node-connector { transform-origin: left center; }

.lp-ind.is-in .lp-ind-node-connector {
	transform: scaleX(1);
}

.lp-ind-node {
	opacity: 0;
	transition:
		opacity var(--ao-m-dur) var(--ao-m-ease),
		transform var(--ao-m-dur-mid) var(--ao-m-ease),
		border-color var(--ao-m-dur-mid) ease;
	transition-delay: calc(260ms + var(--i, 0) * 70ms);
}

.lp-ind.is-in .lp-ind-node {
	opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
	.lp-ind-node:hover {
		transform: translateY(-3px);
		border-color: var(--ao-m-orange);
		transition-delay: 0s;
	}

	.lp-ind-node:hover .lp-ind-node-dot {
		background: var(--ao-m-orange);
	}
}

.lp-ind-node-dot {
	transition: background-color var(--ao-m-dur-fast) ease;
}

/* =====================================================
 * 15. CTA bands
 *
 * Two blurred radial blooms drifting slowly on their own composited
 * layer. Paused whenever the band is off screen, which is most of the
 * time. No particles, no canvas, no JavaScript per frame.
 * ===================================================== */

.lp-cta--mid,
.lp-ctab {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

.lp-cta--mid::before,
.lp-cta--mid::after,
.lp-ctab::before,
.lp-ctab::after {
	content: "";
	position: absolute;
	border-radius: 50%;
	filter: blur(60px);
	pointer-events: none;
	z-index: -1;
	opacity: .55;
	animation: ao-aurora 14s ease-in-out infinite;
	animation-play-state: paused;
	will-change: auto;
}

.lp-cta--mid::before,
.lp-ctab::before {
	top: -42%;
	left: -12%;
	width: 620px;
	height: 620px;
	background: radial-gradient(circle, rgba(255, 161, 92, .55), rgba(255, 161, 92, 0) 66%);
}

.lp-cta--mid::after,
.lp-ctab::after {
	bottom: -48%;
	right: -8%;
	width: 560px;
	height: 560px;
	background: radial-gradient(circle, rgba(223, 205, 255, .6), rgba(223, 205, 255, 0) 66%);
	animation-duration: 18s;
	animation-direction: reverse;
	animation-delay: -5s;
}

.lp-cta--mid.is-visible::before,
.lp-cta--mid.is-visible::after,
.lp-ctab.is-visible::before,
.lp-ctab.is-visible::after {
	animation-play-state: running;
	will-change: transform;
}

@keyframes ao-aurora {
	0%,
	100% { transform: translate3d(-6%, 0, 0) scale(1); }
	50%  { transform: translate3d(6%, 4%, 0) scale(1.12); }
}

/* The closing CTA's button gets a border that sweeps once on hover -
   the last interactive flourish on the page, and only on intent. */
.lp-ctab .lp-btn--light,
.lp-cta--mid .lp-btn--light {
	position: relative;
	isolation: isolate;
	transition: transform var(--ao-m-dur-fast) var(--ao-m-ease);
}

.lp-ctab .lp-btn--light::before,
.lp-cta--mid .lp-btn--light::before {
	content: "";
	position: absolute;
	inset: -2px;
	border-radius: inherit;
	padding: 2px;
	background: conic-gradient(from var(--ao-sweep, 0turn),
		transparent 0turn,
		var(--ao-m-orange) .12turn,
		var(--ao-m-blue) .3turn,
		transparent .45turn,
		transparent 1turn);
	-webkit-mask:
		linear-gradient(#000 0 0) content-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask:
		linear-gradient(#000 0 0) content-box,
		linear-gradient(#000 0 0);
	mask-composite: exclude;
	opacity: 0;
	transition: opacity var(--ao-m-dur-mid) ease;
	pointer-events: none;
}

@property --ao-sweep {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0turn;
}

@media (hover: hover) and (pointer: fine) {
	.lp-ctab .lp-btn--light:hover,
	.lp-cta--mid .lp-btn--light:hover {
		transform: translateY(-2px);
	}

	.lp-ctab .lp-btn--light:hover::before,
	.lp-cta--mid .lp-btn--light:hover::before,
	.lp-ctab .lp-btn--light:focus-visible::before,
	.lp-cta--mid .lp-btn--light:focus-visible::before {
		opacity: 1;
		animation: ao-sweep 1.1s linear;
	}
}

@keyframes ao-sweep {
	to { --ao-sweep: 1turn; }
}

/* =====================================================
 * 16. Success stories
 *
 * The panel already swapped instantly. Making it arrive - and making
 * the headline metric re-count - is what turns a tab switch into the
 * sense that new evidence has landed.
 *
 * The section's own design, including the index accent and the artwork
 * zoom, lives in lp-components.css. What is left here is the one piece
 * this layer legitimately owns: the panel's arrival, timed against the
 * --ao-m-* tokens every other section reveal uses. The tab and media
 * rules that used to sit here were unscoped (.lp-ct-tab, .lp-ct-media)
 * and re-declared geometry the component now sets for itself.
 * ===================================================== */

.lp-ct-panel.is-active {
	animation: ao-panel-in .45s var(--ao-m-ease) both;
}

/* The panel's two halves settle a beat behind the panel itself, so a
   story change reads as new evidence arriving rather than a swap. */
.lp-ct-panel.is-active > * {
	animation: ao-panel-part-in .5s var(--ao-m-ease) both;
}

.lp-ct-panel.is-active > .lp-ct-media {
	animation-delay: .06s;
}

@keyframes ao-panel-in {
	from {
		opacity: 0;
		transform: translate3d(0, 12px, 0);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes ao-panel-part-in {
	from {
		opacity: 0;
		transform: translate3d(0, 10px, 0);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

.lp-ct-metric-value {
	font-variant-numeric: tabular-nums;
}

/* =====================================================
 * 17. Why choose / Awards
 *
 * Both keep their layouts. The change is sequencing: a diagonal stagger
 * rather than row by row, so the eye travels across the grid instead of
 * along each row in turn.
 * ===================================================== */

.lp-why-item {
	transition:
		opacity var(--ao-m-dur) var(--ao-m-ease),
		transform var(--ao-m-dur) var(--ao-m-ease),
		border-color var(--ao-m-dur-mid) ease,
		box-shadow var(--ao-m-dur-mid) ease;
}

.lp-why-num {
	transition:
		transform var(--ao-m-dur-mid) var(--ao-m-ease),
		opacity var(--ao-m-dur-mid) ease;
}

@media (hover: hover) and (pointer: fine) {
	.lp-why-item:hover {
		transform: translateY(-5px);
	}

	.lp-why-item:hover .lp-why-num {
		transform: translateY(-4px) scale(1.06);
		opacity: 1;
	}

	.lp-why-item:hover .lp-why-icon {
		transform: translateY(-3px);
	}
}

.lp-why-icon {
	transition: transform var(--ao-m-dur-mid) var(--ao-m-ease);
}

.lp-award-card {
	transition:
		opacity var(--ao-m-dur) var(--ao-m-ease),
		transform var(--ao-m-dur) var(--ao-m-ease),
		border-color var(--ao-m-dur-mid) ease,
		box-shadow var(--ao-m-dur-mid) ease;
}

.lp-award-chip {
	transition:
		background-color var(--ao-m-dur-fast) ease,
		border-color var(--ao-m-dur-fast) ease,
		transform var(--ao-m-dur-fast) var(--ao-m-ease);
}

@media (hover: hover) and (pointer: fine) {
	.lp-award-card:hover {
		transform: translateY(-4px);
		border-color: rgba(255, 161, 92, .5);
	}

	.lp-award-card:hover .lp-award-chip {
		border-color: var(--ao-m-orange);
		transform: translateY(-2px);
	}
}

/* =====================================================
 * 18. FAQ
 *
 * Replaces the measured max-height accordion. 0fr -> 1fr animates to the
 * answer's real height, stays correct when the viewport is resized, and
 * needs no measurement in JavaScript.
 *
 * interpolate-size: allow-keywords would be the more direct expression
 * of this, but it is Chromium-only, so fr units are the cross-browser
 * answer.
 * ===================================================== */

.lp-faq-a {
	display: grid;
	grid-template-rows: 0fr;
	max-height: none;
	overflow: hidden;
	transition: grid-template-rows .36s var(--ao-m-ease);
}

/* The clipping element must carry no padding of its own, or the closed
   row keeps that padding as residual height. The answer's padding lives
   on the paragraph inside, where it is clipped rather than measured. */
.lp-faq-a__inner {
	min-height: 0;
	overflow: hidden;
}

.lp-faq-item.open .lp-faq-a {
	grid-template-rows: 1fr;
}

.lp-faq-item {
	transition:
		border-color var(--ao-m-dur-mid) ease,
		background-color var(--ao-m-dur-mid) ease;
	position: relative;
}

/* Warm rule down the open question. Scale, not width, and it sits on a
   pseudo-element so it never participates in layout. */
.lp-faq-item::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 2px;
	border-radius: 2px;
	background: linear-gradient(180deg, var(--ao-m-orange), var(--ao-m-blue));
	transform: scaleY(0);
	transform-origin: top center;
	transition: transform var(--ao-m-dur-mid) var(--ao-m-ease);
}

.lp-faq-item.open::before {
	transform: scaleY(1);
}

.lp-faq-icon {
	transition: transform var(--ao-m-dur-mid) var(--ao-m-ease);
}

.lp-faq-item.open .lp-faq-icon {
	transform: rotate(180deg);
}

.lp-faq-q {
	transition: color var(--ao-m-dur-fast) ease;
}

.lp-faq-tab {
	transition:
		background-color var(--ao-m-dur-mid) ease,
		border-color var(--ao-m-dur-mid) ease,
		color var(--ao-m-dur-mid) ease;
}

/* =====================================================
 * 19. Reduced motion
 *
 * One block. Every utility above reads these tokens, so resetting them
 * here disables the whole layer without touching a single section rule.
 * Content stays fully visible, counters print their final values, and
 * every tab, accordion and rail keeps working.
 * ===================================================== */

@media (prefers-reduced-motion: reduce) {
	:root {
		--ao-m-dur: .01ms;
		--ao-m-dur-mid: .01ms;
		--ao-m-dur-fast: .01ms;
		--ao-m-stagger: 0ms;
		--ao-m-y: 0px;
		--ao-m-x: 0px;
	}

	.lp-reveal,
	[data-reveal],
	.lp-ai__node,
	.lp-ind-node {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}

	/* The script does not tag these under reduced motion; this covers a
	   preference switched on after the page has loaded. */
	[data-ao-rise] {
		opacity: 1 !important;
		animation: none !important;
	}

	.lp-ai__panel.is-on .lp-ai__node {
		animation: none !important;
	}

	.ao-line > span {
		transform: none !important;
		transition: none !important;
	}

	/* Everything that draws or fills renders complete. */
	.lp-stats-band__grid::after,
	.lp-costaxis__bar,
	.lp-ind-node-connector,
	.lp-ct-tab.is-active::after,
	.lp-chain__link::before,
	.lp-chain__progress span {
		transform: none !important;
		transition: none !important;
	}

	.lp-stats-band__node,
	.lp-chain__node {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}

	/*
	 * The device chain. Hover keeps its colour change and loses its
	 * travel, which is what lp-components already does for .lp-card and
	 * .lp-tier. The track's own scrolling stays instant, so the prev /
	 * next controls jump rather than glide.
	 */
	.lp-chain__link:hover .lp-chain__card,
	.lp-chain__btn:active {
		transform: none !important;
	}

	.lp-chain__card,
	.lp-chain__index,
	.lp-chain__btn,
	.lp-chain__btn svg,
	.lp-chain__viewport::before,
	.lp-chain__viewport::after {
		transition: none !important;
	}

	.lp-chain__track {
		scroll-behavior: auto !important;
	}

	.lp-proc__progress {
		height: 100% !important;
		animation: none !important;
		transition: none !important;
	}

	.lp-proc__rail.is-tracking .lp-proc__phase {
		opacity: 1 !important;
	}

	.lp-ct-panel.is-active,
	.lp-ct-panel.is-active > * {
		animation: none !important;
	}

	/* Continuous decorative motion stops entirely. The marquees become
	   horizontally scrollable so every item stays reachable. */
	.lp-techm__track,
	.lp-clients-track,
	.lp-techm.is-visible .lp-techm__track,
	.lp-clients.is-visible .lp-clients-track {
		animation: none !important;
		will-change: auto !important;
	}

	.lp-techm__row,
	.lp-clients-marquee {
		overflow-x: auto;
	}

	.lp-cta--mid::before,
	.lp-cta--mid::after,
	.lp-ctab::before,
	.lp-ctab::after,
	.lp-cta--mid.is-visible::before,
	.lp-cta--mid.is-visible::after,
	.lp-ctab.is-visible::before,
	.lp-ctab.is-visible::after {
		animation: none !important;
		will-change: auto !important;
	}

	.lp-ctab .lp-btn--light:hover::before,
	.lp-cta--mid .lp-btn--light:hover::before {
		animation: none !important;
	}

	/*
	 * The form spinner is the one animation that must keep running under
	 * reduced motion: it is the only signal that a submission is in
	 * flight. lp-components.css already slows it to 1.6s for exactly
	 * that reason, but the page stylesheet's blanket
	 *   * { animation-duration: .01ms !important }
	 * overrides it, leaving an infinite animation with a 0.01ms
	 * iteration - a spinner recalculating style on every frame for as
	 * long as the request takes. Restating the intended duration with
	 * the same weight puts the considered value back.
	 */
	.lp-form-spinner {
		animation-duration: 1.6s !important;
	}
}
