Files
dogfather-universe/workspace/assets/css/module.css
T
DogFatherGitandClaude Opus 5 69ba533cee Wer mit der Tastatur bedient, sieht wieder, wo er steht
pruef-barrierefrei-workspace, wissen.html, Scout und Creator: Beim
Durchtabben veraendert sich an den Wissenskacheln NICHTS. Kein Rahmen,
kein Ring, keine Kante. Wer nicht mit der Maus arbeitet, tippt blind.

=== EIN SPEZIFITAETS-UNFALL, UND ER BETRIFFT NICHT NUR DIESE SEITE ===

Die Regel war da und richtig geschrieben:

  wissen.css   .kachel:focus-visible { box-shadow: 0 0 0 3px ... }

Sie kam nur nicht an. Gemessen mit einem neuen Werkzeug
(server/mess-fokus.mjs, echte Tastendruecke, kein focus()):

  :focus true   :focus-visible true
  boxShadow     gleich   rgba(0,0,0,0.95) 7px 7px 14px -10px inset
  outline       gleich   none

`:focus-visible` griff also, und trotzdem blieb alles, wie es war.
Der Grund steht in module.css, in einer Liste von 45 Klassennamen:

  :is(.eintrag-karte, ..., .kachel, ..., .gruppe[data-gruppe], ...)

`:is()` uebernimmt die Spezifitaet seines STAERKSTEN Arguments.
`.gruppe[data-gruppe]` ist eine Klasse PLUS ein Attribut. Damit ist die
ganze Liste (0,2,0) statt (0,1,0) -- genau so stark wie
`.kachel:focus-visible`. Bei Gleichstand gewinnt, was spaeter geladen
wird, und module.css wird zuletzt geladen. Ein einziges Attribut in
einer Aufzaehlung, sechs Zeilen weiter rechts, hat den Fokusring von
jedem Bauteil im Haus verschluckt, dessen Fokusregel aus einer Klasse
besteht.

=== GELOEST WIRD DAS NICHT, INDEM MAN DIE LISTE SCHWAECHER MACHT ===

Das war schon einmal so (`:where()`, Spezifitaet null) und ergab einen
Zwitter aus neuer Form und alter Kante -- der Kommentar in module.css
beschreibt es. Wer die Zahl senkt, verschiebt das Problem auf die
naechste Regel.

Geloest wird es, indem die ANTWORT dort steht: ein Fokusring fuer die
ganze Modulliste, in derselben Datei wie die Form, mit
`:focus-visible` also eine Klasse staerker als die Grundregel. Er gilt
damit fuer jedes Modul im Haus -- auch fuer die, die es noch nicht
gibt, und auch dort, wo nie jemand an eine Fokusregel gedacht hat.

`outline-offset` ist NEGATIV, und das ist kein Geschmack: `clip-path`
(die Fase an der Ecke) schneidet alles ab, was ausserhalb der Form
liegt. Ein Ring mit positivem Abstand waere unsichtbar gewesen -- der
alte war es ja auch. Nach innen gezeichnet bleibt er stehen. Gemessen,
nicht geschlossen.

=== WAS NICHT MITREPARIERT WURDE, UND WARUM ES DASTEHT ===

Derselbe Gleichstand trifft auch Hover-Regeln in frueher geladenen
Dateien: `.ablage:hover` (dateien.css), `.call:hover` (calls.css),
`.kk:hover` (scouting.css), `.fortschritt:hover` (uebersicht.css)
setzen alle `border-color`, und die Grundregel setzt `border: 0`.
Diese vier tun vermutlich nichts.

Angefasst habe ich sie nicht -- es gibt kein Messgeraet dafuer. Fokus
laesst sich pruefen (die Pruefung tabbt und vergleicht), Hover nicht.
Und die naheliegende Loesung wuerde die Form von 45 Bauteilen auf 38
Seiten neu entscheiden; das ohne Messgeraet zu tun waere Raten mit viel
Einsatz. Der Befund steht deshalb als Absatz in module.css, damit der
Naechste nicht wieder bei null anfaengt.

=== UND EINE BEHAUPTUNG VON MIR WIRD ZURUECKGENOMMEN ===

Im Commit d7bb0f7e steht, ein Mindestabstand von 0,10 sei fuer 45
Kachelfarben „rechnerisch nicht mehr moeglich", mit einer Tabelle von
„Decken". Das ist falsch herum gelesen: Das Werkzeug SUCHT eine
Anordnung. Findet es nichts Besseres, sagt das etwas ueber das
Verfahren, nicht ueber die Welt. Nachweisbar ist nur, was es GEFUNDEN
hat -- und wie wenig das eine Decke ist, zeigt der eigene Lauf: Fuer
dieselben 45 Farben kam dasselbe Verfahren je nach Rasterweite einmal
auf 0,0974 und einmal auf 0,0876.

Die Pruefung sagt das jetzt so, und das Werkzeug heisst zwar weiter
kachelton-decke.mjs, erklaert aber in den ersten zwanzig Zeilen, dass
es keine Decke misst. Beide Werkzeuge liegen jetzt ueberhaupt im
Verzeichnis: Sie hiessen `tools/_toene-*.mjs`, und `tools/_*` ist
ausgenommen -- die Kommentare verwiesen also auf Dateien, die es nach
dem Klonen nirgends gibt.

GEMESSEN, alles nach den Aenderungen:

  pruef-barrierefrei-workspace   18 Punkte, 0 Fehler (vorher 2)
  pruef-buehne                  230 Punkte, 0 Fehler
  pruef-kachelraster             15 Punkte, 0 Fehler
  pruef-start-ansicht           157 Punkte, 0 Fehler
  pruef-kopfleiste-farbe          9 Punkte, 0 Fehler
  pruef-rueckmeldung             30 Punkte, 0 Fehler
  pruef-entwicklung-kacheln      34 Punkte, 0 Fehler
  pruef-kachel-universum         13 Punkte, 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:50:54 +02:00

