/*
   TenderToGo Motion Layer
   ------------------------------------------------------------------
   Zentrales Bewegungs-System fuer die gesamte Applikation.

   Prinzip (nach apple-design / HIG-Motion):
     * Jede Aenderbarkeit ist unterbrochen und verlaeuft kontinuierlich.
     * NUR transform + opacity (GPU-Kompositing) -- kein Layout, kein Paint.
     * Kurz und ruhig: UI-Elemente < 300 ms, kein Overshoot in der Routine.
     * Reduced-Motion wird respektiert: Bewegung wird zu einem leisen
       Crossfade, Farben und Zustand bleiben erhalten.

   Diese Datei aendert KEINEN visuellen Zustand -- sie gibt dem Bestehenden
   ein Fluss-Gefuehl: Seiten erscheinen weich statt hart zu wechseln,
   Listen "steigen" gestaffelt ein, Druck-Feedback ist sofort.
*/

/* === Motion-Tokens === */
:root {
    --motion-ease-out: cubic-bezier(0.23, 1, 0.32, 1);   /* Ein- und Ausblendung */
    --motion-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); /* Bewegung im Bild */
    --motion-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);  /* Panel / Slideover */

    --motion-duration-fast: 140ms;
    --motion-duration: 200ms;
    --motion-duration-slow: 280ms;
    --motion-duration-panel: 320ms;

    --motion-stagger: 45ms;
    --motion-rise: 14px;
}

/* === Seitenwechsel (MPA) ===
   Der Browser blendet von der alten zur neuen Seite ueber (Cross-Document
   View Transition), die neue steigt dabei leicht auf. Anders als eine
   Eintritts-Animation am Inhalt steht die neue Seite sofort vollstaendig und
   sichtbar im DOM -- nichts parkt bei opacity 0, bis eine Animation laeuft
   (U4, U5, U7, U8: sichtbar, sobald die Seite geladen ist). Die Navigation
   ist eine eigene Ebene und bleibt stehen, statt mit ueberzublenden.
   Browser ohne View Transitions wechseln ohne Ueberblendung. */
@view-transition {
    navigation: auto;
}
.navbar-modern {
    view-transition-name: tg-navigation;
}
::view-transition-old(root) {
    animation: motion-page-out var(--motion-duration) var(--motion-ease-out) both;
}
::view-transition-new(root) {
    animation: motion-page-in var(--motion-duration-slow) var(--motion-ease-out) both;
}

@keyframes motion-page-in {
    from { opacity: 0; transform: translateY(var(--motion-rise)); }
    to   { opacity: 1; transform: none; }
}
@keyframes motion-page-out {
    to { opacity: 0; }
}
@keyframes motion-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* === Press-Feedback: das Interface antwortet SOFORT auf den Finger ===
   Ein hauchdunnes Zusammendruecken, solange der Knopf gedrueckt ist.

   WICHTIG: Hier wird bewusst KEINE transition-Regel gesetzt. Fast alle
   Komponenten haben eigene Transitions (teilweise "all"), und eine
   spaetere, engere Regel wuerde die bestehenden Hover-Farbuebergaenge
   aendern oder loeschen. Wo transform Teil der bestehenden Transition
   ist ("all 0.15s" & Co.), animiert der Press-Effekt automatisch mit;
   sonst wirkt er sofort -- beides ist das gewollte "antwortet sofort". */
.btn:active, .tg-btn:active, .tg-suche-tab:active, .tg-suche-page-btn:active,
.tg-suche-action-btn:active, .tg-treffer-action-btn:active,
.tg-notice-icon-btn:active, .tg-admin-nav-link:active,
.btn-cta-nav:active, .nav-link-modern:active, .user-dropdown-trigger:active,
.tg-suche-search-btn:active, .dropdown-item:active,
.tg-suche-empty-btn:active, .tg-suche-dropdown-apply:active,
.tg-suche-dropdown-reset:active, .tg-pipeline-card:active {
    transform: scale(0.97);
}

/* === Karten: weicher Press, bestehender Hover-Lift bleibt erhalten ===
   Die Karten tragen eigene :hover-Regeln (translateY-Lift) in global.css
   bzw. in den Templates, die in der Kaskade NACH motion.css sitzen und bei
   gleicher Spezifitaet gewinnen. Damit der Press-Zustand zuverlaessig wirkt
   (besonders waehrend auf Desktop gedrueckt UND gehovert wird), wird hier die
   Spezifitaet mit verdoppelter Klassenangabe erhoht. */
