CRYONOVA Schritt 3: Feldfokus, Blickfaenge, Testkorrekturen

Der Feldfokus zeigt jetzt den Ion-Rand und den weichen Schein, den das
Design-System auf Seite 15 verlangt. Er fehlte, weil der allgemeine
Tastaturring seinen dunklen Innenring darueberlegte: Dessen Selektor hat
Spezifitaet 0,3,0, die Feldregel nur 0,2,1 -- und Spezifitaet schlaegt
Reihenfolge, egal wie weit unten die Regel steht. Eingabefelder sind
jetzt vom Innenring ausgenommen; sie brauchen ihn nicht, weil sie selbst
eine dunkle Flaeche sind. Der Aqua-Umriss bleibt fuer alle erhalten.

Die zwei Blickfang-Motive stehen jetzt auch wirklich auf einer Seite:
das Wappen auf "Ueber mich", direkt nach dem Absatz ueber die Herkunft
des Namens, der Monolith auf "Portfolio" zwischen Einleitung und den
echten Projekten. Beide als Zierbild ausgezeichnet -- ihre Aussage steht
schon im Text daneben. Auf dem Handy laedt automatisch die kleine
Fassung.

Vier Fehler steckten in der Pruefung selbst, nicht im Stilblatt:
- Sie griff das erste "input" der Anfrageseite. Das sind aber sechs
  optisch versteckte Auswahl-Radios, kein Textfeld.
- Sie mass ohne Fensterfokus. Ein Browser wendet :focus nur an, wenn das
  Fenster selbst den Fokus hat -- das DOM meldet trotzdem brav
  matches(":focus") === true, die Farbe bleibt die alte.
- Sie mass mitten im Uebergang, bevor die Animation stand.
- Und sie zaehlte Schattenebenen an "),", einem Muster, das in keinem
  Schattenwert je vorkommt. Geprueft wird jetzt die Anforderung selbst:
  Ion-Farbe und ein Weichzeichner ueber 0.

