/* Small additions on top of the existing main.css design system - not part of the original template. */

/* Homepage sections stack up with the base template's 6em top/bottom wrapper
   padding on every single one - with ~10 sections that compounds into a lot
   of dead vertical space. Tighten it slightly, scoped to the homepage only. */
.home-section {
	padding-top: 4.25em;
	padding-bottom: 4.25em;
	margin-bottom: 1.5em;
}

	/* Slight background variation so the stacked sections don't read as one
	   continuous white page. Kept deliberately subtle - these are tints, not
	   a change to the color system. */
	.home-section.tint-warm {
		background: #f8f7f5;
	}

	.home-section.tint-cool {
		background: #f1f4f7;
	}

.box {
	border: solid 2px rgba(210, 215, 217, 0.75);
	border-radius: 4px;
	padding: 1.5em;
	margin: 0 0 2em 0;
}

.validation-summary-errors ul {
	list-style: none;
	margin: 0 0 2em 0;
	padding: 1em 1.5em;
	border-radius: 4px;
	background: rgba(255, 0, 0, 0.08);
	color: #b00020;
}

.validation-message,
.field-validation-error {
	display: block;
	color: #b00020;
	font-size: 0.8em;
	margin-top: 0.35em;
}

.input-validation-error {
	border-color: #b00020 !important;
}

/* Contact form: the base template only styles text/email/password/select/textarea,
   leaving tel inputs and checkboxes with no visible box at all. Darken and unify. */
form input[type="text"],
form input[type="email"],
form input[type="tel"],
form select,
form textarea {
	background: #eef0f2;
	border: solid 1px #9aa1a9;
}

	form input[type="text"]:focus,
	form input[type="email"]:focus,
	form input[type="tel"]:focus,
	form select:focus,
	form textarea:focus {
		background: #fff;
		border-color: #df7366;
	}

form input[type="checkbox"] {
	appearance: auto;
	-webkit-appearance: auto;
	-moz-appearance: auto;
	width: 1.15em;
	height: 1.15em;
	flex: none;
	margin: 0.2em 0 0 0;
}

.consent-row {
	display: flex;
	align-items: flex-start;
	gap: 0.6em;
}

	.consent-row label {
		display: inline;
		margin: 0;
	}

.contact-form-box {
	width: 100%;
	background: #f3f4f6;
	border: solid 1px #d7dade;
	border-radius: 0.75em;
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
	padding: 2.5em;
}

	@media screen and (max-width: 736px) {
		.contact-form-box {
			padding: 1.5em;
		}
	}

/* ==========================================================================
   Homepage refinement pass - masthead, hero, pillars, client work, etc.
   ========================================================================== */

/* Slim global masthead: the old design put a full photo hero + tagline +
   circled CTA in #header on every page, competing with each page's own H1.
   Reduced to logo + nav only so the homepage hero below can lead visually. */
#header {
	/* Sticky rather than fixed: it keeps its place in the flow, so nothing below
	   needs an offset. The box height deliberately never changes - shrinking it
	   on scroll would pull every following section up by ~60px, which reads as
	   the page jumping under you. */
	position: sticky;
	top: 0;
	z-index: 10;
	background-image: none;
	background-color: #201b26;
	padding: 4.5em 0 1.25em 0;
	text-align: center;
	transition: background-color 0.25s ease-out, box-shadow 0.25s ease-out;
}

	/* Once the page has scrolled, the bar takes a translucent background and a
	   soft edge, so content reads as passing behind it rather than colliding. */
	#header.is-stuck {
		background-color: rgba(32, 27, 38, 0.94);
		box-shadow: 0 2px 18px rgba(0, 0, 0, 0.35);
	}

		/* Blur only where supported. Without it the colour has to carry the
		   separation on its own, hence the higher opacity above. */
		@supports ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))) {
			#header.is-stuck {
				background-color: rgba(32, 27, 38, 0.82);
				-webkit-backdrop-filter: blur(12px);
				backdrop-filter: blur(12px);
			}
		}

	/* main.css sets 'html, body { overflow-x: hidden }' below 736px, which turns
	   them into scroll containers and stops the header sticking to the viewport.
	   'clip' suppresses the same horizontal overflow without creating one - but
	   it has to stay off <html>, because clipping there also stops overflow
	   propagating to the viewport, and window.scrollY then reads 0 forever. */
	@media screen and (max-width: 736px) {
		html {
			overflow-x: visible;
		}

		body {
			overflow-x: clip;
		}
	}

	@media (prefers-reduced-motion: reduce) {
		#header {
			transition: none;
		}
	}

	#header .site-title {
		display: inline-flex;
		align-items: center;
		gap: 0.6em;
		margin: 0;
		max-width: 100%;
		white-space: nowrap;
	}

		#header .site-title-mark {
			height: 48px;
			width: auto;
			filter: drop-shadow(0 0 6px rgba(107, 178, 255, 0.65)) drop-shadow(0 0 18px rgba(79, 168, 255, 0.4));
			transition: filter 0.3s ease-in-out;
		}

		#header .site-title-text {
			color: #fff;
			font-size: 1.3em;
			font-weight: 600;
			text-shadow: 0 0 10px rgba(107, 178, 255, 0.5);
			transition: text-shadow 0.3s ease-in-out;
		}

		#header .site-title:hover .site-title-mark {
			filter: drop-shadow(0 0 10px rgba(107, 178, 255, 0.85)) drop-shadow(0 0 26px rgba(79, 168, 255, 0.6));
		}

		#header .site-title:hover .site-title-text {
			text-shadow: 0 0 16px rgba(107, 178, 255, 0.8);
		}

		@media screen and (max-width: 736px) {
			#header .site-title-mark {
				height: 38px;
			}

			#header .site-title-text {
				font-size: 1.1em;
			}
		}

		@media screen and (max-width: 400px) {
			#header .inner {
				max-width: calc(100% - 4.5em);
			}

			#header .site-title {
				min-width: 0;
				white-space: normal;
				text-align: left;
			}

			#header .site-title-mark {
				height: 32px;
				flex-shrink: 0;
			}

			#header .site-title-text {
				min-width: 0;
				font-size: 0.95em;
				line-height: 1.2em;
			}
		}

/* Hamburger nav toggle - hidden on desktop, shown only at mobile widths where
   the inline nav list no longer has room and would otherwise clip off-screen. */
.nav-toggle {
	display: none;
	position: absolute;
	top: 1.1em;
	right: 1.1em;
	z-index: 2;
	width: 40px;
	height: 40px;
	padding: 0;
	background: transparent;
	border: solid 1px rgba(255, 255, 255, 0.25);
	border-radius: 0.3em;
	cursor: pointer;
}

	.nav-toggle span {
		display: block;
		width: 20px;
		height: 2px;
		margin: 5px auto;
		background: #fff;
		transition: transform 0.25s ease, opacity 0.25s ease;
	}

	.nav-toggle.is-active span:nth-child(1) {
		transform: translateY(7px) rotate(45deg);
	}

	.nav-toggle.is-active span:nth-child(2) {
		opacity: 0;
	}

	.nav-toggle.is-active span:nth-child(3) {
		transform: translateY(-7px) rotate(-45deg);
	}

