/**
 * Animation / interaction styles — Whylet Design System.
 *
 * IMPORTANT — reveal safety contract:
 * The hidden state is scoped to `html.js`. That class is set by a tiny inline
 * script in <head> BEFORE first paint. Consequences:
 *   - JS disabled / blocked / failed  -> `.js` never applied -> content is
 *     visible by default. Content can never be trapped at opacity:0.
 *   - JS enabled -> hidden state applies before paint, so there is no flash of
 *     visible-then-hidden content.
 * This replaces the previous <noscript> override, which could not protect
 * against JS that loaded but errored.
 */

/* ---------- Scroll reveal ---------- */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-reveal) var(--ease), transform var(--dur-reveal) var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
.js .reveal.show { opacity: 1; transform: none; }

/* Staggered entry within a group */
.js .reveal:nth-child(2) { --reveal-delay: 60ms; }
.js .reveal:nth-child(3) { --reveal-delay: 120ms; }
.js .reveal:nth-child(4) { --reveal-delay: 180ms; }
.js .reveal:nth-child(5) { --reveal-delay: 240ms; }
.js .reveal:nth-child(6) { --reveal-delay: 300ms; }

/* ---------- Hero entrance (CSS-native, never JS-gated) ---------- */
@keyframes heroCopyIn { from { opacity: 0; transform: translate3d(0, 24px, 0); } to { opacity: 1; transform: none; } }
@keyframes heroArtIn  { from { opacity: 0; transform: translate3d(24px, 0, 0) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes orbitDrift { to { transform: rotate(360deg); } }
@keyframes patternFloat { 50% { transform: translate3d(0, -7px, 0) rotate(.35deg); } }
@keyframes float { 50% { transform: translate(5px, -10px); opacity: .75; } }
@keyframes scan { 0%, 100% { transform: translateY(-180px); } 50% { transform: translateY(180px); } }
@keyframes marquee { to { transform: translateX(-50%); } }

.hero-copy { animation: heroCopyIn .8s var(--ease) both; }
.hero-art { animation: heroArtIn .95s var(--ease) .08s both; }
.hero-orbit { animation: orbitDrift 22s linear infinite; }
.pattern { animation: patternFloat 7s ease-in-out infinite; }
.hero-scan { animation: scan 7s ease-in-out infinite; }
.pattern .particle { animation: float 6s ease-in-out infinite; }
.pattern .particle:nth-child(2n) { animation-duration: 8s; }
.pattern .particle:nth-child(3n) { animation-duration: 10s; }

/* Marquee: .marquee-track renders duplicated content, so -50% loops seamlessly. */
.marquee-track { animation: marquee 38s linear infinite; }

/* ---------- Navigation underline ---------- */
.nav-links a:after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -7px;
  height: 1px;
  background: var(--accent-strong);
  transition: right var(--dur-base) var(--ease);
}
.nav-links a:hover:after { right: 0; }

/* ---------- Component hover transitions ---------- */
.service, .assure-card, .process-item, .faq-item {
  transition: background var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.service:hover { background: var(--accent-wash); }
.assure-card:hover { background: rgba(245, 241, 231, 0.04); }
.assure-card:hover .assure-no { transform: translateX(4px); }
.process-item:hover { background: rgba(245, 241, 231, 0.04); }
.process-item .no { display: inline-block; transition: transform var(--dur-base) var(--ease); }
.process-item:hover .no { transform: translateX(4px); }

.step { transition: border-color var(--dur-base) var(--ease), transform var(--dur-base) var(--ease); }
.step:hover { border-color: rgba(184, 70, 25, 0.4); transform: translateY(-3px); }

.contact .form { transition: box-shadow var(--dur-slow) var(--ease); }
.contact .form:focus-within { box-shadow: var(--shadow-lg); }

/* ---------- Mobile: drop continuous background GPU work ---------- */
@media (max-width: 760px) {
  /* Decorative hero motion is dropped on small screens for battery/paint cost.
     The marquee is NOT dropped: it now carries the Polar Start -> Whylet
     relationship, which must be readable on mobile. It is a single composited
     transform, so the cost is negligible. */
  .hero-orbit, .pattern, .pattern .particle, .hero-scan { animation: none !important; }
  .marquee-track { animation-duration: 26s; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *:before, *:after { animation: none !important; transition: none !important; }
  /* With the animation stopped the marquee would sit clipped at its first
     phrase. Reflow it into a static, fully readable block instead, and drop the
     duplicate track that exists only to make the loop seamless. */
  .marquee-track { width: auto; flex-wrap: wrap; }
  .marquee-item { white-space: normal; }
  .marquee-item + .marquee-item { display: none; }
  .js .reveal, .hero-copy, .hero-art { opacity: 1 !important; transform: none !important; }
  .hero-orbit, .pattern { transform: none !important; }
}
