/* ==========================================================================
   Motion — scroll reveals, pointer-reactive surfaces, ambient texture.
   Depends on tokens.css.

   Nothing here is required to read the site: reveal states only apply under
   .has-js (set by an inline script before first paint), and every effect is
   switched off under prefers-reduced-motion.

   The reveal selector list below is mirrored in assets/js/motion.js —
   keep the two in sync when adding a new animated element.
   ========================================================================== */

/* ---- Cross-document page transitions ----

   Browsers without View Transitions simply navigate as normal. The nav and
   footer are given stable names so the chrome holds still while the page
   body cross-fades under it. */

@view-transition {
  navigation: auto;
}

::view-transition-old(page-body) {
  animation: page-exit var(--duration-fast) var(--ease-smooth) both;
}

::view-transition-new(page-body) {
  animation: page-enter var(--duration-reveal) var(--ease-out-expo) both;
}

@keyframes page-exit {
  to { opacity: 0; transform: translateY(calc(-1 * var(--space-px-10))); }
}

@keyframes page-enter {
  from { opacity: 0; transform: translateY(var(--space-px-20)); }
  to { opacity: 1; transform: translateY(0); }
}

main {
  view-transition-name: page-body;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(page-body),
  ::view-transition-new(page-body) {
    animation: none;
  }
}

/* ---- Ambient grain ---- */

body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* ---- Scroll progress ---- */

.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--progress-height);
  z-index: var(--z-progress);
  pointer-events: none;
  transform: scaleX(var(--scroll-progress, 0));
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--color-accent), var(--color-accent-secondary));
}

/* ---- Scroll reveal ---- */

/* The hidden state is wrapped in :where() so it contributes no specificity.
   Without it, a multi-class entry such as `.offer-hero .hero-badge` would
   outrank `.has-js .is-revealed` and the element would never become visible. */
.has-js :where(
  .telemetry,
  .section-title,
  .section-subtitle,
  .hero-badge,
  .hero h1,
  .hero-subtitle,
  .credibility-label,
  .credibility-logo,
  .stat-item,
  .icp-card,
  .product-card,
  .testimonial-card,
  .about-prose,
  .specialty-tag,
  .final-cta-title,
  .final-cta .btn
) {
  opacity: 0;
  transform: translate3d(0, var(--reveal-shift), 0);
  transition:
    opacity var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s),
    transform var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s);
}

.has-js .is-revealed {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Titles wipe open rather than sliding.

   This uses a mask, not clip-path: clip-path shrinks the element's
   intersection rectangle to nothing, so IntersectionObserver would never
   report the element as visible and it would stay hidden forever. Masking
   is paint-only and leaves intersection geometry intact. */
.has-js :where(.section-title, .hero h1, .final-cta-title) {
  mask-image: linear-gradient(to bottom, #000 0 0);
  mask-repeat: no-repeat;
  mask-position: 0 0;
  mask-size: 100% 0%;
  -webkit-mask-image: linear-gradient(to bottom, #000 0 0);
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: 0 0;
  -webkit-mask-size: 100% 0%;
  transition:
    opacity var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s),
    transform var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s),
    mask-size var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s),
    -webkit-mask-size var(--duration-reveal) var(--ease-out-expo) var(--reveal-delay, 0s);
}

.has-js :where(.section-title, .hero h1, .final-cta-title).is-revealed {
  mask-size: 100% 100%;
  -webkit-mask-size: 100% 100%;
}

/* ---- Pointer spotlight on cards ---- */

.has-spotlight {
  position: relative;
  isolation: isolate;
}

.has-spotlight::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-smooth);
  background: radial-gradient(
    var(--card-min) circle at var(--pointer-x, 50%) var(--pointer-y, 50%),
    var(--overlay-accent-15),
    transparent 60%
  );
}

.has-spotlight:hover::before {
  opacity: 1;
}

/* Gradient hairline that traces the card edge on hover. */
.has-spotlight::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: var(--space-px-1);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-smooth);
  background: radial-gradient(
    var(--card-min) circle at var(--pointer-x, 50%) var(--pointer-y, 50%),
    var(--color-accent-secondary),
    transparent 60%
  );
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
}

.has-spotlight:hover::after {
  opacity: 1;
}

/* ---- Magnetic buttons ---- */

.btn {
  transform: translate3d(var(--magnet-x, 0px), calc(var(--magnet-y, 0px) + var(--btn-lift, 0px)), 0);
  transition:
    transform var(--duration-quick) var(--ease-out-quint),
    background var(--duration-fast),
    border-color var(--duration-fast),
    box-shadow var(--duration-fast);
}

.btn-primary:hover {
  --btn-lift: var(--lift-sm);
}

.btn-lg.btn-primary:hover {
  --btn-lift: var(--lift-md);
}

/* ---- Sheen sweep across primary buttons ---- */

.btn-primary {
  position: relative;
  overflow: hidden;
}

.btn-primary::after {
  content: '';
  position: absolute;
  top: 0;
  left: -75%;
  width: 50%;
  height: 100%;
  pointer-events: none;
  transform: skewX(-20deg);
  background: linear-gradient(
    100deg,
    transparent,
    rgba(var(--color-white-rgb), 0.38),
    transparent
  );
  transition: left var(--duration-sheen) var(--ease-out-expo);
}

