/* games-a: Word Snake, Balloon Pop, Word Wheel and Memory Match (see styles.css for the shared tokens and components). */

/*
 * The apps' spring animations as keyframes: each overshoot and settle below follows the
 * Android spring (damping ratio and stiffness) it stands for.
 */

/* Word Snake */
.snake-board { flex-shrink: 0; }
.snake-board > canvas { border-radius: 20px; }
.snake-banner-spot { pointer-events: none; }
.snake-banner { max-width: 100%; animation: snakeBannerIn 0.4s ease-out both; }
.snake-slot { color: #fff; font-weight: 900; line-height: 1; }
.snake-slot-pop { animation: snakeSlotPop 0.3s ease-in-out both; }

/* Eaten letter: snaps to 1.35 and springs back (damping 0.4). */
@keyframes snakeSlotPop {
  0% { transform: scale(1.35); }
  30% { transform: scale(0.91); }
  60% { transform: scale(1.023); }
  88% { transform: scale(0.994); }
  100% { transform: scale(1); }
}
/* Word banner: scales in from 0.6 (damping 0.5) as it fades in. */
@keyframes snakeBannerIn {
  0% { transform: scale(0.6); opacity: 0; }
  23% { transform: scale(1.065); }
  47% { transform: scale(0.99); }
  60% { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* Balloon Pop */
.balloon-prompt { margin: 0 16px; }
.balloon-bounce { animation: balloonBounce 0.5s ease-in-out both; }
.balloon-toast-spot {
  position: absolute;
  top: 10px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.balloon-toast { max-width: calc(100% - 32px); animation: balloonToastIn 0.35s cubic-bezier(.2, .9, .3, 1) both; }
.balloon-freeze { position: absolute; top: 12px; right: 12px; pointer-events: none; }

/* A new meaning: snaps to 0.86 and springs back (damping 0.42, stiffness 500). */
@keyframes balloonBounce {
  0% { transform: scale(0.86); }
  31% { transform: scale(1.032); }
  62% { transform: scale(0.993); }
  93% { transform: scale(1.002); }
  100% { transform: scale(1); }
}
@keyframes balloonToastIn { from { transform: translateY(-100%); opacity: 0; } to { transform: none; opacity: 1; } }

/* Word Wheel */
.wheel-clue { animation: wheelClueIn 0.3s ease-out both; }
.wheel-slot { font-weight: 900; line-height: 1; }
.wheel-typed { animation: wheelTyped 0.3s ease-in-out both; }
.wheel-wave { animation: wheelWave 0.36s linear both; }
.wheel-stage { animation: wheelStageIn 0.4s ease-out both; }
.wheel-ring { cursor: pointer; touch-action: none; }
.wheel-btn {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  border: 1.5px solid rgba(255, 255, 255, 0.2);
  transition: transform 0.18s cubic-bezier(.3, 1.6, .5, 1), background 0.15s;
}
.wheel-btn:active:not(:disabled) { transform: scale(0.97); }
.wheel-btn:disabled { opacity: 0.4; cursor: default; }
.wheel-badge {
  position: absolute;
  top: 0;
  right: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--gold);
  color: var(--ink);
  font-size: 12px;
  font-weight: 800;
  pointer-events: none;
}

/* The clue: fades in while swelling from 0.8 (damping 0.6). */
@keyframes wheelClueIn {
  0% { transform: scale(0.8); opacity: 0; }
  34% { transform: scale(1.019); }
  83% { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
/* A traced letter lands in its box: 0.9 to 1 (damping 0.45). */
@keyframes wheelTyped {
  0% { transform: scale(0.9); }
  30% { transform: scale(1.02); }
  60% { transform: scale(0.996); }
  100% { transform: scale(1); }
}
/* The solved word's letters hop one after another. */
@keyframes wheelWave {
  0% { transform: translateY(0); }
  33.3% { transform: translateY(-14px); }
  66.7% { transform: translateY(4px); }
  100% { transform: translateY(0); }
}
/* "Brilliant!" and "Time's up!": scale in from 0.6 (damping 0.5) as they fade in. */
@keyframes wheelStageIn {
  0% { transform: scale(0.6); opacity: 0; }
  23% { transform: scale(1.065); }
  47% { transform: scale(0.99); }
  60% { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* Memory Match: the board wraps its rows at the width the code gives it (a short last row in the middle). */
.memory-area { padding: 8px 16px; min-height: 0; }
.memory-board {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  animation: memoryBoardIn 0.4s cubic-bezier(.4, 0, .2, 1) both;
}
.memory-card { position: relative; flex: none; cursor: pointer; animation: memoryDeal 0.55s ease-out both; }
.memory-motion { position: absolute; inset: 0; perspective: 1000px; }
.memory-motion.memory-bounce { opacity: 0.92; animation: memoryBounce 0.4s ease-in-out both; }
.memory-motion.memory-shake { animation: memoryShake 0.38s linear both; }
.memory-flip {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 0.35s cubic-bezier(.4, 0, .2, 1);
}
.memory-flip.up { transform: rotateY(180deg); }
.memory-face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 16px;
  box-shadow: var(--card-shadow);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.memory-front { padding: 6px; transform: rotateY(180deg); }
.memory-back-rim {
  position: absolute;
  inset: 5px;
  border: 1.5px solid rgba(255, 255, 255, 0.35);
  border-radius: 12px;
}
.memory-back-mark {
  position: relative;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
  font-weight: 900;
  line-height: 1;
}
.memory-face .memory-term {
  max-width: 100%;
  overflow: hidden;
  color: var(--ink);
  font-weight: 900;
  line-height: 1.2;
  white-space: nowrap;
}
.memory-face .memory-meaning {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.memory-face .memory-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  color: var(--primary);
}
.memory-badge { position: absolute; top: 6px; right: 6px; border-radius: 50%; }
.memory-clear-spot { pointer-events: none; }
.memory-clear { animation: memoryClearIn 0.4s ease-out both; }
.memory-preview { animation: memoryPreviewIn 0.35s cubic-bezier(.2, .9, .3, 1) both; }
.memory-match { animation: memoryMatchIn 0.45s ease-out both; }

/* Dealing: each card swells in from nothing (damping 0.6, stiffness 400). */
@keyframes memoryDeal {
  0% { transform: scale(0); opacity: 0; }
  18% { opacity: 1; }
  36% { transform: scale(1.094); }
  71% { transform: scale(0.991); }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes memoryBoardIn {
  0% { transform: scale(0.9); opacity: 0; }
  75% { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
/* A match: snaps to 1.12 and springs back (damping 0.35). */
@keyframes memoryBounce {
  0% { transform: scale(1.12); }
  22% { transform: scale(0.963); }
  43% { transform: scale(1.011); }
  65% { transform: scale(0.9965); }
  100% { transform: scale(1); }
}
/* A miss: a few swings either way. */
@keyframes memoryShake {
  0% { transform: translateX(0); }
  13.2% { transform: translateX(-10px); }
  28.9% { transform: translateX(10px); }
  44.7% { transform: translateX(-8px); }
  60.5% { transform: translateX(8px); }
  76.3% { transform: translateX(-4px); }
  100% { transform: translateX(0); }
}
/* "Board cleared!": scales in from 0.5 (damping 0.5) as it fades in. */
@keyframes memoryClearIn {
  0% { transform: scale(0.5); opacity: 0; }
  23% { transform: scale(1.081); }
  47% { transform: scale(0.99); }
  60% { opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes memoryPreviewIn { from { transform: translateY(-50%); opacity: 0; } to { transform: none; opacity: 1; } }
/* A new pair's banner rises from below (damping 0.6). */
@keyframes memoryMatchIn {
  0% { transform: translateY(100%); opacity: 0; }
  34% { transform: translateY(-9%); opacity: 1; }
  70% { transform: translateY(1%); }
  100% { transform: translateY(0); opacity: 1; }
}

@media (hover: hover) {
  .wheel-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.2); }
  .memory-card:hover .memory-back { filter: brightness(1.06); }
}

/* Word Snake: the arrow keys beside the swipe hint, only where there's a mouse (a keyboard is likely). */
.snake-keys { display: none; gap: 3px; margin-left: 4px; }
.snake-key {
  min-width: 22px;
  height: 22px;
  padding: 0 4px;
  border-radius: 6px;
  background: #fff;
  box-shadow: 0 2px 0 var(--line);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 800;
  line-height: 20px;
  text-align: center;
}
@media (hover: hover) and (pointer: fine) {
  .snake-keys { display: flex; }
}

/*
 * Desktop (the activity gets the whole window). Balloon Pop: the prompt lies across the middle of
 * the stats row (hearts on the left, score on the right), so the sky below is the window's whole
 * width and nearly all of its height.
 */
@media (min-width: 900px) {
  .balloon-hud { display: grid; align-items: center; padding-bottom: 10px; }
  .balloon-hud > * { grid-area: 1 / 1; min-width: 0; }
  .balloon-hud > .balloon-prompt { justify-self: center; width: min(640px, calc(100% - 380px)); margin: 0; }
  .balloon-prompt .t-title { font-size: 26px; line-height: 32px; }
  /* The sky's top edge is open sky here (the prompt doesn't span the window): balloons fade out there instead of being cut off. */
  .balloon-sky > canvas {
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 44px);
    mask-image: linear-gradient(to bottom, transparent, #000 44px);
  }
}

/*
 * Desktop Memory Match: the counts on the left, the memorize bar or the last pair in the middle and
 * the score on the right share one row of fixed height, so the board below gets nearly all the
 * window and doesn't jump as the banners change.
 */
@media (min-width: 900px) {
  .memory-hud {
    flex: none;
    display: grid;
    grid-template-columns: minmax(max-content, 1fr) minmax(0, 560px) minmax(max-content, 1fr);
    align-items: center;
    height: 64px;
  }
  .memory-hud > :last-child { justify-self: end; }
  .memory-hud-mid { min-width: 0; height: 100%; }
  .memory-area { padding: 8px 16px 18px; }
}

/* Desktop Word Wheel: the clue is bigger in the side panel (the wheel fills the rest of the window). */
@media (min-width: 900px) {
  .wheel-clue .t-title { font-size: 26px; line-height: 32px; }
}
