Chat: Sprachnachrichten -- und ein stiller Fehler, der jedes Foto betraf

Filipe: "dan will ich auch dass man im chat auch sprachnachrichten und
gifts reinschicken kann. also nur die modis rechte linke hand und
dogfather."

Dieser Commit macht die Sprachnachrichten. Die GIFs kommen als
naechstes -- ich lese "gifts" als GIFs und sage das ausdruecklich,
statt es stillschweigend anzunehmen.

AUFNEHMEN: TIPPEN, NICHT HALTEN
-------------------------------
Gedruecktbleiben ist der bekanntere Weg und der schlechtere: Wer beim
Sprechen verrutscht, verliert die ganze Aufnahme, und mit einer Hand am
Kaffee haelt niemand neunzig Sekunden still. Einmal tippen startet, das
Haekchen schickt, das Kreuz verwirft.

Drei Minuten Hoechstdauer, danach stoppt sie von selbst -- und schickt
NICHT von selbst ab. Wer die Grenze erreicht, hat gerade mitten im Satz
aufgehoert; das ungefragt zu verschicken waere die schlechteste Sekunde
dafuer.

Unter einer Sekunde wird gar nichts geschickt: Das ist ein Versehen,
kein Inhalt.

Die Aufnahmespur wird beim Beenden UND beim Verlassen der Seite
geschlossen. Ein Mikrofon, das offen bleibt, ist ein Vertrauensbruch,
auch wenn niemand zuhoert.

DREI BEHAELTER, WEIL DIE GERAETE DREI LIEFERN
---------------------------------------------
WebM/Opus (Chrome, Android), MP4/AAC (Safari, iPhone), Ogg/Opus
(Firefox). Wer nur einen nimmt, baut eine Funktion, die bei der Haelfte
des Teams stumm bleibt -- und zwar ohne Fehlermeldung.

DER BEHAELTER ALLEIN GENUEGT NICHT: WebM und MP4 tragen genauso gut
Video. Ein Video, das als "Ton" durchginge, landete in einem
Abspielgeraet ohne Bild -- es liefe, man hoerte etwas, und niemand
wuesste, dass die Haelfte fehlt. Die Erkennung sieht deshalb auf die
KENNUNG DER SPUR: Videospur -> abgelehnt, keine Tonspur -> abgelehnt.

Kein MP3: Kein Aufnahmegeraet im Browser erzeugt MP3. Es zuzulassen
hiesse, eine Tuer fuer Musikdateien aufzumachen, nach der niemand
gefragt hat.

"ALSO NUR" IST DER PUNKT
------------------------
Fotos und PDF darf jeder schicken, auch Creator -- das war eine
Entscheidung vom 09.09. und bleibt. Ton nicht. Geprueft wird in der
Route (istTeamDogi), nicht nur im Browser: Ein ausgeblendeter Knopf ist
eine Bitte, abgelehnt wird erst am Server.

Eigene Byte-Grenze fuer Ton (4 MB statt 12). Zwoelf Megabyte sind fuer
ein Foto richtig und fuer eine Sprachnachricht sinnlos -- das waeren
rund fuenfzig Minuten am Stueck.

Die Laenge kommt vom Absender und ist damit eine BEHAUPTUNG, keine
Messung; das steht so an der Spalte. Sie dient nur der Vorschau, bis
das Abspielgeraet die wahre Laenge kennt. Was schuetzt, sind die Bytes.

"FOTO"/"PDF" STAND AN VIER STELLEN
----------------------------------
Dieselbe Aufzaehlung in Gespraechsliste, Zitat, angehefteter Nachricht
und Benachrichtigung -- jede mit ihrem eigenen Fragezeichen-Doppelpunkt.
Mit der Sprachnachricht waeren es vier Aenderungen gewesen, und die
vierte ist die, die man vergisst. Jetzt anhangWort() an einer Stelle.

DER FUND: JEDES FOTO MELDETE "KEINE VERBINDUNG"
-----------------------------------------------
Beim Anfassen derselben Funktion aufgefallen: In `anhangSchicken` stand
seit dem 19.09. `const { nachricht } = e.daten;` -- ein `e`, das es
dort nicht gibt (gemeint war `ergebnis`). Die Zeile wirft, der `catch`
daneben faengt, und der Absender liest:

    "Keine Verbindung -- der Anhang wurde nicht geschickt."

Das Foto war aber da. Es kam Sekunden spaeter ueber den Ereignisstrom
in den Verlauf, mit einer roten Meldung darueber, die das Gegenteil
behauptet -- und der getippte Begleitsatz blieb im Feld stehen, also
schickt man es noch einmal.

WARUM DAS VIER TAGE UNBEMERKT BLIEB, und das ist der lehrreiche Teil:
pruef-chat-anhaenge war die ganze Zeit gruen. Sie schickt mit `fetch`
an die Route -- der bequeme Weg, und er prueft den Server gruendlich.
Sie prueft aber nicht den Weg, den ein Mensch geht. Der Fehler lag
hinter der Bueroklammer, und dort hat nie jemand hingesehen. Dazu
fuehlt er sich wie ein Netzproblem an -- und Netzprobleme sucht niemand
im Programm.

Jetzt geht ein Block durch das Dateifeld selbst und sieht auf das, was
der Mensch danach sieht: steht dort eine Meldung, und ist das Feld
leer? Gegenprobe gefahren -- mit dem alten Fehler wieder eingesetzt
werden genau diese zwei Zeilen rot, mit dem Wortlaut von oben.

Uebernommen wird eine frisch geschickte Nachricht jetzt an EINER
Stelle (nachrichtUebernehmen), fuer Anhang und Sprachnachricht. Zwei
Fassungen waeren zwei Gelegenheiten fuer denselben Fehler.

AUGENSCHONEND
-------------
Kein Blinkpunkt waehrend der Aufnahme -- der ist genau das, was die
Hausregel ausschliesst. Der Punkt atmet langsam (1,8 s, 45 bis 100 %)
und steht bei prefers-reduced-motion ganz still; die laufende Zeit
daneben traegt die Auskunft ohnehin.

Die Farben der Sprachnachricht-Blase kommen aus `--blase-leise`, der
fuer DIESE Blase ausgerechneten leisen Schrift. Eine feste Farbe waere
dieselbe Wette, die am 22.09. beim Loeschknopf 1,91:1 auf Babyblau
ergeben hat.

GEPRUEFT
--------
pruef-chat-anhaenge: 86 Pruefungen, 0 Fehler (vorher 60).
Aufgenommen wird mit MediaRecorder im echten Browser ueber den echten
Knopf, mit Chromiums erfundenem Mikrofon. Damit prueft der Abschnitt
nebenbei das, was keine gebastelte Datei pruefen koennte: ob die
Erkennung im Server versteht, was ein Browser wirklich erzeugt
(gemessen: 35 829 Bytes audio/webm, 2743 ms).

  * DogFather sieht den Mikrofonknopf, der Scout nicht
  * der Scout schickt dieselbe Aufnahme an der Oberflaeche vorbei:
    403, und nichts davon ist gespeichert
  * ein Video im Ton-Behaelter: 415
  * Laenge, Vorlesewort, Bedienbarkeit, preload=metadata, Breite
  * "Sprachnachricht" steht in der Gespraechsliste statt einer leeren
    Zeile

