/* ============================================================
   Trixy — marketing surfaces (landing, login, register).

   Separate from app.css on purpose: the dashboard is a tool someone
   works in all day and stays quiet, while these three pages are the
   shop window and are allowed to move.

   Every animation here is gated behind prefers-reduced-motion. A page
   that ignores that setting is not "lively", it is unusable for the
   people who turned it on.
   ============================================================ */

/* ───────── Doodles ─────────
   Decorative only: aria-hidden, never carrying meaning, and always
   behind the content they sit near. */
.doodle {
  position: absolute;
  color: var(--brand, #533AD3);
  /* Presence is what makes the motion readable. At the 6-10% this started
     at, a 16px drift was invisible — the doodles were technically animating
     and visibly static. */
  opacity: .20;
  pointer-events: none;
  z-index: 0;
}
.doodle svg { width: 100%; height: 100%; display: block; }
.doodle-soft { opacity: .13; }
.doodle-ink  { opacity: .30; }

/* ───────── Motion ───────── */
/* The keyframes carry the parallax offsets themselves.
   An animation and a static rule cannot both own `transform` — the
   animation wins and the other is silently dropped — so the pointer
   offsets are folded into every step instead of fighting for the
   property. --px/--py are written by marketing.js. */
@keyframes dd-float {
  0%, 100% { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(var(--r, 0deg)); }
  50%      { transform: translate(var(--px, 0px), calc(var(--py, 0px) - 22px)) rotate(calc(var(--r, 0deg) + 4deg)); }
}
@keyframes dd-drift {
  0%, 100% { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(var(--r, 0deg)); }
  33%      { transform: translate(calc(var(--px, 0px) + 18px), calc(var(--py, 0px) - 20px)) rotate(calc(var(--r, 0deg) - 6deg)); }
  66%      { transform: translate(calc(var(--px, 0px) - 15px), calc(var(--py, 0px) + 14px)) rotate(calc(var(--r, 0deg) + 6deg)); }
}
@keyframes dd-swing {
  0%, 100% { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(calc(var(--r, 0deg) - 7deg)); }
  50%      { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(calc(var(--r, 0deg) + 7deg)); }
}
@keyframes dd-pulse {
  0%, 100% { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(var(--r, 0deg)) scale(1); }
  50%      { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(var(--r, 0deg)) scale(1.12); }
}
@keyframes dd-spin-slow {
  from { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(0deg); }
  to   { transform: translate(var(--px, 0px), var(--py, 0px)) rotate(360deg); }
}
@keyframes dd-draw { to { stroke-dashoffset: 0; } }
@keyframes dd-marquee { to { transform: translateX(-50%); } }
@keyframes dd-pop {
  0%   { transform: scale(.6); opacity: 0; }
  60%  { transform: scale(1.06); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

.anim-float  { animation: dd-float 5s ease-in-out infinite; }
.anim-drift  { animation: dd-drift 9s ease-in-out infinite; }
.anim-spin   { animation: dd-spin-slow 28s linear infinite; }
.anim-swing  { animation: dd-swing 5.5s ease-in-out infinite; }
.anim-pulse  { animation: dd-pulse 6s ease-in-out infinite; }
.anim-delay-1 { animation-delay: -1.5s; }
.anim-delay-2 { animation-delay: -3.5s; }
.anim-delay-3 { animation-delay: -5.5s; }

/* The hero doodles draw themselves in, as if sketched. */
.doodle-draw svg * {
  stroke-dasharray: 260;
  stroke-dashoffset: 260;
  animation: dd-draw 1.6s ease-out forwards;
}
.doodle-draw.dd-late svg * { animation-delay: .35s; }

/* ───────── Scroll reveal ─────────
   Elements start displaced and settle as they enter the viewport.
   `.is-in` is added by the observer in marketing.js. */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .55s ease-out, transform .55s cubic-bezier(.22,1,.36,1);
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: none; }
.reveal-sm { transform: translateY(12px); }
.reveal-l  { transform: translateX(-28px); }
.reveal-r  { transform: translateX(28px); }
.reveal-scale { transform: scale(.94); }

/* Stagger a group of children by their index. */
.stagger > * { transition-delay: calc(var(--i, 0) * 70ms); }

/* ───────── Hover ───────── */
.lift {
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease-out;
}
.lift:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px -16px rgba(83,58,211,.35);
}

/* An underline that grows from the left rather than appearing at once. */
.link-grow { position: relative; }
.link-grow::after {
  content: ""; position: absolute; left: 0; bottom: -3px;
  width: 100%; height: 2px; background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform .25s ease-out;
}
.link-grow:hover::after { transform: scaleX(1); }

/* Buttons pick up a moving sheen on hover. */
.btn-shine { position: relative; overflow: hidden; }
.btn-shine::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 20%, rgba(255,255,255,.28) 50%, transparent 80%);
  transform: translateX(-120%);
  transition: transform .6s ease-out;
}
.btn-shine:hover::before { transform: translateX(120%); }

/* ───────── Marquee ───────── */
.marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.marquee > div { display: flex; width: max-content; animation: dd-marquee 32s linear infinite; }
.marquee:hover > div { animation-play-state: paused; }

/* ───────── Ground ───────── */
.grid-paper {
  background-image:
    linear-gradient(rgba(83,58,211,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(83,58,211,.05) 1px, transparent 1px);
  background-size: 32px 32px;
}
.blob {
  position: absolute; border-radius: 50%;
  filter: blur(70px); opacity: .5; pointer-events: none; z-index: 0;
}

/* ───────── Reduced motion ─────────
   Everything settles into its final state; nothing loops. */
@media (prefers-reduced-motion: reduce) {
  .anim-float, .anim-drift, .anim-spin,
  .marquee > div { animation: none !important; }
  .doodle-draw svg * { stroke-dashoffset: 0; animation: none !important; }
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .lift:hover { transform: none; }
  .btn-shine::before { display: none; }
}

/* The sticky nav only earns a shadow once there is content beneath it. */
[data-sticky-nav].is-scrolled { box-shadow: 0 6px 24px -12px rgba(15,23,42,.18); }

/* A doodle with no animation still parallaxes; the animated ones fold the
   same variables into their keyframes above. */
[data-parallax]:not([class*="anim-"]) { transform: translate(var(--px, 0px), var(--py, 0px)); }

/* The landing's header menu shares the dashboard's navigation face. */
.nav-menu { font-family: Lato, Inter, -apple-system, 'Segoe UI', sans-serif; }
.nav-menu a { transition: color .18s ease-out; }

/* ── Rotating brand lines (sign-in / sign-up panel) ──────────────────────
   Every pair sits in the same grid cell, so the block is as tall as the
   longest one and the list under it never jumps as the lines change. */
.auth-lines { display: grid; }
.auth-lines > .auth-line {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .6s ease-out, transform .6s ease-out;
  pointer-events: none;
}
.auth-lines > .auth-line.is-active { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .auth-lines > .auth-line { transition: none; }
}
