/* ==========================================================================
   Unodevs — atmosphere layer

   Everything here is depth, light and kinetics. It loads after main.css and
   can be dequeued wholesale ('unodevs-aurora') by a child theme to get the
   plain version back.

   Ground rules kept throughout:
   - transform, opacity and filter only. No layout properties are animated.
   - Enter/exit use strong custom ease-out. ease-in is never used on UI.
   - Nothing scales from 0 — surfaces materialise from 0.94 with blur.
   - Every hover effect is behind (hover: hover) and (pointer: fine).
   - Scroll-driven effects are scrubbed by position, so they are reversible.

   Contents
   1.  Registered properties
   2.  Aurora
   3.  Grain
   4.  Conic gradient borders
   5.  Spotlight surfaces
   6.  Shine + arrow buttons
   7.  Line-mask text reveal
   8.  Hero stage
   9.  Kinetic type ribbon
   10. Bento grid
   11. Scroll-pinned story
   12. Sticky stacking cards
   13. Stats shell + odometer
   14. Index rows
   15. Team
   16. Contact
   17. Accordion, quotes, misc
   18. Cursor blend
   19. Reduced motion / transparency / contrast
   ========================================================================== */


/* 1. Registered properties
   --------------------------------------------------------------------------
   An unregistered custom property is a string, and strings do not
   interpolate. Registering the angle as <angle> is what lets the conic
   border actually rotate smoothly instead of snapping.
   ========================================================================== */

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

@property --u-spot-x {
	syntax: '<percentage>';
	inherits: false;
	initial-value: 50%;
}

@property --u-spot-y {
	syntax: '<percentage>';
	inherits: false;
	initial-value: 50%;
}


/* 2. Aurora
   --------------------------------------------------------------------------
   Three heavily blurred colour fields. They drift on a very slow loop and
   lean towards the pointer via --u-px / --u-py, which JavaScript updates on
   a spring so the lean has weight instead of tracking rigidly.

   The loop is deliberately slow (default 24s). Oscillation near 0.2Hz is
   genuinely uncomfortable to sit beside, so the setting floor is 10s.
   ========================================================================== */

[data-u-aurora-scope] { position: relative; isolation: isolate; }

.u-aurora {
	position: absolute;
	inset: -20% -10% auto;
	height: 130%;
	z-index: -1;
	pointer-events: none;
	overflow: hidden;
	opacity: var(--u-aurora-opacity, .7);
	contain: strict;
}

.u-aurora-blob {
	position: absolute;
	display: block;
	border-radius: 50%;
	filter: blur(90px);
	will-change: transform;
	transform:
		translate3d(
			calc(var(--u-px, 0) * var(--u-lean, 1) * 1px),
			calc(var(--u-py, 0) * var(--u-lean, 1) * 1px),
			0
		);
}

.u-aurora-1 {
	--u-lean: 1;
	top: -14%;
	left: 4%;
	width: 46vw;
	height: 46vw;
	background: radial-gradient(circle at 50% 50%, rgba(var(--u-primary-rgb), .55), transparent 66%);
	animation: u-drift-a var(--u-aurora-speed, 24s) var(--u-ease-in-out) infinite alternate;
}

.u-aurora-2 {
	--u-lean: -0.6;
	top: -4%;
	right: 2%;
	width: 40vw;
	height: 40vw;
	background: radial-gradient(circle at 50% 50%, rgba(var(--u-accent-rgb), .5), transparent 66%);
	animation: u-drift-b calc(var(--u-aurora-speed, 24s) * 1.35) var(--u-ease-in-out) infinite alternate;
}

.u-aurora-3 {
	--u-lean: 0.35;
	top: 26%;
	left: 34%;
	width: 34vw;
	height: 34vw;
	background: radial-gradient(circle at 50% 50%, rgba(var(--u-primary-rgb), .32), transparent 68%);
	animation: u-drift-c calc(var(--u-aurora-speed, 24s) * 1.7) var(--u-ease-in-out) infinite alternate;
}

.u-aurora-soft { opacity: calc(var(--u-aurora-opacity, .7) * .55); }
.u-aurora-soft .u-aurora-blob { filter: blur(110px); }

/* Composed with the pointer lean via individual transform properties, so
   the drift keyframes and the pointer lean never fight over `transform`. */
@keyframes u-drift-a {
	from { translate: 0 0; scale: 1; }
	to   { translate: 6% 5%; scale: 1.14; }
}
@keyframes u-drift-b {
	from { translate: 0 0; scale: 1.08; }
	to   { translate: -7% 8%; scale: .92; }
}
@keyframes u-drift-c {
	from { translate: 0 0; scale: .95; }
	to   { translate: 5% -6%; scale: 1.18; }
}


/* 3. Grain
   --------------------------------------------------------------------------
   One SVG turbulence tile, inline as a data URI. Fixed to the viewport,
   pointer-events off, sitting above the background and below content.
   ========================================================================== */

.u-grain {
	position: fixed;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	opacity: var(--u-grain-opacity, .04);
	mix-blend-mode: overlay;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
	background-size: 160px 160px;
}


/* 4. Conic gradient borders
   --------------------------------------------------------------------------
   A rotating conic gradient painted into a 1px ring using two backgrounds
   and mask compositing. The angle is a registered <angle>, so it rotates
   continuously rather than jumping between two states.
   ========================================================================== */

.u-conic { position: relative; }

.u-conic::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	padding: 1px;
	background: conic-gradient(
		from var(--u-angle),
		transparent 0deg,
		rgba(var(--u-primary-rgb), .85) 60deg,
		rgba(var(--u-accent-rgb), .85) 130deg,
		transparent 210deg,
		transparent 360deg
	);
	-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: .55;
	pointer-events: none;
	animation: u-rotate 9s linear infinite;
	transition: opacity 300ms var(--u-ease-out);
}

@keyframes u-rotate { to { --u-angle: 360deg; } }

@media (hover: hover) and (pointer: fine) {
	.u-conic:hover::before { opacity: 1; }
}


/* 5. Spotlight surfaces
   --------------------------------------------------------------------------
   A soft radial highlight follows the pointer inside the element. Position
   comes from two registered percentage properties updated on pointermove,
   so the highlight itself never triggers layout or paint of the content.
   ========================================================================== */

.u-spotlight { position: relative; overflow: hidden; }

.u-spotlight::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: radial-gradient(
		420px circle at var(--u-spot-x) var(--u-spot-y),
		rgba(var(--u-primary-rgb), .16),
		transparent 62%
	);
	opacity: 0;
	pointer-events: none;
	transition: opacity 260ms var(--u-ease-out);
	z-index: 0;
}

.u-spotlight > * { position: relative; z-index: 1; }

@media (hover: hover) and (pointer: fine) {
	.u-spotlight:hover::after { opacity: 1; }
}


/* 6. Shine + arrow buttons
   --------------------------------------------------------------------------
   The shine is a clip-path wipe rather than a moving pseudo-element, so it
   never contributes to layout. Press feedback stays instant.
   ========================================================================== */

.u-btn { position: relative; overflow: hidden; }
.u-btn > span { position: relative; z-index: 1; }

.u-shine::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, .38) 50%, transparent 62%);
	transform: translateX(-120%);
	transition: transform 620ms var(--u-ease-out);
	pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
	.u-shine:hover::before { transform: translateX(120%); }
}

.u-arrow-link .u-icon { transition: transform 220ms var(--u-ease-out); }
@media (hover: hover) and (pointer: fine) {
	.u-arrow-link:hover .u-icon { transform: translateX(4px); }
}

/* Copy button swaps its label without changing width, so the row never
   reflows mid-interaction. */
.u-copy .u-copy-label { transition: opacity 140ms ease; }
.u-copy.is-copied .u-copy-label { opacity: .55; }

.u-dot-live {
	display: inline-block;
	width: 7px;
	height: 7px;
	margin-right: 8px;
	border-radius: 50%;
	background: #22c55e;
	box-shadow: 0 0 0 0 rgba(34, 197, 94, .55);
	animation: u-ping 2.4s var(--u-ease-out) infinite;
}
@keyframes u-ping {
	0%   { box-shadow: 0 0 0 0 rgba(34, 197, 94, .5); }
	70%  { box-shadow: 0 0 0 9px rgba(34, 197, 94, 0); }
	100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
}


/* 7. Line-mask text reveal
   --------------------------------------------------------------------------
   Each line sits inside an overflow-hidden box and rises from below with a
   little blur that resolves as it settles. Blur bridges the visual gap so
   the eye reads one smooth movement rather than a sliding object.
   ========================================================================== */

[data-u-lines] { display: block; }

[data-u-lines] .u-line {
	display: block;
	overflow: hidden;
	padding-bottom: .06em;
	margin-bottom: -.06em;
}

[data-u-lines] .u-line-in {
	display: block;
	transform: translateY(108%);
	filter: blur(10px);
	opacity: 0;
	transition:
		transform 900ms var(--u-ease-out),
		filter 700ms var(--u-ease-out),
		opacity 500ms var(--u-ease-out);
	transition-delay: calc(var(--i, 0) * 90ms);
	will-change: transform;
}

[data-u-lines].is-in .u-line-in {
	transform: none;
	filter: none;
	opacity: 1;
}

.u-no-motion [data-u-lines] .u-line-in,
.u-no-lines [data-u-lines] .u-line-in {
	transform: none;
	filter: none;
	opacity: 1;
	transition: none;
}

/* Scramble text settles into place; the monospace lock stops the line
   width jittering while characters cycle. */
.u-scramble.is-scrambling { font-variant-numeric: tabular-nums; }


/* 8. Hero stage
   ========================================================================== */

