frontend: Strahlenkranz robust machen (Stapelordnung + Pfad-Inversion)

Gemeldet von der deployten Seite: „nur die linke Hälfte gelb, kein Rahmen
drum herum". Zwei Ursachen gefunden — beide betreffen den Kranz, weil er
AUSSERHALB der Knotenbox liegt und damit fremden Malvorgängen ausgeliefert ist:

- Fehlende Stapelordnung: Jedes später kommende Geschwister malt seinen
  undurchsichtigen Hintergrund über den Schein und schneidet ihn einseitig ab —
  übrig bleibt eine gelbe Kante, die wie ein halber Hintergrund aussieht statt
  wie ein Rahmen. Die Geschwister-Abstände (gemessen 24–25 px) liegen nur knapp
  über der Reichweite des Scheins (Blur 16 + Spread 5 = 21 px); bei Zoom,
  längeren Labels oder engeren Layouts reicht das nicht. Jetzt `z-index:2`.
- Pfad-Inversion dimmte die Meldung weg: `.cheap-on .node:not(.cheap)` setzt
  `opacity:.32; filter:saturate(.4)` und traf damit auch den gelben Kranz
  (nachgemessen: Deckkraft 0,32 ⇒ praktisch unsichtbar). Gerade bei einer nicht
  gewählten Alternative ist „das ist jetzt live" aber die interessantere
  Nachricht. Neue Regel hebt beides für `.fresh` auf.

Verifiziert gegen das gebaute dist-Artefakt (dasselbe, das deployt wird):
z-index 2 gesetzt; ein nicht-günstiger Knoten mit .fresh hat wieder
opacity 1 / filter none bei unverändertem Kranz; im kompakten Modus liegt
kein Geschwister mehr über dem Schein. Vitest 46/46.

