From 099ee87bc172e60087c2caf0c51e664163753734 Mon Sep 17 00:00:00 2001 From: mhoennig Date: Sun, 23 Aug 2026 07:24:04 +0200 Subject: [PATCH] feat: Cursor-Zeile hebt sich aus der Ebene, plus Puls beim Zeilenwechsel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Hervorhebung der Cursor-Zeile (D25) war zu leise. Sie benutzte denselben Kanal, den schon jeder Knoten belegt — jeder Status hat einen Rahmen (SPEC §4); ein weiterer Ring darunter ist ein Unterschied im Grad, nicht in der Art. Dazu kommt jetzt Tiefe: Schlagschatten + scale(1.04). Der einzige Kanal, den im Diagramm noch nichts belegt, also ohne Konflikt mit einer Farbcodierung. Um die Mitte skaliert, damit die Knotenmitte erhalten bleibt (alignStems, Stationspunkte messen genau die — nachgemessen dx=dy=0). Beim Zeilenwechsel meldet sie sich zusätzlich mit einem einmaligen Puls (Hüpfer + auslaufender Ring auf ::after); kein Blinken, prefers-reduced-motion schaltet ihn ab. Behoben dabei: Die Pfad-Inversion (D18) blasste den Ring auf 0,32 aus — die Ausnahme, die .fresh (D28) und .focusmark (D32) längst haben, fehlte für .current als einziger, obwohl der Fall der häufigste ist (Umschalter default an, im Beispiel 7 von 18 Knoten betroffen). diagramToSvg() muss die Erhebung abschalten (Klasse `exporting`): Der Export zieht die Live-Geometrie per getBoundingClientRect() nach, anders als beim box-shadow schlägt eine Vergrößerung dort durch. Nachgemessen: 155,6 statt 161,9 px. Im Druck fällt beides ebenso weg. SPEC §9 und D25 (Nachtrag) nachgezogen; llms.md unberührt (Notation, keine Editor-UI, D43). Co-Authored-By: Claude Fable 5 --- docs/DECISIONS.md | 76 ++++++++++++++++++++++++++++++++++++++++++ docs/SPEC.md | 14 ++++++-- frontend/CLAUDE.md | 17 +++++++++- frontend/src/app.js | 25 +++++++++++--- frontend/src/style.css | 75 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 190 insertions(+), 17 deletions(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index b8679bd..e1f52f8 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -634,6 +634,82 @@ weiter, Alt+Enter zurück in die Zeile. Umbruch. Auf einer Zeile ohne Knoten (Kommentar, Leerzeile, ausgeblendetes Verworfenes) geschieht nichts — dieselbe stille Regel wie bei der Cursor-Zeile. +**Nachtrag — die Cursor-Zeile hebt sich jetzt aus der Ebene, und die fehlende +Ausnahme gegen die Pfad-Inversion.** Gemeldet als „müsste etwas deutlicher +sein". Beim Nachsehen kam zuerst etwas anderes heraus, das keine +Gestaltungsfrage ist: + +**Auf einem guten Drittel der Knoten war der Ring gar nicht zu sehen.** Die +Pfad-Inversion (D18) setzt `.cheap-on .node:not(.cheap){opacity:.32; +filter:saturate(.4)}` — und das trifft den `box-shadow` mit. Genau diese Falle +haben D28 (gelber Kranz) und D32 (Fokusmarke) je für sich gefunden und mit +einer Ausnahmeregel behoben; `.current` hat seine nie bekommen. Gemessen im +mitgelieferten Beispiel mit dem Cursor auf `+ [?] Dark mode`: Deckkraft 0,32. +Der Fall ist zudem der häufigste der drei — der Pfad-Umschalter ist +voreingestellt an, und jeder optionale Knoten und jede nicht gewählte +Alternative fällt darunter (im Beispiel 7 von 18 Knoten). Anders als beim +optionalen Knoten (D29), wo das Zurücktreten die **Aussage** ist, wird hier +überhaupt keine Aussage über den Plan gemacht: Es ist eine Editierhilfe, und wo +der Cursor steht, muss sichtbar bleiben, egal wie der Pfad entschieden hat. + +**Warum der Ring auch ungedimmt leise wirkt:** Er benutzt denselben Kanal, den +schon jeder Knoten belegt — **jeder Status hat einen Rahmen** (SPEC §4). Ein +weiterer Ring in einem Feld aus lauter gerahmten Kästchen ist ein Unterschied +im Grad, nicht in der Art. Die beiden Strahlenkränze entkommen dem, weil sie +einen Kanal benutzen, den sonst nichts hat (Leuchten nach außen); die +Cursor-Zeile war auf dem Rahmen-Kanal sitzen geblieben. + +**Gewählt: Tiefe** — Ring behalten, dazu Schlagschatten und `scale(1.04)`. Der +Knoten hebt sich aus der Ebene. Das ist der einzige Kanal, den im Diagramm noch +gar nichts belegt (nichts anderes wirft Schatten oder bewegt sich), kollidiert +also mit **keiner** Farbcodierung und wirkt über allen acht Statusfarben +gleich. Zwei angenehme Eigenschaften, beide nachgemessen: `transform` ändert +kein Layout (die Linien bleiben stehen), und weil um die **Mitte** skaliert +wird, bleibt die Knotenmitte punktgenau erhalten (dx = dy = 0) — `alignStems()` +(D29) und die Stationspunkte des günstigsten Pfads (D18) messen genau die und +bleiben unberührt. Nur `drawDepLinks()` (D41) setzt auf Knoten**kanten** auf und +verschiebt sich für diesen einen Knoten um ~4 px; das ist flüchtig und fällt +nicht auf. Ein Spalt zur Anschlusslinie entsteht nicht — der Knoten wächst +darüber, statt sich zurückzuziehen. + +**Dazu ein einmaliger Puls beim Zeilenwechsel:** Man verliert den Knoten beim +**Bewegen**, nicht im Stillstand — also meldet er sich genau dann einmal, mit +einem kurzen Hüpfer und einem auslaufenden Ring. Kein WCAG-Problem: 2.2.2 zielt +auf Blinkendes, 2.3.1 auf Flackern über 3 Hz, ein einzelner Durchlauf ist +keines von beidem (dieselbe Prüfung wie in D28); `prefers-reduced-motion` +schaltet ihn ab. Ausgelöst wird er an derselben Bedingung, an der schon das +Scrollen hängt (`caretLine` hat sich geändert) — sonst pulste er bei jedem +Tastendruck. Bewusst **nicht** über `box-shadow` animiert: Die Kombinationen +mit `.fresh` und `.focusmark` haben je eigene Schatten-Listen, eine Animation +darauf ließe den gelben bzw. petrolfarbenen Kranz für die Dauer des Pulses +verschwinden. Stattdessen `transform` plus das freie `.node::after` +(`::before` gehört dem Optional-Kreis, D29). + +**Der Export brauchte eine eigene Behandlung** — und das ist die Stelle, an der +die Erhebung anders liegt als der Ring. D25 konnte sich darauf verlassen, dass +`diagramToSvg()` nie `box-shadow` ausliest; die Vergrößerung schlägt aber über +`getBoundingClientRect()` durch, mit dem der Export die Live-Geometrie nachzieht +— genau ein Knoten stünde 4 % zu groß im Bild. Während des Messens trägt `#out` +deshalb die Klasse `exporting`, die Erhebung und Puls neutralisiert. +Nachgemessen: 155,6 statt 161,9 px, also die unskalierte Breite. Per Klasse +statt durch Abnehmen von `.current`/`.pulse`, damit der Export keine laufende +Animation abreißt und hinterher neu startet. Im Druck fällt beides ebenso weg. + +**Verworfene Alternativen:** ein **dritter Strahlenkranz** (ein dunkles +Tinte-Leuchten liest sich auf hellem Grund als Schatten — die Lehre steht schon +im D32-Nachtrag —, und ein heller Schein bräuchte eine dritte Signalfarbe neben +Gelb und Teal); **Invertieren** des Knotens auf Tinte-Füllung mit weißer Schrift +(das stärkste Signal, kostet aber für die Cursor-Zeile die Statusfarbe — genau +die Regel, wegen der D28 und D32 ihre Kränze nach außen gelegt haben, und für +eine Editierhilfe wäre sie schlecht gebrochen); ein **Zeiger-Dreieck** links am +Knoten (`::after` wäre frei, bräuchte aber wie der Optional-Kreis eigene +Geometrie für alle drei Darstellungsmodi); und **die Umgebung zurücktreten +lassen** (flackerte bei jedem Pfeiltastendruck durch den ganzen Baum). + +Nebenbefund beim Aufräumen: Der Kommentar über der Regel behauptete noch, die +Fokusmarke `!!!` trage „bewusst DIESELBE Hervorhebung" — überholt, seit der +D32-Nachtrag ihr den eigenen Petrol-Kranz gegeben hat. Ersetzt. + ## D26 — Legende scrollbar: eigener Container statt `
`, plus Splitter Die Legende („Agenda") im Editor-Panel war zu hoch für ihren Platz und wurde **abgeschnitten** statt scrollbar zu sein — obwohl `.hint` seit jeher diff --git a/docs/SPEC.md b/docs/SPEC.md index 3547183..720cc39 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -556,9 +556,17 @@ verknüpft (siehe D25): „hinschauen": Er holt **keine Bildschirmtastatur** herauf — die erscheint erst, wenn das Textfeld selbst angetippt wird. - **Text → Diagramm:** Der Knoten der **Cursor-Zeile** wird im Diagramm - hervorgehoben (weißer Halo + Ring in Tinte) und beim Zeilenwechsel ins Bild - gescrollt. Zeilen ohne Knoten (Kommentar, Leerzeile, ausgeblendetes - verworfenes Element) heben nichts hervor. + hervorgehoben und beim Zeilenwechsel ins Bild gescrollt. Zeilen ohne Knoten + (Kommentar, Leerzeile, ausgeblendetes verworfenes Element) heben nichts + hervor. Die Hervorhebung arbeitet auf einer **eigenen Achse — Tiefe**: weißer + Halo + Ring in Tinte, dazu ein Schlagschatten und eine leichte Vergrößerung, + sodass der Knoten sich aus der Ebene hebt. Das ist der einzige Kanal, den + sonst nichts im Diagramm belegt, kollidiert also mit keiner Farbcodierung + (Status §4, gelber Kranz und Petrol-Kranz oben). **Beim Zeilenwechsel** meldet + sie sich zusätzlich mit einem **einmaligen Puls** — einem kurzen Hüpfer und + einem auslaufenden Ring; kein Blinken, und bei `prefers-reduced-motion` + entfällt er. Der Pfad-Filter (§9, günstigster Pfad) blasst sie nie aus: Wo der + Cursor steht, bleibt sichtbar. Siehe D25. - **Text → Diagramm, ausdrücklich:** **Alt+Klick** im Textfeld (Tastatur: **Alt+Enter**) holt den Knoten der Cursor-Zeile in die **Mitte** des Diagramms und gibt ihm den Tastaturfokus — dieselbe Geste in beide Richtungen. Sie diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 48ef758..ba658a5 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -211,7 +211,22 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der `syncCaret()` setzt die Klasse `current` auf den Knoten der Cursor-Zeile; `render()` stellt sie nach jedem Neubau wieder her (ohne zu scrollen). Die CSS-Regel braucht den `#out`-Präfix (`ul.or .node{box-shadow:none}` ist - spezifischer). Auffindbarkeit: `setAltMode()` setzt bei gedrückter Alt-Taste + spezifischer) **und** — wie `.fresh`/`.focusmark` — die Ausnahme + `.cheap-on .node:not(.cheap).current{opacity:1;filter:none}`; sie fehlte lange + als einzige, obwohl der Fall der häufigste ist (Pfad-Umschalter default an, + jeder `+`-Knoten und jede nicht gewählte Alternative betroffen). + Zum Ring kommen **Schlagschatten + `scale(1.04)`** (D25-Nachtrag): Tiefe ist der + einzige noch freie Kanal. Um die **Mitte** skalieren ist Bedingung — `alignStems()` + und die Stationspunkte messen die Knotenmitte, die dadurch unverändert bleibt. + **`diagramToSvg()` muss die Erhebung abschalten** (Klasse `exporting` an `#out`, + am Ende wieder ab): Der Export zieht die Live-Geometrie per + `getBoundingClientRect()` nach, anders als beim `box-shadow` schlägt die + Vergrößerung dort durch. Der **Puls** (`pulse`, Hüpfer + Ring auf dem freien + `.node::after`) wird nur bei geändertem `caretLine` gesetzt — sonst pulst es bei + jedem Tastendruck — und braucht das Lesen von `offsetWidth` als Neustart-Trick, + weil dieselbe Aufgabe die Klasse vorher entfernt. Nicht über `box-shadow` + animieren: Das löschte für die Dauer des Pulses den gelben bzw. Petrol-Kranz der + Kombinationen. Auffindbarkeit: `setAltMode()` setzt bei gedrückter Alt-Taste die Klasse `alt` an `#out` (Cursor + Ring am Knoten unter dem Zeiger) — der `blur`-Handler ist Pflicht, sonst bleibt der Modus nach Alt+Tab hängen; dazu `jumpHint` im Knoten-Tooltip und `hint_jump` als letzte Zeile der Legende. diff --git a/frontend/src/app.js b/frontend/src/app.js index a395d6c..145276c 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -394,6 +394,13 @@ out.addEventListener('focusout', () => setTimeout(drawDepLinks, 0)); (und = durchgezogen Tinte, oder = gestrichelt Grau) neu gezogen und treffen so garantiert die Knoten — unabhängig vom Darstellungsmodus. */ function diagramToSvg(){ + /* Der Export misst die **Live-Geometrie**. Den Ring der Cursor-Zeile liest er + nie aus (`box-shadow` steht nicht in der Liste), ihre Erhebung + (D25-Nachtrag) schlüge aber über `getBoundingClientRect()` durch und + exportierte genau einen Knoten 4 % zu groß. Neutralisiert wird sie per + Klasse statt durch Abnehmen von `.current`/`.pulse` — so reißt der Export + keine laufende Puls-Animation ab und startet sie hinterher nicht neu. */ + out.classList.add('exporting'); const treeRect = out.getBoundingClientRect(); const PAD = 24; const W = Math.ceil(treeRect.width) + PAD*2; @@ -570,6 +577,7 @@ function diagramToSvg(){ }); const svg = `${parts.join('')}`; + out.classList.remove('exporting'); return {svg, W, H}; } function svgToPng(svg, W, H, scale){ @@ -925,9 +933,9 @@ out.addEventListener('touchcancel', disarmPress); out.addEventListener('contextmenu', e => { if(pressTimer || armedEl) e.preventDefault(); }); /* Text -> Diagramm: Knoten der Cursor-Zeile hervorheben (`caretLine` steht oben). */ -function highlightCurrentNode(scroll){ +function highlightCurrentNode(moved){ markCurrentLineNo(); /* die eine Stelle, an der die Cursor-Zeile neu gesetzt wird */ - if(currentNodeEl) currentNodeEl.classList.remove('current'); + if(currentNodeEl) currentNodeEl.classList.remove('current', 'pulse'); currentNodeEl = caretLine == null ? null : out.querySelector('.node[data-line="' + caretLine + '"]'); @@ -936,8 +944,17 @@ function highlightCurrentNode(scroll){ /* Die Cursor-Zeile ist die zweite Lesart von „ausgewählt" — ihre Abhängigkeits-Kanten hervorheben (D41). */ drawDepLinks(); - /* Nur beim Zeilenwechsel scrollen, sonst ruckelte das Diagramm beim Tippen. */ - if(scroll) currentNodeEl.scrollIntoView({block:'nearest', inline:'nearest', behavior:'smooth'}); + /* Beides nur beim **Zeilenwechsel**: Scrollen ruckelte sonst bei jedem + Tastendruck, und der Puls (D25-Nachtrag) flackerte beim Tippen. */ + if(!moved) return; + /* Neustart der Animation erzwingen: Steht der Cursor wieder auf demselben + Knoten (Zeile mit Knoten -> Zeile ohne -> zurück), wurde `pulse` oben in + DERSELBEN Aufgabe entfernt — der Browser sieht dann keinen Klassenwechsel + und startet nichts. Das Lesen von `offsetWidth` erzwingt den Zwischenstand. */ + currentNodeEl.classList.remove('pulse'); + void currentNodeEl.offsetWidth; + currentNodeEl.classList.add('pulse'); + currentNodeEl.scrollIntoView({block:'nearest', inline:'nearest', behavior:'smooth'}); } function caretLineOf(){ return src.value.slice(0, src.selectionStart).split('\n').length; diff --git a/frontend/src/style.css b/frontend/src/style.css index 3f8723d..0d901f7 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -578,11 +578,21 @@ im Druck. Der `#out`-Präfix ist nötig: `ul.or .node{box-shadow:none}` (weiter unten) ist spezifischer als `.node.current` und schluckte den Ring sonst überall unterhalb einer any-of-Gruppe. */ - /* Die Fokusmarke `!!!` (SPEC §1) trägt bewusst DIESELBE Hervorhebung: Es gibt - nur einen Begriff „hier schauen", und ein dritter Ring neben Fokusring, - Strahlenkranz und Cursor-Ring wäre ein Zeichen zu viel. Der Unterschied - steht im `aria-label`. */ - #out .node.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink)} + /* Der Ring allein war zu leise (D25-Nachtrag): Er benutzt denselben Kanal, den + schon jeder Knoten belegt — **jeder Status hat einen Rahmen** (SPEC §4). Ein + weiterer Ring in einem Feld aus lauter gerahmten Kästchen ist ein Unterschied + im Grad, nicht in der Art. Deshalb kommt **Tiefe** dazu: Schlagschatten plus + leichte Vergrößerung. Das ist der einzige Kanal, den im Diagramm noch nichts + belegt (nichts anderes wirft Schatten oder hebt sich), kollidiert also mit + keiner Farbcodierung und wirkt über allen acht Statusfarben gleich. + `transform` ändert **kein Layout** — die Linien bleiben stehen; und weil um + die **Mitte** skaliert wird, bleibt auch die Knotenmitte unverändert, auf die + `alignStems()` und `drawCheapPath()` messen. `z-index`, weil Schatten und + vergrößerter Knoten AUSSERHALB der Box liegen (dasselbe wie bei `.fresh`). */ + #out .node.current{ + box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink),0 10px 20px -6px rgba(36,52,71,.5); + transform:scale(1.04);z-index:3; + } /* Fokusmarke `!!!` (SPEC §1, D32): **Strahlenkranz in Petrol**, nach dem Muster der Neuheiten-Markierung (D28), nur in der Akzentfarbe der App statt in Gelb. Der geteilte Ring mit der Cursor-Zeile war zu leise — „das erkennt man zu @@ -598,8 +608,10 @@ obwohl die Geometrie dieselbe war. Der Ring bleibt dunkles Petrol und ordnet die Marke der Akzentfarbe zu; das Leuchten macht die Reichweite. */ #out .node.focusmark{box-shadow:0 0 0 3px var(--or),0 0 20px 7px rgba(20,184,166,.85);z-index:2} - /* Beides zugleich: Cursor-Zeile innen (Tinte), fremde Marke außen (Petrol). */ - #out .node.focusmark.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink),0 0 20px 7px rgba(20,184,166,.85)} + /* Beides zugleich: Cursor-Zeile innen (Tinte), fremde Marke außen (Petrol). + Die Erhebung der Cursor-Zeile gilt in jeder Kombination — der Schlagschatten + wird deshalb hier mit angehängt (das `transform` erbt die Regel oben). */ + #out .node.focusmark.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink),0 0 20px 7px rgba(20,184,166,.85),0 10px 20px -6px rgba(36,52,71,.5);z-index:3} /* Neu in Produktion seit dem letzten Besuch (D28): gelber Strahlenkranz um den 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 @@ -610,13 +622,44 @@ 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). */ - #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),0 10px 20px -6px rgba(36,52,71,.5);z-index:3} /* Neu in Produktion UND jemand zeigt darauf: Ring in Petrol (der bewusste Zuruf, innen), Kranz in Gelb (die stehende Nachricht, außen). Zwei Scheine nach außen gingen nicht — einer muss der Ring sein. Steht bewusst **nach** `.node.focusmark.current`: gleiche Spezifität (drei Klassen), und wenn alles drei zutrifft, soll Zuruf + Neuheit gewinnen, nicht die eigene Cursor-Zeile. */ #out .node.fresh.focusmark{box-shadow:0 0 0 3px var(--or),0 0 20px 7px rgba(234,179,8,.65);z-index:2} + /* Puls beim Zeilenwechsel (D25-Nachtrag): Man verliert den Knoten beim + **Bewegen**, nicht im Stillstand — also meldet er sich genau dann einmal. + Einmalig, kein Blinken: WCAG 2.2.2 zielt auf Blinkendes, 2.3.1 auf Flackern + über 3 Hz; ein einzelner Durchlauf ist keins von beidem (vgl. D28). + Ausgelöst wird er in `highlightCurrentNode()` **nur** bei geändertem + `caretLine` — sonst pulste er bei jedem Tastendruck. + Bewusst NICHT über `box-shadow` animiert: die Kombinationen mit `.fresh` und + `.focusmark` haben je eigene Schatten-Listen, eine Animation darauf ließe den + gelben bzw. petrolfarbenen Kranz für die Dauer des Pulses verschwinden. + Stattdessen zwei Kanäle, die niemand sonst benutzt: ein kurzer Hüpfer im + `transform` und ein auslaufender Ring auf dem freien `::after` + (`::before` gehört dem Optional-Kreis, D29). */ + @keyframes nodeLift{0%{transform:scale(1.04)}40%{transform:scale(1.11)}100%{transform:scale(1.04)}} + @keyframes nodeRipple{from{transform:scale(1);opacity:.5}to{transform:scale(1.4);opacity:0}} + #out .node.current.pulse{animation:nodeLift .36s ease-out 1} + /* `both` ist Pflicht: ohne Fill-Mode schnappt der Ring am Ende auf die + Anfangsdeckkraft zurück und bliebe stehen. */ + #out .node.current.pulse::after{ + content:'';position:absolute;inset:-3px;border-radius:calc(var(--r) + 3px); + border:2px solid var(--ink);pointer-events:none; + animation:nodeRipple .45s ease-out 1 both; + } + @media (prefers-reduced-motion: reduce){ + #out .node.current.pulse{animation:none} + #out .node.current.pulse::after{display:none} + } + /* Während `diagramToSvg()` misst: Erhebung und Puls abschalten — der Export + zeichnet aus der Live-Geometrie nach, und die Vergrößerung ist eine + Editierhilfe, keine Aussage über den Plan (D25). */ + #out.exporting .node.current{transform:none;animation:none} + #out.exporting .node.current::after{display:none} /* Alt gedrückt = Sprung-Geste scharf: Cursor an allen Knoten, Petrol-Ring am Knoten unter dem Zeiger. Auf verlinkten Knoten ist das die einzige Rückmeldung, weil dort der einfache Klick dem Link gehört (D25). */ @@ -696,6 +739,16 @@ der wahrscheinlichsten Gründe, überhaupt zu zeigen. Anders als beim optionalen Knoten (D29), wo das Zurücktreten die Aussage IST. */ .cheap-on .node:not(.cheap).focusmark{opacity:1;filter:none} + /* Und dasselbe für die Cursor-Zeile (D25-Nachtrag) — die Ausnahme fehlte hier + als einzige, obwohl der Fall der häufigste ist: Der Umschalter ist + voreingestellt an, und jeder optionale Knoten und jede nicht gewählte + Alternative ist „nicht auf dem Pfad" (im mitgelieferten Beispiel 7 von 18 + Knoten). Gemessen auf `+ [?] Dark mode`: Deckkraft 0,32 — der Ring war dort + praktisch unsichtbar. Wo der Cursor steht, muss sichtbar bleiben, egal wie + der Pfad entschieden hat; anders als beim optionalen Knoten (D29), wo das + Zurücktreten die Aussage IST, ist hier gar keine Aussage über den Plan + gemeint — es ist eine Editierhilfe. */ + .cheap-on .node:not(.cheap).current{opacity:1;filter:none} /* implizit als M angenommene Größe: invertiertes Badge (weiß statt petrol) */ .size.implicit{background:var(--card);color:var(--or);border-color:var(--or)} /* Günstigster-Pfad-Linie: gestrichelt, geschwungen, petrol — fädelt durch @@ -1078,8 +1131,12 @@ *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important} /* Knoten nicht über den Seitenrand zerschneiden */ #out li{break-inside:avoid} - /* Editierhilfe bzw. Zuruf, nicht drucken (D25, Fokusmarke SPEC §1) */ + /* Editierhilfe bzw. Zuruf, nicht drucken (D25, Fokusmarke SPEC §1). + Bei der Cursor-Zeile gehören Erhebung und Puls mit dazu — sonst stünde ein + Knoten im Druck grundlos vergrößert und schief zu seiner Anschlusslinie. */ .node.current,.node.focusmark{box-shadow:none!important} + .node.current{transform:none!important;animation:none!important} + .node.current::after{display:none!important} .node.fresh{box-shadow:none!important} /* „neu seit dem letzten Besuch" ist persönlich (D28) */ /* Faltung (D38): das ▾ offener Knoten ist Bedienelement — nicht drucken; das „▸ n" eingeklappter Knoten ist Kennzeichnung und bleibt. */