.u-hero { padding-block: clamp(110px, 16vw, 210px) clamp(60px, 8vw, 110px); }
.u-hero-title { max-width: 15ch; }

.u-hero-stage { position: relative; margin-top: clamp(50px, 7vw, 90px); }

.u-hero-panel {
	position: relative;
	max-width: 620px;
	padding: 0;
	overflow: hidden;
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-lg);
	will-change: transform;
}

.u-hero-panel-bar {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 15px 20px;
	border-bottom: 1px solid var(--u-glass-edge);
}
.u-hero-panel-bar span {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: rgba(var(--u-text-rgb), .18);
}
.u-hero-panel-bar em {
	margin-left: auto;
	font-style: normal;
	font-size: .74rem;
	letter-spacing: .04em;
	color: var(--u-muted);
}

.u-hero-panel-body {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 30px;
	padding: 28px;
}

.u-hero-metric strong {
	display: block;
	font-family: var(--u-font-heading);
	font-size: clamp(2.8rem, 6vw, 3.6rem);
	line-height: 1;
	letter-spacing: -0.045em;
	background: linear-gradient(135deg, var(--u-primary), var(--u-accent));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
.u-hero-metric span {
	display: block;
	max-width: 26ch;
	margin-top: 10px;
	font-size: .85rem;
	color: var(--u-muted);
}

.u-hero-bars { display: flex; align-items: flex-end; gap: 7px; height: 96px; }
.u-hero-bars span {
	width: 13px;
	height: var(--h);
	min-height: 10px;
	border-radius: 5px;
	background: linear-gradient(180deg, var(--u-primary), var(--u-accent));
	transform-origin: bottom;
	transform: scaleY(0.04);
	transition: transform 780ms var(--u-ease-out);
	transition-delay: var(--d, 0ms);
}
[data-u-reveal].is-in .u-hero-bars span { transform: none; }

.u-hero-chip {
	position: absolute;
	display: inline-flex;
	align-items: center;
	padding: 10px 16px;
	border-radius: var(--u-radius-pill);
	font-size: .82rem;
	font-weight: 540;
	box-shadow: var(--u-shadow);
	white-space: nowrap;
	will-change: transform;
}
.u-hero-chip { top: 12%; right: -2%; }
.u-hero-chip-b { top: auto; bottom: 8%; right: 14%; }

.u-float-a { animation: u-float 7s var(--u-ease-in-out) infinite alternate; }
.u-float-b { animation: u-float 9s var(--u-ease-in-out) infinite alternate-reverse; }
@keyframes u-float {
	from { translate: 0 0; rotate: -1.2deg; }
	to   { translate: 0 -14px; rotate: 1.2deg; }
}

.u-scroll-hint {
	display: flex;
	justify-content: center;
	margin-top: clamp(40px, 6vw, 72px);
}
.u-scroll-rail {
	display: block;
	width: 22px;
	height: 38px;
	border: 1.5px solid rgba(var(--u-text-rgb), .22);
	border-radius: 12px;
	position: relative;
}
.u-scroll-bead {
	position: absolute;
	left: 50%;
	top: 7px;
	width: 3px;
	height: 7px;
	margin-left: -1.5px;
	border-radius: 2px;
	background: var(--u-primary);
	animation: u-bead 1.9s var(--u-ease-in-out) infinite;
}
@keyframes u-bead {
	0%, 100% { transform: translateY(0); opacity: 1; }
	60%      { transform: translateY(14px); opacity: .15; }
}


/* 9. Kinetic type ribbon
   ========================================================================== */

.u-ribbon {
	padding-block: clamp(40px, 6vw, 80px);
	overflow: hidden;
	user-select: none;
}
.u-ribbon-row {
	overflow: hidden;
	mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.u-ribbon-track {
	display: flex;
	align-items: center;
	gap: 34px;
	width: max-content;
	will-change: transform;
	/* Constant motion, so linear. The scroll nudge is applied by JS as a
	   separate translate, which is why the loop itself never eases. */
	animation: u-scroll-x 38s linear infinite;
}
.u-ribbon-b .u-ribbon-track { animation-duration: 46s; animation-direction: reverse; }
.u-ribbon:hover .u-ribbon-track { animation-play-state: paused; }

@keyframes u-scroll-x { to { transform: translateX(-50%); } }

.u-ribbon-word {
	font-family: var(--u-font-heading);
	font-size: clamp(2.4rem, 7vw, 5.2rem);
	font-weight: 680;
	letter-spacing: -0.045em;
	line-height: 1;
	white-space: nowrap;
	background: linear-gradient(120deg, var(--u-text), var(--u-muted));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
.u-ribbon-word.is-outline {
	background: none;
	color: transparent;
	-webkit-text-stroke: 1.4px rgba(var(--u-text-rgb), .28);
}
.u-ribbon-sep {
	font-size: clamp(.9rem, 2vw, 1.4rem);
	color: var(--u-primary);
	opacity: .75;
}


/* 10. Bento grid
   ========================================================================== */

.u-bento {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(14px, 1.8vw, 22px);
	grid-auto-rows: minmax(190px, auto);
}

.u-tile {
	display: flex;
	flex-direction: column;
	gap: 14px;
	padding: clamp(28px, 3vw, 38px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-sm);
	transition: transform 300ms var(--u-ease-out), box-shadow 320ms var(--u-ease-out);
}
.u-tile-lg { grid-row: span 2; }
.u-tile-wide { grid-column: span 2; flex-direction: row; align-items: center; gap: 28px; }

.u-tile h3 { font-size: 1.15rem; margin: 0; letter-spacing: -0.022em; line-height: 1.3; }
.u-tile p { margin: 0; color: var(--u-muted); font-size: .94rem; line-height: 1.65; }
.u-tile-lg h3 { font-size: 1.45rem; }
.u-tile-copy { display: grid; gap: 12px; }
.u-tile-icon { margin-bottom: 6px; }

@media (hover: hover) and (pointer: fine) {
	.u-tile:hover { transform: translateY(-4px); box-shadow: var(--u-shadow); }
}

.u-tile-icon {
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	border-radius: 13px;
	background: linear-gradient(135deg, rgba(var(--u-primary-rgb), .18), rgba(var(--u-accent-rgb), .18));
	color: var(--u-primary);
}
.u-tile-icon svg {
	width: 22px;
	height: 22px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.7;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* Orbit graphic — three rings, three beads, all rotation only. */
.u-tile-visual { flex: 1; display: grid; place-items: center; min-height: 200px; }
.u-orbit { position: relative; width: 210px; height: 210px; }
.u-orbit-core {
	position: absolute;
	inset: 42%;
	border-radius: 50%;
	background: linear-gradient(135deg, var(--u-primary), var(--u-accent));
	box-shadow: 0 0 34px rgba(var(--u-primary-rgb), .55);
}
.u-orbit-ring {
	position: absolute;
	inset: 0;
	border: 1px solid rgba(var(--u-text-rgb), .14);
	border-radius: 50%;
	animation: u-rotate-360 var(--s, 14s) linear infinite;
}
.u-orbit-ring i {
	position: absolute;
	top: -4px;
	left: 50%;
	width: 8px;
	height: 8px;
	margin-left: -4px;
	border-radius: 50%;
	background: var(--u-primary);
	box-shadow: 0 0 12px rgba(var(--u-primary-rgb), .8);
}
.u-orbit-r1 { --s: 12s; inset: 6%; }
.u-orbit-r2 { --s: 19s; inset: 20%; animation-direction: reverse; }
.u-orbit-r2 i { background: var(--u-accent); box-shadow: 0 0 12px rgba(var(--u-accent-rgb), .8); }
.u-orbit-r3 { --s: 27s; inset: 32%; }
@keyframes u-rotate-360 { to { transform: rotate(360deg); } }

.u-tile-meter { display: grid; gap: 8px; min-width: 190px; }
.u-meter-label, .u-meter-value { font-size: .78rem; color: var(--u-muted); letter-spacing: .04em; text-transform: uppercase; }
.u-meter-value { color: var(--u-primary); font-weight: 620; }
.u-meter-bar {
	display: block;
	height: 7px;
	border-radius: 4px;
	background: rgba(var(--u-text-rgb), .1);
	overflow: hidden;
}
.u-meter-bar i {
	display: block;
	width: var(--w, 20%);
	height: 100%;
	border-radius: 4px;
	background: linear-gradient(90deg, var(--u-primary), var(--u-accent));
	transform-origin: left;
	transform: scaleX(0);
	transition: transform 900ms var(--u-ease-out) 200ms;
}
[data-u-reveal].is-in .u-meter-bar i { transform: none; }


/* 11. Scroll-pinned story
   ========================================================================== */

.u-story { position: relative; height: 320vh; }
.u-story-pin {
	position: sticky;
	top: 0;
	height: 100vh;
	display: grid;
	align-items: center;
	overflow: hidden;
}
.u-story-inner {
	display: grid;
	grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
	gap: clamp(32px, 6vw, 80px);
	align-items: center;
}

.u-story-nav { list-style: none; margin: 28px 0 0; padding: 0; display: grid; gap: 14px; }
.u-story-nav li {
	display: flex;
	align-items: center;
	gap: 12px;
	font-size: .95rem;
	color: var(--u-muted);
	transition: color 260ms ease;
}
.u-story-nav li.is-active { color: var(--u-text); }
.u-story-tick {
	display: block;
	width: 34px;
	height: 2px;
	border-radius: 2px;
	background: rgba(var(--u-text-rgb), .18);
	transform-origin: left;
	transition: transform 320ms var(--u-ease-out), background-color 260ms ease;
}
.u-story-nav li.is-active .u-story-tick {
	background: var(--u-primary);
	transform: scaleX(1.7);
}

.u-story-stage { position: relative; min-height: 340px; }
.u-story-panel {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 14px;
	padding: clamp(28px, 4vw, 44px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-lg);
	/* Materialise: scale and blur move together, never from scale(0). */
	opacity: 0;
	transform: scale(.955) translateY(14px);
	filter: blur(8px);
	pointer-events: none;
	transition:
		opacity 420ms var(--u-ease-out),
		transform 520ms var(--u-ease-out),
		filter 460ms var(--u-ease-out);
}
.u-story-panel.is-active {
	opacity: 1;
	transform: none;
	filter: none;
	pointer-events: auto;
}
.u-story-index {
	font-family: var(--u-font-heading);
	font-size: 3.2rem;
	line-height: 1;
	letter-spacing: -0.05em;
	color: transparent;
	-webkit-text-stroke: 1.4px rgba(var(--u-primary-rgb), .55);
}
.u-story-panel h3 { font-size: clamp(1.3rem, 2.4vw, 1.9rem); margin: 0; }
.u-story-panel p { margin: 0; color: var(--u-muted); }


/* 12. Sticky stacking cards
   ========================================================================== */

.u-stack { list-style: none; margin: 0; padding: 0; }
.u-stack-item {
	position: sticky;
	top: calc(96px + (var(--n) * 16px));
	padding-bottom: 22px;
}
.u-stack-card {
	padding: clamp(26px, 3.4vw, 42px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow);
	transform-origin: top center;
	/* Scaled by JS from scroll position, so it is scrubbable and reversible. */
	will-change: transform;
}
.u-stack-card header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 16px;
}
.u-stack-n {
	font-family: var(--u-font-heading);
	font-size: 1.6rem;
	letter-spacing: -0.04em;
	background: linear-gradient(135deg, var(--u-primary), var(--u-accent));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
.u-stack-meta {
	font-size: .76rem;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--u-muted);
	padding: 5px 12px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius-pill);
}
.u-stack-card h3 { font-size: clamp(1.3rem, 2.6vw, 2rem); margin: 0 0 .4em; }
.u-stack-card p { margin: 0; color: var(--u-muted); max-width: 60ch; }


/* 13. Stats shell + odometer
   ========================================================================== */

.u-stats-shell {
	border-radius: var(--u-radius-lg);
	padding: clamp(28px, 4vw, 52px);
	box-shadow: var(--u-shadow);
}
.u-odometer { font-variant-numeric: tabular-nums; }


/* 14. Index rows
   ========================================================================== */

.u-index { list-style: none; margin: 0; padding: 0; }
.u-index-row {
	position: relative;
	display: grid;
	grid-template-columns: 72px minmax(0, 1fr) minmax(0, 1.5fr);
	gap: clamp(16px, 3vw, 40px);
	align-items: start;
	padding: clamp(22px, 3vw, 34px) 0;
	transition: transform 300ms var(--u-ease-out);
}
.u-index-rule {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 1px;
	background: var(--u-border);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 900ms var(--u-ease-out);
}
[data-u-reveal].is-in .u-index-rule { transform: none; }

.u-index-n {
	font-family: var(--u-font-heading);
	font-size: .95rem;
	letter-spacing: .06em;
	color: var(--u-primary);
	padding-top: .35em;
}
.u-index-row h3 { margin: 0; font-size: clamp(1.15rem, 2.2vw, 1.5rem); }
.u-index-row p { margin: 0; color: var(--u-muted); }

@media (hover: hover) and (pointer: fine) {
	.u-index-row:hover { transform: translateX(6px); }
}


/* 15. Team
   ========================================================================== */

.u-team-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(14px, 2vw, 22px);
}

.u-person {
	padding: clamp(22px, 2.6vw, 30px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-sm);
	transition: transform 300ms var(--u-ease-out), box-shadow 320ms var(--u-ease-out);
}
.u-person-top { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 20px; }

.u-person-avatar {
	display: grid;
	place-items: center;
	width: 62px;
	height: 62px;
	border-radius: 20px;
	background: linear-gradient(135deg, var(--u-primary), var(--u-accent));
	color: #fff;
	font-weight: 660;
	letter-spacing: .02em;
	font-size: 1.05rem;
	box-shadow: var(--u-shadow-sm);
	transition: transform 340ms var(--u-ease-out), border-radius 340ms var(--u-ease-out);
}
.u-person-tag {
	font-size: .72rem;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--u-muted);
	padding: 5px 11px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius-pill);
}
.u-person-name { font-size: 1.12rem; margin: 0 0 .25em; }

