:root {
	--hvr-trns: transform var(--g-trn-sp) var(--g-trn-tf) 0s, opacity var(--g-trn-sp) var(--g-trn-tf) 0s, filter var(--g-trn-sp) var(--g-trn-tf) 0s;
	--hvr-y-amt: 2rem;
}

/* Opacity Out */
.hvr_op-out {
	opacity: 1;
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	a:is(:hover, :focus-visible) .hvr_op-out, 
	.hvr_op-out:is(:hover, :focus-visible) {
		opacity: .55;
	}
}

/* Opacity In */
.hvr_op-in {
	opacity: 0;
	transition: var(--hvr-trns);
}

.hvr_op-in.abs {
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
}

@media (hover: hover) and (pointer: fine) {
	a:is(:hover, :focus-visible) .hvr_op-in, 
	.hvr_op-in:is(:hover, :focus-visible) {
		opacity: 1;
	}
}

/* Opacity List */
.hvr_op-lst {
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	ul:has(.hvr_op-lst:is(:hover,:focus-visible)) .hvr_op-lst:not(:is(:hover,:focus-visible)) {
		opacity: 0.5;
	}
}

/* Scale Down List */
/* Siblings recede; the hovered card must NOT grow. Every list this class is
   used on is a [data-role="scroller"], whose [data-role="list"] carries
   overflow-x: auto — and a non-visible overflow on one axis forces the other
   to clip too, so anything scaled above 1 gets cut off at the list edge.
   Shrinking is safe; growing is not. */
.hvr_scl-lst {
	--hvr-scl-lst-off: 0.98;
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	ul:has(.hvr_scl-lst:is(:hover,:focus-visible)) .hvr_scl-lst:not(:is(:hover,:focus-visible)) {
		transform: scale(var(--hvr-scl-lst-off));
	}
}

/* Zoom Image */
/* The hovered item answers by scaling its own photo INSIDE its frame, so
   nothing grows outside the card. That is the whole point: every list this
   lands in is a [data-role="scroller"], whose list carries overflow-x: auto
   and therefore clips on both axes — an item that scales itself gets cut off
   at the list edge, an item that scales its image does not.

   overflow lives on the <picture>, not just on .crd: the card clips at its
   own edge, but the image sits at the top of the card, so without a clip of
   its own a scaled photo would spill down over the title and copy.

   Composes with .hvr_op-lst — siblings recede, the hovered one comes to
   life. Kept to 1.05; this is a slow settle, not a lurch. */
.hvr_zm {
	--hvr-zm-amt: 1.05;

	picture {
		display: block;
		overflow: hidden;
	}

	img {
		transition: var(--hvr-trns);
	}

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

		&:is(:hover,:focus-visible) img {
			transform: scale(var(--hvr-zm-amt));
		}

	}
}

/* Blur List */
.hvr_blr-lst {
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	ul:has(.hvr_blr-lst:is(:hover,:focus-visible)) .hvr_blr-lst:not(:is(:hover,:focus-visible)) {
		filter: blur(3px);
	}
}

/* Grayscale List */
.hvr_gry-lst img {
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	ul:has(.hvr_gry-lst:is(:hover,:focus-visible)) .hvr_gry-lst:not(:is(:hover,:focus-visible)) img {
		filter: grayscale(1);
	}
}

/* Grayscale */
.hvr_gry {
	transition: var(--hvr-trns);
	
	@media (hover: hover) and (pointer: fine) {
		&:is(:hover,:focus-visible) {
			filter: grayscale(1);
		}
	}
}

/* Scale Up */
.hvr_scl-up {
	transition: var(--hvr-trns);
}

@media (hover: hover) and (pointer: fine) {
	a:is(:hover, :focus-visible) .hvr_scl-up, 
	.hvr_scl-up:is(:hover, :focus-visible) {
		transform: scale(1.05,1.05);
	}
}

/* Scale Down */
.hvr_scl-dwn {
	transition: var(--hvr-trns);
	
	@media (hover: hover) and (pointer: fine) {
		&:is(:hover,:focus-visible) {
			transform: scale(0.9);
		}
	}
}

/* translateY - Up */
.hvr_trn-up {
	--hvr-y-amt: 1rem;
	transition: var(--hvr-trns);
	
	@media (hover: hover) and (pointer: fine) {
		&:is(:hover,:focus-visible) {
			transform: translateY(calc(-1 * var(--hvr-y-amt)));
		}
	}
}

/* translateY - Down */
.hvr_trn-dwn {
	transition: var(--hvr-trns);
	
	@media (hover: hover) and (pointer: fine) {
		&:is(:hover,:focus-visible) {
			transform: translateY(var(--hvr-y-amt));
		}
	}
}

ul:has([class*="hvr_trn"]) {
	padding-block: var(--hvr-y-amt);
}

/* Shift Image */
.hvr_shf {
	overflow: hidden;
	
	img {
		width: calc(100% + var(--hvr-y-amt));
		max-width: none;
		transform: translateX(calc(-.5 * var(--hvr-y-amt)));
		transition: var(--hvr-trns);
	}
	
	@media (hover: hover) and (pointer: fine) {
		&:is(:hover,:focus-visible) img {
			transform: translateX(0);
		}
	}
}

/* Underline */
.hvr_und {
	position: relative;
	
	&::before {
		content: '';
		position: absolute;
		width: 100%;
		height: var(--bdr-w);
		bottom: 0;
		left: 0;
		background-color: var(--text-color);
		transform: scaleX(0.65);
		opacity: 0;
		transform-origin: 0 50%;
		transition: var(--hvr-trns);
	}
	
	&.clr-swp::before {
		background-color: var(--link);
	}
}

@media (hover: hover) and (pointer: fine) {
	a:is(:hover, :focus-visible, .active, .selected) .hvr_und:before, 
	.hvr_und:is(:hover, :focus-visible, .active, .selected):before {
		opacity: 1;
		transform: scaleX(1);
	}
}