diff --git a/assets/css/webdesign.css b/assets/css/webdesign.css
index 45e0861d..1eb29970 100644
--- a/assets/css/webdesign.css
+++ b/assets/css/webdesign.css
@@ -1756,3 +1756,169 @@ button.po-aufg-haken:hover { border-color: var(--wd-gold); background: rgb(var(-
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;
+ }
+}
diff --git a/pruef-aufgaben-computer.png b/pruef-aufgaben-computer.png
index 99e23776..fa4cb542 100644
Binary files a/pruef-aufgaben-computer.png and b/pruef-aufgaben-computer.png differ
diff --git a/pruef-aufgaben-handy.png b/pruef-aufgaben-handy.png
index d845441f..d3ee3d7f 100644
Binary files a/pruef-aufgaben-handy.png and b/pruef-aufgaben-handy.png differ
diff --git a/pruef-design.mjs b/pruef-design.mjs
index 22a3f20a..6abf34cd 100644
--- a/pruef-design.mjs
+++ b/pruef-design.mjs
@@ -38,7 +38,20 @@ const srv = createServer((q, r) => {
});
await new Promise((r) => srv.listen(4329, r));
-const SEITEN = readdirSync(join(W, "webdesign")).filter((f) => f.endsWith(".html"));
+/* diagnose.html ist bewusst ausgenommen.
+
+ Sie ist das Werkzeug fuer den Fall, dass die Seite NICHT laeuft, und
+ traegt deshalb alles fest in sich: eigene Farben, eigenes Layout,
+ keine externe CSS- oder JS-Datei, keine Uebersetzung. Genau das ist
+ ihr Zweck -- eine Diagnoseseite, die an derselben kaputten
+ Stilvorlage scheitert wie das Problem, das sie untersuchen soll,
+ waere wertlos.
+
+ Sie deshalb an den Regeln fuer die eigentliche Seite zu messen, wuerde
+ zwei Meldungen erzeugen, die man auf Dauer wegsieht -- und irgendwann
+ sieht man dann auch eine echte weg. */
+const SEITEN = readdirSync(join(W, "webdesign"))
+ .filter((f) => f.endsWith(".html") && f !== "diagnose.html");
const SPRACHEN = ["de", "de-CH", "en", "fr", "pt"];
const funde = [];
diff --git a/pruef-portal-aufgaben-computer.png b/pruef-portal-aufgaben-computer.png
index 93ebe0ea..81527584 100644
Binary files a/pruef-portal-aufgaben-computer.png and b/pruef-portal-aufgaben-computer.png differ
diff --git a/pruef-portal-aufgaben-handy.png b/pruef-portal-aufgaben-handy.png
index 9507de01..6ea88ba0 100644
Binary files a/pruef-portal-aufgaben-handy.png and b/pruef-portal-aufgaben-handy.png differ
diff --git a/pruef-portal-postfach-computer.png b/pruef-portal-postfach-computer.png
index 2045276d..ff52f626 100644
Binary files a/pruef-portal-postfach-computer.png and b/pruef-portal-postfach-computer.png differ
diff --git a/pruef-portal-postfach-handy.png b/pruef-portal-postfach-handy.png
index 1a5a42e5..ff9f5c60 100644
Binary files a/pruef-portal-postfach-handy.png and b/pruef-portal-postfach-handy.png differ
diff --git a/pruef-postfach-computer.png b/pruef-postfach-computer.png
index 8def97bf..bb7d45a4 100644
Binary files a/pruef-postfach-computer.png and b/pruef-postfach-computer.png differ
diff --git a/pruef-postfach-handy.png b/pruef-postfach-handy.png
index 01af6c54..555e9e1f 100644
Binary files a/pruef-postfach-handy.png and b/pruef-postfach-handy.png differ
diff --git a/pruef-system.mjs b/pruef-system.mjs
index a41bcb70..b7cad3ca 100644
--- a/pruef-system.mjs
+++ b/pruef-system.mjs
@@ -43,7 +43,20 @@ const srv = createServer((q, r) => {
});
await new Promise((r) => srv.listen(4332, r));
-const SEITEN = readdirSync(join(W, "webdesign")).filter((f) => f.endsWith(".html"));
+/* diagnose.html ist bewusst ausgenommen.
+
+ Sie ist das Werkzeug fuer den Fall, dass die Seite NICHT laeuft, und
+ traegt deshalb alles fest in sich: eigene Farben, eigenes Layout,
+ keine externe CSS- oder JS-Datei, keine Uebersetzung. Genau das ist
+ ihr Zweck -- eine Diagnoseseite, die an derselben kaputten
+ Stilvorlage scheitert wie das Problem, das sie untersuchen soll,
+ waere wertlos.
+
+ Sie deshalb an den Regeln fuer die eigentliche Seite zu messen, wuerde
+ zwei Meldungen erzeugen, die man auf Dauer wegsieht -- und irgendwann
+ sieht man dann auch eine echte weg. */
+const SEITEN = readdirSync(join(W, "webdesign"))
+ .filter((f) => f.endsWith(".html") && f !== "diagnose.html");
const ALT = "127, 208, 232"; // der bisherige Markenton
const NEU = "255 120 40"; // drastisch anders, damit nichts untergeht
diff --git a/webdesign/ablauf.html b/webdesign/ablauf.html
index 040bc9be..ec1c3a3e 100644
--- a/webdesign/ablauf.html
+++ b/webdesign/ablauf.html
@@ -13,8 +13,8 @@
-
-
+
+