Files
dogfather-universe/assets/css/webdesign.css
T
DogFatherGitandClaude Opus 5 81c7d40274 Grosse Kacheln kippen jetzt weniger als kleine
Auf der Portfolio-Seite war die Bewegung zu stark. Der Grund liegt nicht
am Winkel, sondern an der Groesse: Bei gleichem Winkel legt eine grosse
Kachel an ihren Ecken viel mehr Weg zurueck als eine kleine.

Eine Preiskachel auf der Startseite ist 282 Punkte lang, eine
Portfolio-Kachel 1503. Fuenf Grad sehen bei der einen beilaeufig aus und
bei der anderen wie das Kippen des halben Bildschirms -- obwohl in
beiden Faellen exakt derselbe Wert im Stilblatt steht.

Der Winkel haengt jetzt an der Kachelgroesse. Bezugswert sind 420
Punkte: Kacheln bis dahin kippen voll, groessere anteilig weniger. Nach
unten bei 1,4 Grad begrenzt, damit auch die groesste Kachel noch
erkennbar reagiert und der Effekt nicht einfach ausfaellt.

Gemessen ueber alle Seiten:

  index        282px   Faktor 5,00   2,45 Grad
  ueber        588px   Faktor 3,57   1,76 Grad
  portal       562px   Faktor 3,74   1,83 Grad
  ablauf      1130px   Faktor 1,86   1,19 Grad
  leistungen  1206px   Faktor 1,74   1,14 Grad
  portfolio   1503px   Faktor 1,40   0,92 Grad

Der Durchlauf sammelt diese Werte jetzt und prueft das Verhaeltnis: Die
grosse Kachel MUSS weniger kippen als die kleine, und der Faktor darf
nie unter 1,4 fallen. Ein blosser Test auf "hoechstens neun Grad" haette
den Unterschied nicht bemerkt -- beide Faelle lagen ja deutlich
darunter, und trotzdem war einer davon zu viel.

