html, body {
  margin: 0;
  padding: 0;
  background: #000;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

canvas {
  display: block;
}

#controls {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 100;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

#controls label {
  background: #333;
  color: #fff;
  border: 1px solid #666;
  padding: 6px 14px;
  font-size: 13px;
  border-radius: 4px;
  font-family: sans-serif;
}

#controls select,
#controls input[type="range"] {
  accent-color: #9bb7ff;
}

#controls select {
  background: #161616;
  color: #fff;
  border: 1px solid #5a5a5a;
  border-radius: 6px;
  height: 30px;
  padding: 0 10px;
}

#controls button {
  background: #161616;
  color: #fff;
  border: 1px solid #5a5a5a;
  border-radius: 6px;
  height: 30px;
  padding: 0 10px;
  font-family: sans-serif;
  font-size: 12px;
  cursor: pointer;
}

#controls button:hover {
  background: #23232e;
}

#controls button.active {
  background: rgba(129, 176, 147, 0.28);
  border-color: #81b093;
  color: #d9f2de;
}

#controls .hint {
  color: #ded3ef;
  background: rgba(28, 20, 38, 0.8);
  border: 1px solid #5e4c78;
  border-radius: 999px;
  padding: 4px 10px;
  font-family: sans-serif;
  font-size: 11px;
}

#selected-ring-info {
  color: #ffe8ba;
  border-color: #8d6a2c;
  background: rgba(50, 36, 12, 0.78);
  min-width: 180px;
  text-align: center;
}

#epicycle-slider {
  width: 190px;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

#epicycle-slider:focus {
  outline: none;
}

#epicycle-slider::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 999px;
  background: linear-gradient(90deg, #6f7f5a 0%, #d8c9a8 45%, #9a2d5f 100%);
  border: 1px solid #464646;
}


#epicycle-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border-radius: 50%;
  background: #f5f1e8;
  border: 2px solid #7f4a8f;
  box-shadow: 0 0 0 3px rgba(127, 74, 143, 0.2);
}


#epicycle-slider::-moz-range-track {
  height: 8px;
  border-radius: 999px;
  background: linear-gradient(90deg, #6f7f5a 0%, #d8c9a8 45%, #9a2d5f 100%);
  border: 1px solid #464646;
}


#epicycle-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #f5f1e8;
  border: 2px solid #7f4a8f;
  box-shadow: 0 0 0 3px rgba(127, 74, 143, 0.2);
}


#epicycle-slider-value {
  color: #f7f1e6;
  background: rgba(30, 18, 36, 0.82);
  border: 1px solid #6a4f76;
  border-radius: 999px;
  padding: 4px 10px;
  font-family: sans-serif;
  font-size: 12px;
  min-width: 44px;
  text-align: center;
}

#epicycle-slider-value::-webkit-outer-spin-button,
#epicycle-slider-value::-webkit-inner-spin-button {
  margin: 0;
}

#epicycle-slider-value:focus {
  outline: none;
  border-color: #9b78c2;
  box-shadow: 0 0 0 3px rgba(123, 86, 163, 0.22);
}



/* ---- "Read the write-up" corner button ---- */

#medium-link {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 13px;
  background: rgba(14, 11, 20, 0.93);
  border: 1px solid #6a8f77;
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
  color: #d9f2de;
  font-family: sans-serif;
  font-size: 12px;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}

#medium-link:hover {
  background: rgba(129, 176, 147, 0.28);
  border-color: #a3ccb2;
}

#medium-link .medium-glyph {
  font-size: 15px;
  line-height: 1;
  color: #c7a9ee;
}

#medium-link .medium-arrow {
  color: #9ec4ab;
}

@media (max-width: 620px) {
  #medium-link {
    font-size: 11px;
    padding: 7px 11px;
  }
}

/* ---- Guided tutorial ---- */

#tutorial {
  position: fixed;
  inset: 0;
  z-index: 300;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.18s ease;
}

#tutorial.is-active {
  opacity: 1;
  visibility: visible;
}

