/* ==========================================================================
   Cubes Web — motion: keyframes, animation utilities, scroll reveal.
   Animations move with the `translate` property so `:hover { transform }` still works.
   Content is never hidden unless the browser can reveal it again (see Reveal).
   ========================================================================== */

@keyframes fadeUp {
	from { opacity: 0; translate: 0 28px; }
	to { opacity: 1; translate: 0 0; }
}
@keyframes driveIn {
	0% { opacity: 0; translate: -70% 0; }
	70% { opacity: 1; translate: 3% 0; }
	100% { opacity: 1; translate: 0 0; }
}
@keyframes floatY {
	0%, 100% { translate: 0 0; }
	50% { translate: 0 -8px; }
}
@keyframes road {
	from { background-position: 0 0; }
	to { background-position: -160px 0; }
}
@keyframes glow {
	0%, 100% { opacity: 0.35; }
	50% { opacity: 0.85; }
}
/* RTL rows start at the right edge and overflow to the left, so they may only move right
   (0 → +50%); the opposite row runs the same keyframes in reverse. */
@keyframes marqueeR {
	from { transform: translateX(0); }
	to { transform: translateX(50%); }
}
@keyframes ping {
	0% { transform: scale(1); opacity: 0.6; }
	100% { transform: scale(1.9); opacity: 0; }
}
@keyframes shine {
	from { transform: translateX(160%) skewX(-20deg); }
	to { transform: translateX(-260%) skewX(-20deg); }
}
@keyframes spinSlow {
	to { transform: rotate(360deg); }
}
@keyframes trip {
	from { right: 0; }
	to { right: 100%; }
}

/* ---------- Entrance (above the fold) ---------- */
.in-1, .in-2, .in-3, .in-4 { animation: fadeUp 0.8s var(--ease) both; }
.in-1 { animation-delay: 0.1s; }
.in-2 { animation-delay: 0.25s; }
.in-3 { animation-delay: 0.4s; }
.in-4 { animation-delay: 0.55s; }
.drive { animation: driveIn 1.5s var(--ease) 0.35s both; }
.float { animation: floatY 4.5s ease-in-out 1.9s infinite; }

/* ---------- Loops ---------- */
.road {
	background-image: repeating-linear-gradient(90deg, rgb(255 255 255 / 0.55) 0 48px, transparent 48px 80px);
	animation: road 0.5s linear infinite;
}
.glow { animation: glow 2.6s ease-in-out infinite; }
.spin-slow { animation: spinSlow 70s linear infinite; }
.trip { animation: trip 6s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate; }
.ticker-track { animation: marqueeR 45s linear infinite; }
.mq-r { animation: marqueeR 55s linear infinite; }
.mq-l { animation: marqueeR 55s linear infinite reverse; }
.mq-wrap:hover .mq-r,
.mq-wrap:hover .mq-l { animation-play-state: paused; }

/* Rotating words: the list holds the words plus the first one again for a seamless loop.
   The keyframes depend on the number of words, so the page generates them (www/index.py). */
.words { display: inline-block; height: 1.25em; line-height: 1.25em; overflow: hidden; vertical-align: bottom; }
.words > span { display: block; }
.words > span > span { display: block; height: 1.25em; white-space: nowrap; }

/* Live dot: <span class="ping-dot"><span class="ping"></span></span> */
.ping-dot { position: relative; display: inline-block; width: 8px; height: 8px; flex-shrink: 0; border-radius: 50%; background: #22c55e; }
.ping { position: absolute; inset: 0; border-radius: 50%; background: inherit; animation: ping 2s ease-out infinite; }

/* ---------- Hover ---------- */
.lift { transition: transform 0.25s ease, box-shadow 0.25s ease; }
.lift:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgb(15 15 20 / 0.12); }
.shine { position: relative; overflow: hidden; }
.shine::after {
	content: "";
	position: absolute;
	inset-block: 0;
	right: 0;
	width: 40%;
	background: rgb(255 255 255 / 0.28);
	transform: translateX(160%) skewX(-20deg);
	pointer-events: none;
}
.shine:hover::after { animation: shine 0.9s ease; }

/* ---------- Reveal on scroll ----------
   1. Browsers with scroll-driven animations: pure CSS.
   2. Others: hidden only once cubes_web.js has put `js-reveal` on <html>
      (it does so only when it can observe and reveal the elements). */
@supports (animation-timeline: view()) {
	.reveal {
		animation: fadeUp linear both;
		animation-timeline: view();
		animation-range: entry 0% cover 22%;
	}
}
@supports not (animation-timeline: view()) {
	.js-reveal .reveal { transition: opacity 0.7s var(--ease), translate 0.7s var(--ease); }
	.js-reveal .reveal:not(.is-visible) { opacity: 0; translate: 0 24px; }
	.js-reveal .reveal-delay-1 { transition-delay: 0.1s; }
	.js-reveal .reveal-delay-2 { transition-delay: 0.2s; }
	.js-reveal .reveal-delay-3 { transition-delay: 0.3s; }
}

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after { animation: none !important; transition: none !important; }
	.js-reveal .reveal:not(.is-visible) { opacity: 1; translate: none; }
}
