/* ==========================================================================
   Page-wide motion layer. Styles for motion.js. Every rule here is an
   enhancement: the page reads correctly without it, and hidden entrance
   states apply only once motion.js has marked the page ready.
   ========================================================================== */

@property --mo-glow {
  syntax: '<color>';
  inherits: true;
  initial-value: #ece6d8;
}

:root {
  --drift: 0px;
}

/* ------------------------------------------------------------------ scroll progress */

.mo-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  z-index: 60;
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* ------------------------------------------------------------------ cursor spotlight */

/* Sits at z-index -1: above the atmosphere (-2), beneath every section. */
.mo-glow {
  --mo-glow: #ece6d8;
  position: fixed;
  left: 0;
  top: 0;
  width: 760px;
  height: 760px;
  margin: -380px 0 0 -380px;
  border-radius: 50%;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--mo-glow) 20%, transparent),
    color-mix(in srgb, var(--mo-glow) 6%, transparent) 55%,
    transparent
  );
  transition: opacity 0.6s var(--ease), --mo-glow 0.6s var(--ease);
  will-change: transform;
}
.mo-glow.is-on { opacity: 1; }

/* ------------------------------------------------------------------ magnetic buttons */

/* motion.js writes --mx-x / --mx-y. Translate composes with each element's own transform. */
.btn,
.topbar nav a {
  --mag-x: var(--mx-x, 0px);
  --mag-y: var(--mx-y, 0px);
  translate: var(--mag-x, 0) var(--mag-y, 0);
}

/* ------------------------------------------------------------------ staggered entrances */

/* Hidden only under .js.motion-ready, which motion.js adds to <html>. */
.js.motion-ready .ix-group:not(.in) li {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
}
.js.motion-ready .ix-group.in li {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.7s var(--ease) calc(var(--i, 0) * 60ms),
    transform 0.7s var(--ease) calc(var(--i, 0) * 60ms);
}
.js.motion-ready .exhibit:not(.in) .features li {
  opacity: 0;
  transform: translate3d(-12px, 0, 0);
}
.js.motion-ready .exhibit.in .features li {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.7s var(--ease) calc(0.15s + var(--i, 0) * 70ms),
    transform 0.7s var(--ease) calc(0.15s + var(--i, 0) * 70ms);
}

/* ------------------------------------------------------------------ marquee */

.marquee {
  position: relative;
  overflow: hidden;
  padding: 26px 0;
  border-block: 1px solid var(--line);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
}
.marquee-track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: mo-marquee 40s linear infinite;
  will-change: translate;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes mo-marquee {
  from { translate: 0 0; }
  to { translate: -50% 0; }
}

.mq-item {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  flex: none;
  padding: 0 clamp(22px, 3.2vw, 44px);
  font: 400 clamp(30px, 4.4vw, 56px)/1 var(--serif);
  font-variation-settings: 'opsz' 96;
  letter-spacing: -0.02em;
  color: var(--text);
  white-space: nowrap;
  transform: skewX(var(--mq-skew, 0deg));
}
.mq-item[hidden] { display: none; }
.mq-item i {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow:
    0 0 0 4px color-mix(in srgb, var(--accent) 14%, transparent),
    0 0 18px 2px color-mix(in srgb, var(--accent) 70%, transparent);
}
.mq-item small {
  font: 500 11px/1 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #8a8c9f;
}

/* ------------------------------------------------------------------ atmosphere drift */

/* motion.js sets --drift (0 to 32px). The grid repeats every 32px, so the drift loops seamlessly. */
body::before {
  background-position:
    0 0, 0 0, 0 0,
    0 var(--drift, 0px),
    var(--drift, 0px) 0,
    0 0;
}

/* ------------------------------------------------------------------ plate breathing */

/* An inset accent edge that breathes on opacity only, so it costs no repaint. */
.plate-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent),
    inset 0 0 56px -10px var(--accent);
  opacity: 0.3;
  animation: mo-breathe 6s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * -1.4s);
}
@keyframes mo-breathe {
  0%, 100% { opacity: 0.22; }
  50% { opacity: 0.7; }
}

/* ------------------------------------------------------------------ logo burst */

.mo-burst {
  position: fixed;
  width: 0;
  height: 0;
  z-index: 70;
  pointer-events: none;
}
.mo-px {
  position: absolute;
  left: -3.5px;
  top: -3.5px;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  will-change: transform, opacity;
}

/* ------------------------------------------------------------------ reduced motion */

/* motion.js adds no entrance states or effects under reduced motion. These rules
   cover what CSS still animates, and turn the ticker into a static, wrapped row. */
@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
    width: 100%;
    flex-wrap: wrap;
    justify-content: center;
  }
  .plate-frame::after {
    animation: none;
    opacity: 0.4;
  }
  .mo-glow,
  .mo-burst {
    display: none;
  }
}
