/* nspire loading screen — a 3-second bar of music that loops forever.
 *
 * Everything runs off one clock: the loop is one bar of 4/4 at 80 BPM, so
 *   --bar  = 3s      (the whole loop)
 *   --beat = 0.75s   (a quarter note: the ring kick, the logo thump)
 *   --step = 0.1875s (a sixteenth: one sequencer pad)
 * Every animation's period divides the bar, so nothing drifts out of phase
 * and the loop point is invisible. Pure CSS — no timers, no JS per frame. */

.nsl {
  --bar: 3s;
  --beat: 0.75s;
  --step: 0.1875s;
  --bg: #07070b;
  --ink: #eceef2;
  --dim: #3c3e43;
  --green: #5cf08a;
  --pink: #ff3d8b;
  --cyan: #3de0ff;

  position: fixed;
  inset: 0;
  z-index: 9999;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Barlow Condensed', 'Arial Narrow', Inter, system-ui, sans-serif;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  -webkit-font-smoothing: antialiased;
}

/* ── backdrop: a perspective grid floor rolling toward the viewer ───────── */
.nsl-floor {
  position: absolute;
  left: -50%;
  right: -50%;
  bottom: -10%;
  height: 60%;
  transform: perspective(420px) rotateX(62deg);
  transform-origin: 50% 100%;
  background-image:
    linear-gradient(to right, rgba(61, 224, 255, 0.32) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(61, 224, 255, 0.32) 1px, transparent 1px);
  background-size: 60px 60px;
  animation: nsl-floor var(--bar) linear infinite;
  -webkit-mask-image: linear-gradient(to top, #000 25%, transparent 100%);
  mask-image: linear-gradient(to top, #000 25%, transparent 100%);
}
@keyframes nsl-floor {
  to { background-position: 0 240px; }
}

/* soft coloured haze that breathes once per bar */
.nsl-haze {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(40% 35% at 30% 40%, rgba(255, 61, 139, 0.16), transparent 70%),
    radial-gradient(40% 35% at 70% 60%, rgba(61, 224, 255, 0.14), transparent 70%);
  animation: nsl-haze var(--bar) ease-in-out infinite;
}
@keyframes nsl-haze {
  0%, 100% { transform: rotate(0deg) scale(1); }
  50% { transform: rotate(8deg) scale(1.08); }
}

/* CRT scanlines + a sweeping light bar, once per bar */
.nsl-scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(to bottom, rgba(255, 255, 255, 0.025) 0 1px, transparent 1px 3px);
}
.nsl-scan::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 18%;
  background: linear-gradient(to bottom, transparent, rgba(92, 240, 138, 0.06), transparent);
  animation: nsl-sweep var(--bar) linear infinite;
}
@keyframes nsl-sweep {
  from { top: -20%; }
  to { top: 100%; }
}

/* ── centre stage ──────────────────────────────────────────────────────── */
.nsl-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(18px, 3vh, 32px);
}

