/* Little Words — games/shared/anticipation.css
 * Shared styles for the six anticipation engines.
 *
 * CASCADE NOTE (the rail that bit us before): family sheets load AFTER
 * engine2.css, so a bare element/base rule here would silently shadow
 * engine2's own mobile @media block. Every selector in this file is therefore
 * inside the .anticip- namespace — nothing here can reach a shared layout
 * rule, and shared layout still belongs in engine2.css, not here.
 *
 * Mobile-first. Built at 375px, verified at 320px. Nothing here scrolls
 * sideways: the tension stage is sized off the viewport with a hard cap and
 * every transform that grows an object grows it inside its own clipped box.
 */

/* ---------- the tension stage ---------- */
.anticip-stage {
  --tension: 0;
  /* live mic level, published by the turn loop's stake contract while the
     child is actually talking. Transient: it never commits a rung. */
  --charge: 0;
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
  /* the object needs headroom to grow into without pushing the page */
  height: min(46vh, 320px);
  min-height: 200px;
  overflow: hidden;
  border-radius: 22px;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.anticip-stage:focus-visible {
  outline: 3px solid var(--lw-sage, #6BAF8D);
  outline-offset: 3px;
}

/* the object itself — one wrapper every family animates */
.anticip-obj {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  transform-origin: 50% 92%;
  will-change: transform;
  transition: transform .5s cubic-bezier(.34, 1.56, .64, 1);
}
.anticip-obj img,
.anticip-obj svg { display: block; width: 100%; height: auto; }

/* ---------- the meter a non-reader can read ----------
 * Not a number and not a fraction: a row of filled dots that grows as the
 * object does. It never says how many are left, because not knowing when it
 * goes is the whole mechanic. */
.anticip-meter {
  display: flex;
  gap: 8px;
  justify-content: center;
  align-items: center;
  margin: 10px auto 0;
  min-height: 22px;
}
.anticip-pip {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: rgba(30, 42, 74, .16);
  transition: transform .3s cubic-bezier(.34, 1.56, .64, 1), background .3s;
}
.anticip-pip.on { background: var(--t3, #E8A13C); transform: scale(1.35); }

/* ---------- the one big control ---------- */
.anticip-go {
  display: block;
  width: min(100%, 340px);
  min-height: 56px;
  margin: 14px auto 0;
  padding: 14px 20px;
}

.anticip-hint {
  text-align: center;
  margin: 8px auto 0;
  max-width: 34ch;
  font-size: 1rem;
  line-height: 1.35;
  opacity: .82;
}

/* ---------- shared escalation ----------
 * The wobble is driven by --tension, so an engine gets its escalating
 * unsteadiness for free and cannot forget to escalate it. */
@keyframes anticip-wobble {
  0%, 100% { rotate: calc(-1deg * var(--tension)); }
  25%      { rotate: calc(1.6deg * var(--tension)); }
  50%      { rotate: calc(-1.4deg * var(--tension)); }
  75%      { rotate: calc(1.2deg * var(--tension)); }
}
.anticip-wobble {
  animation: anticip-wobble calc(1.1s - .55s * var(--tension)) ease-in-out infinite;
}
@keyframes anticip-strain {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(calc(1 + .18 * var(--tension))); }
}
.anticip-strain { animation: anticip-strain calc(.9s - .4s * var(--tension)) ease-in-out infinite; }

/* ---------- release flourishes ---------- */
@keyframes anticip-burst-flash {
  0%   { opacity: 0; transform: scale(.4); }
  22%  { opacity: .92; transform: scale(1.25); }
  100% { opacity: 0; transform: scale(1.9); }
}
.anticip-flash {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 62%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, #FFFBF5 0%, var(--t3, #E8A13C) 48%, transparent 72%);
  pointer-events: none;
  animation: anticip-burst-flash .55s ease-out forwards;
}
.anticip-shard {
  position: absolute;
  width: 16px; height: 16px;
  border-radius: 4px;
  pointer-events: none;
  will-change: transform, opacity;
  transition: transform .85s cubic-bezier(.2, .7, .3, 1), opacity .85s ease-out;
}

/* ---------- family: stack and crash ---------- */
.anticip-tower {
  position: relative;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 2px;
  transform-origin: 50% 100%;
  transition: rotate .45s cubic-bezier(.34, 1.56, .64, 1);
}
.anticip-block {
  width: clamp(58px, 22vw, 88px);
  height: clamp(24px, 8vw, 34px);
  border-radius: 8px;
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .14);
  transition: transform .7s cubic-bezier(.3, .8, .4, 1), opacity .7s;
  will-change: transform;
}
.anticip-block.drop-in { animation: anticip-drop .42s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes anticip-drop {
  from { transform: translateY(-70px) rotate(-8deg); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.anticip-floor {
  width: min(92%, 360px);
  height: 10px;
  border-radius: 6px;
  background: rgba(30, 42, 74, .14);
  margin-top: 4px;
}

/* ---------- family: hatch and reveal ---------- */
.anticip-crack { transition: opacity .35s ease-out; }
@keyframes anticip-rock {
  0%, 100% { rotate: calc(-3deg * var(--tension)); }
  50%      { rotate: calc(3.4deg * var(--tension)); }
}
.anticip-rock { animation: anticip-rock calc(.85s - .42s * var(--tension)) ease-in-out infinite; transform-origin: 50% 88%; }
.anticip-half { transition: transform .8s cubic-bezier(.2, .8, .3, 1), opacity .8s; }

/* ---------- family: ramp and launch ---------- */
.anticip-gauge {
  width: min(78%, 260px);
  height: 16px;
  border-radius: 999px;
  background: rgba(30, 42, 74, .14);
  overflow: hidden;
  margin: 0 auto;
}
.anticip-gauge-fill {
  height: 100%;
  width: calc(100% * var(--tension));
  border-radius: 999px;
  background: linear-gradient(90deg, var(--t2, #8FCBEA), var(--t3, #E8A13C));
  transition: width .5s cubic-bezier(.34, 1.4, .64, 1);
}
.anticip-launched { transition: transform 1.4s cubic-bezier(.4, 0, .3, 1), opacity 1.4s; }

/* ---------- family: care routine ---------- */
.anticip-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin: 10px auto 0;
  max-width: 360px;
  padding: 0;
  list-style: none;
}
.anticip-step {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  min-height: 32px;
  border-radius: 999px;
  background: rgba(30, 42, 74, .07);
  font-size: .85rem;
  opacity: .55;
  transition: opacity .3s, background .3s, transform .3s;
}
.anticip-step.done { opacity: 1; background: rgba(107, 175, 141, .24); transform: scale(1.04); }
.anticip-step.now  { opacity: 1; background: var(--t2, #8FCBEA); }

/* the water/foam that rises with the routine */
.anticip-fill {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: calc(6% + 40% * var(--tension));
  background: linear-gradient(180deg, rgba(143, 203, 234, .72), rgba(143, 203, 234, .95));
  border-radius: 0 0 22px 22px;
  transition: height .6s cubic-bezier(.34, 1.4, .64, 1);
  pointer-events: none;
}
.anticip-grime { transition: opacity .5s ease-out; }

/* ---------- family: rescue ---------- */
.anticip-lift { transition: transform .6s cubic-bezier(.34, 1.56, .64, 1); }
.anticip-mud  { transition: transform .6s ease-out, opacity .6s; }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .anticip-wobble, .anticip-strain, .anticip-rock { animation: none; }
  .anticip-obj, .anticip-block, .anticip-tower, .anticip-half,
  .anticip-gauge-fill, .anticip-fill, .anticip-lift { transition-duration: .01ms; }
}

/* ---------- narrow phones (320px) ---------- */
@media (max-width: 360px) {
  .anticip-stage { height: min(40vh, 250px); min-height: 176px; }
  .anticip-pip { width: 12px; height: 12px; }
  .anticip-meter { gap: 6px; }
  .anticip-step { font-size: .78rem; padding: 5px 8px; }
  .anticip-go { width: 100%; }
}