Geprueft: 334 Pruefungen gruen (CRYONOVA 53, Blickfang 13, Abmelden 16,
Angebot 54, Abbruch 42, System 5, Automatik 55, Angebote 56, Kette 40).

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-24 23:03:27 +02:00
co-authored by Claude Opus 5
parent 336e702d90
commit 99b5dd4eb2
23 changed files with 418 additions and 2 deletions
+118
View File
@@ -77,6 +77,14 @@ const hexZuRgb = (h) => [1, 3, 5].map((i) => parseInt(h.substr(i, 2), 16));
const browser = await chromium.launch();
const seite = await browser.newPage({ viewport: { width: 1440, height: 950 } });
/* Ohne das misst jede :focus-Pruefung den Ruhezustand. Ein Browser
wendet :focus nur an, wenn das FENSTER selbst den Fokus hat -- im
Testlauf hat es den nie. Das DOM meldet trotzdem brav
element.matches(":focus") === true, die Farbe bleibt aber die alte.
Genau diese Kombination hat hier zwei Fehlalarme erzeugt. */
const cdp = await seite.context().newCDPSession(seite);
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true });
await seite.goto("http://127.0.0.1:4372/webdesign/index.html");
await seite.waitForTimeout(500);
@@ -399,6 +407,116 @@ for (const b of bilder) {
pruefe("alle Motive sind vorhanden und unter 300 KB",
zuGross.length === 0, zuGross.join(", ") || "alle schlank");
console.log("\n=== 12. SIGNATURE-VERLAEUFE (Seite 18) ===");
await seite.goto("http://127.0.0.1:4372/webdesign/index.html");
await seite.waitForTimeout(400);
const verlaeufe = await seite.evaluate(() => {
const alle = Array.from(document.styleSheets)
.flatMap((b) => { try { return Array.from(b.cssRules); } catch { return []; } });
const text = alle.map((r) => r.cssText).join("\n");
const gefunden = ["cryo", "prisma", "aurora", "liquid"]
.filter((n) => text.includes(".wd-verlauf--" + n));
/* Champagne NIEMALS mit Violet mischen (Seite 18). Das ist keine
Geschmacksfrage: Champagne steht fuer Treue und Bezahltes, Violet
fuer Spezielles. Gemischt kann niemand mehr ablesen, was eine
Flaeche bedeutet -- und Ablesbarkeit ist der Zweck des Systems. */
const liquid = alle.find((r) => (r.selectorText || "").includes("wd-verlauf--liquid"));
const liquidText = liquid ? liquid.cssText : "";
return {
gefunden,
champagneRein: !/--wd-lila-rgb|--wd-indigo-rgb/.test(liquidText),
};
});
pruefe("alle vier Signature-Verlaeufe sind gebaut",
verlaeufe.gefunden.length === 4, verlaeufe.gefunden.join(", "));
pruefe("Liquid Value mischt Champagne NICHT mit Violet",
verlaeufe.champagneRein, "Verbot aus Seite 18 eingehalten");
console.log("\n=== 13. FORMULARE UND TABELLEN (Seite 15) ===");
await seite.goto("http://127.0.0.1:4372/webdesign/anfrage.html");
await seite.waitForTimeout(600);
/* Echter Klick statt evaluate-focus(), und danach warten: Der Rand hat
einen Uebergang. Sofort gemessen sieht man die Animation auf halbem
Weg -- Rand noch alt, Schein noch bei 0 0 0 0 und durchsichtig.
Der Selektor nennt ausdruecklich Texteingaben: Die Anfrageseite
beginnt mit sechs Auswahlkacheln, deren Radios optisch versteckt
sind. Ein blindes "erstes input" greift die statt des Feldes. */
await seite.locator('.wd-feld textarea, .wd-feld input[type="text"], .wd-eingabe')
.first().click();
await seite.waitForTimeout(700);
const feldFokus = await seite.evaluate(() => {
/* Nur ECHTE Texteingaben. Die Anfrageseite beginnt mit sechs
Auswahlkacheln, deren Radios optisch versteckt sind -- ein blindes
"erstes input" greift die und misst deren neutrales Weiss statt des
Ion-Randes. Genau das hat hier zweimal falschen Alarm ausgeloest. */
const f = document.activeElement;
if (!f || f === document.body) return null;
const st = getComputedStyle(f);
return { rand: st.borderColor, schatten: st.boxShadow };
});
/* Das System nennt ausdruecklich "Ion-Blue-Rand und sanften Glow". */
pruefe("das Eingabefeld bekommt im Fokus einen Ion-Rand",
feldFokus && /74,\s*200,\s*255/.test(feldFokus.rand), feldFokus && feldFokus.rand);
/* Geprueft wird die Anforderung selbst, nicht die Anzahl Kommas:
Der Schein muss in Ion-Blue leuchten und WEICH sein, also einen
Weichzeichner ueber 0 haben. Eine harte 0px-Kante waere ein Rahmen,
kein Schein. (Die frueher hier stehende Zaehlung trennte an "),"
-- das Muster kommt in keinem Schattenwert je vor, weil nach der
Farbe immer noch die Masse folgen.) */
const scheinIon = feldFokus && /74,\s*200,\s*255/.test(feldFokus.schatten);
const scheinWeich = feldFokus &&
[...feldFokus.schatten.matchAll(/74,\s*200,\s*255[^)]*\)((?:\s+-?\d+px){2,4})/g)]
.some((t) => parseFloat(t[1].trim().split(/\s+/)[2]) > 0);
pruefe("und einen weichen Schein dazu",
scheinIon && scheinWeich,
feldFokus && feldFokus.schatten.slice(0, 60));
const tabelle = await seite.evaluate(() => {
const alle = Array.from(document.styleSheets)
.flatMap((b) => { try { return Array.from(b.cssRules); } catch { return []; } })
.map((r) => r.cssText).join("\n");
/* "sehr schwaches, positionsabhaengiges Licht" -- die Betonung liegt
auf SCHWACH. Eine Tabelle ist zum Lesen da; ein kraeftiges
Wanderlicht zieht den Blick zur Maus statt zur Zahl. */
const m = alle.match(/wd-tabelle tbody tr:hover[^}]*rgb\(var\(--wd-blau-rgb\)\s*\/\s*\.(\d+)\)/);
return { gebaut: alle.includes(".wd-tabelle"), staerke: m ? Number("0." + m[1]) : null,
positionsabhaengig: /wd-tabelle tbody tr:hover[^}]*--wd-lichtx/.test(alle) };
});
pruefe("Tabellen sind gestaltet", tabelle.gebaut);
pruefe("das Zeilenlicht ist positionsabhaengig", tabelle.positionsabhaengig);
pruefe("und bleibt sehr schwach (unter 10 %)",
tabelle.staerke !== null && tabelle.staerke < 0.10,
tabelle.staerke !== null ? Math.round(tabelle.staerke * 100) + " %" : "nicht gefunden");
console.log("\n=== 14. KACHEL-ANATOMIE (Seite 11) ===");
await seite.goto("http://127.0.0.1:4372/webdesign/leistungen.html");
await seite.waitForTimeout(600);
const anatomie = await seite.evaluate(() => {
const k = document.querySelector(".wd-karte");
if (!k) return null;
const st = getComputedStyle(k);
return {
ebenen: (st.backgroundImage.match(/gradient/g) || []).length,
lichtkante: /inset/.test(st.boxShadow),
randbreite: st.borderWidth,
};
});
/* Die Kachel baut ihre Kante ueber eine ZWEITE Hintergrundebene auf der
border-box -- der Rahmen selbst ist durchsichtig. Wer beim Anpassen
nur die Flaeche setzt, laesst die Kante ersatzlos wegfallen: Genau
das ist beim Bauen passiert, der Rand mass danach rgba(0,0,0,0).
Sichtbar war es kaum, messbar sofort. */
pruefe("die Kachel hat zwei Hintergrundebenen (Flaeche UND Kante)",
anatomie && anatomie.ebenen >= 2, anatomie && anatomie.ebenen);
pruefe("sie hat eine innere Lichtkante", anatomie && anatomie.lichtkante);
pruefe("die Kante ist 1 px stark (System Seite 11)",
anatomie && anatomie.randbreite === "1px", anatomie && anatomie.randbreite);
await browser.close();
srv.close();
const f = ergebnisse.filter((e) => !e.ok).length;