:root {
  --beat: 0.387097s;
  --bg: #0b0b12;
  --w: min(300px, 46vmin);
  --h: calc(var(--w) * 514 / 466);
}

.classic {
  --h: calc(var(--w) * 505 / 520);
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
}

body {
  position: fixed;
  inset: 0;
  container-type: size;
}

#v {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.stereo,
.tunnel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
  cursor: crosshair;
}

/* The stereogram canvas is the dot grid: stretched dot for dot, without smoothing. */
.stereo {
  image-rendering: pixelated;
}

.stereo-on .stereo,
.tunnel-on .tunnel {
  display: block;
}

.tunnel-on > :not(.tunnel, .tunnel-hint, .tunnel-combo, .tedit, .tedit-open, .snd, .boom, .warn),
.tunnel-on #v {
  display: none;
}

.stereo-on > :not(.stereo, .stereo-hint, .tedit, .tedit-open, .snd, .boom, .warn),
.stereo-on #v {
  display: none;
}

/* Two dots one pattern period apart: when the eyes fuse the picture, they become three. */
.stereo-hint {
  position: absolute;
  left: 50%;
  top: 18px;
  z-index: 5;
  width: min(90vw, 460px);
  translate: -50% 0;
  display: none;
  pointer-events: none;
  text-align: center;
  font: 600 15px/1.35 system-ui, sans-serif;
  color: #fff;
  text-shadow: 0 1px 3px #000, 0 0 8px #000;
  opacity: 0;
}

.stereo-hint i {
  position: absolute;
  top: 0;
  left: calc(50% - var(--pw, 100px) / 2 - 5px);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 2px #000;
}

.stereo-hint i + i {
  left: calc(50% + var(--pw, 100px) / 2 - 5px);
}

.stereo-hint p {
  margin: 22px 0 0;
  padding: 6px 12px;
  border-radius: 10px;
  background: #000a;
}

/* The two guide dots stay for the whole screen (they help to catch the figure again), the text fades. */
.stereo-on .stereo-hint.show {
  display: block;
  opacity: 1;
}

.stereo-on .stereo-hint.show i {
  opacity: 0.75;
}

.stereo-on .stereo-hint.show p {
  opacity: 0;
  animation: stereo-hint 14s ease forwards;
}

@keyframes stereo-hint {
  0% { opacity: 0; }
  5%, 80% { opacity: 1; }
  100% { opacity: 0; }
}

