/* AGENCY — Bewegung
 *
 * Gegenstück zu assets/motion.js. Hier steht, wie sich etwas bewegt; dort
 * steht, wann. Die Trennung hat einen Grund: ohne JavaScript soll die Seite
 * vollständig und fertig aussehen, nicht halb aufgebaut. Deshalb ist der
 * Ausgangszustand jeder Animation an eine Klasse gebunden, die das Skript
 * setzt — nie an das Element selbst.
 *
 * Am Ende der Datei schaltet ein einziger Block alles ab, was sich bewegt,
 * und zwar in den fertigen Zustand.
 */

/* ── Einlaufen ─────────────────────────────────────────────────────────── */

.rv{
  opacity:0;
  transform:translate3d(0,16px,0);
  transition:opacity .55s cubic-bezier(.22,.61,.36,1),
             transform .6s cubic-bezier(.22,.61,.36,1);
  transition-delay:var(--d,0ms);
  will-change:opacity, transform;
}
.rv.in{ opacity:1; transform:none; will-change:auto }

/* Nach dem Einlaufen darf will-change wieder weg — ein Dutzend dauerhaft
   beförderter Ebenen kostet mehr, als die Animation je einbringt. */

/* Versetzte Kinder. Der Abstand kommt aus dem Skript als --d. */
.stagger > *, [data-stagger] > *{
  opacity:0;
  transform:translate3d(0,12px,0);
  transition:opacity .5s ease var(--d,0ms), transform .5s cubic-bezier(.22,.61,.36,1) var(--d,0ms);
}
.stagger.in > *, [data-stagger].in > *{ opacity:1; transform:none }

/* Seitwärts, für Zeilen in einer Rangliste: sie schieben sich ein, als würde
   die Liste sich gerade sortieren. */
.rv-x{ opacity:0; transform:translate3d(-10px,0,0) }
.rv-x.in{ opacity:1; transform:none;
  transition:opacity .45s ease var(--d,0ms), transform .45s cubic-bezier(.22,.61,.36,1) var(--d,0ms) }

/* ── Balken ────────────────────────────────────────────────────────────── */

/* Die Zielbreite steht als --w im Markup; ohne Skript ist der Balken sofort
   fertig, mit Skript wächst er einmal dorthin. */
[data-grow]{ width:var(--w,0%) }
@media (prefers-reduced-motion:no-preference){
  [data-grow]{ width:0; transition:width .85s cubic-bezier(.22,.61,.36,1) var(--d,0ms) }
  [data-grow].grown{ width:var(--w,0%) }
}

/* ── Zeiger ────────────────────────────────────────────────────────────── */

/* Ein sehr schwaches Licht dort, wo der Zeiger steht. Es liegt hinter dem
   Inhalt und fängt keine Klicks ab. */
.card, .card2, .panel, .step{ position:relative }
.card::after, .card2::after, .panel::after, .step::after{
  content:'';
  position:absolute; inset:0; z-index:0;
  border-radius:inherit;
  pointer-events:none;
  opacity:0;
  transition:opacity .3s ease;
  background:radial-gradient(340px circle at var(--mx,50%) var(--my,50%),
                             color-mix(in srgb, var(--accent) 9%, transparent), transparent 62%);
}
.card:hover::after, .card2:hover::after, .panel:hover::after, .step:hover::after{ opacity:1 }
.card > *, .card2 > *, .panel > *, .step > *{ position:relative; z-index:1 }

/* ── Anheben ───────────────────────────────────────────────────────────── */

.lift{ transition:transform .22s cubic-bezier(.22,.61,.36,1), box-shadow .22s, border-color .22s }
.lift:hover{ transform:translateY(-3px); box-shadow:0 12px 30px -14px rgba(0,0,0,.42) }
.lift:active{ transform:translateY(-1px); transition-duration:.08s }

/* ── Knöpfe ────────────────────────────────────────────────────────────── */

/* Ein Knopf, der beim Klicken nicht nachgibt, fühlt sich an, als sei nichts
   passiert. Zwei Pixel reichen dafür. */
.btn{ transition:transform .12s cubic-bezier(.22,.61,.36,1), background .18s, border-color .18s, color .18s }
.btn:active{ transform:translateY(1px) scale(.985) }
.btn.is-ok{ border-color:var(--pos); color:var(--pos) }

