/* ==========================================================================
   Divigi — services-list.css

   Every :hover rule below is paired with a .svc-on class. Phones never fire
   hover, so the whole effect was invisible there; the script adds .svc-on to
   whichever row is centred in the viewport as you scroll, which gives touch
   users the same reveal one row at a time.
   Plain-CSS translation of the interactive-hover-links component.

   Tailwind/shadcn classes mapped to this theme rather than installed:
     bg-background          -> transparent (the section already has a bg)
     border-b-2 border-muted-> 2px bottom rule, --svc-line
     text-muted-foreground  -> --svc-dim   (the resting colour)
     text-foreground        -> --svc-lit   (the hover colour)
     md:text-6xl / text-4xl -> clamp()
     md:py-8 / py-4         -> clamp()
     size-8 / md:size-12    -> arrow sizing

   The single most important part is that the heading sits DIM at rest and
   lights up on hover. That contrast is where the whole effect comes from; a
   full-contrast heading kills it no matter how good the motion is.

   Deliberately namespaced .svc-* so nothing here collides with Bootstrap, the
   theme's own .service-menu, or the CSS bundle.

   Rendered from template-parts/services-list.php by both the front page and
   the proposal page; divigi_uses_services_list() in functions.php decides where
   this file and service-hover.js load.
   ========================================================================== */

.svc-list {
	--svc-line: rgba(18, 18, 18, .14);
	/* Light theme reads black at rest, not dimmed. The reference's dim-to-bright
	   ramp only works on a dark ground; on white it just looked like unloaded
	   text. Dark mode keeps the ramp below. */
	--svc-dim:  #111013;
	--svc-lit:  #111013;
	--svc-ease: cubic-bezier(.22, 1, .36, 1);

	list-style: none;
	margin: 0;
	padding: 0;
	width: 100%;
}

.dark .svc-list {
	--svc-line: rgba(255, 255, 255, .16);
	--svc-dim:  rgba(255, 255, 255, .34);
	--svc-lit:  #ffffff;
}

.svc-item { list-style: none; }

.svc-link {
	position: relative;              /* the preview is positioned against this */
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	padding: clamp(18px, 2.6vw, 34px) 0;
	border-bottom: 2px solid var(--svc-line);
	text-decoration: none;
	transition: border-color .5s var(--svc-ease);
	/* No overflow:hidden here on purpose — the preview has to be able to leave
	   the row. Only the arrow is clipped, by its own wrapper below. */
}

/* Yellow rule that fills left to right on hover — same mechanic as the nav
   underline in main.css, so the two read as one language. The static border
   above stays as the resting rule; this is painted over it. */
.svc-link::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: -2px;                    /* sits exactly on the 2px border */
	height: 2px;
	width: 0;
	background-color: #ebf212;
	transition: width 1.4s ease-in-out;
	pointer-events: none;
	z-index: 11;
}

.svc-link:hover::after ,
.svc-link.svc-on::after { width: 100%; }

@media (prefers-reduced-motion: reduce) {
	.svc-link::after { transition: none; }
}

/* ---- copy ---------------------------------------------------------------- */
.svc-copy {
	position: relative;
	z-index: 10;                     /* stays above the preview image */
	display: block;
	min-width: 0;
}

.svc-heading {
	display: block;
	font-size: clamp(28px, 5vw, 60px);
	line-height: 1.02;
	font-weight: 700;
	color: var(--svc-dim);
	/* Transform is deliberately quicker than the letters' 250ms head start, so
	   the leftward shift has landed before they begin coming back. */
	transition: color .5s var(--svc-ease), transform .3s var(--svc-ease);
	white-space: nowrap;
}

.svc-link:hover .svc-heading ,
.svc-link.svc-on .svc-heading {
	color: var(--svc-lit);
	transform: translateX(-16px);    /* letters push the other way — see JS */
}

/* Word wrapper. .svc-l is inline-block, and every inline-block edge is a valid
   place to break a line — so a wrapping heading split mid-word. Grouping each
   word in a nowrap box moves the break opportunities back to the spaces. */
