/* ==========================================================================
   Magic Flow 8.0 — motion-v4.css (V4-Fixing, 2026-07-06)
   Spec-Punkte: B1 (CTA-Puls), A3 (Play-Puls), A7 (Tacho-Zeiger),
   A10 (Checklisten-Stagger), A12 (Strichpreis + Feature-Stagger),
   A15 (Gastgeber-Pop), A18 (Maskottchen).

   Regeln (Spec B3):
   · NUR transform / opacity / filter wird animiert (60fps-Composite).
   · Alles räumliche ist über body.mf-motion gegated (setzt js/motion.js
     nur OHNE prefers-reduced-motion); bei reduced-motion bleiben reine
     Opacity-Fades (body.mf-motion-soft) + Endzustände ("reduce, not
     remove", vgl. main.css §17b). Ohne JS ist alles statisch sichtbar.
   · Checkmark-Mechanik nach Live-Referenz magiccreationretreat.com
     (QA/v4/REFERENZEN.md §1): IO pro Gruppe, Stagger ~150ms, Haken
     poppt nach dem Zeilen-Fade ein (bei uns veredelt mit Overshoot).
   ========================================================================== */

/* --------------------------------------------------------------------------
   B1 — Primär-CTAs: permanenter Puls (Scale 1→1.03) + Gold-Glow-Atmung ~3.2s
   Gilt für ALLE .mf-btn (Her mit meinem Ticket / Ja! Ich bin bereit! /
   Zur Ticketauswahl / Exit-Popup) UND die Ticket-Karten-CTAs.
   -------------------------------------------------------------------------- */
@keyframes mf-cta-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.03); }
}
@keyframes mf-cta-glow {
  0%, 100% { opacity: 0.18; }
  50% { opacity: 1; }
}
body.mf-motion .mf-btn:not(.mf-btn--ghost) {
  animation: mf-cta-breathe 3.2s ease-in-out infinite;
}
/* Hover/Fokus/Tap: Puls pausiert, damit die Hover-States (Lift/Active)
   sauber greifen — danach atmet der Button weiter. */
body.mf-motion .mf-btn:not(.mf-btn--ghost):hover,
body.mf-motion .mf-btn:not(.mf-btn--ghost):focus-visible,
body.mf-motion .mf-btn:not(.mf-btn--ghost):active {
  animation: none;
}

/* Ticket-Karten-CTA "> Her mit Meinem Ticket <" — gleiche Gold-Familie,
   gleicher Puls (Scale minimal kleiner: der CTA ist ein vollbreiter
   Kartenbalken). Glow als Overlay (nur opacity). */
.mf-ticket__cta { position: relative; }
.mf-ticket__cta::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  box-shadow: 0 0 26px 7px rgba(251, 194, 1, 0.4);
  opacity: 0;
  pointer-events: none;
}
@keyframes mf-cta-breathe-bar {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.02); }
}
body.mf-motion .mf-ticket__cta {
  animation: mf-cta-breathe-bar 3.2s ease-in-out infinite;
}
body.mf-motion .mf-ticket__cta::after {
  animation: mf-cta-glow 3.2s ease-in-out infinite;
}
body.mf-motion .mf-ticket:hover .mf-ticket__cta,
body.mf-motion .mf-ticket:focus-visible .mf-ticket__cta {
  animation: none;
}

/* --------------------------------------------------------------------------
   A3 — Video-Play-Buttons: deutlicher Puls (Scale + Glow), ~2.6s.
   .is-inview setzt js/motion.js (initIdlePulse) nur im Viewport und nur
   ohne reduced-motion.
   -------------------------------------------------------------------------- */
@keyframes mf-play-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.12); }
}
@keyframes mf-play-glow {
  0%, 100% { opacity: 0.12; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.12); }
}
body.mf-motion .mf-video__btn.is-inview .mf-video__play {
  animation: mf-play-breathe 2.6s ease-in-out infinite;
}
body.mf-motion .mf-video__btn.is-inview .mf-video__play::after {
  animation: mf-play-glow 2.6s ease-in-out infinite;
}
body.mf-motion .mf-video__btn:hover .mf-video__play,
body.mf-motion .mf-video__btn:focus-visible .mf-video__play {
  animation: none;
}

