/* FitBuddy motion, Spotter direction. Fast, then still.
   One easing curve does almost everything. One spring exists and it is only
   for a win: a streak advancing, a reaction landing. If everything springs,
   nothing feels like anything. */
:root {
  --dur-instant: 90ms;
  --dur-1: 130ms;
  --dur-2: 190ms;
  --dur-3: 260ms;
  --dur-4: 400ms;
  --dur-5: 640ms;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.42, 0.64, 1);

  --t-hover: var(--dur-1) var(--ease-out);
  --t-press: var(--dur-instant) var(--ease-out);
  --t-enter: var(--dur-3) var(--ease-out);
  --t-sheet: var(--dur-4) var(--ease-out);
  --t-celebrate: var(--dur-5) var(--ease-spring);

  --press-scale: 0.97;
  --press-scale-tile: 0.985;

  /* The live dot pulses. Nothing else does. */
  --dur-pulse: 1800ms;
  --t-pulse: var(--dur-pulse) var(--ease-in-out);

  /* List entrance. Multiplied by the item index, capped, so a long list never
     leaves anyone waiting on motion to read it. */
  --stagger-step: 26ms;
  --stagger-cap: 5;

  /* The streak flame, the system's one illustration. Its three layers run on
     deliberately mismatched clocks so they never resync: a flame that repeats
     on a visible loop stops reading as fire and starts reading as a GIF.
     Embers ride a fourth clock again. */
  --dur-flame-outer: 2600ms;
  --dur-flame-mid:   3400ms;
  --dur-flame-core:  4300ms;
  --dur-ember:       2200ms;
}

@keyframes fb-fade-up { from { opacity:0; transform:translateY(8px) } to { opacity:1; transform:none } }
@keyframes fb-fade-in { from { opacity:0 } to { opacity:1 } }
@keyframes fb-pop { 0%{transform:scale(0.86);opacity:0} 60%{transform:scale(1.04)} 100%{transform:scale(1);opacity:1} }
@keyframes fb-sheen { from { background-position: -160% 0 } to { background-position: 260% 0 } }
@keyframes fb-pulse { 0%,100%{opacity:1} 50%{opacity:0.45} }
@keyframes fb-ring { from { stroke-dashoffset: var(--fb-ring-from, 0) } }

/* Flame. Every layer animates from its own base (transform-origin 50% 100%),
   because fire is anchored where it burns and only the top is free to move.
   Transform and opacity only, like everything else. */
@keyframes fb-flame-sway {
  0%,100% { transform: translate3d(0,0,0) scale(1,1) }
  22%     { transform: translate3d(-1.5%,0,0) scale(0.975,1.045) }
  48%     { transform: translate3d(1.2%,0,0) scale(1.03,0.975) }
  74%     { transform: translate3d(-0.6%,0,0) scale(0.99,1.02) }
}
/* The inner layers run this one, which leans the other way, so the core reads
   as lagging behind the edge rather than moving with it. */
@keyframes fb-flame-counter {
  0%,100% { transform: translate3d(0,0,0) scale(1,1) }
  30%     { transform: translate3d(1.4%,0,0) scale(1.035,0.97) }
  60%     { transform: translate3d(-1%,0,0) scale(0.97,1.04) }
}
/* Embers rise in viewBox user units, not percentages: a percentage transform on
   an SVG group has no box to resolve against and throws the ember across the
   page. --ember-rise is in the flame's own 64x80 coordinate space. */
@keyframes fb-ember {
  0%   { transform: translate3d(0,0,0) scale(0.5); opacity: 0 }
  18%  { opacity: 1 }
  70%  { opacity: 0.8 }
  100% { transform: translate3d(0,var(--ember-rise,-26px),0) scale(0.2); opacity: 0 }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant:0ms;--dur-1:0ms;--dur-2:0ms;--dur-3:0ms;--dur-4:0ms;--dur-5:0ms;
    --press-scale:1;--press-scale-tile:1;--dur-pulse:0ms;--stagger-step:0ms;
  }
  *,*::before,*::after{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important}
}
