/* ==========================================================================
   MOTION TOKENS — edit this block to change the feel of the whole page.
   3 durations, 3 easings. Everything below composes from these.
   ========================================================================== */
:root {
  --motion-fast: 160ms;   /* micro-interactions: hover, focus, arrow nudges */
  --motion-base: 520ms;   /* entrances: reveals, card fades, chart draws */
  --motion-hero: 900ms;   /* hero-only: line-mask reveal, first paint */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);   /* house curve — all entrances */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); /* micro-interactions, hover */
  --ease-press: cubic-bezier(0.33, 1, 0.68, 1);  /* button press-release only */
  --travel-y: 18px;       /* entrance travel distance, one axis: up */
  --stagger-step: 64ms;   /* per-item delay inside a reveal group */
}
@media (max-width: 768px) {
  :root { --travel-y: 10px; --stagger-step: 40ms; }
}
@media (prefers-reduced-motion: reduce) {
  :root { --motion-fast: 0ms; --motion-base: 0ms; --motion-hero: 0ms; --travel-y: 0px; --stagger-step: 0ms; }
}

/* ==========================================================================
   GLOBAL REDUCED-MOTION GUARD — one place, kills all transform/scroll motion.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html.motion [data-animate],
  html.motion .mini-bars i,
  html.motion .sparkline-area,
  html.motion .sparkline circle,
  html.motion .hero-line-inner {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
  }
  .hero-media, .creator-track, .brand-track { animation: none !important; }
}

/* ==========================================================================
   GENERIC REVEAL — entrances, one axis (up + opacity), capped stagger.
   Default (no .motion on <html>): everything visible. No FOUC if JS dies.
   ========================================================================== */
html.motion [data-animate]:not([data-animate="chart"]) {
  opacity: 0;
  transform: translateY(var(--travel-y));
  transition: opacity var(--motion-base) var(--ease-out), transform var(--motion-base) var(--ease-out);
}
html.motion [data-animate].is-in { opacity: 1; transform: none; }

[data-animate-group] > [data-animate]:nth-child(1) { transition-delay: calc(var(--stagger-step) * 0); }
[data-animate-group] > [data-animate]:nth-child(2) { transition-delay: calc(var(--stagger-step) * 1); }
[data-animate-group] > [data-animate]:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }
[data-animate-group] > [data-animate]:nth-child(4) { transition-delay: calc(var(--stagger-step) * 3); }
[data-animate-group] > [data-animate]:nth-child(n+5) { transition-delay: calc(var(--stagger-step) * 4); }

/* ==========================================================================
   HOVER — card lift + arrow nudge. Reused everywhere a card/link exists.
   ========================================================================== */
.data-card, .home .testimonial-card, .home .work-card, .collaboration-paths a {
  transition: transform var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard), box-shadow var(--motion-fast) var(--ease-standard);
}
.home .testimonial-card:hover { transform: translateY(-4px); border-color: var(--color-accent-ink); }
.collaboration-paths a:hover { transform: translateY(-4px); }
.data-card:hover { transform: translateY(-4px); border-color: var(--color-accent-ink); }

.work-arrow, .text-link .arrow, .collaboration-paths strong b, .button .arrow {
  display: inline-block; transition: transform var(--motion-fast) var(--ease-standard);
}
.work-card:hover .work-arrow,
.text-link:hover .arrow,
.collaboration-paths a:hover strong b,
.home .button:hover .arrow { transform: translateX(4px); }

.home .button:active { transform: translateY(-2px) scale(0.985); transition: transform 100ms var(--ease-press); }

/* ==========================================================================
   NUMBER COUNTERS — final value pre-rendered in HTML; JS animates the digits.
   Reserve nothing extra: text length only ever grows toward its own final width.
   ========================================================================== */
[data-counter] { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   CHARTS — bars scaleY, lines stroke-draw, areas clip-path wipe. Fire once.
   ========================================================================== */
html.motion .mini-bars i {
  transform: scaleY(0); transform-origin: bottom;
  transition: transform 600ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger-step));
}
html.motion .mini-bars.is-in i { transform: scaleY(1); }

html.motion .sparkline-area {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 900ms var(--ease-out);
}
html.motion .sparkline.is-in .sparkline-area { clip-path: inset(0 0 0 0); }