/* Der Hauptknopf bekommt beim Überfahren ein wanderndes Licht — das einzige
   Element auf der Seite, das um Aufmerksamkeit bittet, also darf es das. */
.btn-primary{ position:relative; overflow:hidden }
.btn-primary::before{
  content:''; position:absolute; inset:0;
  transform:translateX(-120%);
  background:linear-gradient(100deg, transparent 20%,
             color-mix(in srgb, #fff 26%, transparent) 50%, transparent 80%);
  pointer-events:none;
}
.btn-primary:hover::before{ animation:btn-sheen .75s ease-out }
@keyframes btn-sheen{ to{ transform:translateX(120%) } }

/* ── Fortschritt ───────────────────────────────────────────────────────── */

.scroll-prog{
  position:fixed; top:0; left:0; right:0; height:2px; z-index:90;
  background:linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 40%, var(--s2, var(--accent))));
  transform:scaleX(0); transform-origin:0 50%;
  pointer-events:none;
}

/* ── Kopfzeile ─────────────────────────────────────────────────────────── */

header.site{ transition:background .28s ease, border-color .28s ease, backdrop-filter .28s ease }
header.site.stuck{
  background:color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter:saturate(1.5) blur(12px);
  -webkit-backdrop-filter:saturate(1.5) blur(12px);
  border-bottom-color:var(--line);
}
header.site .inner{ transition:padding .28s ease }
header.site.stuck .inner{ padding-top:9px; padding-bottom:9px }

/* ── Aufschlag ─────────────────────────────────────────────────────────── */

@keyframes fl-up{ from{ background:var(--pos-wash) } to{ background:transparent } }
@keyframes fl-dn{ from{ background:var(--neg-wash) } to{ background:transparent } }
.fl-up{ animation:fl-up .6s ease-out }
.fl-dn{ animation:fl-dn .6s ease-out }

/* ── Puls ──────────────────────────────────────────────────────────────── */

/* Für alles, was gerade wirklich läuft: ein Ring, der einmal pro Takt
   nach außen läuft. Er sagt „hier kommt etwas an", und das ist auf einer
   Seite mit einem Live-Feed die wichtigste Auskunft überhaupt. */
@keyframes ring{
  0%{ box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent) }
  70%{ box-shadow:0 0 0 9px transparent }
  100%{ box-shadow:0 0 0 0 transparent }
}
.pulse{ animation:ring 2.2s ease-out infinite }

/* ── Zustandswechsel ───────────────────────────────────────────────────── */

/* Wenn ein Agent seine Haltung ändert, soll man es sehen, ohne hinzusehen. */
@keyframes state-in{
  from{ opacity:0; transform:translate3d(0,-6px,0) }
  to{ opacity:1; transform:none }
}
.state-changed{ animation:state-in .4s cubic-bezier(.22,.61,.36,1) }

/* ── Skelett ───────────────────────────────────────────────────────────── */

/* Solange nichts da ist, ein wanderndes Grau statt eines leeren Kastens —
   das liest sich als „lädt" und nicht als „kaputt". */
@keyframes shimmer{ from{ background-position:-180% 0 } to{ background-position:180% 0 } }
.skel{
  border-radius:6px;
  background:linear-gradient(90deg, var(--surface-2) 25%,
             color-mix(in srgb, var(--line) 55%, var(--surface-2)) 45%, var(--surface-2) 65%);
  background-size:220% 100%;
  animation:shimmer 1.5s linear infinite;
  color:transparent;
}

/* ── Abschaltung ───────────────────────────────────────────────────────── */

/* Wer Bewegung abbestellt hat, bekommt keine — und landet im Endzustand,
   nicht in einem halb aufgebauten. Das ist der Grund, warum hier opacity
   und transform ausdrücklich zurückgesetzt werden statt nur die Animation
   abzuschalten. */
@media (prefers-reduced-motion:reduce){
  .rv, .rv.in, .rv-x, .rv-x.in,
  .stagger > *, [data-stagger] > *{
    opacity:1 !important; transform:none !important; transition:none !important;
  }
  [data-grow]{ width:var(--w,0%) !important; transition:none !important }
  .lift:hover, .btn:active{ transform:none }
  .btn-primary::before{ display:none }
  .card::after, .card2::after, .panel::after, .step::after{ display:none }
  .pulse, .skel, .fl-up, .fl-dn, .state-changed{ animation:none !important }
  .scroll-prog{ display:none }
  header.site .inner, header.site{ transition:none }
}

