/* ============================================================
   PERSONAL OS — DIE BEWEGUNG.  Fassung v34 (24.08.2026)

   DIE EINZIGE DATEI IM PROJEKT, IN DER `transition`, `animation` ODER
   `@keyframes` STEHEN DARF. `js/pruefen.test.js` besteht darauf.

   Warum an einem Ort: Am 24.08.2026 wurde ALLE Bewegung aus dieser App
   zurueckgebaut, und der Grund war gut. Diese App baut bei jeder Handlung
   die ganze Huelle neu (`app/anstrich.js`). Jede an eine Klasse gebundene
   `@keyframes`-Animation startete deshalb bei JEDEM Klick von vorn —
   nicht wenn etwas passierte, sondern wenn irgendetwas passierte. Das
   sah nicht nach Werkzeug aus, das sah nach Fehler aus.

   Die Antwort ist nicht „keine Bewegung", sondern eine Trennung:

   1. TRANSITIONS sind sicher. `ui/morphen.js` gleicht ab statt zu
      ersetzen — der Knoten bleibt. Eine `transition` laeuft deshalb nur,
      wenn der Wert sich WIRKLICH aendert. Das ist der ganze Alltag:
      Knopf sinkt ein, Chip rastet, Schalter faehrt, Chevron rueckt.

   2. `@keyframes` NUR an Knoten, die wirklich entstehen und vergehen —
      Sheet, Popover, Toast, Blende. Die haengen ausserhalb des
      Abgleichs und koennen deshalb gar nicht neu starten.

   3. DER BUEHNENWECHSEL haengt an `app.sichtKennung()`, nicht am
      Anstrich: nur wenn der Ort sich aendert, faehrt die Buehne ein.

   4. ANIMIERT WIRD NUR `transform`, `opacity`, `box-shadow`, `color`,
      `background` — nie Breite, Hoehe, `top`, `left`. Was das Layout
      anfasst, ruckelt auf dem Geraet, auf dem es niemand nachmisst.
      (Zwei begruendete Ausnahmen stehen unten und tragen ihren Grund.)

   5. GENAU ZWEI DAUERBEWEGUNGEN: die wandernde Chromkante und der
      Denk-Orb, solange die Warteschlange schreibt. Sonst nichts —
      kein Spinner, kein Shimmer, kein Puls.

   6. `prefers-reduced-motion: reduce` schaltet ALLES ab. Der Block
      steht ganz unten und ist der letzte im Stylesheet.

   7. DIE DAUER FOLGT DER STRECKE. Sieben Klassen, sieben Dauern, und es
      gibt keine achte (`tokens.css`, Abschnitt 5). Was unter dem Finger
      passiert, bleibt kurz; was einen Weg zuruecklegt, bekommt Zeit
      dafuer. Und JEDE Sache geht schneller hinein als heraus —
      `--dauer-griff` hin, `--dauer-loesen` zurueck. Das ist der
      Unterschied zwischen einer Taste und einem Bild, das umspringt.

   Die Kurven und die sieben Dauern stehen in `tokens.css` (`--schnapp`,
   `--weich`, `--gleiten`, `--sprung` und `--dauer-*`). Sie stehen dort
   und nicht hier, weil sie zum System gehoeren und nicht zu einer Regel.
   ============================================================ */

/* ============================================================
   1 · DER FINGER — was unter der Hand passiert
   ============================================================ */

/* `.hoehe-marke` (Hoehenspur, gefallen), `.kachel-klick` und
   `.ampel-punkt` (nie gebaute Klassen) trafen keinen Knoten mehr — eine
   Dauer ohne Aussage. Entfernt am 25.08.2026 beim Motion-Audit dieser
   Welle; `.stufenbalken-teil` unten aus demselben Grund. */
/* JEDER GRIFF GEHT SCHNELL HINEIN UND GEMAECHLICH ZURUECK.

   Die Grundregel steht auf `--dauer-loesen`: Das ist der RUECKWEG, und
   er gilt immer dann, wenn nichts weiter passiert. `:hover` und
   `:active` ueberschreiben ihn mit `--dauer-griff` — dem Hinweg.

   Warum herum und nicht andersherum: Eine Taste gibt sofort nach, sobald
   der Finger kommt, und richtet sich langsam wieder auf, wenn er geht.
   Genau das passiert hier, und es ist der Unterschied zwischen einer
   Flaeche, die auf einen Klick REAGIERT, und einer, die zwischen zwei
   Bildern umschaltet. Es kostet zwei Zeilen. */