pruef-chat, pruef-chat-optik: unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-23 01:51:56 +02:00
co-authored by Claude Opus 5
parent 28b0143166
commit 2d14907d0d
44 changed files with 1532 additions and 614 deletions
+244 -2
View File
@@ -84,7 +84,21 @@ d.prepare("INSERT INTO betreuung (creator_id, betreuer_id, seit) VALUES (?,?,?)"
d.close();
const pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
const browser = await pw.chromium.launch();
/* EIN ECHTES MIKROFON, NUR ERFUNDEN (23.09.2026).
Fuer Sprachnachrichten braucht diese Pruefung eine Tonquelle.
Chromium bringt eine mit: `--use-fake-device-for-media-stream`
liefert einen gleichmaessigen Ton, `--use-fake-ui-for-media-stream`
beantwortet die Nachfrage nach der Erlaubnis mit Ja.
WARUM NICHT EINE SELBST GEBAUTE BYTEFOLGE: Aus demselben Grund, der
zwanzig Zeilen weiter unten beim PNG steht. Eine gebastelte
WebM-Kopfzeile wuerde beweisen, dass meine Erkennung meine Bastelei
versteht. Was hier hochgeht, hat dagegen MediaRecorder erzeugt --
dasselbe Stueck Programm, das auf Filipes Handy laeuft. */
const browser = await pw.chromium.launch({
args: ["--use-fake-device-for-media-stream", "--use-fake-ui-for-media-stream"],
});
async function alsRolle(rolle, code, breite = 1280) {
const ctx = await browser.newContext({ viewport: { width: breite, height: 900 } });
@@ -259,6 +273,59 @@ let bildNachrichtId = 0;
springt -- das ist der Zweck, nicht Zierrat. */
ok(bild?.attrW === "240" && bild?.attrH === "150",
`Breite und Höhe stehen am Bild (${bild?.attrW}×${bild?.attrH}) — der Verlauf springt nicht`);
/* ---- ÜBER DEN ECHTEN KNOPF, NICHT ÜBER DIE SCHNITTSTELLE ---------
================================================================
WARUM DAS HIER STEHT: EIN STILLER FEHLER, EINE LÜCKE IN DIESER
PRÜFUNG (23.09.2026)
================================================================
Alles oben schickt mit `fetch` an die Route -- der bequeme Weg,
und er prüft den Server gründlich. Er prüft aber NICHT den Weg,
den ein Mensch geht: Büroklammer, Datei wählen, warten.
In genau diesem Weg stand seit dem 19.09. `const { nachricht } =
e.daten;` -- ein `e`, das es dort nicht gibt. Die Zeile warf, der
`catch` daneben fing, und der Absender las: „Keine Verbindung --
der Anhang wurde nicht geschickt." Das Foto war aber da. Es kam
Sekunden später über den Ereignisstrom, mit einer roten Meldung
darüber, die das Gegenteil behauptete, und der getippte
Begleitsatz blieb im Feld stehen -- also schickt man es noch
einmal.
Diese Prüfung war die ganze Zeit grün. Sie hat den Server
geprüft, nicht die Bedienung. Deshalb geht dieser Block jetzt
durch das Dateifeld selbst und sieht auf das, was der Mensch
danach sieht: steht dort eine Fehlermeldung, und ist das Feld
leer? */
await luna.seite.fill("#text", "über den Knopf geschickt");
await luna.seite.setInputFiles("#anhang-feld", {
name: "ueber-den-knopf.png",
mimeType: "image/png",
/* Das kleinste gültige PNG: 1×1, ein Pixel. Es geht hier nicht um
das Bild, sondern um den Weg. */
buffer: Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
"base64"),
});
await luna.seite.waitForTimeout(2500);
const danach = await luna.seite.evaluate(() => ({
fehlertext: document.getElementById("fehler")?.textContent.trim() || "",
feld: document.getElementById("text")?.value || "",
letzterName: document.querySelector(".chat-nachricht:last-of-type .chat-bild")
?.getAttribute("title") || "",
}));
ok(danach.letzterName.includes("ueber-den-knopf.png"),
`über die Büroklammer geschickt: das Foto steht im Verlauf (${danach.letzterName.slice(0, 40)})`);
/* DIE EIGENTLICHE AUSSAGE. Eine Fehlermeldung über einem Foto, das
angekommen ist, ist schlimmer als gar keine Rückmeldung. */
ok(danach.fehlertext === "",
` und darüber steht KEINE Fehlermeldung ("${danach.fehlertext}")`);
/* UND DAS FELD IST LEER. Bleibt der Begleitsatz stehen, schickt man
dasselbe Foto ein zweites Mal -- der Satz stand vorher drin. */
ok(danach.feld === "",
` das Schreibfeld ist leer, der Begleitsatz ging mit ("${danach.feld}")`);
}
/* =======================================================================
@@ -592,7 +659,182 @@ melde("\n=== 8. Das leere Gespräch ===");
/* =======================================================================
9. KEINE STILLEN FEHLER
======================================================================= */
melde("\n=== 9. Stille Fehler ===");
/* =======================================================================
SPRACHNACHRICHTEN (23.09.2026)
Filipe: „dan will ich auch dass man im chat auch sprachnachrichten
und gifts reinschicken kann. also nur die modis rechte linke hand
und dogfather."
ZWEI FRAGEN, UND DIE ZWEITE IST DIE, DIE ER AUSDRUECKLICH GESTELLT
HAT:
1. Geht es ueberhaupt -- aufnehmen, hochladen, abspielen?
2. Geht es fuer die anderen NICHT? Ohne diesen Teil stuende sein
„also nur" bloss im Kommentar.
AUFGENOMMEN WIRD MIT MediaRecorder, im echten Browser, ueber den
echten Knopf. Damit prueft dieser Abschnitt nebenbei etwas, das
keine gebastelte Datei pruefen koennte: ob die Erkennung im Server
das versteht, was ein Browser tatsaechlich erzeugt.
======================================================================= */
melde("\n=== 9. Eine Sprachnachricht ===");
/** Im Browser aufnehmen und die Bytes als Base64 zurueckgeben.
* Fuer die Gegenprobe gebraucht: Patrick soll GENAU DIESELBE Art
* Datei schicken wollen wie DogFather -- sonst bewiese eine Absage
* nur, dass seine Datei kaputt war. */
async function tonAufnehmen(seite, ms) {
return seite.evaluate(async (dauer) => {
const spur = await navigator.mediaDevices.getUserMedia({ audio: true });
const typ = ["audio/webm;codecs=opus", "audio/webm", "audio/ogg", "audio/mp4"]
.find((t) => window.MediaRecorder.isTypeSupported(t)) || "";
const g = new MediaRecorder(spur, typ ? { mimeType: typ } : undefined);
const stuecke = [];
g.addEventListener("dataavailable", (e) => { if (e.data?.size) stuecke.push(e.data); });
const fertig = new Promise((r) => g.addEventListener("stop", r));
g.start(200);
await new Promise((r) => setTimeout(r, dauer));
g.stop();
await fertig;
spur.getTracks().forEach((t) => t.stop());
const brocken = new Blob(stuecke, { type: g.mimeType || typ });
const puffer = new Uint8Array(await brocken.arrayBuffer());
let roh = "";
for (const byte of puffer) roh += String.fromCharCode(byte);
return { b64: btoa(roh), typ: brocken.type, bytes: puffer.length };
}, ms);
}
{
await oeffne(dogi.seite, raumDogi);
/* ---- Der Knopf ist da -- und bei Patrick nicht ------------------ */
const knopfDogi = await dogi.seite.locator("#ton-auf").isVisible();
ok(knopfDogi, "DogFather sieht den Mikrofonknopf");
await oeffne(pat.seite, raumId);
const knopfPat = await pat.seite.locator("#ton-auf").isVisible();
/* DIE GEGENPROBE AM BILDSCHIRM. Ein Knopf, der da ist und dann
abgelehnt wird, ist schlimmer als keiner. */
ok(!knopfPat, "der Scout sieht ihn nicht — „also nur die modis rechte linke hand und dogfather“");
/* ---- Aufnehmen ueber den echten Knopf --------------------------- */
const vorher = await dogi.seite.locator(".chat-nachricht").count();
await dogi.seite.click("#ton-auf");
await dogi.seite.waitForSelector("#tonleiste:not([hidden])", { timeout: 8000 });
ok(true, "der Knopf startet die Aufnahme, die Leiste erscheint");
await dogi.seite.waitForTimeout(2600);
const zeit = (await dogi.seite.locator("#ton-zeit").innerText()).trim();
/* DIE ZEIT MUSS LAUFEN. Stuende sie still, wuesste niemand, ob noch
aufgenommen wird -- und man redet in eine Aufnahme, die steht. */
ok(/^0:0[2-9]$/.test(zeit), `die Zeit läuft mit (${zeit})`);
await dogi.seite.click("#ton-senden");
await dogi.seite.waitForTimeout(3000);
const nachher = await dogi.seite.locator(".chat-nachricht").count();
ok(nachher === vorher + 1, `die Sprachnachricht steht im Verlauf (${vorher} -> ${nachher})`);
ok(!(await dogi.seite.locator("#tonleiste").isVisible()),
" und die Aufnahmeleiste ist wieder zu");
const blase = await dogi.seite.evaluate(() => {
const k = document.querySelector(".chat-ton");
if (!k) return null;
const g = k.querySelector("audio");
return {
marke: k.querySelector(".chat-ton__marke")?.textContent.trim() || "",
dauer: k.querySelector(".chat-ton__dauer")?.textContent.trim() || "",
quelle: g?.getAttribute("src") || "",
bedienbar: !!g?.controls,
vorladen: g?.getAttribute("preload") || "",
vorlesewort: g?.getAttribute("aria-label") || "",
breite: Math.round(k.getBoundingClientRect().width),
};
});
ok(!!blase, "sie ist als Sprachnachricht gezeichnet");
ok(blase?.marke === "Sprachnachricht", ` beschriftet: ${blase?.marke}`);
ok(/^0:0[2-9]$/.test(blase?.dauer || ""), ` mit ihrer Länge (${blase?.dauer})`);
ok(blase?.bedienbar === true, " mit dem Abspielgerät des Browsers, nicht nachgebaut");
ok(blase?.vorladen === "metadata",
" das nur den Kopf lädt — zehn Sprachnachrichten kosten so Kilobyte statt Megabyte");
ok(/Sprachnachricht/.test(blase?.vorlesewort || ""),
` und ein Vorleseprogramm sagt mehr als „Audio" (${blase?.vorlesewort})`);
ok((blase?.breite || 0) >= 200,
` breit genug, um den Schieber zu treffen (${blase?.breite} px)`);
/* ---- Was steht in der Datenbank? -------------------------------- */
const db2 = new DatabaseSync(process.env.WORKSPACE_DB);
const zeile = db2.prepare(`SELECT anhang_art, anhang_typ, anhang_groesse, anhang_dauer
FROM chat_nachrichten WHERE anhang_art = 'ton' ORDER BY id DESC LIMIT 1`).get();
db2.close();
ok(zeile?.anhang_art === "ton", `erkannt als ${zeile?.anhang_art}`);
/* DER TYP KOMMT AUS DEN ERSTEN BYTES, nicht aus dem Content-Type --
und das ist hier die eigentliche Aussage: Die Erkennung versteht,
was ein echter Browser erzeugt. */
ok(/^audio\/(webm|ogg|mp4)$/.test(zeile?.anhang_typ || ""),
` und der Typ kommt aus dem Inhalt (${zeile?.anhang_typ})`);
ok((zeile?.anhang_groesse || 0) > 500, ` ${zeile?.anhang_groesse} Bytes sind angekommen`);
ok((zeile?.anhang_dauer || 0) >= 2000 && (zeile?.anhang_dauer || 0) < 20000,
` und die Länge steht dabei (${zeile?.anhang_dauer} ms)`);
/* ---- In der Gesprächsliste steht ein Wort dafür ------------------ */
const vorschau = await dogi.seite.evaluate(async () => {
const a = await fetch("/workspace/api/chat/raeume");
const j = await a.json();
return (j.raeume || []).map((r) => r.letzte?.text || "");
});
ok(vorschau.includes("Sprachnachricht"),
`in der Gesprächsliste steht „Sprachnachricht" statt einer leeren Zeile`);
/* ---- DIE GEGENPROBE: derselbe Ton, ein anderer Absender ---------- */
const aufnahme = await tonAufnehmen(pat.seite, 1500);
ok(aufnahme.bytes > 500, `Patrick nimmt dieselbe Art Datei auf (${aufnahme.bytes} Bytes)`);
const absage = await absichtlich([pat], () => pat.seite.evaluate(async ([r, b64, typ]) => {
const roh = atob(b64);
const puffer = new Uint8Array(roh.length);
for (let i = 0; i < roh.length; i++) puffer[i] = roh.charCodeAt(i);
const a = await fetch(`/workspace/api/chat/raeume/${r}/anhang`, {
method: "POST",
headers: { "Content-Type": typ, "X-Dateiname": "Sprachnachricht.webm", "X-Dauer": "1500" },
body: puffer,
});
return { status: a.status, text: (await a.json())?.fehler || "" };
}, [raumId, aufnahme.b64, aufnahme.typ]));
/* ER GEHT AN DER OBERFLAECHE VORBEI -- genau darum geht es. Der
ausgeblendete Knopf ist die Hoeflichkeit, diese Antwort ist die
Schranke. */
ok(absage.status === 403,
`am Knopf vorbei geschickt: abgelehnt (HTTP ${absage.status})`);
ok(/Team Dogi/.test(absage.text),
` mit einem Satz, der sagt warum ("${absage.text}")`);
const db3 = new DatabaseSync(process.env.WORKSPACE_DB);
const vonPat = db3.prepare(
"SELECT COUNT(*) AS n FROM chat_nachrichten WHERE anhang_art = 'ton' AND person_id = ?")
.get(idPat).n;
db3.close();
ok(vonPat === 0, ` und nichts davon ist gespeichert (${vonPat})`);
/* ---- Und ein Video im Tonbehälter geht auch nicht ---------------- */
const alsVideo = await absichtlich([dogi], () => dogi.seite.evaluate(async (r) => {
/* Eine WebM-Kopfzeile mit einer VIDEO-Spur. Hier ist Basteln
ausnahmsweise richtig: Es geht nicht darum, ob echtes Video
erkannt wird, sondern ob die Spurkennung ueberhaupt angesehen
wird -- und das laesst sich nur mit einer Datei pruefen, die
genau daran scheitern muss. */
const kopf = [0x1a, 0x45, 0xdf, 0xa3];
const wort = [..."V_VP9"].map((c) => c.charCodeAt(0));
const puffer = new Uint8Array([...kopf, ...new Array(20).fill(0x42), ...wort,
...new Array(200).fill(0x11)]);
const a = await fetch(`/workspace/api/chat/raeume/${r}/anhang`, {
method: "POST",
headers: { "Content-Type": "audio/webm", "X-Dateiname": "nicht-ton.webm" },
body: puffer,
});
return a.status;
}, raumDogi));
ok(alsVideo === 415,
`ein Video im Ton-Behälter wird abgelehnt (HTTP ${alsVideo}) — sonst liefe es ohne Bild und niemand wüsste es`);
}
melde("\n=== 10. Stille Fehler ===");
{
/* ABSICHTLICH PROVOZIERTE ABSAGEN ZÄHLEN NICHT.
+156 -13
View File
@@ -77,6 +77,24 @@ const ANHANG_MAX = 12 * 1024 * 1024;
const ANHANG_ORDNER = join(DATEN_ORDNER, "chat-anhaenge");
const ANHANG_NAME_MAX = 200;
/* EIGENE GRENZE FUER TON (23.09.2026).
Zwoelf Megabyte sind fuer ein Foto richtig und fuer eine
Sprachnachricht sinnlos: Bei Opus mit 32 kbit/s waeren das rund
fuenfzig Minuten am Stueck. Vier Megabyte reichen fuer etwa zwanzig
Minuten -- mehr als genug fuer „hoer mal kurz" und immer noch eine
echte Schranke.
SIE WIRD NACH DEM EMPFANG GEPRUEFT, und das ist kein Versehen: Ob
etwas Ton ist, sagen erst die ersten Bytes. Vorher weiss niemand,
welche Grenze gilt. Gespeichert wird trotzdem nichts -- abgelehnt
wird, bevor die Datei die Platte sieht.
DIE LAENGE IN MINUTEN STEHT IM BROWSER (chat.js) und stoppt die
Aufnahme von selbst. Hier zaehlen Bytes, weil nur die hier messbar
sind -- eine Dauer waere eine Behauptung des Absenders. */
const TON_MAX = 4 * 1024 * 1024;
const jetzt = () => new Date().toISOString();
/* ---------- Schranke ---------------------------------------------------- */
@@ -549,9 +567,84 @@ function dateiErkennen(b) {
return { art: "pdf", typ: "application/pdf", endung: ".pdf", breite: 0, hoehe: 0 };
}
/* =====================================================================
SPRACHNACHRICHTEN (23.09.2026)
Filipe: „dan will ich auch dass man im chat auch sprachnachrichten
und gifts reinschicken kann. also nur die modis rechte linke hand
und dogfather."
DREI BEHAELTER, WEIL DIE GERAETE DREI LIEFERN -- das ist keine
Grosszuegigkeit, sondern die Bedingung dafuer, dass es ueberhaupt
auf jedem Handy geht:
WebM/Opus Chrome, Edge, Android
MP4/AAC Safari, iPhone, iPad
Ogg/Opus Firefox
Wer nur einen davon nimmt, baut eine Funktion, die bei der Haelfte
des Teams stumm bleibt.
WARUM KEIN MP3: Kein Aufnahmegeraet im Browser erzeugt MP3. Es
zuzulassen hiesse, eine Tuer fuer Musikdateien aufzumachen, nach
der niemand gefragt hat. Bestellt waren Sprachnachrichten.
DER BEHAELTER ALLEIN GENUEGT NICHT. WebM und MP4 tragen genauso
gut Video -- und ein Video, das hier als "Ton" durchginge, landete
in einem Abspielgeraet ohne Bild: Es liefe, man hoerte etwas, und
niemand wuesste, dass die Haelfte fehlt. Deshalb wird im Kopf nach
der KENNUNG DER SPUR gesucht: Steht dort eine Videospur, wird
abgelehnt; steht keine Tonspur darin, ebenfalls.
GESUCHT WIRD NUR IM ANFANG (16 kB). Dort stehen bei allen drei
Formaten die Spurangaben. Die ganze Datei zu durchsuchen hiesse,
bei vier Megabyte nach Zeichenketten zu graben -- und dabei
irgendwann ein "avc1" mitten in den Tondaten zu finden.
===================================================================== */
const anfang = b.toString("latin1", 0, Math.min(b.length, 16384));
const hatVideo = /V_VP8|V_VP9|V_AV1|V_MPEG|avc1|hvc1|hev1|av01|mp4v|theora/.test(anfang);
/* --- WebM / Matroska: EBML-Kennung ------------------------------- */
if (b[0] === 0x1a && b[1] === 0x45 && b[2] === 0xdf && b[3] === 0xa3) {
if (hatVideo) return null;
if (!/A_OPUS|A_VORBIS|A_AAC|A_PCM/.test(anfang)) return null;
return { art: "ton", typ: "audio/webm", endung: ".webm", breite: 0, hoehe: 0 };
}
/* --- Ogg ---------------------------------------------------------- */
if (kopf(0, 4) === "OggS") {
if (hatVideo) return null;
if (!/OpusHead|vorbis|Speex|FLAC/.test(anfang)) return null;
return { art: "ton", typ: "audio/ogg", endung: ".ogg", breite: 0, hoehe: 0 };
}
/* --- MP4 / M4A: "ftyp" steht an Stelle 4, nicht 0 ----------------- */
if (kopf(4, 8) === "ftyp") {
if (hatVideo) return null;
if (!/M4A |mp4a|Opus/.test(anfang)) return null;
return { art: "ton", typ: "audio/mp4", endung: ".m4a", breite: 0, hoehe: 0 };
}
return null;
}
/** Wie heisst ein Anhang in einem Satz?
*
* „Foto" steht in der Gespraechsliste, im Zitat, an einer angehefteten
* Nachricht und in der Benachrichtigung -- an vier Stellen stand
* dieselbe Aufzaehlung, jede mit ihrem eigenen `? :`. Beim Hinzukommen
* der Sprachnachricht waeren es vier Aenderungen gewesen, und die
* vierte ist die, die man vergisst. Jetzt eine Stelle.
*
* LEER FUER UNBEKANNTES, nicht "Anhang": Der Aufrufer setzt das Wort
* hinter ein `||` -- ein Ersatzwort fuer etwas, das es nicht gibt,
* stuende sonst in einer Vorschau, in der nichts ist.
*/
export function anhangWort(art) {
return art === "bild" ? "Foto"
: art === "pdf" ? "PDF"
: art === "ton" ? "Sprachnachricht"
: "";
}
/** Der Anzeigename. Er steht nur in der Datenbank -- auf der Platte
* bekommt jede Datei einen erzeugten Zufallsnamen, damit ein Name mit
* "../" darin nirgendwo hinkommt. */
@@ -963,12 +1056,13 @@ chatRouter.get("/workspace/api/chat/raeume", (req, res) => {
bild: t.bild })),
letzte: letzte ? {
/* Ein Anhang ohne Begleittext hätte hier eine leere Zeile
hinterlassen. "Foto"/"PDF" ist die Vorschau, die man in
jeder Gesprächsliste erwartet. */
hinterlassen. „Foto", „PDF", „Sprachnachricht" ist die
Vorschau, die man in jeder Gesprächsliste erwartet -- das
Wort kommt aus anhangWort(), an einer Stelle für alle vier
Orte, an denen es gebraucht wird. */
text: letzte.weg_am ? null
: (letzte.text ? letzte.text.slice(0, 140)
: (letzte.anhang_art === "bild" ? "Foto"
: letzte.anhang_art === "pdf" ? "PDF" : "")),
: anhangWort(letzte.anhang_art)),
zurueckgenommen: !!letzte.weg_am,
von: letzte.von, erstellt: letzte.erstellt,
} : null,
@@ -1299,7 +1393,7 @@ chatRouter.get("/workspace/api/chat/raeume/:id/nachrichten", (req, res) => {
p.bild AS von_bild, p.chat_kachel AS von_kachel,
n.antwort_auf, n.angeheftet_am, n.rudel,
n.anhang_name, n.anhang_art, n.anhang_typ, n.anhang_groesse,
n.anhang_breite, n.anhang_hoehe,
n.anhang_breite, n.anhang_hoehe, n.anhang_dauer,
a.text AS zitat_text, a.weg_am AS zitat_weg, ap.name AS zitat_von,
a.anhang_art AS zitat_anhang
FROM chat_nachrichten n
@@ -1394,13 +1488,25 @@ chatRouter.get("/workspace/api/chat/raeume/:id/nachrichten", (req, res) => {
darf_rudel: istTeamDogi(req.person)
&& leute.some((t) => t.id !== req.person.id && istTeamDogi(t)),
rudel_wort: RUDEL_WORT,
/* DARF ICH SPRACHNACHRICHTEN SCHICKEN? (23.09.2026)
Aus derselben Funktion wie die Schranke in der Anhang-Route.
Der Browser vergleicht keine Rollen -- assets/js/chat.js
bekommt jeder, der die Seite oeffnet.
ANDERS ALS BEIM RUDEL HAENGT ES NICHT AM RAUM: Eine
Sprachnachricht an einen Creator ist eine Sprachnachricht an
einen Creator; sie erreicht ihn. Der Ruf ans Rudel erreicht in
so einem Raum niemanden -- deshalb dort die zweite Bedingung
und hier nicht. */
darf_ton: istTeamDogi(req.person),
angeheftet: angeheftet.map((a) => ({
id: a.id,
von: a.von || "Gelöscht",
heftete: a.heftete || null,
seit: a.angeheftet_am,
text: String(a.text || "").slice(0, 200)
|| (a.anhang_art === "bild" ? "Foto" : a.anhang_art === "pdf" ? "PDF" : ""),
|| anhangWort(a.anhang_art),
})),
/* Aufsteigend zurück -- gelesen wird von oben nach unten. */
/* Die Reaktionen in EINER Abfrage fuer alle Nachrichten -- nicht
@@ -1445,7 +1551,7 @@ chatRouter.get("/workspace/api/chat/raeume/:id/nachrichten", (req, res) => {
von: n.zitat_von || "Gelöscht",
text: n.zitat_weg ? null
: (String(n.zitat_text || "").slice(0, 140)
|| (n.zitat_anhang === "bild" ? "Foto" : n.zitat_anhang === "pdf" ? "PDF" : "")),
|| anhangWort(n.zitat_anhang)),
zurueckgenommen: !!n.zitat_weg,
} : null,
/* Der Anhang wird als fertige ADRESSE geliefert, nicht als
@@ -1455,6 +1561,7 @@ chatRouter.get("/workspace/api/chat/raeume/:id/nachrichten", (req, res) => {
art: n.anhang_art, typ: n.anhang_typ,
name: n.anhang_name, groesse: n.anhang_groesse,
breite: n.anhang_breite || 0, hoehe: n.anhang_hoehe || 0,
dauer: n.anhang_dauer || 0,
weg: `/workspace/api/chat/anhang/${n.id}`,
} : null,
}));
@@ -1722,10 +1829,45 @@ chatRouter.post("/workspace/api/chat/raeume/:id/anhang",
const erkannt = dateiErkennen(req.body);
if (!erkannt) {
return res.status(415).json({
fehler: "Das geht nicht – erlaubt sind Fotos (PNG, JPEG, WebP, GIF) und PDF.",
fehler: "Das geht nicht – erlaubt sind Fotos (PNG, JPEG, WebP, GIF), PDF und Sprachnachrichten.",
});
}
/* ==== SPRACHNACHRICHTEN SIND NICHT FUER ALLE (23.09.2026) =====
Filipe: „dan will ich auch dass man im chat auch
sprachnachrichten und gifts reinschicken kann. also nur die
modis rechte linke hand und dogfather."
Das „also nur" ist der Punkt. Fotos und PDF darf jeder
schicken, auch Creator -- das steht als Entscheidung im
Kommentar ueber dieser Route und bleibt. Ton nicht.
HIER UND NICHT NUR IM BROWSER. Ein ausgeblendeter Knopf ist
eine Bitte; abgelehnt wird erst an dieser Stelle. Dieselbe
Ueberlegung wie bei der Nachtruhe zwanzig Zeilen darueber. */
if (erkannt.art === "ton" && !istTeamDogi(req.person)) {
return res.status(403).json({
fehler: "Sprachnachrichten schicken nur Team Dogi und DogFather.",
});
}
if (erkannt.art === "ton" && req.body.length > TON_MAX) {
return res.status(413).json({
fehler: `Die Sprachnachricht ist zu lang – erlaubt sind ${Math.round(TON_MAX / 1048576)} MB.`,
});
}
/* WIE LANG SIE IST, SAGT DER ABSENDER -- und das ist eine
Behauptung, keine Messung. Sie steht nur in der Vorschau, bis
das Abspielgeraet die wahre Laenge kennt. Begrenzt wird sie
trotzdem: Ohne Obergrenze stuende in der Gespraechsliste
„Sprachnachricht (999:59)", und die Liste saehe kaputt aus. */
let dauer = null;
if (erkannt.art === "ton") {
const roh = Number.parseInt(req.get("x-dauer") || "", 10);
dauer = Number.isFinite(roh) && roh > 0 ? Math.min(roh, 60 * 60 * 1000) : null;
}
let begleittext = "";
try { begleittext = decodeURIComponent(req.get("x-text") || ""); } catch { begleittext = ""; }
begleittext = begleittext.trim().slice(0, TEXT_MAX);
@@ -1744,11 +1886,11 @@ chatRouter.post("/workspace/api/chat/raeume/:id/anhang",
d.prepare(`INSERT INTO chat_nachrichten
(raum_id, person_id, text, erstellt,
anhang_datei, anhang_name, anhang_art, anhang_typ,
anhang_groesse, anhang_breite, anhang_hoehe)
VALUES (?,?,?,?,?,?,?,?,?,?,?)`)
anhang_groesse, anhang_breite, anhang_hoehe, anhang_dauer)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`)
.run(raumId, req.person.id, begleittext, n,
aufPlatte, name, erkannt.art, erkannt.typ,
req.body.length, erkannt.breite || null, erkannt.hoehe || null);
req.body.length, erkannt.breite || null, erkannt.hoehe || null, dauer);
const id = d.prepare("SELECT last_insert_rowid() AS id").get().id;
d.prepare("UPDATE chat_raeume SET letzte_am = ? WHERE id = ?").run(n, raumId);
d.prepare("UPDATE chat_teilnehmer SET gelesen_bis = ? WHERE raum_id = ? AND person_id = ?")
@@ -1762,8 +1904,10 @@ chatRouter.post("/workspace/api/chat/raeume/:id/anhang",
art: erkannt.art, typ: erkannt.typ, name,
groesse: req.body.length,
breite: erkannt.breite || 0, hoehe: erkannt.hoehe || 0,
dauer: dauer || 0,
weg: `/workspace/api/chat/anhang/${id}`,
},
rudel: false,
};
const empfaenger = teilnehmerVon(raumId).filter((t) => t.id !== req.person.id);
chatEreignis(raumId, nachricht, empfaenger.map((t) => t.id));
@@ -2720,8 +2864,7 @@ export function pushTextFuer(art, nachricht, raumId) {
Benachrichtigung, die nur "Neue Nachricht" sagt, zwingt zum
Öffnen, um zu erfahren, ob es wichtig war. */
text: String(nachricht.text || "").slice(0, 120)
|| (nachricht.anhang?.art === "bild" ? "Foto"
: nachricht.anhang?.art === "pdf" ? "PDF" : ""),
|| anhangWort(nachricht.anhang?.art),
ziel,
};
}
+20
View File
@@ -3267,6 +3267,26 @@ function umstellungen(d) {
["chat_nachrichten", "anhang_breite", "INTEGER"],
["chat_nachrichten", "anhang_hoehe", "INTEGER"],
/* WIE LANG IST DIE SPRACHNACHRICHT? (23.09.2026)
Filipe: „dan will ich auch dass man im chat auch sprachnachrichten
und gifts reinschicken kann."
In Millisekunden, und sie ist AUSDRUECKLICH nur fuer die Anzeige,
bevor die Datei geladen ist: In der Gespraechsliste steht
„Sprachnachricht (0:14)", und in der Blase steht die Laenge schon
da, waehrend der Ton noch laedt. Ohne sie springt die Zeile in
dem Moment, in dem die Zahl nachkommt.
SIE KOMMT VOM ABSENDER und ist damit eine Behauptung, keine
Messung -- das gehoert gesagt. Sie zu ueberpruefen hiesse, vier
Behaelterformate zu zerlegen (WebM schreibt die Dauer beim
Aufnehmen oft gar nicht erst hinein). Der Wert wird deshalb
begrenzt, und die WAHRE Laenge sagt ohnehin das Abspielgeraet,
sobald es die Datei kennt. Was wirklich schuetzt, ist die
Byte-Grenze, nicht diese Zahl. */
["chat_nachrichten", "anhang_dauer", "INTEGER"],
/* WELCHE VORLAGE DAHINTERSTECKT (09.09.2026).
Filipe: "ich will nur dass du dich informierst und schaust was
+5 -5
View File
@@ -16,15 +16,15 @@
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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
<!-- 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,
WARUM das Telefon nicht klingelt, ist das besonders unpassend. -->
<link rel="manifest" href="/workspace/crew.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<style>
/* Bewusst in der Seite und nicht in einer eigenen Datei: Diese Seite
soll auch dann noch etwas anzeigen, wenn genau das schiefgeht,
@@ -126,7 +126,7 @@
<script src="assets/js/anruf-probe.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/anruf-probe.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
</body>
</html>
+4 -4
View File
@@ -23,25 +23,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/workspace-192.png?v=202609230135",
"src": "/assets/img/app-symbole/workspace-192.png?v=202609230151",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-512.png?v=202609230135",
"src": "/assets/img/app-symbole/workspace-512.png?v=202609230151",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609230135",
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609230151",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609230135",
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609230151",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+135
View File
@@ -2703,3 +2703,138 @@
0 Klammer, Feld, Emoji, Senden -- die eigentliche Zeile */
.chat__eingabe .antwort-leiste { order: -2; }
.chat__eingabe .textform { order: -1; flex: 1 0 100%; margin-bottom: 2px; }
/* =====================================================================
SPRACHNACHRICHTEN (23.09.2026)
Filipe: „dan will ich auch dass man im chat auch sprachnachrichten
und gifts reinschicken kann. also nur die modis rechte linke hand
und dogfather."
AUGENSCHONEND HEISST HIER: KEIN BLINKEN. Der naheliegende rote
Blinkpunkt während der Aufnahme ist genau das, was die Hausregel
ausschließt („keine aggressiven Flacker-/Strobe-Effekte"). Der Punkt
atmet stattdessen langsam (1,8 s, zwischen 45 % und 100 %
Deckkraft) -- man sieht, dass etwas läuft, ohne dass es zieht. Und
bei `prefers-reduced-motion` steht er ganz still; dann trägt die
laufende Zeit daneben die Auskunft allein, die sie ohnehin trägt.
===================================================================== */
/* ---- Der Mikrofonknopf in der Schreibzeile ------------------------- */
.chat__ton {
flex: none;
display: inline-flex; align-items: center; justify-content: center;
/* 40 px wie die Büroklammer daneben -- zwei Knöpfe nebeneinander in
zwei Größen sehen aus, als hätte einer Vorrang. */
width: 40px; height: 40px;
border: 0; border-radius: 50%;
background: transparent;
color: var(--text-leise);
cursor: pointer;
transition: background var(--tempo, .18s) ease, color var(--tempo, .18s) ease;
}
.chat__ton svg {
width: 21px; height: 21px;
fill: none; stroke: currentColor; stroke-width: 1.7;
stroke-linecap: round; stroke-linejoin: round;
}
.chat__ton:hover { background: rgba(255, 255, 255, .07); color: var(--text); }
.chat__ton:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
.chat__ton:disabled { opacity: .45; cursor: default; }
/* Läuft die Aufnahme, ist derselbe Knopf der Abschick-Knopf. Dass er
seine Bedeutung wechselt, muss man SEHEN. */
.chat__ton[data-laeuft="ja"] {
background: color-mix(in srgb, var(--akzent) 22%, transparent);
color: color-mix(in srgb, var(--akzent) 60%, #ffffff);
}
/* ---- Die Leiste während der Aufnahme ------------------------------- */
.tonleiste {
display: flex; align-items: center; gap: 10px;
margin: 0 0 8px;
padding: 9px 12px;
border: 1px solid color-mix(in srgb, var(--akzent) 30%, transparent);
border-radius: var(--radius-klein, 12px);
background: color-mix(in srgb, var(--akzent) 10%, rgba(12, 18, 28, .92));
}
.tonleiste__punkt {
flex: none; width: 10px; height: 10px; border-radius: 50%;
background: #e0736d;
animation: ton-atmen 1.8s ease-in-out infinite;
}
@keyframes ton-atmen {
0%, 100% { opacity: 1; }
50% { opacity: .45; }
}
.tonleiste__zeit {
flex: none;
font-variant-numeric: tabular-nums;
font-size: 1.02rem; font-weight: 700;
color: var(--text);
/* Feste Breite: Ohne sie springt alles rechts davon bei jedem
Zehnerwechsel der Sekunden. */
min-width: 3.1ch;
}
.tonleiste__wort {
flex: 1 1 auto;
font-size: .84rem; color: var(--text-leise);
}
.tonleiste__weg,
.tonleiste__senden {
flex: none;
display: inline-flex; align-items: center; justify-content: center;
/* 40 px, damit ein Daumen beides trifft, ohne das Falsche zu
erwischen -- hier kostet ein Fehlgriff die ganze Aufnahme. */
width: 40px; height: 40px;
border: 1px solid var(--rand);
border-radius: 50%;
background: transparent;
font-size: 1rem; line-height: 1;
cursor: pointer;
}
.tonleiste__weg { color: var(--text-leise); }
.tonleiste__weg:hover { color: var(--text); border-color: var(--text-leise); }
.tonleiste__senden {
color: color-mix(in srgb, var(--akzent) 55%, #ffffff);
border-color: color-mix(in srgb, var(--akzent) 45%, transparent);
background: color-mix(in srgb, var(--akzent) 16%, transparent);
}
.tonleiste__senden:hover { background: color-mix(in srgb, var(--akzent) 26%, transparent); }
.tonleiste__weg:focus-visible,
.tonleiste__senden:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
.tonleiste__punkt { animation: none; }
}
/* ---- Die Sprachnachricht in der Blase ------------------------------ */
.chat-ton {
display: grid; gap: 6px;
/* So breit, dass der Schieber des Abspielgeräts bedienbar ist, und
nicht breiter als eine Blase am Handy. */
width: min(260px, 100%);
}
.chat-ton__zeile {
display: flex; align-items: baseline; gap: 8px;
font-size: .78rem;
/* DIE FARBE DER BLASE, NICHT EINE FESTE. Jede Blase trägt die Farbe,
die ihr Absender ausgesucht hat -- `--blase-leise` ist die dafür
ausgerechnete leise Schrift. Dieselbe Überlegung wie bei der
Rudel-Marke weiter oben, und derselbe Fehler, der am 22.09. beim
Löschknopf 1,91:1 auf Babyblau ergeben hat. */
color: var(--blase-leise, var(--text-leise));
}
.chat-ton__marke { font-weight: 600; letter-spacing: .02em; }
.chat-ton__dauer { font-variant-numeric: tabular-nums; }
.chat-ton__geraet {
width: 100%; height: 36px;
display: block;
border-radius: 999px;
}
.chat-ton[data-kaputt="ja"] .chat-ton__geraet { display: none; }
@media (forced-colors: active) {
.tonleiste { border: 1px solid CanvasText; }
.tonleiste__punkt { background: CanvasText; }
.chat__ton[data-laeuft="ja"] { border: 2px solid Highlight; }
}
+347 -14
View File
@@ -780,6 +780,12 @@
darfAllesLoeschen = !!daten.darf_alles_loeschen;
darfRudel = !!daten.darf_rudel;
rudelWort = daten.rudel_wort || 'rudel';
/* DER MIKROFONKNOPF ERSCHEINT, WENN DER SERVER ES SAGT
(23.09.2026). Filipe: „also nur die modis rechte linke hand
und dogfather." Hier wird keine Rolle verglichen -- dieselbe
Ueberlegung wie bei darf_anheften und darf_alles_loeschen. */
const mikro = $('ton-auf');
if (mikro) mikro.hidden = !daten.darf_ton;
/* DER STAND VON VORHIN, nicht der von jetzt. `gelesenMelden()`
weiter unten setzt ihn gleich auf die letzte Nachricht -- die
Linie muss also aus dem Wert gezogen werden, der beim OEFFNEN
@@ -1608,6 +1614,51 @@
return kasten;
}
/* ---- SPRACHNACHRICHT (23.09.2026) ------------------------------
Filipe: „dan will ich auch dass man im chat auch
sprachnachrichten und gifts reinschicken kann."
DAS EINGEBAUTE ABSPIELGERAET DES BROWSERS, nicht ein
nachgebautes. Ein eigenes haette eine eigene Abspieltaste, einen
eigenen Schieber und eine eigene Tastaturbedienung -- drei
Dinge, die das Geraet seit Jahren richtig macht und die man
einzeln kaputtbauen kann. Es laesst sich weit genug gestalten
(siehe chat.css), und es kennt Vorleseprogramme.
`preload="metadata"`: Geladen wird beim Oeffnen nur der Kopf der
Datei -- daraus kennt das Geraet die Laenge. Die Tondaten kommen
erst beim Abspielen. Zehn Sprachnachrichten im Verlauf kosten so
ein paar Kilobyte statt ein paar Megabyte.
DIE LAENGE STEHT TROTZDEM DANEBEN: Bis der Kopf da ist, zeigt
das Geraet nichts, und die Zeile waere erst leer und spraenge
dann. Die Zahl kommt vom Absender und ist nur die Vorschau --
was das Geraet sagt, gilt. */
if (a.art === 'ton') {
const kasten = el('div', 'chat-ton');
const geraet = document.createElement('audio');
geraet.controls = true;
geraet.preload = 'metadata';
geraet.src = a.weg;
geraet.className = 'chat-ton__geraet';
/* Ein Vorleseprogramm sagt sonst nur "Audio". */
geraet.setAttribute('aria-label',
`Sprachnachricht${a.dauer ? ', ' + dauerWort(a.dauer) : ''}`);
const zeile = el('span', 'chat-ton__zeile');
const marke = el('span', 'chat-ton__marke', 'Sprachnachricht');
zeile.append(marke);
if (a.dauer) zeile.append(el('span', 'chat-ton__dauer', dauerWort(a.dauer)));
/* Ein Ton, der nicht laedt, hinterlaesst sonst ein stummes
Geraet ohne Erklaerung -- dieselbe Sicherung wie beim Bild. */
geraet.addEventListener('error', () => {
kasten.dataset.kaputt = 'ja';
marke.textContent = 'Sprachnachricht lässt sich gerade nicht laden';
});
kasten.append(zeile, geraet);
return kasten;
}
const karte = el('a', 'chat-datei');
karte.href = a.weg;
karte.target = '_blank';
@@ -2913,10 +2964,56 @@
const ANHANG_TYPEN = new Set(['image/png', 'image/jpeg', 'image/webp', 'image/gif', 'application/pdf']);
let schicktGerade = false;
/** Eine gerade abgeschickte Nachricht in den Verlauf holen.
*
* ================================================================
* HIER STAND EIN FEHLER, UND ZWAR EIN STILLER (gefunden 23.09.2026)
* ================================================================
*
* In `anhangSchicken` stand `const { nachricht } = e.daten;` -- ein
* `e`, das es in dieser Funktion gar nicht gibt (gemeint war
* `ergebnis`). Das ist kein Schreibfehler ohne Folgen: Die Zeile
* wirft einen ReferenceError, der `catch` daneben faengt ihn, und
* der Absender liest „Keine Verbindung -- der Anhang wurde nicht
* geschickt."
*
* DAS FOTO WAR ABER DA. Es ging durch, der Server speicherte es,
* ueber den Ereignisstrom erschien es Sekunden spaeter im Verlauf
* -- mit einer roten Meldung darueber, die das Gegenteil behauptet.
* Dazu blieb der getippte Begleitsatz im Feld stehen (die Zeile,
* die ihn leert, kam nie dran), also schickt man es noch einmal.
*
* Der Fehler ist nur deshalb so lange unbemerkt geblieben, weil er
* sich wie ein Netzproblem anfuehlt -- und Netzprobleme sucht
* niemand im Programm.
*
* Jetzt EINE Stelle fuer beide Wege (Anhang und Sprachnachricht).
* Zwei Fassungen waeren zwei Gelegenheiten fuer denselben Fehler.
*/
function nachrichtUebernehmen(nachricht) {
if (!nachricht) { melde('Ging nicht.'); return; }
/* Nur eintragen, wenn sie nicht schon über den Strom kam --
sonst stünde dasselbe Foto zweimal da. */
if (!nachrichten.some((x) => x.id === nachricht.id)) {
nachrichten.push({ ...nachricht, selbst: true });
}
$('text').value = '';
if (offen) entwurfWeg(offen.id);
hoeheAnpassen();
zaehlerZeigen();
unten = true; neuUnten = 0;
verlaufZeichnen();
melde('');
raeumeLaden();
}
async function anhangSchicken(datei) {
if (!offen || !datei) return;
if (schicktGerade) { melde('Einen Moment – der letzte Anhang ist noch unterwegs.'); return; }
if (!ANHANG_TYPEN.has(datei.type)) {
/* SPRACHNACHRICHTEN STEHEN HIER BEWUSST NICHT. Sie kommen aus
dem Mikrofon daneben, nicht aus dem Dateiwaehler -- bestellt
waren Sprachnachrichten, keine Musikdateien. */
melde('Das geht nicht – erlaubt sind Fotos (PNG, JPEG, WebP, GIF) und PDF.');
return;
}
@@ -2964,20 +3061,7 @@
: sagWas(ergebnis.daten?.fehler, 'Ging nicht.'));
return;
}
const { nachricht } = e.daten;
/* Nur eintragen, wenn sie nicht schon über den Strom kam --
sonst stünde dasselbe Foto zweimal da. */
if (!nachrichten.some((x) => x.id === nachricht.id)) {
nachrichten.push({ ...nachricht, selbst: true });
}
$('text').value = '';
entwurfWeg(offen.id);
hoeheAnpassen();
zaehlerZeigen();
unten = true; neuUnten = 0;
verlaufZeichnen();
melde('');
raeumeLaden();
nachrichtUebernehmen(ergebnis.daten?.nachricht);
} catch {
melde('Keine Verbindung – der Anhang wurde nicht geschickt.');
} finally {
@@ -2989,6 +3073,255 @@
}
}
/* =====================================================================
SPRACHNACHRICHTEN AUFNEHMEN (23.09.2026)
=====================================================================
Filipe: „dan will ich auch dass man im chat auch sprachnachrichten
und gifts reinschicken kann. also nur die modis rechte linke hand
und dogfather."
TIPPEN STATT HALTEN -- die Entscheidung steht im HTML begruendet.
DREI BEHAELTER, WEIL DIE GERAETE DREI LIEFERN: Chrome und Android
koennen WebM/Opus, Safari und das iPhone nur MP4, Firefox Ogg. Die
Liste wird der Reihe nach durchprobiert und der erste genommen,
den das Geraet kann. Einen festen Typ zu verlangen hiesse, dass
die Funktion bei der Haelfte des Teams gar nicht erst angeht --
und zwar ohne Fehlermeldung, weil MediaRecorder dann einfach
wirft.
WAS BEWUSST NICHT PASSIERT: kein eigener Pegelausschlag, kein
Wellenbild. Beides sieht gut aus und kostet eine Bildschleife, die
waehrend der Aufnahme dauernd zeichnet -- auf einem aelteren Handy
ist das genau die Rechenzeit, die dem Aufnehmen fehlt. Ein ruhiger
Punkt und die Zeit reichen, um zu wissen, dass es laeuft.
===================================================================== */
/** Aus Millisekunden „1:07". An einer Stelle, weil drei sie
* brauchen: die laufende Aufnahme, die Blase und das Vorlesewort. */
function dauerWort(ms) {
const sek = Math.max(0, Math.round(Number(ms) / 1000));
return `${Math.floor(sek / 60)}:${String(sek % 60).padStart(2, '0')}`;
}
/* DREI MINUTEN. Eine Sprachnachricht im Team ist „hoer mal kurz",
kein Vortrag -- und wer eine halbe Stunde spricht, schickt etwas,
das niemand abhoert. Die Aufnahme stoppt von selbst und sagt es;
abgeschickt wird sie NICHT von selbst (siehe unten). */
const TON_MAX_MS = 3 * 60 * 1000;
let tonGeraet = null; // MediaRecorder
let tonSpur = null; // MediaStream -- muss am Ende aus sein
let tonStuecke = [];
let tonStart = 0;
let tonUhr = null;
let tonAbsicht = null; // 'senden' | 'weg' | null
function tonTypWaehlen() {
const kandidaten = [
'audio/webm;codecs=opus', 'audio/webm',
'audio/ogg;codecs=opus', 'audio/ogg',
'audio/mp4',
];
for (const t of kandidaten) {
try { if (window.MediaRecorder?.isTypeSupported?.(t)) return t; } catch { /* weiter */ }
}
return ''; // der Browser nimmt seinen eigenen
}
function tonLeisteZeigen(an) {
const leiste = $('tonleiste');
if (leiste) leiste.hidden = !an;
const knopf = $('ton-auf');
if (knopf) knopf.dataset.laeuft = an ? 'ja' : 'nein';
/* Waehrend der Aufnahme kann man nichts anhaengen -- zwei
gleichzeitige Uploads waeren zwei Nachrichten in unklarer
Reihenfolge. */
const klammer = $('anhang-auf');
if (klammer) klammer.disabled = an;
}
function tonUhrZeigen() {
const ms = Date.now() - tonStart;
const feld = $('ton-zeit');
if (feld) feld.textContent = dauerWort(ms);
/* NUR ALLE FUENF SEKUNDEN VORLESEN. `aria-live` an der Zeit haette
im Sekundentakt gesprochen und alles andere uebertoent. */
const wort = $('ton-wort');
if (wort) {
const sek = Math.floor(ms / 1000);
const soll = sek >= 5 && sek % 5 === 0 ? `nimmt auf, ${dauerWort(ms)}` : null;
if (soll && wort.textContent !== soll) wort.textContent = soll;
}
if (ms >= TON_MAX_MS) {
/* NICHT VON SELBST ABSCHICKEN. Wer die Grenze erreicht, hat
gerade mitten im Satz aufgehoert -- das ungefragt zu
verschicken waere die schlechteste Sekunde, um es zu tun.
Die Aufnahme haelt an, das Ergebnis liegt bereit. */
tonAbsicht = null;
tonStoppen();
melde(`Aufnahme gestoppt – ${Math.round(TON_MAX_MS / 60000)} Minuten sind das Höchste. `
+ 'Mit dem Häkchen schickst du sie ab.', 'hinweis');
}
}
function tonAufraeumen() {
if (tonUhr) { clearInterval(tonUhr); tonUhr = null; }
/* DIE SPUR MUSS AUS. Ohne das bleibt das Mikrofon an -- am Handy
sichtbar als rotes Zeichen in der Statusleiste, und es zieht
Strom. Eine Aufnahmefunktion, die das Mikrofon offen laesst, ist
ein Vertrauensbruch, auch wenn niemand zuhoert. */
try { tonSpur?.getTracks().forEach((t) => t.stop()); } catch { /* schon aus */ }
tonSpur = null;
tonGeraet = null;
tonLeisteZeigen(false);
const feld = $('ton-zeit');
if (feld) feld.textContent = '0:00';
const wort = $('ton-wort');
if (wort) wort.textContent = 'nimmt auf …';
}
function tonStoppen() {
try { tonGeraet?.stop(); } catch { /* war schon aus */ }
}
async function tonStarten() {
if (!offen || tonGeraet) return;
if (!navigator.mediaDevices?.getUserMedia || !window.MediaRecorder) {
melde('Dieser Browser kann keine Sprachnachrichten aufnehmen.');
return;
}
let spur;
try {
spur = await navigator.mediaDevices.getUserMedia({ audio: true });
} catch (f) {
/* DER HAEUFIGSTE FALL IST KEIN FEHLER, SONDERN EIN NEIN. Ein
„Ging nicht" liesse jeden raten, woran es lag -- und die
Antwort steht in einem Kasten, den man wegklicken kann und
danach nicht wiederfindet. */
melde(f?.name === 'NotAllowedError'
? 'Das Mikrofon ist gesperrt. Im Browser neben der Adresszeile auf das Schloss tippen und Mikrofon erlauben.'
: f?.name === 'NotFoundError'
? 'Kein Mikrofon gefunden.'
: 'Das Mikrofon lässt sich gerade nicht öffnen.');
return;
}
tonSpur = spur;
tonStuecke = [];
tonAbsicht = null;
const typ = tonTypWaehlen();
try {
tonGeraet = new MediaRecorder(spur, typ ? { mimeType: typ } : undefined);
} catch {
/* Nimmt der Browser den gewaehlten Typ doch nicht, bekommt er
seinen eigenen. Lieber eine Aufnahme in einem anderen Format
als gar keine -- der Server erkennt alle drei. */
try { tonGeraet = new MediaRecorder(spur); } catch {
melde('Dieser Browser kann keine Sprachnachrichten aufnehmen.');
tonAufraeumen();
return;
}
}
tonGeraet.addEventListener('dataavailable', (x) => {
if (x.data && x.data.size) tonStuecke.push(x.data);
});
tonGeraet.addEventListener('stop', () => {
const dauer = Date.now() - tonStart;
const art = tonGeraet?.mimeType || typ || 'audio/webm';
const absicht = tonAbsicht;
const stuecke = tonStuecke;
tonStuecke = [];
tonAufraeumen();
if (absicht !== 'senden') {
if (absicht === 'weg') melde('Aufnahme verworfen.', 'hinweis');
return;
}
/* UNTER EINER SEKUNDE IST EIN VERSEHEN. Ein Tippen auf den
Knopf und gleich wieder auf das Haekchen ergibt eine Datei
mit nichts darin -- die zu verschicken hiesse, dem anderen
eine leere Nachricht zu schicken, die er dreimal abspielt. */
if (dauer < 900 || !stuecke.length) {
melde('Zu kurz – nichts aufgenommen.');
return;
}
const brocken = new Blob(stuecke, { type: art });
void tonSchicken(brocken, dauer, art);
});
tonStart = Date.now();
/* 250 ms: kleine Stuecke, damit beim Stoppen nichts verlorengeht.
Ohne Zeitscheibe liefert mancher Browser alles erst am Ende --
und wenn die Seite dazwischen weggeht, ist alles weg. */
tonGeraet.start(250);
tonLeisteZeigen(true);
tonUhrZeigen();
tonUhr = setInterval(tonUhrZeigen, 250);
melde('');
}
/** Die fertige Aufnahme hochladen.
*
* UEBER DENSELBEN WEG WIE JEDER ANHANG -- dieselbe Route, dieselbe
* Fortschrittsanzeige, dasselbe Abbrechen. Ein eigener Weg waere
* eine zweite Gelegenheit, eine Pruefung zu vergessen. */
async function tonSchicken(brocken, dauer, typ) {
if (!offen) return;
if (schicktGerade) { melde('Einen Moment – der letzte Anhang ist noch unterwegs.'); return; }
schicktGerade = true;
$('anhang-auf').disabled = true;
if ($('ton-auf')) $('ton-auf').disabled = true;
let anzeige = null;
const begleittext = $('text').value.trim();
try {
let lauf = null;
anzeige = hochladeAnzeige($('anhang-fortschritt'),
`Sprachnachricht (${dauerWort(dauer)})`, () => lauf && lauf.abbrechen());
/* DIE ENDUNG IM NAMEN FOLGT DEM TYP, nicht umgekehrt. Der Server
bestimmt sie ohnehin aus den ersten Bytes neu -- hier geht es
nur darum, dass in der Datenbank kein "aufnahme.webm" steht,
wenn es eine m4a ist. */
const endung = /mp4/.test(typ) ? 'm4a' : /ogg/.test(typ) ? 'ogg' : 'webm';
lauf = hochladen(`/workspace/api/chat/raeume/${offen.id}/anhang`, brocken, {
kopf: {
'Content-Type': typ,
'X-Dateiname': encodeURIComponent(`Sprachnachricht.${endung}`),
'X-Text': encodeURIComponent(begleittext),
'X-Dauer': String(Math.round(dauer)),
},
beiFortschritt: anzeige.fortschritt,
beiVerarbeitung: anzeige.verarbeiten,
});
const ergebnis = await lauf.fertig;
if (ergebnis.abgebrochen) {
anzeige.abschluss('Abgebrochen – nichts wurde geschickt.');
anzeige = null;
return;
}
if (!ergebnis.ok) {
melde(ergebnis.netz ? 'Keine Verbindung – die Sprachnachricht wurde nicht geschickt.'
: sagWas(ergebnis.daten?.fehler, 'Ging nicht.'));
return;
}
nachrichtUebernehmen(ergebnis.daten?.nachricht);
} catch {
melde('Keine Verbindung – die Sprachnachricht wurde nicht geschickt.');
} finally {
if (anzeige) anzeige.weg();
schicktGerade = false;
$('anhang-auf').disabled = false;
if ($('ton-auf')) $('ton-auf').disabled = false;
}
}
$('ton-auf')?.addEventListener('click', () => {
if (tonGeraet) { tonAbsicht = 'senden'; tonStoppen(); return; }
void tonStarten();
});
$('ton-senden')?.addEventListener('click', () => { tonAbsicht = 'senden'; tonStoppen(); });
$('ton-weg')?.addEventListener('click', () => { tonAbsicht = 'weg'; tonStoppen(); });
/* WER DIE SEITE VERLAESST, LAESST DAS MIKROFON NICHT AN. */
window.addEventListener('pagehide', () => { tonAbsicht = 'weg'; tonStoppen(); tonAufraeumen(); });
$('anhang-auf').addEventListener('click', () => $('anhang-feld').click());
$('anhang-feld').addEventListener('change', () => {
const datei = $('anhang-feld').files?.[0];
+18 -18
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -367,17 +367,17 @@
<!-- 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=202609230135"></script>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/textform.js?v=202609230151"></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/zuteilung.js?v=202609230135" defer></script>
<script src="assets/js/aufgaben.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/zuteilung.js?v=202609230151" defer></script>
<script src="assets/js/aufgaben.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -168,15 +168,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/automation.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/automation.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -197,15 +197,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/befinden.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/befinden.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</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=202609230135"></script>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/textform.js?v=202609230151"></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/checkliste.js?v=202609230135" defer></script>
<script src="assets/js/ampel.js?v=202609230135" defer></script>
<script src="assets/js/schulung.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/bereich.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/checkliste.js?v=202609230151" defer></script>
<script src="assets/js/ampel.js?v=202609230151" defer></script>
<script src="assets/js/schulung.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/bereich.js?v=202609230151" defer></script>
</body>
</html>
+18 -18
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -108,14 +108,14 @@
</main>
<!-- Der Fuß gehört zu jeder Seite - siehe pruef-css-klassen. -->
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/auskunft.js?v=202609230135" defer></script>
<script src="assets/js/bewerben.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/auskunft.js?v=202609230151" defer></script>
<script src="assets/js/bewerben.js?v=202609230151" defer></script>
</body>
</html>
+17 -17
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -80,15 +80,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/auskunft.js?v=202609230135" defer></script>
<script src="assets/js/bewerbungen.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/auskunft.js?v=202609230151" defer></script>
<script src="assets/js/bewerbungen.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -89,15 +89,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/ki.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/calls.js?v=202609230135" defer></script>
<script src="assets/js/ki.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/calls.js?v=202609230151" defer></script>
</body>
</html>
+64 -19
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -274,6 +274,28 @@
verdeckt -- also genau dann unsichtbar, wenn man ihn
braucht. -->
<p class="hochlade" id="anhang-fortschritt" hidden></p>
<!-- DIE AUFNAHME LÄUFT (23.09.2026)
Über der Schreibzeile und nicht darunter -- aus demselben
Grund wie der Hochladebalken darüber: Am Handy sitzt die
Leiste direkt über der Tastatur, alles darunter wäre
verdeckt.
DIE ZEIT STEHT DA, GROß. Ohne sie weiß niemand, ob noch
aufgenommen wird — und man redet in eine Aufnahme, die
längst steht, oder hört auf, während sie läuft.
`aria-live` sagt sie auch dem vor, der nicht hinsieht;
bewusst nur alle fünf Sekunden (siehe chat.js), sonst
spricht das Vorleseprogramm im Sekundentakt. -->
<div class="tonleiste" id="tonleiste" hidden role="group"
aria-label="Sprachnachricht aufnehmen">
<span class="tonleiste__punkt" aria-hidden="true"></span>
<span class="tonleiste__zeit" id="ton-zeit">0:00</span>
<span class="tonleiste__wort" id="ton-wort" aria-live="polite">nimmt auf …</span>
<button type="button" class="tonleiste__weg" id="ton-weg"
aria-label="Aufnahme verwerfen" title="Verwerfen">&#10005;</button>
<button type="button" class="tonleiste__senden" id="ton-senden"
aria-label="Sprachnachricht abschicken" title="Abschicken">&#10003;</button>
</div>
<form class="chat__eingabe" id="schreiben" hidden>
<div class="antwort-leiste" id="antwort-leiste" hidden>
<span class="antwort-leiste__strich" aria-hidden="true"></span>
@@ -307,6 +329,29 @@
<path d="M20 11.5 12.3 19.2a4.4 4.4 0 0 1-6.2-6.2l7.9-7.9a2.9 2.9 0 0 1 4.1 4.1l-7.9 7.9a1.5 1.5 0 0 1-2.1-2.1l7.2-7.2" />
</svg>
</button>
<!-- SPRACHNACHRICHT (23.09.2026)
Filipe: „dan will ich auch dass man im chat auch
sprachnachrichten und gifts reinschicken kann. also nur die
modis rechte linke hand und dogfather."
ER STEHT VON HAUS AUS AUF `hidden`. Ob er erscheint, sagt
der Server mit `darf_ton` beim Öffnen eines Gesprächs --
hier steht keine Rolle. Ein Knopf, der da ist und dann
abgelehnt wird, ist schlimmer als keiner.
TIPPEN, NICHT HALTEN. Gedrückthalten ist der bekanntere
Weg, aber der schlechtere: Wer beim Sprechen den Finger
verrutscht, verliert die ganze Aufnahme, und mit einer
Hand am Lenker, am Kind oder am Kaffee hält niemand
neunzig Sekunden still. Einmal tippen startet, der
Häkchen-Knopf schickt, das Kreuz verwirft. -->
<button type="button" class="chat__ton" id="ton-auf" hidden
aria-label="Sprachnachricht aufnehmen" title="Sprachnachricht aufnehmen">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 3.5a2.6 2.6 0 0 1 2.6 2.6v5.4a2.6 2.6 0 0 1-5.2 0V6.1A2.6 2.6 0 0 1 12 3.5Z" />
<path d="M6.4 11a5.6 5.6 0 0 0 11.2 0M12 16.6V20M9.2 20h5.6" />
</svg>
</button>
<textarea id="text" rows="1" maxlength="4000"
placeholder="Nachricht schreiben …"
title="Enter schickt ab, Umschalt+Enter macht eine neue Zeile, @ erwähnt jemanden"></textarea>
@@ -415,25 +460,25 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609230135"></script>
<script src="assets/js/bereiche.js?v=202609230151"></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=202609230135"></script>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135"></script>
<script src="assets/js/glocke.js?v=202609230135"></script>
<script src="assets/js/textform.js?v=202609230151"></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151"></script>
<script src="assets/js/glocke.js?v=202609230151"></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=202609230135"></script>
<script src="assets/js/chat.js?v=202609230135"></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/anruf.js?v=202609230151"></script>
<script src="assets/js/chat.js?v=202609230151"></script>
<script src="assets/js/installieren.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/content.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/content.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -179,15 +179,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/checkliste.js?v=202609230135" defer></script>
<script src="assets/js/content.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/checkliste.js?v=202609230151" defer></script>
<script src="assets/js/content.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609230151" />
</head>
<body class="gate gate--crew">
@@ -459,7 +459,7 @@
<script src="assets/js/gate.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/gate.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
</body>
</html>
+4 -4
View File
@@ -23,25 +23,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609230135",
"src": "/assets/img/app-symbole/crew-192.png?v=202609230151",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609230135",
"src": "/assets/img/app-symbole/crew-512.png?v=202609230151",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609230135",
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609230151",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609230135",
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609230151",
"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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -108,15 +108,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/dateien.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/dateien.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -262,15 +262,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/entwicklung.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/entwicklung.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -146,13 +146,13 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/hilfe.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/hilfe.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
</head>
<body class="gate">
@@ -427,7 +427,7 @@
<script src="assets/js/gate.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/gate.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -383,15 +383,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/kalender.js?v=202609230135" defer></script>
<script src="assets/js/kalender-abo.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/kalender.js?v=202609230151" defer></script>
<script src="assets/js/kalender-abo.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -444,13 +444,13 @@
</form>
</dialog>
<script src="assets/js/meldung.js?v=202609230135"></script>
<script src="assets/js/nachfrage.js?v=202609230135"></script>
<script src="assets/js/wahl.js?v=202609230135"></script>
<script src="assets/js/bereiche.js?v=202609230135"></script>
<script src="assets/js/kopf.js?v=202609230135"></script>
<script src="assets/js/glocke.js?v=202609230135"></script>
<script src="assets/js/leistung.js?v=202609230135"></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151"></script>
<script src="assets/js/nachfrage.js?v=202609230151"></script>
<script src="assets/js/wahl.js?v=202609230151"></script>
<script src="assets/js/bereiche.js?v=202609230151"></script>
<script src="assets/js/kopf.js?v=202609230151"></script>
<script src="assets/js/glocke.js?v=202609230151"></script>
<script src="assets/js/leistung.js?v=202609230151"></script>
<script src="assets/js/installieren.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/material.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/material.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</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=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/material.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/material.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -453,14 +453,14 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/personen.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/personen.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -214,16 +214,16 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/steckbrief.js?v=202609230135" defer></script>
<script src="assets/js/profil.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/steckbrief.js?v=202609230151" defer></script>
<script src="assets/js/profil.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -134,13 +134,13 @@
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=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/rechte.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/rechte.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/report.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/report.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -106,17 +106,17 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/ki.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/report.js?v=202609230135" defer></script>
<script src="assets/js/ki.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/report.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -173,14 +173,14 @@
</div>
</div>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/scouting.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/scouting.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -684,16 +684,16 @@
</p>
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/live.js?v=202609230135" defer></script>
<script src="assets/js/start.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/live.js?v=202609230151" defer></script>
<script src="assets/js/start.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -85,16 +85,16 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/ki.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/startcheck.js?v=202609230135" defer></script>
<script src="assets/js/ki.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/startcheck.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -150,16 +150,16 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/auskunft.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/steckbrief.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/auskunft.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/steckbrief.js?v=202609230151" defer></script>
</body>
</html>
+17 -17
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -111,14 +111,14 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/talente.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/talente.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/team.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/team.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -110,15 +110,15 @@
</main>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/team.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/team.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/team.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/team.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<!-- `data-buehne` steht hier fest und nicht im Skript: Die Kachel zu
@@ -84,14 +84,14 @@
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=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/holen.js?v=202609230135" defer></script>
<script src="assets/js/teamlage.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/holen.js?v=202609230151" defer></script>
<script src="assets/js/teamlage.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -112,14 +112,14 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/teilen.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/teilen.js?v=202609230151" defer></script>
</body>
</html>
+15 -15
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -126,13 +126,13 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/treff-moderation.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/treff-moderation.js?v=202609230151" defer></script>
</body>
</html>
+15 -15
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -248,13 +248,13 @@
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=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/auskunft.js?v=202609230135" defer></script>
<script src="assets/js/treff-regeln.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/auskunft.js?v=202609230151" defer></script>
<script src="assets/js/treff-regeln.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -149,16 +149,16 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/uebersicht.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/uebersicht.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -335,13 +335,13 @@
</main>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/live.js?v=202609230135" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/live.js?v=202609230151" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609230151" defer></script>
</body>
</html>
+15 -15
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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -144,13 +144,13 @@
</main>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/werdegang.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/werdegang.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</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=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/willkommen.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/willkommen.js?v=202609230151" 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=202609230135" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230135" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609230135" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230135" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609230151" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609230151" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/start.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609230151" />
<link rel="stylesheet" href="assets/css/module.css?v=202609230151" />
<!-- 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=202609230135" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609230151" />
</head>
<body class="start">
@@ -190,15 +190,15 @@
</main>
<script src="assets/js/meldung.js?v=202609230135" defer></script>
<script src="assets/js/hochladen.js?v=202609230135" defer></script>
<script src="assets/js/nachfrage.js?v=202609230135" defer></script>
<script src="assets/js/meldung.js?v=202609230151" defer></script>
<script src="assets/js/hochladen.js?v=202609230151" defer></script>
<script src="assets/js/nachfrage.js?v=202609230151" defer></script>
<script src="assets/js/wahl.js?v=202609230135" defer></script>
<script src="assets/js/bereiche.js?v=202609230135" defer></script>
<script src="assets/js/installieren.js?v=202609230135" defer></script>
<script src="assets/js/kopf.js?v=202609230135" defer></script>
<script src="assets/js/glocke.js?v=202609230135" defer></script>
<script src="assets/js/wissen.js?v=202609230135" defer></script>
<script src="assets/js/wahl.js?v=202609230151" defer></script>
<script src="assets/js/bereiche.js?v=202609230151" defer></script>
<script src="assets/js/installieren.js?v=202609230151" defer></script>
<script src="assets/js/kopf.js?v=202609230151" defer></script>
<script src="assets/js/glocke.js?v=202609230151" defer></script>
<script src="assets/js/wissen.js?v=202609230151" defer></script>
</body>
</html>