diff --git a/server/pruef-chat-optik.mjs b/server/pruef-chat-optik.mjs
index 9a615581..e68efff9 100644
--- a/server/pruef-chat-optik.mjs
+++ b/server/pruef-chat-optik.mjs
@@ -493,6 +493,102 @@ melde("\n=== Der Fuss bleibt in der Blase ===");
await luna.seite.unroute("**/api/chat/raeume/*/nachrichten");
}
+
+/* =======================================================================
+ MAN MUSS SEHEN, MIT WEM MAN SCHREIBT (20.09.2026)
+
+ Gemessen am Handy, Gespraech "Team-Runde":
+
+ 360 px -> 0 px sichtbar (98 noetig)
+ 390 px -> 12 px
+ 412 px -> 33 px
+
+ Auf JEDEM Telefon stand also kein Name in der Kopfzeile. Man oeffnet
+ ein Gespraech und weiss nicht, mit wem -- und weil die Zeile nicht
+ leer aussieht (Zurueck-Pfeil, fuenf Knoepfe), wirkt sie nicht kaputt,
+ sondern nur eng.
+
+ WARUM DER GROSSE HANDY-RUNDGANG ES NICHT GEFUNDEN HAT -- zwei eigene
+ Entscheidungen, die zusammen ein Loch ergaben:
+
+ 1. Er ueberspringt, was `width > 0` nicht erfuellt. Ein auf null
+ gequetschtes Element ist unsichtbar, und "unsichtbar" hiess
+ dort "nichts zu pruefen".
+ 2. Er verzeiht `text-overflow: ellipsis` als ABSICHT. Das ist
+ richtig -- ein langer Name soll gekuerzt werden. Es ist nur
+ dann falsch, wenn gar nichts mehr uebrig ist.
+
+ Beides ist einzeln vernuenftig. Deshalb steht die Pruefung hier, wo
+ sie genau eine Sache misst, statt die Regeln dort aufzuweichen.
+ ======================================================================= */
+melde("\n=== Man sieht, mit wem man schreibt ===");
+{
+ let gemessen = 0;
+ const zuEng = [];
+ for (const breite of [320, 360, 390, 430]) {
+ await luna.seite.setViewportSize({ width: breite, height: 844 });
+ await luna.seite.waitForTimeout(400);
+ const m = await luna.seite.evaluate(() => {
+ const t = document.getElementById("verlauf-titel");
+ if (!t) return null;
+ const r = t.getBoundingClientRect();
+ return { text: (t.textContent || "").trim(), sicht: Math.round(r.width),
+ noetig: Math.round(t.scrollWidth) };
+ });
+ if (!m || !m.text) continue;
+ gemessen++;
+ /* SICHTBAR MUSS SEIN, WAS GEBRAUCHT WIRD -- oder wenigstens so
+ viel, dass man den Namen erkennt. Ein Drittel eines Namens ist
+ kein Name. */
+ if (m.sicht < Math.min(m.noetig, 90)) {
+ zuEng.push(`${breite}px: ${m.sicht} von ${m.noetig} px`);
+ }
+ }
+ /* DIE ZAHL GEHOERT IN DIE BEDINGUNG: Faende die Schleife gar keinen
+ Titel, waere "nichts zu eng" trivialerweise wahr. */
+ ok(gemessen === 4 && zuEng.length === 0,
+ `der Gespraechsname ist auf allen ${gemessen} Breiten lesbar`
+ + (zuEng.length ? " — ZU ENG: " + zuEng.join(", ") : ""));
+
+ /* ---- GEGENPROBE ------------------------------------------------
+
+ ERST DEN GEMESSENEN FALL NACHSTELLEN. Der erste Anlauf drehte nur
+ die Angabe zurueck und blieb gruen: In DIESEM Gespraech stehen
+ drei Knoepfe, da reicht der Platz auch ohne die Reparatur. Der
+ Fehler trat in einer GRUPPE auf, wo fuenf Knoepfe stehen --
+ Anrufen, Video, Aufloesen, Wegraeumen, Wer-ist-drin.
+
+ Eine Gegenprobe, die den Fall nicht herstellt, den sie pruefen
+ soll, ist keine. Deshalb bekommt die Knopfreihe hier die Breite,
+ die fuenf Knoepfe wirklich brauchen (5 x 44 + 4 x 6 Abstand).
+ Damit muss die alte Angabe den Namen zerdruecken -- und die neue
+ nicht. Beide Richtungen werden gemessen. */
+ await luna.seite.setViewportSize({ width: 390, height: 844 });
+ await luna.seite.waitForTimeout(300);
+ const ab = await luna.seite.evaluate(() => {
+ const eng = document.createElement("style");
+ eng.textContent = ".chat__kopf-knoepfe { min-width: 244px !important; }";
+ document.head.append(eng);
+
+ const t = document.getElementById("verlauf-titel");
+ const mitNeu = Math.round(t.getBoundingClientRect().width);
+
+ const alt = document.createElement("style");
+ alt.textContent = ".chat__kopf--verlauf .chat__kopf-text { flex: 1 1 0 !important; }";
+ document.head.append(alt);
+ const mitAlt = Math.round(t.getBoundingClientRect().width);
+
+ alt.remove(); eng.remove();
+ return { mitNeu, mitAlt };
+ });
+ ok(ab.mitAlt < 40,
+ `Gegenprobe: mit der alten Angabe bleiben ${ab.mitAlt} px — die Pruefung kann auch NEIN sagen`);
+ ok(ab.mitNeu >= 90,
+ ` und mit der neuen ${ab.mitNeu} px, im selben Aufbau — die Reparatur ist der Unterschied`);
+ await luna.seite.setViewportSize({ width: 1280, height: 900 });
+ await luna.seite.waitForTimeout(300);
+}
+
await luna.ctx.close();
await pat.ctx.close();
await browser.close();
diff --git a/server/pruef-handy-teamdogi.mjs b/server/pruef-handy-teamdogi.mjs
index 6342b19c..a2db3175 100644
--- a/server/pruef-handy-teamdogi.mjs
+++ b/server/pruef-handy-teamdogi.mjs
@@ -386,6 +386,45 @@ const messen = () => {
return e.scrollWidth > e.clientWidth + 3 || e.scrollHeight > e.clientHeight + 3;
}).slice(0, 4).map((e) => `${name(e)} „${(e.textContent || "").trim().slice(0, 28)}…"`);
+ /* ---- Auf fast nichts zusammengedrückter Text (20.09.2026) --------
+
+ ZWEI EIGENE ENTSCHEIDUNGEN ERGABEN ZUSAMMEN EIN LOCH, und es hat
+ einen echten Fehler durchgelassen: In der Kopfzeile eines
+ Gesprächs blieben vom Namen 0 bis 33 px übrig — auf JEDEM
+ Telefon. Man öffnete einen Chat und sah nicht, mit wem man
+ schreibt.
+
+ Warum hier nichts gemeldet wurde:
+
+ 1. `sichtbar()` verlangt `width > 0`. Ein auf null gequetschtes
+ Element ist unsichtbar -- und "unsichtbar" hiess "nichts zu
+ prüfen". Genau falsch herum: Nichts zu sehen IST der Befund.
+ 2. `text-overflow: ellipsis` gilt als Absicht. Das stimmt auch
+ -- ein langer Name soll gekürzt werden. Es stimmt nur nicht
+ mehr, wenn nichts übrig bleibt.
+
+ DIE REGEL IST BEWUSST SCHMAL. "Jede Kürzung melden" wären die
+ ~350 Fehlalarme, die weiter oben schon einmal alles zugedeckt
+ haben. Gemeldet wird nur, was UNTER 40 px sichtbar ist und
+ mindestens das Doppelte bräuchte -- da steht kein Wort mehr,
+ sondern ein Buchstabe mit Punkten. */
+ const zerquetscht = alle.filter((e) => {
+ if (e.children.length > 0) return false;
+ if (nurVorlesen(e)) return false;
+ const t = (e.textContent || "").trim();
+ if (t.length < 4) return false;
+ const st = getComputedStyle(e);
+ if (st.visibility === "hidden" || st.display === "none") return false;
+ if (Number(st.opacity) <= 0.05) return false;
+ /* Steht es überhaupt im Aufbau? Ein Element in einem geschlossenen
+ Klappfeld ist kein Fall -- es ist gar nicht dran. */
+ if (!e.offsetParent && st.position !== "fixed") return false;
+ const breiteHier = e.getBoundingClientRect().width;
+ const noetig = e.scrollWidth;
+ return breiteHier < 40 && noetig >= breiteHier * 2 && noetig > 60;
+ }).slice(0, 4).map((e) => `${name(e)} „${(e.textContent || "").trim().slice(0, 24)}…" `
+ + `${Math.round(e.getBoundingClientRect().width)} statt ${Math.round(e.scrollWidth)}px`);
+
/* ---- Zu kleine Tippziele ----------------------------------------- */
const klein = bedienbar.filter((e) => {
const r = e.getBoundingClientRect();
@@ -459,7 +498,7 @@ const messen = () => {
elemente: alle.length,
bedienbar: bedienbar.length,
ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth,
- ueberstand, abgeschnitten, klein, ueberdeckt, namenlos,
+ ueberstand, abgeschnitten, zerquetscht, klein, ueberdeckt, namenlos,
};
};
@@ -595,6 +634,9 @@ for (const [breite, hoehe, geraet] of BREITEN) {
details.push(`${kurz}: ragt über den Rand — ${m.ueberstand.join(", ")}`);
schlecht++;
}
+ if (m.zerquetscht?.length) {
+ details.push(`${kurz}: Text auf fast nichts gedrückt — ${m.zerquetscht.join(", ")}`); schlecht++;
+ }
if (m.abgeschnitten.length) {
details.push(`${kurz}: Text abgeschnitten — ${m.abgeschnitten.join(", ")}`); schlecht++;
}
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 40c27813..e5c48b15 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`. -->
-
-
+
+
-
+