.knopf,
.ikon,
.stepper-knopf,
.werkzeug,
.orte-zeile,
.pfad-glied,
.platte-klick,
.zeile.ist-oeffenbar{
  transition:box-shadow var(--dauer-loesen) var(--weich),
             transform var(--dauer-loesen) var(--weich),
             color var(--dauer-loesen) var(--weich),
             background-color var(--dauer-loesen) var(--weich);
}
.knopf:hover,.knopf:active,
.ikon:hover,.ikon:active,
.stepper-knopf:hover,.stepper-knopf:active,
.werkzeug:hover,.werkzeug:active,
.orte-zeile:hover,.orte-zeile:active,
.pfad-glied:hover,.pfad-glied:active,
.platte-klick:hover,.platte-klick:active,
.zeile.ist-oeffenbar:hover,.zeile.ist-oeffenbar:active{
  transition-duration:var(--dauer-griff);
  transition-timing-function:var(--schnapp);
}

/* ---- DER DRUCK ----

   `data-anpressen` stand seit v34 an sechzehn Stellen im Quelltext —
   Kacheln, Tageszeilen, Lueckengriffe, Wochentage, die Marke — und in
   `css/` stand dazu KEINE Regel. Die App bestellte ueberall Druck und
   bekam ihn nirgends (Kodex Q8: was niemand liest, ist tot).

   Was ein Griff aus Material tut, wenn man ihn drueckt: Er geht hinein.
   Das Relief kippt von `--neo-auf` auf `--neo-ein` und die Flaeche sinkt
   um ein Pixel — mehr nicht, denn eine Taste faehrt nicht, sie klickt.
   Unter 120 ms, mechanisch, und beim Loslassen sofort zurueck.

   Die Regel steht ABSICHTLICH auf dem Attribut und nicht auf einer
   Klasse: Sie ist eine Eigenschaft des Griffs („dieses Ding laesst sich
   druecken"), keine Angabe zum Aussehen. Wer einen neuen Griff baut,
   schreibt `dataset:{anpressen:"1"}` und hat den Druck. */
[data-anpressen]{
  transition:box-shadow var(--dauer-loesen) var(--weich),
             transform var(--dauer-loesen) var(--weich);
}
[data-anpressen]:active:not(:disabled){
  box-shadow:var(--neo-ein);
  transform:translateY(1px);
  transition-duration:var(--dauer-griff);
  transition-timing-function:var(--schnapp);
}

/* Was sich anklicken laesst, hebt sich unter dem Zeiger eine Stufe —
   und sinkt beim Druck in die Mulde. Nur was WIRKLICH etwas tut: Eine
   Flaeche, die auf einen Klick nicht antwortet, darf ihn auch nicht
   versprechen. */
.platte-klick:hover,
.zeile.ist-oeffenbar:hover{box-shadow:var(--neo-auf-tief)}
.platte-klick:active,
.zeile.ist-oeffenbar:active{box-shadow:var(--neo-ein);transform:translateY(1px)}

/* Der Chevron rueckt 3 px nach. Mehr waere eine Geste, weniger nichts. */
.zeile-chevron,
.pfad-chevron,
.suchfeld-glyph,
.ausklapper-pfeil{
  transition:transform var(--dauer-schnapp) var(--weich),
             color var(--dauer-griff) var(--schnapp);
}

/* Die Marke ist der Lichtschalter. Sie darf gedrueckt aussehen. */
.kopf-marke{transition:transform var(--dauer-loesen) var(--weich)}
.kopf-marke:active{transform:scale(.94);transition-duration:var(--dauer-griff);
  transition-timing-function:var(--schnapp)}

/* Felder: die Mulde vertieft sich beim Fokus. Kein blauer Ring. */
/* Das Feld ist die Ausnahme von der Asymmetrie: Es soll nicht
   „nachgeben", es soll sich OEFFNEN. Die Mulde vertieft sich in beide
   Richtungen gleich lang und auf derselben weichen Kurve — wer den
   Fokus setzt und wieder wegnimmt, sieht denselben Weg zweimal. */
.eingabe,.eingabe-flaeche,.eingabe-datum,.eingabe-suche,.suchfeld,
.auswahl-knopf{
  transition:box-shadow var(--dauer-schnapp) var(--weich);
}

/* Die Kopfleiste legt ihr Glas an, wenn Inhalt unter sie faehrt
   (`app/gesten.js` setzt `html.ist-gerollt`). Es ist die einzige
   Bewegung am Bildlauf, und sie schaltet an einer Schwelle — deshalb
   `--dauer-griff` wie jede andere Naeherung, nicht eine eigene Dauer. */
