Files
dogfather-universe/workspace/assets/css/start.css
T
DogFatherGitandClaude Opus 5 fcebbd18bb Workspace: Casper und HasiDog als Buehne im Hintergrund
Filipe: "der hintergrund soll genau so krass und speziell sein, benutz
den hasen und husky."

Gefunden in assets/img: hero-husky.png (Casper, neonblau auf dunkel --
farblich genau die Oberflaeche) und char-hasidog.jpg (HasiDog). Der
Sticker "HasiDog & Casper" hat bestaetigt, dass die beiden zusammen
gehoeren.

Beide sitzen FEST an der Scheibe in den unteren Ecken -- sie scrollen
nicht mit, sondern stehen da wie ein Buehnenbild, vor dem gearbeitet
wird. Die Mitte bleibt frei, dort steht der Inhalt. HasiDog ist weiter
nach aussen geschoben und schwaecher als Casper: Er ist heller, sein
Gesicht zieht den Blick staerker, und direkt neben einer Kachel wuerde
man ihn ansehen statt der Kachel.

AUFBEREITET STATT EINGEBUNDEN (tools/buehne-bauen.mjs):
  * stark abgedunkelt und leicht entsaettigt -- Stimmung, kein Motiv
  * weiche Raender ins Bild EINGERECHNET. Ein hartes Rechteck saehe nach
    aufgeklebtem Foto aus; und eine Maske ueber ein 900-Pixel-Bild kostet
    bei jedem Bildaufbau Rechenzeit.
  * 290 KB PNG -> 41 KB WebP, 110 KB -> 32 KB
Gerechnet mit dem Browser, der ohnehin fuer die Pruefungen da ist -- kein
Bildprogramm, keine neue Abhaengigkeit, 0 EUR.

GEPRUEFT WIRD NICHT, OB ES HUEBSCH IST, sondern ob der Text noch lesbar
ist -- an echten BILDPUNKTEN aus dem fertigen Bildschirmfoto, nicht an
der Farbangabe im Stil. Die weiss naemlich nichts davon, was
dahinterliegt. Gemessen wird der Untergrund direkt NEBEN jedem sichtbaren
Text, auf fuenf Seiten, auf Computer und Handy: bis zu 34 Stellen je
Seite gegen den WCAG-Massstab (4,5:1, bei grosser Schrift 3:1).

UND DAS HAT SOFORT EINEN ALTEN FEHLER GEFUNDEN: Der leiseste Grauton
(--text-still) lag bei 4,43:1 -- knapp UNTER der Norm. Das war schon
lange so, nur hatte es nie jemand nachgerechnet, weil bisher niemand an
echten Bildpunkten gemessen hat. Von #6d7d92 auf #75859a angehoben; jetzt
4,95:1 auf dem hellsten Untergrund. Das gilt fuer JEDE Seite, nicht nur
fuer die mit dem Hintergrundbild.

Schlechtester Wert jetzt: 4,97:1. Alle 30 Messungen bestanden.

Nebenbei eine Falle in den Pruefungen selbst: Ein haengengebliebener
Testserver auf demselben Port fing die Anfragen ab -- der Test sprach mit
einem ALTEN Prozess und dessen anderer Datenbank, und meldete "no such
table". Der Port ist jetzt ein anderer; die Lehre steht hier, weil das
Bild "Server laeuft" trotzdem erscheint und alles richtig aussieht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 00:10:09 +02:00

690 lines
28 KiB
CSS