/* The role line rises out of its own clip mask on hover — a second layer
   of information that was always there, not a state that appears. */
.u-person-role { overflow: hidden; margin: 0 0 .7em; }
.u-person-role span {
	display: block;
	font-size: .9rem;
	color: var(--u-primary);
	transform: translateY(0);
	transition: transform 320ms var(--u-ease-out);
}
.u-person-bio { margin: 0; color: var(--u-muted); font-size: .93rem; }

@media (hover: hover) and (pointer: fine) {
	.u-person:hover { transform: translateY(-5px); box-shadow: var(--u-shadow); }
	.u-person:hover .u-person-avatar { transform: rotate(-6deg) scale(1.06); border-radius: 26px; }
}

.u-hiring-panel {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: clamp(24px, 4vw, 56px);
	flex-wrap: wrap;
	padding: clamp(30px, 4.5vw, 56px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow);
	background-image: linear-gradient(135deg, rgba(var(--u-primary-rgb), .10), rgba(var(--u-accent-rgb), .10));
}
.u-hiring-panel h2 { font-size: clamp(1.4rem, 2.8vw, 2.1rem); max-width: 20ch; margin: 0 0 .4em; }
.u-hiring-panel p { margin: 0; color: var(--u-muted); max-width: 52ch; }


/* 16. Contact
   ========================================================================== */

.u-contact-primary { display: grid; gap: 18px; align-content: start; }

.u-mail-card {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	grid-template-areas: "label go" "address go";
	align-items: center;
	gap: 6px 20px;
	padding: clamp(26px, 3.6vw, 40px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow);
	transition: transform 300ms var(--u-ease-out), box-shadow 320ms var(--u-ease-out);
}
.u-mail-label { grid-area: label; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--u-muted); }
.u-mail-address {
	grid-area: address;
	font-family: var(--u-font-heading);
	font-size: clamp(1.3rem, 3.4vw, 2.2rem);
	letter-spacing: -0.03em;
	word-break: break-word;
}
.u-mail-go {
	grid-area: go;
	display: grid;
	place-items: center;
	width: 52px;
	height: 52px;
	border-radius: var(--u-radius-pill);
	background: var(--u-primary);
	color: #fff;
	transition: transform 280ms var(--u-ease-out);
}
@media (hover: hover) and (pointer: fine) {
	.u-mail-card:hover { transform: translateY(-3px); box-shadow: var(--u-shadow-lg); }
	.u-mail-card:hover .u-mail-go { transform: translateX(4px); }
}

.u-contact-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.u-contact-note { color: var(--u-muted); font-size: .88rem; max-width: 62ch; margin: 6px 0 0; }

.u-side-card {
	padding: 22px;
	border-radius: var(--u-radius);
	box-shadow: var(--u-shadow-sm);
}
.u-side-card h2 { display: flex; align-items: center; font-size: .95rem; margin: 0 0 .6em; }
.u-side-card p, .u-side-card address { margin: 0; color: var(--u-muted); font-size: .93rem; font-style: normal; }
.u-ticks-sm li { font-size: .9rem; }
.u-ticks-sm { margin: 0; }


/* 17. Accordion, quotes, misc
   ========================================================================== */

.u-acc-item { background: var(--u-glass-bg); backdrop-filter: blur(var(--u-blur)) saturate(var(--u-saturate)); -webkit-backdrop-filter: blur(var(--u-blur)) saturate(var(--u-saturate)); border-color: var(--u-glass-edge); }
.u-acc-plus {
	position: relative;
	width: 16px;
	height: 16px;
	flex: none;
}
.u-acc-plus::before, .u-acc-plus::after {
	content: "";
	position: absolute;
	inset: 50% 0 auto;
	height: 1.8px;
	background: currentColor;
	border-radius: 2px;
	transition: transform 260ms var(--u-ease-out), opacity 200ms ease;
}
.u-acc-plus::after { transform: rotate(90deg); }
.u-acc-item[open] .u-acc-plus::after { transform: rotate(0deg); opacity: 0; }

.u-quote-card {
	position: relative;
	padding: clamp(30px, 4vw, 48px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow);
	will-change: transform;
}
.u-quote-card p {
	margin: 0;
	font-family: var(--u-font-heading);
	font-size: clamp(1.15rem, 2.4vw, 1.6rem);
	letter-spacing: -0.025em;
	line-height: 1.3;
}
.u-quote-mark {
	position: absolute;
	top: 6px;
	right: 22px;
	font-family: var(--u-font-heading);
	font-size: 7rem;
	line-height: 1;
	color: rgba(var(--u-primary-rgb), .16);
	pointer-events: none;
}

/* Builder pages get the container stripped so Elementor sections can run
   edge to edge, which is what people expect from a "full width" template.
   The width decision is made in unodevs_page_content(); these rules only
   make sure nothing further up the tree re-constrains it. */
.u-editable.is-builder { display: block; width: 100%; max-width: none; }
.u-editable.is-builder > .elementor { width: 100%; }
.u-page-fullwidth > .u-editable { display: block; }
.u-main-blank { min-height: 100vh; }
.u-builder-page .u-page-head { padding-bottom: 0; }