.kopfleiste{
  transition:background-color var(--dauer-schnapp) var(--weich),
             box-shadow var(--dauer-schnapp) var(--weich);
}

/* HIER STAND DIE UEBERBLENDUNG DER WERKZEUGLEISTE im Fokus-Schreibmodus.
   Sie ist am 26.08.2026 mit der Regel gegangen, die sie bewegte
   (`buehnen.css`): Der Fokus blendet nur noch Flaechen aus, er dimmt
   nichts mehr. Eine Uebergangsdauer fuer eine Opazitaet, die sich nie
   aendert, waere eine Bewegung ohne Aussage (Kodex Q8, Z4). */

/* ============================================================
   2 · DAS EINRASTEN — Zustaende, die kippen
   ============================================================ */

.chip,
.segment,
.haken-box,
.schalter-spur,
/* Der Startgriff am Kalenderblock blendet beim Zeigen ein — die Form steht
   in `buehnen.css`, die Bewegung hier (Kodex Z: Bewegung nur in dieser
   Datei). */
.kal-griff{transition:opacity var(--dauer-schnapp) var(--weich)}
/* Der Anfasser an der Unterkante blendet auf wie der Startgriff daneben —
   dieselbe Zeit, dieselbe Kurve. Zwei Griffe an einem Kasten, die
   verschieden schnell erscheinen, sehen aus wie ein Fehler. */
.kal-laenge{transition:opacity var(--dauer-schnapp) var(--weich)}

.hakengriff::before{
  transition:box-shadow var(--dauer-schnapp) var(--weich),
             background-color var(--dauer-schnapp) var(--weich),
             color var(--dauer-schnapp) var(--weich);
}

/* Der Schalter ist DER Schnapp des Systems: ein Silberknubbel, der in
   160 ms in seine Mulde einrastet. */
/* Der Schalter ist DER Schnapp des Systems. Er traegt als einziger
   `--sprung`: Ein Knubbel, der in seine Mulde faellt, schwingt einmal
   nach — und das ist genau die Bewegung, an der man einen Kippschalter
   von einem Kaestchen unterscheidet. */
.schalter-knopf{
  transition:transform var(--dauer-schnapp) var(--sprung),
             background var(--dauer-schnapp) var(--weich);
}

/* Der Laeufer der Segmente und der Ortsleiste faehrt mit — er ist die
   einzige Stelle, an der eine BREITE animiert wird, und sie ist
   begruendet: Der Laeufer IST die Bewegung. Er liegt in einer eigenen
   Ebene (`position:absolute`), also loest er kein Layout aus.

   ER LAEUFT MIT DEM INHALT, NICHT GEGEN IHN (26.08.2026). Zwei Anlaeufe
   dazu, und der zweite steht hier: Zuerst lief er auf `--dauer-fahrt`
   (520 ms), der Dauer fuer etwas Schweres ueber eine Strecke — zaeh fuer
   einen Weg, der ein Wort breit ist, und weil dabei die BREITE mitlaeuft,
   sah man das Zerren die ganze Zeit. Dann auf `--dauer-schnapp`
   (200 ms) — jetzt war es gehetzt, denn unter ihm tauscht eine ganze
   Seite.

   `--dauer-buehne` mit `--weich` ist beides nicht: Die Kurve traegt
   laenger aus als `--gleiten`, und genau das liest sich als „smooth".

   DIE DAUER IST DIE DES INHALTS DARUNTER, und das ist die eigentliche
   Bedingung — nicht die Zahl, sondern die Gleichheit. Der Laeufer und
   die Seite sind EINE Bewegung; verfehlen sie sich um achtzig
   Millisekunden, sieht man zwei. Steht hier je wieder ein anderer Token
   als in Abschnitt 4 (`.zieht-buehne-ein`), ist das der Fehler, egal
   welcher. */
.indikator{
  transition:transform var(--dauer-buehne) var(--weich),
             width var(--dauer-buehne) var(--weich);
}

/* Das Wort im gewaehlten Werkzeug schiebt sich heraus. Zweite und letzte
   Ausnahme von Regel 4 — `max-width` an einem Element ohne Geschwister
   rechts davon. */
.werkzeug-wort{
  transition:max-width var(--dauer-schnapp) var(--weich),
             opacity var(--dauer-schnapp) var(--weich);
}

/* Balken und Ringe wachsen in ihre Laenge, wenn ein Wert sich aendert. */
/* Balken und Ringe wachsen in ihre Laenge — sie FAHREN, sie schnappen
   nicht. Ein Wert, der in 200 ms von 0 auf 65 % springt, ist gelesen,
   bevor das Auge den Weg gesehen hat; und der Weg IST hier die Aussage
   („so weit ist es gekommen"). */