@media screen and (max-width: 736px) {
	.nav-toggle {
		display: block;
	}

	#header .inner {
		max-width: calc(100% - 3.5em);
	}

	#nav {
		position: absolute;
		top: 100%;
		left: 0;
		width: 100%;
		padding: 0;
		max-height: 0;
		overflow: hidden;
		background: #201b26;
		border-top: solid 1px rgba(255, 255, 255, 0.08);
		transition: max-height 0.3s ease;
	}

		#nav.is-active {
			max-height: 26em;
		}

		#nav > ul {
			display: block;
			height: auto;
			width: 100%;
			border: 0;
			padding: 0.5em 0;
		}

			#nav > ul:before,
			#nav > ul:after {
				display: none;
			}

			#nav > ul > li {
				display: block;
				margin: 0;
				padding: 0.9em 1.5em;
				border: 0;
				border-radius: 0;
				text-align: left;
			}
}

/* Home hero - full-bleed workspace photo with a real-text overlay and a
   summary "trust strip" along the bottom. */
#banner.home-hero {
	position: relative;
	overflow: hidden;
	padding: 0;
	text-align: left;
	color: #fff;
}

	.hero-media {
		position: absolute;
		inset: 0;
		z-index: 0;
		/* Clips the slow zoom below so the scaled image never spills past the hero. */
		overflow: hidden;
	}

		/* Works for either an <img> or a <video> - only sizing and framing live here,
		   so the background can be swapped to looping video without touching this. */
		.hero-bg-image {
			display: block;
			width: 100%;
			height: 100%;
			object-fit: cover;
			object-position: 75% 90%;
		}

		/* The poster paints immediately underneath the video, so the hero never
		   renders empty while the clip loads or if it fails entirely. */
		video.hero-bg-image {
			background-image: url('../images/hero-workspace.jpg');
			background-size: cover;
			background-position: 75% 90%;
		}

		.hero-overlay {
			position: absolute;
			inset: 0;
			background: linear-gradient(100deg,
				rgba(6, 8, 14, 0.72) 0%,
				rgba(6, 8, 14, 0.58) 28%,
				rgba(6, 8, 14, 0.32) 55%,
				rgba(6, 8, 14, 0.12) 78%,
				rgba(6, 8, 14, 0.05) 100%);
		}

	.hero-content {
		position: relative;
		z-index: 1;
		max-width: 1400px;
		margin: 0 auto;
		padding: 5em 2em 3.5em 2em;
		text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 2px 14px rgba(0, 0, 0, 0.45);
	}

		.hero-content > .hero-brand,
		.hero-content > header,
		.hero-content > footer {
			max-width: 34em;
		}

	.hero-brand {
		margin-bottom: 1.75em;
	}

	.hero-logo {
		font-size: 1.7em;
		line-height: 1.15em;
		margin: 0;
	}

		.hero-logo .brand-share {
			color: #fff;
			font-weight: 600;
		}

		.hero-logo .brand-dev {
			color: #4fa8ff;
			font-weight: 600;
		}

		.hero-logo .brand-sub {
			display: block;
			font-size: 0.42em;
			letter-spacing: 0.3em;
			text-transform: uppercase;
			color: rgba(255, 255, 255, 0.65);
			font-weight: 400;
			margin-top: 0.3em;
		}

	.hero-brand-divider {
		display: inline-block;
		width: 1px;
		height: 2.5em;
		background: rgba(255, 255, 255, 0.25);
	}

	/* Sits over looping video, so it needs its own weight and shadow rather than
	   relying on the hero's shared one - the frame behind it changes constantly. */
	.hero-motto {
		font-size: 0.8em;
		line-height: 1.7em;
		letter-spacing: 0.16em;
		text-transform: uppercase;
		font-weight: 600;
		color: #fff;
		margin: 0;
		text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95), 0 2px 10px rgba(0, 0, 0, 0.8);
	}

		/* Typing state. A hidden full-text ghost holds the final size open so the
		   hero never reflows as characters appear, and the typed copy is overlaid
		   on top of it. Only applied once the script takes over, so the plain
		   no-JavaScript rendering is untouched. */
		.hero-motto.is-typing {
			position: relative;
		}

			.hero-motto.is-typing .hero-motto-ghost {
				visibility: hidden;
			}

			.hero-motto.is-typing .hero-motto-text {
				position: absolute;
				left: 0;
				top: 0;
				right: 0;
			}

		.hero-motto-caret {
			display: inline-block;
			width: 2px;
			height: 1em;
			margin-left: 0.15em;
			background: #4fa8ff;
			vertical-align: -0.12em;
			box-shadow: 0 0 6px rgba(79, 168, 255, 0.9);
			animation: heroCaretBlink 0.9s steps(1, end) infinite;
		}

			.hero-motto-caret.is-done {
				animation: none;
				opacity: 0;
				transition: opacity 0.6s ease-out;
			}

@keyframes heroCaretBlink {
	0%, 49% { opacity: 1; }
	50%, 100% { opacity: 0; }
}

/* Off-screen but still announced. Holds the motto's full text while the
   visible copy is mid-animation. */