/* Elementor renders its own section padding, so the theme must not add a
   second layer of it around the builder's output. */
.u-builder-page .u-main > .u-page-article > .u-editable.is-builder { padding: 0; }

/* Page heads that carry their own aurora need the stacking context and a
   little more room for it. */
.u-page-head[data-u-aurora-scope] { overflow: hidden; }


/* 17b. Surface styles — the site-wide material
   --------------------------------------------------------------------------
   One class on <body> swaps the material used by every surface on the page:
   header, cards, bento tiles, drawers, dialogs, panels, footer, chips.

   Each mode is a complete material rather than a filter layered on the last
   one, which is why every mode resets backdrop-filter and box-shadow
   explicitly instead of assuming what came before.

   The surface list is deliberately written out once per mode. It is long,
   but it means adding a mode is a copy-paste of one block rather than a
   hunt through the whole stylesheet.
   ========================================================================== */

:root {
	--u-soft-depth: .6;
	--u-soft-dist: 10px;
	--u-soft-blur: 22px;
}

/* The surfaces every mode restyles. */
body.u-surface-soft .u-glass,
body.u-surface-soft .u-card,
body.u-surface-soft .u-tile,
body.u-surface-soft .u-person,
body.u-surface-soft .u-package,
body.u-surface-soft .u-quote,
body.u-surface-soft .u-stack-card,
body.u-surface-soft .u-story-panel,
body.u-surface-soft .u-hero-panel,
body.u-surface-soft .u-side-card,
body.u-surface-soft .u-mail-card,
body.u-surface-soft .u-stats-shell,
body.u-surface-soft .u-closing-panel,
body.u-surface-soft .u-cta-panel,
body.u-surface-soft .u-hiring-panel,
body.u-surface-soft .u-quote-card,
body.u-surface-soft .u-acc-item,
body.u-surface-soft .u-hero-chip,
body.u-surface-soft .u-header-bar,
body.u-surface-soft .u-drawer-panel,
body.u-surface-soft .u-search-panel,
body.u-surface-soft .u-coming-panel {
	/* Soft UI: the surface is the same colour as the page and is lit from
	   the top left, so it reads as extruded rather than layered. Two
	   shadows — one light, one dark — are what sell it. */
	background: var(--u-bg);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid rgba(var(--u-text-rgb), .05);
	box-shadow:
		calc(var(--u-soft-dist) * -1) calc(var(--u-soft-dist) * -1) var(--u-soft-blur) rgba(255, 255, 255, calc(var(--u-soft-depth) * .9)),
		var(--u-soft-dist) var(--u-soft-dist) var(--u-soft-blur) rgba(var(--u-shadow-rgb), calc(var(--u-soft-depth) * .18));
}

body.u-surface-soft .u-btn-ghost {
	background: var(--u-bg);
	border-color: rgba(var(--u-text-rgb), .05);
	box-shadow:
		-4px -4px 10px rgba(255, 255, 255, .85),
		4px 4px 10px rgba(var(--u-shadow-rgb), .16);
}
body.u-surface-soft .u-btn-ghost:active {
	/* Pressed means inset — the shadow flips inward rather than the button
	   just scaling, because that is what an extruded control does. */
	box-shadow:
		inset -3px -3px 7px rgba(255, 255, 255, .8),
		inset 3px 3px 7px rgba(var(--u-shadow-rgb), .2);
}

/* Flat --------------------------------------------------------------- */

body.u-surface-flat .u-glass,
body.u-surface-flat .u-card,
body.u-surface-flat .u-tile,
body.u-surface-flat .u-person,
body.u-surface-flat .u-package,
body.u-surface-flat .u-quote,
body.u-surface-flat .u-stack-card,
body.u-surface-flat .u-story-panel,
body.u-surface-flat .u-hero-panel,
body.u-surface-flat .u-side-card,
body.u-surface-flat .u-mail-card,
body.u-surface-flat .u-stats-shell,
body.u-surface-flat .u-closing-panel,
body.u-surface-flat .u-cta-panel,
body.u-surface-flat .u-hiring-panel,
body.u-surface-flat .u-quote-card,
body.u-surface-flat .u-acc-item,
body.u-surface-flat .u-hero-chip,
body.u-surface-flat .u-header-bar,
body.u-surface-flat .u-drawer-panel,
body.u-surface-flat .u-search-panel,
body.u-surface-flat .u-coming-panel {
	background: var(--u-surface);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid var(--u-border);
	box-shadow: none;
}

/* Outline ------------------------------------------------------------ */

body.u-surface-outline .u-glass,
body.u-surface-outline .u-card,
body.u-surface-outline .u-tile,
body.u-surface-outline .u-person,
body.u-surface-outline .u-package,
body.u-surface-outline .u-quote,
body.u-surface-outline .u-stack-card,
body.u-surface-outline .u-story-panel,
body.u-surface-outline .u-hero-panel,
body.u-surface-outline .u-side-card,
body.u-surface-outline .u-mail-card,
body.u-surface-outline .u-stats-shell,
body.u-surface-outline .u-closing-panel,
body.u-surface-outline .u-cta-panel,
body.u-surface-outline .u-hiring-panel,
body.u-surface-outline .u-quote-card,
body.u-surface-outline .u-acc-item,
body.u-surface-outline .u-hero-chip {
	background: transparent;
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid rgba(var(--u-text-rgb), .16);
	box-shadow: none;
}

/* ---------------------------------------------------------------------
   THE OVERLAYS KEEP A SOLID BACKGROUND, EVEN IN OUTLINE MODE.

   This was the "side menu is see-through on some demos" bug, and it was
   this rule: the drawer, the search panel and the coming-soon panel were
   in the list above, being given `background: transparent` outright.

   For a card that is correct — a card sits on the page background, so
   transparent shows the page background and the outline reads as intended.
   An overlay is the opposite case. It covers arbitrary page content, so
   transparent shows headlines and photographs straight through the menu,
   and the navigation becomes unreadable over exactly the parts of a page
   that are busiest.

   The principle was already understood here: the header bar was pulled out
   of that list for this very reason, in the rule that used to sit directly
   below this one. The three overlays simply never got the same treatment.

   They keep the outline border, so the mode still looks like itself. Only
   the background is made solid.
   --------------------------------------------------------------------- */
body.u-surface-outline .u-drawer-panel,
body.u-surface-outline .u-search-panel,
body.u-surface-outline .u-coming-panel {
	background: var(--u-surface);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid rgba(var(--u-text-rgb), .16);
	box-shadow: none;
}

/* The header still needs to be readable over content scrolling under it. */
body.u-surface-outline .u-header-bar {
	background: var(--u-bg);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid rgba(var(--u-text-rgb), .16);
	box-shadow: none;
}
body.u-surface-outline .u-closing-panel,
body.u-surface-outline .u-cta-panel,
body.u-surface-outline .u-hiring-panel { background-image: none; }

/* Hard shadow -------------------------------------------------------- */

body.u-surface-brutal .u-glass,
body.u-surface-brutal .u-card,
body.u-surface-brutal .u-tile,
body.u-surface-brutal .u-person,
body.u-surface-brutal .u-package,
body.u-surface-brutal .u-quote,
body.u-surface-brutal .u-stack-card,
body.u-surface-brutal .u-story-panel,
body.u-surface-brutal .u-hero-panel,
body.u-surface-brutal .u-side-card,
body.u-surface-brutal .u-mail-card,
body.u-surface-brutal .u-stats-shell,
body.u-surface-brutal .u-closing-panel,
body.u-surface-brutal .u-cta-panel,
body.u-surface-brutal .u-hiring-panel,
body.u-surface-brutal .u-quote-card,
body.u-surface-brutal .u-acc-item,
body.u-surface-brutal .u-hero-chip,
body.u-surface-brutal .u-header-bar,
body.u-surface-brutal .u-drawer-panel,
body.u-surface-brutal .u-search-panel,
body.u-surface-brutal .u-coming-panel {
	background: var(--u-surface);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 2px solid var(--u-text);
	box-shadow: 6px 6px 0 0 var(--u-text);
}
body.u-surface-brutal .u-btn {
	border: 2px solid var(--u-text);
	box-shadow: 3px 3px 0 0 var(--u-text);
}
@media (hover: hover) and (pointer: fine) {
	body.u-surface-brutal .u-tile:hover,
	body.u-surface-brutal .u-person:hover {
		transform: translate(-2px, -2px);
		box-shadow: 8px 8px 0 0 var(--u-text);
	}
}
body.u-surface-brutal .u-btn:active { transform: translate(3px, 3px); box-shadow: 0 0 0 0 var(--u-text); }
/* The rotating gradient edge fights a hard 2px outline, so it steps aside. */
body.u-surface-brutal .u-conic::before { display: none; }

/* Master switch off --------------------------------------------------- */

body.u-surface-off .u-glass,
body.u-surface-off .u-card,
body.u-surface-off .u-tile,
body.u-surface-off .u-person,
body.u-surface-off .u-package,
body.u-surface-off .u-quote,
body.u-surface-off .u-stack-card,
body.u-surface-off .u-story-panel,
body.u-surface-off .u-hero-panel,
body.u-surface-off .u-side-card,
body.u-surface-off .u-mail-card,
body.u-surface-off .u-stats-shell,
body.u-surface-off .u-closing-panel,
body.u-surface-off .u-cta-panel,
body.u-surface-off .u-hiring-panel,
body.u-surface-off .u-quote-card,
body.u-surface-off .u-acc-item,
body.u-surface-off .u-hero-chip,
body.u-surface-off .u-header-bar,
body.u-surface-off .u-drawer-panel,
body.u-surface-off .u-search-panel,
body.u-surface-off .u-coming-panel {
	background: var(--u-surface);
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border: 1px solid var(--u-border);
	box-shadow: var(--u-shadow-sm);
}
body.u-surface-off .u-conic::before { display: none; }

