/*
 * Motion: one calm direction for every interaction on the site.
 *
 *   Quiet and deliberate: colour eases in, lines draw, content arrives and
 *   settles. One curve (--ease-out), four durations (tokens/layout.css).
 *   Nothing bounces, blinks or loops, except the turning film ring and the
 *   image band, which are content. Movement only where it tells something:
 *   a photograph only comes closer when it is a link.
 *
 *   1. Tint     surfaces ease into their active colour; text follows
 *               (buttons, hero tabs, social squares)
 *   2. Line     a fine underline draws in from the left and leaves to
 *               the right (text links, navigation, footer)
 *   3. Nudge    chevrons and arrows move a few pixels their way
 *               (arrow links, hero tabs, carousels)
 *   4. Settle   a linked photograph comes slowly closer under the pointer;
 *               large photographs arrive slightly enlarged and settle as
 *               they reveal
 *   5. Reveal   content fades and rises into place once, staggered
 *   +  Colour   text colour follows the tint or line it belongs to
 *
 * Components only name their colours (--button-fill, --fill-color, …);
 * the movement lives here, so a new block joins by adding its selector to
 * the matching list. Reduced motion collapses every duration and distance
 * to nothing (tokens/layout.css): states still change, nothing travels.
 */
@layer components {
	/* =====================================================================
	   1. Tint
	   ===================================================================== */
	.button {
		transition: color var(--duration-base) var(--ease-out);
	}

	.button::before {
		transition: background-color var(--duration-base) var(--ease-out);
	}

	.button:is(:hover, :focus-visible) {
		color: var(--button-fill-foreground);
	}

	.button:is(:hover, :focus-visible)::before {
		background-color: var(--button-fill);
	}

	/* Any other surface: name a --fill-color (and a resting --rest-color). */
	:is(.motion-tint, .opener__tab, .site-footer__social) {
		background-color: var(--rest-color, transparent);
		transition:
			background-color var(--duration-base) var(--ease-out),
			color var(--duration-base) var(--ease-out),
			box-shadow var(--duration-base) var(--ease-out);
	}

	:is(.motion-tint, .opener__tab, .site-footer__social):is(:hover, :focus-visible) {
		background-color: var(--fill-color, var(--primary));
	}

	/* =====================================================================
	   2. Line
	   Inline text: the underline is a background on the text itself, so it
	   follows every line of a wrapped link. Box links (navigation) draw a
	   pseudo-element at a fixed distance below the words instead.
	   A link that a grid or flex parent turns into a box keeps the width of
	   its words (width is ignored while it stays inline), so the line never
	   runs across the column.
	   ===================================================================== */
	:is(.motion-line, .arrow-link__text, .site-header__topbar a, .site-footer__list a, .site-footer__legal a, .contact-block a, .gallery__link, .post-entry__link, .form-note a) {
		width: fit-content;
		background-image: linear-gradient(currentColor, currentColor);
		background-position: 100% 100%;
		background-size: 0 var(--border-width);
		background-repeat: no-repeat;
		-webkit-box-decoration-break: clone;
		box-decoration-break: clone;
		text-decoration: none;
		transition:
			background-size var(--duration-base) var(--ease-out),
			color var(--duration-fast) var(--ease-out);
	}

	:is(.motion-line, .site-header__topbar a, .site-footer__list a, .site-footer__legal a, .contact-block a, .gallery__link, .post-entry__link, .form-note a):is(:hover, :focus-visible),
	:is(.arrow-link, .gallery__figure, .post-entry):is(:hover, :focus-within) :is(.arrow-link__text, .gallery__link, .post-entry__link),
	.site-header__topbar a[aria-current] {
		background-position: 0 100%;
		background-size: 100% var(--border-width);
	}

	/* A note link is underlined at rest; the line draws over it. */
	.form-note a {
		text-decoration: underline;
		text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
		text-underline-offset: 0.2em;
	}

	:is(.motion-line-box, .site-header__menu a, .site-header__contact) {
		position: relative;
	}

	:is(.motion-line-box, .site-header__menu a, .site-header__contact)::after {
		content: "";
		position: absolute;
		left: 0;
		right: 0;
		bottom: var(--line-offset, 0.875rem);
		height: var(--border-width);
		background: currentColor;
		scale: 0 1;
		transform-origin: 100% 50%;
		transition: scale var(--duration-base) var(--ease-out);
	}

	:is(.motion-line-box, .site-header__menu a, .site-header__contact):is(:hover, :focus-visible)::after,
	.site-header__menu a[aria-current]::after {
		scale: 1 1;
		transform-origin: 0 50%;
	}

	/* =====================================================================
	   3. Nudge
	   ===================================================================== */
	.carousel__button::before,
	.opener__tab-arrow {
		transition:
			translate var(--duration-base) var(--ease-out),
			background-color var(--duration-base) var(--ease-out);
	}

	.opener__tab:is(:hover, :focus-visible) .opener__tab-arrow,
	.carousel__button--next:is(:hover, :focus-visible):not(:disabled)::before {
		translate: var(--motion-nudge) 0;
	}

	.carousel__button--previous:is(:hover, :focus-visible):not(:disabled)::before {
		translate: calc(var(--motion-nudge) * -1) 0;
	}

	/* The arrow link's chevron is inline (it stays with the last word), so
	   it moves by its mask, not by translate. */
	.arrow-link::after {
		transition: mask-position var(--duration-base) var(--ease-out);
	}

	.arrow-link:is(:hover, :focus-visible) {
		--arrow-link-shift: calc(var(--space-2) + var(--motion-nudge));
	}

	/* =====================================================================
	   4. Settle
	   Only a photograph that is a link comes closer under the pointer; a
	   photograph that is only shown stays still. Large photographs arrive
	   slightly enlarged and settle as they reveal.
	   ===================================================================== */
	:is(.chapter__image, .feature__image, .gallery__image, .post-entry__image) {
		transition: scale var(--duration-slow) var(--ease-out);
	}

	:is(.gallery__figure:has(.gallery__link), .post-entry):is(:hover, :focus-within) :is(.gallery__image, .post-entry__image) {
		scale: var(--motion-zoom);
	}

	:root.js [data-reveal]:not([data-revealed]) :is(.chapter__image, .feature__image, .gallery__image) {
		scale: var(--motion-settle);
	}

	/* The hero photograph settles once as the page opens. */
	.opener__image {
		animation: motion-settle calc(var(--duration-slow) * 1.8) var(--ease-out) both;
	}

	@keyframes motion-settle {
		from { scale: var(--motion-settle); }
		to { scale: 1; }
	}

	/* =====================================================================
	   5. Reveal
	   Hidden only when JavaScript runs (main.js marks what has been seen);
	   --reveal-index staggers entries of one list.
	   ===================================================================== */
	:root.js [data-reveal] {
		opacity: 0;
		translate: 0 var(--motion-distance);
		transition:
			opacity var(--duration-reveal) var(--ease-out),
			translate var(--duration-reveal) var(--ease-out);
		transition-delay: calc(var(--reveal-index, 0) * var(--stagger));
	}

	:root.js [data-reveal][data-revealed] {
		opacity: 1;
		translate: 0 0;
	}

	/* =====================================================================
	   + Colour: text that follows a fill or a line
	   ===================================================================== */
	:is(.opener__tab-title, .opener__tab-label, .gallery__title, .post-entry__title, .criteria__title, .site-header__menu a, .site-header__contact, .site-menu__list a, .site-footer__social) {
		transition: color var(--duration-base) var(--ease-out);
	}

	/* =====================================================================
	   Elsewhere, already on these tokens: the header sliding away
	   (chrome.css), the carousel
	   (carousel.js), the menu fade (chrome.css), the film ring and the
	   image band (feature.css, marquee.css).
	   ===================================================================== */
}
