/* Guess feedback effects. Built by public/js/fx.js, drawn over the photo.
   Transform and opacity only, and every node is thrown away when it ends. */

:root {
  --fx-good: #0f9f5c;
  --fx-bad: #d33a2a;
  --fx-on: #fffaf4;
}

@media (prefers-color-scheme: dark) {
  :root {
    --fx-good: #4dd393;
    --fx-bad: #ff6f60;
    --fx-on: #14100c;
  }
}

.fx {
  position: fixed;
  inset: 0;
  z-index: 65;
  pointer-events: none;
  display: grid;
  place-items: center;
  contain: layout paint style;
  --fx-c: var(--fx-good);
  --fx-a: 30%;
  --fx-pop: 1;
}

.fx[data-kind="miss"] { --fx-c: var(--fx-bad); --fx-a: 20%; }
.fx[data-kind="out"] { --fx-c: var(--fx-bad); --fx-a: 38%; }

/* ---------- the tint ---------- */

.fx-tint {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    120% 90% at 50% 46%,
    color-mix(in srgb, var(--fx-c) calc(var(--fx-a) * 0.45), transparent),
    color-mix(in srgb, var(--fx-c) var(--fx-a), transparent) 100%
  );
  opacity: 0;
  will-change: opacity;
}

.fx[data-kind="hit"] .fx-tint { animation: fx-pulse-2 900ms var(--ease) both; }
.fx[data-kind="miss"] .fx-tint { animation: fx-pulse-1 380ms var(--ease) both; }
.fx[data-kind="out"] .fx-tint { animation: fx-pulse-out 900ms var(--ease) both; }

@keyframes fx-pulse-2 {
  0% { opacity: 0; }
  12% { opacity: 1; }
  34% { opacity: 0.34; }
  54% { opacity: 0.82; }
  100% { opacity: 0; }
}

@keyframes fx-pulse-1 {
  0% { opacity: 0; }
  20% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes fx-pulse-out {
  0% { opacity: 0; }
  10% { opacity: 1; }
  42% { opacity: 0.55; }
  64% { opacity: 0.95; }
  100% { opacity: 0; }
}

/* ---------- the mark ---------- */

.fx-stage {
  position: relative;
  width: clamp(9rem, 40vmin, 15rem);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  will-change: transform;
}

.fx[data-kind="hit"] .fx-stage { animation: fx-in 940ms var(--ease-back) both; }
.fx[data-kind="out"] .fx-stage { animation: fx-in-heavy 880ms var(--ease-back) both, fx-shake 420ms var(--ease) 120ms both; }
.fx[data-kind="miss"] .fx-stage { animation: fx-in-light 460ms var(--ease-back) both, fx-shake 300ms var(--ease) 90ms both; }

.fx-disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--fx-c);
  opacity: 0.94;
  box-shadow: 0 0 0 0.5rem color-mix(in srgb, var(--fx-c) 22%, transparent), 0 1.25rem 3rem rgb(0 0 0 / 0.28);
}

.fx-mark {
  position: relative;
  width: 78%;
  height: 78%;
  overflow: visible;
}

.fx-mark path {
  fill: none;
  stroke: var(--fx-on);
  stroke-width: 10;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: fx-draw 300ms var(--ease) 90ms both;
  will-change: stroke-dashoffset;
}

.fx[data-kind="hit"] .fx-mark path { animation-duration: 340ms; }
.fx[data-kind="miss"] .fx-mark path { animation-duration: 200ms; animation-delay: 60ms; }
.fx-mark path:nth-child(2) { animation-delay: 220ms; }
.fx[data-kind="miss"] .fx-mark path:nth-child(2) { animation-delay: 150ms; }

@keyframes fx-draw {
  from { stroke-dashoffset: 1; }
  to { stroke-dashoffset: 0; }
}

@keyframes fx-in {
  0% { opacity: 0; transform: scale(calc(0.45 * var(--fx-pop))); }
  26% { opacity: 1; transform: scale(calc(1.09 * var(--fx-pop))); }
  38% { transform: scale(calc(0.96 * var(--fx-pop))); }
  48% { transform: scale(var(--fx-pop)); }
  78% { opacity: 1; transform: scale(var(--fx-pop)); }
  100% { opacity: 0; transform: scale(calc(1.12 * var(--fx-pop))); }
}