.svc-w { display: inline-block; white-space: nowrap; }

/* Two spans per letter — see the split in service-hover.js.

   OUTER (.svc-l) slides, using a TRANSITION. A transition always eases from
   whatever value the element currently holds, so leaving the row mid-ripple
   simply reverses from that point.

   INNER (.svc-lp) pops, using a KEYFRAME, because a transition cannot swell
   and return — it only interpolates A to B.

   They were on one element before, and that was the bug: an animation
   overrides a transition on the same property, so the slide inherited the
   keyframe's fixed start value and snapped to it on hover-out. */
.svc-heading .svc-l {
	display: inline-block;
	white-space: pre;                /* keeps spaces once wrapped in spans */
	transition: transform .42s cubic-bezier(.34, 1.56, .64, 1);
	transition-delay: 0s;            /* instant unwind on the way out */
	will-change: transform;
}

/* 48ms between letters rather than the reference's 75ms — the hits land quicker
   and the longest heading finishes in ~1.5s instead of 2.2s. The 250ms offset
   is the head start that lets the whole word shift left first. */
.svc-link:hover .svc-heading .svc-l ,
.svc-link.svc-on .svc-heading .svc-l {
	transform: translateX(16px);
	transition-delay: calc(250ms + var(--svc-i, 0) * 48ms);
}

/* The swell. Starts and ends at scale(1), so it is safe to interrupt at any
   point — there is no held end state to snap away from. */
.svc-lp {
	display: inline-block;
	white-space: pre;
}

/* Peak sits at exactly 50% and the curve is symmetric, so the letter swells and
   settles at the same rate. ease-out was making the grow snap and the return
   crawl, which read as uneven. */
@keyframes svc-pop {
	0%   { transform: scale(1); }
	50%  { transform: scale(1.30); }
	100% { transform: scale(1); }
}

.svc-heading.svc-in .svc-lp {
	animation: svc-pop .52s cubic-bezier(.45, 0, .55, 1);   /* symmetric in/out */
	animation-delay: calc(250ms + var(--svc-i, 0) * 48ms);
}

.svc-heading.svc-out .svc-lp {
	animation: svc-pop .44s cubic-bezier(.45, 0, .55, 1);
	animation-delay: calc(var(--svc-i, 0) * 26ms);
}

@media (prefers-reduced-motion: reduce) {
	.svc-heading.svc-in .svc-lp,
	.svc-heading.svc-out .svc-lp { animation: none; }
}

.svc-sub {
	display: block;                  /* full copy, no clamp */
	margin-top: 10px;
	max-width: 70ch;
	font-size: clamp(13px, 1.05vw, 16px);
	line-height: 1.55;
	color: var(--svc-dim);
	transition: color .5s var(--svc-ease);
}

.svc-link:hover .svc-sub ,
.svc-link.svc-on .svc-sub { color: var(--svc-lit); }

/* ---- cursor-following preview ---------------------------------------------
   The seven photos were normalised to a common luminance and desaturated when
   they were installed, so they already read as one family. The wrapper is here
   to clip the rounded corners and carry the brand tint; it is not doing any
   correcting.
   -------------------------------------------------------------------------- */
.svc-thumb {
	position: absolute;
	/* Above everything in the row: the copy (10) and the yellow rule (11).
	   One value fixes both asks — the image sits on top, and because the rule
	   is now beneath it the border no longer draws a line across the picture. */
	z-index: 20;
	top: 50%;
	left: 50%;
	width: clamp(150px, 19vw, 280px);
	height: clamp(112px, 14.5vw, 210px);
	border-radius: 12px;
	overflow: hidden;                /* clips the image and the wash */
	box-shadow: 0 28px 70px -20px rgba(0, 0, 0, .65),
	            0 0 0 1px rgba(235, 242, 18, .28);   /* thin brand edge */
	pointer-events: none;            /* must never steal the row's hover */
	opacity: 0;
	transform: translate(-10%, -50%) rotate(-12.5deg) scale(0);
	will-change: transform, opacity;
}

