/* Feedback animations. Transform and opacity only. Under prefers-reduced-motion
   every one of them collapses to a plain fade at the bottom of this file. */

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

/* the longer name must stay on one line in every era font, next to two header buttons */
.wordmark { white-space: nowrap; min-width: 0; font-size: clamp(1rem, 4.5vw, 1.35rem); }
.wordmark span { overflow: hidden; text-overflow: ellipsis; }
.bar-right { flex-shrink: 0; }
/* flips, wobbles and confetti must never create a sideways scroll */
html, body { overflow-x: clip; }

/* ---- the dial ---- */
.dial { perspective: 600px; }
.flap.clack { animation: flap-clack 0.42s cubic-bezier(0.3, 1.5, 0.5, 1) var(--d, 0ms) both; transform-origin: 50% 50%; }
@keyframes flap-clack {
  0% { transform: rotateX(0); }
  35% { transform: rotateX(-72deg) scaleY(0.96); }
  70% { transform: rotateX(12deg); }
  100% { transform: rotateX(0); }
}

/* ---- answer card lands ---- */
.reveal-card.land { animation: card-land 0.42s cubic-bezier(0.2, 1.3, 0.4, 1) both; }
@keyframes card-land {
  from { opacity: 0; transform: translateY(28px) scale(0.97); }
  to { opacity: 1; transform: none; }
}
.reveal-card.wobble { animation: card-land 0.3s ease-out both, card-wobble 0.5s ease-in-out 0.25s both; }
@keyframes card-wobble {
  0%, 100% { transform: none; }
  20% { transform: translateX(-7px) rotate(-0.6deg); }
  45% { transform: translateX(6px) rotate(0.5deg); }
  70% { transform: translateX(-3px); }
}

/* ---- rank badge stamps in ---- */
.stamp .rank {
  display: inline-grid; place-items: center;
  min-width: 2.4em; padding: 0.1em 0.35em;
  border: 2px solid currentColor; border-radius: 0.35em;
  font-variant-numeric: tabular-nums;
}
.stamp.stamp-in { animation: stamp-in 0.38s cubic-bezier(0.2, 1.6, 0.4, 1) 0.18s both; transform-origin: 15% 50%; }
@keyframes stamp-in {
  0% { opacity: 0; transform: scale(1.7) rotate(-8deg); }
  70% { opacity: 1; transform: scale(0.94) rotate(1deg); }
  100% { opacity: 1; transform: none; }
}
.stamp.exact .rank { color: var(--accent); }

/* ---- points and the deep-cut bonus ---- */
.points .num { display: inline-block; min-width: 3.2ch; }
.points .bonus { display: inline-block; margin-left: 6px; }
.points .bonus.pop { animation: bonus-pop 0.45s cubic-bezier(0.2, 1.8, 0.4, 1) both; }
@keyframes bonus-pop {
  0% { opacity: 0; transform: translateY(6px) scale(0.4); }
  60% { opacity: 1; transform: scale(1.18); }
  100% { opacity: 1; transform: none; }
}
.points .bonus.waiting { opacity: 0; }

/* ---- the real top 5 cascades in ---- */
.toplist.cascade li { animation: row-in 0.34s ease-out both; animation-delay: calc(var(--i, 0) * 45ms + 420ms); }
@keyframes row-in {
  from { opacity: 0; transform: translateX(-14px); }
  to { opacity: 1; transform: none; }
}
.toplist.cascade li.mine { animation: row-in 0.34s ease-out both, mine-glow 1.2s ease-out both; animation-delay: calc(var(--i, 0) * 45ms + 420ms), calc(var(--i, 0) * 45ms + 700ms); }
@keyframes mine-glow {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 10px transparent; }
}