/* --------------------------------------------------------------------------
   A10/A12 — Sequentieller Stagger ([data-stagger], js initStagger):
   Zeile faded + steigt ein, Haken/Kreuz poppt danach mit Overshoot.
   Gruppen: .mf-checklist (NICHTS/NUR-Karten, 150ms) und
   .mf-ticket__features (Karten-Featurelisten, 100ms).
   -------------------------------------------------------------------------- */
[data-stagger] > * {
  transition:
    opacity 0.55s var(--mf-ease-out),
    transform 0.55s var(--mf-ease-out);
}
body.mf-motion [data-stagger] > *:not(.is-on) {
  opacity: 0;
  transform: translateY(14px);
}
/* reduced-motion: reiner Opacity-Fade, keine Translation */
body.mf-motion-soft [data-stagger] > *:not(.is-on) { opacity: 0; }

/* Haken (grün) / Kreuz (rot) der Fit-Karten poppt NACH der Zeile ein —
   Referenz macht nur ein Opacity-Fade, wir veredeln mit Scale-Overshoot. */
body.mf-motion .sec-werte__fitcard .mf-checklist li::before {
  transform: scale(0);
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.18s;
}
body.mf-motion .sec-werte__fitcard .mf-checklist li.is-on::before {
  transform: scale(1);
}

/* --------------------------------------------------------------------------
   A12 — Strichpreis-Animation + Preis-Pop (Ticket-Karten).
   V4.1 (Jonas-Review 2026-07-07): NUR NOCH MOBIL (max-width 767px) —
   auf Desktop ist die Zeichnen-Animation komplett zurückgebaut, dort steht
   das rote Original-Kreuz statisch und sofort sichtbar (sections.css).
   V4.1-Geometrie-Fix: transform-origin bleibt CENTER (Default) statt
   'left center' — mit Links-Pivot lag die rotierte Linie um ~0.125×Breite
   über der Ziffernmitte („komplett verfehlt", Jonas). Mit Center-Pivot
   wächst der Strich aus der Preis-Mitte heraus und endet EXAKT auf der
   statischen Original-Geometrie (rotate ±14deg durch die Ziffernmitte,
   alle 3 Karten).
   Die Karte selbst staggert via data-reveal(-group) (--reveal-delay je
   Karte, 140ms) — Strich + Pop hängen sich mit festen Offsets dahinter:
   Karte erscheint → Strich zeichnet sich durch 347€/797€/1666€
   → neuer Preis poppt mit Gold-Glow.
   -------------------------------------------------------------------------- */
@media (max-width: 767px) {
  body.mf-motion .mf-ticket__strike::before,
  body.mf-motion .mf-ticket__strike::after {
    transition: transform 0.55s var(--mf-ease-out);
  }
  body.mf-motion .mf-ticket .mf-ticket__strike::before { transform: rotate(14deg) scaleX(0); }
  body.mf-motion .mf-ticket .mf-ticket__strike::after { transform: rotate(-14deg) scaleX(0); }
  body.mf-motion .mf-ticket.is-visible .mf-ticket__strike::before {
    transform: rotate(14deg) scaleX(1);
    transition-delay: calc(var(--reveal-delay, 0s) + 0.6s);
  }
  body.mf-motion .mf-ticket.is-visible .mf-ticket__strike::after {
    transform: rotate(-14deg) scaleX(1);
    transition-delay: calc(var(--reveal-delay, 0s) + 0.85s);
  }
  body.mf-motion .mf-ticket.is-visible .mf-ticket__price {
    animation: mf-price-pop 0.7s var(--mf-ease-out) both;
    animation-delay: calc(var(--reveal-delay, 0s) + 1.15s);
  }
}
@keyframes mf-price-pop {
  0% { transform: scale(1); filter: none; }
  45% { transform: scale(1.22); filter: drop-shadow(0 0 16px rgba(251, 194, 1, 0.9)); }
  100% { transform: scale(1); filter: drop-shadow(0 0 7px rgba(251, 194, 1, 0.45)); }
}

/* --------------------------------------------------------------------------
   A7 — Tacho: DOM-Zeiger schwingt beim Einscrollen von 0% (−90°) mit
   Überschwingen auf die soldPercent-Position (Winkel = % × 1.8° − 90°).
   --mf-sold-percent setzt render.js auf der Sektion — EINZIGE Quelle
   ist config.tickets.soldPercent. .is-on setzt js initGauge (IO, once).
   Zeiger-Optik dem Original-Tacho nachempfunden (dunkler Kegel, Pivot in
   der Gold-Nabe des Zeiger-frei generierten Basisbilds).
   -------------------------------------------------------------------------- */
