/* ── chat-motion.css — Zier-Bewegungsschicht der Chat-UI ─────────────
 *
 * EIGENE Schicht neben companion-motion.css (die bleibt unantastbar:
 * sie traegt die acht WARTEZUSTAENDE; hier lebt ausschliesslich
 * Zier-Motion — Entrances, Hover, Press, Morphs). Nach style.css und
 * companion-motion.css geladen, damit Ueberschreibungen (Send-Icon-
 * Morph) ohne Spezifitaets-Tricks funktionieren.
 *
 * Grammatik (aus der Magie-Recherche 2026-08-25):
 *  - Entrances 200-280ms, --m-ease-out (ease-out-quint) — Dinge
 *    KOMMEN AN, sie explodieren nicht.
 *  - Hover/Press 100-150ms ease — Feedback vor dem Klick.
 *  - Stagger 30-40ms je Element, gedeckelt (ab dem 7. gemeinsam) —
 *    Gesamtdauer unter 300ms, sonst wartet der Mensch auf die UI.
 *  - Nur transform/opacity (composited) — nie Layout-Eigenschaften.
 *  - Hochfrequenz-Null-Regel: Chat-/Verlaufs-Wechsel, Paletten und
 *    alltaegliche Toggles animieren NICHT (deshalb haengt die
 *    Nachricht-Entrance an .is-fresh, nie am Verlauf-Load).
 *  - Interruptibilitaet: Zustaende via transition (retargetbar),
 *    Einmal-Momente via animation … both.
 */

:root {
  --m-fast: 150ms;
  --m-base: 200ms;
  --m-slow: 280ms;
  /* ease-out-quint — schnell raus, weich ankommen */
  --m-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  /* grosse Flaechen (Drawer nutzt dieselbe Kurve in style.css) */
  --m-ease-panel: cubic-bezier(0.32, 0.72, 0.24, 1);
  /* dezenter Spring: Overshoot ≤ 2% — Settle, kein Gummiband */
  --m-spring: linear(0, 0.29 14%, 0.66 30%, 0.92 46%, 1.02 64%, 1 82%, 1);
}

/* ── 1 · Nachricht kommt an (Send-Moment) ───────────────────────────
 * Nur frisch eingefuegte Turns (Alpine setzt is-fresh beim
 * optimistischen Insert); der Verlauf-Load und der Post-Stream-
 * Remount (tmp→Server-ID) animieren NICHT. */