1544 lines
69 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =====================================================================
module.css — DIE FORM ALLER MODULE
Herausgeloest aus start.css am 07.09.2026. Diese Datei beschreibt die
SILHOUETTE der ganzen Anwendung: die abgeschnittene Ecke, das
Kantenlicht, die Eckwinkel und das Raster.
Sie wird von JEDER Seite geladen -- ausser von der Anmeldeseite
(index.html), die unangetastet bleibt.
SIE WIRD ALS LETZTE GELADEN, und das ist keine Kosmetik. Bis zum
07.09.2026 stand sie an dritter Stelle, VOR den Seitendateien. Dort
hat sie auf vier Seiten schlicht nichts bewirkt: `.call` in
calls.css, `.regel`/`.zustand`/`.ki-kasten` in automation.css,
`.unterweisung` in bereich.css und `.fortschritt` in dateien.css
setzen alle selbst `border-radius` und `box-shadow` -- gleiche
Spezifitaet, spaeter im Ladeweg, also gewinnen sie. Ergebnis war
genau das, was Filipe zu Recht bemaengelt hat: die neue Form auf
manchen Seiten, die alte auf anderen, "ueberall ein bisschen".
Als letzte Datei gewinnt die Form ueberall.
WER EINE NEUE KARTE BAUT, traegt ihren Klassennamen in die Listen
unten ein. Die Liste steht siebenmal in dieser Datei (Grundform,
Kantenlicht, Raster, Handy und dreimal Kontrastmodus) -- das ist die
schwache Stelle dieser Bauart, denn eine vergessene Kopie faellt
niemandem auf. Deshalb steht vor jeder Kopie die Marke
MODULLISTE, und `pruef-css-klassen.mjs` vergleicht alle sieben
Vorkommen miteinander: Weicht eines ab, wird die Pruefung rot.
===================================================================== */
/* =====================================================================
HUD-MODULE — die FORM ändert sich, nicht der Lack (07.09.2026)
Filipe: "DU HAST WIEDER EINE KLEINE ÄNDERUNG ÜBERALL GEMACHT ANSTATT
EINE RIESEN ÄNDERUNG."
---------------------------------------------------------------------
ER HAT RECHT, UND DER GRUND WAR IMMER DERSELBE
Ich habe dreimal das MATERIAL getauscht -- Mattglas, Leuchtschiene,
Verlauf mit Schatten -- und dreimal die FORM gelassen. Ein
abgerundetes Rechteck bleibt ein abgerundetes Rechteck. Die
Silhouette ist aber das Einzige, was man aus fünf Metern erkennt;
deshalb sah jede Änderung "wie vorher" aus.
DIE NEUE FORM:
1. DIE ECKE OBEN LINKS IST ABGESCHNITTEN. Eine Schräge statt einer
Rundung -- eine andere geometrische Klasse, und genau deshalb
fällt sie auf. Gebaut mit `clip-path`, also eine echte
Silhouette und kein aufgemalter Fleck.
2. EIN LICHT LÄUFT AUF DER KANTE, oben und über die Schräge, in der
Farbe der Kategorie -- nicht ein Rahmen rundherum (das wäre
wieder ein Kasten), sondern eine beleuchtete Oberkante.
3. ECKWINKEL UNTEN RECHTS. Zwei kurze Striche, die eine Ecke
andeuten, ohne sie zu zeichnen -- die Sprache von Peilung und
Zielmarke.
4. EIN FEINES RASTER statt Körnung. Körnung sagt "Papier", ein
Raster sagt "Messgerät".
---------------------------------------------------------------------
DREI DINGE, DIE BEIM ERSTEN ANLAUF SCHIEFGINGEN
`clip-path` SCHNEIDET DEN SCHLAGSCHATTEN AB. Deshalb liegt die Höhe
hier in `filter: drop-shadow()` und nicht in `box-shadow`: drop-shadow
folgt der WIRKLICHEN Form, box-shadow immer dem Rechteck -- er würde
einen Schatten für eine Ecke zeichnen, die es nicht mehr gibt.
DIE REGELN STANDEN IN `:where()`. Das hat Spezifität NULL, also
gewann jede ältere `.kachel::before`-Regel. Die Silhouette kam durch
(die setzt sonst niemand), das Kantenlicht nicht -- heraus kam ein
Zwitter aus neuer Form und alter Kante. Jetzt steht hier `:is()`:
Das übernimmt die Spezifität seines stärksten Arguments, also die
einer einzelnen Klasse. Damit liegt die Form gleichauf mit
`.kachel` und gewinnt über den Ladeweg -- deshalb muss diese Datei
zuletzt kommen (siehe oben).
UND SIE STAND ZU FRÜH IM LADEWEG. Siehe der Absatz ganz oben; das
war derselbe Fehler noch einmal, nur eine Ebene höher.
===================================================================== */
:root {
/* Die Schräge steht als Größe da, damit Silhouette, Kantenlicht und
Eckwinkel garantiert dieselbe benutzen. */
--fase: 18px;
/* DAS RASTER TRITT ZURUECK (09.09.2026, screen3).
Filipe: "die hintergrunde sollen ueberall so sein dass die sich
nicht in den vordergrund draengeln."
Es stand auf .26 Deckkraft. Das ist auf einer dunklen Flaeche kein
Hauch mehr, sondern ein gezeichnetes Gitter -- im Tagdialog lief es
sichtbar durch die Ueberschrift, in den Sammelkacheln stand es vor
den Karten darin. Ein Hintergrund, den man LIEST, ist kein
Hintergrund.
Jetzt .09. Das ist der Wert, bei dem man aus einem Meter Abstand
eine Struktur SIEHT, aber keine Linien ZAEHLT -- und genau das ist
der Unterschied zwischen Material und Muster. Dieselbe Ueberlegung
wie beim Kohlefasergewebe der Zentrale, das bei drei Prozent liegt.
EINE ZAHL FUER DAS GANZE HAUS: `--raster` steht hier einmal und
wird an 20 Stellen benutzt. Wer es leiser will, aendert diese eine
Zeile -- deshalb war es auch richtig, es nicht an jeder Kachel
einzeln nachzuziehen. */
--raster:
repeating-linear-gradient(0deg, rgba(150, 186, 220, .09) 0 1px, transparent 1px 26px),
repeating-linear-gradient(90deg, rgba(150, 186, 220, .09) 0 1px, transparent 1px 26px);
/* DAS STERNENFELD -- die Stelle, an der ein Haus dem Grund jeder
Kachel etwas Eigenes geben kann, OHNE die Kachelliste ein achtes
Mal abzuschreiben.
Hier steht `none`: Im Agenturhaus aendert sich dadurch kein
einziges Pixel -- eine Ebene ohne Bild zeichnet nichts. Wer ein
Haus baut, setzt diese drei Werte auf `:root` um und hat damit
jede Kachel der ganzen Adresse erwischt, auch die, die es noch
gar nicht gibt.
DREI WERTE, WEIL EIN HINTERGRUND DREI LISTEN HAT. Bild, Groesse
und Lage werden Ebene fuer Ebene einander zugeordnet. Wer nur das
Bild austauscht, bekommt die Groesse der Ebene davor -- deshalb
gehoeren sie zusammen und werden zusammen gesetzt.
Die FORM bleibt davon unberuehrt: Fase, Kantenlicht und Eckwinkel
stehen woanders. Ein Sternenfeld faerbt, es schneidet nicht. */
--sternenfeld: none;
--sternenfeld-mass: auto;
--sternenfeld-lage: 0 0;
/* Wie stark die ganze Ebene aus Raster, Eckwinkeln und Sternenfeld
durchkommt. Steht als Wert da, damit ein Haus mit eigenem Grund
ihn heben kann -- .26 bleibt der Wert des Agenturhauses. */
--modul-schleier: .26;
}
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl) {
position: relative;
clip-path: polygon(var(--fase) 0, 100% 0, 100% 100%, 0 100%, 0 var(--fase));
border-radius: 0;
border: 0;
/* STUFE 1: DIE SCHRAEGE WIRD EINE ECHTE FASE.
Bisher war die abgeschnittene Ecke ein Loch -- Material, das fehlt.
Eine gefraeste Fase ist etwas anderes: Sie hat eine FLAECHE, und
auf der liegt Schatten, weil sie schraeg zum Licht steht. Genau
das macht dieser Innenschatten aus der Richtung der Schraege. Der
Unterschied ist klein zu beschreiben und gross zu sehen: Aus einer
weggeschnittenen Ecke wird ein bearbeitetes Werkstueck.
`inset` und nicht aussen: Ein aeusserer Schatten liegt hier im
`filter` (siehe unten), weil `clip-path` einen `box-shadow` nach
der Form abschneiden wuerde. Ein INNERER Schatten wird von
derselben Form sauber begrenzt -- er soll ja hineinreichen. */
box-shadow: inset 7px 7px 14px -10px rgba(0, 0, 0, .95);
filter:
drop-shadow(0 2px 3px rgba(0, 0, 0, .55))
drop-shadow(0 12px 22px rgba(0, 0, 0, .55));
}
/* DAS KANTENLICHT. Ein Layer mit derselben Silhouette, 1,6 px kleiner --
was übrig bleibt, ist eine Linie, die exakt der Form folgt, Schräge
inklusive. Ein `border` könnte das nicht: Er folgt dem Rechteck. */
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl)::before {
content: "";
position: absolute; inset: 0;
pointer-events: none;
z-index: 2;
width: auto; height: auto;
opacity: 1;
background: linear-gradient(158deg,
color-mix(in srgb, var(--ton, var(--akzent)) 90%, #ffffff) 0%,
color-mix(in srgb, var(--ton, var(--akzent)) 60%, transparent) 15%,
rgba(150, 186, 220, .20) 45%,
rgba(150, 186, 220, .07) 100%);
clip-path: polygon(
var(--fase) 0, 100% 0, 100% 100%, 0 100%, 0 var(--fase),
1.6px calc(var(--fase) + 0.7px), 1.6px calc(100% - 1.6px),
calc(100% - 1.6px) calc(100% - 1.6px), calc(100% - 1.6px) 1.6px,
calc(var(--fase) + 0.7px) 1.6px, 1.6px calc(var(--fase) + 0.7px),
0 var(--fase));
}
/* RASTER UND ECKWINKEL. Beides auf ::after -- ein drittes Element gibt
es nicht, und beides ist reine Optik ohne Klicks. */
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl)::after {
content: "";
position: absolute; inset: 0;
pointer-events: none;
z-index: 0;
/* STUFE 2: ECKWINKEL AN DREI ECKEN STATT AN EINER.
Eine einzelne Ecke unten rechts liest sich als Verzierung. Drei
Ecken lesen sich als RAHMUNG -- das Auge schliesst sie zu einem
Ausschnitt, und genau diese Sprache benutzen Peilung, Zielmarke
und Messgeraet.
Die vierte Ecke bleibt frei, und das ist Absicht: Dort sitzt die
Fase. Ein Winkel auf einer abgeschnittenen Ecke waere ein Winkel,
der ins Leere zeigt.
Sechs Verlaufsebenen fuer sechs Striche. Jede Ebene ist eine
einfarbige Flaeche, die durch `background-size` auf einen Strich
zusammenschrumpft -- billiger als sechs Elemente im Baum, und sie
wandern beim Groessenwechsel automatisch mit. */
--winkel: linear-gradient(var(--ton, var(--akzent)), var(--ton, var(--akzent))) no-repeat;
background:
var(--winkel), var(--winkel), /* unten rechts */
var(--winkel), var(--winkel), /* oben rechts */
var(--winkel), var(--winkel), /* unten links */
var(--raster),
var(--sternenfeld, none);
background-size:
18px 1.5px, 1.5px 18px,
18px 1.5px, 1.5px 18px,
18px 1.5px, 1.5px 18px,
26px 26px, 26px 26px,
var(--sternenfeld-mass, auto);
background-position:
right 10px bottom 10px, right 10px bottom 10px,
right 10px top 10px, right 10px top 10px,
left 10px bottom 10px, left 10px bottom 10px,
0 0, 0 0,
var(--sternenfeld-lage, 0 0);
/* .3 war zu laut: Das Raster soll man nicht LESEN, sondern spueren.
Bei 26 px Abstand und einem Viertel Deckkraft bleibt der Eindruck
"Messgeraet", ohne dass die Linien mit dem Text konkurrieren. */
opacity: var(--modul-schleier, .26);
transform: none;
}
/* Der Inhalt gehört ÜBER Raster und Kantenlicht. Ohne diese Zeile
liegt bei Karten ohne eigenen Stapelwert der Text unter dem Raster
und wird von ihm überzeichnet.
`:not(.licht)` IST KEINE FEINHEIT, SONDERN DIE REPARATUR EINES
FEHLERS, DEN DIESE ZEILE SELBST VERURSACHT HAT (07.09.2026).
Das Licht, das dem Zeiger folgt, ist ein <span class="licht"> und
damit ein direktes Kind jeder Karte. `position: relative` hat ihm
sein `position: absolute` genommen: Aus einer Fläche über der ganzen
Karte wurde ein leerer Inline-Span ohne Ausdehnung. Im Browser
gemessen -- `display: inline`, obwohl in start.css `absolute`
steht -- und genau deshalb war das Licht weg, das Filipe
zurückhaben wollte.
Merksatz: Eine Regel auf `> *` trifft auch das, was gar kein Inhalt
ist. Wer sie schreibt, muss wissen, was sonst noch als Kind in
diesen Karten liegt. */
:is(.eintrag-karte, .call, .datei, .kachel, .leer-hinweis,
.team-karte, .zahl, .k-listentag, .person, .creator) > *:not(.licht) {
position: relative;
z-index: 1;
}
/* Beim Anfassen kommt das Modul NÄHER, es leuchtet nicht auf. */
:is(.kachel, .datei, .pdf, .creator, .person, .kk, .call, .team-karte):hover {
transform: translateY(-3px);
box-shadow: none;
filter:
drop-shadow(0 4px 6px rgba(0, 0, 0, .6))
drop-shadow(0 20px 34px rgba(0, 0, 0, .6))
drop-shadow(0 0 14px color-mix(in srgb, var(--ton, var(--akzent)) 30%, transparent));
}
:is(.kachel, .datei, .pdf, .creator, .person, .kk, .call, .team-karte) {
transition: transform var(--tempo), filter var(--tempo);
}
/* =====================================================================
WER MIT DER TASTATUR BEDIENT, MUSS SEHEN, WO ER STEHT (25.09.2026)
Gefunden von pruef-barrierefrei-workspace auf wissen.html: Die
Wissenskacheln zeigten beim Durchtabben KEINE Veraenderung --
gemessen mit echten Tastendruecken, nicht mit focus().
Die Ursache ist ein Spezifitaets-Unfall, und sie betrifft nicht nur
diese eine Seite:
wissen.css .kachel:focus-visible (0,2,0)
module.css :is(... .gruppe[data-gruppe] ...) (0,2,0)
`:is()` uebernimmt die Spezifitaet seines STAERKSTEN Arguments.
In der Modulliste steht `.gruppe[data-gruppe]` -- eine Klasse PLUS
ein Attribut. Damit ist die ganze Liste (0,2,0) statt (0,1,0), und
weil diese Datei zuletzt geladen wird, gewinnt sie bei
Gleichstand. Der `box-shadow` des Fokusrings wurde also vom
Faseschatten dieser Datei ueberschrieben -- auf JEDEM Modul, dessen
Fokusregel nur aus einer Klasse und `:focus-visible` besteht.
NICHT GELOEST WIRD DAS, INDEM MAN DIE LISTE SCHWAECHER MACHT. Das
war schon einmal so (`:where()`, Spezifitaet null) und hat einen
Zwitter aus neuer Form und alter Kante ergeben -- der Absatz oben
beschreibt es. Wer die Zahl senkt, verschiebt das Problem nur auf
die naechste Regel.
GELOEST WIRD ES, INDEM DIE ANTWORT HIER STEHT. Ein Fokusring fuer
die ganze Modulliste, in derselben Datei wie die Form, mit
`:focus-visible` also eine Klasse staerker als die Grundregel. Er
gilt damit fuer jedes Modul im Haus -- auch fuer die, die es noch
nicht gibt, und auch dort, wo niemand an eine Fokusregel gedacht
hat. Das ist der Unterschied zwischen einer Reparatur und einer
Regel.
`outline-offset` ist NEGATIV, und das ist kein Geschmack:
`clip-path` schneidet alles ab, was ausserhalb der Form liegt --
ein Ring mit positivem Abstand waere unsichtbar. Nach innen
gezeichnet liegt er drin und bleibt stehen. Gemessen mit
server/mess-fokus.mjs.
`:focus-visible` und nicht `:focus`: Wer mit der Maus klickt, will
keinen Rahmen sehen. Die Browser entscheiden das selbst, und sie
entscheiden es richtig.
NOCH OFFEN, UND HIER NOTIERT, DAMIT ES NICHT VERLORENGEHT: Derselbe
Gleichstand trifft auch HOVER-Regeln in frueher geladenen Dateien.
`.ablage:hover` in dateien.css, `.call:hover` in calls.css,
`.kk:hover` in scouting.css und `.fortschritt:hover` in
uebersicht.css setzen alle `border-color` -- und die Grundregel
oben setzt `border: 0`, gleich stark und spaeter im Ladeweg. Diese
vier Regeln tun also vermutlich nichts.
NICHT MITREPARIERT, weil es kein Messgeraet dafuer gibt: Fokus
laesst sich pruefen (pruef-barrierefrei-workspace tabbt und
vergleicht), Hover nicht -- es gibt keine Pruefung, die sagen
koennte, ob eine Aenderung dort etwas kaputt macht. Und die
naheliegende Loesung (die Grundregel schwaecher machen, indem
`.gruppe[data-gruppe]` aus der Liste in einen eigenen Selektor
wandert) wuerde die Form von 45 Bauteilen auf 38 Seiten neu
entscheiden. Das ohne Messgeraet zu tun, waere Raten mit viel
Einsatz. */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl):focus-visible {
outline: 2px solid var(--akzent);
outline-offset: -4px;
}
@media (max-width: 620px) {
/* Dieselbe Form, kleiner -- keine zweite Gestaltung. */
:root { --fase: 12px; }
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl) {
filter: drop-shadow(0 3px 8px rgba(0, 0, 0, .7));
}
}
@media (prefers-reduced-motion: reduce) {
:is(.kachel, .datei, .pdf, .creator, .person, .kk, .call, .team-karte):hover {
transform: none;
}
}
@media (forced-colors: active) {
/* Im Kontrastmodus zählt die Kante, und die muss ein echter `border`
sein. Die Schräge bleibt: Sie ist Geometrie, keine Farbe. */
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl) {
filter: none; border: 1px solid CanvasText;
}
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl)::after {
display: none;
}
/* MODULLISTE */
:is(.eintrag-karte, .call, .chat, .datei, .ablage, .zahlkarte, .regel, .zustand, .ki-kasten, .spalte, .balance, .saeulen-kasten, .neu, .call-raum, .creator, .summe, .pdf, .pdf-ablage, .suchleiste, .person, .kk, .fortschritt, .punkt, .dran__punkt, .unterweisung, .warnkarte, .kachel, .tagesblick, .leer-hinweis, .team-karte, .zahl, .k-listentag, .import-vorschau, .code-fenster, .schulung__neu, .gruppe[data-gruppe], .kopf-zeile, .k-kopf, .steckbrief, .k-anlasskarte, .k-anlasskachel, .k-raster, .entscheidung, .liste-kachel, fieldset.gruppe, .t-kachel, .tperson, .tl)::before {
display: none;
}
}
/* =====================================================================
STUFE 3: DAS ZEICHEN BEKOMMT EINE METALLFASSUNG (07.09.2026)
Filipe: "perfektionier alle kacheln die du vorhin gewechselt hast auf
der ganzen website, mach sie alle noch geiler und geiler und noch
spezieller. sie gehen aber in eine gute richtung schon."
Die Plakette war ein abgerundetes Quadrat mit einem Farbschleier --
also dieselbe Form wie ueberall sonst im Netz. Sie wird jetzt zu
einem GEFASSTEN Schild:
* dieselbe abgeschnittene Ecke wie die Karte, nur kleiner. Ein
Bauteil, das zu seinem Gehaeuse passt.
* ein 2 px breiter Ring aus gebuerstetem Metall -- dieselbe
Handschrift wie die Luenette der Uhr und die Fassung der
Konsole. Damit spricht die ganze Anwendung EINE Materialsprache
statt drei.
* die Farbe der Kategorie liegt INNEN, im Schild, nicht im Ring.
So bleibt der Ring ueberall gleich und das Schild verschieden --
genau die Aufteilung, die ein Typenschild auf einem Geraet hat.
Diese Regeln stehen HIER und nicht in start.css: module.css wird
zuletzt geladen und ist der Ort fuer die FORM. In start.css
beschriebe man dieselbe Sache noch einmal an zweiter Stelle, und die
beiden liefen beim naechsten Mal auseinander.
===================================================================== */
.kachel__zeichen {
--z-fase: 9px;
position: relative;
border: 0;
border-radius: 0;
padding: 2px;
overflow: visible;
clip-path: polygon(
var(--z-fase) 0, 100% 0, 100% 100%, 0 100%, 0 var(--z-fase));
/* Gebuerstetes Metall, rund gedreht -- rund heisst conic. Die Lehre
von heute Nachmittag: Die Verlaufsart muss zur FORM passen. */
/* GEDAEMPFT, aber mit demselben Wechsel. Der erste Anlauf war fast
weiss -- auf 2 px Breite las sich das als greller Rahmen, und die
Fassung zog mehr Aufmerksamkeit als das Zeichen darin. Eine
Fassung ist Beiwerk; sie soll das Schild halten, nicht mit ihm
konkurrieren. Also dieselben Stopps, nur eine Blende dunkler --
der Wechsel hell/dunkel bleibt, und mit ihm das Metall. */
background:
conic-gradient(from 210deg,
#b9c8da 0deg, #5a6b80 44deg, #d6e2ef 88deg, #44536a 140deg,
#aebdd0 196deg, #64758c 244deg, #cddaea 296deg, #4e5d73 340deg,
#b9c8da 360deg);
box-shadow:
0 6px 16px -8px rgba(0, 0, 0, .9),
0 0 0 1px rgba(6, 10, 18, .55),
/* DAS LICHT DES SCHILDES FAELLT AUF DIE KACHEL. Ein beleuchteter
Gegenstand wirft Farbe auf seine Umgebung -- ohne diesen Abfall
sieht selbst ein gut gebautes Schild aufgeklebt aus. Sehr weit
gestreut und weit unter der Blendschwelle: Man soll ihn nicht
sehen, man soll ihn vermissen, wenn er fehlt. */
0 10px 42px -14px color-mix(in srgb, var(--ton, var(--akzent)) 75%, transparent);
}
/* Das Schild IM Ring -- hier liegt die Farbe der Kategorie. */
.kachel__zeichen::before {
content: "";
position: absolute; inset: 2px;
z-index: 0;
pointer-events: none;
clip-path: polygon(
calc(var(--z-fase) - 2px) 0, 100% 0, 100% 100%, 0 100%,
0 calc(var(--z-fase) - 2px));
background:
linear-gradient(150deg, rgba(255, 255, 255, .20) 0%, rgba(255, 255, 255, .04) 26%, transparent 52%),
radial-gradient(120% 100% at 22% 8%,
color-mix(in srgb, var(--ton, var(--akzent)) 58%, transparent) 0%,
color-mix(in srgb, var(--ton, var(--akzent)) 26%, transparent) 48%,
color-mix(in srgb, var(--ton, var(--akzent)) 10%, transparent) 100%),
linear-gradient(#0a0f18, #0a0f18);
}
/* Beim Anfassen hebt sich das Schild leicht -- kein Leuchten, nur
Naehe. Dieselbe Sprache wie bei der Karte selbst. */
.kachel:hover .kachel__zeichen {
transform: translateY(-1px);
border-color: transparent;
box-shadow:
0 10px 22px -9px rgba(0, 0, 0, .95),
0 0 0 1px rgba(6, 10, 18, .55),
0 0 14px -4px color-mix(in srgb, var(--ton, var(--akzent)) 55%, transparent);
}
/* DIE GROSSE KACHEL FUEHRT IHRE EIGENE RUNDUNG -- zweimal sogar
(start.css, 21 px und 18 px), und beide sind mit `.kachel[…] .x`
staerker als eine einzelne Klasse. Gemessen: `border-radius: 18px`,
obwohl module.css `0` setzt und zuletzt geladen wird. Die Fase kam
durch (die setzt sonst niemand), die Rundung blieb -- heraus kam ein
Schild mit abgeschnittener Ecke UND runden Ecken.
Dieselbe Falle wie heute schon zweimal: `:where()` war zu schwach,
`body.start .willkommen` zu stark, und hier ist es die Verschachtelung.
Deshalb steht die Antwort hier mit derselben Gewichtung wie die
Rundung, die sie ersetzt. */
.kachel[data-gross="ja"] .kachel__zeichen,
.kachel .kachel__zeichen {
--z-fase: 11px;
border-radius: 0;
}
@media (forced-colors: active) {
/* Im Kontrastmodus zaehlt die Kante. Die Fase bleibt -- sie ist
Geometrie, keine Farbe. */
.kachel__zeichen { background: Canvas; border: 1px solid CanvasText; box-shadow: none; }
.kachel__zeichen::before { display: none; }
}
/* =====================================================================
DIE TAGESKACHEL "WAS IST DRAN" (07.09.2026)
Filipe: "soll auch besser und auffaelliger aussehen bitte."
Sie bestand aus drei abgerundeten Zeilen mit einem Farbstreifen
links -- also aus der Form, die es hier bis heute Frueh ueberall
gab. Sie bekommt jetzt dieselbe Behandlung wie alles andere, und
zwar konsequent:
* Die drei Zeilen sind MODULE. `.dran__punkt` steht seit heute in
der Modulliste oben: abgeschnittene Ecke, Kantenlicht in der
Farbe des Bereichs, Eckwinkel, Fase. Damit sind sie kleine
Ausgaben derselben Bauteile, zu denen sie fuehren -- was sie ja
auch sind.
* Die ZAHL wird zum gefassten Schild, wie das Zeichen auf den
Kacheln. Sie ist die eigentliche Aussage der Zeile ("EINS
wartet"), und sie stand bisher als blosse Ziffer daneben.
* Zwischen den beiden Haelften laeuft eine gefraeste Nut statt
einer Linie -- dieselbe Sprache wie auf der Konsole.
===================================================================== */
/* Der Farbstreifen links entfaellt: Die Zeile hat jetzt ein
Kantenlicht, und beides zusammen waeren zwei Kanten fuer dieselbe
Aussage. */
.dran__punkt::before { width: 0; }
.dran__zahl {
--z-fase: 7px;
display: grid; place-items: center;
min-width: 30px; min-height: 26px;
padding: 2px;
font-size: 1.02rem;
/* DIE FARBE BLEIBT IN DER ZIFFER, nicht im Schild.
Im ersten Anlauf stand hier Weiss, weil das auf Metall gut
aussieht. Damit war die Aussage weg: Die Zahl traegt die Farbe des
Bereichs, zu dem die Zeile fuehrt -- und bei etwas Ueberfaelligem
die Warnfarbe. Das ist kein Schmuck, sondern die schnellste
Auskunft der ganzen Kachel. pruef-start-ansicht hat es sofort
gemeldet ("ueberfaellige Zeilen sind rot": weiss statt rot), und
die Pruefung hatte recht.
Das Schild darunter bleibt deshalb fast neutral -- nur eine Spur
Farbton, damit die Ziffer nicht auf Grau steht. */
color: var(--ton, var(--akzent));
text-align: center;
clip-path: polygon(var(--z-fase) 0, 100% 0, 100% 100%, 0 100%, 0 var(--z-fase));
background:
conic-gradient(from 210deg,
#b9c8da 0deg, #5a6b80 44deg, #d6e2ef 88deg, #44536a 140deg,
#aebdd0 196deg, #64758c 244deg, #cddaea 296deg, #4e5d73 340deg,
#b9c8da 360deg);
box-shadow: 0 4px 12px -7px rgba(0, 0, 0, .9), 0 0 0 1px rgba(6, 10, 18, .5);
}
/* Das Schild IM Ring traegt die Farbe des Bereichs -- wie bei den
Kacheln liegt die Farbe innen, das Metall bleibt ueberall gleich. */
.dran__zahl::before {
content: ""; position: absolute; inset: 2px; z-index: -1;
clip-path: polygon(
calc(var(--z-fase) - 2px) 0, 100% 0, 100% 100%, 0 100%,
0 calc(var(--z-fase) - 2px));
background:
linear-gradient(150deg, rgba(255, 255, 255, .10) 0%, transparent 48%),
linear-gradient(color-mix(in srgb, var(--ton, var(--akzent)) 14%, #080d15),
color-mix(in srgb, var(--ton, var(--akzent)) 6%, #080d15));
}
.dran__zahl { position: relative; isolation: isolate; }
/* Die Nut zwischen "Was ist dran" und "Heute". Dunkel auf der
Lichtseite, hell auf der Schattenseite -- so liest sich eine
Vertiefung. Eine aufgemalte Linie kann das nicht. */
.tagesblick__seite--heute::before {
content: ""; position: absolute;
left: -21px; top: -6px; bottom: -6px; width: 2px;
pointer-events: none;
background: linear-gradient(90deg,
rgba(0, 0, 0, .75) 0 1px,
rgba(255, 255, 255, .12) 1px 2px);
}
@media (forced-colors: active) {
.dran__zahl { background: Canvas; box-shadow: none; border: 1px solid CanvasText; }
.dran__zahl::before { display: none; }
.tagesblick__seite--heute::before { background: CanvasText; }
}
/* =====================================================================
TIPPZIELE AUF GERÄTEN, DIE MIT DEM FINGER BEDIENT WERDEN
(19.09.2026)
Diese Regel stand zuerst in `start.css` — und griff nicht. Der Grund
ist die Ladereihenfolge: Jede Seite lädt `gate → start → seite →
module → haus`. `aufgaben.css` setzt `.schnitt { min-height: 38px }`
mit derselben Stärke, kommt aber SPÄTER und gewinnt damit.
Gefunden hat das nicht das Lesen, sondern der Rundgang: Nach der
Änderung meldete er `.schnitt` unverändert mit 38 px. Eine Regel, die
man geschrieben hat und die nicht ankommt, sieht im Editor genauso
aus wie eine, die wirkt.
`module.css` ist die vorletzte Datei und schlägt damit jede
Seitendatei. `haus.css` bleibt die letzte — dort geht es um Farben
des Hauses, nicht um Maße.
WARUM `pointer: coarse` UND NICHT EINE BREITE: Die Frage ist nicht,
wie breit der Bildschirm ist, sondern womit jemand tippt. Ein
schmales Browserfenster am Rechner wird mit der Maus bedient und
braucht keine 44 px; ein 1200 px breites Tablet sehr wohl. Eine
Breite hätte beide Fälle falsch beantwortet.
===================================================================== */
@media (pointer: coarse) {
.filterreihe__knopf, .k-chip, .k-ansicht, .marke-tag, .tag-knopf,
.schnitt, .creator-knopf, .tagzeile__knopf, .starthilfe__beispiel,
.t-kuemmern__knopf, .bw-kuemmern__knopf, .wecker-knopf, .wahl2__knopf {
min-height: 44px;
}
/* Die Kalenderpfeile und das Rechtefeld waren zu SCHMAL, nicht zu
niedrig -- 38 bzw. 34 px. Ein Pfeil, den man nicht trifft, blättert
nicht. */
#zurueck-zeit, #vor-zeit, .rechte-feld, .k-pfeil {
min-width: 44px; min-height: 44px;
}
/* Nachgetragen nach dem zweiten Lauf -- der Rundgang hat sie einzeln
benannt, statt dass ich sie hätte raten müssen. */
.knopf, .k-pille { min-height: 44px; }
/* `flex`, NICHT `inline-flex` (berichtigt 20.09.2026).
Gestern stand hier `inline-flex`, um den Text in der jetzt 44 px
hohen Pille mittig zu halten. Damit war sie aber nicht mehr
block-artig und schrumpfte auf die Textbreite: Der Handy-Rundgang
meldete sie heute mit 39x44 -- zu schmal, obwohl sie vorher die
ganze Zelle ausgefuellt hatte. Meine eigene Reparatur hatte ein
neues Problem gemacht.
`flex` zentriert genauso und bleibt block-artig. */
.k-pille { display: flex; align-items: center; }
/* Der Ersatzknopf der Auswahlfelder ist `width: 100%` -- in einer
schmalen Spalte wird er damit 34 px breit. Lieber einmal über den
Rand als dauerhaft nicht zu treffen. */
/* AN DER HUELLE, NICHT AM KNOPF (berichtigt 19.09.2026).
Erst stand hier nur `.wahl2__knopf { min-width: 44px }` -- und der
Knopf blieb 34 px. Der Grund liegt eine Ebene hoeher: start.css
setzt auf dem Handy `.wahl2 { min-width: 0 }`, damit schmale
Geraete nicht waagerecht schieben muessen. Die Huelle schrumpft
also auf 34 px, und der Knopf darin ist `width: 100%`.
Eine Mindestbreite am Kind gegen eine Null am Elternteil ist ein
Kampf, den das Kind nicht gewinnt. Also bekommt die Huelle ihre
44 px -- und der Knopf folgt von selbst. Die urspruengliche
Absicht (kein waagerechtes Schieben) bleibt gewahrt: 44 px ist
schmaler als jedes Feld vorher. */
.wahl2, .wahl2__knopf { min-width: 44px; }
/* Und die Filterknoepfe waren 41 statt 44 breit -- drei Pixel, die
der Rundgang sechsmal gemeldet hat. */
.filterreihe__knopf, .k-chip { min-width: 44px; }
}
/* =====================================================================
DER DIALOG — hierher verschoben am 19.09.2026
Er stand in `aufgaben.css` und `leistung.css`. Das war richtig,
solange nur diese zwei Seiten einen Dialog hatten. Seit es
`nachfrage.js` gibt, kann JEDE Seite nachfragen, bevor etwas weg
ist -- und auf einer Seite, die `aufgaben.css` nicht laedt, waere
der Dialog ungestaltet gewesen: weisser Kasten, Systemschrift,
mitten auf einer dunklen Seite.
`module.css` laedt auf jeder Seite (vorletzte Datei, direkt vor
`haus.css`). Was mehr als eine Seite benutzt, gehoert hierher.
In `aufgaben.css` bleibt genau eine Regel: `.dialog__knoepfe
#b-loeschen` -- die haengt an einer ID, die es nur dort gibt.
===================================================================== */
/* =====================================================================
DIALOGE (07.09.2026 überarbeitet)
Filipe zu zwei davon: "lass alles in dieser kachel viel spezieller und
geiler aussehen" und "dass soll auch viel besser aussehen".
Er hatte recht, und der Grund war nicht Geschmack: Ein Dialog war
bisher ein grauer Kasten (`background: #0b1018`, ein Rand, fertig) --
während die Seite dahinter aus beleuchteten Platten mit Schienen,
Körnung und Glanz besteht. Beim Öffnen fiel man aus dem einen
Material ins andere.
Jetzt trägt er dieselbe Sprache wie alles übrige:
- Leuchtschiene links, im Hausakzent
- Kopfzeile abgesetzt mit einer feinen Fuge
- Körnung und ein fester Glanz von links oben
- Materialstärke: Licht oben, Schatten unten
Und er ist deutlich TIEFER als vorher (#0b1018 war ein helles Grau
gegen das, was jetzt hinter ihm liegt) -- ein Dialog muss sich vom
Untergrund abheben, sonst schwimmt er darin.
Der Hintergrund dahinter wird STÄRKER abgedunkelt und weicher
gezeichnet: Ein Dialog ist der einzige Ort, an dem ein Weichzeichner
richtig ist -- er soll das Dahinter ausdrücklich zurücktreten
lassen. Genau dafür ist er gemacht, und genau deshalb war er unter
den Kacheln falsch.
===================================================================== */
.dialog {
position: relative;
width: min(580px, calc(100vw - 32px));
padding: 0;
border: 1px solid rgba(150, 186, 220, .16);
/* DIE FASE STATT RUNDER ECKEN (08.09.2026).
Filipe: "alles was sie sehen soll dan auch nach der neuen struktur
aufgebaut sein" -- und ein Dialog ist das, was man am genauesten
ansieht, weil er alles andere verdeckt.
Er kann NICHT in die Modulliste von module.css: Die belegt
`::before` und `::after` fuer die Eckwinkel, und beide sind hier
schon vergeben -- an die Leuchtschiene links und den Lichtsaum.
Beides gegen zwei Winkel zu tauschen waere ein Rueckschritt.
Deshalb hier nur der Zuschnitt, von Hand, mit derselben Groesse
`--fase` wie ueberall. Wer die Fase spaeter aendert, aendert sie
hier mit. */
clip-path: polygon(var(--fase, 18px) 0, 100% 0, 100% 100%, 0 100%, 0 var(--fase, 18px));
border-radius: 0;
background:
linear-gradient(90deg,
color-mix(in srgb, var(--akzent) 16%, transparent) 0%,
color-mix(in srgb, var(--akzent) 5%, transparent) 14%,
transparent 40%),
linear-gradient(163deg, #141c29 0%, #0a0e17 58%, #070a11 100%);
color: var(--text);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .55),
inset 2px 0 0 -1px color-mix(in srgb, var(--akzent) 34%, transparent),
0 30px 70px -24px rgba(0, 0, 0, .92),
0 4px 12px -6px rgba(0, 0, 0, .7);
overflow: hidden;
}
/* Die Leuchtschiene -- dieselbe wie an jeder Kachel. */
.dialog::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
border-radius: 4px 0 0 4px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--akzent) 55%, #fff) 0%,
var(--akzent) 26%,
color-mix(in srgb, var(--akzent) 48%, transparent) 100%);
box-shadow:
0 0 9px 0 color-mix(in srgb, var(--akzent) 55%, transparent),
3px 0 20px -3px color-mix(in srgb, var(--akzent) 42%, transparent);
z-index: 2;
}
/* Glanz und Körnung. `pointer-events: none` ist Pflicht: Ohne das läge
eine unsichtbare Fläche über dem ganzen Formular, und kein einziges
Feld wäre anklickbar. */
.dialog::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background:
linear-gradient(122deg,
rgba(255, 255, 255, .075) 0%,
rgba(255, 255, 255, .020) 15%,
transparent 34%);
/* Ohne Körnung -- siehe die Begründung in automation.css: Auf einer
Ebene mit der Spiegelung erbt sie deren Deckkraft und wird zum
grauen Schleier. */
opacity: .55;
z-index: 1;
}
.dialog > * { position: relative; z-index: 2; }
.dialog::backdrop {
background: rgba(2, 4, 8, .78);
backdrop-filter: blur(6px) saturate(80%);
}
/* Der Kopf steht auf einer eigenen Stufe: Überschrift, darunter der
erklärende Satz, darunter eine feine Fuge. Ohne diese Trennung
verschwimmt die Ansage mit dem ersten Feld -- und genau die Ansage
ist das, was den Dialog erklärt. */
.dialog__titel {
margin: 0 0 4px;
font-size: 1.24rem; font-weight: 700; letter-spacing: -.015em;
color: #f2f7fd;
}
.dialog__unter {
margin: 0 0 16px; padding-bottom: 16px;
border-bottom: 1px solid rgba(150, 186, 220, .12);
font-size: .87rem; line-height: 1.55;
color: var(--text-leise);
}
/* Hat ein Dialog keine Erklärung, muss die Fuge trotzdem da sein --
sonst hängt die Überschrift am ersten Feld. */
.dialog__titel:last-of-type,
.dialog__unter:empty { border-bottom: 0; }
.dialog__unter:empty {
margin: 0 0 16px; padding-bottom: 16px;
border-bottom: 1px solid rgba(150, 186, 220, .12);
}
/* =====================================================================
AUS EINEM FENSTER MUSS MAN HERAUSKOMMEN (25.09.2026)
=====================================================================
Miss, ueber den Support-Weg: „Ich konnte da wieder nicht zurueck
gehen, musste die App schliessen damit ich wieder auf die Hauptseite
kam." Dazu ein Bild von „Aufgabe bearbeiten" auf dem Handy.
GEMESSEN (mess-dialog-ausgang.mjs), vier Groessen:
412 x 915 installierte App 782 px Inhalt in 784 px -- knapp ja
412 x 780 Browser mit Leiste 782 px Inhalt in 742 px -- SACKGASSE
360 x 640 aelteres Geraet 794 px Inhalt in 602 px -- SACKGASSE
412 x 430 Tastatur offen 794 px Inhalt in 392 px -- SACKGASSE
`.dialog` hatte `overflow: hidden`, und eine Scroll-Hoehe gab es NUR
fuer `.dialog--breit .neu`. Bei allen anderen wurde alles unterhalb
des Rands schlicht abgeschnitten -- samt der Knopfzeile mit
„Abbrechen". Kein Rollbalken, kein Hinweis, kein Weg zurueck. Auf
dem Rechner faellt das nie auf: Dort ist der Bildschirm hoch genug.
---------------------------------------------------------------------
WARUM EINE REGEL UND NICHT EIN ZWEITES `--breit`
Ein zweiter Sonderfall waere beim dritten Fenster wieder faellig, und
dann wieder. Deshalb rollt ab jetzt JEDES Fenster, und `--breit`
unterscheidet sich nur noch in der Breite -- was sein Name sagt.
---------------------------------------------------------------------
UND WARUM KOPF UND FUSS STEHENBLEIBEN
Rollen allein haette gereicht, um herauszukommen -- aber man muesste
erst durch acht Felder scrollen, um den Ausgang zu SEHEN. Wer nicht
weiss, dass unten etwas ist, sucht ihn nicht. `position: sticky`
haelt die Ueberschrift oben und die Knoepfe unten, ohne dass ein
einziges Zeichen am HTML geaendert werden muss: Damit gilt es auch
fuer jedes Fenster, das es noch nicht gibt.
DER HINTERGRUND IST PFLICHT, nicht Zierde: Ohne ihn liefe der Text
der Felder unter den Knoepfen durch und beide waeren unlesbar. Er
ist derselbe dunkle Ton wie der Fensterboden, leicht durchscheinend
-- gedeckt, nicht als Balken erkennbar.
===================================================================== */
.dialog > form,
.dialog > .neu {
/* 82vh und nicht 100: Darueber und darunter bleibt der abgedunkelte
Hintergrund sichtbar. Ein Fenster, das den Bildschirm randlos
fuellt, sieht aus wie eine neue Seite -- und dann sucht man den
Zurueck-Knopf des Browsers statt den Ausgang im Fenster. */
max-height: min(82vh, 900px);
overflow-y: auto;
/* Wer im Fenster am Ende angekommen ist, soll nicht versehentlich die
Seite DAHINTER weiterschieben. */
overscroll-behavior: contain;
}
.dialog > form > .dialog__titel,
.dialog > .neu > .dialog__titel {
position: sticky; top: 0; z-index: 3;
margin: 0; padding: 14px 0 12px;
/* EIN AUSLAUFENDER RAND STATT EINER KANTE. Ein flaechiger Kasten
sah aus wie ein zweites Fenster ueber dem ersten -- im Bild klar
zu sehen. Der Verlauf endet durchsichtig, damit der Text darunter
hineinlaeuft, statt an einer Linie abzubrechen. Der Ton ist der
obere des Fensters selbst (#141c29), nicht ein dunklerer. */
background: linear-gradient(180deg,
rgba(20, 28, 41, .98) 0%,
rgba(20, 28, 41, .96) 62%,
rgba(20, 28, 41, 0) 100%);
backdrop-filter: blur(7px);
}
.dialog__knoepfe {
display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap;
position: sticky; bottom: 0; z-index: 3;
padding: 16px 0 14px;
/* Spiegelbildlich zum Kopf: oben durchsichtig, unten deckend. Der
Ton ist der untere des Fensterverlaufs (#070a11). */
background: linear-gradient(180deg,
rgba(7, 10, 17, 0) 0%,
rgba(7, 10, 17, .92) 32%,
rgba(7, 10, 17, .98) 100%);
backdrop-filter: blur(7px);
}
/* Wo kein Fenster ist, gilt nichts davon -- die Knopfzeile wird auch
ausserhalb von Dialogen benutzt und soll dort nicht kleben. */
:not(.dialog) > form > .dialog__knoepfe,
body > .dialog__knoepfe { position: static; background: none; backdrop-filter: none; }
/* ---------- Der Dialog --------------------------------------------------- */
.dialog__unter {
margin: -4px 0 14px;
font-size: .85rem; color: var(--text-still);
max-width: 60ch; line-height: 1.5;
}
/* ---------- Der Import --------------------------------------------------- */
.dialog--breit { max-width: 720px; }
.dialog__unter--still { font-size: .8rem; color: var(--text-still); }
/* Ein Fenster, das laenger ist als der Bildschirm, versteckt seine
eigenen Knoepfe. Gerollt wird INNEN, damit "Uebernehmen" immer
erreichbar bleibt. */
/* `--breit` sagt jetzt nur noch, was sein Name sagt: breiter. Die
Scroll-Hoehe stand hier als EINZIGE im ganzen Haus und war damit der
Grund, warum die anderen Fenster keine hatten (25.09.2026). */
/* ---- Die zwei Zeilen, die confirm() nicht kann ---------------------
`nachfrage.js` baut den Dialog; diese beiden Teile gibt es nur dort.
Die Endgueltig-Zeile ist der wichtigste Satz im ganzen Dialog --
sie beantwortet die einzige Frage, die vor einem Loeschen zaehlt.
Deshalb bekommt sie eine eigene Farbe UND ein Zeichen davor: Farbe
allein traegt keine Aussage (Rot-Gruen-Schwaeche, Kontrastmodus),
und im Kontrastmodus wird `color` ohnehin ersetzt. Das Zeichen
bleibt in jedem Fall. */
.nachfrage__endgueltig {
margin: 0 0 4px;
padding: 8px 10px;
font-size: .86rem;
line-height: 1.45;
color: #ffd9d2;
background: rgba(190, 74, 60, .13);
border-left: 3px solid rgba(214, 96, 80, .62);
}
.nachfrage__endgueltig::before { content: "! "; font-weight: 800; }
/* Der Fehler IM Dialog (z. B. fehlender Grund). Er darf nicht
aussehen wie der Fehlerstreifen der Seite dahinter -- der ist
verdeckt, dieser hier gehoert zum Formular. Leer nimmt er keinen
Platz weg, sonst rutschten die Knoepfe beim ersten Fehler. */
.nachfrage__fehler { margin: 0; font-size: .86rem; color: #ffb4a8; }
.nachfrage__fehler:empty { display: none; }
/* Am Handy klebt der Dialog sonst am oberen Rand und die Knoepfe
liegen unter der Tastatur. Er waechst von unten, wie ein Blatt,
das hochgezogen wird -- das ist dort die gewohnte Richtung. */
@media (max-width: 560px) {
.nachfrage { margin: auto auto 0; width: 100vw; max-width: 100vw; }
}
@media (forced-colors: active) {
.nachfrage__endgueltig { border-left: 3px solid CanvasText; background: Canvas; }
}
/* Der kleine Hinweis unter einem Feld im Nachfrage-Dialog ("Du kannst
bis zu 14 Tage geben"). Er steht UNTER dem Feld, nicht daneben:
daneben rutscht er am Handy weg, und dort liest ihn niemand. */
.nachfrage__hinweis { margin: 4px 0 0; font-size: .8rem; color: var(--text-still); }
.nachfrage__hinweis:empty { display: none; }
/* ---- Der Dialog steht auf eigenen Füßen ---------------------------
NACHGEMESSEN AM 19.09.2026, und es war genau derselbe Fehler wie
bei `.dialog` selbst: Das Formular trug erst die Klassen
`neu neu--blank` — und `.neu` gibt seine Abstände NUR in
`aufgaben.css`. Gemessen auf einer Seite ohne diese Datei:
`padding: 0px`. Der Text klebte am Rand, und die Eingabefelder
verloren ihre `height: 44px` — also ausgerechnet die Größe, die
ein Daumen trifft.
Am Bildschirm sah es trotzdem "irgendwie richtig" aus, weil die
Schrift und die Farben aus `gate.css` kamen. Solche Abhängigkeiten
sieht man nicht, man misst sie.
Deshalb steht hier alles, was der Dialog braucht — er borgt nichts
mehr aus einer Seitendatei. `.knopf`, `.abmelden` und `.feld-schild`
bleiben: die stehen in `gate.css` bzw. `start.css`, und die lädt
jede Seite. */
.nachfrage__form { margin: 0; padding: 20px; display: grid; gap: 10px; }
.nachfrage__zeile { display: grid; gap: 5px; }
.nachfrage__form input,
.nachfrage__form textarea {
width: 100%;
box-sizing: border-box;
font: inherit;
color: var(--text);
background: var(--tinte);
border: 1px solid var(--rand);
border-radius: var(--radius, 10px);
padding: 8px 10px;
}
/* 44 Pixel, weil ein Daumen weniger nicht sicher trifft. Dieselbe Zahl
wie überall im Haus -- sie steht hier, damit sie nicht davon abhängt,
welche Seitendatei zufällig geladen ist. */
.nachfrage__form input { height: 44px; }
.nachfrage__form textarea { min-height: 62px; resize: vertical; }
.nachfrage__form input:focus,
.nachfrage__form textarea:focus {
outline: none;
box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, .75),
0 0 0 3px rgba(63, 189, 245, .16);
}
/* Die Knöpfe unten bekommen Luft nach oben -- sonst sitzt "Löschen"
direkt unter dem Satz, der davor warnt. */
.nachfrage .dialog__knoepfe { margin-top: 6px; }
/* ---- Hochladen, das man sehen kann --------------------------------
Gebaut von `hochladen.js`, benutzt an fünf Stellen (Dateien,
Chat-Anhang, Wissen-PDF, Aufgaben-Anhang, Profilbild). Steht hier
und nicht in fünf Seitendateien -- aus demselben Grund wie der
Dialog darüber: Hochladen soll überall gleich aussehen. */
.hochlade { margin: 8px 0; display: grid; gap: 6px; }
.hochlade__kopf {
display: flex; align-items: center; justify-content: space-between;
gap: 10px; flex-wrap: wrap;
}
.hochlade__text { font-size: .9rem; color: var(--text-leise); }
/* 44 Pixel, damit ein Daumen den Abbruch trifft -- gerade hier, denn
wer abbricht, hat es meist eilig. */
.hochlade__abbruch {
min-height: 44px; min-width: 44px; padding: 0 14px;
font: inherit; font-size: .86rem;
color: var(--text-leise);
background: transparent;
border: 1px solid var(--rand);
border-radius: var(--radius, 10px);
cursor: pointer;
}
.hochlade__abbruch:hover:not(:disabled) { color: var(--text); border-color: var(--akzent); }
.hochlade__abbruch:disabled { opacity: .55; cursor: default; }
/* Ein natives <progress>: Vorleseprogramme kennen es, und ohne
`value` zeigt es von allein den unbestimmten Lauf -- genau der Fall,
in dem der Browser die Gesamtgröße nicht kennt. */
.hochlade__balken {
-webkit-appearance: none; appearance: none;
width: 100%; height: 6px; border: none;
background: rgba(150, 186, 220, .14);
border-radius: 999px; overflow: hidden;
}
.hochlade__balken::-webkit-progress-bar { background: rgba(150, 186, 220, .14); }
.hochlade__balken::-webkit-progress-value {
background: var(--akzent); border-radius: 999px;
transition: width .15s linear;
}
.hochlade__balken::-moz-progress-bar { background: var(--akzent); border-radius: 999px; }
/* Der letzte Satz nach einem Abbruch. Ruhig, nicht rot: Wer selbst
abbricht, hat keinen Fehler gemacht. */
.hochlade--schluss .hochlade__text { color: var(--text-still); }
/* Kein Wandern, wenn jemand Bewegung abbestellt hat. Der Balken
springt dann einfach auf den neuen Wert. */
@media (prefers-reduced-motion: reduce) {
.hochlade__balken::-webkit-progress-value { transition: none; }
}
@media (forced-colors: active) {
.hochlade__balken { border: 1px solid CanvasText; }
.hochlade__abbruch { border: 1px solid ButtonText; color: ButtonText; }
}
/* ---- Die kleinen Weg-Knöpfe auf Fingergeräten ----------------------
Gemessen am 20.09.2026 mit `pruef-tippziele`: fünf Bedienelemente
sind fest kleiner als 44 Pixel und wurden von der Fingerregel nicht
erfasst. Der unangenehmste davon ist `.chat__weg` (34×34) -- denn
direkt daneben sitzt der Knopf, der ein Gespräch FÜR ALLE auflöst.
Zwei 34-Pixel-Ziele nebeneinander, eines davon unwiderruflich.
NUR DIE BREITE FEHLTE -- nachgemessen, nicht angenommen.
`start.css` hebt unter 760 px bereits JEDEN `button` auf 44 Höhe.
Der erste Anlauf hier war deshalb eine unsichtbare Trefferfläche
(`::after { inset: -10px }`), um die Zeilen nicht höher zu machen --
gebaut, gemessen, und dabei kam heraus: Die Zeile IST schon 44 hoch.
Die Fläche hätte ein Problem gelöst, das es nicht gibt, und dafür
einen Trick eingeführt, den man beim nächsten Lesen erst verstehen
muss. Also die schlichte Lösung: Was man trifft, sieht man auch.
UND WARUM `pointer: coarse` UND NICHT `max-width`. Ein Tablet ist
1024 Pixel breit und wird trotzdem mit dem Finger bedient. Die
Breitenregel in `start.css` greift dort nicht -- diese hier schon.
Gefragt wird nach dem, worum es geht: Finger oder Maus. */
@media (pointer: coarse) {
.chat__weg, .todo__weg, .sicht__weg,
.nachricht__weg, .antwort-leiste__weg {
min-width: 44px; min-height: 44px;
}
}
/* ---- Wenn die Seite gar nicht erst lädt ----------------------------
Gebaut von `ladefehler()` in meldung.js. Steht hier, weil jede
Seite ihn zeigen können muss -- und weil eine Seite, die nicht
geladen hat, ihre eigene Gestaltung vielleicht auch nicht hat.
RUHIG, NICHT ROT. Ein Funkloch ist kein Fehler des Nutzers. Wer
hier Alarm schlägt, erzeugt Schuldgefühle für ein Kabel. */
.ladefehler {
display: grid; gap: 8px; justify-items: start;
margin: 18px 0;
padding: 16px 18px;
border: 1px dashed var(--rand);
border-radius: var(--radius, 10px);
background: rgba(255, 255, 255, .02);
}
.ladefehler__satz { margin: 0; color: var(--text); font-weight: 600; }
.ladefehler__grund { margin: 0; color: var(--text-still); font-size: .9rem; }
/* 44, weil man genau hier mit dem Daumen trifft -- und weil dieser
Knopf der einzige Weg zurück ist. */
.ladefehler__knopf { min-height: 44px; margin-top: 4px; }
@media (forced-colors: active) {
.ladefehler { border: 1px solid CanvasText; }
}
/* =====================================================================
DIE TEAMKARTEN (20.09.2026)
Filipe: „die kiste von rechte hand soll auch noch vieeeeeel krasser
und spezieller aussehen wie die von den modis. aber auch die von den
modis soll viel besser aussehen bitte. der hintergrund von den
kacheln soll auch viel krasser und geiler sein und so dass man texte
und so besser erkennt. weil gerade ist es schwer lesbar."
---------------------------------------------------------------------
ZUERST DAS LESEN, DANN DAS AUSSEHEN
Der Grund für die schlechte Lesbarkeit steht im Bildschirmfoto: Die
Karten liegen auf dem Bühnenbild der Seite, und ihr Untergrund war
stellenweise durchscheinend. Text auf einem Foto ist immer dann
schwer zu lesen, wenn das Foto stellenweise hell wird — und das tut
es, weil es ein Foto ist und keine Fläche.
Deshalb bekommt die Karte zuerst eine DECKENDE Unterlage und erst
darüber die Verläufe. Das kostet nichts an Wirkung: Die Verläufe
sieht man weiterhin, nur nicht mehr das Bild dahinter.
Danach erst das Besondere. Eine Karte, die schön aussieht und
deren Text man raten muss, ist keine gute Karte.
===================================================================== */
.tperson {
/* 1. DIE DECKENDE UNTERLAGE. `--grund-tief` gibt es im Haus nicht,
deshalb eine feste, sehr dunkle Fläche -- sie muss decken, nicht
zur Stimmung beitragen. */
background-color: #070b12;
border-radius: var(--radius-klein);
/* 2. Eine sichtbare Kante. Ohne sie verschwimmt die Karte am Rand
mit dem Bild dahinter, und man sieht nicht, wo sie aufhört. */
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--r) 22%, rgba(255, 255, 255, .06)),
0 18px 38px -24px rgba(0, 0, 0, .95);
}
/* Die Zahlenkästchen bekommen ebenfalls einen eigenen Grund -- auf
ihnen steht die kleinste Schrift der Karte. */
.tperson .tz {
background: rgba(255, 255, 255, .04);
border-radius: 10px;
}
/* =====================================================================
DIE BEIDEN HAENDE
WAS SIE UNTERSCHEIDET, IST NICHT "mehr Effekt", sondern RANG. Drei
Mittel, alle drei ruhig:
1. ein eigener Ton statt des Stufen-Tons,
2. eine deutlich hellere Kante -- man sieht den Unterschied schon
aus zwei Metern, ohne ein Wort zu lesen,
3. eine schmale Leiste an der linken Kante, wie ein Lesezeichen.
KEIN ZWEITER BAUPLAN: Es ist dieselbe Karte mit denselben Feldern.
Wer morgen ein Feld ergaenzt, ergaenzt es einmal.
---------------------------------------------------------------------
EINE REGEL FUER BEIDE, ZWEI TOENE (23.09.2026)
Filipe, mit dem Bildschirmfoto der Team-Lage: „die farbe der kachel
soll die gleiche sein wie die farbe die der text linke hand hat,
aber mach es richtig knallig so wie die farben bei den modis und
linke hand. soll schoen auffallen bitte."
Auf dem Foto war genau das das Problem: Die Marke „Linke Hand"
leuchtet lila, die Karte darunter war fast farblos. Sie fiel auf den
Ton der STUFE zurueck -- dieselbe Lage wie bei der rechten Hand vor
dem 20.09.
ERST HABE ICH NUR DIE LINKE ANGEFASST, und damit fast einen Fehler
gebaut: Das Lila startete bei 34 % Ton, das Gold lag weiter bei den
11 %, die jede Karte hat. Nebeneinander sah die rechte Hand ploetzlich
aus wie die schwaechere von beiden -- eine Rangordnung, die niemand
bestellt hat. Daneben stand mein eigener Kommentar „gleiche Mittel,
gleiche Staerke". Ein Kommentar, der eine Absicht beschreibt,
erfuellt sie nicht.
Jetzt EINE Regel fuer beide. Der Unterschied ist der Ton und sonst
nichts -- Gold und Lila, gleich kraeftig, keine Rangordnung. Wer
morgen an der Wirkung dreht, dreht sie fuer beide.
„RICHTIG KNALLIG" IST EINE ANWEISUNG, KEINE STIMMUNG. Deshalb tragen
diese beiden Karten ihre Farbe auch in der FLAECHE und nicht nur an
der Kante: Der Verlauf startet bei 34 % Ton.
UND TROTZDEM AUGENSCHONEND -- das ist kein Widerspruch, sondern die
Bedingung: kraeftig heisst GESAETTIGT, nicht hell. Der Grund bleibt
sehr dunkel, die Farbe liegt als Verlauf darueber, die Schrift
behaelt ihren Abstand. Nachgemessen bei 1280 und 390 px:
Name 15,6:1, Kleingedrucktes 8,2:1, Rollenmarke 11,2:1 (Lila) und
12,5:1 (Gold). Verlangt sind 4,5.
===================================================================== */
.tperson[data-rolle="hand"] { --kartenton: var(--ton-hand); --kartengrund: #120c03; }
.tperson[data-rolle="linke"] { --kartenton: var(--ton-linke); --kartengrund: #0d0817; }
.tperson[data-rolle="hand"],
.tperson[data-rolle="linke"] {
--r: var(--kartenton);
background-color: var(--kartengrund);
/* DIE SCHICHTEN STEHEN HIER NOCH EINMAL, und das ist Absicht:
team.css baut sie mit 11 % Ton fuer JEDE Karte. Diese beiden
sollen auffallen, also bekommen sie ihre eigenen -- gleicher
Aufbau, gleiche Reihenfolge, nur kraeftiger. `--raster` bleibt
oben, sonst verliert die Karte ihre feine Struktur. */
background-image:
var(--raster),
linear-gradient(155deg,
color-mix(in srgb, var(--kartenton) 34%, transparent),
color-mix(in srgb, var(--kartenton) 12%, transparent) 44%,
transparent 74%),
linear-gradient(178deg,
color-mix(in srgb, var(--kartenton) 8%, rgba(10, 8, 16, .95)),
rgba(6, 5, 10, .99));
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--kartenton) 52%, transparent),
inset 0 1px 0 rgba(255, 255, 255, .12),
0 22px 46px -22px rgba(0, 0, 0, .98),
0 0 0 1px color-mix(in srgb, var(--kartenton) 10%, transparent);
}
/* Die Leiste. `::before` und nicht ein weiteres Element: Sie ist
Gestaltung, kein Inhalt -- ein Vorleseprogramm soll sie nicht
ansagen. */
.tperson[data-rolle="hand"]::before,
.tperson[data-rolle="linke"]::before {
content: "";
position: absolute; left: 0; top: 14px; bottom: 14px;
width: 3px; border-radius: 0 3px 3px 0;
background: linear-gradient(180deg,
color-mix(in srgb, var(--kartenton) 90%, transparent),
color-mix(in srgb, var(--kartenton) 28%, transparent));
}
/* Der Name darf hier etwas mehr Gewicht haben -- es ist die Karte, die
man zuerst ansieht.
ABGELEITET STATT AUFGESCHRIEBEN: Hier standen `#f7e3ac` und, im
ersten Anlauf fuer die linke Hand, `#f2ddff` -- zwei Farben, die
nichts anderes sind als „der Ton, stark aufgehellt". Als Zahlen
waeren sie die naechsten beiden, die beim Anstrich nicht mitgehen. */
.tperson[data-rolle="hand"] :is(.tperson__name, .tperson__namen),
.tperson[data-rolle="linke"] :is(.tperson__name, .tperson__namen) {
color: color-mix(in srgb, var(--kartenton) 42%, #ffffff);
}
@media (forced-colors: active) {
.tperson { border: 1px solid CanvasText; }
/* Im Kontrastmodus faellt jede Toenung weg. Dann traegt die Kante
die Unterscheidung -- sonst saehen beide Haende aus wie jede
andere Karte. */
.tperson[data-rolle="hand"],
.tperson[data-rolle="linke"] { border: 3px solid Highlight; }
.tperson[data-rolle="hand"]::before,
.tperson[data-rolle="linke"]::before { display: none; }
}
/* Der Installieren-Knopf steht seit dem 22.09.2026 in gate.css.
Grund: Die Anmeldewand laedt module.css nicht -- sie hat nur
gate.css und ihr Haus. Und sie ist seit heute die wichtigste Stelle
fuer diesen Knopf, weil jeder dort zuerst landet. Haette er hier
gestanden, waere er dort nackt erschienen.
Es ist derselbe Fall wie bei .knopf-still, beim Schalter, bei der
Filterleiste und bei .feld-hinweis: ein gemeinsamer Baustein in
einer Seitendatei faellt immer genau dort auf, wo die Datei nicht
geladen wird. */
/* =====================================================================
DIE LEISTE FUER DIE TEXTGESTALTUNG (21.09.2026)
Filipe: "ich will dass die leute auch immer die art von text
aussuchen können, fettgedrückt, unterstrichen und so alles ...
das überall."
SIE STEHT UEBER DEM SCHREIBFELD und ist bewusst leise: vier kleine
Knoepfe, kein Rahmen, keine Farbe. Was man jeden Tag sieht und
selten braucht, darf nicht lauter sein als das, was man schreibt.
44 PIXEL AM FINGER, auch wenn das Zeichen darin klein ist -- die
Hausregel gilt hier wie ueberall. Auf dem Bildschirm wirkt der Knopf
dadurch nicht groesser: Die Flaeche waechst, nicht das Aussehen.
===================================================================== */
.textform {
display: flex;
flex-wrap: wrap;
gap: 2px;
margin-bottom: 6px;
}
.textform__knopf {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 10px;
border: 1px solid transparent;
border-radius: 8px;
background: none;
color: var(--text-leise, #9fb4c8);
font-size: .95rem;
line-height: 1;
cursor: pointer;
transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.textform__knopf:hover {
background: rgba(255, 255, 255, .06);
color: var(--text, #eaf3fb);
}
.textform__knopf:focus-visible {
outline: 2px solid var(--akzent, #3fbdf5);
outline-offset: 2px;
}
/* Jeder Knopf zeigt, was er tut -- das ist schneller gelesen als
jedes Schild daneben. */
.textform__knopf--fett { font-weight: 800; }
.textform__knopf--kursiv { font-style: italic; }
.textform__knopf--unter { text-decoration: underline; }
.textform__knopf--durch { text-decoration: line-through; }
@media (prefers-reduced-motion: reduce) {
.textform__knopf { transition: none; }
}
/* Die Gestaltung im fertigen Text. `u` und `s` bekommen eine eigene
Linienstaerke -- die Vorgabe des Browsers ist auf dunklem Grund
kaum zu sehen. */
.chat-nachricht__text u,
.eintrag-text u { text-decoration-thickness: .08em; text-underline-offset: .18em; }
.chat-nachricht__text s,
.eintrag-text s { text-decoration-thickness: .1em; opacity: .75; }
/* =====================================================================
DAS AUGE IST AM FINGER EIN VOLLES ZIEL (22.09.2026)
=====================================================================
Filipe, zur offenen Entscheidung "36-px-Auge oder 44-px-Fingerziel":
„mach was du am besten hälst es soll nur immer alles einfach zu
bedienen sein und geil aussehen fertig."
BEIDES GEHT -- die Entscheidung war eine Scheinalternative. Gemessen
am echten Aufbau (aufgaben.html, Kopfleiste mit sieben Knöpfen):
Breite Auge übrige Knöpfe Leiste
360 px 42 x 44 alle 44 x 44 zwei Reihen
390 px 42 x 44 alle 44 x 44 zwei Reihen
412 px 34 x 44 alle 44 x 44 eine Reihe
1280 px 116 x 32 mit Beschriftung
Die HÖHE stimmt längst. Es fehlten zwei Pixel Breite -- und bei
412 px zehn. Der Umschalter war damit als einziger Knopf der Leiste
kein volles Ziel, und ausgerechnet er sitzt zwischen zwei anderen.
WARUM DAS NICHT EINFACH VERGESSEN WURDE: In start.css steht
ausdrücklich `min-width: 0` auf diesem Knopf -- damals, um Platz zu
sparen. Am 21.09. habe ich nachgerechnet, dass der Platz da ist:
Bei 412 px braucht die Leiste mit sieben vollen Knöpfen 308 von
380 verfügbaren Pixeln. Die Sparsamkeit war Vorsicht vor einem
Platzmangel, den es nicht gibt.
UND DAS AUSSEHEN BLEIBT: Diese Regel gilt nur an Fingergeräten
(`pointer: coarse`). Am Rechner steht weiterhin der beschriftete
Umschalter da, 116 x 32 -- dort zielt eine Maus, kein Daumen.
===================================================================== */
@media (pointer: coarse) {
/* DER BEHAELTER MUSS MIT -- sonst wiederholt sich der 11.09.
------------------------------------------------------------------
Erster Anlauf war nur der Knopf. Gemessen bei 412 px: Knopf 44,
Behaelter 36, und der Knopf ragte 3 px ueber den Nachbarn. Genau
so lag am 11.09. der Umschalter ueber dem Chat-Knopf, und wer
"Meine Sicht" antippte, landete im Chat.
Die Lehre von damals steht in start.css: "Wer nur den Rahmen
begrenzt, begrenzt nichts" -- und sie gilt hier andersherum
genauso. Wer nur den Inhalt vergroessert, vergroessert nichts,
sondern schiebt ihn hinaus. */
.sicht,
.sicht .wahl2,
.sicht .wahl2__knopf {
min-width: 44px;
}
/* DIE SECHS PIXEL KOMMEN AUS DEN ABSTAENDEN, NICHT AUS DEN ZIELEN.
------------------------------------------------------------------
Gemessen bei 412 px, nachdem das Auge voll war: Die Leiste braucht
386 px und hat 380 -- "Abmelden" rutschte in eine zweite Reihe.
Filipe am 09.09. genau dazu: "es soll alles in einer reihe sein."
Es gibt zwei Arten, sechs Pixel zu finden: an den Tippzielen oder
am Weissraum. Am Ziel zu sparen ist genau der Fehler, der die
Knoepfe ueberhaupt erst auf 34 und 36 gebracht hat. Also am
Weissraum: 4 px auf 2 zwischen den Zeichenknoepfen (sie haben
eigene Kanten, der Abstand ist Zierde) und 10 auf 6 zur linken
Gruppe. Macht 16 px -- genug, mit Luft.
BEI 360 UND 390 bricht die Leiste weiterhin um, und das ist
richtig: Dort fehlen auch mit dieser Ersparnis noch zwoelf Pixel,
und ein Umbruch ist die ehrliche Antwort auf zu wenig Platz. Eine
Schwelle, ab der sie es tut, steht hier bewusst NICHT -- das
Umbrechen misst, statt zu rechnen. */
.kopfleiste { gap: 6px; }
.kopfleiste__rechts { gap: 2px; }
}
/* =====================================================================
DER LIVE-PUNKT (22.09.2026)
=====================================================================
Filipe: „ein live button der richtig geil ist mit einem live roten
punkt symbol am besten, das soll aufblinken für zwei stunden. man
soll nicht drauf drücken können aber so dass es auffällt."
ES IST KEIN KNOPF, UND ES SIEHT AUCH NICHT SO AUS.
`pointer-events: none` ist die halbe Antwort; die andere ist die
Form. Etwas, das wie ein Knopf aussieht und nichts tut, ist eine
Sackgasse — jemand tippt darauf und wartet. Deshalb eine Marke:
runder Punkt plus Wort, wie auf einer Kamera.
BLINKEN OHNE FLACKERN.
Hausregel vom 12.08.2026: keine aggressiven Flacker-/Strobe-Effekte.
Ein Punkt, der zehnmal pro Sekunde umspringt, ist auf einem Handy in
der Hand kein bisschen auffälliger als einer, der atmet — er tut nur
in den Augen weh. 1,4 Sekunden Zyklus, Deckkraft 1 → 0,35, dazu ein
Ring, der nach außen läuft. Das ist der Rhythmus, den jede Kamera
und jeder Sender benutzt, und genau deshalb liest man ihn sofort
als „jetzt".
--------------------------------------------------------------------- */
.live-marke {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px 3px 8px;
border-radius: 999px;
background: #ff1a1a;
color: #fff;
font-size: .72rem;
font-weight: 800;
letter-spacing: .1em;
line-height: 1.1;
/* NICHT ANTIPPBAR -- ausdrücklich so gewollt. Auch nicht aus
Versehen beim Wischen. */
pointer-events: none;
user-select: none;
vertical-align: middle;
}
.live-marke__punkt {
position: relative;
width: 8px;
height: 8px;
border-radius: 50%;
background: #fff;
flex: 0 0 8px;
animation: live-atmen 1.4s ease-in-out infinite;
}
/* Der Ring läuft nach außen und verschwindet -- das ist das, was man
aus dem Augenwinkel bemerkt, ohne hinzusehen. */
.live-marke__punkt::after {
content: "";
position: absolute;
inset: -3px;
border-radius: 50%;
border: 1.5px solid rgba(255, 255, 255, .75);
animation: live-ring 1.4s ease-out infinite;
}
@keyframes live-atmen {
0%, 100% { opacity: 1; }
55% { opacity: .35; }
}
@keyframes live-ring {
0% { transform: scale(.7); opacity: .8; }
70% { transform: scale(1.9); opacity: 0; }
100% { transform: scale(1.9); opacity: 0; }
}
/* WER BEWEGUNGSARMUT EINGESTELLT HAT, SIEHT DASSELBE -- ohne Bewegung.
Das macht man meist wegen Schwindel oder Migräne; ein pulsierender
Punkt ist dann keine Information, sondern eine Zumutung. Der rote
Punkt bleibt, das Wort bleibt, nur das Atmen hört auf. */
@media (prefers-reduced-motion: reduce) {
.live-marke__punkt { animation: none; opacity: 1; }
.live-marke__punkt::after { animation: none; opacity: .5; transform: scale(1.4); }
}
/* Im Kontrastmodus tragen Farben nichts -- dann muss der Rahmen es
sagen. Ohne das wäre die Marke ein Wort ohne Aussage. */
@media (forced-colors: active) {
.live-marke {
border: 2px solid CanvasText;
background: Canvas;
color: CanvasText;
}
.live-marke__punkt { background: CanvasText; }
}
/* ---------------------------------------------------------------------
DIE KACHEL, DIE GERADE LIVE IST (screen6)
---------------------------------------------------------------------
Die Marke sitzt oben rechts in der Kachel. Sie überdeckt nichts:
Der Name steht unten links, das Zeichen oben links.
Dazu ein Saum, der mitatmet -- damit die Kachel auch dann auffällt,
wenn die Marke gerade am Rand des Blicks liegt. Kein Schlagschatten
in Rot über die ganze Wand: Das würde die Nachbarkacheln mitfärben
und wäre genau der „scheiss durcheinander", den Filipe abschafft. */
.kachel[data-live="ja"] {
position: relative;
}
.kachel__live {
position: absolute;
top: 10px;
right: 10px;
z-index: 3;
}
.kachel[data-live="ja"]::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
border: 2px solid #ff1a1a;
pointer-events: none;
animation: live-saum 1.4s ease-in-out infinite;
}
@keyframes live-saum {
0%, 100% { opacity: 1; }
55% { opacity: .3; }
}
@media (prefers-reduced-motion: reduce) {
.kachel[data-live="ja"]::after { animation: none; opacity: 1; }
}
@media (forced-colors: active) {
.kachel[data-live="ja"]::after { border-color: CanvasText; animation: none; }
}
/* Am Handy rückt die Marke etwas enger an den Rand -- bei 360 px
zählt jeder Punkt Breite für den Kachelnamen. */
@media (max-width: 560px) {
.kachel__live { top: 8px; right: 8px; }
.live-marke { padding: 2px 8px 2px 6px; font-size: .68rem; }
}