/**
 * TechMart — motion.
 *
 * One place for every entrance animation on the site, so the whole thing moves
 * with one vocabulary instead of each component inventing its own.
 *
 * Three rules the file follows:
 *
 * 1. **Nothing here hides content by default.** Every initial state is scoped
 *    to `html.tm-motion`, a class an inline snippet in the head adds only when
 *    the visitor has not asked for reduced motion. No JavaScript, an old
 *    browser, or `prefers-reduced-motion: reduce` — the page renders plain and
 *    complete, and the CSS below never runs.
 * 2. **Only `opacity` and `transform`.** Both are composited, so nothing here
 *    triggers layout or paint, and nothing can shift the page: no animation in
 *    this file can move a neighbouring element or contribute to CLS.
 * 3. **Short.** 320–620ms, most of it under 500. Motion that draws attention to
 *    itself is a bug in a shop: it delays the product.
 *
 * Above the fold runs on CSS `animation` alone, so it plays the moment the
 * stylesheet applies rather than waiting on a deferred script. Below the fold
 * is revealed by motion.js, which hides an element only right before it starts
 * watching it — so a script that fails to load leaves the page fully readable
 * rather than blank.
 */

/* -------------------------------------------------------------------------
 * 1. Tokens
 *
 * Durations and easings live here, next to the animations that use them,
 * rather than in base.css with the design tokens: base.css is loaded on every
 * page and these are only meaningful when motion is on.
 * ---------------------------------------------------------------------- */

:root {
	/* The house curve: quick to leave, slow to settle. Used for everything
	   that enters. */
	--tm-motion-ease: cubic-bezier(.22, .68, .28, 1);

	/* For anything that scales, where a hint of overshoot reads as physical
	   rather than mechanical. Kept very mild. */
	--tm-motion-ease-out: cubic-bezier(.2, .9, .3, 1.04);

	--tm-motion-fast: .32s;
	--tm-motion-base: .46s;
	--tm-motion-slow: .62s;

	/* How far an element travels on the way in. Small on purpose: a long
	   slide reads as a page that has not finished loading. */
	--tm-motion-lift: 14px;
	--tm-motion-lift-lg: 22px;

	/* The gap between one staggered item and the next. motion.js reads this
	   at start-up rather than carrying its own copy, so retuning the rhythm
	   of the whole site is a one-line change here. */
	--tm-motion-stagger: 70ms;
}

/* -------------------------------------------------------------------------
 * 2. Keyframes
 *
 * Deliberately few. Most components differ by distance and delay, not by
 * shape of movement, and reusing four keyframes is what makes the site feel
 * like one system.
 * ---------------------------------------------------------------------- */