.chat-turn.is-fresh {
  animation: msg-arrive var(--m-slow) var(--m-ease-out) both;
}
@keyframes msg-arrive {
  from { opacity: 0; transform: translateY(14px) scale(0.99); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ── 2 · Ergebnis-Karten ziehen ein ─────────────────────────────────
 * Ersetzt das tote magic-rise (Keyframes existierten nie) und die
 * nie feuernden animate__-x-transitions auf x-for-Items. Stagger via
 * --i (Alpine: style="--i: $index"), ab Karte 7 gemeinsam. */
.chat-result-card {
  animation: card-in 240ms var(--m-spring) both;
  animation-delay: calc(min(var(--i, 0), 6) * 40ms);
}
@keyframes card-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* HITL-Karten (Bestaetigen/ask_user) muessen SOFORT da sein. */
.chat-result-card--confirmation,
.chat-result-card--ask_user {
  animation-delay: 0ms;
}

/* Die Ergebnis-Leiste schwebt ein, statt den Turn hart zu weiten. */
.chat-result-cards {
  animation: rail-in 240ms var(--m-ease-panel) both;
}
@keyframes rail-in {
  from { opacity: 0; transform: translateX(12px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ── 3 · Live-Quellenleiste: Pills wehen ein ───────────────────────── */
.src-rail-item {
  animation: pill-in var(--m-base) var(--m-ease-out) both;
  animation-delay: calc(min(var(--i, 0), 5) * 30ms);
}
@keyframes pill-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Antwort-Landing: Summary-Pill + Aktionszeile settlen als Abschluss. */
.m-settle {
  animation: pill-in var(--m-base) var(--m-ease-out) both;
}

/* Konfidenz-Bar waechst zum Wert statt fertig dazustehen
 * (Vorbild cm-progress__fill). */
.chat-source-card-confbar-fill,
.src-rail-confbar-fill {
  transition: width 420ms var(--m-ease-out);
}

/* ── 4 · Greifbarkeit: Hover-Lift nur auf objekthaften Flaechen ─────
 * Guards nach interfaces.rauno.me: nur echte Pointer (kein Sticky-
 * Hover auf Touch), nur transform/box-shadow/Farbe — kein Layout. */
@media (hover: hover) {
  .chat-result-card {
    transition: transform var(--m-fast) ease,
                box-shadow var(--m-fast) ease,
                border-color var(--m-fast) ease;
  }
  .chat-result-card:hover {
    transform: translateY(-2px);
    border-color: var(--chat-accent);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--chat-accent) 10%, transparent);
  }
  .src-rail-item,
  .chat-rc-source-chip {
    transition: border-color var(--m-fast) ease,
                background-color var(--m-fast) ease;
    cursor: pointer;
  }
  .src-rail-item:hover,
  .chat-rc-source-chip:hover {
    border-color: var(--chat-accent);
  }
}

/* ── 5 · Sende-Moment ───────────────────────────────────────────────
 * Press-Feedback + Icon-Morph Pfeil↔Stop (Crossfade statt display-
 * Hartschnitt; ueberschreibt die display-Regeln aus style.css). */
.chat-composer-send {
  display: grid;
  place-items: center;
}
.chat-composer-send svg {
  grid-area: 1 / 1;
  transition: opacity var(--m-fast) ease, transform var(--m-fast) var(--m-ease-out);
}
.chat-composer-send svg:nth-of-type(2) {
  display: block;
  opacity: 0;
  transform: scale(0.6);
}
.chat-composer-send.is-stop svg:nth-of-type(1) {
  display: block;
  opacity: 0;
  transform: scale(0.6);
}
.chat-composer-send.is-stop svg:nth-of-type(2) {
  opacity: 1;
  transform: scale(1);
}
.chat-composer-send:active {
  transform: scale(0.92);
}

/* ── 6 · Modals: Companion-Ersatz fuer die animate.css-Klassen ─────
 * (CDN entfernt — Kein-CDN-Linie.) Alpine haelt die Enter-/Leave-
 * Klasse fuer die Animationsdauer. Exit schneller als Enter. */
.m-modal-backdrop-in { animation: m-fade 180ms var(--m-ease-out) both; }
.m-modal-backdrop-out { animation: m-fade 120ms ease both reverse; }
.m-modal-in { animation: m-pop 180ms var(--m-ease-out) both; }
.m-modal-out { animation: m-pop 120ms ease both reverse; }
@keyframes m-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes m-pop {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

/* Hero-Kacheln (Start-Ansicht): Companion-Entrance + CSS-Hover statt
 * animate__fadeInUp + Inline-onmouseover. */
.m-rise-in {
  animation: card-in var(--m-slow) var(--m-ease-out) both;
  animation-delay: calc(var(--i, 0) * 80ms);
}
@media (hover: hover) {
  .m-hero-tile {
    transition: transform var(--m-fast) ease, box-shadow var(--m-fast) ease;
  }
  .m-hero-tile:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.06);
  }
}

/* ── 7 · Reduzierte Bewegung: ein Schalter fuer die ganze Schicht ───
 * plus die Altlasten aus style.css, die die Companion-Regel (keine
 * Rotation/Wanderung bei reduced motion) bisher nicht abdeckte. */
@media (prefers-reduced-motion: reduce) {
  .chat-turn.is-fresh,
  .chat-result-card,
  .chat-result-cards,
  .src-rail-item,
  .m-settle,
  .m-modal-backdrop-in,
  .m-modal-backdrop-out,
  .m-modal-in,
  .m-modal-out,
  .m-rise-in,
  .chat-rc-pa-consumed,
  .chat-bubble-body.is-streaming > * {
    animation-duration: 1ms;
    animation-delay: 0ms;
  }
  .chat-result-card,
  .chat-composer-send,
  .chat-composer-send svg,
  .m-hero-tile,
  .chat-source-card-confbar-fill,
  .src-rail-confbar-fill {
    transition: none;
  }
  .chat-result-card:hover,
  .m-hero-tile:hover {
    transform: none;
  }
  /* Altlasten: Rotation + Wanderung stilllegen (Companion-Regel). */
  .chat-website-card-slide,
  .voice-ring {
    animation: none;
  }
}

/* ── 8 · Streamen: neue Bloecke schreiben sich ein ──────────────────
 * Funktioniert NUR mit dem Idiomorph-Renderpfad (morphMessageBody):
 * bestehende Knoten bleiben identisch, also spielt die Entrance
 * ausschliesslich auf frisch eingefuegten Bloecken — der Text wirkt
 * geschrieben statt gestempelt (SOTA-Streaming-Muster). Nach dem
 * Stream (ohne .is-streaming) erscheinen Bloecke ohne Animation
 * (Verlauf-Load, Persist-Reload). */
.chat-bubble-body.is-streaming > p,
.chat-bubble-body.is-streaming > ul > li,
.chat-bubble-body.is-streaming > ol > li,
.chat-bubble-body.is-streaming > pre,
.chat-bubble-body.is-streaming > blockquote,
.chat-bubble-body.is-streaming > table,
.chat-bubble-body.is-streaming > h1,
.chat-bubble-body.is-streaming > h2,
.chat-bubble-body.is-streaming > h3 {
  animation: token-in 180ms var(--m-ease-out) both;
}
@keyframes token-in {
  from { opacity: 0; filter: blur(3px); transform: translateY(2px); }
  to   { opacity: 1; filter: none; transform: translateY(0); }
}

/* HITL-Beat: Press-Feedback + Consumed-Settle (die Karte wird zum
 * Erledigt-Zustand, sie springt nicht dorthin). */
.chat-rc-pa-btn {
  transition: transform 100ms ease, opacity var(--m-fast) ease;
}
.chat-rc-pa-btn:active {
  transform: scale(0.96);
}
.chat-rc-pa-consumed {
  animation: pill-in var(--m-base) var(--m-ease-out) both;
}

/* Zaehler zittern nicht (Zahlen wechseln in fester Breite). */
.src-rail-summary,
.src-rail-time,
.chat-rc-pa-fields {
  font-variant-numeric: tabular-nums;
}