html.motion .sparkline circle {
  opacity: 0; transition: opacity 300ms var(--ease-out); transition-delay: 750ms;
}
html.motion .sparkline.is-in circle { opacity: 1; }

html.motion .flow span, html.motion .creator-symbols span {
  opacity: 0; transform: translateY(var(--travel-y));
  transition: opacity var(--motion-base) var(--ease-out), transform var(--motion-base) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger-step));
}
html.motion .flow.is-in span, html.motion .creator-symbols.is-in span { opacity: 1; transform: none; }

/* ==========================================================================
   HERO — never gated behind scroll. Autoplay on paint, own short timeline.
   ========================================================================== */
.hero-line-mask { display: block; overflow: hidden; }
.hero-line-inner { display: block; transform: translateY(105%); animation: heroLineIn var(--motion-hero) var(--ease-out) both; }
.hero-line-mask:nth-of-type(1) .hero-line-inner { animation-delay: 0ms; }
.hero-line-mask:nth-of-type(2) .hero-line-inner { animation-delay: 90ms; }
.hero-line-mask:nth-of-type(3) .hero-line-inner { animation-delay: 170ms; }
@keyframes heroLineIn { to { transform: translateY(0); } }

.home .hero-description, .home .button-row { animation: heroFadeUp var(--motion-base) var(--ease-out) both; }
.home .hero-description { animation-delay: 300ms; }
.home .button-row { animation-delay: 380ms; }
@keyframes heroFadeUp { from { opacity: 0; transform: translateY(var(--travel-y)); } to { opacity: 1; transform: none; } }

.hero-media { position: absolute; inset: 0; transform-origin: center; animation: heroKenBurns 2.4s var(--ease-out) both; }
@keyframes heroKenBurns { from { transform: scale(1.045); } to { transform: scale(1); } }

.portrait-note, .portrait-proof { animation: heroFadeUp var(--motion-base) var(--ease-out) both; }
.portrait-note { animation-delay: 460ms; }
.portrait-proof { animation-delay: 540ms; }

/* ==========================================================================
   NAV — scrolled state via a layered ::before, so nothing but opacity moves.
   ========================================================================== */
.home .top-nav::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: rgb(255 255 255 / .97); box-shadow: 0 8px 24px rgb(15 40 35 / .06);
  opacity: 0; transition: opacity var(--motion-fast) var(--ease-standard);
}
.home .top-nav.scrolled::before { opacity: 1; }

/* ==========================================================================
   FORMS — field stagger reveal, focus state, validation, submit transition.
   ========================================================================== */
html.motion .form-group[data-animate] { transition-duration: var(--motion-fast); }
.form-group input, .form-group select, .form-group textarea {
  transition: border-color var(--motion-fast) var(--ease-standard), box-shadow var(--motion-fast) var(--ease-standard);
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
  border-color: var(--color-accent-ink); box-shadow: 0 0 0 3px var(--color-accent-soft); outline: none;
}
.form-group { position: relative; }
.field-error {
  position: absolute; left: 0; top: 100%; margin-top: 4px; font-size: 12px; color: #c0392b;
  opacity: 0; transform: translateY(-4px);
  transition: opacity var(--motion-fast) var(--ease-standard), transform var(--motion-fast) var(--ease-standard);
  pointer-events: none;
}
.form-group.invalid .field-error { opacity: 1; transform: none; }
.form-group.invalid input, .form-group.invalid select, .form-group.invalid textarea { border-color: #c0392b; }

.form-submit { position: relative; transition: transform var(--motion-fast) var(--ease-standard); overflow: hidden; }
.form-submit .submit-label { display: inline-flex; align-items: center; gap: 10px; transition: opacity var(--motion-fast) var(--ease-standard); }
.form-submit .submit-spinner {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity var(--motion-fast) var(--ease-standard);
}
.form-submit .submit-spinner svg { width: 18px; height: 18px; animation: spin 700ms linear infinite; }
.form-submit.is-loading { pointer-events: none; }
.form-submit.is-loading .submit-label { opacity: 0; }
.form-submit.is-loading .submit-spinner { opacity: 1; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .hero-line-inner, .hero-media, .portrait-note, .portrait-proof, .home .hero-description, .home .button-row { animation: none !important; transform: none !important; opacity: 1 !important; }
}