.nsl-core {
  position: relative;
  width: min(62vmin, 440px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}

/* the ring of 64 meter bars — the whole ring kicks on every beat */
.nsl-ring {
  position: absolute;
  inset: 0;
  animation: nsl-kick var(--beat) cubic-bezier(0.2, 0.9, 0.3, 1) infinite,
             nsl-spin calc(var(--bar) * 4) linear infinite;
}
@keyframes nsl-kick {
  0% { scale: 1.06; }
  35% { scale: 0.985; }
  100% { scale: 1; }
}
@keyframes nsl-spin {
  to { rotate: 360deg; }
}

.nsl-bar {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3px;
  height: 17%;
  margin-left: -1.5px;
  transform-origin: 50% 0;
  transform: rotate(var(--a)) translateY(calc(min(62vmin, 440px) * 0.33));
}
.nsl-bar i {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(to bottom, var(--c1), var(--c2));
  transform-origin: 50% 0;
  animation: nsl-meter var(--beat) cubic-bezier(0.15, 0.8, 0.3, 1) infinite;
  animation-delay: var(--d);
  box-shadow: 0 0 8px var(--c1);
}
@keyframes nsl-meter {
  0% { transform: scaleY(var(--h)); opacity: 1; }
  55% { transform: scaleY(calc(var(--h) * 0.45)); opacity: 0.75; }
  100% { transform: scaleY(0.2); opacity: 0.55; }
}

/* shockwave that leaves the logo on the downbeat of every bar */
.nsl-shock {
  position: absolute;
  width: 46%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid var(--green);
  animation: nsl-shock var(--bar) cubic-bezier(0.1, 0.7, 0.3, 1) infinite;
}
.nsl-shock.two {
  border-color: var(--pink);
  animation-delay: calc(var(--beat) * 2);
}
@keyframes nsl-shock {
  0% { transform: scale(0.6); opacity: 0.9; }
  45% { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* spinning record in the middle, logo printed on the label */
.nsl-disc {
  position: absolute;
  width: 58%;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle, transparent 0 30%, rgba(255, 255, 255, 0.05) 30.5% 31%, transparent 31.5% 40%,
      rgba(255, 255, 255, 0.05) 40.5% 41%, transparent 41.5% 52%, rgba(255, 255, 255, 0.05) 52.5% 53%, transparent 53.5%),
    conic-gradient(from 0deg, #111118, #1c1c26 12%, #111118 25%, #1c1c26 37%, #111118 50%, #1c1c26 62%, #111118 75%, #1c1c26 87%, #111118);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 0 60px rgba(92, 240, 138, 0.15);
  animation: nsl-spin calc(var(--bar) / 2) linear infinite;
}

/* ── wordmark ─────────────────────────────────────────────────────────── */
.nsl-word {
  position: relative;
  display: flex;
  font-weight: 700;
  font-size: clamp(38px, 8.5vmin, 76px);
  letter-spacing: 0.02em;
  line-height: 1;
  text-transform: lowercase;
  animation: nsl-thump var(--beat) cubic-bezier(0.2, 0.9, 0.3, 1) infinite;
}
@keyframes nsl-thump {
  0% { transform: scale(1.07); }
  40%, 100% { transform: scale(1); }
}

/* each letter hops in turn, a sixteenth apart, like a melody walking up */
.nsl-word span {
  display: inline-block;
  color: var(--ink);
  animation: nsl-hop var(--bar) cubic-bezier(0.3, 1.6, 0.5, 1) infinite;
  animation-delay: calc(var(--i) * var(--step));
}
/* the letter flashes green as it leaves the ground, then settles back */
@keyframes nsl-hop {
  0% { transform: translateY(0); color: var(--ink); }
  6% { transform: translateY(-0.18em); color: var(--green); text-shadow: 0 0 18px rgba(92, 240, 138, 0.6); }
  14%, 100% { transform: translateY(0); color: var(--ink); text-shadow: none; }
}

/* chromatic glitch on the "one" of the bar */
.nsl-word::before,
.nsl-word::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  letter-spacing: inherit;
  mix-blend-mode: screen;
  opacity: 0;
  animation: nsl-glitch var(--bar) steps(1) infinite;
}
.nsl-word::before { color: var(--pink); }
.nsl-word::after { color: var(--cyan); animation-name: nsl-glitch-b; }
@keyframes nsl-glitch {
  0% { opacity: 0.85; transform: translate(-4px, 1px); clip-path: inset(10% 0 55% 0); }
  2% { opacity: 0.85; transform: translate(3px, -1px); clip-path: inset(60% 0 8% 0); }
  4%, 100% { opacity: 0; transform: none; clip-path: none; }
}
@keyframes nsl-glitch-b {
  0% { opacity: 0.85; transform: translate(4px, -1px); clip-path: inset(50% 0 20% 0); }
  2% { opacity: 0.85; transform: translate(-3px, 1px); clip-path: inset(5% 0 70% 0); }
  4%, 100% { opacity: 0; transform: none; clip-path: none; }
}

.nsl-tag {
  font-family: Inter, system-ui, sans-serif;
  font-size: clamp(9px, 1.4vmin, 12px);
  font-weight: 500;
  letter-spacing: 0.45em;
  text-transform: uppercase;
  color: #8a8c94;
  margin-top: 0.6em;
  margin-right: -0.45em; /* keep the tracked text optically centred */
}

/* ── 16-step sequencer with a playhead ─────────────────────────────────── */
.nsl-seq {
  position: relative;
  display: grid;
  grid-template-columns: repeat(16, 1fr);
  gap: clamp(3px, 0.6vmin, 6px);
  width: min(78vw, 420px);
}
.nsl-pad {
  aspect-ratio: 1;
  border-radius: 3px;
  background: #16171c;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
  animation: nsl-pad var(--bar) linear infinite;
  animation-delay: calc(var(--i) * var(--step));
}
/* every fourth pad is a downbeat — wider gap before it, like a real grid */
.nsl-pad:nth-child(4n + 1) { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12); }
.nsl-pad.on { background: #22242b; }
@keyframes nsl-pad {
  0% { background: var(--hit); box-shadow: 0 0 14px var(--hit); transform: scale(1.12); }
  5% { background: var(--hit); box-shadow: 0 0 6px var(--hit); transform: scale(1); }
  12%, 100% { background: var(--rest); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05); transform: scale(1); }
}
.nsl-head {
  position: absolute;
  top: -6px;
  bottom: -6px;
  width: 2px;
  left: 0;
  background: var(--ink);
  box-shadow: 0 0 10px var(--ink);
  border-radius: 1px;
  animation: nsl-head var(--bar) linear infinite;
}
@keyframes nsl-head {
  from { left: 0; }
  to { left: 100%; }
}

/* ── status line: one word per beat-and-a-third, cycling each bar ─────── */
.nsl-status {
  position: relative;
  height: 1.4em;
  width: 16em;
  overflow: hidden;
  font-family: Inter, system-ui, sans-serif;
  font-size: clamp(10px, 1.5vmin, 13px);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--green);
  text-align: center;
}
.nsl-status span {
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: nsl-word var(--bar) ease-in-out infinite;
  animation-delay: calc(var(--i) * var(--bar) / 3);
}
@keyframes nsl-word {
  0% { opacity: 0; transform: translateY(100%); }
  6%, 28% { opacity: 1; transform: translateY(0); }
  33.3%, 100% { opacity: 0; transform: translateY(-100%); }
}
.nsl-status span::after {
  content: '';
  display: inline-block;
  width: 0.5em;
  height: 1em;
  margin-left: 0.3em;
  vertical-align: -0.15em;
  background: currentColor;
  animation: nsl-blink var(--beat) steps(1) infinite;
}
@keyframes nsl-blink {
  50% { opacity: 0; }
}