Geprueft: 298 Pruefungen gruen (Bewegung 34, Portfolio 19, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 13:11:53 +02:00

3030 lines
135 KiB
CSS

/* =====================================================================
DOGFATHER WEBDESIGN — webdesign.css
Eigenes Designsystem für den Bereich /webdesign, umgesetzt nach dem
"Website Masterplan" (Seite 6, VISUELLE DNA).
Warum eine EIGENE Datei statt main.css zu erweitern:
- main.css trägt drei Welten (Dogfather/HasiDog/SpicyMedia) über
theme-*.css. Der Webdesign-Bereich ist eine vierte, eigenständige
Marke mit eigener Farblogik (Gold ist hier z.B. AUSSCHLIESSLICH für
Hinweise/Zahlung reserviert, im Universe ist es allgemeine Deko).
Eine Vermischung würde beide Systeme unscharf machen.
- Der Bereich ist bis zur Freigabe nicht öffentlich. Solange darf er
am laufenden Universe nichts kaputt machen können — getrennte Datei
heißt: null Risiko für die Live-Seite.
Die Grundtokens (--radius, Schriftfamilien) kommen weiterhin aus
main.css, das hier zusätzlich geladen wird. Alles Eigene trägt bewusst
das Präfix --wd- / .wd-, damit es sich nie mit main.css beißt.
AUGENSCHONEND ist Dauervorgabe (nicht projektspezifisch):
gedeckte Flächen statt greller Neon-Optik, Leuchten nur als weicher
Schimmer, keine Flacker-/Strobe-Effekte, jede Animation respektiert
prefers-reduced-motion, Textkontraste durchgehend über WCAG-AA.
===================================================================== */
/* ---------------------------------------------------------------------
1. FARBWELT & TOKENS
Kontraste gegen die dunkelste Fläche (--wd-schwarz) nachgerechnet:
--wd-text #eef4fb -> 17.4:1 (AAA)
--wd-text-mid #b3c2d4 -> 10.2:1 (AAA)
--wd-text-soft #8f9fb4 -> 6.6:1 (AA, auch für kleine Schrift)
--wd-blau #7fd0e8 -> 10.6:1 (AAA)
--wd-lila #b79dff -> 8.1:1 (AAA)
--wd-gold #e8c877 -> 11.0:1 (AAA)
Bewusst KEIN reines #00e5ff / #ff00ff — solche vollgesättigten Neons
blenden auf dunklem Grund und sind genau das, was vermieden werden soll.
--------------------------------------------------------------------- */
:root {
/* ===================================================================
CRYONOVA — Farbsystem nach dem Design-System "Baby Blue Optical
Luxury" (Edition 2.0, 24.08.2026).
WAS SICH GEAENDERT HAT: nur Farben und Lichtwirkung. Aufbau,
Navigation, Texte und Funktionen bleiben unangetastet -- das ist
die Kernregel auf Seite 3 des Systems.
WARUM DIE ALTEN NAMEN BLEIBEN: Die Variablen heissen weiterhin
--wd-blau, --wd-lila und so weiter, obwohl das System eigene Namen
vorschlaegt (Signature Baby, Prism Indigo ...). Ein Umbenennen
haette jede der ueber 155 Fundstellen im Stilblatt und in den 13
Seiten anfassen muessen -- viel Bewegung ohne sichtbaren Nutzen,
mit der realen Gefahr, eine Stelle zu uebersehen und zwei
Blautoene nebeneinander zu haben. Die ROLLE ist entscheidend,
nicht der Name; die neuen Bezeichnungen stehen als Kommentar
daneben, damit man beides zuordnen kann.
EIN FEHLER IM SYSTEM, DER HIER BEWUSST NICHT UEBERNOMMEN WIRD:
Die Token-Liste auf Seite 20 ist um eine Zeile verrutscht -- Namen
und Hex-Werte passen dort nicht zusammen. Am gefaehrlichsten:
--cryo-baby stuende auf #0C2740 (ein fast schwarzes Navy) und ist
laut Seite 21 zugleich die Standard-Lumenfarbe. Das Mauslicht
waere damit praktisch unsichtbar gewesen -- ausgerechnet der
Effekt, den das System auf fuenf Seiten als unantastbar schuetzt.
Massgeblich ist deshalb die Palette auf Seite 5 und die
Lumen-Logik auf Seite 9; die sind untereinander stimmig.
=================================================================== */
/* ---------- Grundflaechen: DARK DEPTH (34 % der Flaeche) ---------- */
--wd-schwarz: #030810; /* Void — tiefste Ebene, Seitengrund */
--wd-dunkelblau: #061323; /* Midnight Core — Navigation, Kopfzeile */
--wd-dunkelblau-2: #091B2D; /* Obsidian Blue — Abschnittswechsel, Karten */
--wd-flaeche: #0C2740; /* Deep Glass — Kartengrund, Formularfelder */
--wd-flaeche-2: #091B2D; /* Obsidian — zweite Kartenebene */
/* ---------- Markenfarben als KANÄLE ----------
Zusätzlich zu den fertigen Farben stehen die Rot-, Grün- und
Blauanteile einzeln bereit. Das ist kein Selbstzweck.
Halbdurchsichtige Töne — Ränder, Leuchten, sanfte Flächen — brauchen
einen Alphawert. Mit einer fertigen Farbvariablen geht das nicht,
also stand die Farbe in solchen Regeln ausgeschrieben da:
"rgb(var(--wd-blau-rgb) / .16)". Eine Zählung am 23.08.2026 ergab
155 solcher Stellen, allein 74 für Blau.
Die Folge: Wer den Markenton ändern will, muss 155 Stellen finden.
Man übersieht welche, und die Seite hat danach zwei Blautöne, die
sich um eine Nuance unterscheiden — der Unterschied zwischen
gewachsener und gestalteter Oberfläche.
Mit den Kanälen schreibt man rgb(var(--wd-blau-rgb) / .16). Eine
Änderung hier wirkt überall. Die fertigen Farben bleiben daneben
erhalten, weil sie kürzer zu lesen sind, wo kein Alpha gebraucht
wird — sie werden aus denselben Kanälen gebildet, können also nicht
auseinanderlaufen. */
--wd-blau-rgb: 143 216 255; /* Signature Baby #8FD8FF — Hauptfarbe */
--wd-ion-rgb: 74 200 255; /* Ion Blue #4AC8FF — Interaktion */
--wd-aqua-rgb: 46 242 224; /* Hyper Aqua #2EF2E0 — Energie, Fokus */
--wd-lila-rgb: 167 107 255; /* Aurora Violet #A76BFF — Spezial */
--wd-indigo-rgb: 97 92 255; /* Prism Indigo #615CFF — Premium */
--wd-gold-rgb: 232 195 106; /* Liquid Gold #E8C36A — VIP, Treue */
--wd-ok-rgb: 36 214 160; /* Erfolg #24D6A0 */
--wd-fehler-rgb: 255 92 122; /* Signal Coral #FF5C7A */
--wd-warn-rgb: 255 190 74; /* Warnung #FFBE4A */
--wd-chrome-rgb: 175 196 210; /* Chrome Silver #AFC4D2 — sekundaer */
--wd-glas-rgb: 12 39 64; /* Deep Glass als Kanal fuer Glasflaechen */
--wd-blau: rgb(var(--wd-blau-rgb)); /* Hauptaktionen, Linien, Leuchten */
--wd-blau-hell: #D6F1FF; /* Glacier Mist — aktive Flaeche, heller Text */
--wd-blau-tief: rgb(var(--wd-ion-rgb)); /* Ion Blue — Raender, Verlaeufe */
--wd-ion: rgb(var(--wd-ion-rgb));
--wd-aqua: rgb(var(--wd-aqua-rgb)); /* Fokusring, Live-Zustand */
--wd-lila: rgb(var(--wd-lila-rgb)); /* sekundaere Bereiche, Spezial */
--wd-lila-tief: rgb(var(--wd-indigo-rgb));
--wd-indigo: rgb(var(--wd-indigo-rgb));
--wd-gold: rgb(var(--wd-gold-rgb)); /* NUR Hinweise, Zahlungen, VIP */
--wd-gold-tief: #b8934a;
--wd-chrome: rgb(var(--wd-chrome-rgb));
/* ---------- Text ----------
Gemessen gegen alle vier Grundflaechen (Void, Midnight, Obsidian,
Deep Glass): Optic White erreicht 15.0 bis 19.8:1, Glacier 13.0 bis
17.1:1, Chrome 8.4 bis 11.1:1. Alle drei liegen damit deutlich
ueber den geforderten 4.5:1.
WICHTIG -- die Grenze des Systems: Prism Indigo (#615CFF) erreicht
auf KEINER dieser Flaechen 4.5:1 (nur 3.25 bis 4.29:1). Es ist
deshalb ausschliesslich fuer Kanten, Verlaeufe und grosse
Premium-Flaechen zugelassen, niemals fuer Fliesstext. Das
Design-System sieht Indigo ohnehin nur fuer "Premium-Momente" vor
-- die Rechnung bestaetigt also die Regel, statt ihr zu
widersprechen. */
--wd-text: #FBFEFF; /* Optic White — Ueberschriften, Haupttext */
--wd-text-mid: #D6F1FF; /* Glacier Mist — zweite Ebene */
--wd-text-soft: rgb(var(--wd-chrome-rgb)); /* Chrome — Metadaten, Hinweise */
/* Kachelkante: das System nennt 24-36 % Deckkraft (Seite 11). Der
Ruhewert liegt am unteren Ende, damit eine Seite voller Karten
nicht wie ein Gitternetz wirkt; erst Hover und Fokus gehen hoch. */
--wd-rand: rgb(var(--wd-blau-rgb) / .24);
--wd-rand-stark: rgb(var(--wd-blau-rgb) / .36);
--wd-glas: rgb(var(--wd-glas-rgb) / .62);
--wd-glas-tief: rgb(6 19 35 / .86);
/* Statusfarben sind vom Markenblau getrennt (Token-Regel 04): Ein
Fehler darf nicht dieselbe Farbe tragen wie eine Hauptaktion,
sonst wird beides bedeutungslos. Jeder Status erscheint zusaetzlich
immer mit Text -- Farbe allein reicht nie (Seite 16). */
--wd-ok: rgb(var(--wd-ok-rgb));
--wd-fehler: rgb(var(--wd-fehler-rgb));
--wd-warnung: rgb(var(--wd-warn-rgb));
/* Eine Skala mit vier Stufen: 6 / 10 / 14 / 20 -- plus 999px fuer die
Pillenform, die keine Stufe ist, sondern eine eigene Form.
Vorher waren 12 verschiedene Werte im Umlauf, darunter 5, 7, 9 und
11px. Solche Zwischenwerte entstehen nicht aus Absicht, sondern
weil man beim Bauen einer neuen Kachel nicht nachschaut, was
nebenan schon gilt. Auffallen tut es niemandem einzeln -- in Summe
ist es der Unterschied zwischen gewachsener und gestalteter
Oberflaeche. */
--wd-r: 14px; /* Standardradius */
--wd-r-gross: 20px;
--wd-schatten: 0 24px 60px -28px rgba(0, 0, 0, .9);
--wd-schatten-tief: 0 40px 90px -34px rgba(0, 0, 0, .95);
/* Bewegung an EINER Stelle steuerbar — die Reduktions-Regel ganz unten
setzt diese Variablen auf 0s, damit auch neu hinzukommende Animationen
automatisch mit abgeschaltet sind und nicht einzeln nachgepflegt
werden müssen. */
--wd-zeit-schnell: .16s;
--wd-zeit: .28s;
--wd-zeit-lang: .6s;
}
/* ---------------------------------------------------------------------
1b. BILDLAUFLEISTE
Rückmeldung 22.08.2026: "die leiste rechts zum hoch und runter, kannst
du die mal geil aussehen lassen anstatt einfach so kake weiß."
Zu Recht. Auf einer durchgehend dunklen Seite ist eine helle
Bildlaufleiste der einzige grelle Streifen im Bild — sie zieht den
Blick genau dorthin, wo nichts Wichtiges steht, und ist bei einer
dunklen Umgebung schlicht blendend. Das widerspricht der Dauervorgabe
"augenschonend".
Zwei Wege sind nötig, weil kein Browser beide versteht:
* color-scheme: dark -- Firefox und Safari. Ein einziges Wort, das
dem Browser sagt: das hier ist eine dunkle Oberfläche, nimm deine
dunklen Bedienelemente. Wirkt auch auf Auswahlfelder und
Datumsauswahl, die sonst weiß aufblitzen.
* ::-webkit-scrollbar -- Chrome, Edge, Opera. Feiner steuerbar,
aber ausschließlich dort verfügbar.
scrollbar-width/-color (die neue Norm) NICHT verwendet: Sobald es
gesetzt ist, ignoriert Chrome die ::-webkit-Regeln und man bekommt
überall die grobe Fassung. Zwei getrennte Wege ergeben in beiden
Browserfamilien das bessere Ergebnis.
Die Leiste ist bewusst zurückhaltend: gedeckt, erst beim Zeigen etwas
heller. Sie soll auffindbar sein, nicht leuchten.
--------------------------------------------------------------------- */
body.wd,
.wd input, .wd select, .wd textarea {
/* Wirkt zusätzlich auf Formularfelder — sonst bleibt die Datumsauswahl
in Firefox ein weißes Rechteck mitten in der dunklen Seite. */
color-scheme: dark;
}
/* ACHTUNG bei den Selektoren: "body.wd::-webkit-scrollbar" (ohne
Leerzeichen) und ".wd ::-webkit-scrollbar" (mit Leerzeichen) sind
zwei VERSCHIEDENE Dinge, und man braucht beide.
ohne Leerzeichen -> die Leiste des body selbst, also die grosse
rechts am Fensterrand. GENAU die war gemeint.
mit Leerzeichen -> die Leisten von Elementen INNERHALB der Seite,
z.B. im Detailfenster der Verwaltung.
Beim ersten Versuch stand hier nur die zweite Fassung. Alle Messungen
sahen gut aus — an der einzigen Leiste, ueber die sich jemand
beschwert hatte, aenderte sich dadurch nichts. */
body.wd::-webkit-scrollbar,
.wd ::-webkit-scrollbar { width: 12px; height: 12px; }
body.wd::-webkit-scrollbar-track,
.wd ::-webkit-scrollbar-track {
background: rgba(8, 14, 24, .6);
border-radius: 999px;
}
body.wd::-webkit-scrollbar-thumb,
.wd ::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, rgb(var(--wd-blau-rgb) / .44), rgb(var(--wd-lila-rgb) / .36));
border-radius: 999px;
/* Der durchsichtige Rand lässt die Spur seitlich durchscheinen — der
Griff wirkt dadurch schmaler als die Trefferfläche. Bedienbar bleibt
die volle Breite, sichtbar ist nur ein feiner Strich. */
border: 3px solid transparent;
background-clip: content-box;
}
body.wd::-webkit-scrollbar-thumb:hover,
.wd ::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, rgb(var(--wd-blau-rgb) / .6), rgb(var(--wd-lila-rgb) / .5));
background-clip: content-box;
}
body.wd::-webkit-scrollbar-thumb:active,
.wd ::-webkit-scrollbar-thumb:active {
background: linear-gradient(180deg, rgb(var(--wd-blau-rgb) / .8), rgb(var(--wd-lila-rgb) / .7));
background-clip: content-box;
}
/* Die Ecke zwischen waagerechter und senkrechter Leiste — ohne diese
Zeile bleibt genau dort ein weißes Quadrat stehen. */
body.wd::-webkit-scrollbar-corner,
.wd ::-webkit-scrollbar-corner { background: transparent; }
/* ---------------------------------------------------------------------
2. GRUNDLAGEN
--------------------------------------------------------------------- */
body.wd {
background: var(--wd-schwarz);
color: var(--wd-text);
font-family: var(--font-body);
line-height: 1.7;
overflow-x: hidden;
}
/* Cinematische Tiefe: zwei sehr weiche, weit auseinanderliegende
Lichtquellen statt eines flächigen Verlaufs. Fest positioniert, damit
beim Scrollen echte Tiefe entsteht, ohne eine einzige Animation zu
kosten (Masterplan S.6 "Cinematische Tiefe, Licht, Nebel" — S.15 aber
auch "Animationen leistungsbewusst"). */
body.wd::before {
content: "";
position: fixed;
inset: 0;
z-index: -2;
pointer-events: none;
background:
radial-gradient(1100px 720px at 18% -8%, rgba(61, 157, 189, .20), transparent 68%),
radial-gradient(900px 640px at 92% 8%, rgba(124, 92, 214, .16), transparent 66%),
linear-gradient(180deg, var(--wd-schwarz) 0%, var(--wd-schwarz) 46%, var(--wd-schwarz) 100%);
}
/* Feine Rasterlinien — gibt der Fläche Struktur (Premium statt Baukasten),
bleibt mit 3 % Deckkraft klar unter der Wahrnehmungsschwelle für
"unruhig". mask blendet das Raster nach unten aus, damit es nicht
teppichartig über die ganze Seite liegt. */
body.wd::after {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
opacity: .5;
background-image:
linear-gradient(rgb(var(--wd-blau-rgb) / .03) 1px, transparent 1px),
linear-gradient(90deg, rgb(var(--wd-blau-rgb) / .03) 1px, transparent 1px);
background-size: 64px 64px;
-webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 62%);
mask-image: linear-gradient(180deg, #000 0%, transparent 62%);
}
.wd-container { width: min(1180px, 92vw); margin: 0 auto; }
.wd-container--schmal { width: min(860px, 92vw); }
/* Abstand zwischen den Abschnitten.
Vorher clamp(3.4rem, 7vw, 6.5rem) = 100,8px oben UND unten, also gut
200px Leerraum zwischen zwei Abschnitten. Rueckmeldung 22.08.2026:
"ich will nicht soooo viel abstand". Jetzt rund die Haelfte -- immer
noch klar getrennt, aber ohne dass man an leeren Flaechen
vorbeiscrollt. */
.wd-abschnitt { padding: clamp(2.2rem, 4vw, 3.6rem) 0; position: relative; }
.wd-abschnitt--eng { padding: clamp(1.4rem, 2.6vw, 2.2rem) 0; }
/* Abwechselnde Grundfläche statt Trennlinien — ruhiger und trotzdem klar. */
.wd-abschnitt--gehoben { background: linear-gradient(180deg, transparent, var(--wd-dunkelblau) 14%, var(--wd-dunkelblau) 86%, transparent); }
/* ---------- Typografie (Masterplan S.6) ----------
Dynamische Größen mit clamp(); Fließtext bewusst ruhiger und kleiner als
im Universe (dort 1.32rem), weil hier deutlich mehr Sachtext steht —
Preise, Bedingungen und Abläufe müssen lesbar sein, nicht laut. */
.wd h1, .wd h2, .wd h3, .wd h4 {
font-family: var(--font-head);
line-height: 1.15;
letter-spacing: -.015em;
margin: 0 0 .5em;
color: var(--wd-text);
/* Lange deutsche Komposita ("Buchhaltungsverwaltungsseiten") duerfen auf
dem Handy nicht aus dem Kasten laufen — dafuer reicht
overflow-wrap: break-word. Es greift NUR im Notfall, wenn ein Wort
sonst wirklich ueberlaufen wuerde.
"hyphens: auto" stand hier zusaetzlich und ist wieder raus: der
Browser trennt damit nach Silben, auch wenn gar kein Platzproblem
besteht. Auf dem Handy stand dadurch "Alles, was vorher ge-klaert
sein sollte" in der Ueberschrift. In Fliesstext ist Silbentrennung
ein Gewinn, in grossen Ueberschriften sieht sie schlicht billig aus —
und genau die sind das Erste, was jemand von der Seite sieht. */
overflow-wrap: break-word;
hyphens: manual;
}
.wd h1 { font-size: clamp(2.15rem, 5.6vw, 3.9rem); font-weight: 800; }
.wd h2 { font-size: clamp(1.75rem, 4.2vw, 2.75rem); font-weight: 800; }
.wd h3 { font-size: clamp(1.2rem, 2.4vw, 1.5rem); font-weight: 700; }
.wd h4 { font-size: 1.05rem; font-weight: 700; }
.wd p { margin: 0 0 1em; color: var(--wd-text-mid); font-size: clamp(1rem, 1.5vw, 1.12rem); }
.wd .wd-lead { font-size: clamp(1.08rem, 2vw, 1.32rem); color: var(--wd-text); line-height: 1.65; }
.wd .wd-klein { font-size: .92rem; }
.wd .wd-leise { color: var(--wd-text-soft); }
/* :not(.wd-btn) ist hier PFLICHT, kein Feinschliff.
Ohne das gewinnt ".wd a" (Klasse + Element = spezifischer als die reine
Knopf-Klasse ".wd-btn--haupt") und faerbt die Schrift auf dem hellblauen
Hauptknopf ebenfalls hellblau -- blau auf blau, praktisch unlesbar.
Genau so live gemeldet am 22.08.2026 per Bildschirmfoto. */
.wd a:not(.wd-btn) { color: var(--wd-blau); text-decoration: none; }
.wd a:not(.wd-btn):hover { color: var(--wd-blau-hell); }
.wd a.wd-btn { text-decoration: none; }
.wd strong { color: var(--wd-text); font-weight: 700; }
.wd-eyebrow {
display: inline-block;
font-size: 0.8rem;
letter-spacing: .18em;
text-transform: uppercase;
font-weight: 800;
color: var(--wd-blau);
margin-bottom: .9em;
}
.wd-eyebrow--lila { color: var(--wd-lila); }
/* Sichtbarer Fokus ÜBERALL (Masterplan S.15 Barrierearmut). :focus-visible
statt :focus, damit Mausklicks keinen Rahmen hinterlassen, Tastatur aber
immer einen — und zwar auch auf Elementen, die erst später dazukommen. */
.wd :focus-visible {
outline: 3px solid var(--wd-blau);
outline-offset: 3px;
border-radius: 6px;
}
/* Sprungmarke für Tastatur-/Screenreader-Nutzung. */
.wd-skip {
position: absolute; left: -9999px; top: 0; z-index: 200;
background: var(--wd-blau); color: var(--wd-schwarz); font-weight: 800;
padding: .8rem 1.2rem; border-radius: 0 0 10px 0;
}
.wd-skip:focus { left: 0; }
/* ---------------------------------------------------------------------
[hidden] MUSS gewinnen.
Das hidden-Attribut wird vom Browser nur mit "display: none" aus dem
Standard-Stylesheet umgesetzt — jede eigene display-Angabe schlaegt es.
Und genau die haben hier viele Elemente: Knoepfe sind inline-flex,
Karten sind flex, Raster sind grid.
Folge ohne diese Regel: el.hidden = true im JavaScript hat schlicht
keine Wirkung, und das Element bleibt sichtbar. Genau so aufgefallen im
Anfrageformular (22.08.2026) -- der "Zurueck"-Knopf stand auch auf dem
ersten Schritt da, obwohl es dorthin nichts zurueckzugehen gibt.
Das !important ist hier ausnahmsweise richtig: "versteckt" ist eine
Aussage ueber den Zustand, nicht ueber die Gestaltung, und darf von
keiner Gestaltungsregel ueberstimmt werden.
--------------------------------------------------------------------- */
.wd [hidden] { display: none !important; }
.wd-visuell-versteckt {
position: absolute; width: 1px; height: 1px; overflow: hidden;
clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* ---------------------------------------------------------------------
BILDVERHAELTNIS — diese Regel verhindert einen Fehler, der schon
passiert ist und sonst wieder passiert.
Bilder tragen im HTML bewusst width/height als Attribute: der Browser
reserviert damit vor dem Laden den richtigen Platz und die Seite
springt beim Nachladen nicht. Diese Attribute wirken aber wie eine
CSS-Hoehe -- und schlagen damit jedes spaetere "aspect-ratio".
Live gemeldet am 22.08.2026 ("die sollen alle gleich aussehen"): die
beiden Projektbilder standen mit 750px bzw. 696px Hoehe bei nur 576px
Breite da, also hochkant gestreckt und ungleich hoch, obwohl im CSY
sauber 16:10 stand.
"height: auto" gibt die Hoehe an aspect-ratio zurueck. Es steht hier
einmal zentral fuer alle Bilder mit Seitenverhaeltnis, statt in jeder
einzelnen Regel -- so kann es bei einem neuen Bild nicht vergessen
werden.
--------------------------------------------------------------------- */
.wd img[width][height] { height: auto; }
/* ---------------------------------------------------------------------
3. KARTEN — "glasartig mit feinen Neonrändern" (Masterplan S.6)
Der Rand ist bewusst ein Verlauf über border-box statt einer flachen
Farbe: dadurch wirkt er wie eine Lichtkante, nicht wie ein Strich.
--------------------------------------------------------------------- */
.wd-karte {
position: relative;
border-radius: var(--wd-r-gross);
padding: clamp(1.3rem, 2.6vw, 1.9rem);
background:
linear-gradient(180deg, rgba(20, 32, 50, .72), rgba(9, 15, 26, .86)) padding-box,
linear-gradient(140deg, rgb(var(--wd-blau-rgb) / .40), rgb(var(--wd-blau-rgb) / .07) 45%, rgb(var(--wd-lila-rgb) / .30)) border-box;
border: 1px solid transparent;
box-shadow: var(--wd-schatten);
backdrop-filter: blur(10px);
transition: transform var(--wd-zeit) ease, box-shadow var(--wd-zeit) ease;
}
/* Sekundäre Bereiche tragen Lila (Masterplan S.6). */
.wd-karte--lila {
background:
linear-gradient(180deg, rgba(26, 22, 48, .72), rgba(12, 10, 24, .88)) padding-box,
linear-gradient(140deg, rgb(var(--wd-lila-rgb) / .42), rgb(var(--wd-lila-rgb) / .07) 45%, rgb(var(--wd-blau-rgb) / .26)) border-box;
}
/* Nur für Karten, die wirklich klickbar sind — eine Karte, die sich hebt,
ohne dass man sie anklicken kann, verspricht eine Aktion, die es nicht
gibt. */
a.wd-karte:hover, .wd-karte--klickbar:hover {
transform: translateY(-4px);
box-shadow: var(--wd-schatten-tief), 0 0 44px -20px rgb(var(--wd-blau-rgb) / .55);
}
/* Farbige Kappe oben — übernimmt die Optik der Masterplan-PDF, in der jede
Karte einen blauen bzw. lila Balken trägt. */
.wd-karte--kappe { padding-top: clamp(1.6rem, 3vw, 2.2rem); overflow: hidden; }
.wd-karte--kappe::before {
content: "";
position: absolute; top: 0; left: 0; right: 0; height: 5px;
background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau));
}
.wd-karte--lila.wd-karte--kappe::before { background: linear-gradient(90deg, var(--wd-lila-tief), var(--wd-lila)); }
.wd-karte h3 { margin-bottom: .55em; }
.wd-karte > :last-child { margin-bottom: 0; }
/* Aufzählung in Karten — Punkt als eigenes Element statt list-style, damit
die Farbe steuerbar ist und mehrzeilige Punkte sauber einrücken. */
.wd-liste { margin: 0; padding: 0; list-style: none; }
.wd-liste li {
position: relative;
padding-left: 1.35rem;
margin-bottom: .55rem;
color: var(--wd-text-mid);
font-size: clamp(.98rem, 1.4vw, 1.05rem);
}
.wd-liste li::before {
content: "";
position: absolute; left: 0; top: .62em;
width: 7px; height: 7px; border-radius: 50%;
background: var(--wd-blau);
box-shadow: 0 0 10px rgb(var(--wd-blau-rgb) / .7);
}
.wd-karte--lila .wd-liste li::before { background: var(--wd-lila); box-shadow: 0 0 10px rgb(var(--wd-lila-rgb) / .7); }
.wd-liste li:last-child { margin-bottom: 0; }
/* ---------- Raster ---------- */
.wd-grid { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }
.wd-grid--2 { grid-template-columns: repeat(2, 1fr); }
.wd-grid--3 { grid-template-columns: repeat(3, 1fr); }
.wd-grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .wd-grid--3, .wd-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .wd-grid--2, .wd-grid--3, .wd-grid--4 { grid-template-columns: 1fr; } }
/* ---------------------------------------------------------------------
4. KNÖPFE
Genau EIN Haupt-CTA pro Seite (Masterplan S.3) — deshalb gibt es
bewusst nur eine einzige auffällige Knopfvariante. Alles andere ist
sichtbar, konkurriert aber nicht.
--------------------------------------------------------------------- */
.wd-btn {
display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
/* min-height 48px = Touch-Ziel-Mindestmaß (Masterplan S.15). */
min-height: 48px;
padding: .85rem 1.7rem;
/* Abgerundetes Rechteck statt Pillenform (999px).
Rueckmeldung 22.08.2026: "das sieht lang gezogen aus". Stimmt — bei
einer Pille waechst der Radius optisch mit der Breite mit, ein breiter
Knopf wirkt dadurch auseinandergezogen wie eine Tablette. Ein fester
Radius haelt die Form bei jeder Breite gleich und wirkt ruhiger und
hochwertiger. */
border-radius: 14px;
border: 1px solid transparent;
font-family: var(--font-head);
font-weight: 700;
font-size: 1rem;
line-height: 1.2;
cursor: pointer;
text-align: center;
transition: transform var(--wd-zeit-schnell) ease, box-shadow var(--wd-zeit) ease,
background var(--wd-zeit) ease, border-color var(--wd-zeit) ease, color var(--wd-zeit) ease;
}
/* Sofortige, sichtbare Reaktion (Masterplan S.6 "Buttons reagieren sofort
und sichtbar") — active feuert ohne Verzögerung, auch auf dem Handy. */
.wd-btn:active { transform: translateY(1px) scale(.985); }
.wd-btn[disabled], .wd-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; }
.wd .wd-btn--haupt, .wd-btn--haupt {
/* Dunkler Text auf hellem Babyblau: 11.7:1 — der einzige Weg, einen
leuchtenden Knopf zu bauen, ohne die Lesbarkeit zu opfern. */
background: linear-gradient(135deg, var(--wd-blau-hell), var(--wd-blau) 55%, var(--wd-ion));
color: var(--wd-schwarz);
box-shadow: 0 12px 34px -14px rgb(var(--wd-blau-rgb) / .8);
}
.wd-btn--haupt:hover { box-shadow: 0 16px 44px -14px rgb(var(--wd-blau-rgb) / .95); transform: translateY(-2px); }
.wd .wd-btn--zweit, .wd-btn--zweit {
background: rgb(var(--wd-blau-rgb) / .07);
border-color: var(--wd-rand-stark);
color: var(--wd-blau-hell);
}
.wd-btn--zweit:hover { background: rgb(var(--wd-blau-rgb) / .14); border-color: var(--wd-blau); }
.wd .wd-btn--still, .wd-btn--still { background: transparent; border-color: var(--wd-rand); color: var(--wd-text-mid); }
.wd-btn--still:hover { border-color: var(--wd-rand-stark); color: var(--wd-text); }
.wd-btn--breit { width: 100%; }
/* "klein" heißt schmaler und leiser, NICHT niedriger als das Touch-Ziel.
Die Höhe stand hier ursprünglich auf 40px — die Handy-Abnahme
(server/pruefe-webdesign-handy.mjs) hat das quer über alle Seiten
angemerkt: „Dieses Paket anfragen“, „Live ansehen“ und „Was genau
enthalten ist“ waren durchgehend 4px zu flach. 44px ist die Untergrenze,
ab der ein Ziel mit dem Daumen zuverlässig getroffen wird. */
.wd-btn--klein { min-height: 44px; padding: .6rem 1.05rem; font-size: .9rem; }
.wd-btn-reihe { display: flex; flex-wrap: wrap; gap: .8rem; align-items: center; }
/* ---------------------------------------------------------------------
5. HINWEISFLÄCHEN — Gold ist AUSSCHLIESSLICH hierfür reserviert
(Masterplan S.6: "Gold ausschließlich für wichtige Hinweise und
Zahlungsinformationen"). Wer Gold sieht, soll wissen: das ist wichtig.
--------------------------------------------------------------------- */
.wd-hinweis {
position: relative;
border-radius: var(--wd-r);
padding: 1.15rem 1.35rem 1.15rem 1.6rem;
background: linear-gradient(180deg, rgb(var(--wd-gold-rgb) / .09), rgb(var(--wd-gold-rgb) / .04));
border: 1px solid rgb(var(--wd-gold-rgb) / .32);
border-left: 4px solid var(--wd-gold);
}
.wd-hinweis-titel {
margin: 0 0 .35rem;
font-family: var(--font-head);
font-weight: 800;
font-size: .82rem;
letter-spacing: .12em;
text-transform: uppercase;
color: var(--wd-gold);
}
.wd-hinweis p { margin: 0; color: var(--wd-text-mid); font-size: .98rem; }
.wd-hinweis p + p { margin-top: .6rem; }
/* Neutrale Variante für Erklärungen, die NICHT wichtig-wichtig sind —
damit Gold seine Signalwirkung behält. */
.wd-notiz {
border-radius: var(--wd-r);
padding: 1rem 1.25rem;
background: rgb(var(--wd-blau-rgb) / .05);
border: 1px solid var(--wd-rand);
}
.wd-notiz p { margin: 0; font-size: .96rem; }
/* ---------------------------------------------------------------------
6. TAGS / KENNZEICHEN
--------------------------------------------------------------------- */
.wd-tag {
display: inline-flex; align-items: center; gap: .35rem;
padding: .3rem .7rem;
border-radius: 999px;
font-size: .78rem; font-weight: 700; letter-spacing: .04em;
background: rgb(var(--wd-blau-rgb) / .12);
border: 1px solid var(--wd-rand-stark);
color: var(--wd-blau-hell);
}
.wd-tag--lila { background: rgb(var(--wd-lila-rgb) / .12); border-color: rgb(var(--wd-lila-rgb) / .34); color: var(--wd-lila); }
.wd-tag--gold { background: rgb(var(--wd-gold-rgb) / .12); border-color: rgb(var(--wd-gold-rgb) / .34); color: var(--wd-gold); }
.wd-tag--ok { background: rgb(var(--wd-ok-rgb) / .12); border-color: rgb(var(--wd-ok-rgb) / .34); color: var(--wd-ok); }
/* Aqua fuer die Arcade. Als Schriftfarbe unbedenklich: Hyper Aqua liegt
auf allen vier dunklen Flaechen zwischen 12,4:1 und 19,8:1. */
.wd-tag--aqua { background: rgb(var(--wd-aqua-rgb) / .12); border-color: rgb(var(--wd-aqua-rgb) / .34); color: rgb(var(--wd-aqua-rgb)); }
/* Indigo NUR als Flaeche und Kante, NIE als Schrift: Prism Indigo ist
die einzige Farbe der Palette, die als Text durchfaellt (3,25--4,29:1).
Die Schrift bleibt deshalb bewusst Chrome Silver. */
.wd-tag--indigo { background: rgb(var(--wd-indigo-rgb) / .16); border-color: rgb(var(--wd-indigo-rgb) / .40); color: rgb(var(--wd-chrome-rgb)); }
.wd-tags { display: flex; flex-wrap: wrap; gap: .45rem; }
/* =====================================================================
KACHELN ALS GESCHLIFFENE GLASPLATTEN
Was zuerst nur im Verwaltungsbereich stand, gilt jetzt fuer jede
Kachel auf jeder Seite. Eine Sonderloesung fuer einen Bereich waere
beim naechsten neuen Abschnitt wieder vergessen worden -- und die
Seite saehe an zwei Stellen unterschiedlich aus, ohne dass es einen
Grund dafuer gaebe.
Die Farbe kommt aus --wd-lumen. Jede Kachel bringt die schon mit
(Token-Regel 02: Kachelfarbe steuert Lumenfarbe), der
Verwaltungsbereich ueberschreibt sie mit der Farbe des Bereichs.
Dadurch braucht es hier keine einzige Sonderregel.
===================================================================== */
@media (hover: hover) and (pointer: fine) {
/* Die Perspektive steckt in der Kachel selbst, NICHT an einem
Elternteil.
Der naheliegende Weg waere "perspective" auf dem Abschnitt -- dann
teilen benachbarte Kacheln einen gemeinsamen Fluchtpunkt. Genau das
hatte aber eine boese Nebenwirkung: "perspective" macht ein Element
zum Bezugsrahmen fuer position:fixed in seinem Inneren, exakt wie
"transform" oder "filter". Die bildschirmfuellende Buehne im
Verwaltungsbereich lag danach nicht mehr am Fenster, sondern am
Abschnitt -- gemessen 472 statt 900 Punkte Hoehe.
Als Funktion im transform gilt die Perspektive nur fuer diese eine
Kachel. Der gemeinsame Fluchtpunkt entfaellt damit, was bei
hoechstens fuenf Grad Neigung niemand sieht. */
.wd-karte {
transform-style: preserve-3d;
/* --wd-kipp kommt aus dem Skript und haengt an der Kachelgroesse:
kleine Kacheln kippen voll, grosse anteilig weniger. Ohne das
sieht derselbe Winkel bei einer Portfolio-Kachel aus wie das
Kippen des halben Bildschirms. */
transform:
perspective(1400px)
rotateX(calc(var(--wd-ny, 0) * var(--wd-kipp, 5) * -1deg))
rotateY(calc(var(--wd-nx, 0) * var(--wd-kipp, 5) * 1deg));
transition:
transform .32s cubic-bezier(.2,.8,.3,1),
box-shadow .32s ease;
}
/* Beim Ueberfahren kommt die Kachel dem Betrachter entgegen und wirft
einen laengeren Schatten. Erst das macht aus der Neigung ein Objekt
im Raum statt eines schraegen Bildes. */
.wd-karte:hover {
transform:
perspective(1400px)
rotateX(calc(var(--wd-ny, 0) * var(--wd-kipp, 5) * -1deg))
rotateY(calc(var(--wd-nx, 0) * var(--wd-kipp, 5) * 1deg))
translateZ(20px);
box-shadow:
0 40px 84px -34px rgb(0 0 0 / .92),
0 0 52px -18px rgb(var(--wd-lumen) / .38),
inset 0 1px 0 rgb(var(--wd-lumen) / .26);
}
/* Ueberschriften stehen weiter vorn als Fliesstext. Dadurch entsteht
beim Neigen echte Staffelung statt einer flachen Ebene, die sich
mitdreht -- und der Text bleibt fast senkrecht zum Auge, also
scharf, obwohl die Flaeche unter ihm schraeg liegt. */
.wd-karte > * { transform: translateZ(14px); }
.wd-karte h2, .wd-karte h3 { transform: translateZ(28px); }
/* Der Glanzstreifen sitzt beim Lichtkegel im ::after -- siehe dort.
Das ::before bleibt frei fuer die farbige Oberkante
(.wd-karte--kappe), die es schon vor allen Lichteffekten gab. */
}
@media (prefers-reduced-motion: reduce) {
.wd-karte, .wd-karte:hover { transform: none; transition: none; }
.wd-karte > *, .wd-karte h2, .wd-karte h3 { transform: none; }
}
/* =====================================================================
BILDER, DIE SICH BEWEGEN
Faehrt der Zeiger ueber ein Bild, tritt es leicht naeher und wandert
ein Stueck gegen die Zeigerrichtung -- als schaue man durch ein
Fenster und lehne sich zur Seite.
Warum GEGEN die Richtung: Bewegt sich das Bild mit dem Zeiger, wirkt
es wie ein Aufkleber, der verrutscht. Bewegt es sich dagegen, liest
das Auge es als Tiefe hinter dem Rahmen. Derselbe Grund wie bei der
Buehne im Verwaltungsbereich.
Der Ausschlag ist klein (hoechstens 14 Punkte) und der Zoom knapp
ueber eins. Beides zusammen ergibt Bewegung, ohne dass ein Bild beim
Ueberfahren seinen Ausschnitt merklich aendert -- sonst waere jedes
Vorbeifahren mit der Maus ein Bildsprung.
===================================================================== */
@media (hover: hover) and (pointer: fine) {
/* Der Rahmen muss den Ueberstand abschneiden, sonst schiebt sich das
vergroesserte Bild ueber die Kachelkante hinaus. */
.wd-bildrahmen,
.pfo-projekt,
.wd-karte:has(> img:first-child) {
overflow: hidden;
}
.pfo-bild,
.wd-projekt-bild,
.wd-bildrahmen > img,
.wd-karte > img {
transform:
scale(var(--wd-bildzoom, 1))
translate3d(calc(var(--wd-bx, 0) * -14px), calc(var(--wd-by, 0) * -10px), 0);
transition: transform .55s cubic-bezier(.2,.75,.25,1);
will-change: transform;
}
/* Der Zoom kommt erst beim Ueberfahren dazu. Als Dauerzustand waere
jedes Bild permanent leicht beschnitten. */
.pfo-projekt:hover .pfo-bild,
.wd-bildrahmen:hover > img,
.wd-karte:hover > img,
.pfo-bild:hover,
.wd-projekt-bild:hover {
--wd-bildzoom: 1.055;
}
/* AUSNAHME: Bilder INNERHALB einer Kachel bekommen nur den Zoom.
Die Kachel kippt bereits, das Bild bewegt sich also ohnehin mit.
Beides zusammen schaukelt sich auf: Die kippende Kachel schiebt das
Bild unter dem Zeiger weg, der landet auf einem Nachbarelement, das
Bild springt zurueck auf null -- und beim naechsten Zucken von
vorne. Beim Bauen sass der Wert an einer Ecke deshalb dauerhaft
auf 0, waehrend er an der anderen sauber lief.
Diese Regel steht bewusst ganz am Ende der Bildregeln: Sie hat
dieselbe Gewichtung wie ".pfo-bild" und gewinnt nur, weil sie
spaeter kommt. Wird sie nach oben verschoben, ist der Aufschaukel-
Effekt sofort zurueck. */
.wd-karte img {
transform: scale(var(--wd-bildzoom, 1));
}
}
@media (prefers-reduced-motion: reduce) {
.pfo-bild, .wd-projekt-bild, .wd-bildrahmen > img, .wd-karte > img {
transform: none;
transition: none;
}
}
/* ---------------------------------------------------------------------
7. PREISKARTEN (Masterplan S.8)
Preis, Dauer und Personalisierungshinweis gehören sichtbar zusammen —
der Hinweis steht deshalb direkt unter dem Preis, nicht im Kleingedruckten.
--------------------------------------------------------------------- */
.wd-preis-karte { display: flex; flex-direction: column; }
.wd-preis {
font-family: var(--font-head);
font-weight: 800;
font-size: clamp(1.9rem, 4.4vw, 2.5rem);
line-height: 1.1;
margin: .2rem 0 .5rem;
color: var(--wd-blau);
}
.wd-karte--lila .wd-preis { color: var(--wd-lila); }
.wd-preis-zeile { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; margin-bottom: .5rem; }
.wd-preis-label { font-size: .78rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--wd-blau); }
.wd-karte--lila .wd-preis-label { color: var(--wd-lila); }
.wd-preis-wert { color: var(--wd-text-mid); font-size: .98rem; }
/* mt:auto schiebt den Knopf immer an den Kartenboden — sonst stehen die
Knöpfe in einer Reihe unterschiedlich hoher Karten treppenförmig. */
.wd-preis-karte .wd-btn { margin-top: auto; }
.wd-personalisierung {
margin-top: .2rem;
font-size: .88rem;
color: var(--wd-text-soft);
font-style: italic;
}
/* ---------------------------------------------------------------------
8. NUMMERIERTE SCHRITTE (Ablauf / Customer Journey)
--------------------------------------------------------------------- */
.wd-schritte { display: grid; gap: 1rem; }
.wd-schritt {
display: grid;
grid-template-columns: auto 1fr;
gap: 1.1rem;
align-items: start;
border-radius: var(--wd-r-gross);
padding: 1.25rem 1.4rem;
background: linear-gradient(180deg, rgba(20, 32, 50, .55), rgba(9, 15, 26, .75));
border: 1px solid var(--wd-rand);
}
.wd-schritt-nr {
font-family: var(--font-head);
font-weight: 800;
font-size: clamp(1.4rem, 3vw, 1.9rem);
line-height: 1;
min-width: 2.2ch;
color: var(--wd-blau);
font-variant-numeric: tabular-nums;
}
.wd-schritt:nth-child(even) { border-color: rgb(var(--wd-lila-rgb) / .18); }
.wd-schritt:nth-child(even) .wd-schritt-nr { color: var(--wd-lila); }
.wd-schritt h3 { margin: 0 0 .3em; font-size: 1.12rem; }
.wd-schritt p { margin: 0; font-size: 1rem; }
@media (max-width: 520px) {
.wd-schritt { grid-template-columns: 1fr; gap: .4rem; }
}
/* ---------------------------------------------------------------------
9. FAQ — natives <details>, damit es ohne JavaScript funktioniert
und die Tastaturbedienung vom Browser kommt statt nachgebaut zu werden.
--------------------------------------------------------------------- */
.wd-faq { border-radius: var(--wd-r); border: 1px solid var(--wd-rand); background: rgb(var(--wd-glas-rgb) / .5); margin-bottom: .7rem; overflow: hidden; }
.wd-faq > summary {
cursor: pointer;
list-style: none;
padding: 1.05rem 3rem 1.05rem 1.25rem;
position: relative;
font-family: var(--font-head);
font-weight: 700;
font-size: 1.04rem;
color: var(--wd-text);
transition: background var(--wd-zeit-schnell) ease;
}
.wd-faq > summary::-webkit-details-marker { display: none; }
.wd-faq > summary:hover { background: rgb(var(--wd-blau-rgb) / .05); }
.wd-faq > summary::after {
content: "+";
position: absolute; right: 1.2rem; top: 50%; transform: translateY(-50%);
font-size: 1.5rem; line-height: 1; color: var(--wd-blau);
transition: transform var(--wd-zeit) ease;
}
.wd-faq[open] > summary::after { transform: translateY(-50%) rotate(45deg); }
.wd-faq-inhalt { padding: 0 1.25rem 1.15rem; }
.wd-faq-inhalt p { margin: 0; font-size: 1rem; }
.wd-faq-inhalt p + p { margin-top: .7rem; }
/* ---------------------------------------------------------------------
10. FORMULARE (Masterplan S.10 + S.15)
Zustände für Fehler und Erfolg sind Pflicht — und der Fehler steht
IMMER unter dem Feld, nie nur als Farbe: Farbe allein ist für
farbfehlsichtige Menschen keine Information.
--------------------------------------------------------------------- */
.wd-feld { margin-bottom: 1.15rem; }
.wd-feld > label,
.wd-feld-legende {
display: block;
margin-bottom: .45rem;
font-weight: 700;
font-size: .95rem;
color: var(--wd-text);
}
.wd-pflicht { color: var(--wd-blau); margin-left: .15rem; }
.wd-feld-hilfe { display: block; margin: -.2rem 0 .5rem; font-size: .88rem; color: var(--wd-text-soft); }
.wd-eingabe,
.wd-feld input[type="text"], .wd-feld input[type="email"], .wd-feld input[type="tel"],
.wd-feld input[type="url"], .wd-feld input[type="number"], .wd-feld input[type="date"],
.wd-feld input[type="password"], .wd-feld input[type="search"],
.wd-feld select, .wd-feld textarea {
width: 100%;
box-sizing: border-box;
padding: .82rem 1rem;
min-height: 48px;
border-radius: 10px;
background: var(--wd-flaeche);
border: 1.5px solid var(--wd-rand);
color: var(--wd-text);
font-family: var(--font-body);
/* 16px verhindert, dass iOS beim Fokus in ein Feld hineinzoomt. */
font-size: 16px;
line-height: 1.5;
transition: border-color var(--wd-zeit-schnell) ease, box-shadow var(--wd-zeit-schnell) ease, background var(--wd-zeit-schnell) ease;
}
.wd-feld textarea { min-height: 130px; resize: vertical; }
.wd-feld select {
/* Eigener Pfeil: das Standard-Dreieck von Windows ist auf dunklem Grund
fast unsichtbar. */
appearance: none;
background-image: linear-gradient(45deg, transparent 50%, var(--wd-blau) 50%), linear-gradient(135deg, var(--wd-blau) 50%, transparent 50%);
background-position: calc(100% - 20px) center, calc(100% - 14px) center;
background-size: 6px 6px, 6px 6px;
background-repeat: no-repeat;
padding-right: 2.6rem;
}
.wd-feld ::placeholder { color: rgba(143, 159, 180, .7); }
.wd-eingabe:focus, .wd-feld input:focus, .wd-feld select:focus, .wd-feld textarea:focus {
outline: none;
border-color: var(--wd-blau);
background: #12203180;
box-shadow: 0 0 0 4px rgb(var(--wd-blau-rgb) / .16);
}
/* Fehlerzustand */
.wd-feld--fehler .wd-eingabe,
.wd-feld--fehler input, .wd-feld--fehler select, .wd-feld--fehler textarea {
border-color: var(--wd-fehler);
box-shadow: 0 0 0 4px rgb(var(--wd-fehler-rgb) / .12);
}
.wd-feld-fehler {
display: none;
margin: .45rem 0 0;
font-size: .9rem;
color: var(--wd-fehler);
font-weight: 600;
}
.wd-feld-fehler::before { content: "⚠ "; }
.wd-feld--fehler .wd-feld-fehler { display: block; }
/* Auswahlkacheln (Radio/Checkbox als anklickbare Fläche) — deutlich
fingerfreundlicher als native Punkte und zeigt den gewählten Zustand
nicht nur farblich, sondern über Rand + Häkchen. */
.wd-wahl { display: grid; gap: .7rem; }
.wd-wahl--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 640px) { .wd-wahl--2 { grid-template-columns: 1fr; } }
.wd-wahl-kachel { position: relative; display: block; cursor: pointer; }
.wd-wahl-kachel input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.wd-wahl-inhalt {
display: block;
padding: 1rem 1.15rem 1rem 2.9rem;
border-radius: 14px;
background: rgb(var(--wd-glas-rgb) / .6);
border: 1.5px solid var(--wd-rand);
transition: border-color var(--wd-zeit-schnell) ease, background var(--wd-zeit-schnell) ease;
}
.wd-wahl-inhalt::before {
content: "";
position: absolute; left: 1rem; top: 1.15rem;
width: 20px; height: 20px; border-radius: 6px;
border: 2px solid var(--wd-rand-stark);
background: rgba(5, 7, 11, .6);
transition: border-color var(--wd-zeit-schnell) ease, background var(--wd-zeit-schnell) ease;
}
.wd-wahl-kachel input[type="radio"] + .wd-wahl-inhalt::before { border-radius: 50%; }
.wd-wahl-kachel:hover .wd-wahl-inhalt { border-color: var(--wd-rand-stark); }
.wd-wahl-kachel input:checked + .wd-wahl-inhalt {
border-color: var(--wd-blau);
background: rgb(var(--wd-blau-rgb) / .09);
}
.wd-wahl-kachel input:checked + .wd-wahl-inhalt::before {
border-color: var(--wd-blau);
background: var(--wd-blau);
/* Häkchen als CSS-Maske — kein Bild, keine Schriftart nötig. */
box-shadow: inset 0 0 0 3px var(--wd-schwarz), inset 0 0 0 20px var(--wd-blau);
}
.wd-wahl-kachel input:focus-visible + .wd-wahl-inhalt { outline: 3px solid var(--wd-blau); outline-offset: 3px; }
.wd-wahl-titel { display: block; font-weight: 700; color: var(--wd-text); }
.wd-wahl-text { display: block; font-size: .9rem; color: var(--wd-text-soft); margin-top: .15rem; }
/* Erfolgs-/Fehlermeldung eines ganzen Formulars */
.wd-meldung { border-radius: var(--wd-r); padding: 1rem 1.2rem; margin-bottom: 1.2rem; font-weight: 600; }
.wd-meldung--ok { background: rgb(var(--wd-ok-rgb) / .1); border: 1px solid rgb(var(--wd-ok-rgb) / .38); color: var(--wd-ok); }
.wd-meldung--fehler { background: rgb(var(--wd-fehler-rgb) / .1); border: 1px solid rgb(var(--wd-fehler-rgb) / .38); color: var(--wd-fehler); }
.wd-meldung[hidden] { display: none; }
/* ---------------------------------------------------------------------
11. FORTSCHRITT (mehrstufiges Formular)
--------------------------------------------------------------------- */
.wd-fortschritt { margin-bottom: 1.8rem; }
.wd-fortschritt-schiene { height: 6px; border-radius: 999px; background: rgb(var(--wd-blau-rgb) / .12); overflow: hidden; }
.wd-fortschritt-balken {
height: 100%; width: 0%;
border-radius: 999px;
background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau));
transition: width var(--wd-zeit-lang) cubic-bezier(.4, 0, .2, 1);
}
.wd-fortschritt-text { margin: .6rem 0 0; font-size: .88rem; color: var(--wd-text-soft); }
/* ---------------------------------------------------------------------
12. TABELLEN (Verwaltung / Portal)
Auf schmalen Bildschirmen scrollt die Tabelle waagerecht in ihrem
eigenen Kasten, statt die ganze Seite zu verbreitern.
--------------------------------------------------------------------- */
.wd-tabelle-rahmen { overflow-x: auto; border-radius: var(--wd-r); border: 1px solid var(--wd-rand); }
.wd-tabelle { width: 100%; border-collapse: collapse; font-size: .95rem; min-width: 560px; }
.wd-tabelle th, .wd-tabelle td { padding: .8rem 1rem; text-align: left; border-bottom: 1px solid var(--wd-rand); }
.wd-tabelle th {
font-family: var(--font-head); font-size: .78rem; font-weight: 800;
letter-spacing: .1em; text-transform: uppercase; color: var(--wd-blau);
background: rgb(var(--wd-blau-rgb) / .05);
position: sticky; top: 0;
}
.wd-tabelle tbody tr:last-child td { border-bottom: none; }
.wd-tabelle tbody tr:hover { background: rgb(var(--wd-blau-rgb) / .04); }
.wd-tabelle td { color: var(--wd-text-mid); }
/* ---------------------------------------------------------------------
13. BEWEGUNG — "kontrolliert beim Scrollen" (Masterplan S.6)
Die Elemente starten sichtbar und werden erst per JS auf unsichtbar
gesetzt (Klasse .wd-bereit am <html>). Ohne JavaScript oder bei einem
Skriptfehler bleibt dadurch ALLES lesbar — der häufigste schwere Fehler
bei Scroll-Animationen ist eine dauerhaft unsichtbare Seite.
--------------------------------------------------------------------- */
/* Die Einblendung nutzt "translate" als EIGENE Eigenschaft, nicht
"transform".
Grund: Kacheln neigen sich beim Ueberfahren, und das laeuft ueber
"transform". Diese Regel hier hat mit drei Klassen die hoehere
Spezifitaet -- ihr "transform: none" hat die Neigung stillschweigend
geloescht. Sichtbar war das nur auf Seiten, deren Kacheln ein
.wd-auf tragen: Auf "ablauf" kippte die Kachel, auf "leistungen"
nicht, und der Wert kam in beiden Faellen korrekt an.
"translate" wird VOR "transform" angewendet. Beide koennen sich so
nicht mehr in die Quere kommen. */
.wd-bereit .wd-auf {
opacity: 0;
translate: 0 18px;
transition: opacity var(--wd-zeit-lang) ease, translate var(--wd-zeit-lang) cubic-bezier(.22, 1, .36, 1);
}
.wd-bereit .wd-auf.wd-sichtbar { opacity: 1; translate: none; }
/* ---------------------------------------------------------------------
14. KOPF- UND FUSSZEILE des Webdesign-Bereichs
Eigene Leiste statt der Universe-Navigation: der Bereich hat eigene
Ziele (Anfrage statt Bewerbung) und ist bis zur Freigabe nicht
öffentlich. Der Rückweg ins Universe steht trotzdem immer sichtbar
drin (Masterplan S.14 "Direkte Navigation zwischen Universe und
Webdesign").
--------------------------------------------------------------------- */
.wd-kopf {
position: sticky; top: 0; z-index: 60;
background: rgba(5, 7, 11, .92);
backdrop-filter: blur(14px);
border-bottom: 1px solid var(--wd-rand);
}
.wd-kopf-bar {
width: min(1320px, 94vw); margin: 0 auto;
display: flex; align-items: center; gap: 1rem;
padding: .7rem 0;
}
/* min-height 44px: die Marke ist ein Link auf die Startseite und damit
ein echtes Touch-Ziel — sie war vorher exakt so hoch wie das Logo (42px). */
.wd-marke { display: flex; align-items: center; gap: .65rem; flex-shrink: 0; min-height: 44px; }
.wd-marke img { width: 42px; height: 42px; object-fit: contain; }
.wd-marke-text { display: flex; flex-direction: column; line-height: 1.1; }
.wd-marke-oben { font-family: var(--font-head); font-weight: 800; font-size: 1rem; color: var(--wd-text); letter-spacing: .02em; }
.wd-marke-unten { font-size: 0.75rem; letter-spacing: .18em; text-transform: uppercase; color: var(--wd-blau); font-weight: 700; }
.wd-nav { display: flex; align-items: center; gap: .15rem; margin-left: auto; }
.wd-nav a {
/* inline-flex + min-height statt nur Innenabstand: mit reinem padding
kam der Menüpunkt auf 43px — einen Pixel unter dem Touch-Ziel, was
die Handy-Abnahme zu Recht angemerkt hat. */
display: inline-flex; align-items: center; min-height: 44px;
padding: .5rem .8rem; border-radius: 10px;
font-size: .95rem; font-weight: 600; color: var(--wd-text-mid);
transition: color var(--wd-zeit-schnell) ease, background var(--wd-zeit-schnell) ease;
}
.wd-nav a:hover { color: var(--wd-text); background: rgb(var(--wd-blau-rgb) / .07); }
.wd-nav a.wd-aktiv { color: var(--wd-blau); background: rgb(var(--wd-blau-rgb) / .11); }
.wd-nav .wd-btn { margin-left: .5rem; }
.wd-menue-knopf {
display: none; margin-left: auto;
align-items: center; gap: .45rem;
min-height: 44px; padding: .5rem .9rem;
border-radius: 10px; border: 1px solid var(--wd-rand);
background: transparent; color: var(--wd-text); cursor: pointer; font-weight: 700;
}
/* Sprachschalter — teilt sich die gespeicherte Sprache mit dem Universe
(localStorage "dogi-sprache"), damit ein Wechsel hier auch dort gilt. */
.wd-sprache { position: relative; }
.wd-sprache-knopf {
display: inline-flex; align-items: center; gap: .35rem;
/* 44px statt 40px — auch auf dem Computer ist das der bessere Wert:
Touchscreen-Laptops und Tablets im Querformat landen ebenfalls hier. */
min-height: 44px; padding: .5rem .75rem;
border-radius: 10px; border: 1px solid var(--wd-rand);
background: transparent; color: var(--wd-text-mid); cursor: pointer;
font-weight: 700; font-size: .88rem;
}
.wd-sprache-knopf:hover { color: var(--wd-text); border-color: var(--wd-rand-stark); }
.wd-sprache-liste {
position: absolute; right: 0; top: calc(100% + .4rem);
min-width: 190px; padding: .35rem;
border-radius: 10px;
background: var(--wd-dunkelblau);
border: 1px solid var(--wd-rand-stark);
box-shadow: var(--wd-schatten);
display: none;
z-index: 70;
}
.wd-sprache.wd-offen .wd-sprache-liste { display: block; }
.wd-sprache-liste button {
display: flex; align-items: center; gap: .6rem;
width: 100%; min-height: 42px; padding: .5rem .7rem;
border: none; border-radius: 10px; background: transparent;
color: var(--wd-text-mid); cursor: pointer; text-align: left; font-size: .95rem;
}
.wd-sprache-liste button:hover { background: rgb(var(--wd-blau-rgb) / .09); color: var(--wd-text); }
.wd-sprache-liste button[aria-current="true"] { color: var(--wd-blau); font-weight: 700; }
.wd-sprache-punkt { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
@media (max-width: 1080px) {
.wd-menue-knopf { display: inline-flex; }
.wd-nav {
display: none;
position: absolute; left: 0; right: 0; top: 100%;
flex-direction: column; align-items: stretch; gap: .2rem;
padding: .8rem 4vw 1.2rem;
background: var(--wd-schwarz);
border-bottom: 1px solid var(--wd-rand);
box-shadow: var(--wd-schatten);
/* Vollbildnavigation auf dem Handy (Masterplan S.5), aber scrollbar —
bei 8 Punkten + Sprachschalter passt sonst nicht alles auf ein
kleines Display. */
max-height: calc(100dvh - 70px);
overflow-y: auto;
}
.wd-nav.wd-offen { display: flex; }
/* Die minimale Kopfzeile (Zugangswand) enthält nur den Sprachschalter und
hat deshalb bewusst keinen Menü-Knopf. Ohne diese Ausnahme wäre sie auf
dem Handy durch die Regel oben komplett unsichtbar — man könnte die
Sprache dort dann gar nicht mehr umstellen. */
.wd-nav--minimal {
display: flex; position: static; flex-direction: row;
padding: 0; background: none; border: none; box-shadow: none;
max-height: none; overflow: visible; width: auto;
}
.wd-nav--minimal .wd-sprache { margin-top: 0; }
.wd-nav--minimal .wd-sprache-knopf { width: auto; }
.wd-nav--minimal .wd-sprache-liste { position: absolute; width: auto; }
.wd-nav a { padding: .8rem .9rem; font-size: 1.02rem; }
.wd-nav .wd-btn { margin: .6rem 0 0; }
.wd-sprache { margin-top: .6rem; }
.wd-sprache-knopf { width: 100%; justify-content: center; }
.wd-sprache-liste { position: static; width: 100%; margin-top: .4rem; }
}
/* Fußzeile */
.wd-fuss { border-top: 1px solid var(--wd-rand); background: rgba(5, 7, 11, .8); padding: 2.6rem 0 2rem; margin-top: 3rem; }
.wd-fuss-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 2rem; }
@media (max-width: 780px) { .wd-fuss-grid { grid-template-columns: 1fr; gap: 1.5rem; } }
/* Die Spaltenueberschriften der Fusszeile sind jetzt h2 statt h4.
Grund: Sie folgten im Dokument auf die h2 der Seite -- ein Sprung von
h2 direkt auf h4. Wer sich mit einem Screenreader durch die
Ueberschriften bewegt, hoert dabei eine Gliederung, die es nicht gibt,
und vermutet uebersprungene Abschnitte (WCAG 1.3.1). Auf allen 13
Seiten in allen 5 Sprachen -- also 42 Stellen.
Die Klasse haelt die Optik unveraendert: Die Ebene sagt etwas ueber
die STRUKTUR, die Groesse ueber die GEWICHTUNG. Das sind zwei
verschiedene Dinge, und man soll das eine nicht ueber das andere
erzwingen muessen. */
.wd-fuss .wd-fuss-h, .wd-fuss h4 {
font-size: .78rem; letter-spacing: .14em; text-transform: uppercase;
color: var(--wd-blau); margin: 0 0 .8rem; font-weight: 700;
font-family: var(--font-head);
}
.wd-fuss ul li { margin-bottom: .1rem; }
/* Fußzeilenlinks waren nur so hoch wie ihre Zeile (20px) und damit auf dem
Handy praktisch nicht sicher zu treffen — sie liegen zudem dicht
untereinander, was Fehlgriffe zusätzlich begünstigt. Als inline-flex mit
Mindesthöhe sind sie ein ordentliches Touch-Ziel; die Fußzeile wird
dadurch etwas höher, was hier die richtige Abwägung ist. */
.wd-fuss a {
display: inline-flex; align-items: center; min-height: 44px;
color: var(--wd-text-mid); font-size: .95rem;
}
/* Die Marke in der Fußzeile bringt ihre eigene Höhe mit. */
.wd-fuss a.wd-marke { min-height: 48px; }
.wd-fuss a:hover { color: var(--wd-blau); }
.wd-fuss-unten {
margin-top: 2rem; padding-top: 1.2rem;
border-top: 1px solid var(--wd-rand);
display: flex; flex-wrap: wrap; gap: .8rem; justify-content: space-between;
font-size: .86rem; color: var(--wd-text-soft);
}
/* ---------------------------------------------------------------------
15. HERO
"Der erste Bildschirm enthält niemals zu viel Text" (Masterplan S.7).
min-height bewusst mit svh: 100vh ist auf dem Handy die Höhe OHNE
Adressleiste — der Knopf rutscht damit beim ersten Laden unter die
sichtbare Kante, genau das, was die Hero-Regel verbietet.
--------------------------------------------------------------------- */
.wd-hero { position: relative; padding: clamp(2.6rem, 6vw, 4.6rem) 0 clamp(2.2rem, 4vw, 3.4rem); min-height: 68svh; display: flex; align-items: center; }
.wd-hero-inhalt { max-width: 780px; }
.wd-hero h1 { margin-bottom: .45em; }
.wd-hero .wd-lead { margin-bottom: 1.8rem; max-width: 62ch; }
.wd-hero-glanz {
/* Kein Farbverlauf über den ganzen Titel — nur die Kernaussage trägt ihn,
sonst leidet die Lesbarkeit langer Überschriften. */
background: linear-gradient(120deg, var(--wd-blau-hell), var(--wd-blau) 45%, var(--wd-lila));
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.wd-hero-belege { display: flex; flex-wrap: wrap; gap: .5rem 1.4rem; margin-top: 2rem; }
.wd-hero-beleg { display: flex; align-items: center; gap: .45rem; font-size: .92rem; color: var(--wd-text-soft); }
.wd-hero-beleg::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--wd-blau); box-shadow: 0 0 8px var(--wd-blau); }
/* ---------------------------------------------------------------------
16. INSTALLATIONS-HINWEIS ("Als App installieren")
Sitzt unten statt oben: oben würde er die Kopfzeile verdecken, und auf
dem Handy ist der Daumen unten. env(safe-area-inset-bottom) hält ihn
über der Gestenleiste neuerer iPhones — ohne das liegt der Schließen-
Knopf genau unter dem Strich und ist praktisch nicht treffbar.
--------------------------------------------------------------------- */
.wd-install {
position: fixed; z-index: 80;
left: 50%; transform: translateX(-50%);
bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
width: min(560px, calc(100vw - 1.6rem));
display: flex; align-items: center; gap: 1rem;
padding: .85rem 1rem;
border-radius: var(--wd-r);
background: rgba(11, 19, 32, .97);
border: 1px solid var(--wd-rand-stark);
box-shadow: var(--wd-schatten-tief);
backdrop-filter: blur(12px);
animation: wd-install-auf .45s cubic-bezier(.22, 1, .36, 1) both;
}
@keyframes wd-install-auf { from { opacity: 0; transform: translate(-50%, 16px); } to { opacity: 1; transform: translate(-50%, 0); } }
.wd-install-text { display: flex; align-items: center; gap: .8rem; flex: 1; min-width: 0; }
.wd-install-text img { border-radius: 10px; flex-shrink: 0; }
.wd-install-text strong { display: block; font-size: .95rem; color: var(--wd-text); }
.wd-install-text span { display: block; font-size: .84rem; color: var(--wd-text-soft); line-height: 1.45; }
.wd-install-knoepfe { display: flex; align-items: center; gap: .4rem; flex-shrink: 0; }
.wd-install-knoepfe .wd-btn--still { min-width: 44px; padding: .5rem .7rem; }
@media (max-width: 560px) {
/* Auf schmalen Bildschirmen untereinander — nebeneinander wird der Text
auf zwei Wörter pro Zeile gequetscht. */
.wd-install { flex-direction: column; align-items: stretch; gap: .7rem; }
.wd-install-knoepfe { justify-content: flex-end; }
.wd-install-knoepfe .wd-btn--haupt { flex: 1; }
}
/* ---------------------------------------------------------------------
17. BEWEGUNGSREDUKTION — eine Regel für alles
--------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
:root { --wd-zeit-schnell: 0s; --wd-zeit: 0s; --wd-zeit-lang: 0s; }
.wd *, .wd *::before, .wd *::after {
animation-duration: .001ms !important;
animation-iteration-count: 1 !important;
transition-duration: .001ms !important;
scroll-behavior: auto !important;
}
/* Wichtig: die Einblend-Elemente müssen dann SOFORT sichtbar sein,
nicht "unsichtbar mit 0s Übergang". */
.wd-bereit .wd-auf { opacity: 1; translate: none; transform: none; }
.wd-btn:hover, a.wd-karte:hover, .wd-karte--klickbar:hover { transform: none; }
}
/* Druckansicht: Angebote/Zusammenfassungen werden erfahrungsgemäß
ausgedruckt oder als PDF gesichert. */
@media print {
body.wd { background: #fff; color: #000; }
body.wd::before, body.wd::after, .wd-kopf, .wd-fuss, .wd-btn { display: none !important; }
.wd-karte { border: 1px solid #bbb; background: #fff; box-shadow: none; }
.wd h1, .wd h2, .wd h3, .wd p, .wd li { color: #000 !important; }
}
/* ---------------------------------------------------------------------
18. LEERER ZUSTAND IM KUNDENPORTAL
Ein leerer Bereich mit einem einzigen Satz ist eine verpasste
Gelegenheit. Wer hier zum ersten Mal landet, hat gerade sein Passwort
gesetzt und weiß noch nicht, was ihn erwartet — genau dann entscheidet
sich, ob die Seite souverän wirkt oder unfertig.
Deshalb zeigt der leere Zustand, WAS gleich hier stehen wird, statt
nur festzustellen, dass gerade nichts da ist.
--------------------------------------------------------------------- */
.po-leer { text-align: center; padding: clamp(1.6rem, 4vw, 2.6rem) clamp(1rem, 3vw, 2rem); }
.po-leer-symbol { width: clamp(64px, 12vw, 92px); margin: 0 auto .9rem; position: relative; }
.po-leer-symbol img { width: 100%; height: auto; opacity: .9; }
.po-leer-symbol::before {
content: ""; position: absolute; inset: -24%; z-index: -1; border-radius: 50%;
background: radial-gradient(circle, rgb(var(--wd-blau-rgb) / .26), transparent 70%);
filter: blur(20px);
}
.po-leer h3 { margin-bottom: .3em; }
.po-leer > p { max-width: 48ch; margin-left: auto; margin-right: auto; }
.po-leer-liste {
display: grid; grid-template-columns: repeat(2, 1fr); gap: .9rem;
margin: 1.6rem 0 1.2rem; text-align: left;
}
@media (max-width: 640px) { .po-leer-liste { grid-template-columns: 1fr; } }
.po-leer-punkt {
display: grid; grid-template-columns: auto 1fr; gap: .8rem; align-items: start;
padding: .9rem 1rem; border-radius: 14px;
background: rgb(var(--wd-blau-rgb) / .05); border: 1px solid var(--wd-rand);
}
.po-leer-nr {
width: 28px; height: 28px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-family: var(--font-head); font-weight: 800; font-size: .85rem;
color: var(--wd-blau); background: rgb(var(--wd-blau-rgb) / .12);
border: 1px solid var(--wd-rand-stark);
}
.po-leer-punkt strong { display: block; color: var(--wd-text); font-size: .98rem; margin-bottom: .15rem; }
/* :not(.po-leer-nr) ist hier PFLICHT, kein Feinschliff.
Der Zahlenkreis ist ebenfalls ein <span> in dieser Kachel. Ohne den
Ausschluss trifft ihn diese Regel mit -- und sie ist spezifischer
(Klasse + Element) als ".po-leer-nr" (nur Klasse). Sie erzwang dadurch
display:block, Schriftgroesse 14,4px und Zeilenhoehe 23px; die Ziffer
sass 15px neben der Kreismitte, statt darin.
Gemeldet am 22.08.2026 ("wieso sehen die zahlen immer noch so
scheisse aus?") und per Messung bestaetigt. Derselbe Spezifitaets-
Fehler wie zuvor beim Hauptknopf (blau auf blau) und bei den Namen auf
der Zugangswand -- deshalb steht die Begruendung hier so ausfuehrlich. */
.po-leer-punkt span:not(.po-leer-nr) { display: block; font-size: .88rem; color: var(--wd-text-soft); line-height: 1.5; }
.po-leer-fuss { margin: 0; }
/* ---------------------------------------------------------------------
19. VORSCHAU IM LEEREN PORTAL
Die erste Fassung BESCHRIEB, was hier bald stehen wird ("Eine Leiste
zeigt dir, in welcher Phase dein Projekt ist"). Beschreibungen sind
schwach — man muss sie lesen und sich dann etwas vorstellen.
Diese Fassung ZEIGT es: eine echte, halbdurchsichtige Projektkarte,
deren Phasenleiste langsam durchläuft. Man sieht in zwei Sekunden, was
drei Sätze nicht erklären. Genau das ist der Unterschied zwischen
"erklärt" und "verstanden".
Die Karte ist bewusst als Vorschau erkennbar (gedämpft, mit Etikett) —
sie darf nie mit einem echten Projekt verwechselt werden.
--------------------------------------------------------------------- */
.po-vorschau {
position: relative;
border-radius: var(--wd-r-gross);
padding: clamp(1.1rem, 2.6vw, 1.5rem);
background: linear-gradient(180deg, rgba(20,32,50,.5), rgba(9,15,26,.66));
border: 1px dashed var(--wd-rand-stark);
text-align: left;
overflow: hidden;
}
.po-vorschau::after {
/* Sanfter Lichtstreifen, der einmal langsam durchwandert. Er sagt ohne
Worte "hier passiert gleich etwas", ohne zu blinken oder zu zappeln. */
content: "";
position: absolute; inset: 0;
background: linear-gradient(105deg, transparent 35%, rgb(var(--wd-blau-rgb) / .07) 50%, transparent 65%);
background-size: 260% 100%;
animation: po-schimmer 5.5s ease-in-out infinite;
pointer-events: none;
}
@keyframes po-schimmer { 0% { background-position: 130% 0; } 60%, 100% { background-position: -130% 0; } }
.po-vorschau-etikett {
position: absolute; top: .7rem; right: .8rem;
font-size: 0.75rem; letter-spacing: .14em; text-transform: uppercase;
font-weight: 800; color: var(--wd-text-soft);
padding: .2rem .55rem; border-radius: 999px;
background: rgba(5,7,11,.7); border: 1px solid var(--wd-rand);
}
.po-vorschau-nr { font-family: var(--font-head); font-weight: 800; font-size: .78rem; color: var(--wd-blau); opacity: .75; }
.po-vorschau h4 { margin: .15rem 0 .6rem; font-size: clamp(1.05rem, 2.4vw, 1.25rem); color: var(--wd-text); opacity: .85; }
/* Die laufende Phasenleiste — der eigentliche Kern der Vorschau. */
.po-vorschau-phasen { display: flex; gap: 3px; margin-bottom: .5rem; }
.po-vorschau-phasen span {
flex: 1; height: 6px; border-radius: 999px;
background: rgb(var(--wd-blau-rgb) / .13);
animation: po-phase-lauf 7s ease-in-out infinite;
}
.po-vorschau-phasen span:nth-child(1) { animation-delay: 0s; }
.po-vorschau-phasen span:nth-child(2) { animation-delay: .55s; }
.po-vorschau-phasen span:nth-child(3) { animation-delay: 1.1s; }
.po-vorschau-phasen span:nth-child(4) { animation-delay: 1.65s; }
.po-vorschau-phasen span:nth-child(5) { animation-delay: 2.2s; }
.po-vorschau-phasen span:nth-child(6) { animation-delay: 2.75s; }
.po-vorschau-phasen span:nth-child(7) { animation-delay: 3.3s; }
@keyframes po-phase-lauf {
0%, 8% { background: rgb(var(--wd-blau-rgb) / .13); }
14%, 55% { background: var(--wd-blau-tief); }
100% { background: rgb(var(--wd-blau-rgb) / .13); }
}
.po-vorschau-zeile { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; font-size: .82rem; color: var(--wd-text-soft); }
.po-vorschau-marke {
display: inline-flex; align-items: center; gap: .3rem;
padding: .18rem .55rem; border-radius: 999px; font-size: 0.8rem; font-weight: 700;
background: rgb(var(--wd-blau-rgb) / .12); color: var(--wd-blau);
}
.po-vorschau-schritt { margin: .7rem 0 0; font-size: .88rem; color: var(--wd-text-mid); opacity: .8; }
/* Bewegungsreduktion: keine Animation, aber die Leiste soll trotzdem
etwas zeigen — sonst steht dort eine leere graue Reihe. */
@media (prefers-reduced-motion: reduce) {
.po-vorschau::after { animation: none; }
.po-vorschau-phasen span { animation: none; }
.po-vorschau-phasen span:nth-child(-n+3) { background: var(--wd-blau-tief); }
}
/* Die vier Merkmale kompakter und mit farbigem Akzent statt nur Nummer. */
.po-leer-punkt { transition: border-color var(--wd-zeit-schnell) ease, background var(--wd-zeit-schnell) ease; }
.po-leer-punkt:hover { border-color: var(--wd-rand-stark); background: rgb(var(--wd-blau-rgb) / .08); }
.po-leer-nr {
background: linear-gradient(135deg, rgb(var(--wd-blau-rgb) / .22), rgb(var(--wd-lila-rgb) / .18));
color: var(--wd-blau-hell); border-color: var(--wd-rand-stark);
}
/* ---------------------------------------------------------------------
20. LEERER ZUSTAND — GEHOBENE FASSUNG
Drei Rückmeldungen vom 22.08.2026, alle drei berechtigt:
"Schrift und Kacheln sollen viel spezieller sein", "die Zahlen sollen
besser im Kreis sein", "die Kisten sollen eine spezielle Farbe
bekommen wenn sie fertig sind".
Der letzte Punkt war der wichtigste und inhaltlich der schwerste:
Vorher waren erledigte und laufende Phase fast gleich blau. Damit ging
die einzige Information verloren, die die Leiste überhaupt trägt —
nämlich WO man gerade steht. Jetzt sind es drei klar verschiedene
Zustände: erledigt (grün), gerade dran (leuchtendes Blau mit Puls),
kommt noch (gedämpft).
--------------------------------------------------------------------- */
/* ---------- Zahlenkreise ----------
Vorher ein flacher Kreis mit Zahl. Jetzt ein doppelter Ring: außen ein
Farbverlauf als Rand, innen die dunkle Fläche. Das ist derselbe Kniff
wie bei den Karten (Verlauf über border-box) und lässt den Kreis
plastisch wirken, statt aufgemalt. */
.po-leer-nr {
width: 40px; height: 40px; border-radius: 50%;
font-size: 1.02rem; font-weight: 800;
color: var(--wd-blau-hell);
border: 2px solid transparent;
background:
linear-gradient(var(--wd-dunkelblau), var(--wd-dunkelblau)) padding-box,
linear-gradient(140deg, var(--wd-blau), var(--wd-lila)) border-box;
box-shadow: 0 0 18px -6px rgb(var(--wd-blau-rgb) / .55);
flex-shrink: 0;
font-variant-numeric: tabular-nums;
letter-spacing: -.02em;
}
/* ---------- Merkmalskacheln ----------
Jede bekommt oben eine eigene Farbkante. Vier gleiche Kacheln wirken
wie eine Aufzählung; vier unterscheidbare wirken wie ein System. */
.po-leer-punkt {
position: relative;
overflow: hidden;
padding: 1.1rem 1.15rem 1.15rem;
border-radius: 14px;
gap: 1rem;
background: linear-gradient(180deg, rgba(20, 32, 50, .58), rgba(9, 15, 26, .74));
}
.po-leer-punkt::before {
content: "";
position: absolute; top: 0; left: 0; right: 0; height: 3px;
background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau));
opacity: .8;
}
.po-leer-punkt:nth-child(2)::before { background: linear-gradient(90deg, var(--wd-lila-tief), var(--wd-lila)); }
.po-leer-punkt:nth-child(3)::before { background: linear-gradient(90deg, var(--wd-ok), var(--wd-ok)); }
.po-leer-punkt:nth-child(4)::before { background: linear-gradient(90deg, var(--wd-gold-tief), var(--wd-gold)); }
.po-leer-punkt:nth-child(2) .po-leer-nr {
color: var(--wd-lila);
background: linear-gradient(var(--wd-dunkelblau), var(--wd-dunkelblau)) padding-box,
linear-gradient(140deg, var(--wd-lila), var(--wd-blau)) border-box;
box-shadow: 0 0 18px -6px rgb(var(--wd-lila-rgb) / .55);
}
.po-leer-punkt:nth-child(3) .po-leer-nr {
color: var(--wd-ok);
background: linear-gradient(var(--wd-dunkelblau), var(--wd-dunkelblau)) padding-box,
linear-gradient(140deg, var(--wd-ok), var(--wd-blau)) border-box;
box-shadow: 0 0 18px -6px rgb(var(--wd-ok-rgb) / .5);
}
.po-leer-punkt:nth-child(4) .po-leer-nr {
color: var(--wd-gold);
background: linear-gradient(var(--wd-dunkelblau), var(--wd-dunkelblau)) padding-box,
linear-gradient(140deg, var(--wd-gold), var(--wd-lila)) border-box;
box-shadow: 0 0 18px -6px rgb(var(--wd-gold-rgb) / .5);
}
/* ---------- Typografie ----------
Die Überschrift der Kachel war so groß wie der Fließtext darunter und
ging dadurch unter. Jetzt größer, enger gesetzt und mit einem Hauch
negativer Laufweite — das ist der Unterschied, den man als "wertig"
empfindet, ohne ihn benennen zu können. */
.po-leer-punkt strong {
font-family: var(--font-head);
font-size: 1.06rem; font-weight: 800;
letter-spacing: -.015em; line-height: 1.25;
margin-bottom: .3rem;
}
.po-leer-punkt span:not(.po-leer-nr) { font-size: .9rem; line-height: 1.6; }
.po-leer h3 {
font-size: clamp(1.5rem, 3.6vw, 2rem);
letter-spacing: -.02em;
background: linear-gradient(120deg, var(--wd-text), var(--wd-blau-hell) 70%);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.po-leer > p { font-size: 1.02rem; }
/* ---------- Phasen: drei klar verschiedene Zustände ----------
Das war der eigentliche Mangel. Erledigt und laufend sahen fast gleich
aus — damit ging die einzige Aussage der Leiste verloren. */
.po-phase, .po-vorschau-phasen span { height: 7px; }
.po-phase.po-erledigt {
background: linear-gradient(90deg, var(--wd-ok), var(--wd-ok));
box-shadow: 0 0 8px -2px rgb(var(--wd-ok-rgb) / .5);
}
.po-phase.po-jetzt {
background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau));
box-shadow: 0 0 14px -2px rgb(var(--wd-blau-rgb) / .85);
animation: po-jetzt-puls 2.4s ease-in-out infinite;
}
@keyframes po-jetzt-puls { 0%, 100% { opacity: .82; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .po-phase.po-jetzt { animation: none; opacity: 1; } }
/* Dieselbe Logik in der Vorschau: die durchlaufende Leiste wechselt von
"gerade dran" (blau) nach "erledigt" (grün), statt einfach nur an- und
auszugehen. Damit erklärt die Vorschau die Farblogik gleich mit. */
@keyframes po-phase-lauf {
0%, 8% { background: rgb(var(--wd-blau-rgb) / .13); box-shadow: none; }
14%, 30% { background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau));
box-shadow: 0 0 12px -2px rgb(var(--wd-blau-rgb) / .8); }
38%, 62% { background: linear-gradient(90deg, var(--wd-ok), var(--wd-ok));
box-shadow: 0 0 8px -2px rgb(var(--wd-ok-rgb) / .45); }
100% { background: rgb(var(--wd-blau-rgb) / .13); box-shadow: none; }
}
/* Kleine Legende unter der Vorschau, damit die Farben nicht geraten
werden müssen. Farbe allein ist nie Information. */
.po-legende {
display: flex; flex-wrap: wrap; gap: .5rem 1.1rem;
margin-top: .9rem; font-size: .78rem; color: var(--wd-text-soft);
}
.po-legende span { display: inline-flex; align-items: center; gap: .4rem; }
.po-legende i {
width: 16px; height: 6px; border-radius: 999px; display: inline-block;
}
.po-legende .po-l-fertig { background: linear-gradient(90deg, var(--wd-ok), var(--wd-ok)); }
.po-legende .po-l-jetzt { background: linear-gradient(90deg, var(--wd-blau-tief), var(--wd-blau)); }
.po-legende .po-l-offen { background: rgb(var(--wd-blau-rgb) / .18); }
/* ---------------------------------------------------------------------
21. ZAHLENKREISE REPARIERT + VIER PROZESSFARBEN
a) "wieso sehen die zahlen immer noch so scheisse aus?"
Zu Recht. Die Ziffer sass nicht mittig im Kreis. Ursache war die
geerbte Zeilenhoehe: body.wd setzt line-height 1.7, und in einem
40px hohen Kreis erzeugt das einen Textkasten von rund 28px, der
die Ziffer nach unten drueckt. Zusaetzlich hing die Zentrierung an
einer weiter oben stehenden Regel — verlaesst man sich darauf, ist
man beim naechsten Umbau wieder verlassen.
Deshalb hier ALLES explizit: eigenes Raster, place-items, und vor
allem line-height: 1. Eine Ziffer in einem Kreis braucht genau die
Hoehe ihrer selbst, nichts sonst.
b) "es soll 4 farben geben wie 4 kategorien zum prozess"
Sehr gute Idee — und sie macht das System erst schluessig. Die
sieben Phasen sind in Wahrheit vier Abschnitte, und die vier
Merkmalskacheln tragen ohnehin schon vier Farben. Jetzt bedeuten
diese Farben ueberall dasselbe:
1 Blau Start Briefing, Angebot
2 Lila Gestaltung Design
3 Gruen Umsetzung Entwicklung, Tests
4 Gold Abschluss Abnahme, Uebergabe
Damit ist die Farbe nicht mehr Dekoration, sondern Sprache: Wer
Gold sieht, weiss, dass es auf die Zielgerade geht.
--------------------------------------------------------------------- */
/* ---------- a) Der Kreis ---------- */
.po-leer-nr {
display: grid;
place-items: center;
width: 42px; height: 42px;
padding: 0;
border-radius: 50%;
/* Der entscheidende Wert: ohne ihn erbt die Ziffer 1.7 und rutscht. */
line-height: 1;
font-family: var(--font-head);
font-size: 1.15rem;
font-weight: 800;
letter-spacing: 0;
font-variant-numeric: tabular-nums;
flex-shrink: 0;
border: 2px solid transparent;
background:
linear-gradient(var(--wd-dunkelblau-2), var(--wd-dunkelblau-2)) padding-box,
linear-gradient(140deg, var(--wd-blau), var(--wd-lila)) border-box;
}
/* Die Ziffer selbst noch einmal optisch ausrichten: Zahlen haben oben
mehr Luft als unten, rein geometrisch zentriert wirken sie deshalb
leicht zu tief. Ein Hauch nach oben gleicht das aus. */
.po-leer-nr { padding-bottom: .06em; }
/* ---------- b) Die vier Prozessfarben ---------- */
:root {
/* Die vier Prozessfarben sind KEINE eigenen Farben, sondern Rollen.
Sie zeigen auf die Markenfarben, statt deren Werte zu wiederholen --
sonst haette man vier weitere Stellen, die beim naechsten
Farbwechsel stillschweigend zurueckbleiben und die Seite in zwei
Blautoene zerfallen lassen. */
--wd-p1: var(--wd-blau); /* Start — Briefing, Angebot */
--wd-p2: var(--wd-lila); /* Gestaltung — Design */
--wd-p3: var(--wd-ok); /* Umsetzung — Entwicklung, Tests */
--wd-p4: var(--wd-gold); /* Abschluss — Abnahme, Übergabe */
}
.po-leer-punkt:nth-child(1)::before { background: linear-gradient(90deg, var(--wd-ion), var(--wd-p1)); }
.po-leer-punkt:nth-child(2)::before { background: linear-gradient(90deg, var(--wd-indigo), var(--wd-p2)); }
.po-leer-punkt:nth-child(3)::before { background: linear-gradient(90deg, var(--wd-ok), var(--wd-p3)); }
.po-leer-punkt:nth-child(4)::before { background: linear-gradient(90deg, var(--wd-gold-tief), var(--wd-p4)); }
.po-leer-punkt:nth-child(1) .po-leer-nr { color: var(--wd-p1); background: linear-gradient(var(--wd-dunkelblau-2),var(--wd-dunkelblau-2)) padding-box, linear-gradient(140deg, var(--wd-p1), var(--wd-ion)) border-box; box-shadow: 0 0 20px -7px var(--wd-p1); }
.po-leer-punkt:nth-child(2) .po-leer-nr { color: var(--wd-p2); background: linear-gradient(var(--wd-dunkelblau-2),var(--wd-dunkelblau-2)) padding-box, linear-gradient(140deg, var(--wd-p2), var(--wd-indigo)) border-box; box-shadow: 0 0 20px -7px var(--wd-p2); }
.po-leer-punkt:nth-child(3) .po-leer-nr { color: var(--wd-p3); background: linear-gradient(var(--wd-dunkelblau-2),var(--wd-dunkelblau-2)) padding-box, linear-gradient(140deg, var(--wd-p3), var(--wd-ok)) border-box; box-shadow: 0 0 20px -7px var(--wd-p3); }
.po-leer-punkt:nth-child(4) .po-leer-nr { color: var(--wd-p4); background: linear-gradient(var(--wd-dunkelblau-2),var(--wd-dunkelblau-2)) padding-box, linear-gradient(140deg, var(--wd-p4), var(--wd-gold-tief)) border-box; box-shadow: 0 0 20px -7px var(--wd-p4); }
/* ---------- Die Phasenleiste spricht dieselbe Sprache ----------
Erledigte Phasen tragen die Farbe IHRES Abschnitts, nicht pauschal
Gruen. So sieht man auf einen Blick, wie weit man im Prozess ist —
und nicht nur, dass etwas erledigt wurde. */
.po-phase { background: rgb(var(--wd-blau-rgb) / .12); }
.po-phase:nth-child(1).po-erledigt, .po-phase:nth-child(2).po-erledigt { background: var(--wd-p1); box-shadow: 0 0 9px -3px var(--wd-p1); }
.po-phase:nth-child(3).po-erledigt { background: var(--wd-p2); box-shadow: 0 0 9px -3px var(--wd-p2); }
.po-phase:nth-child(4).po-erledigt, .po-phase:nth-child(5).po-erledigt { background: var(--wd-p3); box-shadow: 0 0 9px -3px var(--wd-p3); }
.po-phase:nth-child(6).po-erledigt, .po-phase:nth-child(7).po-erledigt { background: var(--wd-p4); box-shadow: 0 0 9px -3px var(--wd-p4); }
.po-phase:nth-child(1).po-jetzt, .po-phase:nth-child(2).po-jetzt { background: var(--wd-p1); box-shadow: 0 0 16px -2px var(--wd-p1); }
.po-phase:nth-child(3).po-jetzt { background: var(--wd-p2); box-shadow: 0 0 16px -2px var(--wd-p2); }
.po-phase:nth-child(4).po-jetzt, .po-phase:nth-child(5).po-jetzt { background: var(--wd-p3); box-shadow: 0 0 16px -2px var(--wd-p3); }
.po-phase:nth-child(6).po-jetzt, .po-phase:nth-child(7).po-jetzt { background: var(--wd-p4); box-shadow: 0 0 16px -2px var(--wd-p4); }
/* Die Vorschau zeigt denselben Verlauf: jede Phase leuchtet in der Farbe
ihres Abschnitts auf, wenn sie an der Reihe ist. */
.po-vorschau-phasen span:nth-child(1), .po-vorschau-phasen span:nth-child(2) { --po-f: var(--wd-p1); }
.po-vorschau-phasen span:nth-child(3) { --po-f: var(--wd-p2); }
.po-vorschau-phasen span:nth-child(4), .po-vorschau-phasen span:nth-child(5) { --po-f: var(--wd-p3); }
.po-vorschau-phasen span:nth-child(6), .po-vorschau-phasen span:nth-child(7) { --po-f: var(--wd-p4); }
@keyframes po-phase-lauf {
0%, 8% { background: rgb(var(--wd-blau-rgb) / .12); box-shadow: none; }
14%, 60% { background: var(--po-f); box-shadow: 0 0 12px -3px var(--po-f); }
100% { background: rgb(var(--wd-blau-rgb) / .12); box-shadow: none; }
}
/* ---------- Legende: vier Abschnitte statt drei Zustände ----------
Die alte Legende erklärte den Zustand (erledigt / läuft / offen). Der
ist aus der Position ohnehin ablesbar. Wertvoller ist, WAS gerade
passiert — deshalb erklärt sie jetzt die vier Abschnitte. */
.po-legende { gap: .45rem .9rem; font-size: .76rem; }
.po-legende i { width: 14px; height: 7px; }
.po-legende .po-l-1 { background: var(--wd-p1); }
.po-legende .po-l-2 { background: var(--wd-p2); }
.po-legende .po-l-3 { background: var(--wd-p3); }
.po-legende .po-l-4 { background: var(--wd-p4); }
/* =====================================================================
PORTAL — AUFGABENLISTE UND POSTFACH (22.08.2026)
"wenn sie drauf drücken sollen sie auch sehen was ich schon gemacht
habe von dem was im plan war."
Dieselben vier Prozessfarben wie auf der Ablaufseite, in der Vorschau
und in der Verwaltung. Das ist der eigentliche Wert: Eine Farbe
bedeutet im ganzen Bereich dasselbe — sonst wäre sie Dekoration.
===================================================================== */
/* Die grosse Zahl. "9 von 14 erledigt" ist greifbar, "64 %" ist eine
Rechnung, die niemand fühlt. */
.po-aufg-stand { margin: .9rem 0 .2rem; font-size: .92rem; color: var(--wd-text-soft); }
.po-aufg-stand b {
font-family: var(--font-head); font-weight: 800;
font-size: 1.7rem; color: var(--wd-text); margin-right: .3rem;
}
.po-fortschritt { display: flex; gap: 4px; height: 8px; margin-bottom: 1.2rem; }
.po-fs-teil { flex: 1; border-radius: 999px; background: rgba(255,255,255,.07); position: relative; overflow: hidden; }
.po-fs-teil > i { position: absolute; inset: 0 auto 0 0; border-radius: 999px; }
.po-fs-teil[data-k="start"] > i { background: var(--wd-p1); }
.po-fs-teil[data-k="gestaltung"] > i { background: var(--wd-p2); }
.po-fs-teil[data-k="umsetzung"] > i { background: var(--wd-p3); }
.po-fs-teil[data-k="abschluss"] > i { background: var(--wd-p4); }
/* ---------- "Das brauche ich noch von dir" ----------
Ein EIGENER Kasten ganz oben, nicht nur eine farbige Zeile irgendwo
in der Liste. Wer eine lange Liste sieht, liest sie als Bericht über
fremde Arbeit und überliest seinen eigenen Teil — und genau daraus
entstehen die meisten Verzögerungen.
Gold, weil es im ganzen Bereich für "das betrifft dich" steht. Nicht
Rot: Es ist eine Bitte, kein Fehler. */
.po-dubist {
margin: 0 0 1.3rem;
padding: .9rem 1rem 1rem;
border-radius: 14px;
background: rgb(var(--wd-gold-rgb) / .07);
border: 1px solid rgb(var(--wd-gold-rgb) / .32);
}
.po-dubist h4 {
margin: 0; font-size: 1rem; color: var(--wd-gold);
font-family: var(--font-head); font-weight: 700;
}
/* Der beruhigende Gegenpart. Wenn nichts offen ist, soll das auch
dastehen — Abwesenheit einer Aufforderung ist eine gute Nachricht und
darf ruhig ausgesprochen werden. */
.po-allesgut {
margin: 0 0 1.3rem; padding: .75rem .95rem;
border-radius: 10px; font-size: .9rem;
background: rgb(var(--wd-ok-rgb) / .08);
border: 1px solid rgb(var(--wd-ok-rgb) / .28);
color: var(--wd-ok);
}
/* ---------- Gruppen und Zeilen ---------- */
.po-aufg-gruppe { margin-bottom: 1.1rem; }
.po-aufg-kopf {
display: flex; align-items: baseline; gap: .5rem;
font-size: 0.8rem; letter-spacing: .13em; text-transform: uppercase;
margin-bottom: .45rem; padding-bottom: .35rem;
border-bottom: 1px solid var(--wd-rand);
}
.po-aufg-zahl { margin-left: auto; letter-spacing: 0; text-transform: none; font-size: .8rem; color: var(--wd-text-soft); }
.po-aufg-gruppe[data-k="start"] .po-aufg-kopf { color: var(--wd-p1); }
.po-aufg-gruppe[data-k="gestaltung"] .po-aufg-kopf { color: var(--wd-p2); }
.po-aufg-gruppe[data-k="umsetzung"] .po-aufg-kopf { color: var(--wd-p3); }
.po-aufg-gruppe[data-k="abschluss"] .po-aufg-kopf { color: var(--wd-p4); }
/* Zeile und Spalte ausdrücklich für JEDES Kind.
Ohne Spaltenangabe geht es schief, und zwar auf eine Art, die man
nicht errät: Das Raster platziert zuerst alle Elemente mit
FESTGELEGTER Zeile und erst danach die freien. Kästchen und Marke
haben beide eine feste Zeile — sie würden zusammen nach vorne rutschen
und der Titel landete ganz rechts. Genau das ist am 22.08.2026 in der
Verwaltung passiert und erst am Screenshot aufgefallen. */
.po-aufg {
display: grid;
grid-template-columns: auto minmax(0,1fr) auto;
gap: .12rem .7rem; align-items: start;
padding: .55rem .6rem; margin-bottom: .25rem;
border-radius: 10px; border: 1px solid transparent;
}
.po-aufg-haken { grid-row: 1 / span 2; grid-column: 1; }
.po-aufg-titel { grid-row: 1; grid-column: 2; font-size: .94rem; color: var(--wd-text); overflow-wrap: anywhere; }
.po-aufg-marken { grid-row: 1; grid-column: 3; }
.po-aufg-text { grid-row: 2; grid-column: 2 / span 2; font-size: .82rem; color: var(--wd-text-soft); line-height: 1.5; }
.po-aufg--fertig .po-aufg-titel { color: var(--wd-text-soft); text-decoration: line-through; text-decoration-thickness: 1px; }
.po-aufg--weg .po-aufg-titel { color: var(--wd-text-soft); text-decoration: line-through; opacity: .55; }
.po-aufg--du { background: rgb(var(--wd-gold-rgb) / .06); }
/* Im oberen Kasten stehen dieselben Punkte noch einmal. Dort brauchen
sie den eigenen Hintergrund nicht — der Kasten ist schon golden, ein
zweiter Goldton darin würde nur schmutzig wirken. */
.po-aufg--hervor { background: transparent; padding-left: 0; padding-right: 0; }
/* Das Kästchen. Bei eigenen Punkten ein echter Knopf (tastaturbedienbar,
44px Trefferfläche über das Innenabstands-Polster), sonst nur Anzeige.
Ein Knopf, der nichts tut, lässt die Seite kaputt wirken. */
.po-aufg-haken {
width: 26px; height: 26px; margin-top: .05rem; padding: 0;
border-radius: 10px; border: 2px solid var(--wd-rand-stark);
background: transparent; color: transparent;
display: grid; place-items: center;
font-size: .95rem; line-height: 1;
transition: all var(--wd-zeit-schnell) ease;
}
button.po-aufg-haken { cursor: pointer; }
button.po-aufg-haken:hover { border-color: var(--wd-gold); background: rgb(var(--wd-gold-rgb) / .1); }
.po-aufg-haken--fest { cursor: default; }
.po-aufg--fertig .po-aufg-haken { background: var(--wd-ok); border-color: var(--wd-ok); color: var(--wd-schwarz); }
.po-aufg--jetzt .po-aufg-haken { border-color: var(--wd-p2); color: var(--wd-p2); }
.po-aufg--weg .po-aufg-haken { border-style: dashed; color: var(--wd-text-soft); }
/* Offene EIGENE Punkte: der Rand ist golden, damit klar ist, dass hier
geklickt werden kann und soll. */
.po-aufg--du button.po-aufg-haken { border-color: rgb(var(--wd-gold-rgb) / .55); }
.po-aufg-marke {
display: inline-block; white-space: nowrap;
font-size: 0.75rem; letter-spacing: .05em; text-transform: uppercase;
padding: .14rem .45rem; border-radius: 999px;
}
.po-aufg-marke--ok { background: rgb(var(--wd-ok-rgb) / .13); color: var(--wd-ok); }
.po-aufg-marke--jetzt { background: rgb(var(--wd-lila-rgb) / .15); color: var(--wd-p2); }
.po-aufg-marke--du { background: rgb(var(--wd-gold-rgb) / .16); color: var(--wd-gold); }
.po-aufg-nicht {
display: inline-block; margin-left: .4rem;
font-size: 0.75rem; letter-spacing: .05em; text-transform: uppercase;
padding: .12rem .4rem; border-radius: 999px;
background: rgb(var(--wd-fehler-rgb) / .12); color: var(--wd-fehler);
}
/* Auf dem Handy rutscht die Marke unter den Titel — nebeneinander bliebe
für den Titel eine Spalte von zwei Wörtern Breite. */
@media (max-width: 520px) {
.po-aufg { grid-template-columns: auto minmax(0,1fr); }
.po-aufg-marken { grid-row: 2; grid-column: 2; margin-bottom: .15rem; }
.po-aufg-text { grid-row: 3; grid-column: 2; }
}
/* ---------- Postfach auf der Übersicht ---------- */
.po-pf-verlauf {
max-height: 46vh; overflow-y: auto;
margin: .8rem 0 .2rem; padding-right: .3rem;
display: flex; flex-direction: column; gap: .5rem;
}
/* =====================================================================
WIDERRUF (§ 356a BGB) — und die Druckansicht der Bestätigung
Gestalterisch bewusst ZURÜCKHALTEND. Alles andere im Bereich darf
Stimmung machen; diese Seite nicht. Wer hier landet, will eine Sache
erledigen und danach Gewissheit haben. Grosse Effekte würden hier wie
Ablenkung wirken — und der Vorwurf, man wolle den Widerruf erschweren,
ist genau der, den man am wenigsten gebrauchen kann.
===================================================================== */
.wr-h2 { font-size: 1.12rem; margin: 0 0 .5rem; }
.wr-info {
border-left: 3px solid var(--wd-blau);
margin-bottom: 1.4rem;
}
.wr-pruef {
display: grid; grid-template-columns: minmax(0,.42fr) minmax(0,1fr);
gap: .45rem .9rem; margin: .9rem 0 1.1rem;
padding: .9rem 1rem; border-radius: 10px;
background: rgb(var(--wd-blau-rgb) / .05); border: 1px solid var(--wd-rand);
}
@media (max-width: 520px) { .wr-pruef { grid-template-columns: 1fr; gap: .1rem; } }
.wr-pruef dt { color: var(--wd-text-soft); font-size: .88rem; }
.wr-pruef dd { margin: 0; color: var(--wd-text); overflow-wrap: anywhere; white-space: pre-wrap; }
@media (max-width: 520px) { .wr-pruef dd { margin-bottom: .55rem; } }
/* Der Bestätigungsschritt hebt sich ab — hier passiert das Verbindliche. */
.wr-bestaetigen { border-color: var(--wd-rand-stark); }
/* Grün statt Gold für den Abschluss: Der Widerruf ist erfolgreich
erklärt, das ist aus Sicht des Kunden eine gute Nachricht. Gold ist im
Bereich für "das betrifft dich, tu was" reserviert — hier ist nichts
mehr zu tun. */
.wr-fertig { border-color: rgb(var(--wd-ok-rgb) / .42); }
.wr-haken {
width: 46px; height: 46px; border-radius: 50%;
display: grid; place-items: center; line-height: 1;
font-size: 1.5rem; margin-bottom: .7rem;
background: rgb(var(--wd-ok-rgb) / .14); color: var(--wd-ok);
border: 1px solid rgb(var(--wd-ok-rgb) / .4);
}
.wr-beleg {
margin: 1rem 0; padding: 1.1rem 1.2rem;
border-radius: 14px;
background: rgba(8,14,24,.55);
border: 1px solid var(--wd-rand-stark);
}
.wr-beleg-kopf {
display: flex; flex-wrap: wrap; gap: .5rem; align-items: baseline;
justify-content: space-between;
padding-bottom: .6rem; margin-bottom: .7rem;
border-bottom: 1px solid var(--wd-rand);
}
.wr-beleg-nr { font-family: var(--font-head); font-weight: 800; color: var(--wd-blau); }
.wr-beleg dl {
display: grid; grid-template-columns: minmax(0,.42fr) minmax(0,1fr);
gap: .45rem .9rem; margin: 0;
}
@media (max-width: 520px) { .wr-beleg dl { grid-template-columns: 1fr; gap: .1rem; } }
.wr-beleg dt { color: var(--wd-text-soft); font-size: .86rem; }
.wr-beleg dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 520px) { .wr-beleg dd { margin-bottom: .55rem; } }
/* ---------------------------------------------------------------------
DRUCKANSICHT
Die Eingangsbestätigung ist ein Rechtsnachweis. Ein Ausdruck mit
dunklem Hintergrund verbraucht eine halbe Patrone und ist auf Papier
schlecht lesbar — und ein Nachweis, den niemand ausdruckt, weil er
hässlich wird, erfüllt seinen Zweck nicht.
Deshalb: auf Papier schwarz auf weiss, ohne Navigation, ohne Knöpfe,
nur der Beleg. Adressen werden ausgeschrieben, weil ein Link auf
Papier nichts nützt.
--------------------------------------------------------------------- */
@media print {
body.wd { background: #fff !important; color: #000 !important; }
.wd-kopf, #wd-kopf, .wd-fuss, #wd-fuss,
.wr-nicht-drucken, .wr-info, #wr-form, #wr-schritt2,
.wd-meldung, .wd-eyebrow { display: none !important; }
.wd-abschnitt { padding: 0 !important; }
.wd-karte, .wr-beleg {
background: #fff !important; border: 1px solid #000 !important;
box-shadow: none !important; color: #000 !important;
}
.wr-fertig, .wr-beleg { page-break-inside: avoid; }
.wr-haken { border-color: #000 !important; color: #000 !important; background: #fff !important; }
.wr-beleg-nr, .wr-h2, h1, h2, dt, dd, p { color: #000 !important; }
.wr-beleg dt { color: #444 !important; }
/* Adressen ausschreiben — ein Link ist auf Papier wertlos. */
a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .85em; }
}
/* ---------------------------------------------------------------------
RECHTSSEITE
Lange Texte, die man liest statt überfliegt. Deshalb: schmalere
Zeilen, mehr Zeilenabstand, klare Absätze. Und KEIN Blocksatz --
der reisst im Deutschen wegen der langen Wörter Löcher in die Zeile
und macht genau die Texte schwerer lesbar, bei denen es auf jedes
Wort ankommt.
--------------------------------------------------------------------- */
.rl-nav {
display: flex; flex-wrap: wrap; gap: .45rem;
margin: 1.2rem 0 1.6rem;
}
.rl-nav a {
/* inline-flex + min-height 44px statt nur Innenabstand.
Mit reinem padding kamen die vier Sprungmarken auf 39px -- fuenf
Pixel unter dem Daumenmass. Genau derselbe Fall wie frueher bei
.wd-nav a (dort waren es 43px): Ein Innenabstand, der auf dem
Bildschirm gut aussieht, ergibt nicht automatisch ein treffbares
Ziel. Und ausgerechnet auf der Rechtsseite muss man verlaesslich
zum Widerrufsrecht springen koennen. */
display: inline-flex; align-items: center; min-height: 44px;
padding: .42rem .95rem; border-radius: 999px;
border: 1px solid var(--wd-rand); background: var(--wd-glas);
font-size: .88rem; color: var(--wd-text-mid) !important; text-decoration: none;
}
.rl-nav a:hover { border-color: var(--wd-rand-stark); color: var(--wd-text) !important; }
.rl-sprache { margin-bottom: 1.8rem; }
.rl-h2 {
margin-top: 2.4rem;
/* Ein Sprungziel darf nicht unter der klebenden Kopfzeile landen. */
scroll-margin-top: 5.5rem;
}
.rl-text { line-height: 1.75; }
.rl-text h3 {
font-size: 1rem; margin: 1.5rem 0 .5rem;
color: var(--wd-blau);
}
.rl-text h3:first-child { margin-top: 0; }
.rl-text p { margin: 0 0 .8rem; }
.rl-text ul { margin: 0 0 .9rem; padding-left: 1.2rem; }
.rl-text li { margin-bottom: .35rem; }
.rl-text code {
/* min() statt eines reinen em-Werts: In einem ohnehin kleineren Absatz
rutschte der Code sonst auf 11,2px -- unter die Lesbarkeitsgrenze. */
font-size: max(.78rem, .86em); padding: .1rem .35rem; border-radius: 6px;
background: rgb(var(--wd-blau-rgb) / .09); color: var(--wd-blau);
}
/* Die Belehrung hebt sich ab: Sie ist der Teil, auf den es rechtlich
ankommt, und muss auch optisch als geschlossener Block erkennbar sein. */
.rl-widerruf { border-left: 3px solid var(--wd-gold); }
.rl-adresse {
padding: .7rem .9rem; border-radius: 10px;
background: rgb(var(--wd-blau-rgb) / .05); border: 1px solid var(--wd-rand);
}
/* Das Muster-Formular sieht bewusst wie ein Formular aus — man soll
sehen, dass man es ausdrucken und ausfüllen kann. */
.rl-formular {
margin-top: .6rem; padding: 1rem 1.1rem;
border-radius: 10px; border: 1px dashed var(--wd-rand-stark);
background: rgba(8,14,24,.4);
font-size: .93rem;
}
.rl-formular p { margin: 0 0 .6rem; }
/* =====================================================================
FEINSCHLIFF — das Höhensystem (23.08.2026)
Bis hierher trug jede Karte EINEN Schatten: 0 24px 60px -28px. Das ist
solide, aber es ist auch der Grund, warum eine Oberfläche "ordentlich"
statt "teuer" wirkt.
Echtes Licht erzeugt zwei Dinge gleichzeitig:
1. einen engen, dunklen Kontaktschatten direkt an der Kante — er
sagt dem Auge, dass ein Gegenstand AUFLIEGT
2. einen weiten, weichen Umgebungsschatten — er sagt, wie HOCH er
darüber schwebt
Nur einen von beiden zu setzen, sieht aus wie ein Aufkleber. Beide
zusammen ergeben einen Gegenstand.
Dazu kommt die LICHTKANTE: eine 1 Pixel hohe, sehr schwache weisse
Linie an der Oberkante (inset 0 1px 0). Sie tut so, als käme das Licht
von oben und bräche sich an der Kante. Das ist das meistübersehene
Detail in dunklen Oberflächen — und dasjenige, das den grössten
Unterschied macht. Ohne sie wirkt eine Karte wie ein Loch im
Hintergrund; mit ihr wie ein Stück Material.
Drei Stufen, mehr braucht es nicht:
1 ruhende Flächen (Karten, Felder)
2 hervorgehobene Flächen (aktive Karte, Knopf)
3 Schwebendes (Fenster, Menü)
===================================================================== */
:root {
/* Kontaktschatten + Umgebungsschatten + Lichtkante, in dieser
Reihenfolge — die Lichtkante zuletzt, damit sie über allem liegt. */
--wd-hoehe-1:
0 1px 2px rgba(0, 0, 0, .40),
0 10px 28px -12px rgba(0, 0, 0, .70),
inset 0 1px 0 rgba(255, 255, 255, .055);
--wd-hoehe-2:
0 2px 4px rgba(0, 0, 0, .45),
0 18px 44px -16px rgba(0, 0, 0, .80),
inset 0 1px 0 rgba(255, 255, 255, .075);
--wd-hoehe-3:
0 4px 8px rgba(0, 0, 0, .50),
0 40px 90px -30px rgba(0, 0, 0, .92),
inset 0 1px 0 rgba(255, 255, 255, .09);
/* Vertiefte Flächen — Eingabefelder liegen NICHT auf der Oberfläche,
sie sind hineingeschnitten. Derselbe Lichteinfall, nur umgekehrt:
oben dunkel (Schattenkante), unten hell. */
--wd-tiefe:
inset 0 1px 2px rgba(0, 0, 0, .35),
inset 0 -1px 0 rgba(255, 255, 255, .03);
}
/* ---------- Karten ---------- */
.wd-karte {
box-shadow: var(--wd-hoehe-1);
/* Etwas schneller als der bisherige Standard: Bei Flächen, die man
überfährt, wirkt alles über 200 ms träge. */
transition:
transform .18s cubic-bezier(.2, .8, .3, 1),
box-shadow .18s cubic-bezier(.2, .8, .3, 1),
border-color .18s ease;
}
a.wd-karte:hover, .wd-karte--klickbar:hover {
transform: translateY(-3px);
box-shadow: var(--wd-hoehe-3), 0 0 40px -22px rgb(var(--wd-blau-rgb) / .5);
}
/* Beim Drücken zurück auf die Fläche — ohne das fehlt die Rückmeldung,
dass der Klick angekommen ist. */
a.wd-karte:active, .wd-karte--klickbar:active {
transform: translateY(-1px);
box-shadow: var(--wd-hoehe-1);
transition-duration: .06s;
}
/* ---------- Knöpfe ---------- */
.wd-btn {
transition:
transform .16s cubic-bezier(.2, .8, .3, 1),
box-shadow .16s cubic-bezier(.2, .8, .3, 1),
background .16s ease, border-color .16s ease, color .16s ease;
}
/* Der Hauptknopf ist hell auf dunklem Grund. Seine Lichtkante gehört
deshalb nach INNEN und heller — sie lässt die Fläche gewölbt wirken
statt flach aufgeklebt. */
/* ⚠️ Die Gewichtung muss zur Grundregel passen.
Weiter oben steht ".wd .wd-btn--haupt, .wd-btn--haupt { ... }" -- der
erste Teil zaehlt ZWEI Klassen. Ein blosses ".wd-btn--haupt" hier
unten zaehlt eine und verliert, obwohl es spaeter steht. Beim ersten
Versuch blieb der Hauptknopf deshalb ohne Lichtkante, waehrend die
Karten sie schon hatten -- gemessen, nicht vermutet.
Dieselbe Falle wie am 22.08.2026 bei ".wd a" gegen ".wd-btn--haupt".
Wer in dieser Datei etwas nachtraegt, muss die Gewichtung der
Grundregel uebernehmen, nicht nur die Reihenfolge. */
.wd .wd-btn--haupt, .wd-btn--haupt {
box-shadow:
0 1px 2px rgba(0, 0, 0, .35),
0 10px 26px -12px rgb(var(--wd-blau-rgb) / .55),
inset 0 1px 0 rgba(255, 255, 255, .45);
}
.wd .wd-btn--haupt:hover, .wd-btn--haupt:hover {
transform: translateY(-2px);
box-shadow:
0 2px 4px rgba(0, 0, 0, .4),
0 18px 40px -14px rgb(var(--wd-blau-rgb) / .8),
inset 0 1px 0 rgba(255, 255, 255, .55);
}
.wd .wd-btn--haupt:active, .wd-btn--haupt:active { transform: translateY(0); transition-duration: .06s; }
.wd-btn--zweit, .wd-btn--still {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.wd-btn--zweit:hover, .wd-btn--still:hover {
transform: translateY(-1px);
box-shadow:
0 6px 18px -10px rgba(0, 0, 0, .8),
inset 0 1px 0 rgba(255, 255, 255, .07);
}
/* ---------- Eingabefelder: vertieft statt aufliegend ---------- */
.wd-feld input[type="text"], .wd-feld input[type="email"], .wd-feld input[type="tel"],
.wd-feld input[type="url"], .wd-feld input[type="number"], .wd-feld input[type="date"],
.wd-feld input[type="password"], .wd-feld input[type="search"],
.wd-feld select, .wd-feld textarea, .wd-eingabe {
box-shadow: var(--wd-tiefe);
transition: border-color .16s ease, box-shadow .16s ease, background .16s ease;
}
/* Im Fokus bleibt die Vertiefung erhalten und der Ring kommt dazu —
sonst "springt" das Feld beim Anklicken aus der Fläche heraus. */
.wd-eingabe:focus, .wd-feld input:focus, .wd-feld select:focus, .wd-feld textarea:focus {
box-shadow: var(--wd-tiefe), 0 0 0 4px rgb(var(--wd-blau-rgb) / .16);
}
/* ---------- Marken und Abzeichen ---------- */
.wd-tag, .vw-status, .po-aufg-marke, .vw-aufg-wer, .vw-aufg-nicht {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
/* ---------- Schwebende Flächen ---------- */
.vw-detail-blatt { box-shadow: var(--wd-hoehe-3), 0 0 0 1px rgb(var(--wd-blau-rgb) / .06) inset; }
.wd-nav-panel, .wd-menue-flaeche { box-shadow: var(--wd-hoehe-3); }
/* ---------- Schrift: optische Korrektur ----------
Grosse Schriftgrade wirken bei gleicher Laufweite zu locker gesetzt —
das Auge sieht bei 48px mehr Weissraum zwischen den Buchstaben als bei
16px. Professioneller Satz zieht deshalb mit wachsender Größe enger.
Bei kleinen Grössen genau umgekehrt: dort hilft etwas mehr Luft. */
.wd h1 { letter-spacing: -.028em; }
.wd h2 { letter-spacing: -.021em; }
.wd h3 { letter-spacing: -.012em; }
/* Verhindert Schusterjungen in Überschriften — ein einzelnes Wort in der
letzten Zeile sieht immer nach Versehen aus. */
.wd h1, .wd h2, .wd-fuehrung { text-wrap: balance; }
.wd p { text-wrap: pretty; }
/* ---------- Ruhe bei Bewegungsempfindlichkeit ---------- */
@media (prefers-reduced-motion: reduce) {
.wd-karte, .wd-btn { transition: none !important; }
a.wd-karte:hover, .wd-karte--klickbar:hover,
.wd-btn:hover, .wd-btn--haupt:hover, .wd-btn--zweit:hover, .wd-btn--still:hover {
transform: none !important;
}
}
/* =====================================================================
LESEBREITE (23.08.2026)
Gemessen über alle Seiten: 105 von 200 Textabsätzen waren zu breit,
der schlimmste mit 151 Zeichen pro Zeile.
Warum das zählt: Beim Zeilensprung muss das Auge zurück an den
Zeilenanfang finden. Je länger die Zeile, desto häufiger landet es in
der falschen — man liest eine Zeile doppelt oder überspringt eine und
merkt es erst zwei Sätze später. Der Text ist dann nicht "schwer", er
ist schlecht gesetzt.
Bewährt sind 45 bis 75 Zeichen. Bücher, Zeitungen und jedes ordentlich
gesetzte Buch halten sich daran; es ist der älteste und bestbelegte
Grundsatz der Typografie überhaupt.
Die Einheit ist ch (Breite der Ziffer Null). Damit hängt die Breite an
der SCHRIFTGRÖSSE, nicht an Pixeln: Kleingedrucktes bekommt
automatisch einen schmaleren Block, große Schrift einen breiteren --
in beiden Fällen landet man bei ähnlich vielen Zeichen.
max-width macht nie etwas breiter. In schmalen Karten und Spalten
ändert sich also gar nichts -- die Regel greift nur dort, wo eine
Zeile wirklich über das Lesbare hinauswächst.
===================================================================== */
:root {
--wd-lesebreite: 68ch;
--wd-lesebreite-eng: 60ch; /* für Kleingedrucktes und Hinweise */
}
.wd p,
.wd li,
.wd .wd-fuehrung {
max-width: var(--wd-lesebreite);
}
/* Kleingedrucktes darf enger stehen: Es wird überflogen, nicht gelesen,
und ein schmaler Block ist dabei schneller zu erfassen. */
.wd .wd-klein,
.wd .wd-feld-hilfe,
.wd .rl-text .wd-klein {
max-width: var(--wd-lesebreite-eng);
}
/* Wo mittig gesetzt wird, muss auch der BLOCK mittig bleiben.
Ohne das klebt zentrierter Text nach der Begrenzung am linken Rand --
die Schrift wäre zentriert, ihr Kasten aber nicht. */
/* Zwei Faelle, beide noetig:
ELTERNELEMENT zentriert -> die Kinder mittig halten
ABSATZ SELBST zentriert -> ihn selbst mittig halten
Beim ersten Versuch fehlte der zweite Fall. Ergebnis: zwei Absaetze,
deren Schrift zentriert war, deren Kasten aber links klebte -- auf
anfrage.html mit 384 Pixeln Luft rechts und null links. Gefunden, weil
die Pruefung den Abstand links mit dem rechts VERGLEICHT, statt nur zu
zaehlen, ob zentriert ist. */
.wd :is(p, li)[style*="text-align:center"],
.wd :is(p, li)[style*="text-align: center"],
.wd [style*="text-align:center"] :is(p, li),
.wd [style*="text-align: center"] :is(p, li),
/* Alle Behaelter, die ihren Inhalt mittig setzen -- aus der zentralen
Stilvorlage UND aus den seiteneigenen <style>-Bloecken zusammengesucht.
Ein einzelner uebersehener Behaelter faellt sofort auf: Der Text steht
dann mittig, sein Kasten aber links. */
.wd .po-leer :is(p, li),
.wd .af-danke :is(p, li),
.wd .wd-cta-flaeche :is(p, li),
.wd .wd-intro :is(p, li),
.wd .zg-mitte :is(p, li),
.wd .vw-leer-gross :is(p, li),
.wd .wd-abschnitt--mitte :is(p, li),
.wd .wr-fertig > p,
.wd .vw-leer-hinweis {
margin-inline: auto;
}
/* AUSNAHMEN — hier wäre eine Begrenzung falsch:
Nachrichtenblasen tragen ihre Breite schon selbst (82 % der Spalte);
eine zweite Begrenzung würde sie im Gespräch unruhig springen lassen.
Tabellenzellen und Beschreibungslisten richten sich nach ihrer Spalte.
Eine eigene Breite darin bricht die Ausrichtung zur Nachbarspalte.
Die Fusszeile ist bewusst mehrspaltig und schon schmal. */
.wd .vw-blase p, .wd .po-nachricht p,
.wd td p, .wd th p,
.wd dd, .wd dd p,
.wd .wd-fuss p, .wd .wd-fuss li,
.wd .vw-paar dd, .wd .wr-pruef dd, .wd .wr-beleg dd {
max-width: none;
}
/* =====================================================================
KACHELN: LICHT UNTER DEM ZEIGER (23.08.2026)
Die Kacheln hatten Verlaufsrand, Verlaufsfläche, Schatten und
Lichtkante — alles richtig, alles statisch. Was fehlte, war das
Gefühl von MATERIAL: eine Oberfläche, die auf Licht reagiert.
Der Effekt: Ein weicher Lichtfleck folgt dem Zeiger über die Kachel.
Das ist kein Zierrat, sondern die Fortsetzung derselben Erzählung wie
bei der Lichtkante oben — es gibt eine Lichtquelle, und die Fläche
verhält sich, als wäre sie aus etwas.
VIER ENTSCHEIDUNGEN, DAMIT ES HOCHWERTIG UND NICHT BILLIG WIRKT
1. Sehr schwach. 13 % Deckkraft. Man soll es SPÜREN, nicht ANSEHEN.
Ein greller Fleck sieht nach Spielerei aus; ein kaum sichtbarer
nach teurem Material. Passt zugleich zur Dauervorgabe
"augenschonend" — nichts blitzt, nichts blendet.
2. Nur bei echtem Zeiger (hover: hover). Auf einem Handy gibt es
keinen Zeiger; dort bliebe ein Lichtfleck an einer zufälligen
Stelle kleben.
3. Die Farbe folgt der Kachel. Blaue Kacheln leuchten blau, lila
lila — sonst bräche der Effekt die Farbordnung, die überall sonst
Bedeutung trägt.
4. Aus bei prefers-reduced-motion. Auch wenn sich nichts bewegt:
Etwas, das dem Zeiger folgt, ist Bewegung.
===================================================================== */
@media (hover: hover) and (pointer: fine) {
.wd-karte {
/* Startwert oben mittig — falls die Kachel vor der ersten
Zeigerbewegung schon überfahren wird. */
--wd-lichtx: 50%;
--wd-lichty: 0%;
/* DIE LICHTFARBE STEHT JETZT AN DER KACHEL, NICHT IN DER REGEL.
Vorher war die Farbe im Lichtverlauf fest verdrahtet, und fuer
jede weitere Kachelfarbe brauchte es einen kompletten zweiten
Block -- einmal fuer die Flaeche, einmal fuer die leuchtende
Kante. Bei zwei Farben ging das gerade noch; das CRYONOVA-System
kennt sechs Lumen-Rollen (Baby, Aqua, Indigo, Violet, Gold,
Coral). Das waeren zwoelf fast gleiche Bloecke gewesen, die beim
naechsten Feinschliff zwangslaeufig auseinanderlaufen.
Jetzt setzt die Kachel nur noch ihre Farbe; der Verlauf wird
einmal beschrieben. Genau das meint das Design-System mit
"Kachelfarbe steuert Lumenfarbe" (Token-Regel 02). */
--wd-lumen: var(--wd-blau-rgb);
isolation: isolate;
}
/* Die sechs Lumen-Rollen aus dem System (Seite 9).
Mehr braucht es nicht -- jede weitere Farbe waere Dekoration und
wuerde die Bedeutung der bestehenden verwaessern. */
.wd-karte--lila { --wd-lumen: var(--wd-lila-rgb); }
.wd-karte--aqua { --wd-lumen: var(--wd-aqua-rgb); }
.wd-karte--premium { --wd-lumen: var(--wd-indigo-rgb); }
.wd-karte--vip { --wd-lumen: var(--wd-gold-rgb); }
.wd-karte--kritisch { --wd-lumen: var(--wd-fehler-rgb); }
.wd-karte::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
z-index: 0;
opacity: 0;
/* Ausblenden ruhiger als Einblenden -- das System nennt 120-180 ms
hinein und 240-360 ms hinaus (Seite 10). Der Unterschied ist der
Grund, warum sich Licht wie Licht anfuehlt und nicht wie ein
Schalter. */
transition: opacity .30s ease;
/* ZWEI Ebenen: oben der Glanzstreifen, darunter der Lichtkegel.
Der Glanz lag zuerst im ::before -- und hat damit die farbige
Oberkante geloescht, die dort schon wohnt (.wd-karte--kappe).
Sichtbar war das als "bei einer Kachel Farbe oben, bei den
anderen keine": Die Lila-Fassung hat eine Klasse mehr und damit
mehr Gewicht, ihre Farbe blieb; die blaue verschwand.
Ein Element hat nur zwei Pseudoelemente. Beide waren belegt, also
teilen sich Glanz und Lichtkegel jetzt eines -- als zwei
Hintergrundebenen desselben ::after. */
background:
linear-gradient(
calc(112deg + var(--wd-nx, 0) * 26deg),
transparent 34%,
rgb(255 255 255 / .07) 46%,
rgb(var(--wd-lumen) / .16) 50%,
rgb(255 255 255 / .07) 54%,
transparent 66%),
radial-gradient(
220px circle at var(--wd-lichtx) var(--wd-lichty),
rgb(var(--wd-lumen) / .28),
rgb(var(--wd-lumen) / .10) 40%,
transparent 70%
);
}
.wd-karte:hover::after {
opacity: 1;
transition-duration: .15s;
}
/* DER RAND LEUCHTET MIT — und das ist der Teil, der auffällt.
Die Kachel hat schon zwei Hintergrundebenen: die Fläche
(padding-box) und den Verlaufsrand (border-box). Der Rand ist nur
einen Pixel breit, aber genau dort lässt sich Licht am stärksten
zeigen, ohne dass es kitschig wird.
Beim Überfahren bekommt die Randebene einen Lichtpunkt an derselben
Stelle wie die Fläche. Ergebnis: Die Kante glüht dort auf, wo der
Zeiger steht, und verläuft nach beiden Seiten aus. Ein Lichtfleck
OHNE mitleuchtende Kante wirkt wie ein Fleck AUF der Kachel; mit ihr
wirkt die ganze Kachel beleuchtet.
Die Fläche bleibt unverändert — sonst würde der Text flackern. */
/* Auch die Kante folgt jetzt der Kachelfarbe -- eine Regel statt
einer je Farbe. Die Flaeche (padding-box) bleibt dabei
unveraendert; wuerde sie mitleuchten, flackerte der Text darauf. */
.wd-karte:hover {
background:
linear-gradient(180deg, rgb(12 39 64 / .78), rgb(6 19 35 / .90)) padding-box,
radial-gradient(240px circle at var(--wd-lichtx) var(--wd-lichty),
rgb(var(--wd-lumen) / .95),
rgb(var(--wd-lumen) / .30) 42%,
rgb(var(--wd-lumen) / .12) 100%) border-box;
}
/* Der Inhalt muss ÜBER dem Lichtfleck liegen.
Ohne das legt sich der absolut gesetzte Lichtfleck über den Text —
absolut positionierte Elemente malen über normalen Fluss-Inhalt,
auch wenn sie im Quelltext davor stehen. Das Ergebnis wäre ein
leichter Schleier auf der Schrift, den man erst bemerkt, wenn man
zwei Kacheln nebeneinander vergleicht. */
.wd-karte > * { position: relative; z-index: 1; }
/* Der Rand zieht mit. Ein Lichtfleck ohne mitleuchtende Kante wirkt
wie ein Fleck AUF der Kachel statt wie Licht darauf. */
.wd-karte { transition: border-color .28s ease, box-shadow .18s cubic-bezier(.2,.8,.3,1), transform .18s cubic-bezier(.2,.8,.3,1); }
}
@media (prefers-reduced-motion: reduce) {
.wd-karte::after { display: none; }
}
/* =====================================================================
HANDY UND INSTALLIERTE APP — Sicherheitsabstände
AUSGANGSLAGE (gefunden am 23.08.2026)
Die Seite trug bereits `apple-mobile-web-app-status-bar-style:
black-translucent`. Das heißt wörtlich: Der Seiteninhalt beginnt bei
y=0 und läuft UNTER Uhr, Empfangsbalken und Akkuanzeige durch. Auf
einem iPhone mit Aussparung stand die Kopfzeile also im installierten
Betrieb hinter der Statusleiste.
Gleichzeitig fehlte `viewport-fit=cover` auf allen dreizehn Seiten.
Ohne diese Angabe liefert jedes `env(safe-area-inset-*)` schlicht
null. Die eine Stelle, die den unteren Abstand bereits benutzte (der
Installations-Hinweis), war damit wirkungslos — sie sah richtig aus
und tat nichts. Genau die Sorte Fehler, die man nie bemerkt, weil der
Code stimmt.
LÖSUNG IN ZWEI TEILEN
1. `viewport-fit=cover` in jeder Seite (dort erledigt).
2. Die Abstände hier einmal zentral benennen, statt sie an fünfzehn
Stellen einzeln zu schreiben. Wer sie einzeln schreibt, vergisst
eine — und dann liegt genau ein Knopf unter der Gestenleiste.
WARUM `max()` UND NICHT NUR `env()`
Auf einem Gerät ohne Aussparung ist der Wert 0. Ein Kopfbereich mit
0 Abstand klebt aber am oberen Rand. `max(env(...), <Mindestwert>)`
gibt beiden Fällen ein brauchbares Ergebnis: Notch-Geräte bekommen
den echten Abstand, alle anderen den normalen.
===================================================================== */
:root {
--wd-sicher-oben: env(safe-area-inset-top, 0px);
--wd-sicher-unten: env(safe-area-inset-bottom, 0px);
--wd-sicher-links: env(safe-area-inset-left, 0px);
--wd-sicher-rechts: env(safe-area-inset-right, 0px);
}
/* Die Kopfzeile klebt oben (position: sticky). Im Browser sitzt sie
unter der Adressleiste und braucht nichts. Installiert gibt es keine
Adressleiste mehr — dann muss sie sich selbst unter die Statusleiste
schieben, sonst steht die Marke hinter der Uhr. */
.wd-kopf {
padding-top: var(--wd-sicher-oben);
}
/* Querformat: Bei gedrehtem Gerät liegt die Aussparung seitlich. Ohne
diesen Abstand verschwindet die linke Spalte halb darunter. `92vw`
allein hilft nicht — vw zählt die Aussparung mit. */
.wd-container,
.wd-container--schmal {
padding-left: var(--wd-sicher-links);
padding-right: var(--wd-sicher-rechts);
}
/* Unten die Gestenleiste. Betrifft den Fußbereich und alles, was fest
am unteren Rand sitzt. */
.wd-fuss {
padding-bottom: calc(1.5rem + var(--wd-sicher-unten));
}
@media (display-mode: standalone), (display-mode: window-controls-overlay), (display-mode: minimal-ui) {
/* ------------------------------------------------------------------
NUR IM INSTALLIERTEN BETRIEB
Installiert fehlt alles, was ein Browser sonst beisteuert: keine
Adressleiste, kein Zurück-Knopf, kein Neuladen durch Herunterziehen
im gewohnten Sinn. Was im Browser eine Kleinigkeit ist, wird hier
zum Fehler.
------------------------------------------------------------------ */
/* Das Gummiband-Nachfedern am Seitenende sieht in einer App nach
einem Darstellungsfehler aus -- im Browser erwartet man es, in
einer App nicht. Innerhalb scrollbarer Bereiche bleibt Scrollen
natürlich unverändert. */
html, body {
overscroll-behavior-y: none;
}
/* Der Hinweis "Als App installieren" ist installiert sinnlos. Er wird
zwar schon per JavaScript unterdrückt -- aber nur, wenn das Skript
lädt. Diese Regel greift auch dann, wenn es das nicht tut. */
.wd-install { display: none !important; }
}
/* ---------------------------------------------------------------------
TIPP-VERHALTEN
Auf Android legt der Browser über jede angetippte Fläche ein graues
Rechteck. Bei runden Kacheln und Knöpfen zeichnet es die eckige
Trefferfläche nach und sieht nach einem Fehler aus. Ersetzt wird es
nicht ersatzlos: Jeder Knopf hat einen sichtbaren :active-Zustand,
sonst fehlte die Rückmeldung, dass der Tipp angekommen ist.
--------------------------------------------------------------------- */
.wd a, .wd button, .wd [role="button"], .wd summary, .wd label {
-webkit-tap-highlight-color: transparent;
}
.wd .wd-btn:active,
.wd .vw-ub-kachel:active,
.wd .vw-ub-projekt:active,
.wd .vw-filter-knopf:active {
/* Kein Verschieben, nur ein kurzes Einsinken: Bewegung nach unten
wird als Druck gelesen und braucht keine Farbe. */
transform: scale(.985);
}
@media (prefers-reduced-motion: reduce) {
.wd .wd-btn:active,
.wd .vw-ub-kachel:active,
.wd .vw-ub-projekt:active,
.wd .vw-filter-knopf:active { transform: none; }
}
/* =====================================================================
CRYONOVA-BILDWELT (Design-System Seiten 24-29)
Das System nennt vier Referenzmotive und macht sie zur verbindlichen
Grundlage: "Die Website uebernimmt direkt die Bildsprache der PDF."
Verboten sind ausdruecklich einfache Verlaeufe und beliebige blaue
Flaechen als Ersatz.
WIE DIE MOTIVE VERTEILT SIND -- und warum so
Der Ring (ohne Logo) traegt die grossen Hintergrundflaechen. Die
beiden Motive MIT Logo sind bewusst KEIN Seitenhintergrund: Auf jeder
Seite steht oben bereits das echte Dogfather-Logo, und ein zweites,
grosses Logo im Hintergrund waere kein Luxus, sondern ein Fehler --
zwei Marken auf einem Bildschirm, die um dieselbe Aufmerksamkeit
ringen. Sie erscheinen deshalb dort, wo sie fuer sich stehen duerfen:
als Blickfang auf der Startseite und an der Zugangswand, jeweils ohne
Text darueber.
DREI SCHICHTEN UEBER JEDEM MOTIV
Ein Bild allein macht Text unlesbar -- das System fordert auf Seite 31
ausdruecklich, dass bei Bedarf "eine Navy- oder Frost-Glasflaeche
zwischen Bild und Inhalt" liegt. Deshalb liegt ueber jedem Motiv:
1. eine Navy-Faerbung, die das Bild in die Markenwelt zieht,
2. ein Verlauf nach unten, der die Textzone beruhigt,
3. der Inhalt selbst.
LADEZEIT
Zwei Groessen je Motiv. Das Handy laedt 33 KB statt 110 KB -- das
System nennt fuer Mobile ausdruecklich "Textkontrast und Ladezeit
priorisieren" (Seite 24).
===================================================================== */
.wd-motiv {
position: relative;
isolation: isolate;
}
/* Das Motiv selbst liegt in einer eigenen Ebene HINTER allem.
Bewusst ein Pseudo-Element und kein <img>: So kann kein Inhalt
versehentlich darunter geraten, und der Browser laedt es als
Hintergrund mit niedrigerer Dringlichkeit als die Schrift. */
.wd-motiv::before {
content: "";
position: absolute;
inset: 0;
z-index: -2;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
/* Die Faerbung zieht das Motiv in die Markenwelt und nimmt ihm
zugleich die Leuchtkraft, die sonst mit dem Text konkurriert. */
opacity: .55;
}
/* Die Glasflaeche zwischen Bild und Inhalt.
Ohne sie waere Text auf den hellen Kristallspitzen der Motive nicht
sicher lesbar -- und genau das ist die Stelle, an der ein schoenes
Bild eine Seite unbrauchbar macht. Der Verlauf ist unten dichter,
weil dort in aller Regel der Fliesstext steht. */
.wd-motiv::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
background:
linear-gradient(180deg,
rgb(3 8 16 / .55) 0%,
rgb(6 19 35 / .78) 55%,
rgb(3 8 16 / .94) 100%);
}
/* ---------- Die einzelnen Motive ---------- */
.wd-motiv--ring::before { background-image: url("/assets/img/cryo-ring.webp"); }
.wd-motiv--wappen::before { background-image: url("/assets/img/cryo-wappen.webp"); }
/* Der Monolith zeigt in der Bildmitte das Dogfather-Logo. Als
Seitenhintergrund waere das ein zweites Logo neben dem echten in der
Kopfzeile -- zwei Marken, die um dieselbe Aufmerksamkeit ringen.
Deshalb hier ein Ausschnitt der linken Bildhaelfte: dieselbe
Kristallwelt, dasselbe Licht, nur ohne das Wappen. */
.wd-motiv--monolith::before {
background-image: url("/assets/img/cryo-kristall.webp");
background-position: center left;
}
/* Auf dem Handy die kleinere Fassung. Die Abfrage steht NACH den
grossen Regeln, damit sie gewinnt. */
@media (max-width: 900px) {
.wd-motiv--ring::before { background-image: url("/assets/img/cryo-ring-klein.webp"); }
.wd-motiv--wappen::before { background-image: url("/assets/img/cryo-wappen-klein.webp"); }
.wd-motiv--monolith::before { background-image: url("/assets/img/cryo-kristall-klein.webp"); }
/* Motiv staerker beschneiden und Text weiter beruhigen -- auf einem
schmalen Schirm bleibt vom Bild ohnehin nur ein Ausschnitt, und
Lesbarkeit geht vor Wirkung (System Seite 24). */
.wd-motiv::before { opacity: .42; }
.wd-motiv::after {
background: linear-gradient(180deg,
rgb(3 8 16 / .68) 0%,
rgb(6 19 35 / .86) 50%,
rgb(3 8 16 / .96) 100%);
}
}
/* ---------- Blickfang-Motive (mit Logo, ohne Text darueber) ---------- */
/* Anders als die Hintergruende steht dieses Motiv fuer sich: volle
Leuchtkraft, kein Verlauf darueber, kein Text darin. Es ist ein Bild,
das man ansieht -- keine Flaeche, auf der etwas steht. */
.wd-blickfang {
position: relative;
display: block;
width: 100%;
border-radius: var(--wd-radius-l, 20px);
overflow: hidden;
border: 1px solid rgb(var(--wd-blau-rgb) / .30);
box-shadow:
0 30px 80px -40px rgb(0 0 0 / .9),
inset 0 1px 0 rgb(var(--wd-blau-rgb) / .18);
aspect-ratio: 1672 / 941;
background: center / cover no-repeat;
}
.wd-blickfang--wappen { background-image: url("/assets/img/cryo-wappen.webp"); }
.wd-blickfang--monolith { background-image: url("/assets/img/cryo-monolith.webp"); }
@media (max-width: 900px) {
.wd-blickfang--wappen { background-image: url("/assets/img/cryo-wappen-klein.webp"); }
.wd-blickfang--monolith { background-image: url("/assets/img/cryo-monolith-klein.webp"); }
}
/* Reduzierte Bewegung betrifft Bilder nicht -- sie bewegen sich nicht.
Der Vollstaendigkeit halber bleibt hier bewusst nichts abgeschaltet. */
/* =====================================================================
AKTIONEN MIT RANG (Design-System Seite 14)
Das System kennt sechs Rangstufen. Drei gab es bereits (Haupt,
Zweit, Still); hier kommen die drei dazu, die eine Aussage tragen,
welche die vorhandenen nicht abdecken koennen.
WARUM RANG UEBERHAUPT WICHTIG IST
Wenn jeder Knopf gleich laut ist, ist keiner mehr laut. Ein Nutzer
entscheidet in Sekundenbruchteilen, was der naechste Schritt ist --
und diese Entscheidung trifft er ueber Gewicht und Farbe, nicht
ueber den Text. Deshalb hat jede Stufe genau eine Bedeutung:
haupt die wichtigste Aktion auf dieser Seite -- nur EINE
zweit starke Alternative daneben
still Nebenaktion, tritt zurueck
premium bezahlte Erweiterung (Indigo)
vip Treuevorteil, extrem sparsam (Champagne)
gefahr kritisch und schwer umkehrbar (Signal Coral)
===================================================================== */
/* PREMIUM -- Indigo.
Indigo erreicht als Text keine 4,5:1 (gemessen 3,25-4,29 auf allen
Grundflaechen), deshalb steht es hier NICHT als Schriftfarbe, sondern
als Flaeche unter hellem Text. Genau so bleibt die Farbe erhalten und
die Lesbarkeit trotzdem sicher. */
.wd .wd-btn--premium, .wd-btn--premium {
background: linear-gradient(135deg,
rgb(var(--wd-indigo-rgb) / .92),
rgb(var(--wd-lila-rgb) / .88));
border-color: rgb(var(--wd-indigo-rgb) / .6);
color: var(--wd-text);
box-shadow: 0 12px 34px -16px rgb(var(--wd-indigo-rgb) / .9);
}
.wd-btn--premium:hover {
box-shadow: 0 16px 44px -14px rgb(var(--wd-indigo-rgb) / .95);
transform: translateY(-2px);
}
/* VIP -- Champagne.
Das System nennt Champagne "maximal sparsam" und verbietet
ausdruecklich die Mischung mit Violet (Seite 18). Deshalb hier ein
reiner Goldrahmen ohne zweite Akzentfarbe. */
.wd .wd-btn--vip, .wd-btn--vip {
background: rgb(var(--wd-gold-rgb) / .12);
border-color: rgb(var(--wd-gold-rgb) / .55);
color: var(--wd-gold);
}
.wd-btn--vip:hover {
background: rgb(var(--wd-gold-rgb) / .2);
border-color: var(--wd-gold);
}
/* GEFAHR -- Signal Coral.
Bewusst KEINE gefuellte Flaeche: Ein vollflaechig roter Knopf zieht
den Blick staerker an als die Hauptaktion und wird dadurch
versehentlich gedrueckt. Kritische Aktionen sollen auffindbar sein,
nicht verlockend. */
.wd .wd-btn--gefahr, .wd-btn--gefahr {
background: rgb(var(--wd-fehler-rgb) / .10);
border-color: rgb(var(--wd-fehler-rgb) / .5);
color: var(--wd-fehler);
}
.wd-btn--gefahr:hover {
background: rgb(var(--wd-fehler-rgb) / .18);
border-color: var(--wd-fehler);
}
/* Gesperrt: 42 % Deckkraft und kein aktives Lumen (Seite 14). */
.wd .wd-btn:disabled, .wd-btn[aria-disabled="true"] {
opacity: .42;
cursor: not-allowed;
transform: none !important;
box-shadow: none !important;
}
/* =====================================================================
FOKUS: doppelter Aqua-Ring (Seite 14 und 19)
Das System verlangt "Fokus: doppelter Aqua-Ring" und im Qualitaets-
tor "2 px Aqua plus sichtbarer Abstand".
Der doppelte Ring ist kein Schmuck: Ein einfacher heller Ring
verschwindet auf hellen Flaechen, ein einfacher dunkler auf dunklen.
Die Kombination aus dunklem Innenring und hellem Aussenring ist auf
JEDEM Untergrund sichtbar -- das ist der eigentliche Grund fuer die
Bauweise.
===================================================================== */
.wd :is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
outline: 2px solid rgb(var(--wd-aqua-rgb));
outline-offset: 2px;
}
/* Der dunkle Innenring trennt das Aqua von hellen Flaechen.
Eingabefelder sind hier BEWUSST ausgenommen: Sie sind selbst eine
dunkle, vertiefte Flaeche, das Aqua hebt sich davon ohnehin ab. Ein
Innenring waere nicht nur ueberfluessig, er ueberschreibt auch den
Ion-Schein, den das System auf Seite 15 fuer den Feldfokus verlangt.
Warum die Ausnahme im Selektor stehen muss und nicht einfach weiter
unten ueberschrieben wird: Diese Regel hat Spezifitaet 0,3,0
(Klasse + :is + :focus-visible), die Feldregel nur 0,2,1 -- und
Spezifitaet schlaegt Reihenfolge, egal wie weit unten sie steht. */
.wd :is(a, button, summary, [tabindex]):focus-visible {
box-shadow: 0 0 0 4px rgb(3 8 16 / .85);
}
/* =====================================================================
MATERIALIEN (Design-System Seite 7)
Die Farben werden zu Oberflaechen. Vier davon lassen sich mit CSS
ehrlich bauen; "Liquid Chrome" und "Champagne Pin" sind bewusst nur
Details und brauchen keine eigene Flaechenklasse.
===================================================================== */
/* OPTIC GLASS -- halbtransparent, klare Baby-Blue-Kante.
backdrop-filter nur, wo der Browser es kann; sonst bleibt die
Flaeche schlicht dunkel statt kaputt. */
.wd-glasflaeche {
background: rgb(var(--wd-glas-rgb) / .55);
border: 1px solid rgb(var(--wd-blau-rgb) / .28);
border-radius: var(--wd-radius-l, 20px);
}
@supports (backdrop-filter: blur(1px)) {
.wd-glasflaeche {
backdrop-filter: blur(14px) saturate(1.2);
background: rgb(var(--wd-glas-rgb) / .38);
}
}
/* FROSTED ICE -- helle, matte Flaeche fuer ruhige Inhalte.
Auf einer dunklen Seite heisst "hell" nicht weiss, sondern ein
aufgehelltes Navy. Echtes Weiss waere hier ein Loch im Bildschirm --
und das System verbietet weisse Vollflaechen ausdruecklich. */
.wd-frost {
background: linear-gradient(180deg,
rgb(var(--wd-blau-rgb) / .10),
rgb(var(--wd-blau-rgb) / .04));
border: 1px solid rgb(var(--wd-blau-rgb) / .20);
border-radius: var(--wd-radius-l, 20px);
}
/* PRISM EDGE -- duenne Kante von Ion zu Indigo, nur fuer
Premium-Momente. Zwei Hintergrundebenen: Flaeche und Rand. */
.wd-prisma {
border: 1px solid transparent;
background:
linear-gradient(var(--wd-flaeche), var(--wd-flaeche)) padding-box,
linear-gradient(135deg,
rgb(var(--wd-ion-rgb) / .9),
rgb(var(--wd-indigo-rgb) / .9)) border-box;
border-radius: var(--wd-radius-l, 20px);
}
/* VOID NAVY -- tiefe Flaeche fuer Navigation und ruhige Zonen. */
.wd-void { background: var(--wd-schwarz); }
/* =====================================================================
STATUS-SPEKTRUM (Design-System Seite 16)
Acht Zustaende. Die eiserne Regel steht auf derselben Seite:
"Jeder Status wird immer mit Text + Farbe + optionalem Symbol
dargestellt. Farbe allein reicht niemals."
Deshalb faerbt diese Klasse nur -- den TEXT liefert immer das
Markup. Es gibt hier bewusst keine Variante, die nur einen farbigen
Punkt zeigt: Wer Farben nicht unterscheiden kann, saehe dann gar
nichts.
===================================================================== */
.wd-status {
display: inline-flex;
align-items: center;
gap: .35rem;
padding: .18rem .6rem;
border-radius: 999px;
font-size: .78rem;
font-weight: 700;
border: 1px solid transparent;
white-space: nowrap;
}
.wd-status--neu { background: rgb(var(--wd-blau-rgb) / .14); color: var(--wd-blau); border-color: rgb(var(--wd-blau-rgb) / .35); }
.wd-status--arbeit { background: rgb(var(--wd-aqua-rgb) / .13); color: var(--wd-aqua); border-color: rgb(var(--wd-aqua-rgb) / .32); }
.wd-status--wartet { background: rgb(var(--wd-warn-rgb) / .14); color: var(--wd-warnung); border-color: rgb(var(--wd-warn-rgb) / .35); }
.wd-status--freigabe { background: rgb(var(--wd-lila-rgb) / .15); color: var(--wd-lila); border-color: rgb(var(--wd-lila-rgb) / .35); }
.wd-status--bezahlt { background: rgb(var(--wd-ok-rgb) / .13); color: var(--wd-ok); border-color: rgb(var(--wd-ok-rgb) / .32); }
.wd-status--kritisch { background: rgb(var(--wd-fehler-rgb) / .13); color: var(--wd-fehler); border-color: rgb(var(--wd-fehler-rgb) / .35); }
.wd-status--pausiert { background: rgb(var(--wd-chrome-rgb) / .12); color: var(--wd-chrome); border-color: rgb(var(--wd-chrome-rgb) / .30); }
.wd-status--vip { background: rgb(var(--wd-gold-rgb) / .13); color: var(--wd-gold); border-color: rgb(var(--wd-gold-rgb) / .35); }
/* =====================================================================
SIGNATURE-VERLAEUFE (Design-System Seite 18)
Vier Verlaeufe mit je einer klaren Aufgabe. Das System gibt dazu eine
Dosierungsregel, die wichtiger ist als die Verlaeufe selbst:
"Maximal ein Signature-Verlauf pro sichtbarer Bildschirmhoehe.
Keine Regenbogenflaechen. Kein Vollflaechen-Neon.
Champagne niemals mit Violet mischen."
Das letzte Verbot ist keine Geschmacksfrage: Champagne steht fuer
Treue und Bezahltes, Violet fuer Spezielles. Mischt man beides, kann
niemand mehr ablesen, was eine Flaeche bedeutet -- und genau die
Ablesbarkeit ist der Zweck eines Farbsystems.
Deshalb sind es HILFSKLASSEN und keine Vorgabe auf Kacheln: Ein
Verlauf, der automatisch auf jeder Karte laege, waere sofort eine
Regenbogenflaeche. Man setzt ihn bewusst an eine Stelle.
===================================================================== */
/* CRYO FLOW -- primaere Energie. Baby zu Ion zu Aqua. */
.wd-verlauf--cryo {
background: linear-gradient(135deg,
rgb(var(--wd-blau-rgb) / .95) 0%,
rgb(var(--wd-ion-rgb) / .90) 50%,
rgb(var(--wd-aqua-rgb) / .85) 100%);
}
/* PRISM SHIFT -- Premium und Fokus. Ion zu Indigo. */
.wd-verlauf--prisma {
background: linear-gradient(135deg,
rgb(var(--wd-ion-rgb) / .92) 0%,
rgb(var(--wd-indigo-rgb) / .92) 100%);
}
/* AURORA CUT -- Spezialmoment. Indigo zu Violet. */
.wd-verlauf--aurora {
background: linear-gradient(135deg,
rgb(var(--wd-indigo-rgb) / .90) 0%,
rgb(var(--wd-lila-rgb) / .90) 100%);
}
/* LIQUID VALUE -- VIP und Treue. Champagne allein, mit einer dunklen
Tiefe statt einer zweiten Akzentfarbe: Das System verbietet die
Mischung mit Violet ausdruecklich. */
.wd-verlauf--liquid {
background: linear-gradient(135deg,
rgb(var(--wd-gold-rgb) / .92) 0%,
rgb(var(--wd-gold-rgb) / .55) 55%,
rgb(var(--wd-dunkelblau-2)) 100%);
}
/* Text auf einem Signature-Verlauf braucht immer dunkle Schrift --
alle vier sind hell genug, dass helle Schrift darauf verschwindet. */
.wd-verlauf--cryo, .wd-verlauf--prisma,
.wd-verlauf--aurora, .wd-verlauf--liquid { color: var(--wd-schwarz); }
/* =====================================================================
FORMULARE UND TABELLEN (Design-System Seite 15)
"Fokus: Eingabefeld erhaelt Ion-Blue-Rand und sanften Glow.
Tabellenzeile erhaelt beim Hover ein sehr schwaches,
positionsabhaengiges Licht."
Das Wort "sehr schwach" ist hier die eigentliche Anweisung. Eine
Tabelle ist zum Lesen da: Wandert beim Ueberfahren ein kraeftiges
Licht mit, springt der Blick staendig zur Maus statt zur Zahl, die
man eigentlich sucht. Deshalb liegt die Deckkraft hier bei einem
Bruchteil dessen, was eine Kachel bekommt.
===================================================================== */
/* Der Fokus im Eingabefeld: Ion-Rand plus weicher Schein.
Die Vertiefung bleibt erhalten -- sonst springt das Feld beim
Anklicken optisch aus der Flaeche heraus. */
.wd-feld input:focus, .wd-feld select:focus, .wd-feld textarea:focus,
.wd-eingabe:focus {
border-color: rgb(var(--wd-ion-rgb) / .85);
box-shadow:
var(--wd-tiefe),
0 0 0 4px rgb(var(--wd-ion-rgb) / .16),
0 0 18px -4px rgb(var(--wd-ion-rgb) / .45);
}
/* Ein Feld mit Fehler traegt IMMER auch Text -- die Farbe allein
waere fuer niemanden lesbar, der sie nicht unterscheiden kann. */
.wd-feld--fehler input, .wd-feld--fehler select, .wd-feld--fehler textarea {
border-color: rgb(var(--wd-fehler-rgb) / .7);
}
.wd-feld--fehler input:focus, .wd-feld--fehler select:focus,
.wd-feld--fehler textarea:focus {
box-shadow:
var(--wd-tiefe),
0 0 0 4px rgb(var(--wd-fehler-rgb) / .18);
}
/* ---------- Tabellen ---------- */
.wd-tabelle {
width: 100%;
border-collapse: collapse;
font-size: .92rem;
}
.wd-tabelle th {
text-align: left;
font-size: .74rem;
font-weight: 800;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--wd-text-soft);
padding: .6rem .8rem;
border-bottom: 1px solid rgb(var(--wd-blau-rgb) / .22);
}
.wd-tabelle td {
padding: .7rem .8rem;
border-bottom: 1px solid rgb(255 255 255 / .05);
color: var(--wd-text-mid);
}
/* Zahlen in gleicher Ziffernbreite: Sonst stehen Betraege in einer
Spalte nicht untereinander, und man vergleicht sie falsch. */
.wd-tabelle td.wd-zahl, .wd-tabelle th.wd-zahl {
text-align: right;
font-variant-numeric: tabular-nums;
}
@media (hover: hover) and (pointer: fine) {
.wd-tabelle tbody tr {
--wd-lichtx: 50%;
position: relative;
transition: background-color .2s ease;
}
/* Das positionsabhaengige Licht der Zeile -- bewusst nur 7 %, ein
Viertel dessen, was eine Kachel bekommt. Es soll die Zeile
nachzeichnen, nicht den Blick fangen. */
.wd-tabelle tbody tr:hover {
background: linear-gradient(90deg,
transparent 0%,
rgb(var(--wd-blau-rgb) / .07) var(--wd-lichtx),
transparent 100%);
}
}
@media (prefers-reduced-motion: reduce) {
.wd-tabelle tbody tr:hover { background: rgb(var(--wd-blau-rgb) / .05); }
}
/* =====================================================================
KACHEL-ANATOMIE (Design-System Seite 11)
Das System beschreibt sechs Bestandteile: Material (Obsidian Glass
statt flacher Farbe), Kante (1 px Baby Blue, 24-36 % Deckkraft),
Lumen, Inhalt ueber dem Licht, Tiefe (zarter Schatten plus innere
Lichtkante) und Zustand.
Fuenf davon standen bereits. Was fehlte, ist die INNERE LICHTKANTE:
eine haarfeine helle Linie an der Oberkante. Sie ist der Unterschied
zwischen "dunkles Rechteck" und "Objekt aus Glas" -- Licht faellt von
oben, also faengt die obere Kante es ein. Ohne sie wirkt jede Kachel
flach, egal wie gut die Farben sind.
===================================================================== */
.wd-karte {
/* BEIDE Hintergrundebenen, nicht nur eine.
Die Kachel baut ihre Kante ueber einen zweiten Verlauf auf der
border-box -- der Rahmen selbst ist durchsichtig. Ein erster
Versuch setzte hier nur die Flaeche (padding-box) und liess die
Randebene damit ersatzlos wegfallen: Der Rand mass danach
rgba(0,0,0,0), also gar nichts. Sichtbar war das kaum, messbar
sofort -- und das System verlangt ausdruecklich eine Kante von
1 px Baby Blue mit 24-36 % Deckkraft (Seite 11). */
background:
linear-gradient(180deg,
rgb(var(--wd-glas-rgb) / .58),
rgb(6 19 35 / .72)) padding-box,
linear-gradient(140deg,
rgb(var(--wd-blau-rgb) / .36),
rgb(var(--wd-blau-rgb) / .10) 45%,
rgb(var(--wd-lila-rgb) / .26)) border-box;
/* Die innere Lichtkante: eine haarfeine helle Linie oben. Sie ist
der Unterschied zwischen "dunkles Rechteck" und "Objekt aus
Glas" -- Licht faellt von oben, also faengt die obere Kante es
ein. Ohne sie wirkt jede Kachel flach, egal wie gut die Farben
sind. */
box-shadow:
var(--wd-hoehe-1),
inset 0 1px 0 rgb(var(--wd-blau-rgb) / .16);
}