Reaction: Rollen sichtbar, Moderation im Live-Chat

Filipes Wunsch: „die modis, linke hand und rechte hand soll im chat
extra aussehen und auch sachen wie stummschaltungen, sperrungen,
meldunge und alles mögliche im chat machen können falls sich jemand
nicht benimmt."

WER SPRICHT
Jeder Beitrag aus dem Team trägt jetzt ein Abzeichen: „Dogi", „Team"
(beide Hände) und „Modi". Ein WORT und nicht nur eine Farbe — rund
acht Prozent der Männer unterscheiden Rot und Grün schlecht, und hier
hängt an der Unterscheidung etwas. Gedeckte Töne auf schwacher Fläche,
11,52 px (die Hausgrenze ist 11,5), weil daneben ein Video läuft.
Die Wörter sagen den RANG nicht: Filipe steht nie über seinem Team.
Eine Prüfung schlägt an, wenn dort „Chef", „Boss" oder „Leitung"
stünde.

WAS DIE MODERATION KANN
Am Namen öffnet sich ein Menü mit vier Wegen: Beitrag wegnehmen,
10 Minuten stumm, aus der Sendung — und der Verweis in den Treff, wo
längere Maßnahmen hingehören (mit Begründungspflicht und Frist in
Tagen). Die Reaction baut kein zweites Sperrsystem daneben: Wer im
Treff eine Pause hat, schreibt hier auch nicht. Neu ist nur, was der
Treff nicht hat — MINUTEN. Höchstens eine Stunde; wer länger etwas
braucht, nimmt den Treff.
Nicht gegen das Team: Wer einen Modi stummschalten könnte, hätte einen
Weg, die Moderation selbst auszuschalten, mitten in der Sendung.

MELDEN DARF JEDER
Die Moderation sieht nicht alles, wer mitliest schon. Zweimal melden
zählt einmal (sonst füllt einer allein die Liste). Bei der Moderation
erscheint im Kopf der Schiene „1 Meldung" — nur wenn etwas offen ist;
eine Zahl, die immer dasteht und meistens null ist, wird nach drei
Tagen nicht mehr gelesen.

VIER FEHLER, DIE DABEI AUFGEFALLEN SIND

1. `oeffentlich()` nahm `meldungen` und `massnahmen` NICHT aus dem
   Rundruf. Der Rundruf wird aus dem Stand dessen gebaut, der gerade
   etwas getan hat — bei einer Moderationshandlung wären der gemeldete
   Text, der Name des Gemeldeten und der Name des MELDERS an jeden im
   Saal gegangen. Wer meldet, muss sich darauf verlassen können, dass
   das niemand sieht.

2. `meldung.js` hatte zwei Schlüssel doppelt: `geschlossen` und
   `nur_leitung`. Der spätere gewinnt stillschweigend — in der Hilfe
   stand dadurch „Der Saal ist zu". Ein Wort, ein Satz; eine Prüfung
   hält das jetzt fest.

3. Wer stummgeschaltet war, bekam bei OFFENEM Chat „Der Chat ist
   gerade zu" — der Aufrufer reimte sich den Grund aus der Chat-Stufe
   zusammen. Jetzt gibt `schreibGrund()` den echten Grund zurück.

4. Wer rausgenommen wurde, merkte nichts: Das Video lief weiter, nur
   die Anwesenheitsmeldung schlug still fehl. Jetzt hält alles an und
   es steht ein Satz da, der sagt, dass es nur für heute gilt.

UND EINER, DEN NUR DAS BILDSCHIRMFOTO GEFUNDEN HAT
Das Menü lag messbar komplett im Fenster (x=1099..1315 von 1440,
y=652..840 von 900) und war trotzdem abgeschnitten: Die Chatliste
rollt, und ein rollender Vorfahre beschneidet sein Kind. „Im Fenster"
und „sichtbar" sind zwei verschiedene Fragen, und ich hatte die
falsche gemessen. Das Menü hängt jetzt fest am Fenster und klappt nach
oben oder links, wo kein Platz ist. Die Messung fasst seitdem mit
`elementFromPoint` an jeden Knopf an, statt Rechtecke zu vergleichen.