.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

	#banner.home-hero h1 {
		color: #fff;
		font-size: 2.75em;
		line-height: 1.18em;
		margin-bottom: 0.5em;
	}

		#banner.home-hero h1 .accent {
			color: #4fa8ff;
		}

	#banner.home-hero .hero-sub {
		color: rgba(255, 255, 255, 0.92);
		font-size: 1.2em;
		margin: 0 0 1em 0;
	}

	#banner.home-hero .hero-entity {
		font-size: 0.95em !important;
		color: rgba(255, 255, 255, 0.62);
		margin: 0;
	}

	#banner.home-hero footer {
		margin-top: 2em;
	}

	/* The hero sits on video, so its CTAs carry a stronger glow than the site-wide
	   default further down this file. */
	#banner.home-hero footer .button {
		margin: 0 0.75em 0.5em 0;
		box-shadow: 0 0 18px rgba(223, 115, 102, 0.45);
	}

		#banner.home-hero footer .button:hover {
			box-shadow: 0 2px 30px rgba(239, 131, 118, 0.8);
		}

		#banner.home-hero footer .button.outline {
			border-color: rgba(255, 255, 255, 0.7);
			box-shadow: 0 0 18px rgba(255, 255, 255, 0.18);
		}

			#banner.home-hero footer .button.outline:hover {
				border-color: #fff;
				box-shadow: 0 2px 28px rgba(255, 255, 255, 0.42);
			}

	#banner.home-hero footer .icon {
		margin-left: 0.4em;
		transition: transform 0.25s ease-in-out;
	}

	#banner.home-hero footer .button:hover .icon {
		transform: translateX(5px);
	}

	.button.outline {
		background: transparent;
		border: solid 1px rgba(255, 255, 255, 0.55);
		color: #fff;
	}

		.button.outline:hover {
			background: rgba(255, 255, 255, 0.1);
			color: #fff;
		}

	@keyframes trust-strip-fade-in {
		from { opacity: 0; transform: translateY(14px); }
		to   { opacity: 1; transform: translateY(0); }
	}

	.hero-trust-strip {
		position: relative;
		z-index: 1;
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: 1.5em;
		background: linear-gradient(180deg,
			rgba(6, 8, 14, 0.45) 0%,
			rgba(6, 8, 14, 0.85) 45%,
			rgba(6, 8, 14, 0.92) 100%);
		padding: 2em 2em 1.5em 2em;
		animation: trust-strip-fade-in 1.8s ease-out 0.5s both;
	}

		.trust-item {
			display: flex;
			align-items: center;
			gap: 0.85em;
		}

			.trust-item .icon {
				color: #4fa8ff;
			}

				.trust-item .icon:before {
					font-size: 1.8em;
				}

			.trust-item strong {
				display: block;
				color: #fff;
				font-weight: 600;
				font-size: 0.95em;
				letter-spacing: 0.03em;
			}

			.trust-item span {
				display: block;
				color: rgba(255, 255, 255, 0.55);
				font-size: 0.75em;
				letter-spacing: 0.03em;
			}


		@keyframes trust-tagline-slide-in {
			from { opacity: 0; transform: translateX(45px); }
			to   { opacity: 1; transform: translateX(0); }
		}

		.trust-tagline {
			text-align: right;
			font-size: 0.72em;
			letter-spacing: 0.12em;
			text-transform: uppercase;
			color: rgba(255, 255, 255, 0.92);
			line-height: 1.6em;
			border-top: solid 2px #df7366;
			padding-top: 0.4em;
			text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
			/* Slides in after the strip itself has begun fading up. */
			animation: trust-tagline-slide-in 1.1s cubic-bezier(0.23, 1, 0.32, 1) 1.1s both;
		}

			.trust-tagline span {
				display: block;
			}

	@media screen and (max-width: 960px) {
		.hero-content {
			padding: 4em 1.5em 3em 1.5em;
		}

		#banner.home-hero h1 {
			font-size: 2.25em;
		}
	}

	@media screen and (max-width: 736px) {
		.hero-overlay {
			background: rgba(6, 8, 14, 0.5);
		}

		.hero-content > .hero-brand,
		.hero-content > header,
		.hero-content > footer {
			max-width: 100%;
		}

		.hero-brand {
			flex-wrap: wrap;
			gap: 1em;
			margin-bottom: 2em;
		}

		#banner.home-hero h1 {
			font-size: 1.85em;
		}

		#banner.home-hero footer .button {
			display: block;
			width: 100%;
			max-width: 320px;
			margin: 0 0 0.75em 0;
		}

		.hero-trust-strip {
			flex-direction: column;
			align-items: flex-start;
			padding: 1.5em;
		}

		.trust-tagline {
			text-align: left;
		}
	}

/* Client logos: pull the section closer to the hero and keep the carousel
   from dominating the page - a tasteful strip, not a huge feature block. */
.client-logos-wrapper {
	padding-top: 2.5em;
	padding-bottom: 2.5em;
}

	.client-logos-wrapper .container.special > header {
		margin-bottom: 1.5em;
	}

/* Service pillars */
.pillars {
	margin-top: 1em;
}

	.pillar {
		text-align: left;
		padding: 2em 1.75em;
		border: solid 1px rgba(72, 57, 73, 0.1);
		border-radius: 0.4em;
		background: #fff;
	}

	.pillar-icon {
		display: inline-block;
		margin-bottom: 0.6em;
		color: #df7366;
	}

		.pillar-icon:before {
			font-size: 2em;
		}

	.pillar h3 {
		margin-bottom: 0.5em;
	}

	.pillar > p {
		text-align: left;
	}

	.pillar-list {
		list-style: none;
		margin: 1em 0 1.25em 0;
		padding: 0;
		display: flex;
		flex-wrap: wrap;
		gap: 0.5em;
	}

		.pillar-list li {
			/* 0.8em/#6b5f6c passed AA at 5.41:1 but read as faint. Slightly larger and
			   darker (7.1:1) for presence, without changing the component. */
			font-size: 0.85em;
			color: #584e59;
			background: #f1eeec;
			border-radius: 1em;
			padding: 0.35em 0.9em;
		}

		/* Some capability chips now link to their service page. Keep the chip
		   looking like a chip rather than inheriting the template's link border. */
		.pillar-list li a {
			color: inherit;
			border-bottom: 0;
			text-decoration: underline;
			text-decoration-color: rgba(223, 115, 102, 0.6);
			text-underline-offset: 0.2em;
		}

			.pillar-list li a:hover,
			.pillar-list li a:focus-visible {
				color: #b8503f;
				text-decoration-color: #b8503f;
			}

	.pillar-link {
		display: inline-block;
		font-weight: 400;
		color: #df7366;
		border-bottom: 0;
	}

		.pillar-link:hover {
			color: #ef8376;
		}

		.pillar-link .icon {
			margin-left: 0.25em;
		}

		.pillar-link .icon:before {
			font-size: 0.9em;
		}

/* Problem-solving section */
.problem-solving header {
	max-width: 42em;
	margin-left: auto;
	margin-right: auto;
}

.solution-chips {
	list-style: none;
	margin: 2em 0 1.5em 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75em;
}

	.solution-chips li {
		background: rgba(255, 255, 255, 0.6);
		border: solid 1px rgba(72, 57, 73, 0.15);
		border-radius: 2em;
		padding: 0.5em 1.1em;
		font-size: 0.95em;
	}

		.solution-chips .icon {
			color: #df7366;
			margin-right: 0.4em;
		}

.problem-solving-footnote {
	max-width: 42em;
	margin: 0 auto;
	text-align: center;
	font-style: italic;
	color: #7d7d7d;
}

/* Page titles. The base template only ever used h1 for the masthead logo, so it
   never defined a body h1 size - without this, every page H1 falls back to the
   browser default and renders smaller than the h2s beneath it. */
#banner h1 {
	font-size: 2.85em;
	line-height: 1.2em;
	/* Evens out the wrap so a long heading doesn't leave one word stranded
	   on the last line. Ignored by browsers that don't support it. */
	text-wrap: balance;
}

	@media screen and (max-width: 736px) {
		#banner h1 {
			font-size: 1.85em;
		}
	}

/* Concise team excerpts. Left-aligned rather than justified so the narrow
   columns don't develop word-spacing gaps, and kept at readable size rather
   than shrunk to force equal card heights. */
.team-bio {
	text-align: left;
	font-size: 0.9em;
	line-height: 1.7em;
	margin-top: 1em;
}

/* Combined-experience credential under the team heading. */
.team-stat {
	font-size: 1em !important;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #8a7f8b;
	margin: 0 0 0.5em 0 !important;
}

	.team-stat strong {
		color: #df7366;
		font-weight: 600;
		font-size: 1.25em;
	}

/* About submenu (About ShareDev / News). The toggle is styled to match the sibling
   nav links exactly so the bar still reads as one row of items. */
/* main.css styles every <button> as a coral CTA. Its :hover rule outranks a bare
   class, and because #nav sets line-height:0 the coral background collapsed into a
   thin bar straight through the label - it read as an orange strikethrough. Every
   interactive state is reset here at matching specificity. */