.btn-primary:hover::after {
  left: 130%;
}

/* ---- Nav polish ---- */

.site-nav {
  transform: translate3d(0, var(--nav-shift, 0), 0);
  transition:
    transform var(--duration-fast) var(--ease-out-quint),
    background var(--duration-fast) var(--ease-default),
    border-color var(--duration-fast) var(--ease-default);
}

.site-nav.is-hidden {
  --nav-shift: -100%;
}

.nav-link {
  position: relative;
}

.nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: calc(-1 * var(--space-3xs));
  width: 100%;
  height: var(--space-px-2);
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform var(--duration-fast) var(--ease-out-expo);
}

.nav-link:hover::after,
.nav-link.active::after {
  transform: scaleX(1);
  transform-origin: 0 50%;
}

/* Chrome is injected after load — fade it in rather than popping it. */
.has-js #nav-placeholder,
.has-js #footer-placeholder {
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-smooth);
}

.has-js #nav-placeholder.is-loaded,
.has-js #footer-placeholder.is-loaded {
  opacity: 1;
}

/* ---- Reticle cursor companion ---- */

.reticle {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--reticle-size);
  height: var(--reticle-size);
  z-index: var(--z-reticle);
  pointer-events: none;
  opacity: 0;
  color: var(--color-accent);
  transform: translate3d(var(--reticle-x, 0), var(--reticle-y, 0), 0) translate(-50%, -50%);
  transition:
    opacity var(--duration-fast) var(--ease-smooth),
    width var(--duration-fast) var(--ease-out-quint),
    height var(--duration-fast) var(--ease-out-quint);
}

.reticle.is-active {
  opacity: 0.5;
}

.reticle.is-locked {
  width: var(--reticle-size-locked);
  height: var(--reticle-size-locked);
  opacity: 0.9;
}

.reticle svg {
  width: 100%;
  height: 100%;
  animation: reticle-spin var(--duration-spin-mid) linear infinite;
}

.reticle.is-locked svg {
  animation-duration: var(--duration-spin-slow);
}

@keyframes reticle-spin {
  to { transform: rotate(1turn); }
}

/* ---- Hero optics ---- */

.hero-optics {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.hero-optics svg {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(140vh, 150vw);
  height: min(140vh, 150vw);
  transform: translate(-50%, -50%);
  color: var(--color-accent);
  opacity: 0.16;
}

.hero-optics-rings {
  transform-origin: center;
  animation: reticle-spin var(--duration-spin-slow) linear infinite;
}

.hero-optics-ticks {
  transform-origin: center;
  animation: reticle-spin var(--duration-spin-mid) linear infinite reverse;
}

.hero-scan {
  position: absolute;
  inset-inline: 0;
  height: var(--space-px-120);
  background: linear-gradient(
    to bottom,
    transparent,
    var(--overlay-accent-10),
    transparent
  );
  animation: hero-scan var(--duration-scan) var(--ease-smooth) infinite;
}

@keyframes hero-scan {
  0% { transform: translateY(-20vh); opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translateY(110vh); opacity: 0; }
}

/* Live indicator on the hero eyebrow. */
.hero-badge::before {
  content: '';
  display: inline-block;
  width: var(--space-px-5);
  height: var(--space-px-5);
  margin-right: var(--space-2xs);
  border-radius: var(--radius-full);
  background: currentColor;
  vertical-align: middle;
  animation: badge-pulse var(--duration-pulse) var(--ease-smooth) infinite;
}

@keyframes badge-pulse {
  0%, 100% { opacity: 0.35; transform: scale(0.85); }
  50% { opacity: 1; transform: scale(1); }
}

/* ---- Hero scroll cue ---- */

.hero-cue {
  position: absolute;
  bottom: var(--space-px-40);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
  color: var(--color-text-subtle);
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-wider);
}

.hero-cue-rail {
  position: relative;
  width: var(--space-px-1);
  height: var(--space-px-40);
  overflow: hidden;
  background: var(--overlay-white-10);
}

.hero-cue-rail::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  height: 50%;
  background: var(--color-accent);
  animation: cue-travel var(--duration-pulse) var(--ease-smooth) infinite;
}

@keyframes cue-travel {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(200%); }
}

@media (max-width: 768px) {
  .hero-cue {
    display: none;
  }
}

/* ==========================================================================
   Optics — the brand-native layer: rangefinder grid, target acquisition,
   tracer travel, and telemetry readouts.
   ========================================================================== */

/* ---- Rangefinder grid: hairlines with crosshair marks at intersections ---- */

.grid-field {
  position: relative;
  isolation: isolate;
}

.grid-field::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cpath d='M32 28v8M28 32h8' stroke='rgba(212,175,55,0.22)' stroke-width='1'/%3E%3C/svg%3E"),
    repeating-linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px var(--grid-cell)),
    repeating-linear-gradient(to bottom, var(--grid-line) 0 1px, transparent 1px var(--grid-cell));
  background-size: var(--grid-cell) var(--grid-cell), auto, auto;
  mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, #000 20%, transparent 78%);
}

