/* ============================================================
   KOBOLDMAN.DE — Motion-Schicht
   ------------------------------------------------------------
   Alles hier ist REIN ADDITIV. Ohne motion.js wird keine der
   .motion-Klassen gesetzt -> die Seite sieht exakt so aus wie
   vorher. Zum Ausbauen: die zwei Tags fuer motion.css/motion.js
   aus den HTML-Seiten entfernen, fertig.

   Regeln, an die sich JEDE Animation hier haelt:
   - nur transform + opacity (compositor-safe, kein Layout-Reflow)
   - nichts, was Groesse oder Position im Fluss aendert -> CLS 0
   - Endlos-Animationen laufen nur, solange die Sektion sichtbar ist
   - prefers-reduced-motion: siehe Block M.9 am Ende

   Gliederung
   M.1  Basis
   M.2  H2-Unterstrich (hand-gezeichnet, stroke-dashoffset)
   M.3  Regionalkarte (Linien zeichnen sich, Orte poppen, Radar)
   M.4  FlowStrip (Schiene + wandernde Punkte)
   M.5  Marquee-Ticker
   M.6  Parallax-Divider
   M.7  Counter
   M.8  Reveal-Feinschliff
   M.9  Reduced Motion
   ============================================================ */


/* ============================================================
   M.1 — Basis
   ============================================================ */

/* Wird von motion.js auf <html> gesetzt. Alles unten haengt
   daran, damit ohne JS garantiert nichts versteckt bleibt. */
.motion .m-hidden{opacity:0}


/* ============================================================
   M.2 — H2-Unterstrich
   Der Pfad wird in motion.js fuer die gemessene Breite der
   LETZTEN Textzeile erzeugt (Range API), deshalb sitzt er auch
   bei mehrzeiligen und zentrierten Ueberschriften richtig.
   ============================================================ */
.motion h2.has-swoosh{position:relative}