.svc-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	/* No filter. The files themselves are graded — every one normalised to the
	   same mean luminance (~80) and desaturated on the way in — so a CSS filter
	   here would grade them a second time and re-introduce the variance it is
	   meant to remove. */
}

/* Brand wash. `soft-light` tints without flattening the photo the way a plain
   translucent overlay would, and the gradient keeps the top brighter so the
   image still reads as a photo rather than a colour swatch. */
.svc-thumb::after {
	content: "";
	position: absolute;
	inset: 0;
	/* Lighter than before, since the photos no longer need rescuing — this is
	   now just a brand tint, not a correction. */
	background: linear-gradient(150deg,
	            rgba(235, 242, 18, .26) 0%,
	            rgba(235, 242, 18, .06) 45%,
	            rgba(0, 0, 0, .22) 100%);
	mix-blend-mode: soft-light;
	pointer-events: none;
}

.svc-link:hover .svc-thumb ,
.svc-link.svc-on .svc-thumb { opacity: 1; }

/* Photographs, so no invert — that rule existed for the old line-art icons and
   would turn a photo into a negative. */

/* ---- circular tag icon ----------------------------------------------------
   The theme's original .service-menu .icon, carried over unchanged in
   behaviour: a circle that grows from nothing on hover with the tag mark
   swinging in from the lower left. Only the ring colour differs — the old one
   sat on top of a yellow row sweep that no longer exists, so the ring itself
   carries the brand colour now.
   -------------------------------------------------------------------------- */
.svc-icon {
	position: absolute;
	right: 75px;
	top: 50%;
	z-index: 6;
	display: grid;
	place-items: center;
	width: 0;
	height: 0;
	border-radius: 100%;
	border: 4px solid rgba(235, 242, 18, 0);
	/* Transparent at rest, and clipped to the padding box. Without both, the
	   0x0 circle still painted an 8x8 yellow dot: background fills under a
	   transparent border by default, so the ring showed as a dot before hover. */
	background: transparent;
	background-clip: padding-box;
	overflow: hidden;
	transform: translateY(-50%);
	transition: all .68s ease-in-out;
	transition-delay: .1s;
	pointer-events: none;
}

.svc-link:hover .svc-icon ,
.svc-link.svc-on .svc-icon {
	width: 100px;
	height: 100px;
	right: 50px;
	border-color: #ebf212;
	background: #ebf212;
}

/* ---- resting icon ---------------------------------------------------------
   The service's own icon, shown when the row is idle and traded for the tag
   circle on hover. Same anchor point as .svc-icon so one swaps for the other
   in place rather than the eye tracking between two spots.
   -------------------------------------------------------------------------- */
.svc-rest {
	position: absolute;
	/* 140px to match the theme's original .service-menu li .thumb img, which was
	   max-height:140px. right:30px centres this on the same point the tag circle
	   opens around (its hover centre is 100px in), so one swaps for the other in
	   place. */
	right: 30px;
	top: 50%;
	z-index: 6;
	display: grid;
	place-items: center;
	width: 140px;
	height: 140px;
	transform: translateY(-50%) scale(1);
	opacity: 1;
	transition: opacity .3s ease-in-out, transform .35s var(--svc-ease);
	pointer-events: none;
}

.svc-rest img {
	display: block;
	width: auto;
	max-width: 100%;
	max-height: 140px;               /* same cap the original used */
	margin: 0;
}

/* The icons are dark line art, so they need inverting on a dark ground —
   the same treatment the old .thumbs img rule applied. */
.dark .svc-rest img { filter: invert(1); }

/* Out of the way before the circle finishes opening. */
.svc-link:hover .svc-rest ,
.svc-link.svc-on .svc-rest {
	opacity: 0;
	transform: translateY(-50%) scale(.6);
}

/* (The old rule hiding .svc-rest below 991px is gone — the touch layout below
   puts the service icon back, at a size that reads.) */

.svc-icon img {
	width: 85%;
	margin: 0;
	opacity: 0;
	transform: translateX(-100%) translateY(100%);
	transition: all .85s ease-in-out;
	transition-delay: .24s;          /* lands just after the ring has opened */
	filter: invert(1);               /* white-tag.svg is white artwork */
}

