/* ─────────────────────────────────────────────────────────────
   Shared shell — the parts of the site that are the same wherever
   you are: the live backdrop, the WebGL stage, and the element
   cursor. Loaded by both the landing page and the assessment so
   they stay one environment rather than two lookalikes.

   Expects --ink and --ease to be defined by the page stylesheet.
   ───────────────────────────────────────────────────────────── */

/* ── Backdrop: blurred nature footage ──────────────────────── */

.backdrop { position: fixed; inset: 0; z-index: 0; overflow: hidden; }

/* Parked, not hidden: it only feeds the WebGL texture, but a display:none video
   stops decoding frames in several browsers. */
.bd-video {
  position: absolute; top: 0; left: 0;
  width: 2px; height: 2px;
  opacity: .001;
  pointer-events: none;
}

/* The wash, the cursor hole and the element tint all live in the backdrop
   fragment shader, so the whole backdrop is one textured quad. Only the grain
   is DOM. It retires with the backdrop (uPlain) on the video page. */
body.plain .bd-grain { display: none; }

.bd-grain {
  position: absolute; inset: 0;
  opacity: .5; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.055'/%3E%3C/svg%3E");
}

/* ── 3D stage ──────────────────────────────────────────────── */

#stage {
  position: fixed; inset: 0;
  z-index: 1;
  display: block;
  width: 100%; height: 100%;
}

/* ── Element cursor ────────────────────────────────────────
   Only hidden while the custom cursor is actually live, so the OS pointer comes
   straight back the moment it retires or the pointer leaves the window. */

body.cur-live, body.cur-live a, body.cur-live button { cursor: none; }
/* Text fields keep their I-beam — you cannot aim a caret with a 48px ring. */
body.cur-live input, body.cur-live textarea { cursor: text; }

.cursor {
  position: fixed; inset: 0; z-index: 90;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s var(--ease);
  --cur: var(--ink);
}
.cursor.on { opacity: 1; }
.cursor.off { opacity: 0 !important; }

.cur-ring {
  position: absolute; top: 0; left: 0;
  width: 48px; height: 48px;
  border: 1.5px solid var(--cur);
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--cur);
  /* No backdrop-filter here: it re-samples what's behind the ring every single
     frame while the cursor moves, which is a lot of work for an effect nobody
     can see at 48px. */
  background: rgba(255,255,255,.12);
  transition: width .4s var(--ease), height .4s var(--ease),
              border-color .5s var(--ease), color .5s var(--ease),
              background-color .4s var(--ease);
  will-change: transform;
}
.cur-dot {
  position: absolute; top: 0; left: 0;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--cur);
  transition: background-color .5s var(--ease), opacity .3s var(--ease);
  will-change: transform;
}

.cur-icon {
  display: grid; place-items: center; width: 22px; height: 22px;
  /* The glyph spins out, gets replaced, then spins back in. */
  transition: transform .17s var(--ease), opacity .17s var(--ease);
}
.cur-icon svg { width: 100%; height: 100%; display: block; }
.cur-icon.swap { transform: rotate(-70deg) scale(.4); opacity: 0; }

/* Element change: one soft expansion of the ring. */
@keyframes curPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--cur) 45%, transparent); }
  100% { box-shadow: 0 0 0 18px color-mix(in srgb, var(--cur) 0%, transparent); }
}
.cursor.pulse .cur-ring { animation: curPulse .52s var(--ease); }

/* Over links and buttons the ring opens up and the dot gets out of the way. */
.cursor.over .cur-ring { width: 64px; height: 64px; background: rgba(255,255,255,.2); }
.cursor.over .cur-dot { opacity: 0; }

@media (hover: none), (max-width: 760px) {
  .cursor { display: none; }
  body.cur-live, body.cur-live a, body.cur-live button { cursor: auto; }
}