@keyframes tm-rise {
	from {
		opacity: 0;
		transform: translate3d(0, var(--tm-motion-lift), 0);
	}

	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

@keyframes tm-fall {
	from {
		opacity: 0;
		transform: translate3d(0, calc(var(--tm-motion-lift) * -1), 0);
	}

	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

@keyframes tm-fade {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

@keyframes tm-pop {
	from {
		opacity: 0;
		transform: translate3d(0, 8px, 0) scale(.96);
	}

	to {
		opacity: 1;
		transform: translate3d(0, 0, 0) scale(1);
	}
}

/* A settle rather than an entrance: the element is visible the whole time and
   only relaxes into place. Used where fading in would cost us something —
   see the hero media note below. */
@keyframes tm-settle {
	from {
		transform: scale(1.035);
	}

	to {
		transform: scale(1);
	}
}

/* -------------------------------------------------------------------------
 * 3. Page load
 *
 * The chrome first, then the hero, in one short sequence. Everything is
 * `both`-filled so an element never flashes at its start value before its
 * delay elapses.
 * ---------------------------------------------------------------------- */

html.tm-motion .tm-announcement,
html.tm-motion .tm-topbar {
	animation: tm-fade var(--tm-motion-fast) var(--tm-motion-ease) both;
}

html.tm-motion .tm-header__main {
	animation: tm-fall var(--tm-motion-base) var(--tm-motion-ease) both;
}

/* The hero, staggered. The numbers are the sequence: badge, heading,
   description, buttons — each a beat behind the last, and the whole thing
   finished inside a second. */
html.tm-motion .tm-hero__badge {
	animation: tm-rise var(--tm-motion-base) var(--tm-motion-ease) 80ms both;
}

html.tm-motion .tm-hero__title {
	animation: tm-rise var(--tm-motion-slow) var(--tm-motion-ease) 140ms both;
}

html.tm-motion .tm-hero__desc {
	animation: tm-rise var(--tm-motion-slow) var(--tm-motion-ease) 240ms both;
}

html.tm-motion .tm-hero__actions {
	animation: tm-pop var(--tm-motion-base) var(--tm-motion-ease-out) 340ms both;
}

/*
 * The hero image settles rather than fades, and that is a deliberate
 * departure from the rest of the sequence.
 *
 * The hero image is usually the Largest Contentful Paint element. An element
 * at `opacity: 0` has not been painted as far as the browser is concerned, so
 * fading the hero in from nothing pushes the LCP timestamp out by the whole
 * delay plus duration — the page scores worse for an effect nobody asked for.
 * Scaling costs nothing: the image is painted at full opacity from the first
 * frame and merely relaxes the last 3.5% of its size.
 *
 * If you would rather have the fade and can afford the LCP, add
 * `animation-name: tm-pop` in a child theme.
 */
html.tm-motion .tm-hero__media {
	animation: tm-settle var(--tm-motion-slow) var(--tm-motion-ease) both;
}

/* Everything below the hero on a landing page: one quiet fade so the page
   arrives as a whole rather than in pieces. The sections themselves are
   revealed individually on scroll. */
html.tm-motion .tm-main {
	animation: tm-fade var(--tm-motion-fast) var(--tm-motion-ease) both;
}

/* An interior page has no hero to lead the eye, so its header does the job. */
html.tm-motion .tm-page-head,
html.tm-motion .tm-breadcrumbs {
	animation: tm-rise var(--tm-motion-base) var(--tm-motion-ease) 60ms both;
}

/* -------------------------------------------------------------------------
 * 4. Scroll reveal
 *
 * motion.js adds `tm-reveal` to an element that is below the fold, then
 * `is-in` when it arrives. An element already on screen at load is never
 * given `tm-reveal` at all, so nothing above the fold waits on the observer.
 * ---------------------------------------------------------------------- */

html.tm-motion .tm-reveal {
	opacity: 0;
	transform: translate3d(0, var(--tm-motion-lift-lg), 0);
	transition:
		opacity var(--tm-motion-base) var(--tm-motion-ease),
		transform var(--tm-motion-base) var(--tm-motion-ease);
	transition-delay: var(--tm-reveal-delay, 0ms);
}

html.tm-motion .tm-reveal.is-in {
	opacity: 1;
	transform: translate3d(0, 0, 0);
}

/* Grid and row children arrive one after another. The delay is a custom
   property motion.js sets per element, because `nth-child` cannot know how
   many columns the grid actually resolved to at this viewport. */
html.tm-motion .tm-reveal--soft {
	transform: translate3d(0, var(--tm-motion-lift), 0) scale(.99);
}

html.tm-motion .tm-reveal--soft.is-in {
	transform: translate3d(0, 0, 0) scale(1);
}

/* -------------------------------------------------------------------------
 * 5. Micro-interactions
 *
 * Not entrances — the small responses that make a page feel answered rather
 * than inert. These run whether or not motion.js loaded, but still only when
 * the visitor has not asked for reduced motion.
 * ---------------------------------------------------------------------- */

html.tm-motion .tm-btn {
	transition:
		background-color var(--tm-speed) var(--tm-ease),
		border-color var(--tm-speed) var(--tm-ease),
		color var(--tm-speed) var(--tm-ease),
		box-shadow var(--tm-speed) var(--tm-ease),
		transform var(--tm-speed) var(--tm-ease);
}

html.tm-motion .tm-btn:hover {
	transform: translate3d(0, -1px, 0);
}

/* The press has to be faster than the hover or the button feels spongy. */
html.tm-motion .tm-btn:active {
	transform: translate3d(0, 0, 0) scale(.985);
	transition-duration: 60ms;
}

html.tm-motion .tm-cat-card,
html.tm-motion .tm-brand-card,
html.tm-motion .tm-post-card,
html.tm-motion .tm-benefit {
	transition:
		transform var(--tm-speed-slow) var(--tm-motion-ease),
		box-shadow var(--tm-speed-slow) var(--tm-motion-ease),
		border-color var(--tm-speed) var(--tm-ease);
}

html.tm-motion .tm-cat-card:hover,
html.tm-motion .tm-post-card:hover {
	transform: translate3d(0, -3px, 0);
}

/* A focus ring should never animate: it has to be instant to be useful to
   somebody navigating by keyboard. */
html.tm-motion *:focus-visible {
	transition: none;
}

/* -------------------------------------------------------------------------
 * 6. The off switch
 *
 * base.css already neutralises durations under `prefers-reduced-motion`, and
 * the inline snippet in the head means `html.tm-motion` is never set in the
 * first place. This block is the third belt: it covers a visitor who turns
 * reduced motion on *after* the page has loaded, which the media query
 * re-evaluates live and the head snippet cannot.
 * ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	html.tm-motion .tm-reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}

	html.tm-motion .tm-announcement,
	html.tm-motion .tm-topbar,
	html.tm-motion .tm-header__main,
	html.tm-motion .tm-hero__badge,
	html.tm-motion .tm-hero__title,
	html.tm-motion .tm-hero__desc,
	html.tm-motion .tm-hero__actions,
	html.tm-motion .tm-hero__media,
	html.tm-motion .tm-main,
	html.tm-motion .tm-page-head,
	html.tm-motion .tm-breadcrumbs {
		animation: none;
	}

	html.tm-motion .tm-btn:hover,
	html.tm-motion .tm-btn:active,
	html.tm-motion .tm-cat-card:hover,
	html.tm-motion .tm-post-card:hover {
		transform: none;
	}
}

/* -------------------------------------------------------------------------
 * 7. Printing
 *
 * A half-faded element must not print half-faded.
 * ---------------------------------------------------------------------- */

@media print {
	html.tm-motion .tm-reveal {
		opacity: 1;
		transform: none;
	}
}