.nav-sub-toggle,
.nav-sub-toggle:hover,
.nav-sub-toggle:focus,
.nav-sub-toggle:active {
	display: block;
	background: none;
	background-color: transparent;
	border: 0;
	border-radius: 0;
	padding: 0;
	margin: 0;
	font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	letter-spacing: inherit;
	line-height: inherit;
	color: inherit;
	cursor: pointer;
	text-align: inherit;
	text-transform: inherit;
	box-shadow: none;
}

	.nav-sub-caret {
		display: inline-block;
		width: 0;
		height: 0;
		margin-left: 0.45em;
		vertical-align: middle;
		border-left: 4px solid transparent;
		border-right: 4px solid transparent;
		border-top: 5px solid currentColor;
		opacity: 0.7;
		transition: transform 0.2s ease-in-out;
	}

	.nav-sub-toggle[aria-expanded="true"] .nav-sub-caret {
		transform: rotate(180deg);
	}

	/* Current-section indicator: accent underline only, label keeps the nav colour. */
	.nav-has-sub.is-current > .nav-sub-toggle {
		text-decoration: underline;
		text-decoration-color: #df7366;
		text-decoration-thickness: 2px;
		text-underline-offset: 4px;
	}

		.nav-has-sub.is-current > .nav-sub-toggle .nav-sub-caret {
			opacity: 1;
		}

/* Fixed rather than absolute: #nav is overflow:hidden (it clips the decorative
   300%-wide rules), which would clip an absolutely positioned panel. A fixed panel
   is not clipped by an ancestor's overflow, and JS anchors it to the button. */
/* main.css hides nested submenus with '#nav > ul > li > ul { display: none }' so the
   dropotron plugin can relocate them to <body>. That ID selector out-specifies a bare
   class, so the override is restated at matching specificity and gated on [hidden] so
   the closed state still works. */
#nav > ul > li > ul.nav-sub:not([hidden]) {
	display: block;
}

.nav-sub {
	position: fixed;
	z-index: 200;
	margin: 0;
	padding: 0.5em 0;
	list-style: none;
	background-color: #241f26;
	border: solid 1px rgba(192, 192, 192, 0.25);
	border-radius: 0.4em;
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
	text-align: left;
	line-height: 1.5em;
}

	/* Bridges the 8px gap between the button and the panel. Without it the pointer
	   crosses dead space on the way down, which fires mouseleave and closes the menu
	   mid-movement - the cause of the open/close flicker. Transparent, so nothing
	   changes visually; it only extends the panel's hit region upward. */
	.nav-sub::before {
		content: '';
		position: absolute;
		left: 0;
		right: 0;
		top: -12px;
		height: 12px;
	}

	.nav-sub li {
		display: block;
		margin: 0;
		padding: 0;
		border: 0;
	}

	.nav-sub a {
		display: block;
		padding: 0.55em 1.1em;
		color: rgba(255, 255, 255, 0.85);
		text-decoration: none;
		white-space: nowrap;
		font-size: 0.95em;
	}

		.nav-sub a:hover {
			background-color: rgba(255, 255, 255, 0.08);
			color: #fff;
		}

		.nav-sub a:focus-visible {
			outline: none;
			background-color: rgba(255, 255, 255, 0.16);
			color: #fff;
			text-decoration: underline;
			text-underline-offset: 3px;
		}

	/* Stacked mobile nav: the panel drops inline instead of floating, so it needs no
	   coordinates and cannot be clipped. */
	@media screen and (max-width: 736px) {
		.nav-sub {
			position: static;
			background: none;
			border: 0;
			box-shadow: none;
			padding: 0.25em 0 0.25em 0;
			text-align: center;
		}

			/* No floating panel on mobile, so no gap to bridge. */
			.nav-sub::before {
				display: none;
			}

			.nav-sub a {
				padding: 0.5em 0;
				font-size: 0.9em;
				opacity: 0.85;
			}

		/* Match the left alignment of the sibling links in the stacked nav. */
		.nav-sub-toggle {
			text-align: left;
			width: 100%;
		}

		.nav-sub,
		.nav-sub li {
			text-align: left;
		}
	}

/* Floating Connect bubble. The robot GIF sits on pure black that is part of the
   artwork (its own outlines are the same black), so the pill is filled near-black
   and the background reads as the bubble rather than as an unmasked square. */
.connect-bubble {
	position: fixed;
	right: 1.5em;
	bottom: 1.5em;
	z-index: 100;
	display: flex;
	align-items: center;
	gap: 0.15em;
	padding: 0.35em 1.15em 0.35em 0.35em;
	background-color: #0b0b0b;
	border: solid 2px #df7366;
	border-radius: 999px;
	text-decoration: none;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35), 0 0 20px rgba(79, 168, 255, 0.22);
	opacity: 0;
	transform: translateY(14px);
	pointer-events: none;
	transition: opacity 0.35s ease-in-out, transform 0.35s ease-in-out, box-shadow 0.3s ease-in-out;
}

	.connect-bubble.is-visible {
		opacity: 1;
		transform: translateY(0);
		pointer-events: auto;
	}

	.connect-bubble:hover {
		box-shadow: 0 6px 22px rgba(0, 0, 0, 0.42), 0 0 28px rgba(79, 168, 255, 0.45);
		border-color: #ef8376;
	}

	.connect-bubble.is-visible:hover {
		transform: translateY(-2px);
	}

	.connect-bubble-media {
		display: block;
		width: 52px;
		height: 52px;
		border-radius: 50%;
		overflow: hidden;
		background-color: #000;
		flex-shrink: 0;
	}

		/* The source frame is ~40% empty padding; scaling up inside the circular well
		   crops that in without re-encoding the GIF. */
		.connect-bubble-media img {
			display: block;
			width: 125%;
			height: 125%;
			margin: -12.5%;
			image-rendering: pixelated;
		}

	.connect-bubble-label {
		color: #fff;
		font-size: 0.72em;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		white-space: nowrap;
	}

	.connect-bubble:focus-visible {
		outline: 3px solid #fff;
		outline-offset: 3px;
	}

	@media screen and (max-width: 736px) {
		.connect-bubble {
			right: 1em;
			bottom: 1em;
			padding: 0.3em 0.95em 0.3em 0.3em;
		}

		.connect-bubble-media {
			width: 44px;
			height: 44px;
		}
	}

	@media (prefers-reduced-motion: reduce) {
		.connect-bubble {
			transition: none;
		}

		.connect-bubble.is-visible:hover {
			transform: none;
		}
	}

/* ---- Connect panel -------------------------------------------------------
   The bubble now opens a small panel in the same corner rather than linking
   straight to the contact page. The dock owns the corner position so the
   panel and the bubble stay anchored together. */
.connect-dock {
	/* The corner offset is a variable because the chat view's height is measured
	   from it - on the contact page the dock is lifted, and a height that ignored
	   that ran the panel off the top of the screen. Pixels, not em: the variable
	   is read inside .connect-chat, whose font-size differs from the dock's, so
	   the same em value would resolve to two different lengths. */
	--connect-bottom: 24px;
	position: fixed;
	right: 1.5em;
	bottom: var(--connect-bottom);
	z-index: 100;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.75em;
}

	/* The bubble sits inside the dock now, so it drops its own fixed position
	   and its <button> reset. */
	.connect-dock .connect-bubble {
		position: static;
		right: auto;
		bottom: auto;
		/* main.css gives every button 'width: 100%' below 736px. The bubble is a
		   <button> now, so without this it stretches the full width of the dock
		   instead of hugging its label. */
		width: auto;
		max-width: 100%;
		height: auto;
		line-height: normal;
		cursor: pointer;
	}

		.connect-dock .connect-bubble:hover,
		.connect-dock .connect-bubble:focus {
			background-color: #0b0b0b;
		}

	/* While the panel is open the bubble stays put, whatever the scroll does. */
	.connect-dock.is-open .connect-bubble {
		opacity: 1;
		transform: none;
		pointer-events: auto;
	}

