/*
 * JobShaped — scroll motion primitives (site-wide).
 *
 * Companion to assets/js/scroll-fx.js. Four independent pieces:
 *
 *   .cvgen-progress   read-position hairline, printed at body level
 *   .cvgen-nav        condensed state once the page has scrolled
 *   [data-reveal]     enter-the-viewport rise
 *   .cvgen-tilt       scroll-driven 3D card (the framer-motion container-scroll
 *                     effect, expressed as calc() over one custom property)
 *
 * EVERY hidden or transformed state below is scoped to html.cvgen-fx, which the
 * inline snippet in wp_head adds only when IntersectionObserver is available and
 * the visitor has not asked for reduced motion. That single gate is what keeps a
 * no-JS or reduced-motion visitor from being served content stuck at opacity 0 —
 * do not lift a rule out of it.
 *
 * Builds on the tokens in app.css (loaded first).
 */

/* ============================================================ */
/* Read-position hairline                                        */
/* ============================================================ */

/* Lives at <body> level, outside #page. It has to: #page and .site-main are both
   stacking contexts at z-index 1, so a bar rendered inside <main> sits under the
   sticky header no matter what z-index it carries. */
.cvgen-progress {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	z-index: var( --z-progress );
	pointer-events: none;
}

.cvgen-progress[hidden] { display: none; }

.cvgen-progress::after {
	content: '';
	display: block;
	height: 100%;
	transform: scaleX( var(--scroll-p, 0) );
	transform-origin: 0 50%;
	background: linear-gradient( 90deg, var(--accent) 0%, var(--accent) 45%, var(--mint) 100% );
	box-shadow: 0 0 12px -2px var(--accent-ring);
}

/* ============================================================ */
/* Sticky header, condensed                                      */
/* ============================================================ */

.cvgen-fx .cvgen-nav {
	transition:
		background 0.3s var(--ease),
		box-shadow 0.3s var(--ease),
		border-color 0.3s var(--ease);
}

.cvgen-fx .cvgen-nav-inner { transition: padding 0.3s var(--ease); }

/* Off the top of the page the header earns its own shadow and drops the hairline,
   so it reads as floating over the content rather than as part of it. */
.cvgen-fx .cvgen-nav.is-scrolled {
	background: color-mix( in srgb, var(--canvas) 93%, transparent );
	border-bottom-color: transparent;
	box-shadow: 0 10px 30px -18px rgba( 20, 22, 28, 0.32 );
}

.cvgen-fx .cvgen-nav.is-scrolled .cvgen-nav-inner {
	padding-top: 0.62rem;
	padding-bottom: 0.62rem;
}

/* ============================================================ */
/* Reveals                                                       */
/* ============================================================ */

.cvgen-fx [data-reveal] {
	opacity: 0;
	transform: translateY( 24px );
}

.cvgen-fx [data-reveal='zoom'] {
	transform: translateY( 24px ) scale( 0.965 );
}

.cvgen-fx [data-reveal].is-inview {
	opacity: 1;
	transform: none;
	transition:
		opacity 0.7s var(--ease),
		transform 0.75s var(--ease);
	/* Siblings cascade rather than landing together; the index comes from JS. */
	transition-delay: calc( var(--reveal-i, 0) * 90ms );
}

/* ============================================================ */
/* Scroll tilt                                                   */
/* ============================================================ */

/*
 * The port of framer-motion's ContainerScroll. JS writes one number, --tilt-p,
 * onto .cvgen-tilt as it scrolls (0 = card still low on screen, 1 = flat), and
 * the three transforms below are derived from it:
 *
 *   rotateX   20deg -> 0      the card rakes back then straightens
 *   scale     1.05  -> 1      desktop; 0.9 -> 1 on narrow screens
 *   lift      0     -> -100px the heading rises as the card claims the frame
 *
 * The upstream component recomputes all of this in React on every scroll event
 * and swaps the scale range from a resize listener. Doing the interpolation in
 * calc() means the only per-frame JS is a single setProperty, and the narrow
 * screen range is just a media query.
 */

.cvgen-tilt {
	perspective: 1000px;
}

.cvgen-tilt-lift {
	position: relative;
	z-index: 1;
}

.cvgen-tilt-frame {
	position: relative;
	border-radius: 30px;
	padding: clamp( 0.5rem, 1.4vw, 1.4rem );
	border: 3px solid rgba( 255, 255, 255, 0.10 );
	background: linear-gradient( 165deg, #241d45 0%, #171232 60%, #100d21 100% );
	transform-style: preserve-3d;
	/* The stack from the original component, restated in the theme's cool
	   near-black: a tight contact shadow through to a very wide, very faint
	   one, which is what sells the card as hovering. */
	box-shadow:
		0 9px 20px rgba( 20, 22, 28, 0.29 ),
		0 37px 37px rgba( 20, 22, 28, 0.26 ),
		0 84px 50px rgba( 20, 22, 28, 0.15 ),
		0 149px 60px rgba( 20, 22, 28, 0.04 ),
		0 233px 65px rgba( 20, 22, 28, 0.01 );
}

.cvgen-tilt-screen {
	position: relative;
	height: 100%;
	overflow: hidden;
	border-radius: 20px;
	background: var(--canvas);
}

.cvgen-fx .cvgen-tilt-frame {
	will-change: transform;
	transform:
		rotateX( calc( ( 1 - var(--tilt-p, 0) ) * 20deg ) )
		scale( calc( 1.05 - var(--tilt-p, 0) * 0.05 ) );
}

.cvgen-fx .cvgen-tilt-lift {
	will-change: transform;
	transform: translateY( calc( var(--tilt-p, 0) * -100px ) );
}

/* Narrow screens: the card starts a little small and grows into place instead of
   starting oversized. The upstream 0.7 -> 0.9 range is not usable here because
   the screen holds readable product UI rather than a decorative screenshot. */
@media ( max-width: 768px ) {
	.cvgen-fx .cvgen-tilt-frame {
		transform:
			rotateX( calc( ( 1 - var(--tilt-p, 0) ) * 16deg ) )
			scale( calc( 0.9 + var(--tilt-p, 0) * 0.1 ) );
	}

	.cvgen-fx .cvgen-tilt-lift {
		transform: translateY( calc( var(--tilt-p, 0) * -40px ) );
	}

	.cvgen-tilt-frame { border-radius: 22px; }
	.cvgen-tilt-screen { border-radius: 14px; }
}