.tg-suche-card.tg-suche-card:active, .ticket-card.ticket-card:active,
.tg-treffer.tg-treffer:active, .tg-card.tg-card:active,
.stat-card-item.stat-card-item:active, .tg-stat-card.tg-stat-card:active,
.tg-vergaben-card.tg-vergaben-card:active, .member-card.member-card:active,
.tg-pipeline-card.tg-pipeline-card:active {
    transform: scale(0.995);
}

/* === Gestaffelter Listeneintritt (async geladene Reihen) ===
   Ein Container bekommt die Klasse `.motion-stagger`, dann steigen seine
   direkten Kinder nacheinander ein. Max. 8 Stufen, damit der Schwanz nie
   auf sich warten laesst. Interaktion wird dadurch NIE blockiert. */
/* Fill-Modus "backwards": waehrend der Verzögerung jedes Elements sitzt es
   im from-Zustand (unsichtbar), und nach dem Abklingen faellt es in seinen
   NATUERLICHEN Stil zurueck. Das ist entscheidend: wuerde man "forwards"
   waehlen, behielte die Karte die Keyframe-Transformation translateY(0) und
   diese ueberschriebe den eigenen :hover-Lift (translateY(-2px)) -- der
   Hover-Effekt wuerde still und leise sterben. */
.motion-stagger > * {
    animation: motion-rise var(--motion-duration-slow) var(--motion-ease-out) backwards;
}
.motion-stagger > *:nth-child(1)  { animation-delay: 0ms; }
.motion-stagger > *:nth-child(2)  { animation-delay: calc(var(--motion-stagger) * 1); }
.motion-stagger > *:nth-child(3)  { animation-delay: calc(var(--motion-stagger) * 2); }
.motion-stagger > *:nth-child(4)  { animation-delay: calc(var(--motion-stagger) * 3); }
.motion-stagger > *:nth-child(5)  { animation-delay: calc(var(--motion-stagger) * 4); }
.motion-stagger > *:nth-child(6)  { animation-delay: calc(var(--motion-stagger) * 5); }
.motion-stagger > *:nth-child(7)  { animation-delay: calc(var(--motion-stagger) * 6); }
.motion-stagger > *:nth-child(8)  { animation-delay: calc(var(--motion-stagger) * 7); }
.motion-stagger > *:nth-child(n+9) { animation-delay: calc(var(--motion-stagger) * 8); }

@keyframes motion-rise {
    from { opacity: 0; transform: translateY(var(--motion-rise)); }
    to   { opacity: 1; transform: none; }
}

/* Fade-only-Variante (z.B. Tabellensaetze: viel Inhalt, keine Vertikal-
   Bewegung -- nur ein ruhiges Einblenden, eng gestaffelt). */
.motion-stagger--fade > * {
    transform: none;
    animation-name: motion-fade-in;
    animation-duration: 200ms;
    --motion-stagger: 25ms;
}

/* === Slideover: den bestehenden Slide mit der Drawer-Kurve veredeln ===
   .tg-slideover und -overlay haben in global.css ihre eigene Transition.
   Hier nur die Kurve vereinheitlichen (keine Dauer-/Huegel-Aenderung). */
.tg-slideover {
    transition: transform var(--motion-duration-panel) var(--motion-ease-drawer);
}
/* Overlay: beim Schliessen wartet visibility 0s-Delay auf den Opacity-Fade.
   Ohne das Delay verschwindet der Dimming-Vorhang abrupt im ersten Frame
   (die Grundregel in global.css hat keine visibility-Transition). */
.tg-slideover-overlay {
    transition: opacity var(--motion-duration-panel) var(--motion-ease-out),
                visibility 0s linear var(--motion-duration-panel);
}
.tg-slideover-overlay.active {
    transition: opacity var(--motion-duration-panel) var(--motion-ease-out),
                visibility 0s;
}
/* Der eingelesene Panel-Inhalt blendet einmalig mit ein, damit er nicht
   hart "poppt", waehrend das Panel gleitet. */
.tg-slideover-body [data-motion-panel-in] {
    animation: motion-fade-in var(--motion-duration) var(--motion-ease-out) both;
}

/* === Toasts: die drei Toast-Typen der App (Suche, Merkliste, Detail)
   uebernehmen eigene Transitions in ihren Templates, die in der Kaskade
   NACH motion.css sitzen. Fuer Reduzierte Bewegung muessen wir sie also
   mit !important uebersteuern und dabei die EIGENE Position jedes Toasts
   erhalten (z.B. translate(-50%) fuer die Zentrierung des Suche-Toast).
   Ergebnis: Toasts erscheinen an Ort und Stelle per Opacity-Fade,
   ohne vertikale Verschiebung. */