/* The huge spread shadow dims everything except the highlighted rect. */
#tutorial-spotlight {
  position: absolute;
  border: 1px solid rgba(200, 226, 210, 0.85);
  border-radius: 8px;
  box-shadow: 0 0 0 9999px rgba(4, 3, 8, 0.62), 0 0 18px rgba(160, 210, 180, 0.35);
  transition: opacity 0.18s ease;
  pointer-events: none;
}

#tutorial-popup {
  position: absolute;
  width: 302px;
  max-width: calc(100vw - 24px);
  padding: 12px 14px 10px;
  background: rgba(16, 13, 23, 0.97);
  border: 1px solid #6a5a86;
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
  font-family: sans-serif;
  color: #ded3ef;
  pointer-events: auto;
}

.tutorial-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}

.tutorial-counter {
  font-size: 10px;
  letter-spacing: 0.08em;
  color: #9a86bb;
  font-variant-numeric: tabular-nums;
}

#tutorial-popup h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: #f0e6ff;
}

#tutorial-body {
  margin: 0 0 11px;
  font-size: 11.5px;
  line-height: 1.55;
  color: #cbc2dd;
}

.tutorial-foot {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tutorial-dots {
  display: flex;
  gap: 4px;
  flex: 1;
  justify-content: center;
}

.tutorial-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #443a58;
}

.tutorial-dot.is-active {
  background: #a3ccb2;
}

.tutorial-nav {
  display: flex;
  gap: 6px;
}

#tutorial-popup button {
  font-family: inherit;
  cursor: pointer;
  border-radius: 5px;
}

.tutorial-skip {
  background: transparent;
  border: 0;
  padding: 4px 2px;
  font-size: 10.5px;
  color: #8f84a8;
  text-decoration: underline;
}

.tutorial-skip:hover {
  color: #cbc2dd;
}

.tutorial-back {
  background: #191622;
  border: 1px solid #4b3f63;
  color: #b9addb;
  font-size: 11px;
  padding: 4px 9px;
}

.tutorial-back:hover:not(:disabled) {
  background: #241f30;
}

.tutorial-back:disabled {
  opacity: 0.35;
  cursor: default;
}

.tutorial-next {
  background: rgba(129, 176, 147, 0.26);
  border: 1px solid #81b093;
  color: #dff4e4;
  font-size: 11px;
  font-weight: 600;
  padding: 4px 13px;
}

.tutorial-next:hover {
  background: rgba(129, 176, 147, 0.42);
}

#start-tutorial {
  border-color: #6a8f77;
  color: #d9f2de;
}

/* ---- Gesture hint: a looping hand miming the gesture for the step ---- */

.tutorial-gesture {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 11px;
  padding: 6px 8px;
  background: rgba(30, 24, 42, 0.6);
  border: 1px solid #3b3150;
  border-radius: 8px;
}

.tutorial-gesture[hidden] {
  display: none;
}

.gesture-stage {
  position: relative;
  flex: none;
  width: 80px;
  height: 58px;
  overflow: hidden;
}

.gesture-label {
  font-size: 10.5px;
  line-height: 1.4;
  color: #a89bc4;
}

/* The path the hand travels, drawn behind it. */
.gesture-track {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  border: 1px dashed rgba(163, 204, 178, 0.5);
  opacity: 0;
}

[data-gesture="drag-x"] .gesture-track {
  width: 46px;
  height: 0;
  border-width: 1px 0 0 0;
  opacity: 1;
}

[data-gesture="drag-y"] .gesture-track,
[data-gesture="scroll"] .gesture-track {
  width: 0;
  height: 28px;
  border-width: 0 0 0 1px;
  opacity: 1;
}

[data-gesture="rotate"] .gesture-track {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  opacity: 1;
}

[data-gesture="tap"] .gesture-track {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  opacity: 1;
}

/* Only the scroll hint shows arrowheads, so it reads differently from a drag. */
.gesture-arrow {
  position: absolute;
  left: 50%;
  margin-left: -4px;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  opacity: 0;
}

