/* ==========================================================================
   SNOVOTEK — animations.css
   All animation & transition rules. Every rule in this file is disabled
   under prefers-reduced-motion (see bottom of file) — content still
   appears, just without movement.
   ========================================================================== */

/* ---- Ambient glow drift (dark hero sections) — 20–30s loop ---- */
.glow-a { animation: glow-drift-a 24s ease-in-out infinite; }
.glow-b { animation: glow-drift-b 30s ease-in-out infinite; }
.pg     { animation: glow-drift-a 26s ease-in-out infinite; }
@keyframes glow-drift-a {
	0%, 100% { transform: translate(0, 0); }
	50%      { transform: translate(-60px, 50px); }
}
@keyframes glow-drift-b {
	0%, 100% { transform: translate(0, 0); }
	50%      { transform: translate(50px, -40px); }
}

/* ---- Scroll-triggered hover cursor arrow ---- */
.hero-scroll .arr { animation: arrow-drift 1.8s ease-in-out infinite; }
@keyframes arrow-drift {
	0%, 100% { transform: translateY(0); opacity: .4; }
	50%      { transform: translateY(6px); opacity: 1; }
}

/* ---- Ticker infinite scroll ---- */
.ticker-track { animation: ticker-scroll 26s linear infinite; }
@keyframes ticker-scroll {
	0%   { transform: translateX(0); }
	100% { transform: translateX(-50%); }
}
.ticker:hover .ticker-track { animation-play-state: paused; }

/* ---- Hero word-mask reveal (staggered 80ms per word) ----
   Every "start hidden" rule below is scoped under .js-ready, a class
   header.php adds to <html> via a synchronous inline script the instant
   JS is available. Content is visible by default in CSS; JS only ever
   makes it hidden-then-reveals, never the reverse. That way a
   blocked/failed script, a slow load, or a browser restoring the page
   from back/forward cache (which does not re-fire DOMContentLoaded, so
   a "run once on load" reveal script would otherwise never re-trigger)
   can never leave real content permanently invisible — worst case it
   just shows without the fade-in flourish. main.js additionally forces
   every reveal to complete a few seconds after load and immediately on
   bfcache restore, as a second safety net.
   IMPORTANT: these "start hidden" selectors deliberately use the plain
   class ".js-ready" rather than "html.js-ready" — adding the "html"
   element type would make them MORE specific than their "revealed"
   counterparts below (e.g. ".rv.in"), which would make the hidden
   state win permanently even after JS adds .in. Keep specificity equal
   and rely on source order (hidden rule first, revealed rule after)
   instead of qualifying with an element type. */
.js-ready .hero h1 .w > span, .js-ready .ph h1 .w > span {
	display: block; transform: translateY(112%);
	transition: transform 1s cubic-bezier(.16,1,.3,1);
}
.hero h1 .w > span, .ph h1 .w > span { display: block; }
.loaded .hero h1 .w > span, .loaded .ph h1 .w > span { transform: none; }
.hero h1 .w:nth-child(1) > span, .ph h1 .w:nth-child(1) > span { transition-delay: 0ms; }
.hero h1 .w:nth-child(2) > span, .ph h1 .w:nth-child(2) > span { transition-delay: 80ms; }
.hero h1 .w:nth-child(3) > span, .ph h1 .w:nth-child(3) > span { transition-delay: 160ms; }
.hero h1 .w:nth-child(4) > span, .ph h1 .w:nth-child(4) > span { transition-delay: 240ms; }
.hero h1 .w:nth-child(5) > span, .ph h1 .w:nth-child(5) > span { transition-delay: 320ms; }
.hero h1 .w:nth-child(6) > span, .ph h1 .w:nth-child(6) > span { transition-delay: 400ms; }
.hero h1 .w:nth-child(7) > span, .ph h1 .w:nth-child(7) > span { transition-delay: 480ms; }

.js-ready .hero-eyebrow { opacity: 0; transition: opacity .6s .1s; }
.loaded .hero-eyebrow { opacity: 1; }
.js-ready .hero-sub { opacity: 0; transform: translateY(14px); transition: opacity .9s .5s, transform .9s .5s; }
.loaded .hero-sub { opacity: 1; transform: none; }
.js-ready .hero-btns { opacity: 0; transition: opacity .8s .7s; }
.loaded .hero-btns { opacity: 1; }
.js-ready .hero-scroll { opacity: 0; transition: opacity 1s 1.1s; }
.loaded .hero-scroll { opacity: .4; }

/* ---- Generic scroll reveals: fade up + slide in ----
   .rv  = whole-block reveal
   .rv2 = smaller/faster reveal (secondary elements)
   .stg = staggered children, 100ms apart
   .fL / .fR = slide in from left / right */
.js-ready .rv {
	opacity: 0; transform: translateY(28px);
	transition: opacity 1.1s cubic-bezier(.16,1,.3,1), transform 1.1s cubic-bezier(.16,1,.3,1);
}
.rv.in { opacity: 1; transform: none; }

.js-ready .rv2 {
	opacity: 0; transform: translateY(16px);
	transition: opacity .85s cubic-bezier(.16,1,.3,1), transform .85s cubic-bezier(.16,1,.3,1);
}
.rv2.in { opacity: 1; transform: none; }

/* Staggered children — each child fades/slides up in turn rather than
   all at once, at 150ms intervals, for a more deliberate "one by one"
   reveal as the block scrolls into view. */