.junk {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.leds {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.word {
  position: absolute;
  white-space: nowrap;
  font: 900 1em/1 Impact, "Arial Black", "Helvetica Neue", sans-serif;
  letter-spacing: -0.02em;
  -webkit-text-stroke: 0.07em var(--c);
  paint-order: stroke fill;
  text-shadow: 0 0 0.25em var(--g), 0.07em 0.07em 0 #000;
  user-select: none;
}

.emo {
  position: absolute;
  left: 0;
  top: 0;
  line-height: 1;
  user-select: none;
  filter: drop-shadow(0 0 8px #fff8);
}

.snd {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 10;
  padding: 10px 16px;
  border: 2px solid #ff2bd6;
  border-radius: 10px;
  background: #0b0b12cc;
  color: #fff;
  font: 900 15px/1 Impact, "Arial Black", sans-serif;
  letter-spacing: 0.04em;
  box-shadow: 0 0 14px #ff2bd6, inset 0 0 10px #ff2bd655;
  cursor: pointer;
  animation: nag 1s steps(2) infinite;
}

.snd.on {
  border-color: #2bf0ff;
  box-shadow: 0 0 10px #2bf0ff;
  animation: none;
  opacity: 0.6;
}

.snd:hover, .snd:focus-visible {
  opacity: 1;
  outline: none;
}

@keyframes nag {
  50% { scale: 1.08; }
}

.ghosts {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.ghost {
  position: absolute;
  filter: drop-shadow(0 0 14px var(--glow));
}

.ghost img {
  display: block;
  width: 100%;
  height: auto;
  opacity: 0;
  user-select: none;
  -webkit-user-drag: none;
}

.parade {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.parade-track {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
}

.walker {
  position: absolute;
  left: 0;
  bottom: 0;
}

.walker img {
  display: block;
  height: 100%;
  width: auto;
  transform-origin: 50% 100%;
  user-select: none;
  -webkit-user-drag: none;
}

.x {
  position: absolute;
  left: 0;
  top: 0;
  animation: bx 11.3s linear infinite alternate;
}

/* Light frames are black where unlit: `screen` makes black a no-op over the visualizer.
   The lit copy runs the same animations on the same timeline, so both stay in lockstep. */
.l {
  mix-blend-mode: screen;
}

.l, .t {
  pointer-events: none;
}

.y {
  animation: by 7.7s linear infinite alternate;
}

/* Echoes: the same bounce, late by --d, so each copy sits where the sprite was a moment ago. */
.t, .t .y {
  animation-delay: var(--d);
}

.t {
  opacity: var(--o);
  mix-blend-mode: screen;
  filter: hue-rotate(var(--hr)) saturate(2.5);
}

.t1 { --d: .6s; --hr: 270deg; --o: .18; }
.t2 { --d: .42s; --hr: 180deg; --o: .26; }
.t3 { --d: .26s; --hr: 100deg; --o: .36; }
.t4 { --d: .12s; --hr: 40deg; --o: .5; }

.s {
  width: var(--w);
  height: var(--h);
  animation: jolt calc(var(--beat) * 2) steps(1) infinite, pump var(--beat) ease-out infinite, wob calc(var(--beat) * 4) ease-in-out infinite alternate;
}

.s img, .s canvas {
  display: block;
  width: 100%;
  height: 100%;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

@keyframes bx {
  from { transform: translateX(0); }
  to { transform: translateX(calc(100vw - var(--w))); transform: translateX(calc(100cqw - var(--w))); }
}

@keyframes by {
  from { transform: translateY(0); }
  to { transform: translateY(calc(100vh - var(--h))); transform: translateY(calc(100cqh - var(--h))); }
}

@keyframes jolt {
  0% { translate: 1px -1px; }
  5% { translate: -1px 1px; }
  10% { translate: 1px 0; }
  15%, 50% { translate: 0 0; }
  52% { translate: -1px 0; }
  57% { translate: 0 0; }
}

@keyframes pump {
  0% { scale: 1.1 0.9; }
  18% { scale: 0.95 1.07; }
  40%, 100% { scale: 1; }
}

@keyframes wob {
  from { rotate: -7deg; }
  to { rotate: 7deg; }
}

.boom {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 90;
  pointer-events: none;
}

.warn {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #000;
  color: #fff;
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  text-align: center;
  animation: warn-out 3s linear forwards;
}

.warn-box {
  max-width: 34em;
}

.warn-sign {
  font-size: 56px;
  line-height: 1;
  color: #ffd400;
}

.warn h1 {
  margin: 12px 0 10px;
  font-size: 22px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #ffd400;
}

.warn p {
  margin: 0 0 8px;
}

.warn-small {
  color: #bbb;
  font-size: 14px;
}

.warn-bar {
  height: 3px;
  margin-top: 20px;
  background: #ffd400;
  transform-origin: left;
  animation: warn-bar 2.6s linear forwards;
}

@keyframes warn-out {
  0%, 87% { opacity: 1; visibility: visible; }
  100% { opacity: 0; visibility: hidden; }
}

@keyframes warn-bar {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

/* Before the launch: only the scientist, centred and breathing; the red button on his console is the start. */
.idle {
  --w: min(440px, 78vmin, calc(78vh * 466 / 514));
  --h: calc(var(--w) * 514 / 466);
}

.classic .idle {
  --w: min(440px, 78vmin);
  --h: calc(var(--w) * 505 / 520);
}

.idle #v, .idle .ghosts, .idle .parade, .idle .junk, .idle .leds, .idle .t, .idle .snd {
  display: none;
}

.idle .x {
  animation: none;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
}

.idle .y {
  animation: none;
}

.idle .s {
  animation: breathe 3.2s ease-in-out infinite;
}

/* The light layer is opaque black where unlit: a filter there would draw its rectangle. */
.idle .x:not(.l) .s img, .idle .x:not(.l) .s canvas {
  animation: glow 3.2s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { scale: 1; }
  50% { scale: 1.035; }
}

@keyframes glow {
  0%, 100% { filter: brightness(1) drop-shadow(0 0 6px #b04dff33); }
  50% { filter: brightness(1.12) drop-shadow(0 0 20px #b04dff88); }
}

.s {
  position: relative;
}

.go {
  position: absolute;
  left: 48.7%;
  top: 55.6%;
  width: 22%;
  height: 13%;
  translate: -50% -50%;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* In the show the flying scientist is a target: three hits in a row stop the record and reset (v.js). */
body:not(.idle) .x:not(.t):not(.l) .s {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.classic .go {
  inset: 0;
  width: auto;
  height: auto;
  translate: none;
  border-radius: 0;
}

.idle .go::after {
  content: "";
  position: absolute;
  inset: -6%;
  border-radius: 50%;
  border: 3px solid #ff3b3b;
  box-shadow: 0 0 16px #ff3b3b, inset 0 0 12px #ff3b3b88;
  animation: go-ring 1.4s ease-out infinite;
  pointer-events: none;
}

.go:focus-visible {
  outline: 3px solid #b6ff3b;
  outline-offset: 4px;
}

.idle .go:hover::after {
  border-color: #ffd23b;
  box-shadow: 0 0 22px #ffd23b, inset 0 0 14px #ffd23b88;
}

@keyframes go-ring {
  0% { scale: 0.85; opacity: 1; }
  100% { scale: 1.5; opacity: 0; }
}

/* Visit counter under the scientist (built by v.js from /c.json): mechanical odometer, only before the launch. */
.idle .x {
  translate: -50% calc(-50% - var(--w) * 0.07);
}

.odo {
  position: absolute;
  left: 50%;
  top: 100%;
  translate: -50% 0;
  margin-top: calc(var(--w) * 0.015);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.22em;
  font-size: calc(var(--w) * 0.072);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease-out;
}

body:not(.idle) .odo {
  display: none;
}

.odo.on {
  opacity: 1;
}

.odo-win {
  display: flex;
  gap: 0.1em;
  padding: 0.14em;
  border-radius: 0.24em;
  border: 2px solid #b04dff;
  background: linear-gradient(#2c2536, #0c0a11);
  box-shadow: 0 0 0.5em #b04dff88, inset 0 0 0.3em #000;
}

.odo.hit .odo-win {
  animation: odo-hit 0.9s ease-out;
}

.reel {
  position: relative;
  width: 0.78em;
  height: 1.25em;
  overflow: hidden;
  border-radius: 0.1em;
  background: #f1ecdf;
}

.reel.gap {
  margin-left: 0.14em;
}

/* Cylinder shading + the hairline of a real counter window. */
.reel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(#000c, #0000 32%, #0000 68%, #000c),
    linear-gradient(#0000 49%, #0002 50%, #0000 51%);
}

.strip {
  display: block;
}

.strip i {
  display: block;
  height: 1.25em;
  font: 800 1em/1.25em "Courier New", ui-monospace, monospace;
  font-style: normal;
  text-align: center;
  color: #16121c;
}

@keyframes odo-hit {
  0% { box-shadow: 0 0 1.4em #b6ff3b, inset 0 0 0.3em #000; border-color: #b6ff3b; }
  100% { box-shadow: 0 0 0.5em #b04dff88, inset 0 0 0.3em #000; border-color: #b04dff; }
}

@media (prefers-reduced-motion: reduce) {
  .odo.hit .odo-win { animation: none; }
  .warn-bar { animation: none; }
  .t { display: none; }
  .x, .y, .s, .idle .s, .idle .go::after, .idle .x:not(.l) .s img, .idle .x:not(.l) .s canvas { animation: none; }
  .x { left: 50%; top: 50%; translate: -50% -50%; }
}

/* Tunnel: "tap along" hint (fades in, holds, fades out by 10 s) and the streak counter. */
.tunnel-hint,
.tunnel-combo {
  position: absolute;
  left: 50%;
  z-index: 5;
  translate: -50% 0;
  display: none;
  pointer-events: none;
  text-align: center;
  color: #fff;
  font-family: system-ui, sans-serif;
}

.tunnel-hint {
  top: 50%;
  width: max-content;
  max-width: 92vw;
  translate: -50% -50%;
  padding: 14px 22px;
  border-radius: 16px;
  background: #000c;
  box-shadow: 0 0 0 2px #fff;
  opacity: 0;
}

.tunnel-hint p {
  margin: 0;
  font: 800 clamp(20px, 4.4vw, 30px)/1.2 system-ui, sans-serif;
}

.tunnel-hint small {
  display: block;
  margin-top: 6px;
  font-size: 13px;
  opacity: 0.75;
}

.tunnel-on .tunnel-hint.show {
  display: block;
  animation: tunnel-hint 10s ease forwards;
}

@keyframes tunnel-hint {
  0% { opacity: 0; scale: 0.9; }
  6% { opacity: 1; scale: 1; }
  70% { opacity: 1; }
  100% { opacity: 0; }
}

.tunnel-combo {
  bottom: 12%;
  padding: 4px 16px;
  border-radius: 12px;
  background: #000;
  box-shadow: 0 0 0 2px #fff;
  font: 900 clamp(26px, 6vw, 44px)/1 system-ui, sans-serif;
}

.tunnel-on .tunnel-combo.show {
  display: block;
}

.tunnel-combo.bump {
  animation: tunnel-bump 0.25s ease-out;
}

/* 3–2–1, speed-ups and the victory: gold; a miss: red. */
.tunnel-combo.gold {
  color: #ffd23a;
  box-shadow: 0 0 0 2px #ffd23a, 0 0 24px #ffb30088;
  text-shadow: 0 0 12px #ffb300;
}

.tunnel-combo.miss {
  color: #ff5a5a;
  box-shadow: 0 0 0 2px #ff5a5a;
}

.tunnel-combo.win {
  bottom: 50%;
  translate: -50% 50%;
  padding: 10px 26px;
  font-size: clamp(34px, 9vw, 80px);
}

.tunnel-combo.win.bump {
  animation: tunnel-win 0.6s cubic-bezier(0.2, 1.6, 0.4, 1);
}

@keyframes tunnel-win {
  0% { scale: 0.3; rotate: -8deg; }
  100% { scale: 1; rotate: 0deg; }
}

@keyframes tunnel-bump {
  0% { scale: 1.35; }
  100% { scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tunnel-combo.bump { animation: none; }
}

/* Tunnel editor (?tunnel-master): a panel on the right, only on the tunnel screen. */
.tedit,
.tedit-open {
  display: none;
}

.tunnel-on .tedit:not([hidden]),
.stereo-on .tedit:not([hidden]) {
  position: fixed;
  top: 8px;
  right: 8px;
  bottom: 8px;
  z-index: 30;
  display: flex;
  flex-direction: column;
  width: min(340px, calc(100vw - 16px));
  border-radius: 14px;
  background: #111e;
  box-shadow: 0 0 0 1px #fff3, 0 8px 30px #000a;
  color: #eee;
  font: 13px/1.3 system-ui, sans-serif;
}

.tunnel-on .tedit-open:not([hidden]),
.stereo-on .tedit-open:not([hidden]) {
  position: fixed;
  top: 8px;
  right: 8px;
  z-index: 30;
  display: block;
}

.tedit button,
.tedit-open {
  padding: 5px 10px;
  border: 0;
  border-radius: 8px;
  background: #fff2;
  color: #fff;
  font: 12px/1.3 system-ui, sans-serif;
  cursor: pointer;
}

.tedit button:hover,
.tedit-open:hover {
  background: #fff3;
}

.tedit button:disabled {
  opacity: 0.4;
  cursor: default;
}

.tedit .tedit-main {
  background: #ffd23a;
  color: #000;
  font-weight: 700;
}

.tedit-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid #fff2;
}

.tedit-body {
  overflow-y: auto;
  padding: 4px 12px 12px;
}

.tedit h4 {
  margin: 14px 0 6px;
  color: #ffd23a;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tedit-row {
  display: block;
  margin: 6px 0;
}

.tedit-row input[type="range"] {
  width: 100%;
  margin: 2px 0 0;
  accent-color: #ffd23a;
}

.tedit-label {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.tedit-label output {
  color: #ffd23a;
  font-variant-numeric: tabular-nums;
}

.tedit-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}

.tedit-check input {
  width: 16px;
  height: 16px;
  accent-color: #ffd23a;
}

.tedit-name,
.tedit-paste {
  box-sizing: border-box;
  width: 100%;
  margin: 4px 0;
  padding: 6px 8px;
  border: 1px solid #fff3;
  border-radius: 8px;
  background: #0008;
  color: #fff;
  font: 13px/1.3 system-ui, sans-serif;
}

.tedit-paste {
  font: 11px/1.3 ui-monospace, monospace;
  resize: vertical;
}

.tedit-btns {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0;
}

.tedit-note {
  min-height: 16px;
  color: #8f8;
  font-size: 12px;
}

.tedit-item {
  margin: 6px 0;
  padding: 8px;
  border-radius: 10px;
  background: #fff1;
}

.tedit-item-name {
  font-weight: 700;
}

.tedit-item code {
  display: block;
  margin: 4px 0;
  overflow: hidden;
  color: #aaa;
  font-size: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tedit-off {
  opacity: 0.35;
}

.stereo-hint.nodots i {
  display: none;
}
