Das Licht folgt dem Zeiger - auf jeder Karte, und der Rand mit

Auf der Startseite gab es einen Lichtfleck unter dem Zeiger. Jetzt auf
JEDER Karte im ganzen Workspace -- und mit zwei Schichten statt einer:

  der FLECK   ein weicher Schein unter dem Zeiger, in der Farbe des
              Bereichs (--ton). Eine Aufgabenkarte leuchtet orange, eine
              Kalenderkarte tuerkis.
  der RAND    eine helle Stelle, die auf der KANTE mitwandert.

Der Rand ist der Teil, der den Unterschied macht. Er entsteht aus einem
Farbverlauf, von dem eine Maske nur den ein Pixel breiten Saum stehen
laesst: zwei Ebenen, eine ueber die Innenflaeche, eine ueber den ganzen
Kasten, und mask-composite: exclude laesst genau die Differenz uebrig --
den Rahmen. Dadurch leuchtet wirklich die Kante an der Stelle, an der
der Zeiger steht, statt eines Rechtecks, das so tut als ob.

Beides steckt in einem eingefuegten <span class="licht">. Ein eigenes
Element statt ::before/::after am Kasten selbst, weil die bei fast
allen Karten schon belegt sind (Akzentstreifen, Wasserzeichen) -- ein
Pseudo-Element doppelt zu benutzen geht nicht, und der Fehler faellt
erst auf, wenn eines von beiden verschwindet.

Kosten: EIN Zuhoerer fuer das ganze Dokument, gedrosselt auf einen
Bildaufbau, passiv angemeldet. Das Licht-Element wird beim ersten
Ueberfahren eingesetzt, nicht beim Laden -- Karten entstehen laufend
neu, wenn Listen sich aktualisieren. Ohne feinen Zeiger (Handy) und bei
"weniger Bewegung" laeuft gar nichts und es wird auch nichts eingefuegt.

pointerout feuert auch beim Wechsel zwischen Kindern INNERHALB einer
Karte. Ohne die Pruefung auf relatedTarget haette das Licht bei jeder
Bewegung ueber ein Wort hinweg geflackert.

DIE ALTE FASSUNG IN start.js IST WEG. Sie stehen zu lassen haette zwei
Zuhoerer auf denselben Bewegungen bedeutet -- doppelte Arbeit bei jedem
Zeigerzucken, und der Fehler waere erst aufgefallen, wenn jemand die
eine geaendert haette und sich nichts tat.

GEPRUEFT AN ECHTEN BILDPUNKTEN, nicht am Quelltext: Der Zeiger wird in
die Mitte einer Kachel gesetzt, dann wird die Helligkeit der Kante
direkt darueber gegen dieselbe Kante an der fernen Ecke gemessen.
Ergebnis 50 gegen 17. Geht die Maske jemals verloren, waere die ganze
Karte eingefaerbt und der Text unlesbar -- das faellt damit sofort auf.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-01 11:51:47 +02:00
co-authored by Claude Opus 5
parent 766c75b51d
commit 41ffb91688
23 changed files with 362 additions and 155 deletions
+93
View File
@@ -1463,3 +1463,96 @@ body.start #protokoll {
radial-gradient(90% 40% at 85% 98%, rgba(138, 118, 255, .07), transparent 72%);
}
}
/* =====================================================================
DAS LICHT FOLGT DEM ZEIGER — auf jeder Karte, im ganzen Workspace
Zwei Schichten in einem eingefuegten <span class="licht"> (siehe
kopf.js, dort steht auch, warum ein eigenes Element und nicht
::before am Kasten selbst):
::before der FLECK — ein weicher Schein unter dem Zeiger
::after der RAND — eine helle Stelle, die auf der KANTE
mitwandert
Der Rand ist der Teil, der es besonders macht. Er entsteht aus einem
Farbverlauf, von dem eine Maske nur den ein Pixel breiten Saum stehen
laesst: zwei Ebenen, eine ueber die Innenflaeche, eine ueber den
ganzen Kasten, und "exclude" laesst genau die Differenz uebrig — den
Rahmen. Dadurch leuchtet wirklich die Kante an der Stelle, an der der
Zeiger ist, statt eines Rechtecks, das so tut als ob.
Die Farbe kommt aus --ton, also aus der Kachelfarbe des Bereichs.
Eine Aufgabenkarte leuchtet orange, eine Kalenderkarte tuerkis.
===================================================================== */
.licht {
position: absolute; inset: 0;
border-radius: inherit;
pointer-events: none;
z-index: 0;
opacity: 0;
transition: opacity .28s ease;
}
[data-licht="an"] > .licht { opacity: 1; }
/* Der Fleck. Bewusst gross und sehr weich — ein kleiner harter Kreis
sieht nach Taschenlampe aus, ein grosser weicher nach Beleuchtung. */
.licht::before {
content: "";
position: absolute; inset: 0;
border-radius: inherit;
background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 0%),
color-mix(in srgb, var(--ton, var(--akzent)) 20%, transparent),
transparent 68%);
}
/* Der Rand. Etwas kleiner im Radius als der Fleck, dafuer kraeftiger --
so wirkt er wie eine Reflexion auf einer Kante, nicht wie ein zweiter
Schein. */
.licht::after {
content: "";
position: absolute; inset: 0;
border-radius: inherit;
padding: 1px;
background: radial-gradient(170px circle at var(--mx, 50%) var(--my, 0%),
color-mix(in srgb, var(--ton, var(--akzent)) 85%, #ffffff 15%),
color-mix(in srgb, var(--ton, var(--akzent)) 30%, transparent) 45%,
transparent 72%);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude;
}
/* Alles, was Licht bekommen soll, braucht einen eigenen Bezugspunkt --
sonst legt sich der Schein ueber die halbe Seite statt ueber die
Karte. Die meisten haben ihn schon; diese Zeile ist die Versicherung
fuer die uebrigen. */
.kachel, .karte, .spalte, .k-anlasskarte, .k-tag, .k-wochentag,
.dran__punkt, .zahl, .datei, .person, .eintrag, .thema,
.k-listentag, .steckbrief, .leer-hinweis, .block {
position: relative;
}
/* Inhalt ueber das Licht. Die Karten setzen ihre Kinder meist nicht
ausdruecklich; bei gleichem Stapelwert gewinnt das spaetere Element,
und .licht wird als erstes Kind eingefuegt. Fuer die Faelle, in denen
ein Kind selbst positioniert ist, hier die Zusicherung. */
.kachel__link, .kachel__text, .karte__titel, .spalte__kopf,
.k-anlasskarte__txt, .dran__link, .steckbrief__kopf { position: relative; z-index: 1; }
/* Ohne feinen Zeiger oder bei "weniger Bewegung" wird gar kein
Licht-Element eingefuegt (kopf.js). Diese Regel ist die zweite
Sicherung, falls doch eines im Dokument steht. */
@media (prefers-reduced-motion: reduce) {
.licht { display: none; }
}
@media (hover: none), (pointer: coarse) {
.licht { display: none; }
}
/* Im Kontrastmodus gibt es keine Farbverlaeufe -- ein Licht, das dort
als Flaeche erscheint, wuerde den Text verdecken. */
@media (forced-colors: active) {
.licht { display: none; }
}