.balken-fuell,.ring-wert,.bogen-teil{
  transition:transform var(--dauer-fahrt) var(--gleiten),
             stroke-dashoffset var(--dauer-fahrt) var(--gleiten);
}

/* ============================================================
   3 · WAS KOMMT UND GEHT

   Alles hier haengt AUSSERHALB des Abgleichs (`ui/morphen.js` sieht es
   nie), kann also nicht bei einem Anstrich neu starten.
   ============================================================ */

/* ---- Das Sheet ---- */
@keyframes schleier-auf{from{opacity:0}to{opacity:1}}
@keyframes sheet-auf{from{transform:translateY(18px);opacity:0}to{transform:none;opacity:1}}
@keyframes sheet-zu{from{transform:none;opacity:1}to{transform:translateY(10px);opacity:0}}

/* HEREIN LANGSAMER ALS HINAUS. Ein Sheet, das sich Zeit nimmt zu
   kommen, wirkt schwer; eines, das sich Zeit nimmt zu gehen, wirkt
   traege. Deshalb `--dauer-flug` (340 ms) fuer den Weg herein und
   `--dauer-fort` (200 ms) fuer den Weg hinaus — und `--weich` fuer
   beide, weil sie derselbe Vorgang in zwei Richtungen sind. */
.sheet-huelle,.blende-flug{animation:schleier-auf var(--dauer-flug) var(--weich)}
.sheet-panel,.blende-panel{animation:sheet-auf var(--dauer-flug) var(--weich)}
.sheet-huelle.ist-zu,.blende-flug.ist-zu{animation:schleier-auf var(--dauer-fort) var(--weich) reverse forwards}
.sheet-huelle.ist-zu .sheet-panel,
.blende-flug.ist-zu .blende-panel{animation:sheet-zu var(--dauer-fort) var(--weich) forwards}

/* Am Laptop schwebt das Sheet in der Mitte statt vom Rand aufzusteigen —
   dann ist der Einzug eine Skalierung, kein Aufstieg. */
@media (min-width:900px){
  @keyframes sheet-auf{from{transform:scale(.965) translateY(8px);opacity:0}
                       to{transform:none;opacity:1}}
  @keyframes sheet-zu{from{transform:none;opacity:1}
                      to{transform:scale(.985);opacity:0}}
}

/* Die Rueckfrage ueber dem Sheet. */
.sheet-rueckfrage{animation:schleier-auf var(--dauer-fort) var(--weich)}
.sheet-rueckfrage-karte{animation:sheet-auf var(--dauer-schnapp) var(--weich)}

/* ---- Popover, Auswahlmenue, Suchtreffer ----
   Sie wachsen aus ihrem Ausloeser heraus. `--blase-quelle` setzt
   `ui/felder.js` beim Ausrichten: `top`, wenn die Blase unter dem Feld
   haengt, `bottom`, wenn sie darueber klappt. */
@keyframes blase-auf{from{transform:scale(.96) translateY(-4px);opacity:0}
                     to{transform:none;opacity:1}}

.popover,.auswahl-menue,.suchleiste-panel,.kalender{
  transform-origin:var(--blase-quelle,top) center;
  animation:blase-auf var(--dauer-schnapp) var(--weich);
}

/* ---- DER EINZUG EINER TREFFERLISTE ----

   Sie ist der begruendete Gegenfall zu Regel 2. Eine Trefferliste wird
   nicht vom Anstrich gebaut, sondern von einem Filter, einer Suche oder
   einem Chip — die Zeilen entstehen also GENAU DANN, wenn jemand etwas
   getan hat, und ihr Erscheinen IST die Antwort darauf. `ds/einzug.js`
   vergibt `--einzug-i` und diese Klasse; die Herleitung steht dort.

   Der Versatz laeuft ueber `animation-delay` und nicht ueber
   `transition-delay`: Diese Knoten gibt es vorher nicht, es gibt also
   keinen Wert, von dem aus etwas uebergehen koennte.

   `backwards` ist nicht schmueckendes Beiwerk: Ohne es stuende die
   zwoelfte Zeile ihre 312 ms Wartezeit lang voll sichtbar da und
   spraenge dann auf unsichtbar zurueck, um einzulaufen. */
@keyframes treffer-ein{
  from{transform:translateY(7px);opacity:0}
  to{transform:none;opacity:1}
}
.zieht-ein{
  animation:treffer-ein var(--dauer-flug) var(--weich) backwards;
  animation-delay:calc(var(--einzug-i,0) * var(--staffel));
}

