/* ─────────────────────────────────────────────────────────────────────────────
   Editor highlighting, celebration, and the motion that makes actions land.
   ───────────────────────────────────────────────────────────────────────────── */

/* ── Syntax-highlighted editor ─────────────────────────────────────────────────
   The textarea and the highlight layer must render text *identically* — same font,
   size, spacing, padding, wrapping and border — or the caret drifts away from the
   characters. Every shared property lives on both selectors for that reason. */

.editor-wrap { position: relative; margin-top: 10px; }

.editor-highlight,
.editor-wrap .editor-input {
  margin: 0;
  padding: 12px;
  border: 1px solid var(--neutral-border);
  border-radius: 12px;
  font-family: var(--font-mono, "Roboto Mono", ui-monospace, monospace);
  font-size: 13px;
  line-height: 20px;
  letter-spacing: normal;
  tab-size: 2;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: break-word;
  min-height: 96px;
}

.editor-highlight {
  position: absolute;
  inset: 0;
  overflow: auto;
  pointer-events: none;
  background: rgba(0, 0, 0, 0.35);
  color: var(--text-white);
}

.editor-wrap .editor-input {
  position: relative;
  display: block;
  width: 100%;
  resize: vertical;
  background: transparent;
  /* The text itself is invisible; the layer underneath supplies the colour. The caret is
     painted separately so it stays visible. */
  color: transparent;
  caret-color: var(--neon-lime);
  outline: none;
}
.editor-wrap .editor-input::selection { background: rgba(134, 93, 255, 0.4); }
.editor-wrap .editor-input:focus { border-color: var(--brand-purple); }
.editor-wrap .editor-input:focus + .editor-highlight,
.editor-wrap:focus-within .editor-highlight { border-color: var(--brand-purple); }
.editor-wrap .editor-input::placeholder {
  color: rgba(255, 255, 255, 0.25);
  font-family: Roboto, sans-serif;
}

.tok-key { color: #FF7BC8; font-weight: 700; }
.tok-fn { color: #7DD3FC; }
.tok-string { color: var(--neon-lime); }
.tok-num { color: #FFAB00; }
.tok-ident { color: #A5B4FC; }
.tok-op { color: rgba(255, 255, 255, 0.55); }
.tok-comment { color: rgba(255, 255, 255, 0.3); font-style: italic; }
.tok-word { color: var(--text-white); }

/* ── Celebration ───────────────────────────────────────────────────────────── */
.confetti-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 100;
}

/* Stars arrive one at a time; --i staggers them from the markup. */
.victory-stars .star {
  display: inline-block;
  transform: scale(0.3);
  opacity: 0;
  transition: transform 320ms cubic-bezier(0.2, 1.6, 0.4, 1), opacity 200ms ease-out;
}
.victory-stars .star:not(.on) { opacity: 1; transform: scale(1); }
.victory-stars .star.pop { opacity: 1; transform: scale(1); }

/* ── Wrong answer ──────────────────────────────────────────────────────────── */
@keyframes shake-x {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-7px); }
  30% { transform: translateX(6px); }
  45% { transform: translateX(-4px); }
  60% { transform: translateX(3px); }
  80% { transform: translateX(-2px); }
}
.shake { animation: shake-x 380ms cubic-bezier(0.36, 0.07, 0.19, 0.97); }

/* ── Results arrive rather than appear ─────────────────────────────────────── */
@keyframes row-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.result-card .data-table tbody tr {
  animation: row-in 260ms var(--ease-standard) both;
}
/* Only the first handful are staggered — a 500-row result must not take ten seconds. */
.result-card .data-table tbody tr:nth-child(1) { animation-delay: 20ms; }
.result-card .data-table tbody tr:nth-child(2) { animation-delay: 45ms; }
.result-card .data-table tbody tr:nth-child(3) { animation-delay: 70ms; }
.result-card .data-table tbody tr:nth-child(4) { animation-delay: 95ms; }
.result-card .data-table tbody tr:nth-child(5) { animation-delay: 120ms; }
.result-card .data-table tbody tr:nth-child(6) { animation-delay: 145ms; }
.result-card .data-table tbody tr:nth-child(7) { animation-delay: 170ms; }
.result-card .data-table tbody tr:nth-child(8) { animation-delay: 195ms; }

.result-card.tone-ok {
  animation: correct-glow 900ms ease-out;
}
@keyframes correct-glow {
  0% { box-shadow: 0 0 0 0 rgba(0, 200, 150, 0.5); }
  100% { box-shadow: 0 0 0 18px rgba(0, 200, 150, 0); }
}

/* ── Sound toggle in Profile ───────────────────────────────────────────────── */
.sound-row { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--neutral-border); }

@media (prefers-reduced-motion: reduce) {
  .victory-stars .star { transition: none; opacity: 1; transform: none; }
  .result-card .data-table tbody tr { animation: none; }
  .shake { animation: none; }
  .result-card.tone-ok { animation: none; }
}