/* Every mode transitions rather than snapping, so flipping the control in
   the Customizer reads as the material changing, not the page reloading. */
.u-glass, .u-card, .u-tile, .u-person, .u-package, .u-header-bar {
	transition:
		background-color 300ms var(--u-ease-out),
		border-color 300ms var(--u-ease-out),
		box-shadow 320ms var(--u-ease-out),
		transform 300ms var(--u-ease-out);
}


/* 17c. Mobile bottom navigation
   --------------------------------------------------------------------------
   Phones only. The bottom of a phone screen is where the thumb already is,
   so the primary destinations live there rather than behind a burger at the
   top edge.

   Sizing notes: tabs are 56px tall (comfortably above the 44px minimum for
   a touch target) and the bar respects safe-area-inset-bottom so it clears
   the home indicator on notched phones instead of sitting under it.
   ========================================================================== */

.u-bottomnav {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 240;
	display: none;
	padding: 0 12px calc(10px + env(safe-area-inset-bottom, 0px));
	pointer-events: none;
	/* Slides out of the way on scroll-down, back on scroll-up. */
	transform: translateY(0);
	transition: transform 320ms var(--u-ease-out);
	will-change: transform;
}
.u-bottomnav.is-hidden { transform: translateY(calc(100% + 12px)); }

.u-bottomnav-inner {
	position: relative;
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	align-items: stretch;
	pointer-events: auto;
	border-radius: var(--u-radius-pill);
	box-shadow: var(--u-shadow-lg);
	overflow: hidden;
}

.u-bottomnav-edge { padding: 0; }
.u-bottomnav-edge .u-bottomnav-inner {
	border-radius: 0;
	border-left: 0;
	border-right: 0;
	border-bottom: 0;
	padding-bottom: env(safe-area-inset-bottom, 0px);
}

.u-bnav-tab {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 4px;
	min-height: 56px;
	padding: 8px 2px;
	border: 0;
	background: transparent;
	color: var(--u-muted);
	font-size: .68rem;
	font-weight: 540;
	letter-spacing: .01em;
	text-align: center;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: color 200ms var(--u-ease-out), transform 160ms var(--u-ease-out);
}
/* Feedback lands on press, not on release. */
.u-bnav-tab:active { transform: scale(.93); }
.u-bnav-tab.is-current { color: var(--u-primary); font-weight: 620; }

/* Hover and focus were missing entirely, so a tab gave no feedback until it
   was already the current one. */
@media (hover: hover) and (pointer: fine) {
	.u-bnav-tab:hover { color: var(--u-text); }
	.u-bnav-tab.is-current:hover { color: var(--u-primary); }
}
.u-bnav-tab:focus-visible {
	outline: 2px solid var(--u-primary);
	outline-offset: -4px;
	border-radius: var(--u-radius-pill);
}

.u-bnav-icon { display: block; }
.u-bnav-icon svg {
	width: 22px;
	height: 22px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.7;
	stroke-linecap: round;
	stroke-linejoin: round;
	transition: transform 260ms var(--u-ease-out);
}
.u-bnav-tab.is-current .u-bnav-icon svg { transform: translateY(-1px) scale(1.08); }

.u-bnav-label {
	display: block;
	line-height: 1;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* The active pill is a single element that slides between tabs, rather than
   a background on each tab fading in and out. One moving object reads as
   one continuous thing; five cross-fading ones read as a flicker.

   It is its own piece of glass sitting on the glass bar — the iOS approach.
   A second blur layer over the first is what gives the pill an edge you can
   actually see, instead of a flat tint that disappears over busy content. */
.u-bnav-pill {
	position: absolute;
	top: 6px;
	bottom: 6px;
	left: 0;
	width: 20%;
	z-index: 0;
	border-radius: var(--u-radius-pill);

	background:
		linear-gradient(160deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, .06)),
		linear-gradient(135deg, rgba(var(--u-primary-rgb), .22), rgba(var(--u-accent-rgb), .18));
	backdrop-filter: blur(14px) saturate(200%);
	-webkit-backdrop-filter: blur(14px) saturate(200%);

	/* Rim light on top, contact shadow underneath: the two together are
	   what make it read as a raised lozenge rather than a coloured patch. */
	border: 1px solid rgba(255, 255, 255, .3);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, .45),
		inset 0 -1px 0 rgba(255, 255, 255, .1),
		0 4px 14px rgba(var(--u-shadow-rgb), .22);

	/*
	 * Liquid travel.
	 *
	 * Position and shape are separate: --x moves it, --sx and --sy squash
	 * it. While the pill is in transit the script stretches it along the
	 * direction of travel and thins it against that axis, then releases both
	 * back to 1. That volume-preserving squash is what makes a moving object
	 * read as liquid rather than as a rigid tile sliding — the shape reacts
	 * to its own speed.
	 *
	 * Scale is applied after the translate so the stretch happens about the
	 * pill's own centre, not the bar's origin.
	 */
	--x: 0px;
	--sx: 1;
	--sy: 1;
	transform: translateX(var(--x)) scale(var(--sx), var(--sy));
	transform-origin: center;
	opacity: 0;
	/* Under-damped, so it settles with a hint of overshoot the way a
	   physical control does when you throw it. */
	transition:
		transform 560ms cubic-bezier(0.32, 1.28, 0.42, 1),
		width 560ms cubic-bezier(0.32, 1.28, 0.42, 1),
		opacity 220ms var(--u-ease-out);
	pointer-events: none;
	will-change: transform;
}

/* The stretch itself relaxes faster than the travel, so the pill is back to
   its proper shape a moment before it stops — it arrives settled rather
   than still wobbling. */
.u-bnav-pill.is-travelling {
	transition:
		transform 560ms cubic-bezier(0.32, 1.28, 0.42, 1),
		width 560ms cubic-bezier(0.32, 1.28, 0.42, 1),
		opacity 220ms var(--u-ease-out);
}

/* A specular streak that only shows while moving — the highlight sliding
   across the surface is the other half of the liquid read. */
.u-bnav-pill::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .5) 50%, transparent 70%);
	opacity: 0;
	transition: opacity 260ms var(--u-ease-out);
	pointer-events: none;
}
.u-bnav-pill.is-travelling::after { opacity: .55; }
.u-bottomnav.has-active .u-bnav-pill { opacity: 1; }

/* Menu tab: two lines that cross into an X while the drawer is open. */
.u-bnav-burger svg path {
	transform-origin: center;
	transition: transform 320ms var(--u-ease-out);
}
.u-bnav-menu[aria-expanded="true"] { color: var(--u-primary); }
.u-bnav-menu[aria-expanded="true"] .u-burger-top { transform: translateY(2.5px) rotate(45deg); }
.u-bnav-menu[aria-expanded="true"] .u-burger-bottom { transform: translateY(-2.5px) rotate(-45deg); }

@media (max-width: 900px) {
	.u-bottomnav { display: block; }

	/* One menu control, not two. The bottom bar already carries a Menu tab
	   that opens the same drawer, so the header burger is redundant — and
	   two controls for one drawer is worse than either alone.

	   The overlay header's toggle goes with it. Its full-screen panel is a
	   desktop idea; on a phone the bottom bar's Menu tab already opens the
	   drawer, which is the same links with a thumb-reachable trigger. */
	.u-bottomnav-on .u-burger,
	.u-bottomnav-on .u-overlay-toggle { display: none; }

	/* With both controls gone the header is just a wordmark, so it does not
	   need the height it reserves for them. */
	.u-bottomnav-on .u-header-overlay .u-header-row { min-height: 58px; }

	/* Give the page somewhere to end, so the bar never covers the last
	   line of the footer. */
	.u-page { padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }

	/* The floating back-to-top button would otherwise sit on top of it. */
	.u-to-top { bottom: calc(90px + env(safe-area-inset-bottom, 0px)); }
}

/* The drawer sits above the bar, and the bar hides while it is open so the
   two never fight for the same corner. */
.u-drawer.is-open ~ .u-bottomnav,
body.u-drawer-open .u-bottomnav { transform: translateY(calc(100% + 12px)); }

@media (prefers-reduced-transparency: reduce) {
	.u-bnav-pill {
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
		background: rgba(var(--u-primary-rgb), .16);
	}
}

@media (prefers-reduced-motion: reduce) {
	.u-bottomnav,
	.u-bnav-pill { transition: opacity 200ms ease; }
	/* No stretch, no specular sweep — the pill still moves, it just does
	   not deform on the way. */
	.u-bnav-pill { transform: translateX(var(--x)); }
	.u-bnav-pill::after { display: none; }
	.u-bottomnav.is-hidden { transform: none; }
	.u-bnav-tab:active { transform: none; }
	.u-bnav-tab.is-current .u-bnav-icon svg { transform: none; }
	.u-bnav-burger svg path { transition: none; }
}

@media print {
	.u-bottomnav { display: none !important; }
}


/* 17c-2. Pricing cards
   --------------------------------------------------------------------------
   The packages were inheriting the generic card padding, which is far too
   tight for a column carrying a name, a price, a summary and a tick list.
   A pricing card is read top to bottom in a single glance, so the vertical
   rhythm inside it has to be deliberate rather than default.
   ========================================================================== */

.u-packages .u-grid { gap: clamp(18px, 2.4vw, 30px); }

.u-package {
	display: flex;
	flex-direction: column;
	padding: clamp(30px, 3.4vw, 42px) clamp(26px, 3vw, 34px);
	border-radius: var(--u-radius-lg);
}