/* Der Stift an einer Quellenzeile tritt hervor, wenn der Zeiger auf ihr
   steht. Dreissig Bleistifte untereinander waeren ein Muster und keine
   Auskunft — er kommt, wenn er gebraucht wird. */
.quellzeile-stift{transition:opacity var(--dauer-schnapp) var(--weich)}

/* ---- Toast ---- */
@keyframes toast-auf{from{transform:translateY(16px) scale(.97);opacity:0}to{transform:none;opacity:1}}
@keyframes toast-zu{from{transform:none;opacity:1}to{transform:translateY(8px);opacity:0}}
.toast{animation:toast-auf var(--dauer-flug) var(--weich)}
.toast.ist-zu{animation:toast-zu var(--dauer-fort) var(--weich) forwards}

/* ---- Das Band einer neuen Fassung ---- */
@keyframes band-auf{from{transform:translateY(-100%);opacity:0}to{transform:none;opacity:1}}
.fassungsband{animation:band-auf var(--dauer-flug) var(--weich)}

/* ---- Die Blende ----
   Sie sitzt auf dem einen Element, das gerade zaehlt. Wechselt dieses
   Element, FAEHRT sie hinueber — das ist die eine Bewegung, die eine
   Aussage traegt: „jetzt gilt das hier".

   BEI 200 MS WAR SIE KEINE FAHRT (bis 25.08.2026), sondern ein Sprung
   mit Nachlauf: Das Auge sah den alten Platz, dann den neuen, und den Weg
   dazwischen nur als Wisch. `--dauer-fahrt` (520 ms) auf `--gleiten`
   zeigt den Weg — sie zieht los, nimmt Fahrt auf und schwingt am Ziel
   aus, statt anzuhalten. Das ist der Unterschied zwischen einem Rahmen,
   der umspringt, und einem Sucher, der nachgefuehrt wird. */
/* NUR NOCH `transform`. Hier standen auch `width` und `height` — die
   einzige Ausnahme von Regel 4, die niemand als solche ausgewiesen hatte.
   Sie ist mit dem Kasten gefallen: Ein Bogen ist jetzt ein SVG-Pfad, seine
   Groesse steht im `viewBox` und wird gesetzt, nicht gefahren. Was faehrt,
   ist die Lage — und das war ohnehin die Bewegung, die etwas sagt. */
.blende-rahmen{transition:opacity var(--dauer-schnapp) var(--weich)}
.blende-bogen{transition:transform var(--dauer-fahrt) var(--gleiten)}

/* ---- Die Ortsleiste ----
   Die Gleitpille faehrt durch ihre Mulde: dieselbe Klasse von Bewegung
   wie die Blende (etwas Schweres ueber eine Strecke), deshalb dieselbe
   Kurve, nur kuerzer — die Strecke ist ein Fingerbreit, kein Bildschirm.

   Das Ikon der aktiven Zeile darf ueberschwingen. Es ist das einzige
   Element hier, das WIRKLICH einrastet, und 14 % sind der Unterschied
   zwischen „ist jetzt an" und „war schon immer an". */
/* Die Gleitpille FAEHRT — dieselbe Klasse wie die Blende, also dieselbe
   Dauer und dieselbe Kurve. Hier standen 380 ms und 240 ms als eigene
   Zahlen; das waren die achte und neunte Dauer des Systems, und genau
   solche Einzelwerte sind der Anfang davon, dass eine Oberflaeche in
   fuenf verschiedenen Geschwindigkeiten spricht.

   SIE RASTET SEIT DEM 26.08.2026 EIN (`--sprung` statt `--gleiten`). Sie
   faehrt eine senkrechte Strecke von einem Fach ins naechste und haelt
   dort an — mit `--gleiten` schwang sie aus wie etwas, das noch weiter
   koennte. Der Ueberschwung ist der Unterschied zwischen „ist
   angekommen" und „ist zum Stehen gekommen". */
.orte-moment-gleitpille{
  transition:transform var(--dauer-fahrt) var(--sprung),
             opacity var(--dauer-schnapp) var(--weich);
}
.orte-moment-container{transition:opacity var(--dauer-schnapp) var(--weich)}
.orte-moment-zeile{transition:color var(--dauer-schnapp) var(--weich)}
/* DAS IKON HEBT SICH, ES WAECHST NICHT (26.08.2026).
   Hier stand `scale(1.14)`: eine Groessenaenderung, und die hat keine
   Richtung. In einer Leiste, in der alles senkrecht faehrt — die Pille,
   der Faecher, der Buehnenwechsel —, war sie die einzige Bewegung, die
   nirgendwohin zeigte. Zwei Pixel nach oben sagen dasselbe in der
   Sprache der Nachbarn. */