/* ---- end of day ---- */
.tally { display: grid; justify-items: center; gap: 2px; margin: 0 0 14px; color: var(--on-bg); text-align: center; }
.tally-acc { margin: 0; font: 900 clamp(3.4rem, 18vw, 4.6rem)/0.9 "Big Shoulders Display", "Arial Narrow", sans-serif; color: var(--accent); font-variant-numeric: tabular-nums; }
.tally-acc small { font-size: 0.45em; color: var(--on-bg); margin-left: 4px; }
.tally-sub { margin: 4px 0 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.tally-verdict { margin: 0; font-weight: 700; }
.tally-verdict.show { animation: fade-up 0.4s ease-out both; }
.celebrate {
  margin: 8px 0 0; padding: 6px 14px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink); font-weight: 800;
}
.celebrate.show { animation: stamp-in 0.5s cubic-bezier(0.2, 1.6, 0.4, 1) both; }
@keyframes fade-up { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* the share card prints out like a ticket */
.card-img.print { animation: ticket-print 0.75s cubic-bezier(0.3, 1, 0.4, 1) 0.2s both; transform-origin: 50% 0; }
@keyframes ticket-print {
  from { opacity: 0; transform: translateY(-18px) scaleY(0.6); }
  to { opacity: 1; transform: none; }
}

/* streak ticks up */
.streak.tick { animation: streak-tick 0.6s cubic-bezier(0.2, 1.6, 0.4, 1) both; display: inline-block; }
@keyframes streak-tick {
  0% { transform: translateY(0); }
  35% { transform: translateY(-9px) scale(1.25); }
  100% { transform: none; }
}

/* ---- small touches ---- */
.btn { transition: transform 0.09s ease, filter 0.15s ease; }
.btn:active { transform: scale(0.97); }
.btn.primary:hover { filter: brightness(1.06); }
.icon-btn { transition: transform 0.09s ease; }
.icon-btn:active { transform: scale(0.92); }
.icon-btn.sound svg { width: 18px; height: 18px; }
.icon-btn.sound { display: inline-grid; place-items: center; padding: 0; }
.icon-btn.sound[data-level="on"] .snd-off,
.icon-btn.sound[data-level="low"] .snd-off, .icon-btn.sound[data-level="low"] .snd-w2,
.icon-btn.sound[data-level="off"] .snd-w1, .icon-btn.sound[data-level="off"] .snd-w2 { display: none; }
.icon-btn.sound[data-level="off"] { opacity: 0.7; }
.sound-hint { margin: 10px auto 0; max-width: 34ch; text-align: center; font-size: 0.88rem; font-weight: 600; color: var(--on-bg); opacity: 0.9; }

/* timer: last five seconds */
.timer.urgent .timer-fill { animation: timer-pulse 0.5s ease-in-out infinite alternate; }
@keyframes timer-pulse { from { opacity: 1; } to { opacity: 0.45; } }
.hint.urgent { animation: hint-beat 1s ease-in-out infinite; font-weight: 700; color: var(--accent); }
@keyframes hint-beat { 0%, 100% { transform: none; } 12% { transform: scale(1.12); } }

/* ---- reduced motion: same information, simple fades ---- */
@media (prefers-reduced-motion: reduce) {
  .flap.clack, .stamp.stamp-in, .points .bonus.pop, .toplist.cascade li, .toplist.cascade li.mine,
  .reveal-card.land, .reveal-card.wobble, .celebrate.show, .tally-verdict.show, .card-img.print, .streak.tick {
    animation: plain-fade 0.25s ease-out both;
    animation-delay: 0s;
  }
  .timer.urgent .timer-fill, .hint.urgent { animation: none; }
  @keyframes plain-fade { from { opacity: 0; } to { opacity: 1; } }
}

/* ======================================================================
   Suspense reveal: the answer card climbs the year's ranked list.
   Positions use `transform`; the outcome beats animate the separate
   `translate` / `scale` / `rotate` properties so they compose with it.
   ====================================================================== */
.ladder { display: none; position: relative; height: calc(var(--row-h, 38px) * 5); overflow: hidden; margin: 6px 0 2px;
  -webkit-mask-image: linear-gradient(transparent, #000 12%, #000 97%, transparent);
  mask-image: linear-gradient(transparent, #000 12%, #000 97%, transparent); }
.reveal-card.suspense .ladder.on { display: block; }
.reveal-card.suspense :is(.stamp, .your, .top-title, .toplist, .source, .points .bonus) { display: none; }
.ladder-scroll { position: absolute; inset: 0; transition: transform var(--step, 120ms) ease-out; }
.ladder-row, .ladder-pos {
  position: absolute; left: 0; right: 0; top: 0;
  height: calc(var(--row-h, 38px) - 6px);
  transition: transform var(--step, 120ms) cubic-bezier(0.3, 0.8, 0.4, 1);
}
.ladder-pos { z-index: 2; }
.ladder-row, .ladder-card {
  display: grid; grid-template-columns: 3.1rem 1fr; align-items: center; gap: 8px;
  padding: 0 10px; border-radius: calc(var(--radius) * 0.4);
}
.ladder-card { position: relative; height: 100%; }
.ladder-row { color: var(--ink); background: color-mix(in srgb, var(--ink) 6%, transparent); font-size: 0.9rem; }
.lr-rank, .lc-rank { font-weight: 800; font-variant-numeric: tabular-nums; }
.lr-rank { color: var(--muted); }
.lr-name, .lc-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; min-width: 0; }
.ladder-card { z-index: 2; background: var(--accent); color: var(--accent-ink); font-weight: 800;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22); }
.ladder-card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: #fff; opacity: 0; pointer-events: none; }
.points .num.bump { animation: num-bump 0.18s ease-out; }
@keyframes num-bump { 40% { scale: 1.12; } }

/* hit: flash and punch */
.ladder-card.landed { animation: card-hit 0.5s cubic-bezier(0.2, 1.6, 0.4, 1) both; }
.ladder-card.landed::after { animation: card-flash 0.45s ease-out both; }
@keyframes card-hit { 0% { scale: 1; } 35% { scale: 1.1; } 100% { scale: 1; } }
@keyframes card-flash { 0% { opacity: 0.85; } 100% { opacity: 0; } }

/* miss: hesitate, then fall away in sepia */
.ladder-row.absorbed { opacity: 0; transition: opacity 0.2s ease; }
.ladder-card.hesitate { animation: card-hesitate 0.38s ease-in-out both; }
@keyframes card-hesitate { 25% { translate: -5px 0; } 50% { translate: 4px 0; } 75% { translate: -2px 0; } }
.ladder-card.fall { animation: card-fall 0.75s cubic-bezier(0.5, 0, 0.9, 0.5) forwards; }
@keyframes card-fall {
  0% { filter: none; }
  30% { filter: sepia(1) saturate(0.6); translate: 0 6px; rotate: -3deg; }
  100% { filter: sepia(1) saturate(0.4); translate: 30px 240px; rotate: 22deg; opacity: 0; }
}
/* drift: swept sideways into another year */
.ladder-card.swept { animation: card-swept 0.6s cubic-bezier(0.6, 0, 0.9, 0.6) forwards; }
@keyframes card-swept { to { translate: 120% -14px; rotate: -7deg; opacity: 0; } }
/* paradox: time glitch (RGB split, jitter), then yanked out to the future */
.ladder-card.glitch { animation: card-glitch 0.46s steps(2, end) both; }
@keyframes card-glitch {
  0% { text-shadow: 2px 0 #ff2e88, -2px 0 #2ee6ff; translate: 0 0; }
  20% { text-shadow: -3px 0 #ff2e88, 3px 0 #2ee6ff; translate: 5px 0; opacity: 0.8; }
  40% { text-shadow: 4px 1px #ff2e88, -4px -1px #2ee6ff; translate: -6px 1px; opacity: 1; }
  60% { text-shadow: -2px 0 #ff2e88, 2px 0 #2ee6ff; translate: 3px -1px; opacity: 0.6; }
  80% { text-shadow: 5px 0 #ff2e88, -5px 0 #2ee6ff; translate: -4px 0; opacity: 1; }
  100% { text-shadow: 2px 0 #ff2e88, -2px 0 #2ee6ff; translate: 0 0; }
}
.ladder-card.glitch::after { animation: card-flash 0.12s steps(2) 3; }
.ladder-card.yank { animation: card-yank 0.42s cubic-bezier(0.7, 0, 1, 0.5) forwards; text-shadow: 3px 0 #ff2e88, -3px 0 #2ee6ff; }
@keyframes card-yank { to { translate: 0 -260px; scale: 1 0.25; opacity: 0; } }

/* ---- slower, more dramatic climb (2026-11-10 feedback) ---- */
/* opening beat: the card waits at the bottom with a heartbeat */
.ladder-card.pulse { animation: heartbeat 0.9s ease-in-out infinite; }
@keyframes heartbeat { 0%, 100% { scale: 1; } 14% { scale: 1.045; } 28% { scale: 1; } 42% { scale: 1.03; } 56% { scale: 1; } }
/* drumroll: the held card trembles very slightly */
.ladder-card.held { animation: held-tremble 0.12s linear infinite; }
@keyframes held-tremble { 0%, 100% { translate: 0 0; } 50% { translate: 0 -1px; } }
/* fake-out "almost": it settles as if this is it... */
.ladder-card.almost { animation: almost-settle 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) both; }
@keyframes almost-settle { 0% { scale: 1; } 30% { scale: 1.05; } 60% { scale: 0.99; } 100% { scale: 1; } }
/* fake-out "nudge": it strains toward the next rank up, then settles back */
.ladder-card.nudge { animation: nudge-up 0.52s ease-in-out both; }
@keyframes nudge-up { 0%, 100% { translate: 0 0; } 35% { translate: 0 -14px; } 55% { translate: 0 -11px; } }
/* hit-stop: everything freezes for a beat before the landing */
.ladder.freeze .ladder-row, .ladder.freeze .ladder-pos, .ladder.freeze .ladder-card, .ladder.freeze .ladder-scroll { transition: none !important; animation-play-state: paused !important; }
/* the points stamp down on landing */
.points .num.stamp-down { animation: stamp-down 0.42s cubic-bezier(0.2, 1.7, 0.4, 1) both; }
@keyframes stamp-down { 0% { scale: 2.1; rotate: -6deg; opacity: 0.4; } 60% { scale: 0.92; rotate: 1deg; opacity: 1; } 100% { scale: 1; rotate: 0deg; } }
/* camera shakes */
.app.shake { animation: cam-shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }
@keyframes cam-shake { 10%, 90% { translate: -2px 0; } 20%, 80% { translate: 4px 1px; } 30%, 50%, 70% { translate: -7px -1px; } 40%, 60% { translate: 7px 1px; } }
.app.shake-soft { animation: cam-soft 0.35s ease-out both; }
@keyframes cam-soft { 30% { translate: 0 4px; } 60% { translate: 0 -2px; } }
.app.shake-glitch { animation: cam-glitch 0.3s steps(3) both; }
@keyframes cam-glitch { 33% { translate: 5px 0; } 66% { translate: -5px 1px; } }
/* tension: screen edges close in and the card leans closer as it nears #1 */
html::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 40;
  box-shadow: inset 0 0 120px 40px rgba(0, 0, 0, 0.55); opacity: 0; transition: opacity 0.6s ease;
}
html[data-tension="1"]::after { opacity: 0.25; }
html[data-tension="2"]::after { opacity: 0.5; }
html[data-tension="3"]::after { opacity: 0.8; }
.reveal-card { transition: scale 0.6s ease; }
html[data-tension="2"] .reveal-card { scale: 1.02; }
html[data-tension="3"] .reveal-card { scale: 1.04; }
@media (prefers-reduced-motion: reduce) {
  html::after { display: none; }
  .ladder-card.pulse, .ladder-card.held, .ladder-card.almost, .ladder-card.nudge,
  .points .num.stamp-down, .app.shake, .app.shake-soft, .app.shake-glitch { animation: none; }
}