/* ── Live-Protokoll ────────────────────────────────────────────────────── */

/* Eine gerade eingetroffene Entscheidung schiebt sich von oben herein und
   ist für einen Moment unterlegt. Sie zu übersehen ist das Einzige, was in
   diesem Panel wirklich schadet — es ist der Beweis, dass etwas läuft. */
@keyframes lv-new{
  0%{ opacity:0; transform:translate3d(0,-8px,0);
      background:color-mix(in srgb, var(--accent) 13%, transparent) }
  55%{ opacity:1; transform:none }
  100%{ background:transparent }
}
.lv-new{ animation:lv-new .85s cubic-bezier(.22,.61,.36,1) }

@media (prefers-reduced-motion:reduce){ .lv-new{ animation:none } }

/* ── Kein Aufblitzen beim Laden ─────────────────────────────────────────── */

/* theme-boot.js setzt .no-anim aufs <html>, bis zwei Frames gezeichnet
   sind. Ohne das animiert die Seite beim Laden aus ihrer Standardfarbe in
   die gespeicherte — und wer Dunkel eingestellt hat, sieht bei jedem
   Aufruf erst Weiß. */
.no-anim, .no-anim *, .no-anim *::before, .no-anim *::after{
  transition:none !important;
  animation:none !important;
}

/* ── Neigung zum Zeiger ────────────────────────────────────────────────── */

/* Die Perspektive sitzt am Elternteil, nicht am Element selbst: So kippt die
   Fläche um ihre eigene Mitte statt zu schrumpfen, und Kindelemente behalten
   ihre Schärfe. Der Übergang ist kurz genug, dass es der Bewegung folgt, und
   lang genug, dass es nicht zittert. */
.console, .hero-fig, .fig-wrap{
  transform:perspective(1200px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transform-style:preserve-3d;
  transition:transform .5s cubic-bezier(.22,.61,.36,1);
  will-change:auto;
}
.console.tilting, .hero-fig.tilting, .fig-wrap.tilting{
  transition:transform .12s ease-out;
  will-change:transform;
}

@media (prefers-reduced-motion:reduce){
  .console, .hero-fig, .fig-wrap{transform:none; transition:none}
}

/* ── Treibende Formen in den dunklen Bändern ───────────────────────────── */

.orb{
  position:absolute; border-radius:50%; pointer-events:none;
  filter:blur(58px); opacity:.5;
  /* Die Formen liegen HINTER dem Raster: Sie sollen die Fläche tönen, nicht
     die Linien überdecken. */
  z-index:-1;
  animation:orb-drift linear infinite;
  animation-duration:calc(46s + var(--i, 0) * 11s + var(--h, 0) * 7s);
  animation-delay:calc(var(--i, 0) * -13s - var(--h, 0) * -5s);
}
.orb-1{width:min(46vw,540px); aspect-ratio:1; left:-8%;  top:6%;
  background:radial-gradient(circle, color-mix(in srgb, var(--accent) 26%, transparent), transparent 68%)}
.orb-2{width:min(38vw,440px); aspect-ratio:1; right:-6%; top:32%;
  background:radial-gradient(circle, color-mix(in srgb, var(--s3, var(--accent)) 24%, transparent), transparent 68%)}
.orb-3{width:min(30vw,360px); aspect-ratio:1; left:38%;  bottom:-12%;
  background:radial-gradient(circle, color-mix(in srgb, var(--s1, var(--accent)) 22%, transparent), transparent 68%)}

/* Eine lange, flache Schleife statt eines Kreises: Die Form soll wandern,
   nicht offensichtlich rotieren. */
@keyframes orb-drift{
  0%   {transform:translate3d(0,0,0) scale(1)}
  25%  {transform:translate3d(6vw,-3vh,0) scale(1.09)}
  50%  {transform:translate3d(2vw,5vh,0) scale(.96)}
  75%  {transform:translate3d(-5vw,2vh,0) scale(1.05)}
  100% {transform:translate3d(0,0,0) scale(1)}
}

.grid-bg{isolation:isolate}

@media (prefers-reduced-motion:reduce){
  .orb{display:none}
}