.orte-moment-zeile svg{transition:transform var(--dauer-schnapp) var(--sprung)}
.orte-moment-zeile.ist-aktiv svg{transform:translateY(-2px)}

/* Die Bereichszeilen sprechen dieselbe Sprache, nur leiser: ein Pixel,
   und ohne Ueberschwung. Sie sind vier neben drei — was hier so laut
   waere wie oben, waere doppelt so laut. */
.orte-zeile svg{transition:transform var(--dauer-schnapp) var(--weich)}
.orte-zeile.ist-aktiv svg{transform:translateY(-1px)}

/* ---- Die Leiste klappt ein ----
   Die Breite ist Layout und keine der fuenf erlaubten Eigenschaften —
   sie steht hier trotzdem, und zwar begruendet: Eine Leiste, die ihre
   Breite abgibt, MUSS sie fahren, sonst springt der halbe Bildschirm.
   Es ist EIN Element mit fester Position, kein Reflow-Sturm. Die
   Woerter darin blenden nur aus; abgeschnitten werden sie ohnehin. */
.orte{transition:width var(--dauer-flug) var(--gleiten)}
.huelle{transition:padding-left var(--dauer-flug) var(--gleiten)}
/* `max-width` faehrt mit, weil die Woerter aus dem FLUSS gehen muessen und
   nicht nur auf durchsichtig (`ds.css` sagt, was das sonst kostet). Das
   ist dieselbe begruendete Ausnahme wie bei `.werkzeug-wort` — und die
   Deckkraft geht schneller als die Breite, damit die Schrift weg ist,
   bevor die Spalte sie einklemmt. */
.orte-wort,.orte-zahl,.orte-marke-wort,.ausklapper-pfeil,.orte-augenbraue{
  transition:max-width var(--dauer-flug) var(--gleiten),
             max-height var(--dauer-flug) var(--gleiten),
             opacity var(--dauer-fort) var(--weich)}
.orte-klapp svg{transition:transform var(--dauer-flug) var(--gleiten)}

/* ---- Der Workspace-Faecher ----
   Er springt nach OBEN heraus, gestaffelt von unten nach oben: Der Griff
   steht unten, also kommt an, was ihm am naechsten ist. `--faecher-i`
   zaehlt deshalb rueckwaerts (`ds/navigation.js`).

   HEREIN MIT STAFFEL UND UEBERSCHWUNG, HINAUS OHNE BEIDES. Ein Faecher,
   der sich beim Zugehen genauso viel Zeit nimmt wie beim Aufgehen, steht
   im Weg — man klappt ihn zu, WEIL man ihn nicht mehr sehen will. */
@keyframes faecher-auf{
  from{transform:translateY(10px);opacity:0}
  to{transform:none;opacity:1}
}
.orte-workspace[open] .orte-zeile{
  animation:faecher-auf var(--dauer-schnapp) var(--sprung) backwards;
  animation-delay:calc(var(--faecher-i,0) * var(--staffel));
}
.orte-workspace[open] .orte-workspace-griff{animation:none}
.orte-workspace-liste{transition:opacity var(--dauer-fort) var(--weich)}

/* ---- Der Ausklapper ---- */
.ausklapper[open] .ausklapper-pfeil{transform:rotate(180deg)}
.orte-workspace:not([open]) .ausklapper-pfeil{transform:rotate(180deg)}

/* ---- Das Ziehen (`js/ds/ziehen.js`) ----
   Die Quelle blasst aus, das Ziel sinkt ein — beides Zustandswechsel, ganz
   normale Transitions. Der Geist ist der Sonderfall: `.ist-abgehoben`
   traegt die Transition NUR fuer die eine Quittung beim Abheben
   (scale 1 -> 1.02); sobald der erste Zeigerzug kommt, nimmt `ziehen.js`
   die Klasse wieder weg, damit die laufenden Positionsupdates dem Finger
   sofort folgen und nicht hinterherfedern (kein WAAPI, keine
   Interpolation waehrend des eigentlichen Zugs — Kodex Z4). */
.ist-zieht{transition:opacity var(--dauer-schnapp) var(--weich)}
.ist-ziel{transition:box-shadow var(--dauer-schnapp) var(--weich),
                     outline-color var(--dauer-schnapp) var(--weich)}