.connect-panel {
	width: 330px;
	max-width: calc(100vw - 2em);
	background: #fff;
	border: solid 1px rgba(72, 57, 73, 0.14);
	border-radius: 0.7em;
	box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
	overflow: hidden;
	text-align: left;
}

	.connect-panel-head {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 0.5em;
		padding: 0.85em 0.6em 0.85em 1.1em;
		background: #201b26;
	}

		.connect-panel-title {
			margin: 0;
			color: #fff;
			font-size: 0.92em;
			font-weight: 600;
			letter-spacing: 0.02em;
		}

		.connect-panel-close {
			flex-shrink: 0;
			width: 2em;
			height: 2em;
			padding: 0;
			background: none;
			border: 0;
			border-radius: 50%;
			box-shadow: none;
			color: rgba(255, 255, 255, 0.75);
			line-height: 1;
			cursor: pointer;
		}

			.connect-panel-close:hover,
			.connect-panel-close:focus-visible {
				background: rgba(255, 255, 255, 0.12);
				color: #fff;
				box-shadow: none;
			}

.connect-options {
	padding: 0.4em 0;
}

.connect-option {
	display: flex;
	align-items: flex-start;
	gap: 0.85em;
	width: 100%;
	/* main.css sizes input/textarea/select but not button, so the chat option -
	   the only <button> here - was rendering at the browser's ~13px default
	   while its sibling links sat at the page size. */
	font: inherit;
	padding: 0.8em 1.1em;
	background: none;
	border: 0;
	border-bottom: solid 1px rgba(72, 57, 73, 0.08);
	border-radius: 0;
	box-shadow: none;
	height: auto;
	line-height: 1.45em;
	text-align: left;
	color: #483949;
	cursor: pointer;
	transition: background-color 0.18s ease-out;
}

	.connect-option:last-child {
		border-bottom: 0;
	}

	.connect-option:hover,
	.connect-option:focus-visible {
		background: #faf7f6;
		box-shadow: none;
		color: #483949;
	}

	.connect-option-icon {
		flex-shrink: 0;
		width: 2.2em;
		height: 2.2em;
		border-radius: 50%;
		background: rgba(223, 115, 102, 0.12);
		color: #c75f50;
		text-align: center;
	}

		.connect-option-icon:before {
			line-height: 2.2em;
			font-size: 0.9em;
		}

	.connect-option-text {
		display: block;
		min-width: 0;
	}

		.connect-option-text strong {
			display: block;
			font-size: 0.92em;
			color: #483949;
		}

		.connect-option-text span {
			display: block;
			font-size: 0.8em;
			line-height: 1.45em;
			color: #6b626c;
		}

/* Chat view. The panel grows to hold the assistant, capped against the
   viewport so it never runs off a short screen. */
.connect-chat {
	/* 230px covers the bubble, the gap above it, and the panel's own head and
	   foot, so the whole panel clears the top of the screen. */
	height: min(520px, calc(100vh - 230px - var(--connect-bottom)));
}

	.connect-chat iframe {
		display: block;
		width: 100%;
		height: 100%;
		border: 0;
	}

.connect-dock.is-chat .connect-panel {
	width: 380px;
}

.connect-panel-foot {
	padding: 0.5em 1.1em 0.7em 1.1em;
	border-top: solid 1px rgba(72, 57, 73, 0.1);
}

	.connect-back {
		padding: 0.2em 0;
		background: none;
		border: 0;
		box-shadow: none;
		height: auto;
		line-height: 1.6em;
		font-size: 0.8em;
		color: #c75f50;
		cursor: pointer;
	}

		.connect-back:hover,
		.connect-back:focus-visible {
			background: none;
			box-shadow: none;
			color: #b8503f;
			text-decoration: underline;
		}

		.connect-back .icon:before {
			font-size: 0.85em;
			margin-right: 0.2em;
		}

	/* On the contact page the reCAPTCHA v3 badge occupies this corner, so the
	   dock is lifted above it rather than overlapping it. */
	.connect-dock.is-above-badge {
		--connect-bottom: 104px;
	}

@media screen and (max-width: 736px) {
	.connect-dock {
		--connect-bottom: 16px;
		right: 1em;
		left: 1em;
		align-items: flex-end;
	}

	.connect-panel,
	.connect-dock.is-chat .connect-panel {
		width: 100%;
		max-width: none;
	}

	.connect-chat {
		height: min(440px, calc(100vh - 210px - var(--connect-bottom)));
	}

	.connect-dock.is-above-badge {
		--connect-bottom: 96px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.connect-option {
		transition: none;
	}
}


/* Site-wide button glow. Scoped to .button so the nav hamburger and the submenu
   toggles - which are <button> elements without that class - stay unaffected, as
   does the Connect bubble, which carries its own glow. */
.button {
	box-shadow: 0 0 15px rgba(223, 115, 102, 0.30);
	transition: background-color 0.35s ease-in-out, color 0.35s ease-in-out, box-shadow 0.3s ease-in-out, transform 0.25s ease-in-out, border-color 0.3s ease-in-out;
}

	.button:hover {
		box-shadow: 0 2px 24px rgba(239, 131, 118, 0.60);
		transform: translateY(-2px);
	}

	.button:active {
		transform: translateY(0);
	}

	/* The dark variant takes a neutral glow - a coral halo around a near-black pill
	   reads as a colour clash on the light sections where it is mostly used. */
	.button.alt {
		box-shadow: 0 0 15px rgba(43, 37, 44, 0.28);
	}

		.button.alt:hover {
			box-shadow: 0 3px 24px rgba(43, 37, 44, 0.45);
		}

	/* Keep the lift out of it for anyone who has asked for less motion; the glow
	   itself still conveys the hover state. */
	@media (prefers-reduced-motion: reduce) {
		.button,
		.button:hover,
		.button:active {
			transform: none;
		}
	}

/* Visible keyboard focus. The base template only styled :focus on form fields, so
   links, buttons and the nav toggle had no focus indicator at all. :focus-visible
   means this shows for keyboard users without adding an outline on mouse clicks. */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
	outline: 3px solid #df7366;
	outline-offset: 2px;
	border-radius: 2px;
}

	/* The dark header needs a light ring. #nav is overflow:hidden over a fixed-height
	   ul, so an outset ring would be clipped - inset it so it draws inside the link. */
	#header a:focus-visible,
	#header button:focus-visible,
	#banner.home-hero a:focus-visible {
		outline-color: #fff;
	}

	/* The nav needs a different treatment: main.css sets '#nav > ul > li > a
	   { outline: 0 }' and #nav is overflow:hidden over a fixed 21px-tall ul, so an
	   outline is both reset and clipped. A background and underline draw inside the
	   element box, so neither problem applies. */
	#nav > ul > li > a:focus-visible,
	#nav a:focus-visible {
		outline: none;
		background-color: rgba(255, 255, 255, 0.22);
		text-decoration: underline;
		text-underline-offset: 3px;
		border-radius: 2px;
	}

