/* ===================================================================
   Hover Emoji Effects (Customize → Hover Emoji Effects)
   Only enqueued when the feature is switched on — see
   gathercole_hover_emoji_enqueue() in inc/hover-emoji.php.

   Both pops are appended straight to <body> as position: fixed,
   anchored to the word's on-screen coordinates at the moment of hover
   (hover-emoji.js sets left/top inline, plus --bounce-fall for the
   bounce). Fixed-to-the-viewport rather than absolute-inside-the-word
   for two reasons: the bounce needs to travel all the way to the
   bottom of the *viewport* regardless of where the word sits on the
   page, and neither pop should risk being clipped by some ancestor's
   overflow while it travels a long distance.
   =================================================================== */

.hover-emoji-trigger {
	position: relative;
	cursor: default;
}

.hover-emoji-pop {
	position: fixed;
	pointer-events: none;
	z-index: 999;
	will-change: transform, opacity;
}

.hover-emoji-pop img {
	display: block;
	width: 100%;
	height: 100%;
	/* Uploaded images (Customize → Hover Emoji Effects) may not fill
	   their canvas edge to edge — contain keeps the whole image visible
	   and undistorted regardless of how much empty space the artwork
	   itself leaves around it. */
	object-fit: contain;
}

/* Football: falls from the word, bouncing off the About section's CTA
   buttons, then the Skills/Stack section right after it, then continues
   falling — each subsequent bounce covering a bigger drop than the
   last — until it exits past the bottom of the viewport. A single run,
   not a loop, since it's a one-way journey. hover-emoji.js computes
   --b1/--b2 (the CTA row's and Skills section's positions — the first
   two impacts), --r1/--r2/--b3/--r3 (the rebounds and the final impact
   after them) and --exit (past the bottom of the viewport) as absolute
   pixel offsets from the word, since where those elements actually sit
   varies by viewport/content.

   The horizontal offset at each keyframe only ever increases (never
   zigzags back toward center) so the whole fall reads as one continuous
   drift to the right rather than straight down — "bouncing off"
   different elements as it goes, rather than just dropping in a
   straight line.

   "Bouncy" rather than stiff comes from a consistent, smooth pair of
   curves used throughout — every fall uses the same gentle ease-in
   (accelerating downward, cubic-bezier(0.45,0,0.85,0.35)) and every
   rebound uses the same gentle ease-out (decelerating into the peak,
   cubic-bezier(0.15,0.7,0.3,1)) — plus continuous rotation and a
   *uniform* scale dip at each impact that also gets a touch smaller
   with every bounce (as if it's losing a little air/energy each time
   it hits something). Using the same two curves everywhere (rather
   than a different bespoke curve per segment) is what keeps the motion
   reading as smooth rather than mechanical. Scale is deliberately
   uniform (same X and Y) rather than the non-uniform squash-and-stretch
   a cartoon character would normally get — the uploaded football image
   is round, and stretching X/Y unevenly warped/distorted it into an
   ellipse rather than reading as "squashed", so this keeps it perfectly
   circular throughout and leans on scale + rotation + easing alone for
   the bounciness instead.

   Each rebound (--r1/--r2/--r3, set in hover-emoji.js) is a genuinely
   noticeable fraction of the drop that preceded it, not just a token
   wobble — that visible up-then-down motion at each impact is what
   actually reads as "bouncing off something" rather than just slowing
   down and speeding back up in place. */
.hover-emoji-pop.bounce {
	top: 0;
	left: 0;
	width: 64px;
	height: 64px;
	transform-origin: 50% 100%;
	transform: translate(-50%, 0) rotate(0deg) scale(1);
	animation: hover-emoji-bounce-fall 3s forwards;
}