.schleppgeist.ist-abgehoben{transition:transform var(--dauer-schnapp) var(--sprung)}
.schleppgeist.faehrt-fort{transition:opacity var(--dauer-fort) var(--weich)}

/* ============================================================
   4 · DER BUEHNENWECHSEL — ein Aufbau, keine Ueberblendung

   HIER STANDEN VIEW TRANSITIONS (bis 26.08.2026), und sie waren der
   Grund, aus dem der Wechsel nie nach Aufbau aussah. Eine View
   Transition friert alt und neu als BILDER ein und blendet sie
   gegeneinander. Ein Bild hat keine Abschnitte — es kann darin nichts
   nacheinander ankommen. Was blieb, war ein Ueberblenden mit einem Ruck,
   und weil die Gruppe zusaetzlich ihren Kasten morphte (Position UND
   Groesse zweier verschieden hoher Buehnen), lief der Ruck schraeg.

   Jetzt zeichnet `app/anstrich.js` normal und setzt `.zieht-buehne-ein`
   auf die neue Buehne. Deren Abschnitte kommen nacheinander herein.

   NUR BEI ORTSWECHSEL — die Klasse wird genau dort gesetzt. Diese App
   zeichnet bei jedem Haken neu; ein Einzug am Anstrich hiesse, dass
   jeder Haken aussieht wie ein Seitenwechsel (Kodex Z4).
   ============================================================ */

@keyframes buehne-teil-ein{
  from{transform:translateY(16px);opacity:0}
  to{transform:none;opacity:1}
}
/* NACH OBEN, wenn man nach oben geht. Die Richtung ist die einzige
   Aussage, die dieser Wechsel traegt — sie muss stimmen. */
@keyframes buehne-teil-ein-hoch{
  from{transform:translateY(-16px);opacity:0}
  to{transform:none;opacity:1}
}
/* UND ZUR SEITE, WO REITER STEHEN. Die Linsen der Zeit und die Segmente
   des Studiums liegen nebeneinander, und die Leiste darueber sagt das
   auch: Der Laeufer faehrt waagerecht. Ein Inhalt, der dabei von UNTEN
   kommt, widerspricht ihm — zwei Bewegungen, die verschiedene Geschichten
   erzaehlen, liest man als Ruckeln und Neuladen. Jetzt kommt er aus
   derselben Richtung, in die der Laeufer zieht. */
@keyframes buehne-teil-ein-rechts{
  from{transform:translateX(22px);opacity:0}
  to{transform:none;opacity:1}
}
@keyframes buehne-teil-ein-links{
  from{transform:translateX(-22px);opacity:0}
  to{transform:none;opacity:1}
}

/* Die Abschnitte, nicht die Buehne: `main.buehne` traegt genau ein Kind
   (`.seite`, `.blatt`, `.nah`, `.fokus`), und dessen Kinder sind das,
   was man nacheinander ankommen sieht — Kopf, Abschnitte, Spalten. */
/* `--dauer-buehne` UND NICHT `--dauer-flug`. Bis zum 26.08.2026 stand hier
   der Flug, und `--dauer-buehne` hatte im ganzen Projekt keinen einzigen
   Leser: ein Token, das sich selbst als „die Buehne wechselt" bezeichnete
   und nie eine Buehne wechselte (Kodex Q8).

   Zwei Folgen, und die zweite ist die aergerlichere. Erstens lief der
   Wechsel auf der Dauer einer fremden Klasse — Z4(3) verlangt je Klasse
   genau eine Dauer, und der Bruch fiel niemandem auf, weil
   `probe/tiefgang.mjs` §15 prueft, ob eine Dauer EINE DER SIEBEN ist, und
   nicht, ob es die richtige ist. Zweitens wurde mehrfach an
   `--dauer-buehne` gedreht, um den Wechsel zu beruhigen, und es aenderte
   sich nichts — die Zahl las ja niemand. */
.zieht-buehne-ein>*>*{
  animation:buehne-teil-ein var(--dauer-buehne) var(--gleiten) backwards;
  animation-delay:calc(var(--einzug-i, 0) * var(--staffel));
}
html.transition-hoch .zieht-buehne-ein>*>*{
  animation-name:buehne-teil-ein-hoch;
}
/* Seitwaerts laeuft es OHNE STAFFELUNG: Ein Reiterwechsel tauscht
   denselben Kasten gegen einen anderen Inhalt — das ist eine Bewegung,
   kein Aufbau. Gestaffelt saehe es aus, als baute sich die Seite neu auf,
   und genau das soll es nicht mehr.

   ZUR DAUER: Hier stand erst `--dauer-schnapp` (200 ms), dann
   `--dauer-flug` — beides fremde Klassen fuer eine Bewegung, die einen
   Bühnenwechsel zeigt. Jetzt `--dauer-buehne`, die Klasse, die dafuer da
   ist. Die Kurve bleibt `--weich`: Sie traegt weiter aus als `--gleiten`,
   und genau das liest sich als „smooth". Der Laeufer bekommt dieselbe
   Dauer und dieselbe Kurve (siehe `.indikator`), damit die beiden
   Bewegungen EINE bleiben. */
