diff --git a/server/pruef-formulare.mjs b/server/pruef-formulare.mjs
index a7bade63..959986bf 100644
--- a/server/pruef-formulare.mjs
+++ b/server/pruef-formulare.mjs
@@ -310,6 +310,181 @@ console.log("\n=== Kein Feld ohne Gestaltung");
await kontext.close();
}
+/* =====================================================================
+ WAS AUFKLAPPT, MUSS AUCH PLATZ BEKOMMEN (22.09.2026)
+ =====================================================================
+ Filipe zum Bildschirmfoto: „wie scheisse sieht das aus, verbesser das
+ bitte." Zu sehen war das Aufgaben-Formular: „Anlegen" und
+ „Abbrechen" lagen mitten in der Personenliste.
+
+ WARUM DIE PRUEFUNG DARUEBER DAS NICHT FINDEN KONNTE: Sie oeffnet das
+ Formular und misst die Felder -- im zugeklappten Zustand. Der Fehler
+ entsteht erst beim AUFKLAPPEN. Ein Zustand, der nie hergestellt
+ wird, kann nicht gemessen werden; die Pruefung war gruen und hat
+ dabei nie hingesehen.
+
+ Gemessen war es dann eindeutig, bei 1280 px:
+
+ Zelle Zeilen Hoehe Inhalt
+ feld-verant 24px 44px 68 107
+ feld-mehrere 43px 44px 87 261 <-- 174 zu viel
+
+ Die Zelle steckte in einer festen 44-Pixel-Zeile. Was herauslaeuft,
+ belegt keinen Platz -- also legt es sich ueber das Naechste.
+
+ HIER WIRD NICHT DIESE EINE STELLE GEPRUEFT, sondern die Eigenschaft:
+ Jedes Element mit `aria-expanded` im Formular wird aufgeklappt, und
+ danach darf keine Rasterzelle mehr Inhalt haben, als sie hoch ist.
+ Damit faellt auch die naechste auf, die es noch gar nicht gibt.
+ ===================================================================== */
+console.log("\n=== Was aufklappt, bekommt auch Platz");
+{
+ const kontext = await browser.newContext({ viewport: { width: 1280, height: 1000 } });
+ const seite = await kontext.newPage();
+ await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
+ await seite.click('.rolle[data-rolle="admin"]');
+ await seite.fill("#code", "CODE-DOGI-0001");
+ await seite.click("button[type=submit]");
+ await seite.waitForTimeout(900);
+
+ let zellenGesamt = 0, aufgeklapptGesamt = 0;
+ const schlimm = [];
+
+ for (const [wohin, knopf] of FORMULARE) {
+ await seite.goto(`${BASIS}/workspace/${wohin}`, { waitUntil: "networkidle" });
+ await seite.waitForTimeout(900);
+ const auf = await seite.$(knopf);
+ if (!auf) continue;
+ await auf.click().catch(() => {});
+ await seite.waitForTimeout(700);
+
+ /* ALLES AUFKLAPPEN, was sich aufklappen laesst. */
+ const wieViele = await seite.evaluate(() => {
+ const f = document.querySelector(".neu__raster");
+ if (!f) return 0;
+ const knoepfe = [...f.querySelectorAll("[aria-expanded]")]
+ .filter((b) => b.offsetParent !== null);
+ for (const b of knoepfe) b.click();
+ return knoepfe.length;
+ });
+ await seite.waitForTimeout(600);
+ aufgeklapptGesamt += wieViele;
+
+ const befund = await seite.evaluate(() => {
+ const r = document.querySelector(".neu__raster");
+ if (!r) return { zellen: 0, zuEng: [] };
+ const zellen = [...r.children].filter((c) => !c.hidden && c.offsetParent !== null);
+
+ /* WIE TIEF REICHT DER INHALT WIRKLICH -- zwei Anlaeufe davor
+ waren falsch, und der zweite war der gefaehrlichere:
+
+ (1) `scrollHeight` der Zelle. Meldete elf Zellen als kaputt,
+ die alle in Ordnung sind: Der Hinweis unter einem Feld
+ haengt seit dem 17.09. ABSICHTLICH absolut unter der Zelle
+ (`top: 100%`). Er ragt hinaus, das ist seine Aufgabe. Eine
+ Warnung, die bei richtigem Verhalten anschlaegt, wird
+ abgeschaltet.
+
+ (2) Nur die DIREKTEN Kinder im Fluss. Das war gruen -- auch
+ mit dem echten Fehler. Nachgemessen mit
+ zurueckgenommener Behebung: immer noch gruen. Der Grund
+ ist das Raster selbst: Es staucht das Kind auf die feste
+ Zeilenhoehe, das Kind bleibt also brav in der Zelle. Was
+ herauslaeuft, ist der Inhalt DARIN. Eine Pruefung, die
+ nur eine Ebene tief sieht, sieht davon nichts.
+
+ Also in die Tiefe -- aber nicht blind: Teilbaeume unter
+ absolut gesetzten Elementen bleiben aussen vor (siehe 1), und
+ wer selbst scrollt (`overflow` nicht `visible`), darf Inhalt
+ unterhalb haben; das ist der Sinn eines Rollbereichs. */
+ const unten = (c) => {
+ const oben = c.getBoundingClientRect().top;
+ let tiefste = 0;
+ const geh = (el) => {
+ for (const k of el.children) {
+ const st = getComputedStyle(k);
+ if (st.position === "absolute" || st.position === "fixed") continue;
+ if (st.display === "none" || k.hidden) continue;
+ tiefste = Math.max(tiefste, k.getBoundingClientRect().bottom - oben);
+ if (st.overflow === "visible" && st.overflowY === "visible") geh(k);
+ }
+ };
+ geh(c);
+ return Math.round(tiefste);
+ };
+ const zuEng = zellen
+ /* 4 px Luft fuer Abrundungen im Rastermass. 174 px faellt
+ hier nicht durch. */
+ .filter((c) => unten(c) > Math.round(c.getBoundingClientRect().height) + 4)
+ .map((c) => `${c.id || "(ohne Kennung)"}: Inhalt reicht bis ${unten(c)} px, `
+ + `Zelle ist ${Math.round(c.getBoundingClientRect().height)} px hoch`);
+ return { zellen: zellen.length, zuEng };
+ });
+ zellenGesamt += befund.zellen;
+ for (const z of befund.zuEng) schlimm.push(`${wohin} — ${z}`);
+ }
+
+ /* DIE ANZAHL GEHOERT IN DIE BEDINGUNG. Ohne sie waere „nichts laeuft
+ heraus" auch dann gruen, wenn gar nichts aufgeklappt wurde -- und
+ genau das war der Fehler der Pruefung darueber. */
+ ok(zellenGesamt > 10, `${zellenGesamt} Rasterzellen angesehen`);
+ ok(aufgeklapptGesamt > 0,
+ `${aufgeklapptGesamt} aufklappbare Bereiche wirklich geoeffnet`);
+ ok(schlimm.length === 0 && aufgeklapptGesamt > 0,
+ schlimm.length
+ ? `${schlimm.length} Zelle(n) laufen aus ihrer Zeile heraus:\n `
+ + schlimm.join("\n ")
+ : "keine Zelle laeuft aus ihrer Zeile heraus");
+
+ /* GEGENPROBE: Die Messung muss ein Herauslaufen auch SEHEN. Dafuer
+ wird eine Zelle kuenstlich eingeklemmt -- und danach wieder
+ freigegeben. Ohne diese Zeile waere „nichts laeuft heraus" die
+ Aussage einer Messung, von der niemand weiss, ob sie etwas
+ bemerken wuerde. */
+ /* Fuer die Gegenprobe zurueck auf ein Formular, das offen ist -- der
+ letzte Durchlauf oben kann auf einer Seite geendet haben, die gar
+ keines hat. Eine Gegenprobe, die mangels Gelegenheit ausfaellt,
+ ist keine. */
+ await seite.goto(`${BASIS}/workspace/aufgaben.html`, { waitUntil: "networkidle" });
+ await seite.waitForTimeout(900);
+ await seite.click("#neu-oeffnen").catch(() => {});
+ await seite.waitForTimeout(700);
+
+ const probe = await seite.evaluate(() => {
+ /* Dieselbe Rechnung wie oben -- sonst prueft die Gegenprobe eine
+ andere Messung als die, um die es geht. */
+ const unten = (c) => {
+ const oben = c.getBoundingClientRect().top;
+ let tiefste = 0;
+ const geh = (el) => {
+ for (const k of el.children) {
+ const st = getComputedStyle(k);
+ if (st.position === "absolute" || st.position === "fixed") continue;
+ if (st.display === "none" || k.hidden) continue;
+ tiefste = Math.max(tiefste, k.getBoundingClientRect().bottom - oben);
+ if (st.overflow === "visible" && st.overflowY === "visible") geh(k);
+ }
+ };
+ geh(c);
+ return Math.round(tiefste);
+ };
+ const r = document.querySelector(".neu__raster");
+ const c = r && [...r.children].find((x) => !x.hidden && x.offsetParent !== null && unten(x) > 40);
+ if (!c) return null;
+ const vorher = c.style.height;
+ c.style.height = "12px";
+ const erkannt = unten(c) > Math.round(c.getBoundingClientRect().height) + 4;
+ c.style.height = vorher;
+ const wiederGut = unten(c) <= Math.round(c.getBoundingClientRect().height) + 4;
+ return { erkannt, wiederGut };
+ });
+ ok(!!probe && probe.erkannt && probe.wiederGut,
+ probe ? "Gegenprobe: eine kuenstlich eingeklemmte Zelle wird erkannt"
+ : "KONNTE NICHT NACHSEHEN: keine Zelle fuer die Gegenprobe gefunden");
+
+ await kontext.close();
+}
+
await browser.close();
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
console.log(fehler ? `\n${fehler} Formular(e) fehlerhaft.` : "\nAlles in Ordnung.");
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 1aa65f65..97e22552 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,15 +16,15 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+