/* ============================================================
 * Messages — animation primitives.
 *
 * Jaspr's @css annotation does not emit @keyframes or @media
 * blocks (same constraint that forces window.css to host the
 * window-title-bar keyframes). Animation *application* lives in
 * the @css blocks of messages_bubble.dart, messages_suggestions.dart
 * and messages_window.dart. The keyframe definitions and the
 * prefers-reduced-motion fallback live here.
 *
 * Tokens chosen to match Apple Messages:
 *   • 280–320ms duration
 *   • cubic-bezier(0.2, 0.9, 0.25, 1) — gentle spring-out
 *   • Translate from 6px under the rest position + slight scale
 *   • Transform-origin pinned to the bubble's tail corner so the
 *     animation reads as "growing from the composer / from the
 *     contact pill" instead of "popping in space"
 * ============================================================ */

/* Outgoing user bubble — emerges from bottom-right (composer side). */
@keyframes msg-bubble-in-right {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Incoming assistant bubble & action card — emerges from bottom-left. */
@keyframes msg-bubble-in-left {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Icebreaker chips — same envelope as user bubble, slightly tighter. */
@keyframes msg-chip-in {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Closing notice & system rows — pure fade, no transform. */
@keyframes msg-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Accessibility: honour the user's reduced-motion preference. We keep
 * the fade so newly inserted content still resolves visually, but
 * remove any translation / scale that could trigger vestibular issues.
 *
 * Target duration: ~60ms. Hard skipping (1ms) made content snap in so
 * abruptly that screen-reader announce-on-mount lagged the visual,
 * causing a perceived flicker on chat turns. 60ms keeps the motion
 * imperceptibly short while still giving the layout a frame to settle. */
@media (prefers-reduced-motion: reduce) {
  .msg-bubble--sent,
  .msg-bubble--received,
  .msg-bubble--action,
  .msg-suggestion-chip {
    animation-duration: 60ms !important;
    animation-timing-function: linear !important;
    transform: none !important;
  }
  /* Collapse the loading-overlay and content-reveal transitions so
   * users with vestibular disorders don't see the expanding bubble. */
  .msg-bubble__action-loading-overlay,
  .msg-bubble__action-rows-content,
  .msg-bubble--actions {
    transition-duration: 60ms !important;
  }
  .msg-bubble__notice-row,
  .msg-window__notice {
    animation-duration: 60ms !important;
  }
  /* Composer fade-out on conversation end. Skip the translate so the
   * slot collapses straight to height 0 without sliding. */
  .msg-window__composer-slot {
    transition-duration: 60ms !important;
    transform: none !important;
  }
  /* Typing indicator dots: stop bouncing, keep a subtle opacity
   * pulse so the "still working" affordance survives. */
  .msg-typing__dot {
    animation: none !important;
    opacity: 0.7 !important;
  }
  /* Closing card fade-in. */
  .msg-closing-card,
  .msg-closing-card__title {
    animation-duration: 60ms !important;
    transition-duration: 60ms !important;
    transform: none !important;
  }
}

/* Prevent iOS Safari auto-zoom: the browser zooms any input whose
 * font-size is below 16px when it gains focus. We override on touch
 * devices only so desktop rendering is unaffected.
 *
 * `!important` is required because the base rule for
 * `.msg-composer__input` is emitted by Jaspr as an inline <style>
 * block (see messages_composer.dart). Depending on source order in
 * the rendered <head>, the inline rule may appear after this
 * stylesheet and win the cascade at equal specificity. !important
 * makes the touch override deterministic. */
@media (pointer: coarse) {
  .msg-composer__input {
    font-size: var(--font-size-callout) !important;
  }

  /* Lift the composer above the Android gesture-navigation bar and the
   * iOS home indicator.  --msg-safe-bottom is explicitly set to 0px by
   * the keyboard bridge whenever the keyboard is open, so this padding
   * never creates a gap between the composer and the keyboard surface.
   * On macOS (pointer: fine) this entire block is a no-op. */
  .msg-window__bottom {
    padding-bottom: var(--msg-safe-bottom, env(safe-area-inset-bottom, 0px));
  }
}