.gesture-arrow-up {
  top: 3px;
  border-bottom: 5px solid #a3ccb2;
}

.gesture-arrow-down {
  bottom: 3px;
  border-top: 5px solid #a3ccb2;
}

[data-gesture="scroll"] .gesture-arrow {
  animation: gesture-arrow-pulse 1.8s ease-in-out infinite;
}

[data-gesture="scroll"] .gesture-arrow-down {
  animation-delay: 0.9s;
}

/* The mini chart fills the bottom of the stage, so the zoom arrows stack in the
   top-left corner instead of above and below the hand. */
[data-gesture="bars-zoom"] .gesture-arrow {
  left: 16px;
  margin-left: 0;
  animation: gesture-arrow-pulse 2.6s ease-in-out infinite;
}

[data-gesture="bars-zoom"] .gesture-arrow-up {
  top: 3px;
  bottom: auto;
}

[data-gesture="bars-zoom"] .gesture-arrow-down {
  top: 13px;
  bottom: auto;
  animation-delay: 1.3s;
}

/* Anchored so the fingertip, not the box corner, sits at the animated point. */
.gesture-hand {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 34px;
  margin-left: -7px;
  margin-top: -4px;
}

.gesture-hand svg {
  display: block;
  width: 26px;
  height: 34px;
  fill: #e6dcf7;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.65));
}

/* Contact point: a steady dot while dragging, an expanding ring on a tap. */
.gesture-dot {
  position: absolute;
  left: 7px;
  top: 4px;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: rgba(163, 204, 178, 0.75);
  opacity: 0;
}

[data-gesture="drag-x"] .gesture-dot,
[data-gesture="drag-y"] .gesture-dot,
[data-gesture="rotate"] .gesture-dot,
[data-gesture="bars-range"] .gesture-dot,
[data-gesture="bars-height"] .gesture-dot {
  opacity: 1;
  background: rgba(163, 204, 178, 0.4);
}

[data-gesture="tap"] .gesture-hand {
  animation: gesture-tap 1.9s ease-in-out infinite;
}

[data-gesture="tap"] .gesture-dot {
  background: none;
  border: 2px solid rgba(163, 204, 178, 0.9);
  animation: gesture-ripple 1.9s ease-out infinite;
}

/* Clicking a bar echoes the chart's own warm hover ring rather than the mint. */
[data-gesture="bars-tap"] .gesture-dot {
  background: none;
  border: 2px solid rgba(255, 235, 170, 0.95);
}

/* Ping-ponging beats a one-way sweep: no blink, no snap back to the start. */
[data-gesture="drag-x"] .gesture-hand {
  animation: gesture-drag-x 1.5s ease-in-out infinite alternate;
}

[data-gesture="drag-y"] .gesture-hand {
  animation: gesture-drag-y 1.4s ease-in-out infinite alternate;
}

[data-gesture="scroll"] .gesture-hand {
  animation: gesture-scroll 1.8s ease-in-out infinite;
}

[data-gesture="rotate"] .gesture-hand {
  animation: gesture-orbit 3.4s linear infinite;
}

@keyframes gesture-tap {
  0%, 100% { transform: translate(0, -4px); }
  14% { transform: translate(0, 1px); }
  30% { transform: translate(0, -4px); }
}

@keyframes gesture-ripple {
  0%, 10% { transform: scale(0.4); opacity: 0; }
  16% { transform: scale(0.5); opacity: 0.9; }
  46% { transform: scale(1.9); opacity: 0; }
  100% { transform: scale(1.9); opacity: 0; }
}

@keyframes gesture-drag-x {
  from { transform: translate(-22px, 0); }
  to { transform: translate(22px, 0); }
}

@keyframes gesture-drag-y {
  from { transform: translate(0, -12px); }
  to { transform: translate(0, 12px); }
}

@keyframes gesture-scroll {
  0%, 100% { transform: translate(0, -8px); }
  50% { transform: translate(0, 8px); }
}

