@charset "UTF-8";
/* ==========================================================================
   NEST — motion layer
   Six approved effects. Every one of them is inert under
   prefers-reduced-motion, and none of them are required for the page to work.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. PRELOADER
   The monogram wipes itself in, the blue diagonal overshoots the frame, then
   the curtain lifts on that same angle. Once per session.
   -------------------------------------------------------------------------- */
.preloader {
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: var(--slate-900);
}
.preloader[hidden] { display: none; }

.preloader__mark {
  position: relative;
  width: clamp(96px, 10.5vw, 156px);
  color: var(--white);
  clip-path: inset(100% 0 0 0);
  animation: plWipe .26s var(--ease-out) .02s forwards;
}
@keyframes plWipe { to { clip-path: inset(-10% 0 0 0); } }

/* drawn last, breaking out past the letter */
.preloader__slash {
  position: absolute;
  inset-block-end: -7%; inset-inline-start: -14%;
  width: 128%; height: 3px;
  background: linear-gradient(to left, var(--blue-300), var(--blue-600));
  transform: skewX(-38deg) scaleX(0);
  transform-origin: right;
  animation: plSlash .18s var(--ease-out) .22s forwards;
}
@keyframes plSlash { to { transform: skewX(-38deg) scaleX(1); } }

.preloader.is-done {
  animation: plLift .42s cubic-bezier(.76, 0, .24, 1) forwards;
  pointer-events: none;
}
@keyframes plLift { to { clip-path: inset(0 0 100% 0); } }
.preloader.is-done .preloader__mark { animation: plOut .24s var(--ease-out) forwards; }
@keyframes plOut { to { opacity: 0; transform: translateY(-14px); } }

html.is-loading, html.is-loading body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .preloader { display: none !important; }
  html.is-loading, html.is-loading body { overflow: auto; }
}

/* --------------------------------------------------------------------------
   2. CURSOR
   Pointer devices only. Rides alongside the native cursor rather than
   replacing it, so the pointer is never lost.
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  .cursor {
    position: fixed; inset-block-start: 0; inset-inline-start: 0;
    z-index: 9998;
    width: 34px; height: 34px;
    margin: -17px 0 0 -17px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .55);
    pointer-events: none;
    opacity: 0;
    display: grid; place-items: center;
    transition: width .32s var(--ease-out), height .32s var(--ease-out),
                margin .32s var(--ease-out), background .32s var(--ease-inout),
                box-shadow .32s var(--ease-inout), opacity .25s linear;
    will-change: transform;
  }
  .cursor.is-on { opacity: 1; }
  .cursor__label {
    font-family: var(--font-display);
    font-size: .74rem;
    letter-spacing: .06em;
    color: var(--white);
    opacity: 0;
    transform: scale(.7);
    transition: opacity .25s var(--ease-inout), transform .3s var(--ease-out);
    white-space: nowrap;
  }
  .cursor.is-active {
    width: 84px; height: 84px; margin: -42px 0 0 -42px;
    background: rgba(44, 90, 144, .82);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
  }
  .cursor.is-active .cursor__label { opacity: 1; transform: none; }
  /* on a bone band the ring inverts or it disappears */
  .cursor.is-light { box-shadow: inset 0 0 0 1px rgba(20, 23, 25, .45); }
  .cursor.is-light.is-active { background: rgba(19, 37, 58, .88); box-shadow: none; }
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor { display: none; }
}

/* --------------------------------------------------------------------------
   4. FILM GRAIN
   SVG turbulence, so nothing is downloaded. Above the background, below the
   content, and never intercepts a click.
   -------------------------------------------------------------------------- */
.section--ink, .strip, .footer, .hero { position: relative; }

.section--ink::after,
.strip::after,
.footer::after,
.hero::after {
  content: "";
  position: absolute; inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

/* content sits above the grain */
.section--ink > .wrap,
.footer > .wrap,
.panels { position: relative; z-index: 2; }
.hero__content, .hero__scroll, .hero__dots { z-index: 3; }

/* --------------------------------------------------------------------------
   7. CARD IMAGE PARALLAX
   The photo drifts slower than its frame, so it reads as sitting behind the
   card rather than pasted onto it. The hover scale rides on the same
   transform through a custom property, so the two never fight.
   -------------------------------------------------------------------------- */
.card__img {
  --py: 0px;
  --cs: 1.07;
  transform: translate3d(0, var(--py), 0) scale(var(--cs));
  transition: filter var(--dur-slow) var(--ease-inout);
  will-change: transform;
}
.card:hover .card__img { --cs: 1.13; filter: saturate(1.1); }

@media (prefers-reduced-motion: reduce) {
  .card__img { --py: 0px !important; }
}
