/* =====================================================================
   Algalert — motion
   Loaded after the app's own styles. Remove the two lines that load this
   file and motion.js from index.html and the app is exactly as before.

   Rules this file keeps to:
   - Movement has to mean something: arrival, confirmation, "this is live".
   - Nothing replays on every search, filter or refresh. The entrance
     sequence runs once per visit; after that the app sits still.
   - Only transform and opacity are animated, so it stays smooth on a
     cheap phone in the sun.
   - Anyone who has asked their device for reduced motion gets none of it.
   ===================================================================== */

@media (prefers-reduced-motion: no-preference) {

/* ------------------------------------------------------------ timing */
:root{
  --ease-out: cubic-bezier(.16, 1, .3, 1);       /* fast in, long settle */
  --ease-spring: cubic-bezier(.34, 1.36, .64, 1); /* a little overshoot */
}

/* ------------------------------------------------ welcome: the logo lives */
#onboard.on .inner > svg circle{
  transform-box: fill-box; transform-origin: center;
  animation: sun 5s ease-in-out infinite;
}
#onboard.on .inner > svg path:nth-of-type(1),
#onboard.on .inner > svg path:nth-of-type(2){
  transform-box: view-box; transform-origin: 78px 54px;   /* the base of the frond */
  animation: sway 6s ease-in-out infinite;
}
#onboard.on .inner > svg path:nth-of-type(2){ animation-duration: 6.8s; animation-delay: -.8s; }
#onboard.on .inner > svg path:nth-of-type(3){ animation: drift 4.2s ease-in-out infinite; }
#onboard.on .inner > svg path:nth-of-type(4){ animation: drift 4.2s ease-in-out infinite reverse; animation-delay: -1.1s; }

@keyframes sun   { 0%,100%{ transform: scale(1);   opacity: .95 } 50%{ transform: scale(1.07); opacity: 1 } }
@keyframes sway  { 0%,100%{ transform: rotate(-3deg) } 50%{ transform: rotate(3.5deg) } }
@keyframes drift { 0%,100%{ transform: translateX(-3px) } 50%{ transform: translateX(3px) } }

/* ------------------------------------------- welcome: the page arrives */
#onboard.on .inner > svg,
#onboard.on .word,
#onboard.on .tag,
#onboard.on .lead,
#onboard.on .props > div,
#onboard.on .cta,
#onboard.on .coast{
  animation: rise-in .9s var(--ease-out) both;
}
#onboard.on .inner > svg   { animation-name: pop-in; animation-duration: 1s; }
#onboard.on .word          { animation-delay: .12s }
#onboard.on .tag           { animation-delay: .20s }
#onboard.on .lead          { animation-delay: .30s }
#onboard.on .props > div:nth-child(1){ animation-delay: .42s }
#onboard.on .props > div:nth-child(2){ animation-delay: .50s }
#onboard.on .props > div:nth-child(3){ animation-delay: .58s }
#onboard.on .coast         { animation-name: coast-in; animation-duration: 1.4s; animation-delay: .25s }
#onboard.on .cta           { animation-delay: .72s }

@keyframes rise-in  { from{ opacity: 0; transform: translateY(18px) } to{ opacity: 1; transform: none } }
@keyframes pop-in   { from{ opacity: 0; transform: scale(.82) } to{ opacity: 1; transform: none } }
@keyframes coast-in { from{ opacity: 0; transform: translateY(40px) } to{ opacity: 1; transform: none } }

/* --------------------------------------- first paint: content settles in
   motion.js adds .intro to <html> on load and removes it once the first
   beach list has been shown, so later re-renders stay still. */
html.intro #view > *{
  animation: rise-in .7s var(--ease-out) both;
}
html.intro #view > *:nth-child(2){ animation-delay: .06s }
html.intro #view > *:nth-child(3){ animation-delay: .12s }
html.intro #view > *:nth-child(4){ animation-delay: .18s }
html.intro #view > *:nth-child(5){ animation-delay: .24s }
html.intro .rows > li{
  animation: rise-in .6s var(--ease-out) both;
  animation-delay: calc(.28s + var(--i, 0) * 45ms);
}