html.transition-rechts .zieht-buehne-ein>*>*,
html.transition-links .zieht-buehne-ein>*>*{
  animation-duration:var(--dauer-buehne);
  animation-timing-function:var(--weich);
  animation-delay:0ms;
}
html.transition-rechts .zieht-buehne-ein>*>*{animation-name:buehne-teil-ein-rechts}
html.transition-links .zieht-buehne-ein>*>*{animation-name:buehne-teil-ein-links}

/* SECHS STUFEN, DANN NICHT MEHR. Bei 26 ms je Stufe ist der sechste
   Abschnitt 156 ms spaet — das liest sich als Aufbau. Wer weiter
   staffelt, laesst den Leser auf den unteren Rand warten, und eine
   Buehne mit zwanzig Abschnitten braeuchte eine halbe Sekunde, bis sie
   fertig ist. Ab der siebten kommen alle zusammen. */
.zieht-buehne-ein>*>*:nth-child(1){--einzug-i:0}
.zieht-buehne-ein>*>*:nth-child(2){--einzug-i:1}
.zieht-buehne-ein>*>*:nth-child(3){--einzug-i:2}
.zieht-buehne-ein>*>*:nth-child(4){--einzug-i:3}
.zieht-buehne-ein>*>*:nth-child(5){--einzug-i:4}
.zieht-buehne-ein>*>*:nth-child(n+6){--einzug-i:5}

/* Die Chrome-Ebene zieht NICHT mit ein. Kopfleiste und Ortsleiste sind
   der Bezugspunkt, an dem man ablesen kann, dass sich der Rest bewegt
   hat — was selbst mitfaehrt, taugt dazu nicht. */

/* ============================================================
   5 · DIE ZWEI DAUERBEWEGUNGEN

   Es gibt genau zwei, und beide sagen etwas: Die Chromkante sagt „das
   hier ist die eine Aktion", der Orb sagt „es laeuft noch etwas".
   ============================================================ */

/* Die wandernde Chromkante um die eine Primaeraktion je Buehne.
   `js/ds/effekte.js` legt zusaetzlich den WebGL-Ring darueber, wo es
   WebGL gibt; faellt der aus, traegt diese Kante allein (Kodex G1). */
@keyframes chrom-wandern{to{transform:rotate(360deg)}}
.lm-rand::before{animation:chrom-wandern var(--dauer-chrom) linear infinite}

/* Der Denk-Orb malt sich selbst auf eine Canvas-Flaeche
   (`vendor/denkorb-engine.js`). Hier steht nur, dass er da ist. */
.denkorb{display:block}

/* ============================================================
   6 · WER NICHTS DAVON WILL, BEKOMMT NICHTS DAVON

   Nicht „weniger Bewegung" — keine. Zustaende gelten sofort, Flaechen
   sind sofort da. Der Block steht bewusst als letzter im Stylesheet.
   ============================================================ */

@media (prefers-reduced-motion: reduce){
  /* `none`, nicht `1ms`. Eine Bewegung von einer Millisekunde IST eine
     Bewegung: `getAnimations()` findet sie, der Browser plant sie ein,
     und bei Eigenschaften, die er von sich aus ueberblendet
     (`scrollbar-color`, `transform` in der Bildlaufkette), laeuft sie
     auch dann noch, wenn keine Regel sie bestellt hat. Wer reduzierte
     Bewegung einstellt, hat nicht „weniger" bestellt, sondern keine.

     Zustaende gelten dabei nicht spaeter, sondern sofort — genau das
     ist der Unterschied zwischen `transition:none` und `duration:0`.
     Kein Ort in der App wartet auf `transitionend`; das Schliessen von
     Sheet und Toast haengt an einem eigenen Zeitgeber. */
  *,*::before,*::after{
    animation:none !important;
    transition:none !important;
    scroll-behavior:auto !important;
  }
  /* Die drei `::view-transition-*`-Zeilen sind mit den View Transitions
     gefallen (26.08.2026, Abschnitt 4) — es gibt keine mehr, also gibt es
     hier auch nichts mehr abzuschalten (Q8). */
}