/* The featured card sits slightly proud of its neighbours instead of only
   being outlined — height difference reads faster than a border does. */
.u-package.is-featured {
	padding-block: clamp(38px, 4.2vw, 54px);
	box-shadow: var(--u-shadow-lg);
}

/*
 * The badge sits in normal flow, not absolutely positioned.
 *
 * It used to be position: absolute in the top-right corner, which put it in
 * the same place as the package name — so on the featured card the pill and
 * the word "STUDIO" printed on top of each other. Taking it out of absolute
 * positioning means the two can never collide, whatever length either one
 * grows to, instead of the overlap being one long label away from returning.
 */
.u-package .u-badge {
	position: static;
	align-self: flex-start;
	margin: 0 0 18px;
	/* Shrink-wrap, so a longer label does not stretch to the card width. */
	width: max-content;
	max-width: 100%;
}

.u-package-name {
	font-size: 1.05rem;
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
	color: var(--u-muted);
	margin: 0 0 14px;
}

/* Cards without a badge keep the same top edge as the one that has it, so
   the row of prices still lines up across the grid. */
.u-package:not(.is-featured) .u-package-name { margin-top: 0; }

.u-package-price {
	font-family: var(--u-font-heading);
	font-size: clamp(1.9rem, 3.4vw, 2.5rem);
	line-height: 1;
	letter-spacing: -0.035em;
	margin: 0 0 16px;
}

.u-package-summary {
	color: var(--u-muted);
	font-size: .94rem;
	line-height: 1.6;
	margin: 0 0 26px;
	padding-bottom: 26px;
	border-bottom: 1px solid var(--u-border);
}

/* Breathing room between features, and space before the button so the card
   does not end abruptly. */
.u-package .u-ticks {
	flex: 1;
	gap: 14px;
	margin: 0 0 30px;
}
.u-package .u-ticks li {
	padding-left: 30px;
	font-size: .93rem;
	line-height: 1.5;
	color: var(--u-text);
}
.u-package .u-ticks li::before { top: .42em; }

.u-package .u-btn { width: 100%; margin-top: auto; }

/* Kept for any other surface still using an overlaid badge. */
.u-badge { top: 22px; right: 22px; }

.u-fineprint {
	margin-top: clamp(26px, 3vw, 38px);
	padding-top: 22px;
	border-top: 1px solid var(--u-border);
	color: var(--u-muted);
	font-size: .86rem;
	max-width: 72ch;
}

@media (max-width: 900px) {
	/* Stacked, the raised featured card just creates an odd gap. */
	.u-package.is-featured { padding-block: clamp(30px, 3.4vw, 42px); }
}


/* 17d. Price calculator
   ========================================================================== */

.u-calc {
	display: grid;
	grid-template-columns: minmax(0, 1.5fr) minmax(0, .85fr);
	gap: clamp(20px, 3vw, 36px);
	align-items: start;
}

.u-calc-form { display: grid; gap: 16px; }

.u-calc-group {
	border: 1px solid var(--u-glass-edge);
	border-radius: var(--u-radius-lg);
	padding: clamp(20px, 2.6vw, 28px);
	margin: 0;
}
.u-calc-group legend {
	padding: 0 0 14px;
	font-family: var(--u-font-heading);
	font-size: 1.05rem;
	font-weight: 620;
	letter-spacing: -0.02em;
}

.u-calc-options { display: grid; gap: 9px; }
.u-calc-options-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.u-calc-option {
	position: relative;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 14px 16px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius);
	cursor: pointer;
	transition:
		border-color 200ms var(--u-ease-out),
		background-color 200ms var(--u-ease-out),
		transform 180ms var(--u-ease-out);
}
.u-calc-option:active { transform: scale(.985); }
.u-calc-option input { position: absolute; opacity: 0; width: 0; height: 0; }

.u-calc-option-body { flex: 1; display: grid; gap: 3px; }
.u-calc-option-body strong { font-size: .95rem; font-weight: 560; }
.u-calc-option-body em { font-style: normal; font-size: .82rem; color: var(--u-muted); }

.u-calc-tick {
	position: relative;
	width: 22px;
	height: 22px;
	flex: none;
	border: 1.5px solid var(--u-border);
	border-radius: 50%;
	transition: border-color 200ms ease, background-color 200ms ease;
}
.u-calc-tick::after {
	content: "";
	position: absolute;
	left: 6px;
	top: 5px;
	width: 7px;
	height: 11px;
	border-right: 2px solid #fff;
	border-bottom: 2px solid #fff;
	transform: rotate(45deg) scale(.4);
	opacity: 0;
	transition: transform 240ms var(--u-ease-out), opacity 160ms ease;
}
.u-calc-option input:checked ~ .u-calc-tick {
	border-color: var(--u-primary);
	background: var(--u-primary);
}
.u-calc-option input:checked ~ .u-calc-tick::after { transform: rotate(45deg) scale(1); opacity: 1; }
.u-calc-option input:checked ~ .u-calc-option-body strong { color: var(--u-primary); }
.u-calc-option:has(input:checked) {
	border-color: rgba(var(--u-primary-rgb), .5);
	background: rgba(var(--u-primary-rgb), .06);
}
.u-calc-option input:focus-visible ~ .u-calc-tick { box-shadow: 0 0 0 3px rgba(var(--u-primary-rgb), .3); }

@media (hover: hover) and (pointer: fine) {
	.u-calc-option:hover { border-color: rgba(var(--u-text-rgb), .22); }
}

.u-calc-select { display: grid; gap: 7px; }
.u-calc-select span { font-size: .85rem; font-weight: 540; }
.u-calc-select select {
	width: 100%;
	padding: 12px 14px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius);
	background: var(--u-surface);
	color: var(--u-text);
	font: inherit;
	font-size: .95rem;
}
.u-calc-note { margin: 12px 0 0; font-size: .84rem; color: var(--u-muted); }

/* Summary rail */
.u-calc-summary { position: sticky; top: 96px; }
.u-calc-panel {
	padding: clamp(24px, 3vw, 32px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-lg);
}
.u-calc-label { margin: 0; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--u-muted); }
.u-calc-total {
	display: block;
	margin: 6px 0 14px;
	font-family: var(--u-font-heading);
	font-size: clamp(2.4rem, 5vw, 3.2rem);
	line-height: 1;
	letter-spacing: -0.04em;
	font-variant-numeric: tabular-nums;
	background: linear-gradient(135deg, var(--u-primary), var(--u-accent));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
.u-calc-range, .u-calc-time {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	margin: 0 0 8px;
	font-size: .88rem;
	color: var(--u-muted);
}
.u-calc-range span, .u-calc-time span { color: var(--u-text); font-variant-numeric: tabular-nums; }

.u-calc-list {
	list-style: none;
	margin: 18px 0;
	padding: 18px 0 0;
	border-top: 1px solid var(--u-border);
	display: grid;
	gap: 8px;
	font-size: .86rem;
}
.u-calc-list li { display: flex; justify-content: space-between; gap: 12px; }
.u-calc-list li span:first-child { color: var(--u-muted); }
.u-calc-list li span:last-child { font-variant-numeric: tabular-nums; }
.u-calc-list li.is-empty span { color: var(--u-muted); font-style: italic; }

.u-calc-panel .u-btn { width: 100%; }
.u-calc-fine { margin: 14px 0 0; font-size: .78rem; color: var(--u-muted); line-height: 1.55; }


/* 17e. Website audit
   ========================================================================== */

.u-audit { display: grid; gap: 18px; }

.u-audit-form { padding: clamp(20px, 2.6vw, 28px); border-radius: var(--u-radius-lg); }
.u-audit-field {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 6px 6px 6px 14px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius-pill);
	background: var(--u-surface);
	transition: border-color 180ms ease, box-shadow 200ms var(--u-ease-out);
}
.u-audit-field:focus-within {
	border-color: var(--u-primary);
	box-shadow: 0 0 0 3px rgba(var(--u-primary-rgb), .18);
}
.u-audit-icon { display: grid; place-items: center; color: var(--u-muted); flex: none; }
.u-audit-field input {
	flex: 1;
	min-width: 0;
	padding: 10px 0;
	border: 0;
	background: none;
	color: var(--u-text);
	font: inherit;
	font-size: 1rem;
}
.u-audit-field input:focus { outline: none; }
.u-audit-msg { margin: 10px 0 0; font-size: .86rem; min-height: 1.2em; }
.u-audit-msg.is-error { color: #d13438; }

.u-audit-results { display: grid; gap: 16px; }

.u-audit-score {
	display: flex;
	align-items: center;
	gap: clamp(18px, 3vw, 30px);
	flex-wrap: wrap;
	padding: clamp(22px, 3vw, 30px);
	border-radius: var(--u-radius-lg);
	background: var(--u-glass-bg);
	backdrop-filter: blur(var(--u-blur)) saturate(var(--u-saturate));
	-webkit-backdrop-filter: blur(var(--u-blur)) saturate(var(--u-saturate));
	border: 1px solid var(--u-glass-edge);
}
.u-audit-score p { margin: 0; flex: 1; min-width: 240px; color: var(--u-muted); font-size: .9rem; }
.u-audit-score code {
	background: rgba(var(--u-text-rgb), .08);
	padding: .1em .4em;
	border-radius: var(--u-radius-sm);
	font-size: .9em;
}

/* The ring is drawn with a conic gradient rather than SVG — one element,
   and the score drives it through a custom property. */
.u-audit-ring {
	display: grid;
	place-items: center;
	width: 112px;
	height: 112px;
	flex: none;
	border-radius: 50%;
	background:
		conic-gradient(var(--u-primary) calc(var(--score) * 1%), rgba(var(--u-text-rgb), .1) 0);
	position: relative;
	animation: u-ring-in 700ms var(--u-ease-out);
}
.u-audit-ring::before {
	content: "";
	position: absolute;
	inset: 9px;
	border-radius: 50%;
	background: var(--u-surface);
}
.u-audit-ring strong {
	position: relative;
	font-family: var(--u-font-heading);
	font-size: 1.9rem;
	line-height: 1;
	letter-spacing: -0.04em;
}
.u-audit-ring span {
	position: relative;
	font-size: .62rem;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--u-muted);
	margin-top: 3px;
}
@keyframes u-ring-in { from { transform: rotate(-90deg) scale(.9); opacity: 0; } }

