/* ============================================================
   Atmosphere: the motion half of it.

   Everything here is decoration and everything here is optional —
   "Reduce motion & effects" in Settings, or the operating system's
   own reduced-motion setting, switches the lot off.
   ============================================================ */

/* ---------- full-screen washes ---------- */

#flash{
  position:fixed; inset:0; z-index:8999; pointer-events:none; opacity:0;
  background:radial-gradient(120% 90% at 50% 30%, rgba(255,255,255,.9), rgba(190,215,235,.25) 55%, transparent 75%);
}
#flash.lightning{ animation:lightning 1.1s ease-out both; }
@keyframes lightning{
  0%{opacity:0} 3%{opacity:.5} 7%{opacity:.06} 11%{opacity:.72} 17%{opacity:.1}
  22%{opacity:.28} 45%{opacity:.02} 100%{opacity:0}
}
#flash.bad{ background:radial-gradient(140% 110% at 50% 50%, transparent 42%, rgba(192,74,63,.55)); animation:washout .9s ease-out both; }
#flash.good{ background:radial-gradient(140% 110% at 50% 50%, transparent 46%, rgba(111,157,106,.4)); animation:washout .9s ease-out both; }
@keyframes washout{ 0%{opacity:0} 14%{opacity:1} 100%{opacity:0} }

/* the lamp in every scene breathes a little */
.scene-hold::after{
  content:''; position:absolute; inset:0; pointer-events:none; z-index:2;
  background:radial-gradient(60% 45% at 50% 22%, rgba(230,178,75,.10), transparent 70%);
  animation:lampbreathe 7.5s ease-in-out infinite;
}
@keyframes lampbreathe{ 0%,100%{opacity:.55} 42%{opacity:1} 61%{opacity:.68} 64%{opacity:.95} }

/* ---------- reactions ---------- */

.fx-shake{ animation:shake .42s cubic-bezier(.36,.07,.19,.97) both; }
@keyframes shake{
  10%,90%{transform:translateX(-2px)} 20%,80%{transform:translateX(4px)}
  30%,50%,70%{transform:translateX(-7px)} 40%,60%{transform:translateX(7px)}
}

.fx-slam{ animation:slam .5s cubic-bezier(.2,1.5,.35,1) both; }
@keyframes slam{ 0%{opacity:0; transform:scale(1.7) rotate(-9deg)} 60%{opacity:1} 100%{opacity:1; transform:none} }

.fx-pop{ animation:pop .45s cubic-bezier(.2,.9,.3,1.4) both; }
@keyframes pop{ from{opacity:0; transform:scale(.82)} }

.fx-sweep{ position:relative; overflow:hidden; }
.fx-sweep::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(100deg, transparent 20%, rgba(111,157,106,.4) 50%, transparent 80%);
  animation:sweep .85s ease-out both;
}
@keyframes sweep{ from{transform:translateX(-100%)} to{transform:translateX(100%)} }

/* the verdict stamp lands */
.verdict-hd .stampbig{ animation:slam .6s cubic-bezier(.2,1.4,.35,1) both; }

/* a marker that has just been worked leaves a ring behind */
.hotspot .ripple{
  position:absolute; left:50%; top:50%; width:34px; height:34px; margin:-17px 0 0 -17px;
  border:1px solid var(--sodium); border-radius:50%; pointer-events:none;
  animation:ripple .85s cubic-bezier(.15,.7,.3,1) both;
}
@keyframes ripple{ from{transform:scale(.7); opacity:.9} to{transform:scale(3.4); opacity:0} }

/* meters answer when they are spent or paid */
.meter.fx-hit .meter-bar{ animation:meterhit .5s ease-out both; }
@keyframes meterhit{ 0%{box-shadow:0 0 0 0 rgba(230,178,75,.5)} 100%{box-shadow:0 0 0 7px rgba(230,178,75,0)} }
.meter.fx-hit.down .meter-bar{ animation:meterdown .5s ease-out both; }
@keyframes meterdown{ 0%{box-shadow:0 0 0 0 rgba(224,91,76,.6)} 100%{box-shadow:0 0 0 7px rgba(224,91,76,0)} }

/* a proven deduction arrives with a little weight behind it */
.bcard.deduction{ animation:pop .5s cubic-bezier(.2,.9,.3,1.4) both; }

/* a broken claim settles green */
.claim.broken{ animation:settle .6s ease-out both; }
@keyframes settle{ 0%{ background:rgba(111,157,106,.3) } 100%{ background:rgba(111,157,106,.07) } }

/* a locked timeline row */
.tl-table tr.locked td{ animation:lockrow .7s ease-out both; }
@keyframes lockrow{ 0%{ background:rgba(111,157,106,.25) } 100%{ background:transparent } }

/* Screens arrive with a slow pass of light instead of a plain fade. The
   fill mode is `backwards`, not `both`: once it has run the layer returns to
   its own style — transparent and untransformed — so the sweep never leaves
   225px of dead scroll behind it on a phone. */
.screen::before{
  content:''; position:absolute; inset:0; z-index:1; pointer-events:none; opacity:0;
  background:linear-gradient(105deg, transparent 35%, rgba(230,178,75,.055) 50%, transparent 65%);
  animation:passlight 1.1s ease-out backwards;
}
@keyframes passlight{ from{transform:translateX(-60%); opacity:1} to{transform:translateX(60%); opacity:0} }

/* the title logo has a lamp behind it */
#title-screen .logo{ animation:logofade 1.6s ease-out both; }
@keyframes logofade{ from{opacity:0; letter-spacing:.4em; filter:blur(6px)} }

/* ---------- switched off on request ---------- */

body.reduced #flash,
body.reduced .scene-hold::after,
body.reduced .screen::before{ display:none; }
body.reduced *{ animation:none !important; }

@media (prefers-reduced-motion: reduce){
  #flash, .scene-hold::after, .screen::before{ display:none; }
}