/* ── reduced motion: keep it alive, drop the kicks, spins and glitches ── */
@media (prefers-reduced-motion: reduce) {
  .nsl-ring, .nsl-disc, .nsl-word, .nsl-word span, .nsl-floor, .nsl-haze, .nsl-scan::after { animation: none; }
  .nsl-word::before, .nsl-word::after, .nsl-shock { display: none; }
  .nsl-bar i { animation-duration: var(--bar); }
}

/* ── shared bits used by every design (see render.ts) ─────────────────── */
.nsl-center {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* a fixed label ("Loading Kitchen") instead of the cycling lines */
.nsl-status.static span {
  opacity: 1;
  animation: none;
}
/* wordmark + status pinned to the bottom, for designs that fill the screen */
.nsl-foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(28px, 8vh, 80px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  z-index: 3;
}
/* The four designs after "ring" (which lives in NspireLoader.css).
 * Same clock as ring: --bar 3s, --beat 0.75s, --step 0.1875s. */

/* ═══ 2. MATERIALIZE — the studio desk assembling out of dots ═══════════
 * The screenshot sits under a halftone mask: a grid of dots whose radius
 * grows until they touch, intersected with a sweep that crosses the screen.
 * So the desk arrives as dots, left to right, fills in solid, holds, and
 * breaks back up into dots at the end of the bar. */
@property --nsm-r {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}
@property --nsm-s {
  syntax: '<percentage>';
  inherits: true;
  initial-value: -30%;
}

.nsl--materialize {
  --cell: 12px;
  animation: nsm-clock var(--bar) linear infinite;
}
@keyframes nsm-clock {
  0% { --nsm-r: 0.6px; --nsm-s: -30%; }
  12% { --nsm-r: 1.2px; --nsm-s: -10%; }
  55% { --nsm-r: 9px; --nsm-s: 135%; }
  86% { --nsm-r: 9px; --nsm-s: 135%; }
  100% { --nsm-r: 0.6px; --nsm-s: 135%; }
}

/* empty dot grid, so there is something there before the picture arrives */
.nsm-grid {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(61, 224, 255, 0.28) 1.1px, transparent 1.6px);
  background-size: var(--cell) var(--cell);
  background-position: center;
}