/* Secondary pillar link: same component, visually subordinate so the two links in
   one pillar do not compete. */
.pillar-link-secondary {
	font-size: 0.85em;
	opacity: 0.8;
	margin-top: 0.35em;
}

	.pillar-link-secondary:hover {
		opacity: 1;
	}

/* FAQ list. Plain headings and paragraphs - the answers must stay visible, since
   they are the content the FAQ structured data describes. */
.faq-list {
	max-width: 46em;
	margin: 0 auto;
	text-align: left;
}

	.faq-item {
		padding: 1.25em 0;
		border-bottom: solid 1px rgba(72, 57, 73, 0.12);
	}

		.faq-item:last-child {
			border-bottom: 0;
		}

		.faq-item h3 {
			font-size: 1.05em;
			margin-bottom: 0.5em;
		}

		.faq-item p {
			margin: 0;
			text-align: left;
		}

/* Service pages (/web-development, /custom-software) - reuses the existing
   wrapper, container, feature-block and chip components. */
.service-intro {
	max-width: 46em;
}

	.service-intro p {
		font-size: 1.1em;
		line-height: 1.8em;
		margin-bottom: 1em;
	}

	.service-intro p:last-child {
		margin-bottom: 0;
	}

.service-capability-list {
	margin-top: 1.75em;
}

/* Support levels and platform cards on /website-hosting-support. Reuses the
   existing feature-block card; these only add the vertical list inside it,
   which the pill-style .pillar-list is the wrong shape for. */
.support-level-list {
	list-style: none;
	margin: 1em 0 0 0;
	padding: 0;
	text-align: left;
}

	.support-level-list li {
		position: relative;
		font-size: 0.9em;
		line-height: 1.6em;
		color: #584e59;
		padding: 0 0 0 1.25em;
		margin-bottom: 0.5em;
	}

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

		.support-level-list li::before {
			content: '';
			position: absolute;
			left: 0;
			top: 0.6em;
			width: 0.4em;
			height: 0.4em;
			border-radius: 50%;
			background: #df7366;
		}

	.support-level-lead {
		font-size: 0.9em;
		font-weight: 600;
		margin: 1em 0 0 0;
		text-align: left;
	}

	/* Scope and limitation wording under a level. Smaller than the list, but kept
	   at a contrast that still reads - it is the part clients need to notice. */
	.support-level-note {
		font-size: 0.82em;
		line-height: 1.6em;
		color: #6b626c;
		margin: 1.25em 0 0 0;
		padding-top: 1em;
		border-top: solid 1px rgba(72, 57, 73, 0.12);
		text-align: left;
	}

	.support-level .pillar-link {
		margin-top: 1em;
	}

/* Two-column audience list. Collapses to one column on narrow screens. */
.audience-list {
	list-style: none;
	max-width: 46em;
	margin: 0 auto;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 0.75em 2em;
	text-align: left;
}

	.audience-list li {
		position: relative;
		padding-left: 1.4em;
		line-height: 1.6em;
	}

		.audience-list li::before {
			content: '';
			position: absolute;
			left: 0;
			top: 0.62em;
			width: 0.45em;
			height: 0.45em;
			border-radius: 50%;
			background: #df7366;
		}

	@media screen and (max-width: 736px) {
		.audience-list {
			grid-template-columns: 1fr;
		}
	}

.service-note {
	max-width: 46em;
	margin: 2em auto 0 auto;
	font-style: italic;
	color: #7d7d7d;
}

.pillar-note {
	font-size: 0.85em;
	font-style: italic;
	color: #8a7f8b;
	margin-top: -0.5em;
}

/* Required accuracy statement for Public Health Trace. Deliberately quiet but
   legible - it must stay readable, so it is not shrunk below 0.85em. */
.product-disclaimer {
	max-width: 46em;
	margin: 1.75em auto 0 auto;
	padding: 0.4em 0 0.4em 1em;
	border-left: solid 3px rgba(72, 57, 73, 0.18);
	font-size: 0.82em;
	line-height: 1.65em;
	/* Deliberately quieter than body copy but kept at ~5:1 contrast - this is an
	   accuracy statement and has to stay readable. */
	color: #6b6b6b;
	text-align: left;
}

	/* Inline variant that sits inside a product card rather than below a section. */
	.product-disclaimer-compact {
		max-width: none;
		margin-top: 1em;
		padding-top: 0.85em;
		font-size: 0.78em;
		line-height: 1.6em;
	}

.example-media {
	display: block;
	border-radius: 0.4em;
	overflow: hidden;
}

.example-body {
	text-align: left;
}

	.example-body p {
		text-align: left;
	}

.process-list {
	max-width: 46em;
	margin: 0 auto;
	text-align: left;
	padding-left: 1.25em;
}

	.process-list li {
		padding-left: 0.5em;
		margin-bottom: 1em;
		line-height: 1.75em;
	}

/* Company positioning block under the problem-solving chips. */
.positioning-note {
	max-width: 46em;
	margin: 2.5em auto 0 auto;
	padding-top: 2em;
	border-top: solid 1px rgba(72, 57, 73, 0.12);
}

	.positioning-note h3 {
		font-size: 1.35em;
		line-height: 1.4em;
		margin-bottom: 0.9em;
	}

	.positioning-note p {
		margin-bottom: 1em;
	}

/* News article + listing card */
.article-banner .breadcrumbs {
	font-size: 0.8em;
	color: #8a7f8b;
	margin-bottom: 1em;
}

	.article-banner .breadcrumbs span {
		margin: 0 0.35em;
	}

.article-date {
	font-size: 1em !important;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #8a7f8b;
	margin: 0.75em 0 0 0 !important;
}

.news-article {
	max-width: 44em;
	text-align: left;
}

	.news-article p {
		text-align: left;
		margin-bottom: 1.25em;
	}

	.news-article-image {
		display: block;
		margin-bottom: 2.5em;
		border-radius: 0.4em;
		overflow: hidden;
		box-shadow: 0 2px 14px rgba(0, 0, 0, 0.08);
	}

		.news-article-image img {
			display: block;
			width: 100%;
		}

	.article-note {
		margin-top: 2em !important;
		padding-top: 1.5em;
		border-top: solid 1px rgba(72, 57, 73, 0.12);
		font-style: italic;
		color: #7d7d7d;
	}

	.article-cta {
		margin-top: 2em;
	}

		.article-cta .icon {
			margin-left: 0.4em;
		}

		.article-cta .icon:before {
			font-size: 0.85em;
		}

