/* Make Impossible — FX motion layer
   3D transitional system layered on top of styles.css.
   Everything is gated behind html.fx, added by fx.js, so the site stays
   fully readable without JavaScript. Palette, type and radii are inherited. */

:root {
  --fx-ease: cubic-bezier(.22, .84, .2, 1);
  --fx-ease-heavy: cubic-bezier(.76, .02, .2, 1);
  --fx-depth: 1500px;
  --fx-stagger: 70ms;
}

/* ------------------------------------------------------------------ *
 * 1. Stage — every band gets its own 3D space
 * ------------------------------------------------------------------ */
.fx main > section,
.fx .site-footer {
  perspective: var(--fx-depth);
  perspective-origin: 50% 42%;
}

/* ------------------------------------------------------------------ *
 * 2. 3D entrance system (upgrades the flat .reveal from styles.css)
 * ------------------------------------------------------------------ */
.fx .reveal {
  opacity: 0;
  transform: translate3d(0, 44px, -110px) rotateX(8deg);
  transform-style: preserve-3d;
  filter: blur(6px);
  transition:
    opacity .82s var(--fx-ease) var(--reveal-delay, 0ms),
    transform 1.05s var(--fx-ease) var(--reveal-delay, 0ms),
    filter .82s var(--fx-ease) var(--reveal-delay, 0ms);
  will-change: transform, opacity, filter;
}
/* Entrance vocabularies, assigned per element family by fx.js.
   These must stay ABOVE the .is-visible rules: equal specificity means
   source order decides, and the resting state has to win. */
.fx .reveal.fx-card { transform: translate3d(0, 62px, -190px) rotateX(13deg) scale(.965); }
.fx .reveal.fx-flip { transform: translate3d(0, 26px, -70px) rotateX(-34deg); transform-origin: 50% 0%; }
.fx .reveal.fx-swing-l { transform: translate3d(-46px, 26px, -130px) rotateY(13deg); transform-origin: left center; }
.fx .reveal.fx-swing-r { transform: translate3d(46px, 26px, -130px) rotateY(-13deg); transform-origin: right center; }
.fx .reveal.fx-lift { transform: translate3d(0, 90px, -60px) rotateX(6deg); }
.fx .reveal[data-tilt] { transform: translate3d(0, 62px, -190px) rotateX(13deg) scale(.965); }

/* Resting state */
.fx .reveal.is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0) rotateX(0deg);
  filter: blur(0);
}

/* Tilt-enabled cards keep their pointer tilt once revealed */
.fx .reveal.is-visible[data-tilt] {
  transform:
    perspective(1400px)
    rotateX(var(--tilt-x))
    rotateY(var(--tilt-y))
    translateY(var(--tilt-lift));
}

/* ------------------------------------------------------------------ *
 * 3. Word and line cascade for display type
 * ------------------------------------------------------------------ */
/* The mask box must be larger than the word's advance width: these headings
   use negative letter-spacing and italics, so glyph ink overhangs the box on
   the right and below the baseline. Padding opens the clip, the matching
   negative margin keeps the margin box (and therefore the layout) identical. */
.fx-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding: .14em .18em .26em;
  margin: -.14em -.18em -.26em;
}
.fx-wi {
  display: inline-block;
  transform: translate3d(0, 106%, 0) rotateX(-62deg);
  transform-origin: 50% 0%;
  opacity: 0;
  transition:
    transform .95s var(--fx-ease) var(--fx-d, 0ms),
    opacity .55s linear var(--fx-d, 0ms);
  will-change: transform, opacity;
}
.fx .is-visible .fx-wi,
.fx .fx-lit .fx-wi,
.fx .fx-w.is-lit .fx-wi { transform: translate3d(0, 0, 0) rotateX(0deg); opacity: 1; }

/* Hero headline: the accent block lands last and settles into its tilt */
.fx .hero-title-accent {
  transform: rotate(-1.5deg) scaleX(var(--fx-accent-scale, 1));
  transform-origin: left center;
  transition: transform 1.1s var(--fx-ease) 260ms;
}
.fx .hero-copy:not(.is-visible) .hero-title-accent { --fx-accent-scale: 0; }

/* ------------------------------------------------------------------ *
 * 4. Mega copy — scroll scrubbed word by word
 * ------------------------------------------------------------------ */