.nsm-img {
  position: absolute;
  inset: 0;
  background: url('/loader/studio-desk.webp') center / cover no-repeat;
  animation: nsm-drift var(--bar) ease-out infinite;
  -webkit-mask-image:
    radial-gradient(circle, #000 var(--nsm-r), transparent calc(var(--nsm-r) + 0.6px)),
    linear-gradient(100deg, #000 calc(var(--nsm-s) - 25%), transparent var(--nsm-s));
  -webkit-mask-size: var(--cell) var(--cell), 100% 100%;
  -webkit-mask-position: center, 0 0;
  -webkit-mask-repeat: repeat, no-repeat;
  -webkit-mask-composite: source-in;
  mask-image:
    radial-gradient(circle, #000 var(--nsm-r), transparent calc(var(--nsm-r) + 0.6px)),
    linear-gradient(100deg, #000 calc(var(--nsm-s) - 25%), transparent var(--nsm-s));
  mask-size: var(--cell) var(--cell), 100% 100%;
  mask-position: center, 0 0;
  mask-repeat: repeat, no-repeat;
  -webkit-mask-composite: source-in, xor;
          mask-composite: intersect;
}
@keyframes nsm-drift {
  0% { transform: scale(1.08); filter: saturate(1.8) brightness(1.3); }
  55% { transform: scale(1.01); filter: saturate(1.15) brightness(1.05); }
  100% { transform: scale(1); filter: saturate(1) brightness(0.9); }
}

/* the leading edge of the sweep: a bright scan beam riding just ahead */
.nsm-beam {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 18vw;
  left: -20vw;
  background: linear-gradient(100deg, transparent, rgba(92, 240, 138, 0.18) 60%, rgba(236, 238, 242, 0.5) 72%, transparent 74%);
  mix-blend-mode: screen;
  animation: nsm-beam var(--bar) linear infinite;
}
@keyframes nsm-beam {
  0%, 10% { transform: translateX(0); opacity: 0; }
  14% { opacity: 1; }
  52% { opacity: 1; }
  56% { transform: translateX(140vw); opacity: 0; }
  100% { transform: translateX(140vw); opacity: 0; }
}

/* dark floor under the wordmark so it reads over the busy desk */
.nsm-vignette {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(7, 7, 11, 0.94) 0%, rgba(7, 7, 11, 0.6) 22%, transparent 45%),
    radial-gradient(120% 90% at 50% 45%, transparent 55%, rgba(7, 7, 11, 0.7));
}

/* ═══ Calm designs: wave, orbit, aurora ═════════════════════════════════
 * These move slowly and quietly on purpose — a loading screen should hold
 * the eye, not grab it. Each still loops on the 3s bar, but eases gently. */

/* a still wordmark: no hops, no glitch — just the letters */
.nsl-mark {
  display: flex;
  font-weight: 600;
  font-size: clamp(34px, 7vmin, 64px);
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--ink);
}
.nsl-mark span { display: inline-block; }

/* ── 3. WAVE ── */
.nsw-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(26px, 5vh, 48px);
  width: min(86vw, 760px);
}
.nsw-mark { display: flex; flex-direction: column; align-items: center; }
.nsw-svg { width: 100%; height: clamp(60px, 12vh, 110px); overflow: visible; }
.nsw-base { stroke: rgba(236, 238, 242, 0.08); stroke-width: 1; vector-effect: non-scaling-stroke; }
.nsw-line {
  fill: none;
  stroke: url(#nsw-g);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1;
  filter: drop-shadow(0 0 6px rgba(61, 224, 255, 0.35));
  animation: nsw-draw var(--bar) cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes nsw-draw {
  0% { stroke-dashoffset: 1; opacity: 0; }
  12% { opacity: 1; }
  60% { stroke-dashoffset: 0; opacity: 1; }
  85% { stroke-dashoffset: 0; opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}

/* ── 4. ORBIT ── */
.nso-stage {
  position: relative;
  width: min(56vmin, 380px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}
.nso-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(236, 238, 242, 0.08);
  animation: nsl-spin var(--bar) linear infinite;
}
/* a fading comet tail: a conic sweep masked down to the ring's hairline */
.nso-trail {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 65%, rgba(61, 224, 255, 0.5) 97%, #eceef2 100%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 1.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 1.5px));
}
.nso-dot {
  position: absolute;
  left: 50%;
  top: 0;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: #eceef2;
  box-shadow: 0 0 12px 2px rgba(61, 224, 255, 0.7);
}
.nso-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  animation: nso-breathe var(--bar) ease-in-out infinite;
}
@keyframes nso-breathe {
  0%, 100% { opacity: 0.82; }
  50% { opacity: 1; }
}

/* ── 5. AURORA ── */
.nsa-light {
  position: absolute;
  width: 70vmax;
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.35;
  animation: nsa-drift calc(var(--bar) * 2) ease-in-out infinite alternate;
}
.nsa-light.a { background: #1f6f8b; left: -20vmax; top: -30vmax; }
.nsa-light.b { background: #5a2a7a; right: -25vmax; bottom: -35vmax; animation-delay: calc(var(--bar) * -1); }
.nsa-light.c { background: #1d7a4e; left: 20vw; bottom: -45vmax; opacity: 0.22; animation-duration: calc(var(--bar) * 4); }
@keyframes nsa-drift {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(6vmax, 4vmax) scale(1.1); }
}
.nsa-grain {
  position: absolute;
  inset: 0;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.nsa-center {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.nsa-center .nsl-tag { margin-top: -6px; }
.nsa-progress {
  position: relative;
  width: min(48vw, 220px);
  height: 1px;
  overflow: hidden;
  background: rgba(236, 238, 242, 0.1);
}
.nsa-progress i {
  position: absolute;
  inset: 0;
  width: 40%;
  background: linear-gradient(90deg, transparent, #eceef2, transparent);
  animation: nsa-sweep var(--bar) cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes nsa-sweep {
  from { transform: translateX(-100%); }
  to { transform: translateX(250%); }
}

/* ── reduced motion ────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .nsl--materialize, .nsm-img, .nsm-beam, .nso-ring, .nsa-light { animation: none; }
  .nsl--materialize { --nsm-r: 9px; --nsm-s: 135%; }
}