/* rotate(a) translate(r) rotate(-a) interpolates exactly along the circle, so the
   hand orbits the track without ever tipping over. */
@keyframes gesture-orbit {
  from { transform: rotate(0deg) translate(0, -14px) rotate(0deg); }
  to { transform: rotate(360deg) translate(0, -14px) rotate(-360deg); }
}

@keyframes gesture-arrow-pulse {
  0%, 100% { opacity: 0.15; }
  40% { opacity: 1; }
}

/* ---- Spectrum gestures: the hand acts on a miniature bar chart ---- */

/* The bar chart was the part people could not read, so its hints show what is
   being acted on and not just the hand doing it. Colours match the real chart:
   red bars, a warm hover ring, a mint range band. */
.gesture-bars {
  position: absolute;
  left: 50%;
  bottom: 5px;
  display: flex;
  align-items: flex-end;
  height: 24px;
  transform: translateX(-50%);
  opacity: 0;
}

[data-gesture^="bars-"] .gesture-bars {
  opacity: 1;
}

.gesture-bar {
  width: 3px;
  margin: 0 0.5px;
  border-radius: 1px 1px 0 0;
  background: #c94848;
  transform-origin: bottom;
}

/* A plausible spectrum silhouette: loud low terms trailing off into detail. */
.gesture-bar:nth-child(1) { height: 22px; }
.gesture-bar:nth-child(2) { height: 19px; }
.gesture-bar:nth-child(3) { height: 21px; }
.gesture-bar:nth-child(4) { height: 14px; }
.gesture-bar:nth-child(5) { height: 16px; }
.gesture-bar:nth-child(6) { height: 12px; }
.gesture-bar:nth-child(7) { height: 13px; }
.gesture-bar:nth-child(8) { height: 8px; }
.gesture-bar:nth-child(9) { height: 10px; }
.gesture-bar:nth-child(10) { height: 6px; }
.gesture-bar:nth-child(11) { height: 7px; }

/* The range band, matching the full-height mint rectangle the chart brushes out. */
.gesture-band {
  position: absolute;
  left: 0;
  top: -21px;
  bottom: -3px;
  width: 0;
  border: 1px solid rgba(190, 230, 205, 0.85);
  border-radius: 4px;
  background: rgba(190, 230, 205, 0.18);
  opacity: 0;
}

/* Zoom: the bars widen and push their neighbours off the edges of the stage,
   which is what scrolling over the real chart does to the visible window. */
[data-gesture="bars-zoom"] .gesture-bar {
  animation: gesture-bars-zoom 2.6s ease-in-out infinite alternate;
}

[data-gesture="bars-zoom"] .gesture-hand {
  animation: gesture-scroll 2.6s ease-in-out infinite;
}

/* Tap: the hand comes down on a bar, then lifts clear so the bar it just picked
   is actually visible. A hand resting on its target hides the whole point. */
[data-gesture="bars-tap"] .gesture-hand {
  margin-left: -19px;
  animation: gesture-bars-tap 2.2s ease-in-out infinite;
}

[data-gesture="bars-tap"] .gesture-dot {
  animation: gesture-bars-ripple 2.2s ease-out infinite;
}

[data-gesture="bars-tap"] .gesture-bar:nth-child(3) {
  animation: gesture-bar-select 2.2s ease-in-out infinite;
}

/* Range: the band grows out under the hand as it sweeps sideways. */
[data-gesture="bars-range"] .gesture-hand {
  animation: gesture-bars-sweep 1.6s ease-in-out infinite alternate;
}

[data-gesture="bars-range"] .gesture-band {
  opacity: 1;
  animation: gesture-band-grow 1.6s ease-in-out infinite alternate;
}

/* Height: a range is already selected on the left, and the hand drags clear of it
   -- the real chart scales the selection wherever on it you drag. */
[data-gesture="bars-height"] .gesture-hand {
  animation: gesture-drag-y 1.5s ease-in-out infinite alternate;
}