/* ------------------------------------------------ switching tabs: a cut
   becomes a quick dissolve */
#view.swap > *{ animation: fade-in .28s ease-out both; }
@keyframes fade-in { from{ opacity: 0; transform: translateY(6px) } to{ opacity: 1; transform: none } }

/* -------------------------------------------------- live pins on the map
   Only beaches held by a real observation pulse. It is the one piece of
   movement that carries information: somebody is there, this is current. */
.pin:not(.est){ isolation: isolate; }
.pin:not(.est)::before{
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 17px; height: 17px; margin: -8.5px 0 0 -8.5px; border-radius: 50%;
  background: var(--c); opacity: 0; z-index: -1; pointer-events: none;
  animation: live 3.2s ease-out infinite;
  animation-delay: var(--pd, 0s);
}
@keyframes live{
  0%  { transform: scale(1);   opacity: .45 }
  70% { transform: scale(2.8); opacity: 0 }
  100%{ transform: scale(2.8); opacity: 0 }
}
.pin b{ transition: width .18s var(--ease-spring), height .18s var(--ease-spring), box-shadow .18s; }

/* ------------------------------------------- touch: things feel physical */
.btn, .row, .pick, .chip, .tab, .mapfabs button, .mapcard-pop .go, .search .filt, .hero .float{
  transition: transform .16s var(--ease-out), box-shadow .2s, background-color .2s, border-color .2s;
}
.btn:active:not(:disabled),
.mapfabs button:active,
.mapcard-pop .go:active,
.hero .float:active     { transform: scale(.96); }
.row:active             { transform: scale(.985); }
.pick:active            { transform: scale(.98); }
.tab:active             { transform: scale(.92); }

@media (hover: hover){
  .row:hover{ transform: translateY(-2px); box-shadow: 0 8px 22px rgba(21,62,71,.10); }
}

/* the answer you picked answers back */
.pick[aria-pressed="true"] .face{ animation: pick .42s var(--ease-spring); }
@keyframes pick{ 0%{ transform: scale(1) } 40%{ transform: scale(1.22) rotate(-6deg) } 100%{ transform: scale(1) } }

/* ------------------------------------------- the report button, once
   A single ripple a moment after arrival, pointing at the one thing we
   want people to do. It does not repeat. */
html.hint .tab.mid span{ position: relative; }
html.hint .tab.mid span::after{
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid var(--teal); opacity: 0;
  animation: ripple 1.6s var(--ease-out) 2;
}
@keyframes ripple{ 0%{ transform: scale(.9); opacity: .55 } 100%{ transform: scale(1.7); opacity: 0 } }

/* -------------------------------------------------- sheets: a springier rise */
.scrim{ animation: scrim-in .24s ease-out both; }
.sheet{ animation: sheet-in .46s var(--ease-out) both; }
@keyframes scrim-in{ from{ background-color: rgba(21,62,71,0) } }
@keyframes sheet-in{ from{ transform: translateY(100%) } to{ transform: none } }

/* ------------------------------------------------- loading: a moving sheen */
.skel{
  animation: none;
  background: linear-gradient(100deg, var(--card) 30%, #F3EFE6 50%, var(--card) 70%);
  background-size: 250% 100%;
  animation: sheen 1.5s ease-in-out infinite;
}
@keyframes sheen{ from{ background-position: 120% 0 } to{ background-position: -20% 0 } }

/* -------------------------------------------------------------- toasts
   The app removes a toast after three seconds; this fades it in and out
   inside that window instead of letting it blink. */
body > div[role="status"]{ animation: toast 3s var(--ease-out) both; }
@keyframes toast{
  0%  { opacity: 0; transform: translate(-50%, 16px) scale(.96) }
  8%  { opacity: 1; transform: translate(-50%, 0) scale(1) }
  88% { opacity: 1; transform: translate(-50%, 0) scale(1) }
  100%{ opacity: 0; transform: translate(-50%, 8px) scale(.98) }
}

/* ----------------------------------------- the pop-up card on the map */
.mapcard-pop{ transition: transform .42s var(--ease-spring); }

} /* end prefers-reduced-motion */