@keyframes fx-in-heavy {
  0% { opacity: 0; transform: scale(0.5); }
  28% { opacity: 1; transform: scale(1.07); }
  44% { transform: scale(1); }
  76% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.9); }
}

@keyframes fx-in-light {
  0% { opacity: 0; transform: scale(0.72); }
  22% { opacity: 1; transform: scale(1.05); }
  40% { transform: scale(1); }
  68% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.96); }
}

@keyframes fx-shake {
  0%, 100% { translate: 0; }
  18% { translate: -7%; }
  38% { translate: 6%; }
  58% { translate: -4%; }
  78% { translate: 2%; }
}

/* ---------- rings and particles ---------- */

.fx-rings,
.fx-burst {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.fx-rings i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 0.25rem solid var(--fx-c);
  opacity: 0;
  animation: fx-ring 760ms var(--ease) both;
  will-change: transform, opacity;
}

.fx-rings i:nth-child(2) { animation-delay: 160ms; }
.fx[data-kind="miss"] .fx-rings i { animation-duration: 420ms; }
.fx[data-kind="miss"] .fx-rings i:nth-child(2) { display: none; }

@keyframes fx-ring {
  0% { opacity: 0.65; transform: scale(0.9); }
  100% { opacity: 0; transform: scale(1.9); }
}

.fx-burst i {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.7rem;
  height: 0.7rem;
  margin: -0.35rem 0 0 -0.35rem;
  border-radius: var(--r-pill);
  background: var(--fx-c);
  opacity: 0;
  animation: fx-fly 820ms var(--ease) var(--d, 0s) both;
  will-change: transform, opacity;
}

.fx-burst i:nth-child(3n) { background: var(--accent); }
.fx-burst i:nth-child(4n) { background: var(--brand); }

@keyframes fx-fly {
  0% { opacity: 0; transform: translate(0, 0) scale(0.3); }
  22% { opacity: 1; transform: translate(calc(var(--bx) * 0.35), calc(var(--by) * 0.35)) scale(1); }
  100% { opacity: 0; transform: translate(var(--bx), var(--by)) scale(0.4); }
}

/* ---------- the points ---------- */

.fx-points {
  position: absolute;
  left: 0;
  right: 0;
  text-align: center;
  bottom: calc(50% + clamp(5.5rem, 23vmin, 9rem));
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(3rem, 13vmin, 5.5rem);
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--fx-c);
  text-shadow: 0 0.15rem 1.4rem rgb(0 0 0 / 0.45);
  opacity: 0;
  animation: fx-points 900ms var(--ease-back) 120ms both;
  will-change: transform, opacity;
}

@keyframes fx-points {
  0% { opacity: 0; transform: translateY(1rem) scale(calc(0.6 * var(--fx-pop))); }
  28% { opacity: 1; transform: translateY(0) scale(calc(1.12 * var(--fx-pop))); }
  44% { transform: translateY(0) scale(var(--fx-pop)); }
  70% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-3.5rem) scale(var(--fx-pop)); }
}

/* ---------- the photo dims when the photo is lost ---------- */

.photo-layer { transition: filter var(--slow) var(--ease); }
body.fx-dim .photo-layer { filter: saturate(0.35) brightness(0.68); }

/* ---------- wide screens ---------- */

/* The panel sits beside the photo, so centre the effect on the photo. */
@media (min-width: 52rem) {
  body.is-playing .fx { padding-right: 24rem; }
  body.is-playing .fx-points { right: 24rem; }
}

/* ---------- reduced motion ---------- */

/* A browser in this mode collapses animations to nothing, so nothing here
   may depend on one running. The mark is simply shown, and fx.js takes it
   away again. */
@media (prefers-reduced-motion: reduce) {
  .fx-rings,
  .fx-burst { display: none; }

  .fx-tint,
  .fx[data-kind="hit"] .fx-tint,
  .fx[data-kind="miss"] .fx-tint,
  .fx[data-kind="out"] .fx-tint {
    animation: none;
    opacity: 0.85;
  }

  .fx-stage,
  .fx[data-kind="hit"] .fx-stage,
  .fx[data-kind="miss"] .fx-stage,
  .fx[data-kind="out"] .fx-stage {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .fx-mark path { animation: none; stroke-dashoffset: 0; }

  .fx-points { animation: none; opacity: 1; transform: none; }

  .photo-layer { transition: none; }
}