.js-ready .stg > * { opacity: 0; transform: translateY(24px); }
.stg.in > * {
	opacity: 1; transform: none;
	transition: opacity 1.05s cubic-bezier(.16,1,.3,1), transform 1.05s cubic-bezier(.16,1,.3,1);
}
.stg.in > *:nth-child(1)  { transition-delay: 0ms; }
.stg.in > *:nth-child(2)  { transition-delay: 150ms; }
.stg.in > *:nth-child(3)  { transition-delay: 300ms; }
.stg.in > *:nth-child(4)  { transition-delay: 450ms; }
.stg.in > *:nth-child(5)  { transition-delay: 600ms; }
.stg.in > *:nth-child(6)  { transition-delay: 750ms; }
.stg.in > *:nth-child(7)  { transition-delay: 900ms; }
.stg.in > *:nth-child(8)  { transition-delay: 1050ms; }
.stg.in > *:nth-child(9)  { transition-delay: 1200ms; }
.stg.in > *:nth-child(10) { transition-delay: 1350ms; }

.js-ready .fL {
	opacity: 0; transform: translateX(-32px);
	transition: opacity 1.1s cubic-bezier(.16,1,.3,1), transform 1.1s cubic-bezier(.16,1,.3,1);
}
.js-ready .fR {
	opacity: 0; transform: translateX(32px);
	transition: opacity 1.1s cubic-bezier(.16,1,.3,1), transform 1.1s cubic-bezier(.16,1,.3,1);
}
.fL.in, .fR.in { opacity: 1; transform: none; }

/* ---- Service card hover: cyan top border + background shift ----
   No lift/box-shadow here — .svc-3 (the parent grid) has
   overflow:hidden so its shared 1px hairline borders render cleanly,
   but that same overflow:hidden was clipping the lifted card's
   shadow mid-transition, which is what read as "glitchy". Everything
   below stays within the card's own box, so nothing gets clipped. */
.sc {
	transition: background-color .25s ease;
	border-top: 2px solid transparent;
}
.sc::before {
	content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 2px;
	background: var(--cyan); transform: scaleX(0); transform-origin: left;
	transition: transform .4s cubic-bezier(.16,1,.3,1);
}
.sc:hover { background: #FAFBFE; }
.sc:hover::before { transform: scaleX(1); }
.sc-icon { transition: transform .4s cubic-bezier(.34,1.56,.64,1); }
.sc:hover .sc-icon { transform: translateY(-3px); }

/* ---- OEM resource cards: subtle lift on hover ---- */
.rc { transition: transform .3s ease, border-color .3s ease, background-color .25s ease; }
.rc:hover { transform: translateY(-2px); }

/* ---- OEM 5-step process: lights up sequentially while scrolling ---- */
.ps-node { transition: border-color .5s, color .5s, transform .5s cubic-bezier(.34,1.56,.64,1), box-shadow .5s; }
.ps.lit .ps-node { border-color: var(--cyan); color: var(--cyan); transform: scale(1.08); box-shadow: 0 0 20px rgba(56,175,255,.4); }
.ps h4 { opacity: .45; transition: opacity .5s; }
.ps.lit h4 { opacity: 1; }
.ps p { transition: color .5s; }
.ps.lit p { color: rgba(255,255,255,.75); }
.ps-fill { transition: width 1.2s cubic-bezier(.16,1,.3,1); }

/* ---- OEM step rows (linear list variant) — fade/highlight on scroll ---- */
.sr { transition: opacity .5s ease; }
.sr-n { transition: color .5s ease, opacity .5s ease; opacity: .5; }
.sr.lit .sr-n { opacity: 1; }

/* ---- Buttons: lift + brightness on hover ---- */
.btn { transition: transform .22s ease, background-color .22s ease, color .22s ease, border-color .22s ease, filter .22s ease; }
.bp:hover { background: #5CC0FF; transform: translateY(-1px); }
.bo:hover { border-color: var(--cyan); color: var(--cyan); }
.bd:hover { background: var(--cyan); color: var(--void); }
.btn:active { transform: translateY(0); }

/* ---- Mobile menu slide down ---- */
#mobile-menu {
	max-height: 0; overflow: hidden; opacity: 0;
	transition: max-height .35s cubic-bezier(.16,1,.3,1), opacity .3s ease;
}
#mobile-menu.open { max-height: 70vh; opacity: 1; overflow-y: auto; }
#menu-toggle span { transition: transform .3s ease, opacity .3s ease; }
#menu-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
#menu-toggle.open span:nth-child(2) { opacity: 0; }
#menu-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---- Contact form tab switch ---- */
.form-pane { animation: fade-in .35s ease; }
@keyframes fade-in {
	from { opacity: 0; transform: translateY(6px); }
	to   { opacity: 1; transform: none; }
}

/* ---- Respect reduced motion: show everything immediately, no movement ---- */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
	.rv, .rv2, .stg > *, .fL, .fR,
	.hero h1 .w > span, .ph h1 .w > span, .hero-eyebrow, .hero-sub, .hero-btns, .hero-scroll {
		opacity: 1 !important;
		transform: none !important;
	}
	.glow-a, .glow-b, .pg, .ticker-track, .hero-scroll .arr {
		animation: none !important;
	}
	.sc:hover, .rc:hover {
		transform: none !important;
	}
}