Nicht reproduziert: die exakte Beschreibung (gelb nur hinter der linken
Texthälfte) trat bei mir weder im Dev-Server noch im dist-Artefakt auf, in
keinem der drei Modi. Die beiden behobenen Defekte erklären sie plausibel,
bewiesen ist das nicht.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-07-27 19:51:11 +02:00
co-authored by Claude Opus 4.8
parent 7a52277b84
commit 744bb0bcf3
2 changed files with 27 additions and 1 deletions
+17
View File
@@ -710,6 +710,23 @@ soll verschwinden, wenn sie ihren Zweck erfüllt hat.
Dokument geändert, wird es nicht mehr nachgezogen (D27) — dann gibt es keine Dokument geändert, wird es nicht mehr nachgezogen (D27) — dann gibt es keine
saubere Vergleichsbasis, und es wird nichts hervorgehoben. saubere Vergleichsbasis, und es wird nichts hervorgehoben.
**Zwei Nachbesserungen nach dem ersten Blick auf die deployte Seite.** Gemeldet
war „nur die linke Hälfte gelb, kein Rahmen drum herum":
- **`z-index:2` am neuen Knoten.** Der Schein liegt *außerhalb* der Knotenbox.
Ohne eigene Stapelordnung malt jedes **später kommende Geschwister** seinen
undurchsichtigen Hintergrund darüber und schneidet den Kranz einseitig ab —
übrig bleibt eine gelbe Kante, die wie ein halber Hintergrund aussieht statt
wie ein Rahmen. Die Abstände (2425 px) liegen nur knapp über der Reichweite
des Scheins (Blur 16 + Spread 5 = 21 px); in engeren Layouts, bei Zoom oder
längeren Labels reicht das nicht.
- **Die Pfad-Inversion darf „neu" nicht wegdimmen.**
`.cheap-on .node:not(.cheap)` setzt `opacity:.32; filter:saturate(.4)` — das
trifft auch den gelben Kranz und macht ihn praktisch unsichtbar. Gerade bei
einer *nicht gewählten* Alternative ist „das ist jetzt live" aber die
interessantere Nachricht. Deshalb `.cheap-on .node:not(.cheap).fresh
{opacity:1;filter:none}`.
**Stolperfalle (beim Bauen hineingelaufen):** Die Menge der neuen Knoten muss aus **Stolperfalle (beim Bauen hineingelaufen):** Die Menge der neuen Knoten muss aus
**denselben Knotenobjekten** gebildet werden, die gerade gerendert werden. Zuerst **denselben Knotenobjekten** gebildet werden, die gerade gerendert werden. Zuerst
wurde sie beim Laden aus einem eigenen Parse-Durchlauf berechnet — der Zähler wurde sie beim Laden aus einem eigenen Parse-Durchlauf berechnet — der Zähler
+10 -1
View File
@@ -476,7 +476,11 @@
Knoten. Bewusst ein Schein nach AUSSEN statt Farbe im Knoten — die Füllung Knoten. Bewusst ein Schein nach AUSSEN statt Farbe im Knoten — die Füllung
gehört dem Status (SPEC §4) und bleibt lesbar. Kein Blinken: WCAG 2.2.2/2.3.1 gehört dem Status (SPEC §4) und bleibt lesbar. Kein Blinken: WCAG 2.2.2/2.3.1
und es zöge dauerhaft den Blick. `#out`-Präfix wegen `ul.or .node`. */ und es zöge dauerhaft den Blick. `#out`-Präfix wegen `ul.or .node`. */
#out .node.fresh{box-shadow:0 0 0 2px #FACC15,0 0 16px 5px rgba(234,179,8,.65)} /* `z-index`, weil der Schein AUSSERHALB des Knotens liegt: ohne ihn malt jedes
später kommende Geschwister seinen undurchsichtigen Hintergrund darüber und
schneidet den Kranz einseitig ab (in engen Layouts bleibt nur eine gelbe
Kante stehen — sieht aus wie ein halber Hintergrund statt eines Rahmens). */
#out .node.fresh{box-shadow:0 0 0 2px #FACC15,0 0 16px 5px rgba(234,179,8,.65);z-index:2}
/* Beides zugleich: Cursor-Zeile innen (Tinte), Neuheit außen (gelb). */ /* Beides zugleich: Cursor-Zeile innen (Tinte), Neuheit außen (gelb). */
#out .node.fresh.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink),0 0 18px 6px rgba(234,179,8,.65)} #out .node.fresh.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink),0 0 18px 6px rgba(234,179,8,.65)}
/* Alt gedrückt = Sprung-Geste scharf: Cursor an allen Knoten, Petrol-Ring am /* Alt gedrückt = Sprung-Geste scharf: Cursor an allen Knoten, Petrol-Ring am
@@ -539,6 +543,11 @@
any-of-Alternativen samt Teilbaum) treten zurück (blass, entsättigt); any-of-Alternativen samt Teilbaum) treten zurück (blass, entsättigt);
der günstige Pfad hebt sich dadurch von allein ab. */ der günstige Pfad hebt sich dadurch von allein ab. */
.cheap-on .node:not(.cheap){opacity:.32;filter:saturate(.4)} .cheap-on .node:not(.cheap){opacity:.32;filter:saturate(.4)}
/* „Neu in Produktion" darf die Pfad-Inversion nicht wegdimmen: opacity und
saturate treffen sonst auch den gelben Kranz (0,32 Deckkraft ⇒ praktisch
unsichtbar), und gerade bei einer nicht gewählten Alternative ist „das ist
jetzt live" die interessantere Nachricht (D28). */
.cheap-on .node:not(.cheap).fresh{opacity:1;filter:none}
/* implizit als M angenommene Größe: invertiertes Badge (weiß statt petrol) */ /* implizit als M angenommene Größe: invertiertes Badge (weiß statt petrol) */
.size.implicit{background:var(--card);color:var(--or);border-color:var(--or)} .size.implicit{background:var(--card);color:var(--or);border-color:var(--or)}
/* Günstigster-Pfad-Linie: gestrichelt, geschwungen, petrol — fädelt durch /* Günstigster-Pfad-Linie: gestrichelt, geschwungen, petrol — fädelt durch