.news-listing-card,
.news-item {
	padding-bottom: 3em;
}

	.news-item footer .icon {
		margin-left: 0.4em;
	}

		.news-item footer .icon:before {
			font-size: 0.85em;
		}

	.news-listing-card footer .icon {
		margin-left: 0.4em;
	}

	.news-listing-card footer .icon:before {
		font-size: 0.85em;
	}

	/* Show the whole EmployEase artwork. A fixed-height cover crop on a
	   full-width card cut the image down to its middle band, which lost the
	   two hands meeting at the bottom of the image. */
	/* Needs three classes to beat .image.featured's own margin, or it stays
	   left-aligned instead of centering. */
	.image.featured.news-listing-image {
		display: block;
		max-width: 760px;
		margin: 0 auto 2em auto;
	}

		.news-listing-image img {
			display: block;
			width: 100%;
			height: auto;
		}

/* Project cards - 16:10 website previews, shared by Home and Our Work.
   Grid: 3 across on desktop, 2 at tablet (col-6-narrow), 1 on mobile. */
.project-card {
	display: flex;
	flex-direction: column;
	margin-bottom: 2em;
}

	.project-card-media {
		display: block;
		aspect-ratio: 16 / 10;
		overflow: hidden;
		border: solid 1px rgba(72, 57, 73, 0.12);
		border-radius: 0.4em;
		background: #f4f2f0;
		box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
		transition: box-shadow 0.25s ease-in-out;
	}

		.project-card-media img {
			width: 100%;
			height: 100%;
			object-fit: cover;
			object-position: top center;
		}

	.project-card-body {
		padding: 1em 0 0 0;
	}

		.project-card-body h3 {
			font-size: 1.15em;
			margin-bottom: 0.2em;
		}

	.project-card-industry {
		font-size: 0.85em;
		color: #8a7f8b;
		text-align: left;
		margin: 0 0 0.75em 0;
	}

	.project-card-tags {
		list-style: none;
		margin: 0 0 0.9em 0;
		padding: 0;
		display: flex;
		flex-wrap: wrap;
		gap: 0.4em;
	}

		.project-card-tags li {
			font-size: 0.78em;
			color: #584e59;
			background: #f1eeec;
			border-radius: 1em;
			padding: 0.28em 0.75em;
		}

	.project-card-link {
		display: inline-block;
		font-size: 0.9em;
		color: #df7366;
		border-bottom: 0;
	}

		.project-card-link:hover {
			color: #ef8376;
		}

		.project-card-link .icon {
			margin-left: 0.2em;
		}

		.project-card-link .icon:before {
			font-size: 0.85em;
		}

/* ---- Card grid entrance + hover/focus emphasis ----------------------------
   The reveal is opt-in per grid via [data-reveal-group], and the hiding rule
   only bites once the script has added .is-reveal-ready - so with JavaScript
   off the cards simply render, rather than staying invisible forever. */
[data-reveal-group].is-reveal-ready .project-card,
[data-reveal-group].is-reveal-ready .product-card {
	opacity: 0;
}

[data-reveal-group].is-revealed .project-card,
[data-reveal-group].is-revealed .product-card {
	opacity: 1;
	animation: cardReveal 0.5s ease-out both;
	animation-delay: var(--reveal-delay, 0ms);
}

	/* Once a card has finished arriving the animation is dropped, otherwise
	   animation-fill-mode would keep asserting transform:none and the hover
	   lift below would never apply. */
	[data-reveal-group] .project-card.is-reveal-done,
	[data-reveal-group] .product-card.is-reveal-done {
		animation: none;
		opacity: 1;
	}