@media (prefers-reduced-motion: reduce) {
    .tg-suche-toast, .tg-suche-toast.show {
        transform: translate(-50%, 0) !important;
        transition: opacity var(--motion-duration) ease !important;
    }
    .tg-merkliste-toast, .tg-merkliste-toast.show,
    .toast-notification, .toast-notification.show {
        transform: translateY(0) !important;
        transition: opacity var(--motion-duration) ease !important;
    }
}

/* === Flash-Meldungen: weiches Einblenden ===
   Bewusst opacity-only: Alerts koennen selbst transform-Positionierung
   tragen (z.B. translateX(-50%) fuer zentrierte Meldungen) -- eine
   transform-Animation mit Fill wuerde die Position dauerhaft ueberschreiben.
   "backwards" laesst das Element nach dem Einblenden vollstaendig in den
   natuerlichen Kaskaden-Zustand rueckfallen (auch Bootstrap-Dismissal). */
.alert {
    animation: motion-alert-in var(--motion-duration-panel) var(--motion-ease-out) backwards;
}
@keyframes motion-alert-in {
    from { opacity: 0; }
}

/* ====================================================================
   REDUCED MOTION
   Bewegung wird zum leisen Crossfade; Farben und Zustaege bleiben.
   ==================================================================== */
@media (prefers-reduced-motion: reduce) {
    /* Seitenwechsel: nur ein kurzes Ueberblenden, kein Aufsteigen. */
    ::view-transition-old(root), ::view-transition-new(root) {
        animation: motion-fade-in 160ms ease both;
    }
    ::view-transition-old(root) { animation-name: motion-page-out; }

    .motion-stagger > *,
    .tg-slideover-body [data-motion-panel-in],
    .pipeline-panel, .pipeline-complete-message, .complete-icon {
        animation: motion-fade-in 160ms ease both;
    }

    /* Positionsbewegung komplett aus, Crossfade bleibt. */
    .motion-stagger > * { transform: none; }

    /* Press-Scale entfaellt -- der Zustandwechsel bleibt sofort sichtbar. */
    .btn:active, .tg-btn:active, .tg-suche-tab:active, .tg-suche-page-btn:active,
    .tg-suche-action-btn:active, .tg-treffer-action-btn:active,
    .tg-notice-icon-btn:active, .tg-admin-nav-link:active,
    .btn-cta-nav:active, .nav-link-modern:active, .user-dropdown-trigger:active,
    .tg-suche-search-btn:active, .dropdown-item:active,
    .tg-suche-empty-btn:active, .tg-suche-dropdown-apply:active,
    .tg-suche-dropdown-reset:active,
    .tg-suche-card.tg-suche-card:active, .ticket-card.ticket-card:active,
    .tg-treffer.tg-treffer:active, .tg-card.tg-card:active,
    .stat-card-item.stat-card-item:active, .tg-stat-card.tg-stat-card:active,
    .tg-vergaben-card.tg-vergaben-card:active, .member-card.member-card:active,
    .tg-pipeline-card.tg-pipeline-card:active {
        transform: none;
    }

    /* Slideover ohne Slide: nur Crossfade -- aber das fixed Panel darf,
       waehrend es unsichtbar ist, nicht die Seite abdecken (es wuerde
       Pointer- und Tastaturinput abfangen). visibility + pointer-events
       folgen dem Fade: beim Oeffnen sofort sichtbar, beim Schliessen
       erst nach der Dauer unsichtbar. */
    .tg-slideover {
        transition: opacity var(--motion-duration) ease,
                    visibility 0s linear var(--motion-duration),
                    pointer-events 0s linear var(--motion-duration);
        transform: none;
    }
    .tg-slideover:not(.active) { opacity: 0; visibility: hidden; pointer-events: none; }
    .tg-slideover.active {
        opacity: 1; visibility: visible; pointer-events: auto;
        transition: opacity var(--motion-duration) ease, visibility 0s;
    }

    /* Gleiche Kur fuer die Overlay: im Normalmodus blendet die visibility
       sofort, weil sie in global.css nur opacity ueberträgt -- dadurch
       verschwindet der Dimming-Vorhang abrupt. Hier symmetry erhalten. */
    .tg-slideover-overlay {
        transition: opacity var(--motion-duration) ease,
                    visibility 0s linear var(--motion-duration);
    }
    .tg-slideover-overlay.active {
        transition: opacity var(--motion-duration) ease, visibility 0s;
    }
}
