/* ==========================================================================
   EDITORIAL INK — 4. Motion
   Keyframes, reveal states, preloader, custom cursor, reduced-motion.
   ========================================================================== */

/* ==========================================================================
   KEYFRAMES
   ========================================================================== */
@keyframes spin  { to { transform: rotate(360deg); } }
/* JS sets --slide-to to the exact width of one content copy. The -50%
   fallback keeps it animating if the script never runs. */
@keyframes slide { to { transform: translateX(var(--slide-to, -50%)); } }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0   rgba(255, 77, 46, .55); }
  70%  { box-shadow: 0 0 0 11px rgba(255, 77, 46, 0);  }
  100% { box-shadow: 0 0 0 0   rgba(255, 77, 46, 0);  }
}

/* Cue underline: grows from the left, then retracts to the right */
@keyframes sweep {
  0%   { transform: scaleX(0);   transform-origin: 0 50%; }
  45%  { transform: scaleX(1);   transform-origin: 0 50%; }
  55%  { transform: scaleX(1);   transform-origin: 100% 50%; }
  100% { transform: scaleX(0);   transform-origin: 100% 50%; }
}

/* The hero portrait arriving from a single pixel — carried over from the
   previous build, retuned for the new frame. */
@keyframes plate-pop {
  0%   { opacity: 0; transform: scale(.01) rotate(-18deg); }
  55%  { opacity: 1; transform: scale(1.06) rotate(3deg); }
  76%  {             transform: scale(.975) rotate(-1.4deg); }
  90%  {             transform: scale(1.012) rotate(.5deg); }
  100% { opacity: 1; transform: none; }
}

/* ==========================================================================
   PRELOADER
   ========================================================================== */
.preloader { display: none; }

.js .preloader {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 1300;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: var(--bg);
  color: var(--fg);
  transition: clip-path 1s var(--ease-out), opacity .4s .55s;
}
/* Curtain lifts away upward once loading completes */
.preloader.is-done {
  clip-path: inset(0 0 100% 0);
  pointer-events: none;
}

.preloader__inner { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.preloader__name { font-size: clamp(2rem, 6vw, 3.6rem); font-weight: 500; }
.preloader__role { color: var(--accent); }

.preloader__count {
  font-size: .8rem;
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
}

.preloader__bar {
  width: min(240px, 50vw);
  height: 1px;
  background: var(--rule);
  overflow: hidden;
}
.preloader__bar span {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .3s linear;
}

/* ==========================================================================
   CUSTOM CURSOR  (desktop, fine-pointer only — enabled by JS)
   ========================================================================== */
.cursor { display: none; }

@media (hover: hover) and (pointer: fine) {
  .cursor.is-enabled {
    display: block;
    position: fixed;
    top: 0; left: 0;
    z-index: 1050;
    pointer-events: none;
    mix-blend-mode: difference;
    opacity: 0;                 /* revealed on first pointer move */
    transition: opacity .3s;
  }

  .cursor__dot,
  .cursor__ring {
    position: absolute;
    top: 0; left: 0;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    will-change: transform;
  }

  .cursor__dot {
    width: 6px; height: 6px;
    background: #fff;
  }

  .cursor__ring {
    display: grid;
    place-items: center;
    width: 38px; height: 38px;
    border: 1px solid rgba(255, 255, 255, .55);
    transition: width .35s var(--ease-out), height .35s var(--ease-out),
                background .35s var(--ease-out), border-color .35s;
  }

  /* Grows into a labelled disc over anything carrying data-cursor */
  .cursor.is-active .cursor__ring {
    width: 88px; height: 88px;
    background: #fff;
    border-color: #fff;
  }
  .cursor.is-active .cursor__dot { opacity: 0; }

  .cursor__label {
    font-size: .6rem;
    color: #000;
    text-align: center;
    opacity: 0;
    transform: scale(.7);
    transition: opacity .3s, transform .35s var(--ease-out);
  }
  .cursor.is-active .cursor__label { opacity: 1; transform: none; }

  /* Hide the native pointer only where ours is doing the work */
  body.has-cursor,
  body.has-cursor a,
  body.has-cursor button { cursor: none; }
}

/* ==========================================================================
   SCROLL REVEALS
   ========================================================================== */

/* Masked line reveal — each .line clips its inner span, which slides up. */
/* overflow:hidden is what makes the mask, but it crops any glyph taller or
   deeper than the line box — descenders ('g' in "Growth strategy") and the
   italic display face both overflow a tight line-height. Pad both edges and
   pull the padding back with a negative margin, so the glyphs get clearance
   while the visual spacing stays exactly where it was. */
[data-lines] .line {
  display: block;
  overflow: hidden;
  padding: .14em 0 .2em;
  margin: -.14em 0 -.2em;
}
.js [data-lines] .line > span {
  display: inline-block;
  transform: translateY(120%);
  will-change: transform;
  transition: transform 1s var(--ease-out);
}
[data-lines].is-in .line > span { transform: none; }
[data-lines].is-in .line:nth-child(2) > span { transition-delay: .09s; }
[data-lines].is-in .line:nth-child(3) > span { transition-delay: .18s; }
[data-lines].is-in .line:nth-child(4) > span { transition-delay: .27s; }

/* Generic fade-and-rise, staggered via data-delay */
.js .reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .8s var(--ease-out), transform .8s var(--ease-out);
}
.reveal.is-in { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: .09s; }
.reveal[data-delay="2"] { transition-delay: .18s; }
.reveal[data-delay="3"] { transition-delay: .27s; }

/* Hero portrait pop. Sits on the wrapper so the plate and seal ride along,
   leaving the portrait's own transform free for hover. */
.js .hero__figure {
  animation: plate-pop 1.05s var(--ease-out) both;
}
/* Held until the preloader clears, then released by JS */
body:not(.is-ready) .hero__figure { animation-play-state: paused; }

/* Card tilt driven by pointer position (JS sets the custom properties) */
[data-tilt] .shot__btn {
  transform: perspective(900px)
             rotateX(var(--tilt-x, 0deg))
             rotateY(var(--tilt-y, 0deg));
}

/* ==========================================================================
   REDUCED MOTION
   Strip every decorative animation and land each element in its final state.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  .reveal { opacity: 1; transform: none; }
  [data-lines] .line > span { transform: none; }
  .hero__figure { animation: none; opacity: 1; transform: none; }

  .marquee__track,
  .foot__ribbon-track,
  .seal svg { animation: none; }

  .cursor { display: none !important; }
  body.has-cursor,
  body.has-cursor a,
  body.has-cursor button { cursor: auto; }

  .case { opacity: 1; }
  .preloader { display: none; }
}