.fx .mega-copy { perspective: 900px; }
.fx .mega-copy .fx-wi {
  transform: translate3d(0, 92%, 0) rotateX(-58deg);
  opacity: .12;
  transition:
    transform .72s var(--fx-ease),
    opacity .42s linear,
    filter .5s ease;
  filter: blur(3px);
}
.fx .mega-copy .fx-w.is-lit .fx-wi {
  transform: translate3d(0, 0, 0) rotateX(0deg);
  opacity: 1;
  filter: blur(0);
}
/* The highlighted phrase gets an underline that draws with the scrub */
.fx .mega-copy span > .fx-w { position: relative; }
.fx .mega-copy span > .fx-w::after {
  content: "";
  position: absolute;
  left: .18em;
  right: .18em;
  bottom: .14em;
  height: .055em;
  background: var(--violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .7s var(--fx-ease);
}
.fx .mega-copy span > .fx-w.is-lit::after { transform: scaleX(1); }

/* ------------------------------------------------------------------ *
 * 5. Hero ribbon — scroll reactive marquee inside a 3D flipping band
 * ------------------------------------------------------------------ */
.fx .hero-ribbon {
  background: none;
  border-block: 0;
  overflow: visible;
  perspective: 1100px;
  perspective-origin: 50% 50%;
}
.fx .ribbon-flip {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(calc(var(--rb-turn, 0) * -180deg));
  transition: transform 1.15s var(--fx-ease-heavy);
  will-change: transform;
}
.fx .ribbon-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: stretch;
  overflow: hidden;
  color: var(--ink);
  background: var(--acid);
  border-block: 2px solid var(--ink);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform: translateZ(var(--rb-half, 41px));
}
.fx .ribbon-face-b { transform: rotateX(180deg) translateZ(var(--rb-half, 41px)); }
.fx .ribbon-face::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--rb-sheen, 0);
  background: linear-gradient(100deg, transparent 34%, rgba(255, 255, 255, .65), transparent 66%);
  transition: opacity .45s ease;
}
.fx .ribbon-track {
  animation: none;
  transform: translate3d(var(--rb-x, 0), 0, 0) skewX(var(--rb-skew, 0deg));
  will-change: transform;
}
.fx .ribbon-track i { transition: transform .5s var(--fx-ease); }
.fx .hero-ribbon.is-turning .ribbon-track i { transform: rotate(180deg) scale(1.25); }

/* ------------------------------------------------------------------ *
 * 6. Scroll linked depth for section furniture
 * ------------------------------------------------------------------ */
.fx [data-fx-float] {
  transform: translate3d(0, calc(var(--fx-float, 0) * 1px), calc(var(--fx-float, 0) * 0.9px));
  will-change: transform;
}
/* Card families gain a real hover depth instead of a flat lift */
.fx .method-card,
.fx .detail-card,
.fx .service-step,
.fx .use-card,
.fx .related-service,
.fx .entity-card { transform-style: preserve-3d; }
/* Hover depth is handled in styles.css by moving each card's contents, not
   the card itself: under a perspective ancestor any transform on the box
   also shifts it sideways, so it escapes the pointer and flickers.
   Only the surface treatment lives here. */
.fx .related-service:hover { box-shadow: 0 20px 45px rgba(10, 10, 13, .13); }
.fx .service-row { transition: padding .35s var(--ease), background .35s ease; }

/* ------------------------------------------------------------------ *
 * 7. Section seam — a thin acid rule that draws as a band arrives
 * ------------------------------------------------------------------ */
.fx .fx-seam {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--acid), var(--violet) 55%, transparent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.1s var(--fx-ease);
  pointer-events: none;
  z-index: 3;
}
.fx .fx-seam.is-visible { transform: scaleX(1); }

/* ------------------------------------------------------------------ *
 * 8. Mobile tuning — same choreography, shorter travel, no blur cost
 * ------------------------------------------------------------------ */
@media (max-width: 900px) {
  .fx main > section, .fx .site-footer { perspective: 1000px; }
  .fx .reveal { transform: translate3d(0, 30px, -60px) rotateX(6deg); filter: none; }
  .fx .reveal.fx-card,
  .fx .reveal[data-tilt] { transform: translate3d(0, 38px, -90px) rotateX(9deg) scale(.98); }
  .fx .reveal.fx-swing-l { transform: translate3d(-22px, 20px, -70px) rotateY(9deg); }
  .fx .reveal.fx-swing-r { transform: translate3d(22px, 20px, -70px) rotateY(-9deg); }
  .fx .reveal.fx-flip { transform: translate3d(0, 20px, -40px) rotateX(-24deg); }
  .fx .reveal.fx-lift { transform: translate3d(0, 44px, -40px) rotateX(5deg); }
  /* Resting state repeated here so it still wins over the variants above */
  .fx .reveal.is-visible { transform: translate3d(0, 0, 0) rotateX(0deg); filter: none; }
  .fx .reveal.is-visible[data-tilt] {
    transform: perspective(1400px) rotateX(var(--tilt-x)) rotateY(var(--tilt-y)) translateY(var(--tilt-lift));
  }
  .fx .mega-copy .fx-wi { filter: none; }
  .fx .service-row:hover { transform: none; }
}

/* ------------------------------------------------------------------ *
 * 9. Reduced motion — hold everything still
 * ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .fx .reveal,
  .fx .reveal.fx-card,
  .fx .reveal.fx-flip,
  .fx .reveal.fx-swing-l,
  .fx .reveal.fx-swing-r,
  .fx .reveal.fx-lift,
  .fx .reveal[data-tilt] { opacity: 1; transform: none; filter: none; }
  .fx .fx-wi { opacity: 1; transform: none; filter: none; }
  .fx .mega-copy span > .fx-w::after { transform: scaleX(1); }
  .fx .hero-title-accent { transform: rotate(-1.5deg); }
  .fx .ribbon-flip { transition: none; }
  .fx .ribbon-track { transform: none; }
  .fx .fx-seam { transform: scaleX(1); }
  .fx [data-fx-float] { transform: none; }
}