GEPRUEFT
pruef-reaktion: 216 Prüfungen (vorher 156), 0 Fehler — zwei neue
Abschnitte. mess-reaktion misst die Moderation jetzt im echten
Browser: Abzeichen, Überlauf der Schiene, Menü, Stummschaltung beim
Betroffenen, Meldung bis zur Moderation, Rauswurf.
Dazu grün: pruef-meldungen, pruef-struktur, pruef-css-klassen,
pruef-tippziele, pruef-deutsche-texte, pruef-hilfe.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-28 09:32:10 +02:00
co-authored by Claude Opus 5
parent cb8e59bb08
commit a02cf5c026
52 changed files with 2071 additions and 691 deletions
+265 -1
View File
@@ -68,11 +68,19 @@ function anlegen(name, rolle, code) {
createHmac("sha256", kenn).update(code).digest("hex"), ALT);
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
}
const CODES = { admin: "CODE-M00-000001", gast: "CODE-M01-000001", gast2: "CODE-M02-000001" };
const CODES = {
admin: "CODE-M00-000001", gast: "CODE-M01-000001", gast2: "CODE-M02-000001",
modi: "CODE-M03-000001", linke: "CODE-M04-000001",
};
const IDS = {
admin: anlegen("DogFather", "admin", CODES.admin),
gast: anlegen("Nachtfalter", "gast", CODES.gast),
gast2: anlegen("Lenny", "gast", CODES.gast2),
/* Fuer die Moderation. Sie ist der Teil, bei dem ein Fehler am
meisten kostet -- also wird sie im Browser gemessen und nicht
nur ueber die Schnittstelle. */
modi: anlegen("Miss", "modi", CODES.modi),
linke: anlegen("Funny", "linke", CODES.linke),
};
d.close();
@@ -111,6 +119,8 @@ const k = {
admin: await anmelden("admin"),
gast: await anmelden("gast"),
gast2: await anmelden("gast2"),
modi: await anmelden("modi"),
linke: await anmelden("linke"),
};
/* ---------- Die Buehne fuellen ------------------------------------------ */
@@ -139,6 +149,12 @@ const REDEN = [
["gast2", "Ich auch! Hab extra Popcorn geholt"],
["gast", "Wie lange noch?"],
["admin", "Zwei Minuten, ich richte noch die Kamera"],
/* DAS TEAM SCHREIBT MIT. Ohne einen Beitrag von einer linken Hand
und einem Modi liesse sich gar nicht messen, ob die Abzeichen
ankommen -- und eine Messung, die ihren Gegenstand nicht
herstellt, misst nichts. */
["linke", "Ich pass auf den Chat auf, schreibt ruhig"],
["modi", "Und ich auch 🙂"],
["gast2", "Kein Stress, wir sitzen bequem"],
["gast", "Letztes Mal war so gut, ich hab geheult"],
];
@@ -658,6 +674,254 @@ await vermessen(zuschauer.seite, "Zuschauerin am Rechner");
await bild(zuschauer.seite, "4-live-zuschauer");
if (zuschauer.konsole.length) console.log(" KONSOLE:", zuschauer.konsole.slice(0, 4).join(" | "));
/* ---- Rollen und Moderation im Chat --------------------------------
Filipe: „die modis, linke hand und rechte hand soll im chat extra
aussehen und auch sachen wie stummschaltungen, sperrungen,
meldunge ... machen koennen."
GEMESSEN UND NICHT HERGELEITET. Die Schiene ist die schmalste
Flaeche der ganzen Seite, und in jede Beitragszeile ist gerade ein
Abzeichen UND ein zweiter Knopf dazugekommen. Genau so ist am
28.09. die Regie 197 px uebergelaufen: Die Rechnung ging auf, die
Wirklichkeit nicht. */
console.log("");
console.log(" --- Rollen und Moderation ---");
const modi = await alsWer("modi", 1440, 900);
await modi.seite.goto(`${BASIS}/workspace/reaktion.html`, { waitUntil: "domcontentloaded" });
await modi.seite.waitForTimeout(2500);
const abz = await modi.seite.evaluate(() => {
const liste = document.getElementById("chat-liste");
const marken = [...liste.querySelectorAll(".beitrag__rolle")].map((m) => ({
wort: m.textContent.trim(),
rolle: m.dataset.rolle,
schrift: Math.round(parseFloat(getComputedStyle(m).fontSize) * 100) / 100,
breit: Math.round(m.getBoundingClientRect().width),
}));
/* LAEUFT EINE ZEILE UEBER? Nicht die Zahl aus dem Stilblatt, die
tatsaechliche Breite gegen die tatsaechliche Liste. */
const innen = liste.getBoundingClientRect();
const ueber = [...liste.querySelectorAll(".beitrag")]
.map((b) => Math.round(b.scrollWidth - b.clientWidth))
.filter((x) => x > 0);
/* Und die Kopfzeile selbst -- dort stehen Name, Abzeichen und
Knopf nebeneinander. */
const koepfe = [...liste.querySelectorAll(".beitrag__wer")]
.map((h) => Math.round(h.scrollWidth - h.clientWidth))
.filter((x) => x > 0);
return {
marken, ueber, koepfe,
listenbreite: Math.round(innen.width),
namensknoepfe: liste.querySelectorAll(".beitrag__name").length,
beitraege: liste.children.length,
};
});
console.log(` Schiene ${abz.listenbreite} px breit, ${abz.beitraege} Beitraege, `
+ `${abz.marken.length} Abzeichen, ${abz.namensknoepfe} Namen zum Anfassen.`);
for (const m of abz.marken) {
console.log(` „${m.wort}" (${m.rolle}) ${m.schrift} px, ${m.breit} px breit`);
}
if (abz.marken.length < 3) {
console.log(" ACHTUNG: Die Abzeichen kommen im Chat nicht an.");
ausgang = 1;
}
/* 11,5 px ist die Untergrenze des Hauses (pruef-css-klassen). */
if (abz.marken.some((m) => m.schrift < 11.5)) {
console.log(" ACHTUNG: Ein Abzeichen ist kleiner als 11,5 px.");
ausgang = 1;
}
if (abz.ueber.length || abz.koepfe.length) {
console.log(` ACHTUNG: ${abz.ueber.length} Beitraege und ${abz.koepfe.length} Kopfzeilen `
+ `laufen ueber (${[...abz.ueber, ...abz.koepfe].join(", ")} px).`);
ausgang = 1;
}
/* EIN MODI MELDET NICHT -- er handelt. Der Melden-Knopf gehoert
denen, die nichts anderes tun koennen. */
const modiSicht = await modi.seite.evaluate(() =>
document.querySelectorAll("#chat-liste .beitrag__melden").length);
console.log(` Der Modi sieht ${modiSicht} Melden-Knoepfe (soll: 0) `
+ `und ${abz.namensknoepfe} Namen zum Anfassen.`);
if (modiSicht !== 0 || abz.namensknoepfe < 3) {
console.log(" ACHTUNG: Melden und Moderieren sind vertauscht.");
ausgang = 1;
}
/* DAS MENUE MUSS INS BILD PASSEN. Ein Menue, das unten oder rechts
heraussteht, ist auf dem Handy die Haelfte der Zeit nicht
bedienbar -- und man sieht es erst, wenn man es aufmacht. */
await modi.seite.click("#chat-liste .beitrag:last-child .beitrag__name").catch(() => {});
await modi.seite.waitForTimeout(400);
const menue = await modi.seite.evaluate(() => {
const m = document.querySelector(".modmenue");
if (!m) return null;
const r = m.getBoundingClientRect();
const knoepfe = [...m.querySelectorAll(".modmenue__knopf")].map((k2) => ({
wort: k2.textContent.trim(),
hoch: Math.round(k2.getBoundingClientRect().height),
}));
/* IST ES WIRKLICH ZU SEHEN? „Im Fenster" reicht nicht als Frage.
Beim ersten Bau lag das Menue nachweislich komplett im Fenster
(x=1099..1315 von 1440, y=652..840 von 900) und war trotzdem
abgeschnitten -- die Chatliste rollt, und ein rollender
Vorfahre beschneidet sein Kind. Gefunden hat das nicht die
Messung, sondern das Bildschirmfoto.
Deshalb jetzt der einzige Test, der die Frage beantwortet: An
die Stelle jedes Knopfes fassen und nachsehen, was dort
tatsaechlich liegt. */
const greifbar = [...m.querySelectorAll(".modmenue__knopf")].filter((k2) => {
const q = k2.getBoundingClientRect();
const oben = document.elementFromPoint(q.left + q.width / 2, q.top + q.height / 2);
return !!oben && (k2 === oben || k2.contains(oben));
}).length;
return {
links: Math.round(r.left), rechts: Math.round(r.right),
oben: Math.round(r.top), unten: Math.round(r.bottom),
breit: Math.round(r.width), knoepfe, greifbar,
fensterBreit: window.innerWidth, fensterHoch: window.innerHeight,
};
});
if (!menue) {
console.log(" ACHTUNG: Das Moderationsmenue geht nicht auf.");
ausgang = 1;
} else {
console.log(` Menue ${menue.breit} px breit bei x=${menue.links}..${menue.rechts} `
+ `(Fenster ${menue.fensterBreit}), y=${menue.oben}..${menue.unten}`);
for (const b of menue.knoepfe) console.log(` „${b.wort}" ${b.hoch} px hoch`);
console.log(` ${menue.greifbar} von ${menue.knoepfe.length} Knoepfen sind anfassbar`);
const raus = menue.rechts > menue.fensterBreit || menue.links < 0
|| menue.unten > menue.fensterHoch;
if (raus) {
console.log(" ACHTUNG: Das Menue steht aus dem Bild heraus.");
ausgang = 1;
}
if (menue.greifbar !== menue.knoepfe.length) {
console.log(" ACHTUNG: Ein Knopf des Menues ist verdeckt oder abgeschnitten.");
ausgang = 1;
}
if (menue.knoepfe.length < 4 || menue.knoepfe.some((b) => b.hoch < 44)) {
console.log(" ACHTUNG: Ein Knopf im Menue ist kleiner als 44 px.");
ausgang = 1;
}
}
await bild(modi.seite, "12-moderationsmenue");
/* STUMM SCHALTEN -- und beim Betroffenen nachsehen.
Der Chat steht dabei auf „offen": genau der Fall, in dem die
Auskunft vorher falsch war („Der Chat ist gerade zu"). */
await modi.seite.click('.modmenue__knopf:text("10 Minuten stumm")').catch(async () => {
await modi.seite.evaluate(() => {
const k2 = [...document.querySelectorAll(".modmenue__knopf")]
.find((x) => x.textContent.includes("stumm"));
if (k2) k2.click();
});
});
await modi.seite.waitForTimeout(1500);
const beimGast = await zuschauer.seite.evaluate(() => {
const f = document.getElementById("chat-feld");
return { gesperrt: !!f?.disabled, grund: f?.placeholder || "" };
});
console.log(` Die Stummgeschaltete sieht: gesperrt=${beimGast.gesperrt}, `
+ `Grund „${beimGast.grund}"`);
const serverSagt = await roh("/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast, rumpf: { text: "und jetzt?" },
});
console.log(` ... und der Server: ${serverSagt.code}/${serverSagt.j?.fehler}`);
if (!beimGast.gesperrt || !beimGast.grund.includes("stumm")
|| serverSagt.j?.fehler !== "stumm_geschaltet") {
console.log(" ACHTUNG: Die Stummschaltung kommt nicht oder mit falschem Grund an.");
ausgang = 1;
}
await roh(`/workspace/api/reaktion/massnahme/${IDS.gast}`, { method: "DELETE", keks: k.admin });
await modi.seite.waitForTimeout(900);
/* MELDEN -- der Weg fuer die, die selbst nichts tun koennen. */
const letzter = await roh("/workspace/api/reaktion/chat", { keks: k.admin });
const zuMelden = (letzter.j?.beitraege || []).filter((b) => b.person_id === IDS.gast2).pop();
if (zuMelden) {
await roh(`/workspace/api/reaktion/chat/${zuMelden.id}/melden`, {
method: "POST", keks: k.gast, rumpf: { grund: "unfreundlich" },
});
}
await modi.seite.waitForTimeout(1800);
const chip = await modi.seite.evaluate(() => {
const k2 = document.getElementById("chat-meldungen");
if (!k2) return null;
const r = k2.getBoundingClientRect();
return { versteckt: !!k2.hidden, wort: k2.textContent.trim(), hoch: Math.round(r.height) };
});
console.log(` Meldungs-Zeichen: „${chip?.wort}" (versteckt=${chip?.versteckt}, `
+ `${chip?.hoch} px hoch)`);
if (!chip || chip.versteckt || !/Meldung/.test(chip.wort)) {
console.log(" ACHTUNG: Die Meldung erreicht die Moderation nicht.");
ausgang = 1;
}
await modi.seite.click("#chat-meldungen").catch(() => {});
await modi.seite.waitForTimeout(400);
const liste = await modi.seite.evaluate(() => {
const m = document.querySelector(".modmenue--liste");
if (!m) return null;
const r = m.getBoundingClientRect();
const knoepfe = [...m.querySelectorAll(".modmenue__knopf")];
const greifbar = knoepfe.filter((k2) => {
const q = k2.getBoundingClientRect();
const oben = document.elementFromPoint(q.left + q.width / 2, q.top + q.height / 2);
return !!oben && (k2 === oben || k2.contains(oben));
}).length;
return {
zeilen: m.querySelectorAll(".modmeldung").length,
text: m.querySelector(".modmeldung__text")?.textContent || "",
knoepfe: knoepfe.length, greifbar,
rechts: Math.round(r.right), unten: Math.round(r.bottom),
fensterBreit: window.innerWidth, fensterHoch: window.innerHeight,
};
});
if (!liste || liste.zeilen < 1) {
console.log(" ACHTUNG: Die Meldungsliste geht nicht auf.");
ausgang = 1;
} else {
console.log(` ${liste.zeilen} Meldung(en), erste: „${liste.text}" -- `
+ `${liste.greifbar}/${liste.knoepfe} Knoepfe anfassbar`);
if (liste.rechts > liste.fensterBreit || liste.unten > liste.fensterHoch) {
console.log(" ACHTUNG: Die Meldungsliste steht aus dem Bild heraus.");
ausgang = 1;
}
if (liste.greifbar !== liste.knoepfe) {
console.log(" ACHTUNG: Ein Knopf der Meldungsliste ist verdeckt.");
ausgang = 1;
}
}
await bild(modi.seite, "13-meldungen");
if (modi.konsole.length) console.log(" KONSOLE:", modi.konsole.slice(0, 4).join(" | "));
/* AUS DER SENDUNG -- der haerteste Fall. Wer rausgenommen wird, muss
es ERFAHREN; vorher lief bei ihm das Video weiter, und nur die
Anwesenheitsmeldung schlug still fehl. */
await roh("/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.admin, rumpf: { person_id: IDS.gast, art: "raus" },
});
await zuschauer.seite.waitForTimeout(2500);
const rausgesetzt = await zuschauer.seite.evaluate(() => {
const k2 = document.querySelector(".raus");
return {
da: !!k2, markiert: document.body.dataset.raus === "ja",
titel: k2?.querySelector(".raus__titel")?.textContent || "",
deckt: k2 ? Math.round(k2.getBoundingClientRect().height) : 0,
fensterHoch: window.innerHeight,
};
});
console.log(` Die Rausgenommene sieht: „${rausgesetzt.titel}" `
+ `(${rausgesetzt.deckt} von ${rausgesetzt.fensterHoch} px)`);
if (!rausgesetzt.da || !rausgesetzt.markiert
|| rausgesetzt.deckt < rausgesetzt.fensterHoch - 2) {
console.log(" ACHTUNG: Wer rausgenommen wird, merkt es nicht.");
ausgang = 1;
}
await bild(zuschauer.seite, "14-aus-der-sendung");
await roh(`/workspace/api/reaktion/massnahme/${IDS.gast}`, { method: "DELETE", keks: k.admin });
await modi.kontext.close();
await host.kontext.close();
await gast2.kontext.close();
await zuschauer.kontext.close();
+263 -1
View File
@@ -580,7 +580,7 @@ melde("=== 9. Beenden ===");
const c = await roh(CREW, "/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast, rumpf: { text: "Hallo?" },
});
ok(c.code === 409 && c.j?.fehler === "geschlossen",
ok(c.code === 409 && c.j?.fehler === "saal_zu",
`und schreiben geht nicht mehr (${c.code}/${c.j?.fehler})`);
}
@@ -1095,6 +1095,268 @@ melde("=== 14. Keine doppelten Wege ===");
ok(reaktionswege >= 17, `die Reaction bringt ${reaktionswege} eigene Wege mit`);
}
/* =======================================================================
15. MODERATION IM LIVE-CHAT
Der heikelste Teil der ganzen Reaction: Hier kann jemand einem
anderen das Wort nehmen. Geprueft wird deshalb nicht nur, dass es
GEHT, sondern vor allem, wer es NICHT darf und was dabei nicht
herauskommen darf.
======================================================================= */
melde("");
melde("=== 15. Moderation im Live-Chat ===");
{
/* Sauberer Anfang: Der Chat steht auf „offen". */
await roh(CREW, "/workspace/api/reaktion/chatmodus", {
method: "POST", keks: k.admin, rumpf: { modus: "offen" },
});
/* ---- Wer eine Massnahme verhaengen darf ---- */
const zuschauer = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.gast, rumpf: { person_id: IDS.gast2, art: "stumm", minuten: 10 },
});
ok(zuschauer.code === 403 && zuschauer.j?.fehler === "nur_moderation",
`ein Zuschauer schaltet niemanden stumm (${zuschauer.code}/${zuschauer.j?.fehler})`);
/* ---- Nicht gegen das Team ----
Wer einen Modi stummschalten koennte, haette einen Weg, die
Moderation selbst auszuschalten -- mitten in der Sendung. */
const gegenTeam = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.modi, rumpf: { person_id: IDS.linke, art: "stumm", minuten: 10 },
});
ok(gegenTeam.code === 403 && gegenTeam.j?.fehler === "nicht_gegen_team",
`ein Modi schaltet die linke Hand nicht stumm (${gegenTeam.code}/${gegenTeam.j?.fehler})`);
const gegenHost = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.modi, rumpf: { person_id: IDS.admin, art: "raus" },
});
ok(gegenHost.code === 403, `und DogFather erst recht nicht (${gegenHost.code})`);
/* ---- Die Dauer hat eine Obergrenze ---- */
const { STUMM_MAX_MINUTEN, MASSNAHMEN } = await import("./reaktion-tabellen.js");
for (const [min, wort] of [[0, "null"], [-5, "minus"], [STUMM_MAX_MINUTEN + 1, "zu lang"]]) {
const a = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.modi, rumpf: { person_id: IDS.gast2, art: "stumm", minuten: min },
});
ok(a.code === 400 && a.j?.fehler === "dauer_unklar",
`${min} Minuten (${wort}) wird abgelehnt (${a.code})`);
}
const quatsch = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.modi, rumpf: { person_id: IDS.gast2, art: "verbannen" },
});
ok(quatsch.code === 400 && quatsch.j?.fehler === "massnahme_unbekannt",
`eine erfundene Massnahme wird abgelehnt (${quatsch.code})`);
ok(MASSNAHMEN.length === 2 && MASSNAHMEN.includes("stumm") && MASSNAHMEN.includes("raus"),
`es gibt genau zwei kurze Massnahmen: ${MASSNAHMEN.join(", ")}`);
/* ---- Stumm wirkt -- und sagt den richtigen Grund ----
Der Chat steht dabei auf „offen". Genau das ist der Fall, der
vorher die falsche Auskunft gab („Der Chat ist gerade zu"). */
const vorher = await roh(CREW, "/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast2, rumpf: { text: "vorher geht es" },
});
ok(vorher.code === 201, `vor der Massnahme schreibt gast2 (${vorher.code})`);
const stumm = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.modi, rumpf: { person_id: IDS.gast2, art: "stumm", minuten: 10 },
});
ok(stumm.code === 200, `ein Modi schaltet einen Zuschauer stumm (${stumm.code})`);
const nachher = await roh(CREW, "/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast2, rumpf: { text: "und jetzt?" },
});
ok(nachher.code === 403 && nachher.j?.fehler === "stumm_geschaltet",
`danach nicht mehr -- und der Grund stimmt (${nachher.code}/${nachher.j?.fehler})`);
const sichtGast2 = await roh(CREW, "/workspace/api/reaktion", { keks: k.gast2 });
ok(sichtGast2.j?.ich?.darf_schreiben === false
&& sichtGast2.j?.ich?.schreib_grund === "stumm_geschaltet",
"und er steht auch in seinem eigenen Stand");
ok(sichtGast2.j?.ich?.massnahme?.art === "stumm" && !!sichtGast2.j.ich.massnahme.bis,
"mit Art und Ablaufzeitpunkt");
/* ZUSEHEN GEHT WEITER. „stumm" ist nicht „raus" -- wer das
verwechselt, wirft jemanden fuer einen Satz aus der Sendung. */
const nochDabei = await roh(CREW, "/workspace/api/reaktion/dabei", {
method: "POST", keks: k.gast2,
});
ok(nochDabei.code === 200, `zusehen geht weiter (${nochDabei.code})`);
/* ---- Die Massnahmen sind keine oeffentliche Liste ----
In `meldungen` steht der Name dessen, der gemeldet hat. Wer
meldet, muss sich darauf verlassen koennen, dass das niemand
sieht -- sonst meldet beim naechsten Mal keiner mehr. */
ok(Array.isArray(stumm.j?.massnahmen) && stumm.j.massnahmen.length >= 1,
"die Moderation sieht die laufenden Massnahmen");
ok(sichtGast2.j?.massnahmen === null && sichtGast2.j?.meldungen === null,
"ein Zuschauer sieht weder Massnahmen noch Meldungen");
const sichtModi = await roh(CREW, "/workspace/api/reaktion", { keks: k.modi });
ok(Array.isArray(sichtModi.j?.meldungen), "ein Modi schon");
/* GEGENPROBE AM RUNDRUF: `oeffentlich()` muss beide Felder
wegnehmen. Es aus dem Quelltext zu lesen ist hier genauer als
jede Messung -- der Rundruf geht an alle, und ein Fehler darin
waere erst aufgefallen, wenn jemand mitgelesen haette. */
{
const quelle = readFileSync(join(HIER, "workspace-reaktion.js"), "utf8");
const zeile = quelle.match(/const \{([^}]*)\} = l;/);
const weg = (zeile ? zeile[1] : "").split(",").map((x) => x.trim().replace(/\.\.\..*/, ""));
for (const feld of ["zuschauer", "ich", "liste", "meldungen", "massnahmen"]) {
ok(weg.includes(feld), `oeffentlich() nimmt „${feld}" aus dem Rundruf`);
}
}
/* ---- Wieder aufheben ---- */
const auf = await roh(CREW, `/workspace/api/reaktion/massnahme/${IDS.gast2}`, {
method: "DELETE", keks: k.gast,
});
ok(auf.code === 403, `ein Zuschauer hebt sie nicht auf (${auf.code})`);
const auf2 = await roh(CREW, `/workspace/api/reaktion/massnahme/${IDS.gast2}`, {
method: "DELETE", keks: k.modi,
});
ok(auf2.code === 200, `ein Modi schon (${auf2.code})`);
const wieder = await roh(CREW, "/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast2, rumpf: { text: "wieder da" },
});
ok(wieder.code === 201, `Gegenprobe: danach schreibt er wieder (${wieder.code})`);
/* ---- Melden ---- */
const zuMelden = wieder.j.id;
const selbst = await roh(CREW, `/workspace/api/reaktion/chat/${zuMelden}/melden`, {
method: "POST", keks: k.gast2, rumpf: {},
});
ok(selbst.code === 400 && selbst.j?.fehler === "eigener_beitrag",
`den eigenen Beitrag meldet man nicht (${selbst.code})`);
const gemeldet = await roh(CREW, `/workspace/api/reaktion/chat/${zuMelden}/melden`, {
method: "POST", keks: k.gast, rumpf: { grund: "unfreundlich" },
});
ok(gemeldet.code === 201, `ein Zuschauer darf melden (${gemeldet.code})`);
/* ZWEIMAL MELDEN IST EINMAL. Ohne die Sperre koennte einer allein
die Liste fuellen, und die Moderation sieht die echte nicht. */
const nochmal = await roh(CREW, `/workspace/api/reaktion/chat/${zuMelden}/melden`, {
method: "POST", keks: k.gast, rumpf: {},
});
ok(nochmal.code === 200 && nochmal.j?.schon === true,
`zweimal melden zaehlt einmal -- ohne Fehlermeldung (${nochmal.code})`);
const beiModi = await roh(CREW, "/workspace/api/reaktion", { keks: k.modi });
const m = (beiModi.j?.meldungen || []).find((x) => x.beitrag_id === zuMelden);
ok(!!m, "die Meldung steht bei der Moderation");
ok(m?.text === "wieder da" && m?.wer_id === IDS.gast2,
"mit dem Text und der Person, um die es geht");
/* ---- Erledigen ---- */
const nein = await roh(CREW, `/workspace/api/reaktion/meldung/${m.id}/erledigt`, {
method: "POST", keks: k.gast,
});
ok(nein.code === 403, `ein Zuschauer erledigt keine Meldung (${nein.code})`);
const ja = await roh(CREW, `/workspace/api/reaktion/meldung/${m.id}/erledigt`, {
method: "POST", keks: k.modi,
});
ok(ja.code === 200, `ein Modi schon (${ja.code})`);
ok(!(ja.j?.meldungen || []).some((x) => x.id === m.id),
"und sie ist aus der offenen Liste");
const zweimal = await roh(CREW, `/workspace/api/reaktion/meldung/${m.id}/erledigt`, {
method: "POST", keks: k.modi,
});
ok(zweimal.code === 409 && zweimal.j?.fehler === "nicht_offen",
`zweimal erledigen geht nicht (${zweimal.code})`);
/* ---- „raus" heisst raus ---- */
const raus = await roh(CREW, "/workspace/api/reaktion/massnahme", {
method: "POST", keks: k.hand, rumpf: { person_id: IDS.gast2, art: "raus" },
});
ok(raus.code === 200, `die rechte Hand nimmt jemanden aus der Sendung (${raus.code})`);
const rein = await roh(CREW, "/workspace/api/reaktion/dabei", {
method: "POST", keks: k.gast2,
});
ok(rein.code === 403 && rein.j?.fehler === "aus_der_sendung",
`er kommt nicht mehr herein -- und erfaehrt warum (${rein.code}/${rein.j?.fehler})`);
const weg2 = await roh(CREW, "/workspace/api/reaktion/chat", {
method: "POST", keks: k.gast2, rumpf: { text: "hallo?" },
});
ok(weg2.code === 403 && weg2.j?.fehler === "aus_der_sendung",
`und schreiben auch nicht (${weg2.code}/${weg2.j?.fehler})`);
await roh(CREW, `/workspace/api/reaktion/massnahme/${IDS.gast2}`, {
method: "DELETE", keks: k.admin,
});
const zurueck = await roh(CREW, "/workspace/api/reaktion/dabei", {
method: "POST", keks: k.gast2,
});
ok(zurueck.code === 200, `Gegenprobe: aufgehoben, und er ist wieder dabei (${zurueck.code})`);
}
/* =======================================================================
16. WAS DIE SEITE DARAUS MACHT
======================================================================= */
melde("");
melde("=== 16. Rollen und Moderation auf der Seite ===");
{
const js = readFileSync(join(HIER, "..", "workspace", "assets", "js", "reaktion.js"), "utf8");
const css = readFileSync(join(HIER, "..", "workspace", "assets", "css", "reaktion.css"), "utf8");
const html = readFileSync(join(HIER, "..", "workspace", "reaktion.html"), "utf8");
const saetze = readFileSync(join(HIER, "..", "workspace", "assets", "js", "meldung.js"), "utf8");
/* JEDE ROLLE MIT EIGENEM AUSSEHEN BEKOMMT AUCH EINE REGEL.
Ein Abzeichen ohne Stil ist ein Wort ohne Kasten -- es faellt
nicht auf, und damit ist der ganze Zweck weg. */
const abzeichen = [...js.matchAll(/^ {4}(admin|hand|linke|modi): \['([^']+)', '([^']+)'\],/gm)];
ok(abzeichen.length === 4, `vier Rollen tragen ein Abzeichen (${abzeichen.length})`);
for (const [, rolle, wort, marke] of abzeichen) {
ok(wort.length >= 3 && wort.length <= 6, `„${wort}" fuer ${rolle} ist kurz genug`);
ok(css.includes(`.beitrag__rolle[data-rolle="${marke}"]`),
`und „${marke}" hat eine eigene Farbe`);
}
/* GEGENPROBE: Kann diese Pruefung „nein" sagen? */
ok(!css.includes('.beitrag__rolle[data-rolle="gibtesnicht"]'),
"Gegenprobe: eine erfundene Marke hat keine Regel");
/* DAS WORT IST NICHT DER RANG. Filipe steht nie ueber seinem Team --
Woerter wie „Chef" oder „Leitung" haetten hier nichts zu suchen. */
const rangwoerter = ["Chef", "Boss", "Leiter", "Leitung", "Kopf"];
for (const [, , wort] of abzeichen) {
ok(!rangwoerter.includes(wort), `„${wort}" ist kein Rang`);
}
ok(html.includes('id="chat-meldungen"'), "der Meldungs-Knopf steht in der Seite");
ok(css.includes(".schiene__meldungen"), "und hat eine Regel");
ok(js.includes("meldungenZeichnen()") && js.includes("meldungenZeigen"),
"die Seite zeichnet und oeffnet ihn");
/* DIE TIPPZIELE IM MODERATIONSMENUE. Hier wird jemand stumm
geschaltet; ein Fehlgriff trifft den Falschen. */
const knopf = css.match(/\.modmenue__knopf \{[^}]*\}/);
ok(!!knopf && /min-height:\s*44px/.test(knopf[0]),
"jeder Knopf im Moderationsmenue ist 44 px hoch");
/* JEDES FEHLERWORT DES SERVERS HAT EINEN DEUTSCHEN SATZ.
Sonst steht im Chat ein Maschinenwort wie „nicht_gegen_team". */
const server = readFileSync(join(HIER, "workspace-reaktion.js"), "utf8");
const woerter = [...new Set([...server.matchAll(/fehler:\s*"([a-z_0-9]+)"/g)]
.map((x) => x[1]))].filter((w) => w !== "nicht_verfuegbar");
ok(woerter.length > 20, `${woerter.length} Fehlerwoerter im Server gefunden`);
const ohneSatz = woerter.filter((w) => !new RegExp(`^\\s+${w}:`, "m").test(saetze));
ok(ohneSatz.length === 0,
ohneSatz.length ? `OHNE SATZ: ${ohneSatz.join(", ")}` : "alle haben einen deutschen Satz");
/* Die Gegenprobe braucht ein Wort, das es WIRKLICH nicht gibt --
„gibt_es_nicht" steht seit Langem in der Tafel und liess die
Gegenprobe genau das melden, wovor sie warnen sollte. */
ok(!/^\s+zwetschgenknoedel:/m.test(saetze),
"Gegenprobe: ein erfundenes Wort hat keinen Satz");
/* KEIN SCHLUESSEL STEHT ZWEIMAL IN DER SATZTAFEL.
Ein zweiter Eintrag mit demselben Namen gewinnt stillschweigend --
genau so stand am 28.09. in der Hilfe „Der Saal ist zu". */
const schluessel = [...saetze.matchAll(/^ {4}([a-z_0-9]+):/gm)].map((x) => x[1]);
const doppelt = [...new Set(schluessel.filter((x, i) => schluessel.indexOf(x) !== i))];
ok(doppelt.length === 0,
doppelt.length ? `DOPPELT: ${doppelt.join(", ")}` : `${schluessel.length} Saetze, keiner doppelt`);
}
melde("");
melde(`${geprueft} Pruefungen, ${fehler} Fehler`);
melde(fehler === 0 ? "ALLES IN ORDNUNG" : "NICHT IN ORDNUNG");
+56
View File
@@ -83,6 +83,17 @@ export const STAENDE = ["zu", "vorbereitung", "live"];
/** Die Anordnungen des Bildes. */
export const LAYOUTS = ["kino", "gleich", "kamera"];
/** Wie lange eine Stummschaltung hoechstens gilt (Minuten).
*
* Eine Stunde. Wer laenger etwas braucht, nimmt die Massnahmen des
* Treffs -- die haben eine Begruendungspflicht, eine Frist in Tagen
* und stehen in der Geschichte. Eine Stummschaltung ueber Stunden
* waere eine Sperre ohne all das. */
export const STUMM_MAX_MINUTEN = 60;
/** Die zwei kurzen Massnahmen der Sendung. */
export const MASSNAHMEN = ["stumm", "raus"];
/** Wer im Live-Chat schreiben darf.
*
* Filipes Notiz nennt „Chat" als eine der acht Host-Steuerungen.
@@ -165,6 +176,51 @@ export function reaktionTabellen(d) {
weg_von INTEGER REFERENCES personen(id) ON DELETE SET NULL
);
/* ==== DIE KURZEN MASSNAHMEN EINER SENDUNG ====================
„stumm" darf zusehen, aber nicht schreiben. „raus" ist aus
dieser Sendung heraus.
BEIDES ENDET MIT DER SENDUNG -- wie die Gaeste und der
Live-Chat auch. Was laenger gelten soll, gehoert in die
Massnahmen des Treffs: Die haben eine Begruendungspflicht,
eine Frist in Tagen und stehen in der Geschichte. Ein
Fuenf-Minuten-Aerger gehoert dort nicht hinein.
EINE ZEILE JE PERSON. Zwei Massnahmen gegen dieselbe Person
waeren zwei Antworten auf dieselbe Frage -- und dann
entscheidet die Reihenfolge, welche gilt. */
CREATE TABLE IF NOT EXISTS reaktion_massnahmen (
person_id INTEGER PRIMARY KEY REFERENCES personen(id) ON DELETE CASCADE,
art TEXT NOT NULL CHECK (art IN ('stumm','raus')),
/* Leer heisst: bis zum Ende der Sendung. */
bis TEXT,
grund TEXT NOT NULL DEFAULT '',
von INTEGER REFERENCES personen(id) ON DELETE SET NULL,
erstellt TEXT NOT NULL
);
/* Gemeldete Beitraege. Eigene Tabelle und nicht die des Treffs:
Die zeigt auf „eintraege“, hier geht es um „reaktion_chat“ --
ein anderer Gegenstand, und ein Fremdschluessel kann nicht auf
zweierlei zeigen. */
CREATE TABLE IF NOT EXISTS reaktion_meldungen (
id INTEGER PRIMARY KEY AUTOINCREMENT,
beitrag_id INTEGER NOT NULL REFERENCES reaktion_chat(id) ON DELETE CASCADE,
melder_id INTEGER REFERENCES personen(id) ON DELETE SET NULL,
grund TEXT NOT NULL DEFAULT '',
erstellt TEXT NOT NULL,
erledigt_am TEXT,
erledigt_von INTEGER REFERENCES personen(id) ON DELETE SET NULL
);
/* DIESELBE PERSON MELDET DENSELBEN BEITRAG EINMAL. Ohne diese
Sperre koennte einer allein eine Liste fuellen, und die
Moderation sieht vor lauter Meldungen die echte nicht. */
CREATE UNIQUE INDEX IF NOT EXISTS idx_reaktion_meldung_einmal
ON reaktion_meldungen (beitrag_id, melder_id);
CREATE INDEX IF NOT EXISTS idx_reaktion_meldung_offen
ON reaktion_meldungen (erledigt_am, id);
/* Was gelaufen ist. Eine Sendung je Zeile, erst beim Beenden. */
CREATE TABLE IF NOT EXISTS reaktion_verlauf (
id INTEGER PRIMARY KEY AUTOINCREMENT,
+248 -15
View File
@@ -48,8 +48,13 @@ import { einstellung } from "./workspace.js";
import { mitZugangsdaten, wegeAusfaechern } from "./workspace-turn.js";
import {
SICHT_PLAETZE, GAESTE_MAX, TEXT_MAX, SCHREIB_BREMSE, STAENDE, LAYOUTS,
VERLAUF_TAGE, LISTE_MAX, CHAT_MODI,
VERLAUF_TAGE, LISTE_MAX, CHAT_MODI, STUMM_MAX_MINUTEN, MASSNAHMEN,
} from "./reaktion-tabellen.js";
/* DIE SPERREN DES TREFFS GELTEN AUCH HIER. Ein zweites System
daneben hiesse, dass jemand im Treff gesperrt ist und in der
Sendung weiterschreibt -- genau die Luecke, die man erst bemerkt,
wenn sie benutzt wird. */
import { treffSperreLesen } from "./treff-tabellen.js";
export const reaktionRouter = express.Router();
@@ -266,6 +271,22 @@ function lage(person) {
})),
chat_modus: s.chat_modus || "offen",
chat_modi: CHAT_MODI,
/* WAS DIE MODERATION SEHEN MUSS -- und niemand sonst. Eine Liste
von Massnahmen gegen andere ist fuer einen Zuschauer eine
Liste darueber, wer sich danebenbenommen hat. */
meldungen: MODERIERT.has(person.rolle)
? db().prepare(`SELECT m.id, m.beitrag_id, m.grund, m.erstellt,
p.name AS melder, c.text, c.name AS wer, c.person_id AS wer_id, c.weg_am
FROM reaktion_meldungen m
JOIN reaktion_chat c ON c.id = m.beitrag_id
LEFT JOIN personen p ON p.id = m.melder_id
WHERE m.erledigt_am IS NULL ORDER BY m.id`).all()
: null,
massnahmen: MODERIERT.has(person.rolle)
? db().prepare(`SELECT m.person_id, m.art, m.bis, m.grund, p.name
FROM reaktion_massnahmen m JOIN personen p ON p.id = m.person_id
ORDER BY m.erstellt DESC`).all()
: null,
dabei: dabei.length,
/* ==== WER DIE LISTE BEKOMMT -- UND WARUM GENAU DIESE ==========
@@ -301,6 +322,15 @@ function lage(person) {
kamera_aus: !!(dabei.find((d) => d.id === person.id)?.kamera_aus),
mikro_aus: !!(dabei.find((d) => d.id === person.id)?.mikro_aus),
darf_schreiben: darfSchreiben(person, s),
/* Der Grund steht daneben -- die Seite muss ihn nicht raten. */
schreib_grund: schreibGrund(person, s),
/* WER STUMM IST, MUSS ES ERFAHREN. Ein Feld, das sich nicht
beschreiben laesst und schweigt, sieht kaputt aus -- und dann
sucht jemand den Fehler bei sich statt bei seinem Verhalten. */
massnahme: (() => {
const m = massnahmeFuer(person.id);
return m ? { art: m.art, bis: m.bis, grund: m.grund } : null;
})(),
},
/* DIE WARTESCHLANGE SEHEN NUR DIE ZWEI. Sie ist Teil der
Vorbereitung, und Filipe hat dazu gesagt: „nur die zwei sollen
@@ -329,17 +359,55 @@ function lage(person) {
* erst anzubieten. Zwei Rechnungen waeren zwei Gelegenheiten, dass
* ein Feld da ist und mit 403 antwortet -- und das ist eine Falle,
* keine Bedienung. */
function darfSchreiben(person, stand) {
if (stand.stand === "zu") return false;
/** Die kurze Massnahme dieser Sendung -- oder nichts.
*
* ABGELAUFENES ZAEHLT NICHT. Eine Stummschaltung ueber zehn Minuten
* endet nach zehn Minuten, ohne dass jemand etwas tun muss. Eine,
* die von Hand aufgehoben werden muss, bleibt sonst die ganze
* Sendung stehen, weil im Live niemand daran denkt. */
function massnahmeFuer(personId) {
const m = db().prepare("SELECT * FROM reaktion_massnahmen WHERE person_id = ?")
.get(personId);
if (!m) return null;
if (!m.bis) return m;
const ende = Date.parse(m.bis);
if (Number.isFinite(ende) && ende > Date.now()) return m;
db().prepare("DELETE FROM reaktion_massnahmen WHERE person_id = ?").run(personId);
return null;
}
/** WARUM jemand nicht schreiben darf -- oder `null`, wenn er darf.
*
* Der Grund und nicht nur das Ja/Nein, und zwar aus einem Fehler
* heraus: Vorher gab es nur „darf/darf nicht", und der Aufrufer hat
* sich den Grund aus der Chat-Stufe zusammengereimt. Fuer jemanden,
* der stummgeschaltet war, waehrend der Chat offen stand, kam damit
* „Der Chat ist gerade zu" heraus -- eine Auskunft, die nachweisbar
* falsch war und ihn beim naechsten Aufmachen wieder vergeblich
* tippen liess. Wer den Grund kennt, gibt ihn weiter. */
function schreibGrund(person, stand) {
if (stand.stand === "zu") return "saal_zu";
/* ERST DIE SPERREN DES TREFFS. Wer dort eine Pause hat oder
ausgeschlossen ist, schreibt hier auch nicht -- es sind dieselben
Menschen und dieselbe Gemeinschaft. */
try {
if (treffSperreLesen(db(), person.id)) return "treff_massnahme";
} catch { /* gibt es die Tabelle nicht, gilt sie auch nicht */ }
const m = massnahmeFuer(person.id);
if (m) return m.art === "raus" ? "aus_der_sendung" : "stumm_geschaltet";
const modus = stand.chat_modus || "offen";
if (modus === "offen") return true;
if (modus === "offen") return null;
/* „team": wer moderiert, darf. Das ist dieselbe Menge, die auch
Beitraege wegnehmen darf -- wer aufraeumen soll, muss dabei
reden koennen. */
if (modus === "team") return MODERIERT.has(person.rolle);
if (modus === "team") return MODERIERT.has(person.rolle) ? null : "chat_nur_team";
/* „zu": nur die zwei, die die Sendung fuehren. Sonst saesse der
Saal vor einem Fenster, in dem gar nichts mehr passiert. */
return HOST_ROLLEN.has(person.rolle);
return HOST_ROLLEN.has(person.rolle) ? null : "chat_zu";
}
function darfSchreiben(person, stand) {
return schreibGrund(person, stand) === null;
}
function melden(art, daten) {
@@ -481,7 +549,20 @@ reaktionRouter.post("/workspace/api/reaktion/dabei", express.json({ limit: "2kb"
(req, res) => {
try {
const s = sendung();
if (s.stand === "zu") return res.status(409).json({ fehler: "geschlossen" });
if (s.stand === "zu") return res.status(409).json({ fehler: "saal_zu" });
/* WER DRAUSSEN IST, KOMMT NICHT WIEDER HEREIN. Sonst laedt die
Seite neu und ist wieder dabei -- und die Massnahme waere
eine Empfehlung. */
const raus = massnahmeFuer(req.person.id);
if (raus && raus.art === "raus") {
return res.status(403).json({ fehler: "aus_der_sendung" });
}
try {
if (treffSperreLesen(db(), req.person.id)) {
return res.status(403).json({ fehler: "treff_massnahme" });
}
} catch { /* gibt es die Tabelle nicht, gilt sie auch nicht */ }
const schon = db().prepare("SELECT * FROM reaktion_dabei WHERE person_id = ?")
.get(req.person.id);
@@ -814,11 +895,154 @@ reaktionRouter.post("/workspace/api/reaktion/weiter", nurHost, express.json({ li
JEDER SENDER DARF DAS FUER SICH -- Host wie Gast. Ein Gast, der
sein eigenes Bild nicht abschalten kann, muesste den Host darum
bitten. */
/* ---------- Moderation im Live-Chat -------------------------------------
Filipe: „sachen wie stummschaltungen, sperrungen, meldunge und
alles moegliche im chat machen koennen falls sich jemand nicht
benimmt."
WAS HIER PASSIERT, GILT NUR FUER DIESE SENDUNG. Was laenger gelten
soll, gehoert in die Massnahmen des Treffs -- die haben eine
Begruendungspflicht, eine Frist in Tagen und stehen in der
Geschichte. Ein Fuenf-Minuten-Aerger gehoert dort nicht hinein. */
reaktionRouter.post("/workspace/api/reaktion/massnahme", express.json({ limit: "4kb" }),
(req, res) => {
try {
if (!MODERIERT.has(req.person.rolle)) {
return res.status(403).json({ fehler: "nur_moderation" });
}
const art = String(req.body?.art ?? "");
if (!MASSNAHMEN.includes(art)) return res.status(400).json({ fehler: "massnahme_unbekannt" });
const zielId = Number(req.body?.person_id) || 0;
const ziel = db().prepare("SELECT id, name, rolle FROM personen WHERE id = ?").get(zielId);
if (!ziel) return res.status(404).json({ fehler: "nicht_gefunden" });
/* NICHT GEGEN DAS TEAM. Dieselbe Regel wie im Treff: Wer einen
anderen Modi stummschalten koennte, haette einen Weg, die
Moderation selbst auszuschalten -- mitten in der Sendung und
an „Personen & Zugaenge" vorbei, wo diese Entscheidung
hingehoert. */
if (MODERIERT.has(ziel.rolle) || HOST_ROLLEN.has(ziel.rolle)) {
return res.status(403).json({ fehler: "nicht_gegen_team" });
}
let bis = null;
if (art === "stumm") {
const min = Number(req.body?.minuten);
if (!Number.isFinite(min) || min <= 0 || min > STUMM_MAX_MINUTEN) {
return res.status(400).json({ fehler: "dauer_unklar" });
}
bis = new Date(Date.now() + min * 60_000).toISOString();
}
const grund = String(req.body?.grund ?? "").trim().slice(0, 200);
db().prepare(`INSERT INTO reaktion_massnahmen (person_id, art, bis, grund, von, erstellt)
VALUES (?,?,?,?,?,?)
ON CONFLICT(person_id) DO UPDATE SET
art = excluded.art, bis = excluded.bis, grund = excluded.grund,
von = excluded.von, erstellt = excluded.erstellt`)
.run(ziel.id, art, bis, grund, req.person.id, jetzt());
/* „raus" heisst raus: aus dem Saal, aus der Gaesteliste. Sonst
bliebe die Kamera im Bild, waehrend die Person nicht mehr
dabei sein soll. */
if (art === "raus") {
db().prepare("DELETE FROM reaktion_dabei WHERE person_id = ?").run(ziel.id);
db().prepare("DELETE FROM reaktion_gaeste WHERE person_id = ?").run(ziel.id);
}
protokolliere(req.person.id, "reaktion_massnahme",
`${art} gegen ${ziel.name}${bis ? ` bis ${bis.slice(11, 16)}` : ""}`, echteIp(req));
/* DIE PERSON ERFAEHRT ES SELBST -- und zwar sofort. Wer nicht
mehr schreiben kann und nicht weiss warum, sucht den Fehler
bei der Technik. */
stromAn([ziel.id], "reaktion", { was: "massnahme", lage: null });
melden("reaktion", { was: "moderation", lage: oeffentlich(lage(req.person)) });
res.json(lage(req.person));
} catch (fehler) {
console.error("[reaktion] Massnahme:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
reaktionRouter.delete("/workspace/api/reaktion/massnahme/:id(\\d+)", (req, res) => {
try {
if (!MODERIERT.has(req.person.rolle)) {
return res.status(403).json({ fehler: "nur_moderation" });
}
const n = db().prepare("DELETE FROM reaktion_massnahmen WHERE person_id = ?")
.run(Number(req.params.id));
if (!n.changes) return res.status(404).json({ fehler: "nicht_gefunden" });
stromAn([Number(req.params.id)], "reaktion", { was: "massnahme", lage: null });
melden("reaktion", { was: "moderation", lage: oeffentlich(lage(req.person)) });
res.json(lage(req.person));
} catch (fehler) {
console.error("[reaktion] Massnahme weg:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
/** Einen Beitrag melden. Darf jeder -- auch die Community.
*
* DAS IST DER PUNKT DARAN. Die Moderation sieht nicht alles; wer
* mitliest, sieht mehr. Ohne einen Weg fuer die Zusehenden bliebe
* Moderation auf das beschraenkt, was zufaellig jemand vom Team
* gerade gelesen hat. */
reaktionRouter.post("/workspace/api/reaktion/chat/:id(\\d+)/melden",
express.json({ limit: "4kb" }), (req, res) => {
try {
const id = Number(req.params.id);
const b = db().prepare("SELECT * FROM reaktion_chat WHERE id = ?").get(id);
if (!b) return res.status(404).json({ fehler: "nicht_gefunden" });
if (b.person_id === req.person.id) {
return res.status(400).json({ fehler: "eigener_beitrag" });
}
const grund = String(req.body?.grund ?? "").trim().slice(0, 200);
try {
db().prepare(`INSERT INTO reaktion_meldungen (beitrag_id, melder_id, grund, erstellt)
VALUES (?,?,?,?)`).run(id, req.person.id, grund, jetzt());
} catch {
/* Schon gemeldet. Kein Fehler -- wer zweimal tippt, meint
dasselbe, und eine Fehlermeldung dafuer waere eine
Bestrafung fuers Mithelfen. */
return res.json({ ok: true, schon: true });
}
/* Die Moderation erfaehrt es sofort. */
stromAn(
db().prepare(`SELECT id FROM personen WHERE rolle IN ('admin','hand','linke','modi')
AND aktiv = 1`).all().map((p) => p.id),
"reaktion", { was: "meldung" },
);
res.status(201).json({ ok: true });
} catch (fehler) {
console.error("[reaktion] Melden:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
reaktionRouter.post("/workspace/api/reaktion/meldung/:id(\\d+)/erledigt", (req, res) => {
try {
if (!MODERIERT.has(req.person.rolle)) {
return res.status(403).json({ fehler: "nur_moderation" });
}
const n = db().prepare(`UPDATE reaktion_meldungen SET erledigt_am = ?, erledigt_von = ?
WHERE id = ? AND erledigt_am IS NULL`)
.run(jetzt(), req.person.id, Number(req.params.id));
if (!n.changes) return res.status(409).json({ fehler: "nicht_offen" });
res.json(lage(req.person));
} catch (fehler) {
console.error("[reaktion] Meldung erledigt:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
reaktionRouter.post("/workspace/api/reaktion/senden", express.json({ limit: "2kb" }),
(req, res) => {
try {
const s = sendung();
if (s.stand === "zu") return res.status(409).json({ fehler: "geschlossen" });
if (s.stand === "zu") return res.status(409).json({ fehler: "saal_zu" });
const istHost = HOST_ROLLEN.has(req.person.rolle);
const binGast = !!db().prepare("SELECT 1 FROM reaktion_gaeste WHERE person_id = ?")
@@ -910,15 +1134,12 @@ reaktionRouter.post("/workspace/api/reaktion/chat", express.json({ limit: "8kb"
(req, res) => {
try {
const s = sendung();
if (s.stand === "zu") return res.status(409).json({ fehler: "geschlossen" });
if (s.stand === "zu") return res.status(409).json({ fehler: "saal_zu" });
/* DIE STUFE GILT HIER, NICHT NUR IN DER OBERFLAECHE. Ein Feld,
das ausgegraut ist, haelt niemanden auf, der die Schnittstelle
kennt. */
if (!darfSchreiben(req.person, s)) {
return res.status(403).json({
fehler: s.chat_modus === "team" ? "chat_nur_team" : "chat_zu",
});
}
const grund = schreibGrund(req.person, s);
if (grund) return res.status(403).json({ fehler: grund });
const text = String(req.body?.text ?? "").trim().slice(0, TEXT_MAX);
if (!text) return res.status(400).json({ fehler: "leer" });
if (zuSchnell(req.person.id)) return res.status(429).json({ fehler: "zu_schnell" });
@@ -1032,7 +1253,19 @@ export function videoKennung(roh) {
* ohne dass es jemandem auffaellt, weil die Oberflaeche sie ja
* nicht anzeigt. */
function oeffentlich(l) {
const { zuschauer, ich, liste, ...rest } = l;
/* WAS IM RUNDRUF NICHTS ZU SUCHEN HAT.
`zuschauer`, `ich` und `liste` gehoeren nur dem Empfaenger.
`meldungen` und `massnahmen` KAMEN AM 28.09. DAZU -- sie sind
die heikelsten Felder des ganzen Standes: In `meldungen` stehen
der gemeldete Text, der Name des Gemeldeten UND der Name dessen,
der gemeldet hat; in `massnahmen` steht, wer stumm ist und
warum. Der Rundruf wird aus dem Stand DESSEN gebaut, der gerade
etwas getan hat -- und wenn das die Moderation war, gingen beide
Listen an jeden im Saal. Wer meldet, muss sich darauf verlassen
koennen, dass das niemand sieht; sonst meldet beim naechsten Mal
keiner mehr. */
const { zuschauer, ich, liste, meldungen, massnahmen, ...rest } = l;
return rest;
}
+5 -5
View File
@@ -16,8 +16,8 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
<!-- Ohne diese drei nimmt ein iPhone einen Bildschirmausschnitt als
Symbol, Android zeichnet die Leiste weiss, und die Seite oeffnet
ausserhalb der App -- auf einer Seite, die genau erklaeren soll,
@@ -33,7 +33,7 @@
schreibt jede Seite app.webmanifest -- auch die hier. -->
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<style>
/* Bewusst in der Seite und nicht in einer eigenen Datei: Diese Seite
soll auch dann noch etwas anzeigen, wenn genau das schiefgeht,
@@ -135,7 +135,7 @@
<script src="assets/js/anruf-probe.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/anruf-probe.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
</body>
</html>
+4 -4
View File
@@ -23,25 +23,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/workspace-192.png?v=202609280908",
"src": "/assets/img/app-symbole/workspace-192.png?v=202609280931",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-512.png?v=202609280908",
"src": "/assets/img/app-symbole/workspace-512.png?v=202609280931",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609280908",
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609280931",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609280908",
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609280931",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+202
View File
@@ -428,6 +428,208 @@
.beitrag[data-host="ja"] .beitrag__wer { color: var(--an-hell); }
.beitrag[data-team="ja"] .beitrag__wer { color: #9ab7ff; }
/* ==== WER SPRICHT ==================================================
Filipe: „die modis, linke hand und rechte hand soll im chat extra
aussehen."
EIN WORT UND NICHT NUR EINE FARBE. Rund acht Prozent der Männer
unterscheiden Rot und Grün schlecht -- und genau hier hängt an der
Unterscheidung etwas: Ist das jemand vom Team oder irgendwer? Eine
Auskunft, die nur in der Farbe steckt, ist für sie keine.
KLEIN, ABER NICHT ZU KLEIN. 11,5 px ist die Untergrenze des
Hauses; .72rem sind 11,52 px. Darunter wird aus einer Auskunft
eine Andeutung.
UND NICHT GRELL. Der Chat steht neben einem laufenden Video.
Alles, was hier selbst leuchtet, zieht den Blick vom Bild weg --
deshalb gedeckte Töne auf einer sehr schwachen Fläche, kein
Vollton. */
.beitrag__rolle {
font-size: .72rem;
font-weight: 800;
letter-spacing: .06em;
text-transform: uppercase;
padding: 1px 7px 2px;
border-radius: 999px;
border: 1px solid transparent;
white-space: nowrap;
line-height: 1.5;
}
.beitrag__rolle[data-rolle="dogi"] {
color: var(--an-hell);
background: rgba(216, 64, 74, .16);
border-color: rgba(216, 64, 74, .34);
}
.beitrag__rolle[data-rolle="team"] {
color: #9ab7ff;
background: rgba(122, 156, 235, .14);
border-color: rgba(122, 156, 235, .30);
}
.beitrag__rolle[data-rolle="modi"] {
color: #86cdb2;
background: rgba(96, 175, 145, .14);
border-color: rgba(96, 175, 145, .30);
}
/* ---- Der Name als Angriffspunkt der Moderation -------------------
Er sieht aus wie der Name daneben und verrät sich nur beim
Darüberfahren. Ein Knopf, der wie ein Knopf aussieht, stünde in
jeder Zeile des Chats und würde ihn unruhig machen -- und die
Moderation weiß ohnehin, dass sie ihn hat. */
.beitrag__name {
appearance: none;
border: 0; background: none; padding: 0;
font: inherit; color: inherit;
letter-spacing: inherit;
cursor: pointer;
border-bottom: 1px dotted rgba(170, 180, 210, .34);
}
.beitrag__name:hover,
.beitrag__name:focus-visible { color: var(--schrift); border-bottom-color: currentColor; }
.beitrag__melden {
margin-left: auto;
appearance: none; border: 0; background: none;
color: rgba(169, 163, 189, .55);
cursor: pointer; padding: 2px 4px; border-radius: 6px;
font-size: .72rem;
}
.beitrag__melden:hover { color: var(--gleich); background: rgba(224, 161, 58, .12); }
.beitrag__melden:disabled { color: var(--gleich); cursor: default; opacity: .8; }
/* Stehen „weg" und „melden" zusammen, schiebt nur das erste. */
.beitrag__weg ~ .beitrag__melden { margin-left: 0; }
/* ---- Das Menü am Namen -------------------------------------------
Es liegt ÜBER dem Chat und schiebt ihn nicht auseinander. Ein
Menü, das die Liste aufklappt, verschiebt alle Beiträge darunter --
und im Live liest man gerade weiter. */
/* Lage und Groesse setzt das Skript -- siehe `menueHinstellen()`.
Hier steht nur, WIE es aussieht, nicht WO es liegt. */
.modmenue {
position: fixed;
z-index: 400;
overflow-y: auto;
min-width: 13.5rem;
max-width: min(20rem, 78vw);
display: grid;
padding: 5px;
border-radius: 12px;
background: #100e18;
border: 1px solid var(--rand-hell);
box-shadow: 0 14px 34px rgba(0, 0, 0, .55);
}
.modmenue--liste {
min-width: 17rem;
gap: 4px;
}
.modmenue__knopf {
appearance: none; border: 0; background: none;
display: block; width: 100%;
text-align: left;
/* 44 px hoch. Das ist keine Formsache: Hier wird jemand stumm
geschaltet, und ein Fehlgriff trifft den Falschen. */
min-height: 44px;
padding: 10px 12px;
border-radius: 9px;
font: inherit; font-size: .84rem; font-weight: 600;
color: var(--schrift);
cursor: pointer;
text-decoration: none;
}
.modmenue__knopf:hover,
.modmenue__knopf:focus-visible { background: rgba(255, 255, 255, .07); }
.modmenue__knopf--weg { color: var(--schrift-leise); font-weight: 500; }
.modmeldung {
display: grid; gap: 3px;
padding: 9px 10px;
border-radius: 10px;
background: rgba(255, 255, 255, .035);
border: 1px solid var(--rand);
}
.modmeldung__wer {
font-size: .72rem; font-weight: 800;
letter-spacing: .02em; color: var(--schrift-leise);
}
.modmeldung__text {
font-size: .84rem; line-height: 1.4; color: var(--schrift);
overflow-wrap: anywhere;
}
.modmeldung__schon { font-size: .72rem; color: var(--zu); }
.modmeldung__knoepfe { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.modmeldung__knoepfe .modmenue__knopf {
width: auto; flex: 1 1 auto; text-align: center;
font-size: .78rem; padding: 10px 9px;
}
/* ---- Die Zahl im Kopf der Schiene --------------------------------
Sie steht nur da, wenn etwas offen ist. In Gold und nicht in Rot:
Rot gehört in diesem Haus dem Senden, und eine zweite rote Fläche
daneben würde beides entwerten. */
.schiene__meldungen {
appearance: none;
font-size: .72rem; font-weight: 800;
letter-spacing: .04em;
padding: 4px 10px 5px;
min-height: 28px;
border-radius: 999px;
background: rgba(224, 161, 58, .16);
border: 1px solid rgba(224, 161, 58, .38);
color: var(--gleich);
cursor: pointer;
white-space: nowrap;
}
.schiene__meldungen:hover { background: rgba(224, 161, 58, .26); }
.schiene__meldungen[hidden] { display: none; }
/* ==== WER MIT DEM FINGER MODERIERT =================================
Nicht die Bildschirmbreite fragt hier, sondern womit jemand tippt:
Ein Tablet ist 1024 px breit und wird trotzdem mit dem Finger
bedient.
DIE ZWEI ZEICHEN AM BEITRAG WERDEN NICHT GROESSER, SIE BEKOMMEN
EINE FLAECHE. Ein 44 px hoher Knopf in jeder Chatzeile würde die
Schiene aufblähen und den Chat unlesbar machen; eine unsichtbare
Fläche darum herum kostet nichts und trifft genauso.
Nachgerechnet: 20 px hoch plus zweimal 12 px sind 44. */
@media (pointer: coarse) {
.schiene__meldungen { min-height: 44px; }
.beitrag__weg, .beitrag__melden { position: relative; }
.beitrag__weg::after, .beitrag__melden::after {
content: ''; position: absolute; inset: -12px;
}
/* Der Name ist der Angriffspunkt der Moderation -- und in einer
Chatzeile das kleinste Ziel überhaupt. */
.beitrag__name { position: relative; }
.beitrag__name::after { content: ''; position: absolute; inset: -12px -6px; }
}
/* ---- Aus der Sendung ---------------------------------------------
Eine ganze Fläche und kein Hinweisstreifen. Wer rausgenommen ist,
soll nicht daneben weiter zusehen -- und soll auch nicht raten, ob
gerade die Technik hakt. */
.raus {
position: fixed; inset: 0; z-index: 900;
display: grid; align-content: center; justify-items: center;
gap: 10px;
padding: 28px 24px;
text-align: center;
background: #050408;
}
.raus__titel {
margin: 0;
font-size: 1.24rem; font-weight: 800;
color: var(--schrift);
}
.raus__text {
margin: 0; max-width: 34rem;
font-size: .95rem; line-height: 1.6;
color: var(--schrift-leise);
}
.schiene__form {
display: flex; gap: 8px;
padding: 12px 14px;
+31 -4
View File
@@ -197,7 +197,12 @@
'Diesen Zustand gibt es nicht. Möglich sind: zu, Vorbereitung, auf Sendung.',
kein_video:
'Ohne Video keine Sendung. Trag erst ein YouTube-Video ein.',
geschlossen:
/* NICHT „geschlossen". Das Wort gab es schon -- fuer einen
abgeschlossenen Hilfe-Fall -- und ein zweiter Eintrag mit
demselben Schluessel gewinnt einfach: Ab dem Tag stand in der
Hilfe „Der Saal ist zu", und niemand haette den Zusammenhang
gesehen. Ein Wort, ein Satz. */
saal_zu:
'Der Saal ist zu. Sobald DogFather aufmacht, geht es hier weiter.',
person_unklar:
'Diese Person kenne ich nicht. Wähl jemanden aus der Liste.',
@@ -207,9 +212,6 @@
'Es sind schon zwei Gäste dabei. Nimm erst jemanden heraus.',
layout_unbekannt:
'Diese Anordnung gibt es nicht.',
nur_leitung:
'Das dürfen nur DogFather und die rechte Hand – '
+ 'bei Geld entscheidet die Leitung.',
betrag_unklar:
'Dieser Betrag ergibt keinen Sinn. Schreib ihn in Euro, '
+ 'zum Beispiel 5 oder 7,50.',
@@ -217,6 +219,31 @@
'Ohne Namen keine Karte – er steht ja darauf.',
nicht_offen:
'Diese Meldung wartet nicht mehr – jemand hat sie schon entschieden.',
/* ---- Moderation im Live-Chat --------------------------------
Die Sätze sagen WARUM und, wo es einen gibt, den anderen Weg.
„Das darfst du nicht" allein lässt jemanden suchen; „dafür gibt
es den Treff" beendet die Sache. */
nur_moderation:
'Das können nur DogFather, seine Hände und die Modis.',
massnahme_unbekannt:
'Diese Maßnahme gibt es nicht. Möglich sind: stumm und aus der Sendung.',
nicht_gegen_team:
'Gegen jemanden aus dem Team geht das hier nicht. '
+ 'Wenn wirklich etwas ist, gehört das zu „Personen & Zugänge".',
dauer_unklar:
'Eine Stummschaltung geht höchstens eine Stunde. '
+ 'Für länger nimm die Maßnahmen im Treff – die haben eine Begründung und eine Frist.',
eigener_beitrag:
'Deinen eigenen Beitrag musst du nicht melden – du kannst ihn wegnehmen.',
aus_der_sendung:
'Du bist aus dieser Sendung genommen. Das gilt nur für heute.',
stumm_geschaltet:
'Du bist gerade stumm geschaltet. Zusehen geht weiter – '
+ 'in ein paar Minuten kannst du wieder schreiben.',
treff_massnahme:
'Im Treff läuft gerade eine Maßnahme gegen dich. '
+ 'Solange sie läuft, bist du bei der Reaction nicht dabei.',
sendest_nicht:
'Kamera und Mikro schaltet nur, wer gerade sendet – '
+ 'der Host oder ein Gast auf der Bühne.',
+334 -4
View File
@@ -129,6 +129,16 @@
saal.dataset.stand = lage.stand;
document.body.dataset.stand = lage.stand;
meineId = lage.ich.id;
/* WER RAUS IST, SIEHT AB HIER NICHTS MEHR. Die Prüfung steht ganz
oben und nicht am Ende: Alles darunter baut den Saal auf, und
ein Saal, der sich noch aufbaut, während darüber steht „du bist
raus", ist eine widersprüchliche Auskunft. */
if (lage.ich.massnahme && lage.ich.massnahme.art === 'raus') {
rausgenommen('aus_der_sendung');
return;
}
const warSender = binSender;
binSender = lage.ich.host || lage.ich.gast;
/* WER GERADE ZUM SENDER GEWORDEN IST, BAUT SEINE LEITUNGEN NEU AUF.
@@ -933,15 +943,29 @@
}
}
meldungenZeichnen();
const feld = $('chat-feld');
const senden = document.querySelector('.schiene__senden');
const darf = lage.ich.darf_schreiben !== false;
feld.disabled = !darf;
if (senden) senden.disabled = !darf;
feld.placeholder = darf ? 'Sag was …'
: (lage.chat_modus === 'team'
? 'Gerade schreibt nur das Team'
: 'Der Chat ist gerade zu');
/* DER GRUND KOMMT VOM SERVER, er wird hier nicht erraten.
Vorher stand hier eine Ableitung aus der Chat-Stufe -- und die
war für jemanden, der stummgeschaltet war, während der Chat
offen stand, schlicht falsch („Der Chat ist gerade zu"). Wer
die Antwort hat, muss sie nicht rekonstruieren. */
const GRUENDE = {
stumm_geschaltet: 'Du bist gerade stumm geschaltet',
aus_der_sendung: 'Du bist aus dieser Sendung',
treff_massnahme: 'Im Treff läuft eine Maßnahme gegen dich',
chat_nur_team: 'Gerade schreibt nur das Team',
chat_zu: 'Der Chat ist gerade zu',
saal_zu: 'Der Saal ist zu',
};
feld.placeholder = darf
? 'Sag was …'
: (GRUENDE[lage.ich.schreib_grund] || 'Gerade geht das nicht');
$('schiene').dataset.chat = lage.chat_modus || 'offen';
}
@@ -958,6 +982,27 @@
} catch { /* der Chat kommt gleich per Strom nach */ }
}
/* ==== WER SPRICHT ================================================
Filipe: „die modis, linke hand und rechte hand soll im chat
extra aussehen."
EIN ABZEICHEN, KEINE FARBE ALLEIN. Farbe allein ist für rund
acht Prozent der Männer keine Auskunft -- und im Live-Chat ist
genau das die Frage, auf die es ankommt: Ist das jemand vom
Team oder irgendwer?
Die Wörter sind kurz, weil die Schiene schmal ist, und sie
sagen den RANG nicht. „Team" für die Hände, „Modi" für die
Moderation, „Dogi" für den, der sendet. Wer was darf, steht in
der Rechtetafel; hier geht es nur darum, wen man vor sich hat. */
const ABZEICHEN = {
admin: ['Dogi', 'dogi'],
hand: ['Team', 'team'],
linke: ['Team', 'team'],
modi: ['Modi', 'modi'],
};
function beitragBauen(b) {
const li = el('li', 'beitrag');
li.dataset.id = String(b.id);
@@ -966,6 +1011,14 @@
const kopf = el('div', 'beitrag__wer');
kopf.append(el('span', null, b.name));
const abz = ABZEICHEN[b.rolle];
if (abz) {
const marke = el('span', 'beitrag__rolle', abz[0]);
marke.dataset.rolle = abz[1];
kopf.append(marke);
}
/* Wegnehmen darf, wem der Beitrag gehört -- und wer moderiert.
Der Knopf steht nur dort, wo er auch wirkt; ein Knopf, der mit
403 antwortet, ist eine Falle. */
@@ -976,11 +1029,227 @@
weg.addEventListener('click', () => beitragWeg(b.id));
kopf.append(weg);
}
/* MELDEN DARF JEDER -- ausser bei sich selbst.
Das ist der Punkt daran: Die Moderation sieht nicht alles, wer
mitliest schon. Ohne einen Weg für die Zusehenden bliebe
Moderation auf das beschränkt, was zufällig jemand vom Team
gerade gelesen hat. */
if (lage && b.person_id !== lage.ich.id && !lage.ich.moderiert) {
const m = el('button', 'beitrag__melden', 'melden');
m.type = 'button';
m.title = 'Der Moderation zeigen';
m.addEventListener('click', () => beitragMelden(b.id, m));
kopf.append(m);
}
/* DIE MODERATION GREIFT AM NAMEN AN. So machen es alle großen
Chats, und aus gutem Grund: Man sieht den Beitrag, will etwas
gegen die PERSON tun, und der Name ist das, worauf man
ohnehin zeigt. */
if (lage && lage.ich.moderiert && b.person_id && b.person_id !== lage.ich.id) {
kopf.firstChild.replaceWith(namensknopf(b));
}
li.append(kopf);
li.append(el('div', null, b.text));
return li;
}
function namensknopf(b) {
const k = el('button', 'beitrag__name', b.name);
k.type = 'button';
k.title = 'Was tun?';
k.addEventListener('click', () => moderationsMenue(k, b));
return k;
}
/** Das kleine Menü am Namen. Drei Dinge, mehr nicht.
*
* WARUM NICHT MEHR: Im Live entscheidet man in Sekunden. Eine
* Liste mit sieben Möglichkeiten liest niemand zu Ende -- und was
* länger gelten soll als diese Sendung, gehört ohnehin in die
* Maßnahmen des Treffs, wo es eine Begründungspflicht gibt. Der
* Weg dorthin steht als letzter Punkt. */
function moderationsMenue(knopf, b) {
document.querySelector('.modmenue')?.remove();
const menue = el('div', 'modmenue');
menue.setAttribute('role', 'menu');
const tun = (wort, was) => {
const k = el('button', 'modmenue__knopf', wort);
k.type = 'button';
k.addEventListener('click', async () => { menue.remove(); await was(); });
menue.append(k);
};
tun('Beitrag wegnehmen', () => beitragWeg(b.id));
tun('10 Minuten stumm', () => massnahme(b.person_id, 'stumm', 10));
tun('Aus der Sendung', async () => {
const ja = window.frageNach
? await window.frageNach({
titel: `${b.name} aus der Sendung nehmen?`,
text: 'Die Person kann bis zum Ende der Sendung nicht mehr zusehen. '
+ 'Für länger nimm die Maßnahmen im Treff.',
knopf: 'Rausnehmen',
})
: confirm(`${b.name} aus der Sendung nehmen?`);
if (ja) massnahme(b.person_id, 'raus');
});
const treff = el('a', 'modmenue__knopf modmenue__knopf--weg', 'Im Treff sperren …');
treff.href = '/workspace/treff-moderation.html';
treff.target = '_blank';
treff.rel = 'noopener';
menue.append(treff);
menueHinstellen(menue, knopf);
}
/* ==== WARUM DAS MENUE AM KOERPER HAENGT UND NICHT AM KNOPF =========
GEMESSEN, NICHT ÜBERLEGT. Zuerst stand es als Kind der
Beitragszeile da, mit `position: absolute`. Die Rechnung ging
auf: 216 px breit, x=1099..1315 im 1440er Fenster, y=652..840 bei
900 px Höhe — komplett im Bild. Das Bildschirmfoto zeigte
trotzdem einen abgeschnittenen Streifen hinter dem Eingabefeld.
Der Grund: Die Chatliste rollt (`overflow-y: auto`). Ein
absolut gesetztes Kind wird von einem rollenden Vorfahren
BESCHNITTEN, ganz gleich, wo es im Fenster liegt. „Im Fenster"
und „sichtbar" sind zwei verschiedene Fragen, und ich hatte die
falsche gemessen.
Also: fest am Fenster (`position: fixed`), Lage aus dem
tatsächlichen Rechteck des Knopfes gerechnet, und wo unten oder
rechts kein Platz ist, klappt es nach oben bzw. nach links. Und
es geht zu, sobald jemand rollt — sonst stünde es gleich neben
einem ganz anderen Namen. */
function menueHinstellen(menue, anker) {
menue.style.position = 'fixed';
menue.style.visibility = 'hidden';
document.body.append(menue);
const a = anker.getBoundingClientRect();
const m = menue.getBoundingClientRect();
const luft = 8;
let links = a.left;
if (links + m.width > window.innerWidth - luft) links = window.innerWidth - m.width - luft;
if (links < luft) links = luft;
let oben = a.bottom + 6;
/* Passt es unten nicht, klappt es über den Knopf. Passt es auch
dort nicht (kleines Fenster, langes Menü), wird es oben
angesetzt und rollt in sich selbst. */
if (oben + m.height > window.innerHeight - luft) {
const darueber = a.top - m.height - 6;
oben = darueber >= luft ? darueber : luft;
}
menue.style.left = `${Math.round(links)}px`;
menue.style.top = `${Math.round(oben)}px`;
menue.style.maxHeight = `${Math.round(window.innerHeight - oben - luft)}px`;
menue.style.visibility = '';
const zumachen = () => {
menue.remove();
document.removeEventListener('click', beiKlick, true);
window.removeEventListener('resize', zumachen);
document.removeEventListener('scroll', zumachen, true);
};
function beiKlick(e) { if (!menue.contains(e.target) && e.target !== anker) zumachen(); }
setTimeout(() => {
document.addEventListener('click', beiKlick, true);
window.addEventListener('resize', zumachen);
/* `true` -- Rollen steigt nicht auf, es muss beim Einfangen
abgeholt werden, sonst merkt man das Rollen der Chatliste
nicht. */
document.addEventListener('scroll', zumachen, true);
}, 0);
}
async function massnahme(personId, art, minuten) {
const a = await hole('/workspace/api/reaktion/massnahme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ person_id: personId, art, minuten }),
});
if (!a.ok) { melde(await a.json().catch(() => null), 'Das ging nicht.'); return; }
lage = { ...(await a.json()) };
zeichnen();
sagFehler(art === 'stumm' ? 'Für 10 Minuten stumm.' : 'Aus der Sendung genommen.');
}
async function beitragMelden(id, knopf) {
const a = await hole(`/workspace/api/reaktion/chat/${id}/melden`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),
});
if (!a.ok) { melde(await a.json().catch(() => null), 'Das ging nicht.'); return; }
knopf.textContent = 'gemeldet';
knopf.disabled = true;
}
/* ---- Die Meldungen im Kopf der Schiene ----------------------------
Nur für die Moderation, und nur, wenn etwas offen ist. Eine Zahl,
die immer dasteht und meistens null ist, wird nach drei Tagen
nicht mehr gelesen. */
function meldungenZeichnen() {
const knopf = $('chat-meldungen');
if (!knopf) return;
const offen = lage.meldungen || [];
knopf.hidden = !lage.ich.moderiert || offen.length === 0;
knopf.textContent = offen.length === 1 ? '1 Meldung' : `${offen.length} Meldungen`;
}
function meldungenZeigen() {
const offen = lage.meldungen || [];
if (!offen.length) return;
document.querySelector('.modmenue')?.remove();
const menue = el('div', 'modmenue modmenue--liste');
for (const m of offen) {
const zeile = el('div', 'modmeldung');
zeile.append(el('span', 'modmeldung__wer', `${m.wer} — gemeldet von ${m.melder || 'jemandem'}`));
zeile.append(el('span', 'modmeldung__text', m.text));
if (m.weg_am) zeile.append(el('span', 'modmeldung__schon', 'schon weggenommen'));
const reihe = el('div', 'modmeldung__knoepfe');
if (!m.weg_am) {
const weg = el('button', 'modmenue__knopf', 'Wegnehmen');
weg.type = 'button';
weg.addEventListener('click', async () => {
await beitragWeg(m.beitrag_id);
await erledigt(m.id);
});
reihe.append(weg);
}
const stumm = el('button', 'modmenue__knopf', '10 Min stumm');
stumm.type = 'button';
stumm.addEventListener('click', async () => {
await massnahme(m.wer_id, 'stumm', 10);
await erledigt(m.id);
});
reihe.append(stumm);
const ok = el('button', 'modmenue__knopf modmenue__knopf--weg', 'Passt schon');
ok.type = 'button';
ok.addEventListener('click', () => erledigt(m.id));
reihe.append(ok);
zeile.append(reihe);
menue.append(zeile);
}
menueHinstellen(menue, $('chat-meldungen'));
}
async function erledigt(id) {
const a = await hole(`/workspace/api/reaktion/meldung/${id}/erledigt`, { method: 'POST' });
if (!a.ok) { melde(await a.json().catch(() => null), 'Das ging nicht.'); return; }
lage = { ...(await a.json()) };
document.querySelector('.modmenue')?.remove();
zeichnen();
}
async function beitragWeg(id) {
try {
const a = await hole('/workspace/api/reaktion/chat/' + id, { method: 'DELETE' });
@@ -1943,6 +2212,26 @@
const d = JSON.parse(e.data);
if (d.was === 'video') { folgen(d); return; }
if (d.was === 'layout') { $('teil-live').dataset.layout = d.layout; return; }
/* ==== MODERATION ==========================================
Drei Meldungen ohne Stand im Gepäck, und alle drei aus
demselben Grund: Was sie betrifft, steht NICHT im Rundruf.
`meldungen` und `massnahmen` sind aus `oeffentlich()`
ausgenommen, weil dort der gemeldete Text und der Name des
Melders stehen. Wer sie sehen darf, holt sie sich selbst. */
if (d.was === 'massnahme') { standHolen(); return; }
if (d.was === 'meldung') {
if (lage && lage.ich.moderiert) standHolen();
return;
}
if (d.was === 'moderation') {
if (lage && lage.ich.moderiert) standHolen();
/* Für alle anderen ist trotzdem etwas passiert: Wer gerade
stumm geschaltet wurde, erfährt es über den eigenen
Stand, und wer rausgenommen wurde, muss es sofort sehen. */
return;
}
if (d.lage) {
/* Der Rundruf enthält keine Namensliste und kein „ich" --
beides gehört nur dem Empfänger. Was hier ankommt, wird
@@ -2045,6 +2334,17 @@
lage = neu;
zeichnen();
draehteNachziehen();
return;
}
/* HINAUSGENOMMEN ODER GESPERRT. Ohne diesen Zweig läuft das
Video weiter, der Saal sieht normal aus, und nur die
Anwesenheit schlägt still fehl -- die Person wäre
„rausgenommen" und würde davon nichts merken. Das ist
dieselbe Sorte Fehler wie ein stummes Eingabefeld: Es sieht
aus wie ein Defekt, nicht wie eine Entscheidung. */
if (a.status === 403) {
const wort = (await a.json().catch(() => null))?.fehler;
if (wort === 'aus_der_sendung' || wort === 'treff_massnahme') rausgenommen(wort);
}
} catch { /* der nächste Takt versucht es wieder */ }
};
@@ -2170,6 +2470,34 @@
/* =================================================================
LOS
================================================================= */
/** Aus der Sendung -- und das wird auch gesagt.
*
* Drei Dinge müssen zusammen passieren, sonst bleibt ein Rest:
* Der Takt hört auf (sonst klopft er alle 30 Sekunden gegen eine
* geschlossene Tür), die Leitungen gehen weg (sonst stünde die
* eigene Kamera weiter im Bild der anderen), und das Video hält an
* (sonst läuft die Sendung hinter der Meldung weiter). */
function rausgenommen(wort) {
if (document.body.dataset.raus === 'ja') return;
document.body.dataset.raus = 'ja';
clearInterval(dabeiUhr);
try { draehteWeg(); } catch { /* es gab vielleicht keine */ }
try { if (spieler && spielerBereit) spieler.pauseVideo(); } catch { /* egal */ }
try { if (strom) strom.close(); } catch { /* war schon zu */ }
const kasten = el('div', 'raus');
kasten.setAttribute('role', 'alert');
kasten.append(el('h2', 'raus__titel',
wort === 'treff_massnahme' ? 'Du bist gerade gesperrt' : 'Du bist aus der Sendung'));
kasten.append(el('p', 'raus__text',
wort === 'treff_massnahme'
? 'Im Treff läuft eine Maßnahme gegen dich. Solange sie läuft, bist du '
+ 'bei der Reaction nicht dabei. Was los ist, steht im Treff unter „Meine Maßnahmen".'
: 'Die Moderation hat dich aus dieser Sendung genommen. Das gilt nur für heute — '
+ 'bei der nächsten Reaction bist du wieder dabei.'));
document.body.append(kasten);
}
async function standHolen() {
const a = await hole('/workspace/api/reaktion');
if (!a.ok) { sagFehler('Die Reaction ist gerade nicht erreichbar.'); return; }
@@ -2196,6 +2524,8 @@
() => sendenSchalten('mikro', !lage.ich.mikro_aus));
/* Die Chat-Stufe -- nur fuer die zwei */
$('chat-meldungen')?.addEventListener('click', meldungenZeigen);
for (const k of $('chat-stufen').children) {
k.addEventListener('click', async () => {
const a = await hole('/workspace/api/reaktion/chatmodus', {
+19 -19
View File
@@ -12,19 +12,19 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -391,22 +391,22 @@
<!-- TEXTFORM ZUERST (21.09.2026): Die Seite fragt beim Zeichnen nach
`window.Textform`. Kaeme sie spaeter, waere der erste Eintrag ohne
Gestaltung. Kein `defer`, damit sie wirklich vorher dasteht. -->
<script src="assets/js/textform.js?v=202609280908"></script>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/textform.js?v=202609280931"></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/zuteilung.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/zuteilung.js?v=202609280931" defer></script>
<!-- Der Vorlagenkatalog stand bis zum 23.09.2026 mitten in
aufgaben.js. Er bedient jetzt zwei Seiten und hat deshalb eine
eigene Datei; hier zeigt er den Creator-Katalog.
Vor aufgaben.js, weil die Seite ihn beim Start einrichtet. -->
<script src="assets/js/vorlagenbrett.js?v=202609280908" defer></script>
<script src="assets/js/aufgaben.js?v=202609280908" defer></script>
<script src="assets/js/vorlagenbrett.js?v=202609280931" defer></script>
<script src="assets/js/aufgaben.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -168,15 +168,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/automation.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/automation.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -197,16 +197,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/befinden.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/befinden.js?v=202609280931" defer></script>
</body>
</html>
+22 -22
View File
@@ -12,24 +12,24 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280931" />
<!-- Wegen des Blocks „Willst du dazugehoeren?" auf dem Brett
„Mitmachen". Eine eigene Kopie der Regel hier waere die zweite
Stelle, an der dieselbe Sache anders aussieht. -->
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -304,19 +304,19 @@
<!-- TEXTFORM ZUERST (21.09.2026): Die Seite fragt beim Zeichnen nach
`window.Textform`. Kaeme sie spaeter, waere der erste Eintrag ohne
Gestaltung. Kein `defer`, damit sie wirklich vorher dasteht. -->
<script src="assets/js/textform.js?v=202609280908"></script>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/textform.js?v=202609280931"></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/checkliste.js?v=202609280908" defer></script>
<script src="assets/js/ampel.js?v=202609280908" defer></script>
<script src="assets/js/schulung.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/bereich.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/checkliste.js?v=202609280931" defer></script>
<script src="assets/js/ampel.js?v=202609280931" defer></script>
<script src="assets/js/schulung.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/bereich.js?v=202609280931" defer></script>
</body>
</html>
+19 -19
View File
@@ -7,17 +7,17 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -108,15 +108,15 @@
</main>
<!-- Der Fuß gehört zu jeder Seite - siehe pruef-css-klassen. -->
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/auskunft.js?v=202609280908" defer></script>
<script src="assets/js/bewerben.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/auskunft.js?v=202609280931" defer></script>
<script src="assets/js/bewerben.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -7,16 +7,16 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -80,16 +80,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/auskunft.js?v=202609280908" defer></script>
<script src="assets/js/bewerbungen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/auskunft.js?v=202609280931" defer></script>
<script src="assets/js/bewerbungen.js?v=202609280931" defer></script>
</body>
</html>
+1 -1
View File
@@ -47,6 +47,6 @@
</head>
<body>
<div id="platz"></div>
<script src="assets/js/buehne.js?v=202609280908" defer></script>
<script src="assets/js/buehne.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -89,15 +89,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/ki.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/calls.js?v=202609280908" defer></script>
<script src="assets/js/ki.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/calls.js?v=202609280931" defer></script>
</body>
</html>
+20 -20
View File
@@ -12,26 +12,26 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
Dialog zu sehen bekam. -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -739,24 +739,24 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609280908"></script>
<script src="assets/js/bereiche.js?v=202609280931"></script>
<!-- TEXTFORM VOR ALLEM ANDEREN (21.09.2026): chat.js und bereich.js
fragen beim Zeichnen nach `window.Textform`. Kaeme sie spaeter,
waere die erste gezeichnete Nachricht ohne Gestaltung -- und das
faellt nur dem auf, der genau hinsieht. KEIN `defer`, damit sie
wirklich vor den anderen dasteht. -->
<script src="assets/js/textform.js?v=202609280908"></script>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908"></script>
<script src="assets/js/glocke.js?v=202609280908"></script>
<script src="assets/js/textform.js?v=202609280931"></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931"></script>
<script src="assets/js/glocke.js?v=202609280931"></script>
<!-- ANRUF VOR CHAT (18.09.2026): anruf.js stellt `window.anrufStarten`
bereit, und chat.js baut die Knoepfe nur, wenn es das gibt.
Andersherum waere die Reihenfolge eine stille Abhaengigkeit --
die Knoepfe fehlten, und niemand wuesste warum. -->
<script src="assets/js/anruf.js?v=202609280908"></script>
<script src="assets/js/anruf.js?v=202609280931"></script>
<!-- DIE BILDSCHAU (25.09.2026). Eigene Datei, weil sie nichts vom
Chat weiss: Sie bekommt einen Weg und einen Namen und zeigt ein
Bild. Jede andere Seite mit Fotos kann sie ebenso benutzen, ohne
@@ -767,8 +767,8 @@
sie beim ersten Foto noch nicht da -- und der erste Klick ginge
wie frueher in den Tab. Ein Fehler, der nur beim ERSTEN Mal
auftritt, ist der, den man nie nachstellen kann. -->
<script src="assets/js/bildschau.js?v=202609280908"></script>
<script src="assets/js/chat.js?v=202609280908"></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/bildschau.js?v=202609280931"></script>
<script src="assets/js/chat.js?v=202609280931"></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/content.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/content.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -179,15 +179,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/checkliste.js?v=202609280908" defer></script>
<script src="assets/js/content.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/checkliste.js?v=202609280931" defer></script>
<script src="assets/js/content.js?v=202609280931" defer></script>
</body>
</html>
+6 -6
View File
@@ -36,15 +36,15 @@
<link rel="preload" as="image" href="assets/img/buehne/crew-gate-hoch-580.webp"
type="image/webp" media="(max-width: 899px)" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<!-- Diese Wand steht NUR auf der Adresse von Team Dogi (ueberall sonst
404, siehe crewWeiche). Sie darf das Haus deshalb direkt nennen
statt ueber den Platzhalter haus.css zu gehen -- und sie MUSS es:
Eine Zugangswand, die sich erst nach dem Umbiegen faerbt, waere
die eine Seite, auf der man das Umfaerben sieht. -->
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609280931" />
</head>
<body class="gate gate--crew">
@@ -459,7 +459,7 @@
<script src="assets/js/gate.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/gate.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
</body>
</html>
+4 -4
View File
@@ -23,25 +23,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609280908",
"src": "/assets/img/app-symbole/crew-192.png?v=202609280931",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609280908",
"src": "/assets/img/app-symbole/crew-512.png?v=202609280931",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609280908",
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609280931",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609280908",
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609280931",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -108,15 +108,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/dateien.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/dateien.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -297,20 +297,20 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<!-- VOR entwicklung.js: Die Seite richtet den Katalog beim Start ein,
also muss es ihn zu dem Zeitpunkt geben. Mit "defer" laufen beide
in Dokumentreihenfolge. -->
<script src="assets/js/vorlagenbrett.js?v=202609280908" defer></script>
<script src="assets/js/entwicklung.js?v=202609280908" defer></script>
<script src="assets/js/vorlagenbrett.js?v=202609280931" defer></script>
<script src="assets/js/entwicklung.js?v=202609280931" defer></script>
</body>
</html>
+15 -15
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -146,14 +146,14 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/hilfe.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/hilfe.js?v=202609280931" defer></script>
</body>
</html>
+5 -5
View File
@@ -30,9 +30,9 @@
<link rel="preload" as="image" href="assets/img/buehne/gate-hoch-580.webp"
type="image/webp" media="(max-width: 899px)" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
</head>
<body class="gate">
@@ -427,7 +427,7 @@
<script src="assets/js/gate.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/gate.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -383,15 +383,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/kalender.js?v=202609280908" defer></script>
<script src="assets/js/kalender-abo.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/kalender.js?v=202609280931" defer></script>
<script src="assets/js/kalender-abo.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -444,13 +444,13 @@
</form>
</dialog>
<script src="assets/js/meldung.js?v=202609280908"></script>
<script src="assets/js/nachfrage.js?v=202609280908"></script>
<script src="assets/js/wahl.js?v=202609280908"></script>
<script src="assets/js/bereiche.js?v=202609280908"></script>
<script src="assets/js/kopf.js?v=202609280908"></script>
<script src="assets/js/glocke.js?v=202609280908"></script>
<script src="assets/js/leistung.js?v=202609280908"></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931"></script>
<script src="assets/js/nachfrage.js?v=202609280931"></script>
<script src="assets/js/wahl.js?v=202609280931"></script>
<script src="assets/js/bereiche.js?v=202609280931"></script>
<script src="assets/js/kopf.js?v=202609280931"></script>
<script src="assets/js/glocke.js?v=202609280931"></script>
<script src="assets/js/leistung.js?v=202609280931"></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,13 +12,13 @@
vergessen wird. -->
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/material.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/material.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start" data-ton="42" data-buehne="studio">
@@ -138,14 +138,14 @@
<p class="m-laedt" id="laedt">Einen Moment …</p>
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/material.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/material.js?v=202609280931" defer></script>
</body>
</html>
+14 -14
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/notizen.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/notizen.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start" data-ton="46">
@@ -181,12 +181,12 @@
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
liest daraus die Leitungsrollen. -->
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/notizen.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/notizen.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -453,14 +453,14 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/personen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/personen.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -214,16 +214,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/steckbrief.js?v=202609280908" defer></script>
<script src="assets/js/profil.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/steckbrief.js?v=202609280931" defer></script>
<script src="assets/js/profil.js?v=202609280931" defer></script>
</body>
</html>
+23 -17
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/reaktion.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/reaktion.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start reaktion-seite" data-stand="laedt">
@@ -190,6 +190,12 @@
<h2 class="schiene__titel">Live-Chat</h2>
<span class="schiene__zahl" id="chat-zahl">0</span>
<!-- WAS GEMELDET WURDE. Steht nur da, wenn etwas offen ist —
eine Zahl, die immer sichtbar und meistens null ist, wird
nach drei Tagen nicht mehr gelesen. Nur für die
Moderation. -->
<button type="button" class="schiene__meldungen" id="chat-meldungen" hidden></button>
<!-- DIE CHAT-STUFE STEHT DORT, WO DER CHAT IST, und nicht im
Regiepult. Man moderiert, wo man liest — ein Umweg über
ein Register wäre in dem Moment, in dem es laut wird,
@@ -486,14 +492,14 @@
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
liest daraus die Leitungsrollen. -->
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/spendenkarte.js?v=202609280908" defer></script>
<script src="assets/js/reaktion.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/spendenkarte.js?v=202609280931" defer></script>
<script src="assets/js/reaktion.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -134,14 +134,14 @@
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
die seit dem 07.09. jede Seite danach absucht. -->
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/rechte.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/rechte.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/report.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/report.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -106,17 +106,17 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/ki.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/report.js?v=202609280908" defer></script>
<script src="assets/js/ki.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/report.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -173,14 +173,14 @@
</div>
</div>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/scouting.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/scouting.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,21 +12,21 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<!-- Nur die Startseite: Begrüßungskachel, Uhr, Glockenmulde. Siehe
den Hinweis in start.css -- dort stand es bis zum 07.09.2026. -->
<link rel="stylesheet" href="assets/css/heim.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -732,16 +732,16 @@
</p>
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/live.js?v=202609280908" defer></script>
<script src="assets/js/start.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/live.js?v=202609280931" defer></script>
<script src="assets/js/start.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -85,16 +85,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/ki.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/startcheck.js?v=202609280908" defer></script>
<script src="assets/js/ki.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/startcheck.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -150,16 +150,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/auskunft.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/steckbrief.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/auskunft.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/steckbrief.js?v=202609280931" defer></script>
</body>
</html>
+14 -14
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/support.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/support.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -128,16 +128,16 @@
(reading 'LEITUNG')" ab -- gemessen am 24.09.2026, als diese
Zeile beim Anlegen der Seite fehlte. Die Kopfleiste kam
trotzdem, deshalb sah man es nur in der Browserkonsole. -->
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<!-- wahl.js gehoert zu kopf.js: Der Sicht-Umschalter in der
Kopfleiste baut daraus seine Liste. pruef-css-klassen setzt das
seit dem 07.09.2026 durch -- damals fehlte es auf chat.html und
uebersicht.html, und heute hier. -->
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/support.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/support.js?v=202609280931" defer></script>
</body>
</html>
+3 -3
View File
@@ -23,7 +23,7 @@
„Eigenes CSS" leer lassen (der Grund ist schon
durchsichtig).
====================================================================== -->
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/spendenkarte.css?v=202609280931" />
<style>
/* DURCHSICHTIG BIS AUF DIE KARTEN. OBS legt die Quelle über das
Bild; jede Fläche, die hier steht, deckt dort etwas zu. */
@@ -80,7 +80,7 @@
<body>
<div class="obs-tafel spendentafel" id="tafel" aria-live="polite"></div>
<script src="assets/js/spendenkarte.js?v=202609280908" defer></script>
<script src="assets/js/tafel.js?v=202609280908" defer></script>
<script src="assets/js/spendenkarte.js?v=202609280931" defer></script>
<script src="assets/js/tafel.js?v=202609280931" defer></script>
</body>
</html>
+18 -18
View File
@@ -7,18 +7,18 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280931" />
<!-- Wegen des Kastens „Anfragen“ ueber der Liste. Eine eigene Kopie
der Regel hier waere die zweite Stelle, an der dieselbe Sache
anders aussieht. -->
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -111,15 +111,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/talente.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/talente.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -7,20 +7,20 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/team.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/team.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -110,15 +110,15 @@
</main>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/team.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/team.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -7,20 +7,20 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/team.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/team.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<!-- `data-buehne` steht hier fest und nicht im Skript: Die Kachel zu
@@ -84,15 +84,15 @@
Kaputt ist dabei nichts -- er funktioniert. Genau deshalb faellt
es niemandem auf, und deshalb prueft pruef-css-klassen die
ABHAENGIGKEIT statt der Optik. Hier hat sie angeschlagen. -->
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/teamlage.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<script src="assets/js/teamlage.js?v=202609280931" defer></script>
</body>
</html>
+15 -15
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -112,15 +112,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/teilen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/teilen.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -126,14 +126,14 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/treff-moderation.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/treff-moderation.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -7,18 +7,18 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein. Auf der Adresse des
Rudels biegt der Server genau diesen Dateinamen auf crew-haus.css
um, und die Seite kommt schon beim ERSTEN Abruf in Lila und
Babyblau an -- ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -248,14 +248,14 @@
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
die seit dem 07.09. jede Seite danach absucht. -->
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/auskunft.js?v=202609280908" defer></script>
<script src="assets/js/treff-regeln.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/auskunft.js?v=202609280931" defer></script>
<script src="assets/js/treff-regeln.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -12,22 +12,22 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -149,16 +149,16 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/uebersicht.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/uebersicht.js?v=202609280931" defer></script>
</body>
</html>
+15 -15
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -335,14 +335,14 @@
</main>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/live.js?v=202609280908" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/live.js?v=202609280931" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -7,13 +7,13 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/unterstuetzen.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/unterstuetzen.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -106,17 +106,17 @@
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
liest daraus die Leitungsrollen. Ohne sie stürzt jede Seite mit
„Cannot read properties of undefined (reading 'LEITUNG')" ab. -->
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/holen.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/holen.js?v=202609280931" defer></script>
<!-- Die Satz-Tafel. Ohne sie stand auf dieser Seite das Maschinenwort
des Servers (z.B. "nicht_gefunden") statt eines Satzes -- gemeldet
von pruef-meldungen, nicht beim Ansehen. -->
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/unterstuetzen.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/unterstuetzen.js?v=202609280931" defer></script>
</body>
</html>
+16 -16
View File
@@ -7,15 +7,15 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -144,14 +144,14 @@
</main>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/werdegang.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/werdegang.js?v=202609280931" defer></script>
</body>
</html>
+15 -15
View File
@@ -12,13 +12,13 @@
vergessen wird. -->
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<!-- KOERPERKLASSE "start", NICHT "gate" (berichtigt 21.09.2026).
`body.gate` ist die Anmeldewand: `display:flex; align-items:center`,
@@ -75,13 +75,13 @@
<p class="fehler" id="fehler" hidden></p>
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/willkommen.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/willkommen.js?v=202609280931" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280908" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280908" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280908" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280931" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280931" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/start.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609280931" />
<link rel="stylesheet" href="assets/css/module.css?v=202609280931" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609280908" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609280931" />
</head>
<body class="start">
@@ -190,15 +190,15 @@
</main>
<script src="assets/js/meldung.js?v=202609280908" defer></script>
<script src="assets/js/hochladen.js?v=202609280908" defer></script>
<script src="assets/js/nachfrage.js?v=202609280908" defer></script>
<script src="assets/js/meldung.js?v=202609280931" defer></script>
<script src="assets/js/hochladen.js?v=202609280931" defer></script>
<script src="assets/js/nachfrage.js?v=202609280931" defer></script>
<script src="assets/js/wahl.js?v=202609280908" defer></script>
<script src="assets/js/bereiche.js?v=202609280908" defer></script>
<script src="assets/js/installieren.js?v=202609280908" defer></script>
<script src="assets/js/kopf.js?v=202609280908" defer></script>
<script src="assets/js/glocke.js?v=202609280908" defer></script>
<script src="assets/js/wissen.js?v=202609280908" defer></script>
<script src="assets/js/wahl.js?v=202609280931" defer></script>
<script src="assets/js/bereiche.js?v=202609280931" defer></script>
<script src="assets/js/installieren.js?v=202609280931" defer></script>
<script src="assets/js/kopf.js?v=202609280931" defer></script>
<script src="assets/js/glocke.js?v=202609280931" defer></script>
<script src="assets/js/wissen.js?v=202609280931" defer></script>
</body>
</html>