.svc-link:hover .svc-icon img ,
.svc-link.svc-on .svc-icon img {
	opacity: 1;
	/* Rests dead centre. The theme's original ended on translate(10%, 5%),
	   but that markup had no centring on the wrapper — the offset WAS its
	   centring. Here the wrapper is a centred grid, so the same offset just
	   pushed the mark off-centre. */
	transform: translate(0, 0);
}

/* ---- touch --------------------------------------------------------------
   Icon, copy, thumbnail as three flex children — the layout that read best on a
   phone. The desktop mechanic (preview flying out over the row, icon trading
   places with an opening circle) was tried here and put the image back on the
   text, so it stays desktop-only.

       [icon]  Heading                    [thumb]
               Sub text

   Everything still moves on scroll; it just moves in place. The row that is
   active gets: icon up and brighter, heading letters hitting one by one, copy
   lit, thumbnail swinging straight and coming up to full opacity, and the yellow
   rule filling left to right. All of it keyed off .svc-on, which the script puts
   on whichever row is nearest the middle of the screen.
   -------------------------------------------------------------------------- */
@media only screen and (max-width: 991px) {
	.svc-link {
		gap: 12px;
		align-items: center;
	}

	/* Service icon first. It is a <span>, so it needs an explicit display before
	   width and height mean anything. */
	.svc-rest {
		order: -1;
		display: block;
		position: static;
		flex: 0 0 auto;
		width: 34px;
		height: 34px;
		transform: none;
		opacity: .55;
		transition: opacity .4s ease,
		            transform .55s cubic-bezier(.34, 1.56, .64, 1);
	}

	.svc-rest img {
		width: 100%;
		height: 100%;
		max-height: none;
		object-fit: contain;
	}

	/* Fades out as the circle opens over it — the desktop trade, kept. The slot
	   is a flex item so it holds its width while the icon goes, which is what
	   stops the row shifting as you scroll past. */
	.svc-link.svc-on .svc-rest {
		opacity: 0;
		transform: scale(.6);
	}

	.svc-copy { flex: 1 1 auto; min-width: 0; }

	/* In flow, so it can never sit on the text. Dim and tilted at rest, straight
	   and full strength when the row is active. */
	.svc-thumb {
		position: static;
		flex: 0 0 auto;
		width: clamp(76px, 23vw, 108px);
		height: clamp(58px, 17vw, 82px);
		opacity: .3;
		transform: scale(.84) rotate(-7deg);
		box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .7),
		            0 0 0 1px rgba(235, 242, 18, .22);
		transition: opacity .4s ease,
		            transform .6s cubic-bezier(.34, 1.56, .64, 1);
	}

	.svc-link.svc-on .svc-thumb {
		opacity: 1;
		transform: scale(1) rotate(0deg);
	}

	/* The tag circle, moved to the LEFT so it opens over the service icon rather
	   than out at the right edge where the desktop row puts it. Absolute, so it
	   overlays the icon's flex slot instead of taking a slot of its own — that is
	   what makes it read as the icon turning into the arrow. */
	.svc-icon {
		display: grid;
		left: 0;
		right: auto;
		width: 0;
		height: 0;
		border-width: 3px;
	}

	.svc-link:hover .svc-icon,
	.svc-link.svc-on .svc-icon {
		/* -3px centres the 40px circle over the 34px icon slot. */
		left: -3px;
		right: auto;
		width: 40px;
		height: 40px;
	}

	.svc-link:hover .svc-icon img,
	.svc-link.svc-on .svc-icon img { width: 56%; }
}

@media only screen and (max-width: 767px) {
	.svc-heading { white-space: normal; }
}

@media (prefers-reduced-motion: reduce) {
	.svc-thumb { display: none; }
	.svc-heading,
	.svc-heading .svc-l,
	.svc-sub,
	.svc-arrow,
	.svc-link { transition: none; }
	.svc-link:hover .svc-heading { transform: none; }
	.svc-link:hover .svc-heading .svc-l { transform: none; }
	.svc-arrow { opacity: 1; transform: none; }
}
