diff --git a/server/mess-quer.mjs b/server/mess-quer.mjs
index 3c0e8749..be2f7c98 100644
--- a/server/mess-quer.mjs
+++ b/server/mess-quer.mjs
@@ -310,6 +310,7 @@ const GERAETE = [
["Handy", 412, 915],
["iPhone", 390, 844],
["kleines Handy", 360, 640],
+ ["kleinstes Handy", 320, 568],
];
let befunde = 0;
@@ -374,6 +375,16 @@ for (const [gname, breite, hoehe] of GERAETE) {
const register = await host.seite.evaluate(() =>
[...document.querySelectorAll(".reiter__knopf")].map((b) => b.dataset.tafel));
console.log(` Register: ${register.join(" · ")}`);
+ {
+ const z = await host.seite.evaluate(() => {
+ const saal = document.getElementById("saal");
+ const teile = [...saal.children].filter((e) => e.getBoundingClientRect().height > 0)
+ .map((e) => { const q = e.getBoundingClientRect();
+ return `${e.id || e.className.split(" ")[0]} ${Math.round(q.top)}..${Math.round(q.bottom)}`; });
+ return `Zeilen ${getComputedStyle(saal).gridTemplateRows} | ${teile.join(" / ")}`;
+ });
+ console.log(` ${z}`);
+ }
/* Erst die Seite als Ganzes. */
const seitlich = await host.seite.evaluate(() =>
diff --git a/server/mess-reaktion.mjs b/server/mess-reaktion.mjs
index 765c5918..4bfb3400 100644
--- a/server/mess-reaktion.mjs
+++ b/server/mess-reaktion.mjs
@@ -2456,15 +2456,55 @@ await zuschauer.kontext.close();
const alle = [...document.getElementById("saal").children]
.filter((e) => e.getBoundingClientRect().height > 0)
.map((e) => `${e.id || e.className.split(" ")[0]}=${Math.round(e.getBoundingClientRect().height)}`);
+ /* WIEVIEL VOM BILD IST WIRKLICH ZU SEHEN?
+ Die Hoehe der Kinozeile sagt das nicht: Seit die Regie am
+ Handy eine Schublade darueber ist, kann die Zeile 431 Pixel
+ hoch sein und trotzdem vollstaendig verdeckt. Ein gruener
+ Haken ueber eine Zeilenhoehe waere genau die Sorte, die das
+ Falsche misst. Gefragt ist der Streifen, der oberhalb der
+ Schublade uebrig bleibt. */
+ const kino = document.getElementById("teil-live").getBoundingClientRect();
+ const regie = document.getElementById("pult").getBoundingClientRect();
+ const frei = Math.max(0, Math.round(Math.min(kino.bottom, regie.top) - kino.top));
return { saal: g("saal"), leiste: g("regieleiste"), kino: g("teil-live"), pult: g("pult"),
- alle: alle.join(" + ") };
+ frei, alle: alle.join(" + ") };
});
console.log(` Handy offen: Saal ${platzHandy.saal} = Leiste ${platzHandy.leiste} `
+ `+ Kino ${platzHandy.kino} + Regie ${platzHandy.pult}`);
console.log(` Handy Zeilen: ${platzHandy.alle}`);
- if (platzHandy.kino < 190) {
+ const spur = await chef.seite.evaluate(() => {
+ const saal = document.getElementById("saal");
+ const r = saal.getBoundingClientRect();
+ const teile = [...saal.children].filter((e) => e.getBoundingClientRect().height > 0)
+ .map((e) => {
+ const q = e.getBoundingClientRect();
+ return `${e.id || e.className.split(" ")[0]} ${Math.round(q.top)}..${Math.round(q.bottom)}`;
+ });
+ const tr = document.querySelector(".transport");
+ const teileT = [...(tr ? tr.children : [])].map((e) => {
+ const q = e.getBoundingClientRect();
+ return `${e.className.split(" ")[0]}=${Math.round(q.height)}`;
+ });
+ return `Saal ${Math.round(r.top)}..${Math.round(r.bottom)} (Fenster ${window.innerHeight})`
+ + ` | Zeilen ${getComputedStyle(saal).gridTemplateRows}`
+ + ` | ${teile.join(" / ")}`
+ + ` | Transport: ${teileT.join(" + ")}`
+ + ` | Regie-Kopf: ${(() => {
+ const l = document.querySelector(".pult__leiste");
+ if (!l) return "-";
+ const kinder = [...l.children].map((e) => {
+ const q = e.getBoundingClientRect();
+ return `${e.className.split(" ")[0] || e.tagName.toLowerCase()}`
+ + ` ${Math.round(q.top)}..${Math.round(q.bottom)}`;
+ });
+ return `${Math.round(l.getBoundingClientRect().height)} px = ${kinder.join(" / ")}`;
+ })()}`;
+ });
+ console.log(` SPUR: ${spur}`);
+ console.log(` Vom Bild sichtbar (nicht von der Regie verdeckt): ${platzHandy.frei} px`);
+ if (platzHandy.frei < 120) {
offenePunkte.push(`Am Handy bleibt bei offener Regie vom Bild fast nichts `
- + `(${platzHandy.kino} px, noetig 190). Bekannt seit 28.09.2026. `
+ + `(${platzHandy.frei} px sichtbar, noetig 120). Bekannt seit 28.09.2026. `
+ `Wurzel: die umgebrochene Transportleiste braucht auf 320 px `
+ `Breite 220 Pixel. Der Weg steht in reaktion.css beim Handy-Block.`);
}
diff --git a/server/pruef-reaktion.mjs b/server/pruef-reaktion.mjs
index 3d214f0b..f978f45d 100644
--- a/server/pruef-reaktion.mjs
+++ b/server/pruef-reaktion.mjs
@@ -989,12 +989,39 @@ melde("=== 12. Die Regie ===");
Grundregeln, die beide sagen, WIE das Bauteil gebaut ist --
`grid` gegen `flex`, wie bei `.stufen`. */
const positiv = (wert) => wert && wert !== "none" && !/^none/.test(wert);
+
+ /* ZWEI EINSCHRAENKUNGEN MEHR, BEIDE AM 29.09.2026 NOETIG GEWORDEN.
+
+ (3) Der Selektor muss GENAU die Klasse sein. `.saal .pult {
+ display: flex }` ist keine zweite Grundregel zu `.pult {
+ display: grid }`, sondern dieselbe Klasse in einem anderen
+ Zusammenhang -- und genau dafuer sind Selektoren da. Die
+ erste Fassung nahm jede Klasse, der ein Trennzeichen
+ vorausging, und meldete deshalb `pult (grid vs. flex)`.
+
+ (4) Regeln INNERHALB einer Medienabfrage zaehlen nicht. Sie
+ sind per Definition eine Variante fuer eine andere
+ Umgebung -- `messwerte__paar` steht am Fingergeraet als
+ `flex` und sonst als `grid`, und das ist die Absicht.
+
+ Was uebrig bleibt, ist der Fall, um den es ging: `.stufen`
+ stand zweimal als blanke Grundregel, ohne Medienabfrage und
+ ohne Zusammenhang -- zwei verschiedene Bauteile, ein Name. */
+ const ohneMedien = (text) => text.replace(
+ /@media[^{]*\{(?:[^{}]|\{[^{}]*\})*\}/g,
+ (m) => m.replace(new RegExp("[^" + String.fromCharCode(10) + "]", "g"), " "));
+
const lies = (text) => {
const raus = {};
- for (const m of text.matchAll(/(^|[\s};])(\.(-?[a-zA-Z_][a-zA-Z0-9_-]*))\s*\{([^{}]*)\}/g)) {
- const wert = (m[4].match(/(?:^|[\s;])display\s*:\s*([^;]+)/) || [, ""])[1].trim();
+ /* LOOKBEHIND STATT VERBRAUCHEN. Mit `(^|[};])` frisst der erste
+ Treffer die schliessende Klammer, die der naechste als Anfang
+ braeuchte -- `.stufen { … } .stufen { … }` lieferte dann nur
+ EINEN Treffer, und die Gegenprobe zum echten Fall vom 28.09.
+ schlug fehl. */
+ for (const m of ohneMedien(text).matchAll(/(?:^|(?<=[};]))\s*(\.(-?[a-zA-Z_][a-zA-Z0-9_-]*))\s*\{([^{}]*)\}/g)) {
+ const wert = (m[3].match(/(?:^|[\s;])display\s*:\s*([^;]+)/) || [, ""])[1].trim();
if (!positiv(wert)) continue;
- (raus[m[3]] ||= []).push(wert);
+ (raus[m[2]] ||= []).push(wert);
}
return raus;
};
@@ -1010,20 +1037,33 @@ melde("=== 12. Die Regie ===");
: `${Object.keys(grundregeln).length} Klassen sagen, WIE sie gebaut sind `
+ "-- keine davon zweimal verschieden");
- /* GEGENPROBE: Findet die Regel einen eingeschobenen Streit? Ohne
- diese Zeile waere oben nur bewiesen, dass sie „in Ordnung"
- sagen kann. Eingeschoben wird genau der Fall vom 28.09.: eine
- zweite Grundregel mit einem anderen positiven display. */
- ok(streitIn(roh("reaktion.css") + " .pult-tafel { display: flex; } ")
- .some((z) => z.startsWith("pult-tafel (")),
- "Gegenprobe: eine zweite Grundregel mit anderem display faellt auf");
-
- /* UND IN DIE ANDERE RICHTUNG: Ein Bauteil, das erst versteckt und
- dann gezeigt wird, darf NICHT anschlagen -- sonst haette man
- die Regel nur so lange geschaerft, bis sie alles meldet. */
- ok(streitIn(" .probe { display: none; } .probe { display: grid; } ").length === 0
- && streitIn(" .probe { display: grid; } .probe { display: flex; } ").length === 1,
- "Gegenprobe: verstecken-und-zeigen ist kein Streit, grid-gegen-flex schon");
+ /* GEGENPROBEN AN EIGENSTAENDIGEN TEXTEN, nicht an die echte
+ Datei angehaengt. Die erste Fassung tat das -- und scheiterte,
+ sobald der Sucher Medienabfragen ausklammert: Was hinter dem
+ letzten `@media` angehaengt wird, kann darin verschwinden.
+ Eine Gegenprobe, die vom Inhalt der geprueften Datei abhaengt,
+ prueft nicht die Regel, sondern die Datei. */
+ {
+ const faelle = [
+ ["der Fall vom 28.09. (zwei Grundregeln, anderes display)",
+ ".stufen { display: grid; } .stufen { display: flex; }", true],
+ ["verstecken und zeigen",
+ ".probe { display: none; } .probe { display: grid; }", false],
+ ["dieselbe Klasse in einem Zusammenhang",
+ ".pult { display: grid; } .saal .pult { display: flex; }", false],
+ ["eine Variante in einer Medienabfrage",
+ ".paar { display: grid; } @media (pointer: coarse) { .paar { display: flex; } }", false],
+ ["zweimal dasselbe display",
+ ".gleich { display: grid; } .gleich { display: grid; }", false],
+ ];
+ const daneben = faelle
+ .filter(([, text, soll]) => (streitIn(text).length > 0) !== soll)
+ .map(([name]) => name);
+ ok(daneben.length === 0,
+ daneben.length ? `Gegenprobe daneben bei: ${daneben.join(", ")}`
+ : `Gegenprobe: alle ${faelle.length} Faelle richtig eingeordnet `
+ + "(Streit, Zustand, Zusammenhang, Medienabfrage, Wiederholung)");
+ }
/* ---- Nichts rollt absichtlich waagerecht ----------------------
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 7a2c171b..487a394a 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,8 +16,8 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+