/* ---- Telemetry labels ---- */

.telemetry {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  margin-bottom: var(--space-md);
  font-family: var(--font-family-mono);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--letter-spacing-wide);
  text-transform: uppercase;
  color: var(--color-accent);
}

.telemetry::before,
.telemetry::after {
  content: '';
  width: var(--space-px-30);
  height: var(--space-px-1);
  background: linear-gradient(90deg, transparent, var(--overlay-accent-40));
}

.telemetry::after {
  background: linear-gradient(90deg, var(--overlay-accent-40), transparent);
}

.telemetry-index {
  color: var(--color-text-subtle);
}

/* Tabular figures so counting numbers do not jitter. */
.stat-number {
  font-variant-numeric: tabular-nums;
}

/* ---- Scramble-to-lock text ---- */

.is-scrambling {
  color: var(--color-accent-secondary);
}

/* ---- Target acquisition brackets ---- */

.target-lock {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-reticle);
  pointer-events: none;
  opacity: 0;
  transform: translate3d(var(--lock-x, 0), var(--lock-y, 0), 0);
  width: var(--lock-w, 0px);
  height: var(--lock-h, 0px);
  transition:
    opacity var(--duration-lock) var(--ease-out-quint),
    transform var(--duration-lock) var(--ease-out-expo),
    width var(--duration-lock) var(--ease-out-expo),
    height var(--duration-lock) var(--ease-out-expo);
}

.target-lock.is-engaged {
  opacity: 1;
}

.target-lock span {
  position: absolute;
  width: var(--lock-bracket);
  height: var(--lock-bracket);
  border: var(--lock-weight) solid var(--color-accent);
  transition: inset var(--duration-lock) var(--ease-out-expo);
}

/* Brackets sit outside the target, then snap inward on engage. */
.target-lock span:nth-child(1) {
  top: calc(-1 * var(--lock-inset));
  left: calc(-1 * var(--lock-inset));
  border-right: none;
  border-bottom: none;
}

.target-lock span:nth-child(2) {
  top: calc(-1 * var(--lock-inset));
  right: calc(-1 * var(--lock-inset));
  border-left: none;
  border-bottom: none;
}

.target-lock span:nth-child(3) {
  bottom: calc(-1 * var(--lock-inset));
  left: calc(-1 * var(--lock-inset));
  border-right: none;
  border-top: none;
}

.target-lock span:nth-child(4) {
  bottom: calc(-1 * var(--lock-inset));
  right: calc(-1 * var(--lock-inset));
  border-left: none;
  border-top: none;
}

.target-lock.is-engaged span {
  animation: lock-snap var(--duration-lock) var(--ease-out-expo);
}

@keyframes lock-snap {
  from { margin: calc(-1 * var(--space-px-10)); opacity: 0; }
  to { margin: 0; opacity: 1; }
}

.target-lock-readout {
  position: absolute;
  bottom: calc(-1 * var(--space-lg));
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-style: normal;
  font-family: var(--font-family-mono);
  font-size: var(--font-size-xs);
  letter-spacing: var(--letter-spacing-wide);
  color: var(--color-accent);
  opacity: 0.85;
}

/* ---- Tracer travelling the method rail ---- */

.method-steps::after {
  content: '';
  position: absolute;
  top: calc(var(--space-lg) + var(--size-icon-lg) / 2);
  left: var(--space-2xl);
  width: var(--space-px-120);
  height: var(--space-px-2);
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, transparent, var(--color-accent-secondary), transparent);
  filter: blur(0.5px);
  animation: tracer-travel var(--duration-tracer) var(--ease-smooth) infinite;
}

@keyframes tracer-travel {
  0% { transform: translateX(0); opacity: 0; }
  8% { opacity: 1; }
  70% { opacity: 1; }
  80%, 100% {
    transform: translateX(calc(var(--content-max) - var(--space-px-120) - var(--space-2xl) * 2));
    opacity: 0;
  }
}

@media (max-width: 1024px) {
  .method-steps::after {
    display: none;
  }
}

/* ---- Reduced motion ---- */

@media (prefers-reduced-motion: reduce) {
  .has-js :where(
    .telemetry,
    .section-title,
    .section-subtitle,
    .hero-badge,
    .hero h1,
    .hero-subtitle,
    .credibility-label,
    .credibility-logo,
    .stat-item,
    .icp-card,
    .product-card,
    .testimonial-card,
    .about-prose,
    .specialty-tag,
    .final-cta-title,
    .final-cta .btn
  ) {
    opacity: 1;
    transform: none;
    mask-image: none;
    -webkit-mask-image: none;
    transition: none;
  }

  .has-js #nav-placeholder,
  .has-js #footer-placeholder {
    opacity: 1;
    transition: none;
  }

  .reticle,
  .scroll-progress,
  .hero-scan,
  .hero-cue {
    display: none;
  }

  .hero-optics-rings,
  .hero-optics-ticks,
  .hero-badge::before,
  .btn-primary::after {
    animation: none;
    transition: none;
  }
}