@keyframes cardReveal {
	from {
		opacity: 0;
		transform: translateY(18px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* Hover and keyboard focus. :focus-within gives keyboard users the same
   emphasis, since every card's links are what receive focus. */
.project-card,
.product-card {
	transition: transform 0.2s ease-out;
}

	.project-card:hover,
	.project-card:focus-within,
	.product-card:hover,
	.product-card:focus-within {
		transform: translateY(-6px);
	}

.project-card-media,
.product-card-media {
	transition: box-shadow 0.2s ease-out, border-color 0.2s ease-out;
}

	.project-card-media img,
	.product-card-media img {
		transition: transform 0.2s ease-out;
	}

	/* Project cards already carry a hairline border, so the coral shift is a
	   border-color change. Product cards have none, so they get an equivalent
	   1px ring drawn as a shadow - no border means no layout shift or recrop. */
	.project-card:hover .project-card-media,
	.project-card:focus-within .project-card-media {
		border-color: rgba(223, 115, 102, 0.55);
		box-shadow: 0 6px 18px rgba(0, 0, 0, 0.13);
	}

	.product-card:hover .product-card-media,
	.product-card:focus-within .product-card-media {
		box-shadow: 0 0 0 1px rgba(223, 115, 102, 0.55), 0 6px 18px rgba(0, 0, 0, 0.13);
	}

	.project-card:hover .project-card-media img,
	.project-card:focus-within .project-card-media img,
	.product-card:hover .product-card-media img,
	.product-card:focus-within .product-card-media img {
		transform: scale(1.03);
	}

.project-card-link .icon {
	transition: transform 0.2s ease-out;
}

	.project-card:hover .project-card-link .icon,
	.project-card:focus-within .project-card-link .icon {
		transform: translateX(4px);
	}

@media (prefers-reduced-motion: reduce) {
	/* Every card present at once, no stagger, no movement - but the coral ring
	   and deeper shadow stay, so hover and focus still read. */
	[data-reveal-group].is-reveal-ready .project-card,
	[data-reveal-group].is-reveal-ready .product-card,
	[data-reveal-group].is-revealed .project-card,
	[data-reveal-group].is-revealed .product-card {
		opacity: 1;
		animation: none;
		animation-delay: 0ms;
		transform: none;
	}

	.project-card,
	.product-card,
	.project-card:hover,
	.project-card:focus-within,
	.product-card:hover,
	.product-card:focus-within {
		transform: none;
	}

	.project-card:hover .project-card-media img,
	.project-card:focus-within .project-card-media img,
	.product-card:hover .product-card-media img,
	.product-card:focus-within .product-card-media img,
	.project-card:hover .project-card-link .icon,
	.project-card:focus-within .project-card-link .icon {
		transform: none;
	}
}

/* Continuous client-logo marquee. The reel holds two identical copies of the
   strip, so translating it exactly -50% lands the duplicate where the original
   began and the loop has no visible seam. */
.carousel.is-marquee {
	overflow: hidden;
}

	.carousel.is-marquee .reel {
		display: flex;
		flex-wrap: nowrap;
		width: max-content;
		overflow: visible !important;
		transform: none;
		animation: logoMarquee linear infinite;
		will-change: transform;
	}

		/* Hovering holds the strip still - the logos are links, and hitting a
		   moving target is unreasonable. */
		.carousel.is-marquee:hover .reel,
		.carousel.is-marquee:focus-within .reel {
			animation-play-state: paused;
		}

		.carousel.is-marquee .reel > article {
			flex: 0 0 auto;
		}

@keyframes logoMarquee {
	from { transform: translateX(0); }
	to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
	.carousel.is-marquee .reel {
		animation: none;
	}
}

/* Case study pages */
.case-study-banner .breadcrumbs {
	font-size: 0.8em;
	color: #8a7f8b;
	margin-bottom: 1em;
}

	.case-study-banner .breadcrumbs span {
		margin: 0 0.35em;
	}

.case-study-industry {
	font-size: 1.1em !important;
	color: #8a7f8b;
	margin: 0.5em 0 0 0 !important;
}

.case-study-shot {
	margin-bottom: 2.5em;
	border: solid 1px rgba(72, 57, 73, 0.12);
	border-radius: 0.4em;
	overflow: hidden;
	box-shadow: 0 2px 14px rgba(0, 0, 0, 0.08);
}

	.case-study-shot img {
		display: block;
		width: 100%;
	}

.case-study {
	text-align: left;
}

	.case-study h2 {
		font-size: 1.5em;
		margin-bottom: 0.6em;
	}

	.case-study p {
		text-align: left;
	}

.case-study-meta {
	margin-bottom: 2.5em;
}

.case-study-narrative {
	max-width: 44em;
	margin-bottom: 3em;
}

	.case-study-narrative p {
		margin-bottom: 1.25em;
	}

.case-study-features {
	margin-bottom: 1em;
}


	/* Gutter rows carry margin-top:-40px, which pulls the feature blocks up far
	   enough that their coral top border cuts through the heading above, reading
	   as a strikethrough. Cancelling that pull leaves the children's own 40px
	   padding-top as clearance. Needs two classes to out-specify
	   .row.gtr-uniform, and horizontal gutters are left untouched. */
	.row.feature-row {
		margin-top: 0;
	}

	.feature-block {
		border-top: solid 2px #df7366;
		padding-top: 1em;
	}

		.feature-block h3 {
			font-size: 1.05em;
			margin-bottom: 0.4em;
		}

		.feature-block p {
			font-size: 0.9em;
			margin: 0;
		}

.case-study-actions {
	margin-top: 2.5em;
}

	.case-study-actions .button {
		margin: 0 0.6em 0.5em 0;
	}

	.case-study-actions .icon {
		margin-left: 0.4em;
	}

	.case-study-actions .icon:before {
		font-size: 0.85em;
	}

	@media screen and (max-width: 736px) {
		.case-study-actions .button {
			display: block;
			width: 100%;
			max-width: 320px;
			margin: 0 0 0.75em 0;
		}
	}

/* Recent Client Work */
.work-card {
	display: flex;
	flex-direction: column;
	border: solid 1px rgba(72, 57, 73, 0.1);
	border-radius: 0.4em;
	overflow: hidden;
	background: #fff;
	margin-bottom: 2em;
}

	.work-card-media {
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		height: 190px;
		padding: 1em;
		background: #f4f2f0;
		overflow: hidden;
	}

		.work-card-media img {
			width: auto;
			height: auto;
			max-width: 100%;
			max-height: 100%;
			object-fit: contain;
		}

	/* Cards backed by a real project screenshot instead of just a logo. */
	.work-card-media-screenshot {
		padding: 0;
		display: block;
	}

		.work-card-media-screenshot > img:first-child {
			width: 100%;
			height: 100%;
			max-width: none;
			max-height: none;
			object-fit: cover;
			object-position: top center;
		}

		.work-card-badge {
			position: absolute;
			left: 0.75em;
			bottom: 0.75em;
			max-width: 40%;
			max-height: 42px;
			padding: 0.35em 0.6em;
			background: rgba(255, 255, 255, 0.92);
			border-radius: 0.3em;
			box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
		}

	.work-card-media-placeholder {
		color: #9a9a9a;
		font-size: 0.85em;
		font-style: italic;
	}

	.work-card-body {
		padding: 1.1em 1.25em;
	}

		.work-card-body h3 {
			font-size: 1.1em;
			margin-bottom: 0.5em;
		}

	.work-card-tags {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-wrap: wrap;
		gap: 0.5em;
	}

		.work-card-tags li {
			font-size: 0.75em;
			color: #6b5f6c;
			background: #f4f2f0;
			border-radius: 1em;
			padding: 0.25em 0.75em;
		}

/* EmployEase spotlight - kept intentionally compact */
.employease-row {
	align-items: center;
}

.employease-copy .employease-note {
	color: #7d7d7d;
	font-style: italic;
}

.employease-media {
	text-align: center;
}

	.employease-media img {
		max-width: 260px;
		width: 100%;
		border-radius: 0.5em;
	}

	@media screen and (max-width: 736px) {
		.employease-media {
			margin-top: 2em;
		}

		.employease-media img {
			max-width: 200px;
		}
	}

/* Product cards */
.product-card {
	text-align: left;
}

	.product-card-media {
		display: block;
		aspect-ratio: 4 / 3;
		border-radius: 0.4em;
		overflow: hidden;
		margin-bottom: 1em;
	}

		.product-card-media img {
			width: 100%;
			height: 100%;
			object-fit: cover;
		}

	.product-card h3 {
		margin-bottom: 0.25em;
	}

	.product-tagline {
		margin-bottom: 0.5em;
		font-style: italic;
		color: #6b5f6c;
	}

	.product-category {
		display: inline-block;
		font-size: 0.75em;
		text-transform: uppercase;
		letter-spacing: 0.04em;
		color: #df7366;
	}

/* Testimonial / pull-quote */
.testimonial-section header {
	margin-bottom: 1.5em;
}

.featured-quote {
	max-width: 42em;
	margin: 0 auto;
	border-left: 0;
	padding: 0;
	font-style: normal;
	text-align: center;
}

	.featured-quote .icon {
		color: #df7366;
	}

		.featured-quote .icon:before {
			font-size: 2em;
		}

	.featured-quote p {
		font-size: 1.35em;
		line-height: 1.6em;
		color: #483949;
		text-align: center;
		margin: 0.5em 0 1em 0;
	}

	.featured-quote cite {
		font-style: normal;
		color: #7d7d7d;
	}

/* GEO / local relevance section */
.geo-section {
	max-width: 46em;
	margin: 0 auto;
	text-align: left;
}

	.geo-section header {
		text-align: left;
	}

	.geo-section h2 .icon {
		color: #df7366;
		margin-right: 0.3em;
	}

	.geo-section p {
		text-align: left;
	}

/* Clean footer */
.footer-grid {
	margin-bottom: 2em;
}

.footer-logo {
	font-size: 1.4em;
	color: #fff;
	margin-bottom: 0.5em;
}

.footer-about p,
.footer-nav p {
	text-align: left;
}

.footer-nav h4,
.footer-connect h4 {
	color: #fff;
	margin-bottom: 1em;
}

/* Two columns so the Explore list stops making the footer taller than the
   other two footer columns put together. Collapses back to one on mobile. */
.footer-links {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: 1.25em;
}

	@media screen and (max-width: 736px) {
		.footer-links {
			grid-template-columns: 1fr;
		}
	}

/* Shrink the Connect icon row so all five icons stay on one line at every
   breakpoint, instead of wrapping to a second row on narrower columns. */
.footer-connect .icons {
	font-size: 0.55em;
	white-space: nowrap;
	padding-left: 0.5em;
	padding-right: 0.5em;
}

	.footer-links li {
		margin-bottom: 0.6em;
	}

	.footer-links a {
		color: rgba(255, 255, 255, 0.75);
	}

		.footer-links a:hover {
			color: #fff;
		}

/* Respect reduced-motion preferences for the subtle glow/entrance effects
   already defined in main.css. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
	}
}