.mf-gauge { position: relative; }
.mf-gauge__img { width: 100%; }
.mf-gauge__needle {
  position: absolute;
  left: 45.5%;
  top: 15.5%;
  width: 9%;
  height: 43%;
  clip-path: polygon(50% 0%, 88% 97%, 66% 100%, 34% 100%, 12% 97%);
  background: linear-gradient(180deg, #2b2014 0%, #4a3722 55%, #2a1d10 100%);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
  transform: rotate(-90deg); /* Start: 0% (linkes Skalenende) */
  transform-origin: 50% 114%; /* Pivot = Naben-Mitte (y≈64.5% des Bilds) */
}
@keyframes mf-needle-swing {
  0% { transform: rotate(-90deg); }
  60% { transform: rotate(calc(var(--mf-sold-percent, 0) * 1.8deg - 81deg)); }
  80% { transform: rotate(calc(var(--mf-sold-percent, 0) * 1.8deg - 93.5deg)); }
  100% { transform: rotate(calc(var(--mf-sold-percent, 0) * 1.8deg - 90deg)); }
}
.mf-gauge.is-on .mf-gauge__needle {
  animation: mf-needle-swing 1.9s cubic-bezier(0.33, 0.85, 0.4, 1) 0.15s forwards;
  /* reduced-motion: globales duration-Override (main.css) lässt die
     Animation sofort auf dem 100%-Frame enden → Zeiger steht korrekt. */
}

/* --------------------------------------------------------------------------
   A15 — Gastgeber: Reveal-Variante 'pop' (Stats poppen mit Overshoot,
   gestaffelt via --reveal-delay; Count-Up läuft parallel via motion.js).
   -------------------------------------------------------------------------- */
[data-reveal='pop'] {
  transform: translateY(14px) scale(0.82);
  transition-duration: 0.65s;
  transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* --------------------------------------------------------------------------
   A18 — Maskottchen (Rochen "Flap", Oktopus, Steampunk-Magier): kurzes
   Zucken beim Einscrollen, danach dezenter Float-Loop. IO-getriggert
   (.is-inview, js initMascots), nur transform, nur body.mf-motion.
   -------------------------------------------------------------------------- */
@keyframes mf-mascot-wiggle {
  0% { transform: rotate(0deg) translateY(0); }
  22% { transform: rotate(-3deg) translateY(-3px); }
  48% { transform: rotate(2.4deg) translateY(-1px); }
  72% { transform: rotate(-1.4deg) translateY(-2px); }
  100% { transform: rotate(0deg) translateY(0); }
}
@keyframes mf-mascot-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  30% { transform: translateY(-6px) rotate(-1.6deg); }
  65% { transform: translateY(-2px) rotate(1.3deg); }
}
body.mf-motion .mf-mascot.is-inview {
  animation:
    mf-mascot-wiggle 1.1s ease-out,
    mf-mascot-float 7s ease-in-out 1.1s infinite;
}
/* leichte Phasen-Varianz, damit die drei Proof-Illustrationen nicht
   synchron schaukeln */
body.mf-motion .sec-proof__item:nth-child(2) .mf-mascot.is-inview {
  animation-duration: 1.1s, 8.2s;
}
body.mf-motion .sec-proof__item:nth-child(3) .mf-mascot.is-inview {
  animation-duration: 1.1s, 6.4s;
}

/* --------------------------------------------------------------------------
   Reduced Motion — Ergänzungen zu main.css §17b (dort: globales
   duration/iteration-Override). Hier nur explizite Kill-Switches für die
   neuen Loops, damit nichts dauerhaft weiterläuft.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  body.mf-motion .mf-btn:not(.mf-btn--ghost),
  body.mf-motion .mf-ticket__cta,
  body.mf-motion .mf-video__btn.is-inview .mf-video__play,
  body.mf-motion .mf-mascot.is-inview { animation: none !important; }
  [data-reveal='pop'] { transform: none !important; }
  body.mf-motion-soft [data-stagger] > * {
    transition: opacity 0.6s ease !important;
  }
}