.u-audit-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.u-audit-row {
	display: flex;
	align-items: flex-start;
	gap: 13px;
	padding: 15px 17px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius);
	background: var(--u-surface);
}
.u-audit-row div { display: grid; gap: 3px; }
.u-audit-row strong { font-size: .92rem; font-weight: 560; }
.u-audit-row span { font-size: .86rem; color: var(--u-muted); }
.u-audit-dot {
	width: 9px;
	height: 9px;
	margin-top: 6px;
	border-radius: 50%;
	flex: none;
}
.u-audit-row.is-pass .u-audit-dot { background: #22c55e; box-shadow: 0 0 0 3px rgba(34, 197, 94, .18); }
.u-audit-row.is-warn .u-audit-dot { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245, 158, 11, .18); }
.u-audit-row.is-fail .u-audit-dot { background: #ef4444; box-shadow: 0 0 0 3px rgba(239, 68, 68, .18); }
.u-audit-row.is-info .u-audit-dot { background: var(--u-muted); box-shadow: 0 0 0 3px rgba(var(--u-text-rgb), .1); }

.u-audit-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.u-audit-explainer { padding: clamp(22px, 3vw, 30px); border-radius: var(--u-radius-lg); }
.u-audit-explainer h2 { font-size: 1.15rem; }
.u-audit-explainer p { color: var(--u-muted); font-size: .92rem; }

@media (max-width: 900px) {
	.u-calc { grid-template-columns: minmax(0, 1fr); }
	.u-calc-summary { position: static; }
	.u-calc-options-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
	.u-audit-ring { animation: none; }
	.u-calc-option:active { transform: none; }
	.u-calc-tick::after { transition: opacity 150ms ease; }
}


/* 17f. Cookie banner
   ========================================================================== */

.u-cookies {
	position: fixed;
	z-index: 260;
	pointer-events: none;
	/* Enters from just below its resting place. Short travel — it is a
	   notice, not an arrival. */
	opacity: 0;
	transform: translateY(14px);
	transition:
		opacity 300ms var(--u-ease-out),
		transform 380ms var(--u-ease-out);
}
.u-cookies.is-in { opacity: 1; transform: none; }
/* Exit is faster than entry: the choice is made, so leaving is the only
   remaining job. */
.u-cookies.is-leaving {
	opacity: 0;
	transform: translateY(10px);
	transition: opacity 200ms var(--u-ease-out), transform 220ms var(--u-ease-out);
}

.u-cookies-bottom {
	left: 0;
	right: 0;
	bottom: 0;
	padding: 0 clamp(12px, 3vw, 26px) clamp(12px, 2vw, 22px);
}
.u-cookies-left,
.u-cookies-right {
	bottom: 0;
	max-width: 440px;
	padding: 0 clamp(12px, 3vw, 24px) clamp(12px, 2vw, 24px);
}
.u-cookies-left { left: 0; }
.u-cookies-right { right: 0; }

.u-cookies-panel {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: clamp(16px, 3vw, 32px);
	flex-wrap: wrap;
	pointer-events: auto;
	padding: clamp(18px, 2.2vw, 24px) clamp(20px, 2.6vw, 28px);
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-lg);
	max-width: var(--u-container);
	margin-inline: auto;
}
.u-cookies-left .u-cookies-panel,
.u-cookies-right .u-cookies-panel { flex-direction: column; align-items: flex-start; }

.u-cookies-copy { flex: 1; min-width: 240px; }
.u-cookies-copy strong { display: block; font-size: .98rem; margin-bottom: 5px; }
.u-cookies-copy p { margin: 0; font-size: .88rem; line-height: 1.6; color: var(--u-muted); }
.u-cookies-copy a { color: var(--u-primary); text-decoration: underline; text-underline-offset: 3px; }

.u-cookies-actions { display: flex; gap: 10px; flex-wrap: wrap; flex: none; }
/* Decline is the same size and weight as Accept. A banner where refusing is
   harder than agreeing is not consent. */
.u-cookies-actions .u-btn { min-width: 116px; justify-content: center; }

@media (max-width: 620px) {
	.u-cookies-left,
	.u-cookies-right { left: 0; right: 0; max-width: none; }
	.u-cookies-panel { flex-direction: column; align-items: stretch; }
	.u-cookies-actions .u-btn { flex: 1; }
}

/* Clear the mobile bottom bar rather than sitting on top of it. */
@media (max-width: 900px) {
	.u-bottomnav-on .u-cookies-bottom,
	.u-bottomnav-on .u-cookies-left,
	.u-bottomnav-on .u-cookies-right { bottom: calc(74px + env(safe-area-inset-bottom, 0px)); }
}

@media (prefers-reduced-motion: reduce) {
	.u-cookies { transform: none; transition: opacity 200ms ease; }
	.u-cookies.is-leaving { transform: none; }
}


/* 17g. Lite mode
   --------------------------------------------------------------------------
   Applied by the capability probe in inc/performance.php when the device
   cannot hold a steady frame rate, reports little memory or few cores, has
   Data Saver on, or has no backdrop-filter to begin with.

   The rule for what goes here: remove anything whose cost is continuous —
   compositing a blur, animating a large layer — and keep anything whose
   cost is paid once. Colour, layout, borders and shadows all stay, so the
   site still looks like itself; it simply stops paying rent every frame.
   ========================================================================== */

.u-lite .u-glass,
.u-lite .u-acc-item,
.u-lite .u-menu .sub-menu,
.u-lite .u-bnav-pill {
	/* The single most expensive thing in the theme. */
	backdrop-filter: none !important;
	-webkit-backdrop-filter: none !important;
	background: var(--u-surface);
}

.u-lite .u-bnav-pill { background: rgba(var(--u-primary-rgb), .16); }

/* Three large blurred layers animating forever. */
.u-lite .u-aurora,
.u-lite .u-grain,
.u-lite .u-ribbon { display: none; }

/* Conic borders repaint a gradient every frame; the spotlight repaints a
   radial one on every pointer move. */
.u-lite .u-conic::before,
.u-lite .u-spotlight::after { display: none; }

/* Scroll-linked work: pinning, stacking and parallax all run a handler on
   every scroll event. */
.u-lite .u-story { height: auto; }
.u-lite .u-story-pin { position: static; height: auto; padding-block: clamp(48px, 8vw, 96px); }
.u-lite .u-story-stage { position: static; min-height: 0; display: grid; gap: 14px; }
.u-lite .u-story-panel { position: static; opacity: 1; transform: none; filter: none; pointer-events: auto; }
.u-lite .u-stack-item { position: static; }
.u-lite .u-stack-card { transform: none !important; opacity: 1 !important; }

/* Entrance animations still run — they are one-shot and cheap — but the
   blur that accompanies them is not. */
.u-lite [data-u-lines] .u-line-in { filter: none; }
.u-lite .u-search-panel { filter: none; }

/* Floating decoration. */
.u-lite .u-float-a,
.u-lite .u-float-b,
.u-lite .u-orbit-ring,
.u-lite .u-scroll-bead,
.u-lite .u-masthead::after { animation: none; }

.u-lite .u-hero-chip { display: none; }

/* Nothing here should look like a downgrade, so the surfaces that lost
   their blur get a real border instead of a faint glass edge. */
.u-lite .u-card,
.u-lite .u-tile,
.u-lite .u-person,
.u-lite .u-package { border-color: var(--u-border); }




/* 17h. Portfolio
   ========================================================================== */

.u-folio-filter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: clamp(22px, 3vw, 34px); }

.u-folio-chip {
	padding: 9px 18px;
	border: 1px solid var(--u-border);
	border-radius: var(--u-radius-pill);
	background: transparent;
	color: var(--u-muted);
	font-size: .88rem;
	font-weight: 520;
	cursor: pointer;
	transition:
		background-color 200ms var(--u-ease-out),
		border-color 200ms var(--u-ease-out),
		color 200ms var(--u-ease-out),
		transform 150ms var(--u-ease-out);
}
.u-folio-chip:active { transform: scale(.96); }
.u-folio-chip.is-on {
	background: var(--u-primary);
	border-color: var(--u-primary);
	color: #fff;
}
@media (hover: hover) and (pointer: fine) {
	.u-folio-chip:hover { color: var(--u-text); border-color: rgba(var(--u-text-rgb), .25); }
	.u-folio-chip.is-on:hover { color: #fff; }
}

.u-folio-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(16px, 2.4vw, 26px);
}

.u-folio-item {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border-radius: var(--u-radius-lg);
	box-shadow: var(--u-shadow-sm);
	transition: transform 300ms var(--u-ease-out), box-shadow 320ms var(--u-ease-out);
}
.u-folio-item[hidden] { display: none; }

.u-folio-media { overflow: hidden; background: rgba(var(--u-text-rgb), .05); }
.u-folio-media img {
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform 480ms var(--u-ease-out);
}