/* ===================================================================
Startseite nach dem Anmelden. Baut auf den Farben und Bausteinen von
gate.css auf, damit beides wie eine Anwendung wirkt und nicht wie zwei
verschiedene Seiten.
=================================================================== */
/* Grundschrift und Grundfarbe stehen in gate.css auf `body.gate` und
greifen hier deshalb NICHT. Ohne diese Wiederholung fällt die Seite auf
die Browservorgaben zurück: schwarze Serifenschrift auf dunklem Grund,
praktisch unlesbar. */
body.start {
display: block;
min-height: 100svh;
margin: 0;
padding: 0;
color: var(--text);
font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
font-size: 16px;
line-height: 1.55;
letter-spacing: .01em;
background:
radial-gradient(120% 80% at 12% -10%, rgba(63, 189, 245, .10), transparent 58%),
radial-gradient(100% 70% at 92% 8%, rgba(138, 118, 255, .10), transparent 60%),
var(--tinte);
}
/* ---------- Die Bühne ----------------------------------------------------
Casper unten links, HasiDog unten rechts. Beide FEST an der Scheibe,
nicht am Inhalt: Sie scrollen nicht mit, sondern stehen da wie ein
Bühnenbild, vor dem gearbeitet wird.
Drei Regeln, damit daraus kein Poster wird, auf dem man nichts lesen
kann:
1. Sie sitzen in den unteren ECKEN und lassen die Mitte frei -- genau
dort steht der Inhalt.
2. Die weichen Ränder sind ins Bild eingerechnet (tools/buehne-bauen.mjs),
nicht als Maske im Browser. Ein hartes Rechteck sähe nach
aufgeklebtem Foto aus; und eine Maske über ein 900-Pixel-Bild
kostete bei jedem Bildaufbau Rechenzeit.
3. Darüber liegt ein dunkler Schleier. Er ist der Grund, warum der
Text unverändert lesbar bleibt -- gemessen, nicht geschätzt.
Warum überhaupt zwei Bilder statt eines großen: Ein Vollbild hinter
einem Arbeitswerkzeug ist immer im Weg. Zwei Ecken lassen den Blick
in Ruhe und sind trotzdem sofort da. */
body.start::before,
body.start::after {
content: "";
position: fixed; bottom: 0; z-index: 0;
pointer-events: none;
background-repeat: no-repeat;
background-size: contain;
background-position: bottom;
}
/* Casper. Links, blickt nach rechts in die Seite hinein. */
body.start::before {
left: -3vw;
width: min(34vw, 480px); height: min(34vw, 480px);
background-image: url("../img/buehne-husky.webp");
background-position: left bottom;
opacity: .46;
}
/* HasiDog. Rechts, gespiegelt, blickt zurück. Etwas schwächer -- er ist
heller als Casper und würde sonst mehr ziehen. */
/* Weiter nach aussen und nach unten geschoben als Casper: HasiDog ist
heller, sein Gesicht zieht den Blick staerker -- direkt neben einer
Kachel wuerde man es ansehen statt der Kachel. So schaut er von unten
rechts herein, ohne sich dazwischenzustellen. */
body.start::after {
right: -2vw;
width: min(24vw, 330px); height: min(36vw, 480px);
background-image: url("../img/buehne-hasi.webp");
background-position: right bottom;
opacity: .3;
}
/* Der Schleier. Liegt über den beiden und unter dem Inhalt -- er nimmt
ihnen genau so viel Kraft, dass Text darüber unverändert lesbar
bleibt. Nach unten dichter, weil die Bilder dort stehen. */
body.start > .schleier {
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background:
linear-gradient(180deg, transparent 0%, rgba(5, 7, 13, .55) 62%, rgba(5, 7, 13, .8) 100%),
radial-gradient(75% 55% at 50% 62%, rgba(5, 7, 13, .82), transparent 78%);
}
/* Alles Bedienbare liegt über der Bühne. Ohne das läge der Inhalt zwar
sichtbar darüber, aber Klicks landeten teils am falschen Ort. */
body.start > .kopfleiste,
body.start > .inhalt,
body.start > main { position: relative; z-index: 1; }
@media (max-width: 760px) {
/* Auf dem Handy nimmt der Inhalt die ganze Breite ein -- dort wäre die
Bühne nur ein Schatten hinter dem Text. Bleibt, aber deutlich
zurückgenommen und kleiner. */
body.start::before { left: -8vw; width: 60vw; height: 60vw; opacity: .28; }
body.start::after { right: -6vw; width: 42vw; height: 60vw; opacity: .2; }
}
/* ---------- Kopfleiste ------------------------------------------------ */
.kopfleiste {
position: sticky; top: 0; z-index: 5;
display: flex; align-items: center; justify-content: space-between; gap: 16px;
padding: 14px clamp(16px, 4vw, 40px);
background: rgba(6, 9, 16, .82);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
border-bottom: 1px solid var(--rand);
}
/* Damit in einer Flex-Zeile ueberhaupt etwas schrumpfen KANN, braucht es
min-width: 0. Ohne diese eine Zeile behielt jedes Teil seine volle
Wunschbreite -- Zurueck (118) + Marke (141) + rechte Gruppe (297)
ergaben 556 px auf einem 390 px breiten Handy. Die Kopfleiste schob
214 px aus dem Bild und der Abmelden-Knopf war dort nicht mehr zu
erreichen. Auf JEDER Seite, seit es die Kopfleiste gibt; aufgefallen
erst beim Messen, weil man am Rechner nie danebengreift. */
.kopfleiste > * { min-width: 0; }
.kopfleiste .marke {
margin: 0; font-size: .72rem;
/* Die Marke gibt als Erstes nach: Ihr Inhalt steht direkt darunter
noch einmal als Ueberschrift, der Abmelden-Knopf dagegen nirgends. */
flex: 1 1 auto;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Zurück-Knopf. Steht ganz links, weil dort jeder ihn erwartet -- gleiche
Stelle wie im Browser. Auf der Startseite gibt es ihn gar nicht: Dort
ist kein "davor", und ein Knopf, der nichts tut, ist schlimmer als
keiner. Auf den übrigen Seiten entscheidet kopf.js, ob er erscheint. */
/* Entwurf "Neon-Kante": Der senkrechte Lichtstrich links ist dasselbe
Motiv wie die Kante der Anmelde-Tafel (.tafel__kante in gate.css).
Dadurch wirkt der Workspace wie ein Stück und nicht wie zusammen-
gesetzte Teile. */
.zurueck-knopf {
position: relative;
flex: 0 0 auto;
display: inline-flex; align-items: center; gap: 10px;
padding: 9px 18px 9px 17px;
border: 0;
/* Links flach, rechts rund: Die gerade Kante gehört dem Lichtstrich,
nach rechts läuft der Knopf weich aus. */
border-radius: 4px 999px 999px 4px;
background: linear-gradient(100deg,
rgba(63, 189, 245, .10), rgba(138, 118, 255, .05) 60%, transparent);
color: var(--text-leise);
font: inherit; font-size: .84rem; font-weight: 600;
cursor: pointer; white-space: nowrap;
transition: color var(--tempo), background var(--tempo);
}
/* Der Lichtstrich. Ruht etwas kürzer als der Knopf und wächst beim
Überfahren auf volle Höhe -- die Bewegung ersetzt jedes Aufblitzen. */
.zurueck-knopf::before {
content: "";
position: absolute; left: 0; top: 6px; bottom: 6px; width: 2px;
border-radius: 2px;
background: linear-gradient(180deg, var(--akzent), var(--violett));
box-shadow: 0 0 8px -1px rgba(63, 189, 245, .55);
transition: top var(--tempo), bottom var(--tempo), box-shadow var(--tempo);
}
.zurueck-knopf__pfeil {
width: 15px; height: 15px; flex: 0 0 auto;
fill: none; stroke: currentColor;
stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
transition: transform var(--tempo);
}
.zurueck-knopf:hover {
color: #fff;
background: linear-gradient(100deg,
rgba(63, 189, 245, .18), rgba(138, 118, 255, .09) 60%, transparent);
}
.zurueck-knopf:hover::before {
top: 0; bottom: 0;
box-shadow: 0 0 14px 0 rgba(63, 189, 245, .75);
}
/* Der Pfeil rückt nach links -- sagt die Richtung ohne zusätzlichen Text. */
.zurueck-knopf:hover .zurueck-knopf__pfeil { transform: translateX(-3px); }
.zurueck-knopf:active { transform: translateY(1px); }
.zurueck-knopf:focus-visible {
outline: 2px solid var(--akzent);
outline-offset: 3px;
border-radius: 4px 999px 999px 4px;
}
@media (prefers-reduced-motion: reduce) {
.zurueck-knopf, .zurueck-knopf::before, .zurueck-knopf__pfeil { transition: none; }
.zurueck-knopf:hover .zurueck-knopf__pfeil { transform: none; }
}
.kopfleiste__rechts { display: flex; align-items: center; gap: 12px; flex: 0 1 auto; min-width: 0; }
.kopfleiste__rechts > * { flex: 0 0 auto; }
.wer {
font-size: .86rem; color: var(--text-leise);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 46vw;
/* Der Name darf kuerzer werden -- der Knopf daneben nicht. */
flex: 0 1 auto; min-width: 0;
}
/* ---------- Inhalt ---------------------------------------------------- */
.inhalt {
max-width: 880px;
margin: 0 auto;
padding: clamp(28px, 5vw, 56px) clamp(16px, 4vw, 40px) 64px;
}
/* Diese vier standen bis zum 31.08.2026 in aufgaben.css -- also in einer
Datei, die eine neue Seite gar nicht laden muss. Genau dadurch war das
Dashboard beim ersten Aufbau schmal und ohne Kopfzeilen-Layout: die
Klassen im HTML gab es, die Regeln dazu nicht. Derselbe Fehler ist
vorher schon zweimal passiert (.knopf-still, .schalter). Was auf
mehreren Seiten benutzt wird, gehoert hierher, wo jede Seite es hat. */
.inhalt--breit { max-width: 1240px; }
.zurueck { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
.zurueck:hover { border-bottom-color: currentColor; }
.kopf-zeile {
display: flex; align-items: flex-end; justify-content: space-between;
gap: 20px; flex-wrap: wrap; margin-bottom: 24px;
}
.kopf-zeile .titel { margin: 0; font-size: clamp(1.4rem, 2.2vw, 1.85rem); }
.leise { color: var(--text-still); font-weight: 400; }
/* ---------- Auf- und Zuklappen ------------------------------------------
Lange Listen (Protokoll, Verlauf) stehen zugeklappt da und zeigen nur
die neuesten Zeilen. Der Pfeil dreht sich beim Aufklappen -- er zeigt
die Richtung, der Text daneben sagt, was der Knopf TUT.
Steht hier und nicht in einer Seiten-Datei: Er wird an mehreren
Stellen gebraucht, und genau so sind schon dreimal Regeln dort
gelandet, wo eine Seite sie gar nicht laedt. */
.klapp-kopf {
display: flex; align-items: center; justify-content: space-between;
gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
}
.klapp-kopf > .feldschild, .klapp-kopf > .block__titel { margin: 0; }
.klapp-pfeil {
width: 14px; height: 14px; flex: 0 0 auto;
fill: none; stroke: currentColor;
stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
transition: transform var(--tempo);
}
[aria-expanded="true"] > .klapp-pfeil { transform: rotate(180deg); }
/* Zugeklappt bleiben die vier neuesten Zeilen stehen. Bewusst ueber CSS
statt ueber das Entfernen von Zeilen: Das Aufklappen braucht dann
weder einen neuen Aufbau noch eine zweite Abfrage. */
[data-klapp="zu"] > *:nth-child(n+5) { display: none; }
.willkommen { margin-bottom: 38px; }
.willkommen .titel { margin-bottom: 6px; }
/* ---------- Zahlen ---------------------------------------------------- */
.zahlen-block { margin-bottom: 34px; }
.zahlen {
list-style: none; margin: 0; padding: 0;
display: grid; gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(122px, 1fr));
}
.zahl {
padding: 14px 16px;
background: rgba(255, 255, 255, .03);
border: 1px solid var(--rand);
border-radius: var(--radius-klein);
}
.zahl__wert { display: block; font-size: 1.7rem; font-weight: 700; line-height: 1.1; }
.zahl__name { display: block; margin-top: 2px; font-size: .78rem; color: var(--text-still); }
/* Nur wenn wirklich etwas überfällig ist, wird die Kachel hervorgehoben --
sonst stumpft die Farbe ab und man übersieht sie im Ernstfall. */
.zahl[data-warn="ja"] { border-color: rgba(255, 154, 162, .42); background: rgba(255, 154, 162, .07); }
.zahl[data-warn="ja"] .zahl__wert { color: var(--warn); }
/* ---------- Bereiche: Gruppen und Kacheln --------------------------------
Vorher: siebzehn gleiche Rechtecke mit "ÖFFNEN" darauf. Wenn alles
gleich aussieht, ist alles gleich wichtig -- also nichts.
Drei Dinge tragen jetzt die Gestaltung:
1. Die Kachel ist ruhig, bis man sie ansieht. Der Farbton sitzt im
Zeichen und in einer schmalen Kante -- nicht als Fläche. Siebzehn
farbige Flächen wären ein Bonbonglas, kein Werkzeug.
2. Beim Überfahren geht ein sehr weicher Schimmer aus der oberen
linken Ecke an. Kein Blitzen, kein Springen: Alphawerte unter 0.25,
Bewegung unter einem Pixel.
3. Der Einlauf ist gestaffelt -- genau EINE Bewegung beim Aufbau,
danach Ruhe. Bei "weniger Bewegung" fällt sie ersatzlos weg.
Die acht Farbtöne sind gegen genau diesen Hintergrund gerechnet:
Helligkeitsband, Farbstärke, Abstand bei Farbfehlsichtigkeit
(schlechtestes Paar dE 8.4), Normalsicht-Abstand (19.3) und Kontrast
-- alle Prüfungen bestanden. Warum acht und nicht siebzehn: Siebzehn
unterscheidbare Farben gibt es nicht; ein Versuch mit einer eigenen
Farbe je Kachel ergab Paare mit Abstand 1.4, also praktisch dieselbe
Farbe. Sie stützen nur -- WAS eine Kachel ist, sagen Zeichen und Name.
------------------------------------------------------------------------- */
.gruppe { margin-bottom: 34px; }
.gruppe:last-child { margin-bottom: 0; }
.gruppe__kopf {
position: relative;
display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
margin-bottom: 14px; padding-bottom: 10px;
/* Die Trennlinie läuft nach rechts aus, statt hart abzubrechen --
eine durchgezogene Linie über die ganze Breite zerschneidet die
Seite, eine auslaufende gliedert sie nur. */
border-bottom: 1px solid transparent;
border-image: linear-gradient(90deg, var(--rand-hell), transparent 70%) 1;
}
.gruppe__name {
margin: 0; font-size: .76rem; font-weight: 700;
letter-spacing: .1em; text-transform: uppercase; color: var(--text-leise);
}
.gruppe__unter { font-size: .78rem; color: var(--text-still); }
.kacheln {
list-style: none; margin: 0; padding: 0;
display: grid; gap: 12px;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* Siebzehn eigene Töne -- einer je Kachel. Nicht gewählt, sondern
gerechnet: gleichmäßig um den Farbkreis verteilt, in OKLCH bei
konstanter Helligkeit und Farbstärke, damit keine sich vordrängt.
Erzeugt von tools/kachel-farben.mjs; dort steht auch, warum.
Die ZUORDNUNG ist ebenfalls gerechnet. Das Auge vergleicht nur, was
NEBENEINANDER liegt -- gesucht wurde deshalb die Anordnung mit dem
größtmöglichen kleinsten Abstand zweier Nachbarn im Raster. Ergebnis:
mindestens 105,9 Grad zwischen allen Nachbarn. Zum Vergleich: Der
erste Versuch mit frei gewählten Farben hatte Paare bei 1,4 Grad.
Unter allen Anordnungen, die das schaffen, wurde die passendste
genommen -- LIVE rot, Technik gelb, Reports grün, Personen rot-gold.
Geprüft gegen genau diesen Hintergrund: Helligkeitsband, Farbstärke
und Kontrast bestehen für alle siebzehn. */
.kachel[data-ton="1"] { --ton: #3e95e7; } /* 250° */
.kachel[data-ton="2"] { --ton: #7089ea; } /* 271° */
.kachel[data-ton="3"] { --ton: #947de2; } /* 292° */
.kachel[data-ton="4"] { --ton: #b173d0; } /* 314° */
.kachel[data-ton="5"] { --ton: #c66ab5; } /* 335° */
.kachel[data-ton="6"] { --ton: #d56694; } /* 356° */
.kachel[data-ton="7"] { --ton: #dc666f; } /* 17° */
.kachel[data-ton="8"] { --ton: #db6c48; } /* 38° */
.kachel[data-ton="9"] { --ton: #d17717; } /* 59° */
.kachel[data-ton="10"] { --ton: #ba8610; } /* 81° */
.kachel[data-ton="11"] { --ton: #a29205; } /* 102° */
.kachel[data-ton="12"] { --ton: #809e23; } /* 123° */
.kachel[data-ton="13"] { --ton: #50a752; } /* 144° */
.kachel[data-ton="14"] { --ton: #07aa7c; } /* 165° */
.kachel[data-ton="15"] { --ton: #12a69b; } /* 186° */
.kachel[data-ton="16"] { --ton: #04a3b4; } /* 208° */
.kachel[data-ton="17"] { --ton: #059ece; } /* 229° */
.kachel {
--ton: var(--akzent);
/* Wo der Zeiger steht. Wird von start.js gesetzt; die Mitte ist der
Rückfallwert, damit ohne Zeiger nichts springt. */
--mx: 50%;
--my: 0%;
position: relative;
border-radius: 18px;
background:
linear-gradient(155deg,
color-mix(in srgb, var(--ton) 10%, transparent),
rgba(255, 255, 255, .022) 48%);
border: 1px solid var(--rand);
/* Die feine helle Linie an der Oberkante. Ein Pixel, kaum sichtbar --
aber die Kachel wirkt dadurch von oben beleuchtet statt aufgeklebt.
Das ist der Unterschied zwischen "Kasten" und "Objekt". */
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .055);
overflow: hidden;
transition: border-color var(--tempo), transform var(--tempo), box-shadow var(--tempo);
}
.kachel[data-gross="ja"] { grid-column: span 2; }
/* Die farbige Kante links. Sie ist das Einzige, was den Ton kräftig
zeigt -- drei Pixel reichen, um eine Kachel wiederzuerkennen. */
.kachel::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
background: linear-gradient(180deg, var(--ton), transparent 92%);
opacity: .55;
transition: opacity var(--tempo), width var(--tempo);
}
/* Das Licht. Es liegt schwach auf der Kachel und FOLGT beim Überfahren
dem Zeiger -- das ist die Kleinigkeit, die man nicht sieht, sondern
erst beim Benutzen merkt. Kein Blinken, keine Bewegung des Inhalts:
Es wird nur an einer anderen Stelle heller.
Ruhend sitzt es in der oberen linken Ecke (--my: 0%), damit die
Kacheln auch ohne Zeiger von einer Seite beleuchtet wirken. */
.kachel::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
background: radial-gradient(130% 150% at var(--mx) var(--my),
color-mix(in srgb, var(--ton) 20%, transparent), transparent 60%);
opacity: .38;
transition: opacity var(--tempo);
}
.kachel:hover {
border-color: color-mix(in srgb, var(--ton) 45%, var(--rand));
transform: translateY(-2px);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .09),
0 10px 26px -14px color-mix(in srgb, var(--ton) 55%, transparent);
}
.kachel:hover::before { opacity: 1; width: 4px; }
.kachel:hover::after { opacity: 1; }
.kachel:has(:focus-visible) { border-color: var(--ton); }
.kachel__link {
position: relative; z-index: 1;
display: flex; align-items: center; gap: 15px;
padding: 21px 20px 21px 23px;
color: inherit; text-decoration: none;
}
/* Das Wasserzeichen. Dasselbe Zeichen wie im Feld links, aber riesig,
angeschnitten und fast unsichtbar in der rechten unteren Ecke.
Es ist der Grund, warum siebzehn Kacheln nicht mehr wie siebzehn
Kästen aussehen: Jede bekommt eine eigene große Form, ohne dass ein
einziges zusätzliches Bild geladen wird. Bewusst so schwach, dass man
es nicht liest, sondern nur spürt -- eine Kachel soll ihren Namen
tragen, nicht ihr Zeichen. */
.kachel__wasserzeichen {
position: absolute; right: -14px; bottom: -26px;
width: 132px; height: 132px;
pointer-events: none; z-index: 0;
opacity: .07;
transform: rotate(-8deg);
transition: opacity var(--tempo), transform var(--tempo);
}
.kachel__wasserzeichen svg {
width: 100%; height: 100%;
fill: none; stroke: var(--ton);
stroke-width: 1.1; stroke-linecap: round; stroke-linejoin: round;
}
.kachel:hover .kachel__wasserzeichen {
opacity: .13;
transform: rotate(-8deg) translate(-4px, -4px) scale(1.04);
}
.kachel[data-gross="ja"] .kachel__wasserzeichen {
width: 168px; height: 168px; right: -18px; bottom: -34px;
}
.kachel__link:focus-visible {
outline: 2px solid var(--ton); outline-offset: -4px; border-radius: 15px;
}
/* Das Zeichen sitzt in einem eigenen Feld -- dadurch bekommt der Ton
eine Fläche, ohne dass die ganze Kachel farbig wird. Der Verlauf und
der innere Lichtrand darin lassen es geprägt statt gemalt wirken. */
.kachel__zeichen {
position: relative; z-index: 1;
flex: none;
display: grid; place-items: center;
width: 52px; height: 52px; border-radius: 15px;
background:
linear-gradient(160deg,
color-mix(in srgb, var(--ton) 30%, transparent),
color-mix(in srgb, var(--ton) 10%, transparent));
border: 1px solid color-mix(in srgb, var(--ton) 32%, transparent);
/* Lichtkante innen oben, weicher Schein nach aussen -- dadurch wirkt
das Feld geprägt statt gemalt. Der Schein bleibt schwach; ein
leuchtender Kasten wäre in einer dunklen Oberfläche eine Lampe. */
box-shadow:
inset 0 1px 0 color-mix(in srgb, var(--ton) 38%, transparent),
0 4px 14px -8px color-mix(in srgb, var(--ton) 60%, transparent);
transition: background var(--tempo), border-color var(--tempo),
transform var(--tempo), box-shadow var(--tempo);
}
.kachel:hover .kachel__zeichen {
background:
linear-gradient(160deg,
color-mix(in srgb, var(--ton) 46%, transparent),
color-mix(in srgb, var(--ton) 16%, transparent));
border-color: color-mix(in srgb, var(--ton) 62%, transparent);
transform: scale(1.05);
box-shadow:
inset 0 1px 0 color-mix(in srgb, var(--ton) 55%, transparent),
0 6px 20px -8px color-mix(in srgb, var(--ton) 85%, transparent);
}
.kachel[data-gross="ja"] .kachel__zeichen { width: 62px; height: 62px; border-radius: 18px; }
.kachel__svg {
width: 25px; height: 25px;
fill: none; stroke: var(--ton);
stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.kachel[data-gross="ja"] .kachel__svg { width: 31px; height: 31px; }
.kachel__text { position: relative; z-index: 1; display: grid; gap: 3px; min-width: 0; }
.kachel__name {
font-size: 1.06rem; font-weight: 650; letter-spacing: -.014em; line-height: 1.25;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kachel[data-gross="ja"] .kachel__name { font-size: 1.24rem; }
.kachel__unter {
font-size: .78rem; color: var(--text-still); line-height: 1.3;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kachel[data-gross="ja"] .kachel__unter { font-size: .83rem; }
/* Die Zahl auf der Kachel. Sie ersetzt den Pfeil, wenn dort Arbeit
liegt -- eine Kachel, die "3" sagt, ist zehnmal mehr wert als eine,
die "öffnen" sagt. */
.kachel__zahl {
position: relative; z-index: 1;
flex: none; margin-left: auto;
min-width: 32px; padding: 5px 11px;
text-align: center; font-size: .9rem; font-weight: 700;
font-variant-numeric: tabular-nums;
color: var(--ton);
background: color-mix(in srgb, var(--ton) 15%, transparent);
border: 1px solid color-mix(in srgb, var(--ton) 36%, transparent);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--ton) 26%, transparent);
border-radius: 999px;
transition: background var(--tempo), border-color var(--tempo);
}
.kachel:hover .kachel__zahl {
background: color-mix(in srgb, var(--ton) 24%, transparent);
border-color: color-mix(in srgb, var(--ton) 55%, transparent);
}
.kachel__zahl[data-warn="ja"] {
color: var(--warn);
background: rgba(255, 154, 162, .13);
border-color: rgba(255, 154, 162, .44);
box-shadow: inset 0 1px 0 rgba(255, 154, 162, .28);
}
.kachel:hover .kachel__zahl[data-warn="ja"] {
background: rgba(255, 154, 162, .2); border-color: rgba(255, 154, 162, .62);
}
.kachel__pfeil {
position: relative; z-index: 1;
flex: none; margin-left: auto;
color: var(--text-still); font-size: 1rem;
transition: color var(--tempo), transform var(--tempo);
}
.kachel:hover .kachel__pfeil { color: var(--ton); transform: translateX(4px); }
/* Gestaffelter Einlauf. Die Verzögerung kommt aus --nr, das start.js je
Kachel setzt. Steht in einer no-preference-Abfrage, damit bei
"weniger Bewegung" gar keine Animation entsteht -- nicht nur eine
ohne Dauer. */
@media (prefers-reduced-motion: no-preference) {
.kachel {
animation: kachel-ein .38s cubic-bezier(.32, 0, .2, 1) backwards;
animation-delay: calc(var(--nr, 0) * 26ms);
}
@keyframes kachel-ein {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: none; }
}
}
.zahlen-leer {
margin: 0; padding: 15px 17px;
font-size: .88rem; color: var(--text-still);
border: 1px dashed var(--rand); border-radius: var(--radius-klein);
}
@media (max-width: 900px) {
.kacheln { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.kachel[data-gross="ja"] { grid-column: span 2; }
}
@media (max-width: 560px) {
.kacheln { grid-template-columns: 1fr; }
.kachel[data-gross="ja"] { grid-column: span 1; }
.gruppe__kopf { gap: 4px; }
.gruppe__unter { flex-basis: 100%; }
}
.inhalt .fuss { margin-top: 40px; text-align: left; }
@media (max-width: 520px) {
.kopfleiste { padding: 12px 16px; gap: 10px; }
/* Die Marke wich zwar zurueck, nahm aber immer noch so viel Platz,
dass vom Namen nur noch drei Pixel uebrig blieben. Auf dem Handy
verschwindet sie deshalb -- genau derselbe Text steht zwei Zeilen
tiefer als Ueberschrift, der Name des Angemeldeten dagegen
nirgends sonst.
Aber nur dort, wo der Zurueck-Knopf sichtbar ist: Auf der
Startseite gibt es ihn nicht, dort waere die linke Haelfte sonst
leer und die Leiste saehe kaputt aus. */
.kopfleiste:has(.zurueck-knopf:not([hidden])) .marke { display: none; }
.kopfleiste__rechts { margin-left: auto; }
.wer { max-width: none; }
/* Der Pfeil allein sagt "zurueck" -- das Wort daneben kostet auf dem
Handy 65 px, die dem Abmelden-Knopf fehlen. Vorlesende Programme
verlieren nichts: Der Text bleibt im Dokument und wird nur
unsichtbar gerechnet. */
.zurueck-knopf { padding: 9px 12px 9px 11px; }
.zurueck-knopf__text {
position: absolute; width: 1px; height: 1px;
margin: -1px; padding: 0; overflow: hidden;
clip-path: inset(50%); white-space: nowrap;
}
.zurueck-knopf { gap: 0; }
}
/* Zurueckhaltender Zweitknopf. Gehoert bewusst hierher und nicht in eine
einzelne Seite: Er wird ueberall gebraucht, und als Seiten-CSS fehlte er
prompt dort, wo die Datei nicht geladen war -- dann standen nackte
Systemknoepfe in der Oberflaeche. */
/* ---------- Was ist dran ------------------------------------------------
Steht vor den Zahlen. Zahlen sagen, WIE VIEL anliegt -- diese Liste
sagt, WAS zu tun ist. Nur drei Stufen, und nur die oberste ist farbig:
Waere alles hervorgehoben, waere nichts hervorgehoben. */
/* Die Seite ist breit, damit die Kacheln Platz haben. Eine Zeile Text
ueber 1240 px zu ziehen macht sie aber nicht lesbarer, sondern
anstrengender -- Hinweise und Begruessung behalten deshalb ihr Mass. */
.willkommen, .dran__liste, .inhalt .fuss { max-width: 940px; }
.dran { margin-bottom: 30px; }
.dran__liste { display: grid; gap: 7px; margin: 0; padding: 0; list-style: none; }
.dran__punkt {
position: relative;
border: 1px solid var(--rand);
border-radius: var(--radius-klein);
background: rgba(255, 255, 255, .028);
transition: border-color .18s ease, background .18s ease;
}
.dran__punkt::before {
content: ""; position: absolute; left: 0; top: 9px; bottom: 9px; width: 2px;
border-radius: 0 2px 2px 0;
background: var(--rand);
}
.dran__punkt[data-stufe="warnung"] {
border-color: rgba(255, 154, 162, .3);
background: rgba(255, 154, 162, .055);
}
.dran__punkt[data-stufe="warnung"]::before { background: var(--warn); }
.dran__punkt[data-stufe="offen"]::before { background: var(--akzent); opacity: .7; }
.dran__punkt[data-stufe="ruhig"] { opacity: .78; }
.dran__punkt:hover { border-color: rgba(255, 255, 255, .2); background: rgba(255, 255, 255, .05); }
.dran__punkt[data-stufe="ruhig"]:hover { opacity: 1; }
.dran__link {
display: flex; align-items: center; justify-content: space-between; gap: 14px;
padding: 12px 15px 12px 18px;
color: var(--text); text-decoration: none; font-size: .9rem;
}
.dran__punkt[data-stufe="warnung"] .dran__text { font-weight: 600; }
.dran__pfeil {
color: var(--text-still); font-size: .95rem;
transition: transform .18s ease, color .18s ease;
}
.dran__link:hover .dran__pfeil { color: var(--akzent); transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
.kachel__wasserzeichen, .kachel__zeichen { transition: none; }
.kachel:hover .kachel__wasserzeichen { transform: rotate(-8deg); }
.kachel:hover .kachel__zeichen { transform: none; }
.dran__punkt, .dran__pfeil { transition: none; }
.dran__link:hover .dran__pfeil { transform: none; }
}