@keyframes hover-emoji-bounce-fall {
	0%   { transform: translate(-50%, 0) rotate(0deg) scale(1);
	       animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.35); }
	/* First impact: hits the CTA buttons. Slowest, gentlest fall — the
	   "start slower" beat — given the most timeline for its (relatively
	   short) drop, then a clearly visible bounce back up off it. */
	14%  { transform: translate(calc(-50% + 22px), var(--b1)) rotate(160deg) scale(0.85);
	       animation-timing-function: cubic-bezier(0.15, 0.7, 0.3, 1); }
	26%  { transform: translate(calc(-50% + 38px), var(--r1)) rotate(230deg) scale(1);
	       animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.35); }
	/* Second impact: bounces off the Skills/Stack section, a bigger drop
	   than the first, covered in less relative time — the first step up
	   in speed — then its own clearly visible bounce back up, further
	   right again. */
	42%  { transform: translate(calc(-50% + 65px), var(--b2)) rotate(20deg) scale(0.8);
	       animation-timing-function: cubic-bezier(0.15, 0.7, 0.3, 1); }
	52%  { transform: translate(calc(-50% + 82px), var(--r2)) rotate(95deg) scale(0.95);
	       animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.35); }
	/* Third impact: bigger again, covered in even less relative time
	   than the second — accelerating further — with a smaller (but
	   still visible) bounce back up, continuing the same rightward
	   drift right to the end. */
	66%  { transform: translate(calc(-50% + 104px), var(--b3)) rotate(255deg) scale(0.75);
	       animation-timing-function: cubic-bezier(0.15, 0.7, 0.3, 1); }
	74%  { transform: translate(calc(-50% + 116px), var(--r3)) rotate(330deg) scale(0.9);
	       animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.3); }
	90%  { opacity: 1; }
	/* Final plunge off the bottom of the screen: the single biggest
	   drop of all — the payoff for "as it falls a greater distance,
	   speed up" — continuing the same rightward drift one last step. */
	100% { transform: translate(calc(-50% + 130px), var(--exit)) rotate(620deg) scale(0.85); opacity: 0; }
}

/* Car: two stretches — an entrance, then the zoom — each its own single
   continuous keyframe segment. First it glides smoothly onto the page
   from off-screen left, arriving and settling exactly level with the
   word ("inline with F1"), then a brief hold — no skew, one gentle
   ease-out for the whole approach. Once it leaves that hold, speed and
   skew increase together in one uninterrupted accelerating curve all
   the way to the exit. This used to be split into several shorter
   segments (to make skew visibly lag behind speed), but every keyframe
   boundary restarts its own easing curve from scratch — stacking
   several ease-in-flavoured segments back to back produced a visible
   stutter/stop partway through the zoom. One segment, one curve, is
   what actually reads as smooth, with the only deliberate pause being
   the hold above the word.

   The default car image (F1.svg) has been corrected to already face
   right, so no scaleX flip is needed — if a replacement image faces
   left instead, add scaleX(-1) back into every transform below.

   Anchored via translateY(-100%) from a `top` that hover-emoji.js sets
   just above the word's own line (rect.top, minus a gap) — rather than
   vertically centered on the word — so the whole car sits above the
   first line of text it's hovering over instead of covering it. */
.hover-emoji-pop.zoom {
	top: 0;
	left: 0;
	width: 75px;
	height: 75px;
	transform: translate(-50%, -100%) translateX(-55vw) skewX(0deg);
	animation: hover-emoji-zoom 2.6s forwards;
}

@keyframes hover-emoji-zoom {
	/* Phase 1 — smooth entrance: glides in from off-screen and settles
	   level with the word, then a brief hold. Moderate ease-out rather
	   than a very steep decelerating curve — too extreme a curve here
	   made the car all but stop dead for a stretch right as it arrived,
	   which read as the whole animation freezing rather than a smooth
	   arrival. */
	0%   { transform: translate(-50%, -100%) translateX(-55vw) skewX(0deg); opacity: 1;
	       animation-timing-function: ease-out; }
	35%  { transform: translate(-50%, -100%) translateX(0) skewX(0deg); opacity: 1;
	       animation-timing-function: linear; }
	45%  { transform: translate(-50%, -100%) translateX(0) skewX(0deg); opacity: 1;
	       animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.3); }
	/* Phase 2 — the zoom: one single continuous segment (45%→100%) for
	   speed, skew, and fade together, rather than several shorter
	   segments each with their own timing-function. Each keyframe
	   boundary restarts its easing curve from scratch, and a curve that
	   starts slow (anything ease-in-flavoured) does that at every
	   boundary it governs — stacking several of those in a row is what
	   was producing a visible stutter/stop partway through the zoom.
	   One segment, one curve, means only one acceleration profile for
	   the whole takeoff — no internal restarts, so no stop. Skew no
	   longer waits for speed to build up first as a result, but it
	   still increases together with the speed, which is what actually
	   reads as "going faster" — and it's the smoothness that matters
	   most here. */
	90%  { opacity: 1; }
	100% { transform: translate(-50%, -100%) translateX(130vw) skewX(-26deg); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.hover-emoji-pop.bounce,
	.hover-emoji-pop.zoom {
		animation: none;
		opacity: 0; /* removed by JS shortly after anyway; avoids a static pop */
	}
}