.u-folio-body { display: flex; flex-direction: column; gap: 8px; padding: clamp(20px, 2.4vw, 26px); flex: 1; }
.u-folio-meta { margin: 0; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--u-muted); }
.u-folio-title { margin: 0; font-size: 1.15rem; letter-spacing: -0.022em; }
.u-folio-result { margin: 0; color: var(--u-muted); font-size: .93rem; }

@media (hover: hover) and (pointer: fine) {
	.u-folio-item:hover { transform: translateY(-4px); box-shadow: var(--u-shadow); }
	.u-folio-item:hover .u-folio-media img { transform: scale(1.05); }
}

@media (max-width: 1080px) { .u-folio-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .u-folio-grid { grid-template-columns: minmax(0, 1fr); } }


/* 17i. Language switcher
   ========================================================================== */

.u-langs { position: relative; }

.u-lang-toggle {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	height: 38px;
	padding: 0 12px;
	border: 0;
	border-radius: var(--u-radius-pill);
	background: transparent;
	color: inherit;
	font-size: .82rem;
	font-weight: 560;
	letter-spacing: .04em;
	cursor: pointer;
	transition: background-color 160ms ease, transform 140ms var(--u-ease-out);
}
.u-lang-toggle:active { transform: scale(.94); }
.u-lang-toggle .u-icon { width: 17px; height: 17px; }
@media (hover: hover) and (pointer: fine) {
	.u-lang-toggle:hover { background: rgba(var(--u-text-rgb), .07); }
}

.u-lang-menu {
	position: absolute;
	top: calc(100% + 8px);
	right: 0;
	z-index: 20;
	min-width: 160px;
	margin: 0;
	padding: 6px;
	list-style: none;
	border-radius: var(--u-radius);
	box-shadow: var(--u-shadow);
	/* Scales from the trigger, not from its own centre. */
	transform-origin: top right;
}
.u-lang-menu[hidden] { display: none; }
.u-lang-menu a {
	display: block;
	padding: 9px 13px;
	border-radius: var(--u-radius-sm);
	font-size: .9rem;
	color: var(--u-muted);
	transition: background-color 160ms ease, color 160ms ease;
}
.u-lang-menu a.is-current { color: var(--u-primary); font-weight: 560; }
@media (hover: hover) and (pointer: fine) {
	.u-lang-menu a:hover { background: rgba(var(--u-text-rgb), .06); color: var(--u-text); }
}




/* 17j. ImageLab
   --------------------------------------------------------------------------
   Scroll-scrubbed image scaling.

   The frame has a fixed aspect ratio and hides its overflow; only the <img>
   inside is scaled. Nothing reflows, so the whole effect stays on the
   compositor — which is the difference between this being free and this
   being the reason the page stutters.
   ========================================================================== */

.u-imagelab { padding-block: clamp(64px, 9vw, 128px); }

.u-lab-grid { display: grid; gap: clamp(28px, 5vw, 72px); }

.u-lab-item {
	display: block;
	color: inherit;
	text-decoration: none;
}

.u-lab-frame {
	position: relative;
	overflow: hidden;
	border-radius: var(--u-radius-lg);
	background: rgba(var(--u-text-rgb), .05);
	box-shadow: var(--u-shadow);
	/* The frame itself never moves — only the picture inside it. */
	transform: translateZ(0);
}

.u-lab-frame img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Scale is written by the scroll pass as a custom property, so the style
	   recalculation is one value rather than a whole transform string. */
	transform: scale(var(--s, 1));
	transform-origin: center;
	will-change: transform;
}

.u-lab-caption {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	flex-wrap: wrap;
	margin-top: 16px;
}
.u-lab-caption strong { font-size: 1rem; font-weight: 560; letter-spacing: -0.015em; }
.u-lab-caption span { font-size: .82rem; color: var(--u-muted); letter-spacing: .04em; }

a.u-lab-item .u-lab-frame { transition: box-shadow 300ms var(--u-ease-out); }
@media (hover: hover) and (pointer: fine) {
	a.u-lab-item:hover .u-lab-frame { box-shadow: var(--u-shadow-lg); }
	a.u-lab-item:hover .u-lab-caption strong { color: var(--u-primary); }
}

/* Showcase — full width, one per row. */
.u-imagelab-showcase .u-lab-frame { aspect-ratio: 16 / 9; }

/* Duo — two across, every second one pushed down so the pair never move in
   step. Two images scaling in unison reads as a glitch; offset reads as
   deliberate. */
.u-imagelab-duo .u-lab-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.u-imagelab-duo .u-lab-frame { aspect-ratio: 4 / 5; }
.u-imagelab-duo .u-lab-item:nth-child(even) { margin-top: clamp(32px, 7vw, 96px); }

/* Mosaic — uneven grid, smaller movement, for a wall of work. */
.u-imagelab-mosaic .u-lab-grid {
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: clamp(14px, 2vw, 24px);
}
.u-imagelab-mosaic .u-lab-item { grid-column: span 2; }
.u-imagelab-mosaic .u-lab-item:nth-child(3n+1) { grid-column: span 4; }
.u-imagelab-mosaic .u-lab-frame { aspect-ratio: 4 / 3; }
.u-imagelab-mosaic .u-lab-item:nth-child(3n+1) .u-lab-frame { aspect-ratio: 16 / 10; }

@media (max-width: 900px) {
	.u-imagelab-duo .u-lab-grid,
	.u-imagelab-mosaic .u-lab-grid { grid-template-columns: minmax(0, 1fr); }
	.u-imagelab-duo .u-lab-item:nth-child(even) { margin-top: 0; }
	.u-imagelab-mosaic .u-lab-item,
	.u-imagelab-mosaic .u-lab-item:nth-child(3n+1) { grid-column: auto; }
}

/* No scrubbing without motion: the image sits at its resting scale. */
@media (prefers-reduced-motion: reduce) {
	.u-lab-frame img { transform: none; will-change: auto; }
}

/* Lite mode drops the per-frame work entirely. */
.u-lite .u-lab-frame img { transform: none; will-change: auto; }


/* 18. Cursor blend
   --------------------------------------------------------------------------
   Difference blending means the cursor stays visible over any background
   without needing a second colour scheme for it.
   ========================================================================== */



/* 19. Responsive
   ========================================================================== */

@media (max-width: 1080px) {
	.u-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.u-tile-lg { grid-row: span 1; }
	.u-tile-wide { grid-column: span 2; }
	.u-team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.u-story-inner { grid-template-columns: minmax(0, 1fr); gap: 30px; }
	.u-story { height: 300vh; }
}

@media (max-width: 900px) {
	.u-hero-chip, .u-hero-chip-b { display: none; }
	.u-index-row { grid-template-columns: 48px minmax(0, 1fr); }
	.u-index-row p { grid-column: 2; }
}

@media (max-width: 620px) {
	.u-bento { grid-template-columns: minmax(0, 1fr); }
	.u-tile-wide { grid-column: span 1; flex-direction: column; align-items: flex-start; }
	.u-team-grid { grid-template-columns: minmax(0, 1fr); }
	.u-hero-panel-body { flex-direction: column; align-items: flex-start; gap: 22px; }
	.u-mail-card { grid-template-areas: "label label" "address address" "go go"; }
	.u-mail-go { justify-self: start; }
	.u-stack-item { top: 84px; }
}


/* 20. Reduced motion / transparency / contrast
   --------------------------------------------------------------------------
   Reduced motion here means: no drift, no pin, no parallax, no kinetic
   type, no float. Opacity and colour transitions stay, because they carry
   meaning rather than movement.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	.u-aurora-blob,
	.u-float-a,
	.u-float-b,
	.u-orbit-ring,
	.u-scroll-bead,
	.u-dot-live,
	.u-conic::before { animation: none; }

	.u-ribbon-track { animation: none; transform: none; }
	.u-ribbon-row { mask-image: none; -webkit-mask-image: none; }
	.u-ribbon { display: none; }

	[data-u-lines] .u-line-in { transform: none; filter: none; opacity: 1; transition: opacity 200ms ease; }
	[data-u-lines] .u-line { overflow: visible; }

	.u-story { height: auto; }
	.u-story-pin { position: static; height: auto; padding-block: clamp(48px, 8vw, 96px); }
	.u-story-stage { position: static; min-height: 0; display: grid; gap: 14px; }
	.u-story-panel { position: static; opacity: 1; transform: none; filter: none; pointer-events: auto; }

	.u-stack-item { position: static; }
	.u-stack-card { transform: none !important; }

	.u-hero-bars span { transform: none; transition: none; }
	.u-meter-bar i { transform: none; transition: none; }
	.u-index-rule { transform: none; transition: none; }
	.u-shine::before { display: none; }
	.u-spotlight::after { display: none; }
	.u-grain { opacity: calc(var(--u-grain-opacity, .04) * .5); }
}

@media (prefers-reduced-transparency: reduce) {
	.u-aurora { opacity: calc(var(--u-aurora-opacity, .7) * .3); }
	.u-acc-item { background: var(--u-surface); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

@media (prefers-contrast: more) {
	.u-aurora, .u-grain { display: none; }
	.u-conic::before { opacity: 1; }
	.u-ribbon-word { background: none; color: var(--u-text); }
	.u-ribbon-word.is-outline { -webkit-text-stroke-color: var(--u-text); }
	.u-tile p, .u-person-bio, .u-story-panel p { color: var(--u-text); }
}

@media print {
	.u-aurora, .u-grain, .u-ribbon, .u-scroll-hint { display: none !important; }
	.u-story { height: auto; }
	.u-story-pin { position: static; height: auto; }
	.u-story-panel { position: static; opacity: 1; transform: none; filter: none; }
	.u-stack-item { position: static; }
}
