/* ============================================================
   motion.css · instrument motion. Elements draw, trace, and
   calibrate into place. Scroll-driven where supported, JS/IO
   fallback via .is-in. Everything degrades under reduced-motion.
   ============================================================ */

/* ---- Hero ------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: center;
  overflow: hidden;
  isolation: isolate;
}
.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: -1;
}
/* static fallback gradient · also the under-canvas bed */
.hero__bed {
  position: absolute;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(60% 50% at 38% 46%, var(--c-signal-faint), transparent 70%),
    radial-gradient(90% 70% at 80% 110%, color-mix(in oklch, var(--c-signal) 6%, transparent), transparent 60%),
    var(--c-bg);
}
.hero__content { position: relative; z-index: 1; }
.hero__wordmark {
  display: block;
  font-weight: 750;
  font-size: var(--t-display);
  letter-spacing: var(--ls-tighter);
  line-height: 0.95;
}
.hero__wordmark .signal { color: var(--c-signal); }
.hero__thesis {
  display: block;
  font-size: clamp(1.4rem, 1rem + 1.8vw, 2.4rem);
  font-weight: 500;
  color: var(--c-text);
  max-width: 20ch;
  margin-block: var(--s-5) var(--s-7);
  line-height: 1.2;
  letter-spacing: var(--ls-tight);
  text-shadow: 0 2px 30px var(--c-bg);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; }
.hero__scroll {
  position: absolute;
  bottom: var(--s-6); left: 0;
  display: inline-flex; align-items: center; gap: var(--s-3);
}
.hero__scroll .line {
  width: 40px; height: var(--hairline);
  background: linear-gradient(to right, var(--c-signal), transparent);
}

/* ---- Reveal primitives (IO toggles .is-in) ---------------- */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--dur-3) var(--ease-instrument),
              transform var(--dur-3) var(--ease-instrument);
  transition-delay: var(--reveal-delay, 0s);
}
.reveal.is-in { opacity: 1; transform: none; }

/* drawn hairline: scales from 0 → 1 on the x-axis */
.rule-draw {
  transform: scaleX(0);
  transition: transform var(--dur-draw) var(--ease-instrument);
}
.rule-draw.is-in { transform: scaleX(1); }

/* calibrate-in: a faint blur/letter-settle for headings */
.calibrate {
  opacity: 0;
  filter: blur(8px);
  transform: translateY(10px);
  transition: opacity var(--dur-3) var(--ease-instrument),
              filter var(--dur-3) var(--ease-instrument),
              transform var(--dur-3) var(--ease-instrument);
}
.calibrate.is-in { opacity: 1; filter: none; transform: none; }

/* count-up numbers settle */
.tabular { font-variant-numeric: tabular-nums; }

@keyframes pulse-ring {
  0%   { transform: scale(0.8); opacity: 0.9; }
  70%  { transform: scale(1.6); opacity: 0; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* ---- Scroll-driven enhancement where supported ------------ */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .sdr {
      opacity: 0;
      transform: translateY(28px);
      animation: sdr-in linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 32%;
    }
    @keyframes sdr-in {
      to { opacity: 1; transform: none; }
    }
  }
}

/* ---- Closing CTA: light band ------------------------------ */
.convert { position: relative; isolation: isolate; overflow: hidden; }
.convert__bed {
  position: absolute; inset: 0; z-index: -2;
  background:
    radial-gradient(70% 70% at 28% 120%, var(--c-signal-faint), transparent 70%),
    radial-gradient(50% 50% at 90% -10%, color-mix(in oklch, var(--c-signal) 7%, transparent), transparent 60%),
    var(--c-bg);
}
.convert__canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; }
.convert .shell { position: relative; z-index: 1; }

/* ---- Living light divider --------------------------------- */
.lightline {
  position: relative; height: 1px; border: 0; margin: 0;
  background: var(--c-line); overflow: hidden;
}
.lightline::after {
  content: ""; position: absolute; top: 0; left: 0; height: 1px; width: 36%;
  background: linear-gradient(to right, transparent, var(--c-signal), transparent);
  box-shadow: 0 0 8px var(--c-signal-glow);
  animation: line-travel 7s linear infinite;
}
@keyframes line-travel {
  from { transform: translateX(-120%); }
  to   { transform: translateX(380%); }
}

/* ---- The spine, more alive -------------------------------- */
.spine__progress { opacity: 0.7; box-shadow: 0 0 8px var(--c-signal-glow); }
.spine__rail { position: relative; overflow: hidden; }
.spine__rail::after {
  content: ""; position: absolute; left: 0; width: 1px; height: 16vh;
  background: linear-gradient(to bottom, transparent, var(--c-signal), transparent);
  box-shadow: 0 0 8px var(--c-signal-glow);
  animation: spine-pulse 8s linear infinite;
}
@keyframes spine-pulse {
  from { top: -16vh; }
  to   { top: 100vh; }
}

/* ---- Work imagery: cyan light sweep on reveal ------------- */
.work__media::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(115deg,
    transparent 34%, var(--c-signal-soft) 47%,
    rgba(228,250,255,0.55) 50%, var(--c-signal-soft) 53%, transparent 66%);
  transform: translateX(-130%);
  opacity: 0;
}
.work__media.is-in::before { animation: sweep 1.5s var(--ease-instrument) 0.25s; }
@keyframes sweep {
  0%   { transform: translateX(-130%); opacity: 0; }
  18%  { opacity: 1; }
  100% { transform: translateX(130%); opacity: 0; }
}

/* ---- Manifesto rule: a travelling glint ------------------- */
.rule-draw { position: relative; }
.rule-draw.is-in::after {
  content: ""; position: absolute; top: 0; left: 0; height: 100%; width: 28%;
  background: linear-gradient(to right, transparent, rgba(228,250,255,0.9), transparent);
  box-shadow: 0 0 8px var(--c-signal-glow);
  animation: line-travel 5s linear 1.4s infinite;
}

/* ---- Reduced motion: calm static everything --------------- */
@media (prefers-reduced-motion: reduce) {
  .lightline::after, .spine__rail::after, .rule-draw.is-in::after { animation: none; display: none; }
  .work__media.is-in::before { animation: none; }
  .convert__canvas { display: none; }
  .reveal, .calibrate, .sdr {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    animation: none !important;
  }
  .rule-draw { transform: scaleX(1) !important; transition: none !important; }
  .spine__node::after { animation: none; }
  .work__media img, .btn, .trustpilot { transition: none !important; }
}

/* ---- LCP: hero entrance via CSS (not JS reveal) ------------- */
/* The hero wordmark is the LCP element. Driving its entrance with a CSS
   animation that runs at load (instead of the JS IntersectionObserver
   reveal) lets it paint immediately, cutting LCP. JS-added .is-in later
   is a harmless no-op. Reduced-motion disables it (handled above). */
@media (prefers-reduced-motion: no-preference) {
  /* LCP element: paint the wordmark at full opacity immediately; the entrance
     is a transform-only settle, which does not delay the contentful paint. */
  .hero__wordmark.calibrate { opacity: 1; filter: none; animation: hero-cal 0.6s var(--ease-instrument) both; }
  .hero__thesis.reveal { animation: hero-rev 1s var(--ease-instrument) 0.2s both; }
}
@keyframes hero-cal {
  from { transform: translateY(10px); }
  to   { transform: none; }
}
@keyframes hero-rev {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}