.h2-swoosh{
  position:absolute;
  pointer-events:none;
  overflow:visible;
  z-index:0;
}
.h2-swoosh path{
  fill:none;
  stroke:var(--green);
  stroke-width:2.5;
  stroke-linecap:round;
  stroke-linejoin:round;
  opacity:.75;
  /* pathLength="1" im Markup -> eine Einheit = ganzer Pfad */
  stroke-dasharray:1;
  stroke-dashoffset:1;
}
.h2-swoosh.drawn path{
  stroke-dashoffset:0;
  transition:stroke-dashoffset .85s cubic-bezier(.65,0,.35,1);
}
/* auf dunklem Grund (wa-section) etwas kraeftiger */
.wa-section .h2-swoosh path{stroke:#5fe393; opacity:.85}


/* ============================================================
   M.3 — Regionalkarte
   Die Route-Pfade und Klassen liegen im SVG in index.html.
   ============================================================ */
/* ACHTUNG: jeder Startzustand, der etwas VERSTECKT, haengt an
   .motion (setzt motion.js auf <html>). Laeuft das Skript nicht,
   greift keine dieser Regeln und die Karte steht fertig da. */
.motion .region-map .map-grid{opacity:0; transition:opacity .6s ease}
.motion .region-map.drawn .map-grid{opacity:1}

.motion .region-map .map-range{
  opacity:0;
  transform:scale(.8);
  transform-box:fill-box;
  transform-origin:center;
  transition:opacity .7s ease .1s, transform .7s cubic-bezier(.22,.61,.36,1) .1s;
}
.motion .region-map.drawn .map-range{opacity:1; transform:scale(1)}

/* Harrys Wege — zeichnen sich von Stendal nach aussen */
.region-map .map-route{
  fill:none;
  stroke:var(--green-deep);
  stroke-width:1.4;
  stroke-linecap:round;
  opacity:.45;
}
.motion .region-map .map-route{
  stroke-dasharray:1;      /* pathLength="1" im Markup */
  stroke-dashoffset:1;
}
.motion .region-map.drawn .map-route{
  stroke-dashoffset:0;
  transition:stroke-dashoffset .8s cubic-bezier(.5,0,.5,1);
  transition-delay:var(--d, 0ms);
}

/* Orte poppen auf, sobald "ihre" Linie angekommen ist */
.motion .region-map .map-town{
  opacity:0;
  transform:scale(.2);
  transform-box:fill-box;
  transform-origin:center;
}
.motion .region-map.drawn .map-town{
  opacity:1; transform:scale(1);
  transition:opacity .35s ease, transform .45s cubic-bezier(.34,1.56,.64,1);
  transition-delay:var(--d, 0ms);
}

/* Stendal-Radar: zwei Ringe, sehr langsam, nur wenn sichtbar */
.region-map .map-pulse{
  fill:none;
  stroke:var(--green);
  stroke-width:1.5;
  opacity:0;
  transform-box:fill-box;
  transform-origin:center;
}
.region-map.live .map-pulse{
  animation:mapPulse 3.6s ease-out infinite;
  animation-delay:var(--d, 0ms);
}
@keyframes mapPulse{
  0%   {opacity:.55; transform:scale(.3)}
  70%  {opacity:.08}
  100% {opacity:0;   transform:scale(3.2)}
}


/* ============================================================
   M.4 — FlowStrip
   Wiederverwendbar: [data-flowstrip] auf einen Container setzen,
   der Knoten mit .step-num (oder [data-flow-node]) enthaelt.
   Schiene und Punkte werden von motion.js eingehaengt und exakt
   auf die Knoten-Mittelpunkte vermessen -> funktioniert in jedem
   Grid, ohne feste Spaltenzahl im CSS.
   ============================================================ */
.flow-rail{
  position:absolute;
  height:2px;
  pointer-events:none;
  z-index:1;                 /* ueber den Karten — die Nummern
                                setzt motion.js auf z-index:2 und
                                damit ueber die Schiene */
}

/* Die Linie steckt in einem eigenen Kind, weil sie per scaleX
   einlaeuft — laege der Punkt im selben Element, wuerde ihn die
   Skalierung mit in die Breite ziehen. */
.flow-rail-line{
  position:absolute; inset:0;
  border-radius:2px;
  background:linear-gradient(90deg,
    var(--green-deep) 0%, var(--green) 50%, var(--green-deep) 100%);
  opacity:.32;
  transform:scaleX(0);
  transform-origin:left center;
}
.flow-rail.drawn .flow-rail-line{
  transform:scaleX(1);
  transition:transform 1s cubic-bezier(.65,0,.35,1);
}

.flow-dot{
  position:absolute;
  top:50%; left:0;
  width:9px; height:9px;
  margin-top:-4.5px; margin-left:-4.5px;
  border-radius:50%;
  background:var(--green);
  box-shadow:0 0 0 4px rgba(95,175,45,.16);
  opacity:0;
  pointer-events:none;
}
/* .live setzt der IntersectionObserver — ausserhalb des Viewports
   laeuft nichts, das spart Akku auf dem Handy. */
.flow-rail.live .flow-dot{
  animation:flowDot 3.4s linear infinite;
  animation-delay:var(--d, 0ms);
}
@keyframes flowDot{
  0%   {opacity:0; transform:translateX(0)}
  8%   {opacity:1}
  88%  {opacity:1}
  100% {opacity:0; transform:translateX(var(--flow-w, 0px))}
}


/* ============================================================
   M.5 — Marquee-Ticker
   Markup: .ticker > .ticker-track > .ticker-item(s)
   motion.js dupliziert die Spur einmal (Klon ist aria-hidden),
   dadurch laeuft translateX(0 -> -50%) nahtlos im Kreis.
   ============================================================ */
.ticker{
  position:relative;
  overflow:hidden;
  margin-top:20px;
  /* contain:inline-size ist hier NICHT Kosmetik, sondern Pflicht:
     .ticker-track ist width:max-content. Ohne Containment meldet
     der Ticker diese Breite als min-content nach oben, ein
     Grid-Item (min-width:auto!) waechst mit — und die ganze Seite
     bekommt einen horizontalen Scrollbalken. Gemessen: 1504px
     Ueberlauf bei 1280px Viewport. overflow:hidden allein
     verhindert das nicht, es kappt nur die Darstellung. */
  contain:inline-size;
  /* weiche Kanten links/rechts statt harter Abschnitt */
  -webkit-mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.ticker-track{
  display:flex;
  align-items:center;
  gap:8px;
  width:max-content;
  will-change:transform;
}
.ticker-item{
  flex:0 0 auto;
  background:var(--paper);
  border:1px solid var(--border);
  padding:5px 12px;
  border-radius:var(--radius-full);
  font-size:.82rem;
  color:var(--ink-soft);
  white-space:nowrap;
}
.ticker-item.is-home{
  background:var(--green-soft);
  border-color:var(--green);
  color:var(--green-deep);
  font-weight:600;
}
.motion .ticker.running .ticker-track{
  animation:tickerScroll var(--speed, 46s) linear infinite;
}
/* Pause beim Drueberfahren nur mit echter Maus. Auf Touch bleibt der
   Hover-Zustand nach einem Tap haengen — das Laufband stuende dann
   still, bis man woanders hintippt. */
@media (hover:hover) and (pointer:fine){
  .ticker.running:hover .ticker-track{animation-play-state:paused}
}
.ticker.running:focus-within .ticker-track{animation-play-state:paused}
@keyframes tickerScroll{
  from{transform:translateX(0)}
  to  {transform:translateX(-50%)}
}
.ticker-note{
  margin-top:10px;
  font-size:.8rem;
  color:var(--muted);
}


/* ============================================================
   M.6 — Parallax-Divider
   Zwei Wellen-Ebenen, die beim Scrollen gegeneinander laufen.
   --p wird von motion.js gesetzt (-1 .. +1, rAF-gedrosselt).
   Kein background-attachment:fixed — das kostet auf Mobile
   messbar Frames.
   ============================================================ */
.wave-divider{
  position:relative;
  height:clamp(48px, 6vw, 84px);
  background:var(--div-from, var(--paper));
  overflow:hidden;
  line-height:0;
  --p:0;
}
.wave-divider svg{
  position:absolute;
  left:0; right:0; bottom:-20px;
  width:100%;
  height:calc(100% + 40px);   /* Reserve, damit beim Versatz
                                 unten nie eine Luecke aufreisst */
  display:block;
}
.wave-divider .wave-back{
  fill:var(--div-to, var(--cream));
  opacity:.45;
  transform:translateY(calc(var(--p) * 14px));
}
.wave-divider .wave-front{
  fill:var(--div-to, var(--cream));
  transform:translateY(calc(var(--p) * -8px));
}


/* ============================================================
   M.7 — Counter
   Zaehlt erst, wenn sichtbar. Der Zielwert steht als Text im
   HTML -> ohne JS steht dort sofort die richtige Zahl.
   ============================================================ */
.counting{font-variant-numeric:tabular-nums}


/* ============================================================
   M.8 — Reveal-Feinschliff
   Das Reveal selbst kommt aus site.js/styles.css. Hier nur
   die Sonderfaelle, die davon bisher nicht erfasst waren.
   ============================================================ */
.motion .reveal-soft{opacity:0; transform:translateY(14px)}
.motion .reveal-soft.in{
  opacity:1; transform:none;
  transition:opacity .5s ease, transform .5s cubic-bezier(.22,.61,.36,1);
  transition-delay:var(--d, 0ms);
}


/* ============================================================
   M.9 — Reduced Motion
   ------------------------------------------------------------
   WICHTIG, und der Grund fuer diesen Block:
   styles.css A.21 setzt global animation-duration:.01ms +
   animation-iteration-count:1. Fuer eine EINMALIGE Animation
   ist das richtig (sie ist sofort im Endzustand). Fuer eine
   ENDLOS-Animation ist es falsch: der Ticker springt damit
   sofort auf translateX(-50%), der Radar-Ring auf scale(3.2).
   Endlos-Animationen brauchen deshalb ein explizites
   animation:none — sonst stehen sie im Endbild statt aus zu
   sein. motion.js haengt sie zusaetzlich gar nicht erst ein.
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  .ticker.running .ticker-track,
  .region-map.live .map-pulse,
  .flow-rail.live .flow-dot{
    animation:none !important;
    transform:none !important;
  }
  .flow-dot{display:none}
  .region-map .map-pulse{opacity:0}
  .wave-divider .wave-back,
  .wave-divider .wave-front{transform:none !important}
  .ticker{
    -webkit-mask-image:none;
            mask-image:none;
  }
}