[data-gesture="bars-height"] .gesture-band {
  opacity: 1;
  left: -1px;
  width: 14px;
}

[data-gesture="bars-height"] .gesture-bar:nth-child(1),
[data-gesture="bars-height"] .gesture-bar:nth-child(2),
[data-gesture="bars-height"] .gesture-bar:nth-child(3) {
  animation: gesture-bar-lift 1.5s ease-in-out infinite alternate;
}

@keyframes gesture-bars-zoom {
  from { width: 3px; margin: 0 0.5px; }
  to { width: 8px; margin: 0 1.5px; }
}

@keyframes gesture-bars-tap {
  0%, 8% { transform: translate(12px, -24px); }
  20%, 30% { transform: translate(0, 1px); }
  45%, 100% { transform: translate(12px, -24px); }
}

@keyframes gesture-bars-ripple {
  0%, 18% { transform: scale(0.4); opacity: 0; }
  24% { transform: scale(0.5); opacity: 0.95; }
  52%, 100% { transform: scale(2.1); opacity: 0; }
}

@keyframes gesture-bar-select {
  0%, 20% { background: #c94848; box-shadow: none; }
  26%, 100% { background: #ffdc8c; box-shadow: 0 0 0 1px rgba(255, 235, 170, 0.95); }
}

@keyframes gesture-bars-sweep {
  from { transform: translate(-20px, 0); }
  to { transform: translate(18px, 0); }
}

@keyframes gesture-band-grow {
  from { width: 4px; }
  to { width: 40px; }
}

/* The hand starts high and ends low, so the bars run tall to short to match. */
@keyframes gesture-bar-lift {
  from { transform: scaleY(1.35); }
  to { transform: scaleY(0.5); }
}

@media (prefers-reduced-motion: reduce) {
  .gesture-hand,
  .gesture-dot,
  .gesture-arrow,
  .gesture-bar,
  .gesture-band {
    animation: none !important;
  }

  [data-gesture="scroll"] .gesture-arrow,
  [data-gesture="bars-zoom"] .gesture-arrow,
  [data-gesture="tap"] .gesture-dot,
  [data-gesture="bars-tap"] .gesture-dot {
    opacity: 0.9;
  }

  /* Without motion the hints still need to show their end state. */
  [data-gesture="bars-range"] .gesture-band {
    width: 40px;
  }

  [data-gesture="bars-height"] .gesture-band {
    width: 14px;
  }

  [data-gesture="bars-tap"] .gesture-bar:nth-child(3) {
    background: #ffdc8c;
    box-shadow: 0 0 0 1px rgba(255, 235, 170, 0.95);
  }
}

/* ---- Load-time invitation to the tutorial ---- */

/* Same spotlight trick as the tour: the huge spread dims the page, and the
   element's own box is the hole the Tutorial button shines through. */
#intro-highlight {
  position: fixed;
  z-index: 250;
  border-radius: 9px;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  box-shadow: 0 0 0 9999px rgba(4, 3, 8, 0.62), 0 0 0 0 rgba(163, 204, 178, 0.6);
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}

#intro-highlight.is-on {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.5s ease, visibility 0s;
  animation: intro-pulse 1.5s ease-out infinite;
}

@keyframes intro-pulse {
  0% { box-shadow: 0 0 0 9999px rgba(4, 3, 8, 0.62), 0 0 0 0 rgba(163, 204, 178, 0.6); }
  70% { box-shadow: 0 0 0 9999px rgba(4, 3, 8, 0.62), 0 0 0 15px rgba(163, 204, 178, 0); }
  100% { box-shadow: 0 0 0 9999px rgba(4, 3, 8, 0.62), 0 0 0 0 rgba(163, 204, 178, 0); }
}

#start-tutorial.is-inviting {
  background: rgba(129, 176, 147, 0.3);
  border-color: #a3ccb2;
  color: #e6f7ea;
}

@media (prefers-reduced-motion: reduce) {
  #intro-highlight.is-on {
    animation: none;
  }
}
