screen4: Dogi-Media — bearbeiten, entfernen, von wann bis wann

Filipe, 22.09.2026: "wenn wir in der kategorie material was hochladen
will ich dass die rechte und linke hand es auch bearbeiten und loeschen
koennen. dogfather auch fals es ein fehler gab. ... uebrigens ersetz das
wort material durch Dogi-Media. und mach kategorien welche sind benutzt
welche nicht welche sind noch offen, welche laufen von wan bis wann."

WAS JETZT GEHT
- Rechte Hand, linke Hand und DogFather bearbeiten und entfernen jedes
  Stueck, nicht nur ihr eigenes. Bearbeitet wird Text und Zeitfenster,
  nicht die Datei: Sonst zeigte dieselbe Nummer etwas anderes als das,
  was sich jemand gerade angesehen hat.
- Ein vergebenes Stueck bleibt unberuehrt (409). Wer es genommen hat,
  hat sich auf diesen Text verlassen.
- Vier Zustaende, gerechnet statt gespeichert: jetzt frei, kommt noch,
  abgelaufen, schon benutzt. Die Kategorieleiste zeigt zu jedem die
  Anzahl aus den echten Daten und filtert BEIDE Listen.
- "Material" heisst ueberall "Dogi-Media", der Dateiname bleibt.

DREI FEHLER AUS DEM EIGENEN ENTWURF, ALLE VOR DEM AUSLIEFERN GEMESSEN

1. `tagLokal()` ohne Argument gab "NaN-NaN-NaN" zurueck -- eine
   Zeichenkette, die aussieht wie ein Datum. Im Vergleich gewinnt das N
   gegen jede Ziffer, also galt JEDES Stueck mit Enddatum vom ersten Tag
   an als abgelaufen, und "Kommt noch" gab es nie. Kein Absturz, keine
   Meldung. Die drei Kopien der Funktion waren hier auseinandergelaufen;
   alle drei haben jetzt die Vorbelegung und werfen bei einer Zahl, die
   keine ist.
2. `frageNach` liefert bei einer reinen Rueckfrage `true`, nicht
   `{ ok: true }`. Der Entwurf prueft auf `erg?.ok` -- "Entfernen" waere
   ein Knopf gewesen, der nichts tut.
3. Drei erfundene Klassennamen (`knopf--leise`, `m-kat__knopf`,
   `m-karte__weg-knopf`) statt der vorhandenen des Hauses. Jetzt
   `.knopf-still`, `.knopf-still--warn` und die Filterleiste `.filter`.

EIN FUND IM BESTAND, ZWEI WOCHEN ALT

In start.css fehlten an einer Stelle die zwei Zeichen, die einen
Kommentar schliessen. CSS-Kommentare schachteln nicht: Der Block lief
bis zum naechsten Abschluss weiter und verschluckte `.kacheln {`; die
Fehlerbehebung des Browsers nahm danach auch die Regel `.kachel` mit.
In Chromium gemessen, beide Fassungen nacheinander: 738 statt 740
Regeln.

Der Entwurf, der dadurch nie gewirkt hat, ist NICHT wiederhergestellt
worden: Seine Flaeche mischte den Kachelton mit 30/11/3 Prozent ein --
pruef-kachelfarben fiel sofort von 36,5 % auf 4,1 % angekommene Farbe,
und 31 Toene sahen gleich aus. Das ist das Gegenteil dessen, was am
22.09. verlangt war. Er ist geloescht, mit dem Grund daneben. Offen
bleibt eine Frage an Filipe, keine Entscheidung von mir: zu demselben
Entwurf gehoerte ein schmaleres Kachelraster (fuenf bis sechs statt
drei pro Reihe). Das aendert das Aussehen der Startseite sichtbar und
bleibt deshalb, wie es ist.

GEMEINSAME BAUSTEINE AUS DEN SEITENDATEIEN GEHOLT
`.filter` stand Zeichen fuer Zeichen doppelt in dateien.css und
bereich.css, `.feld-hinweis` in aufgaben.css und leistung.css (und die
zwei waren schon auseinandergelaufen). Dogi-Media war jeweils die
dritte Seite, die sie braucht, und laedt keine davon. Derselbe Fehler
wie damals bei .knopf-still und beim Schalter -- jetzt in gate.css
bzw. start.css.

GEPRUEFT
pruef-material 155/0 (von 126, neu: Zeitfenster, Bearbeiten, Entfernen,
Rechte in der Liste und ein Abschnitt am echten Bildschirm mit Browser).
pruef-css-klassen um eine Pruefung erweitert, die genau den
start.css-Fehler findet -- mit sieben Gegenproben, darunter der echte
Fall. pruef-kachelfarben 22/0, pruef-start-ansicht, pruef-struktur,
pruef-meldungen, pruef-zeitraum, pruef-content, pruef-serien 69/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-22 13:59:55 +02:00
co-authored by Claude Opus 5
parent fe1dad48e5
commit fc823240ab
54 changed files with 2287 additions and 668 deletions
+24 -1
View File
@@ -41,8 +41,31 @@ export function heuteLokal() {
return `${d.getFullYear()}-${zwei(d.getMonth() + 1)}-${zwei(d.getDate())}`;
}
/** Derselbe Tag, um `versatz` Tage verschoben. Negativ heißt zurück. */
/** Derselbe Tag, um `versatz` Tage verschoben. Negativ heißt zurück.
*
* ZWEI DINGE AM 22.09.2026 NACHGEZOGEN, beide durch einen echten Schaden:
*
* (1) `versatz = 0`. Dogi-Media rief `tagLokal()` ohne Argument auf und
* bekam `"NaN-NaN-NaN"` zurück -- eine Zeichenkette, die aussieht
* wie ein Datum und sich wie keines verhält. Im Vergleich
* `"2026-12-31" < "NaN-NaN-NaN"` gewinnt das N, also galt JEDES
* Stück mit Enddatum vom ersten Tag an als abgelaufen, und
* "Kommt noch" gab es nie. Kein Absturz, keine Meldung, keine
* Zeile im Protokoll -- nur eine Seite, die etwas anderes zeigt
* als die Wahrheit. Die drei Kopien dieser Funktion waren an
* dieser Stelle auseinandergelaufen: helfer-tag.mjs hatte die
* Vorbelegung, die beiden anderen nicht.
*
* (2) Der Wurf bei einer Zahl, die keine ist. Eine Vorbelegung deckt
* nur den leeren Aufruf ab; `tagLokal(irgendwas)` mit einer
* undefinierten Variablen läge weiter still daneben. Ein Datum,
* das sich nicht ausrechnen lässt, muss SCHEITERN und nicht
* schweigen -- sonst wandert der Unsinn in die Datenbank und in
* die Anzeige, und gefunden wird er Wochen später. */
export function tagLokal(versatz = 0) {
if (!Number.isFinite(Number(versatz))) {
throw new TypeError(`tagLokal: "${versatz}" ist keine Zahl von Tagen.`);
}
const d = new Date(Date.now() + versatz * 86400_000);
return `${d.getFullYear()}-${zwei(d.getMonth() + 1)}-${zwei(d.getDate())}`;
}
+25 -2
View File
@@ -40,12 +40,35 @@ export function heuteLokal() {
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
}
/** Derselbe Tag, um n Tage verschoben (negativ = in der Vergangenheit).
/** Derselbe Tag, um `versatz` Tage verschoben. Negativ heißt zurück.
*
* ZWEI DINGE AM 22.09.2026 NACHGEZOGEN, beide durch einen echten Schaden:
*
* (1) `versatz = 0`. Dogi-Media rief `tagLokal()` ohne Argument auf und
* bekam `"NaN-NaN-NaN"` zurück -- eine Zeichenkette, die aussieht
* wie ein Datum und sich wie keines verhält. Im Vergleich
* `"2026-12-31" < "NaN-NaN-NaN"` gewinnt das N, also galt JEDES
* Stück mit Enddatum vom ersten Tag an als abgelaufen, und
* "Kommt noch" gab es nie. Kein Absturz, keine Meldung, keine
* Zeile im Protokoll -- nur eine Seite, die etwas anderes zeigt
* als die Wahrheit. Die drei Kopien dieser Funktion waren an
* dieser Stelle auseinandergelaufen: helfer-tag.mjs hatte die
* Vorbelegung, die beiden anderen nicht.
*
* (2) Der Wurf bei einer Zahl, die keine ist. Eine Vorbelegung deckt
* nur den leeren Aufruf ab; `tagLokal(irgendwas)` mit einer
* undefinierten Variablen läge weiter still daneben. Ein Datum,
* das sich nicht ausrechnen lässt, muss SCHEITERN und nicht
* schweigen -- sonst wandert der Unsinn in die Datenbank und in
* die Anzeige, und gefunden wird er Wochen später.
*
* Gerechnet wird über die Millisekunden und danach lokal ausgelesen.
* `setDate(getDate() + n)` täte es auch, hat aber an den zwei
* Umstellungstagen im Jahr seine Tücken. */
export function tagLokal(versatz) {
export function tagLokal(versatz = 0) {
if (!Number.isFinite(Number(versatz))) {
throw new TypeError(`tagLokal: "${versatz}" ist keine Zahl von Tagen.`);
}
const d = new Date(Date.now() + versatz * 86400_000);
const p = (n) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
+149
View File
@@ -693,5 +693,154 @@ console.log("\n=== module.css: die Modulliste steht siebenmal — und überall g
`die zweite Wand laedt ihr Haus zuletzt (${wandBl.length} Stilvorlagen)`);
}
/* =========================================================================
IST DAS CSS UEBERHAUPT HEIL? (22.09.2026)
=========================================================================
ENTSTANDEN AUS EINEM ECHTEN FEHLER, der zwei Wochen live stand.
In start.css fehlten an einer Stelle die zwei Zeichen, die einen
Kommentar schliessen:
...
der Inhalt darin angeordnet ist.
=====================================================
<- hier gehoerte `*` `/` hin
.kacheln {
CSS-Kommentare schachteln NICHT. Der Block lief deshalb weiter bis
zum naechsten Abschluss -- und der stand mitten in `.kacheln`.
Verschluckt wurde damit die oeffnende Klammer. Die Fehlerbehebung
des Browsers hat danach auch noch die FOLGENDE Regel mitgenommen,
weil sie deren Rumpf als Block einer ungueltigen Auswahl las.
Gemessen in Chromium, beide Fassungen nacheinander: 738 statt 740
Regeln. Sichtbar war es als Kachelreihe mit drei Spalten zu 413 px
statt fuenf zu 243 px.
WARUM ES NIEMANDEM AUFFIEL: Eine aeltere `.kacheln`-Regel weiter
oben sprang ein. Die Seite sah nicht kaputt aus -- nur anders als
gemeint. Das ist die gefaehrlichste Sorte: Es gibt nichts zu melden,
keinen Fehler in der Konsole, keinen roten Haken. Nur eine Seite,
die etwas anderes zeigt als das, was im Quelltext steht.
WAS HIER GEMESSEN WIRD -- und warum gerade das:
Auf oberster Ebene einer Stilvorlage darf nur dreierlei stehen: eine
Auswahl mit ihrem Block, eine At-Regel, und Leerraum. Steht dort
eine ANGABE (`gap: 12px;`) oder eine schliessende Klammer ohne ihre
oeffnende, dann ist etwas verschluckt worden -- fast immer ein
Kommentar ohne Abschluss.
Das ist strenger als blosses Klammernzaehlen: Eine Klammernprobe ist
gruen, solange gleich viele auf- wie zugehen, auch wenn ein
Kommentar mittendrin einen ganzen Block gefressen hat.
Kommentare und Zeichenketten werden dabei genauso ueberlesen, wie
der Browser sie ueberliest -- sonst schlaegt die Pruefung bei jedem
`/* ... } ... *' + '/` an, und eine Warnung, die immer kommt, ist
keine mehr.
========================================================================= */
console.log("\n=== Ist das CSS ueberhaupt heil? ===");
/** Alle Formfehler einer Stilvorlage. Leeres Feld = in Ordnung. */
function formfehler(text) {
const funde = [];
const zeileVon = (stelle) => text.slice(0, stelle).split("\n").length;
let i = 0, tiefe = 0, puffer = "", pufferAb = 0;
while (i < text.length) {
const c = text[i];
if (c === "/" && text[i + 1] === "*") {
const auf = i;
i += 2;
while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) i++;
if (i >= text.length) {
funde.push({ zeile: zeileVon(auf), was: "ein Kommentar wird nie geschlossen" });
break;
}
i += 2;
continue;
}
if (c === '"' || c === "'") {
const q = c; i++;
while (i < text.length && text[i] !== q) { if (text[i] === "\\") i++; i++; }
i++; continue;
}
if (tiefe === 0) {
if (c === "{") { tiefe = 1; puffer = ""; pufferAb = i + 1; i++; continue; }
if (c === ";") {
/* `@import url(...);` und Geschwister duerfen auf oberster
Ebene mit einem Strichpunkt enden. Alles andere nicht. */
if (!puffer.trim().startsWith("@")) {
funde.push({
zeile: zeileVon(pufferAb),
was: "eine Angabe steht ausserhalb jeder Regel",
beleg: puffer.trim().slice(0, 70).replace(/\s+/g, " "),
});
}
puffer = ""; pufferAb = i + 1; i++; continue;
}
if (c === "}") {
funde.push({ zeile: zeileVon(i), was: "eine schliessende Klammer ohne oeffnende" });
puffer = ""; pufferAb = i + 1; i++; continue;
}
puffer += c; i++; continue;
}
if (c === "{") tiefe++;
else if (c === "}") tiefe--;
if (tiefe === 0) { puffer = ""; pufferAb = i + 1; }
i++;
}
if (tiefe !== 0) {
funde.push({ zeile: "Ende", was: `${tiefe} Regel(n) werden nie geschlossen` });
}
return funde;
}
{
const css = readdirSync(join(WS, "assets", "css")).filter((n) => n.endsWith(".css"));
/* DRITTER AUSGANG: Ohne Dateien misst die Pruefung nichts, und "0
Fehler" waere dann ein gruener Haken fuer gar nichts. */
ok(css.length > 20, `${css.length} Stilvorlagen gefunden`);
const kaputt = [];
for (const name of css) {
const funde = formfehler(readFileSync(join(WS, "assets", "css", name), "utf8"));
for (const f of funde) {
kaputt.push(`${name}:${f.zeile} — ${f.was}` + (f.beleg ? ` ("${f.beleg}")` : ""));
}
}
ok(kaputt.length === 0 && css.length > 20,
kaputt.length
? `${kaputt.length} Stelle(n), an denen CSS still verloren geht:\n `
+ kaputt.join("\n ")
: `keine Stilvorlage verliert still eine Regel (${css.length} geprueft)`);
/* GEGENPROBEN: Die Pruefung muss beides koennen -- anschlagen und
schweigen. Der vorletzte Fall ist der echte von start.css,
Zeichen fuer Zeichen nachgebaut. */
const proben = [
["gesundes CSS", ".a{b:c} /* } *" + "/ .d[e=';']{f:g}", false],
["@import mit Strichpunkt", "@import url(x.css); .a{b:c}", false],
["Kommentar ohne Abschluss", ".a{b:c} /* geht nie zu", true],
["Angabe ausserhalb jeder Regel", "gap: 12px; .a{b:c}", true],
["schliessende Klammer zu viel", ".a{b:c}}", true],
["Regel ohne Abschluss", ".a{b:c", true],
["der Fall aus start.css", "/* Titel\n ====\n\n.kacheln {\n /* innen *" + "/\n"
+ " gap: 12px;\n}\n\n.kachel { color: red; }", true],
];
const daneben = proben.filter(([, text, soll]) => (formfehler(text).length > 0) !== soll);
ok(daneben.length === 0 && proben.length === 7,
daneben.length
? `Gegenprobe daneben bei: ${daneben.map((p) => p[0]).join(", ")}`
: `Gegenprobe: alle ${proben.length} Faelle richtig eingeordnet `
+ `(darunter der echte aus start.css)`);
}
console.log(`\n${fehler === 0 ? "ALLES IN ORDNUNG" : `${fehler} FEHLER`}`);
process.exit(fehler ? 1 : 0);
+609 -5
View File
@@ -72,7 +72,10 @@ const express = (await import("express")).default;
const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
notbremse(240_000, "pruef-material");
/* 240 -> 480 s (22.09.2026): Seit Abschnitt 13 faehrt ein echter
Browser mit. Eine Notbremse, die vor dem letzten Abschnitt
zuschlaegt, macht aus einer langsamen Pruefung eine rote. */
notbremse(480_000, "pruef-material");
await new Promise((r) => setTimeout(r, 900));
process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f); process.exit(7); });
@@ -182,12 +185,17 @@ const PNG = Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
"base64");
function einstellen(keks, name, text = "") {
function einstellen(keks, name, text = "", fenster = {}) {
return roh("/workspace/api/material", {
methode: "POST", roh: PNG, typ: "image/png", keks,
kopf: {
"X-Datei-Name": encodeURIComponent(name),
"X-Text": encodeURIComponent(text),
/* NUR MITSCHICKEN, WENN ES ETWAS ZU SCHICKEN GIBT. Ein leerer
Kopf ist etwas anderes als ein fehlender, und die Pruefung
soll beides treffen koennen. */
...(fenster.ab !== undefined ? { "X-Gilt-Ab": fenster.ab } : {}),
...(fenster.bis !== undefined ? { "X-Gilt-Bis": fenster.bis } : {}),
},
});
}
@@ -421,19 +429,615 @@ melde("=== 8. Die Grenzen des Bereichs ===");
for (const r of ["gast", "modi", "hand", "linke", "admin"]) {
const treffer = [...(w.bereicheFuer({ rolle: r, haus: "crew" }) || [])]
.filter((k) => k.ziel === "material.html");
ok(treffer.length === 1 && treffer[0].name === "Material",
/* HEISST SEIT DEM 22.09.2026 "Dogi-Media" (Filipe: "ersetz das wort
material durch Dogi-Media"). Der DATEINAME bleibt material.html:
Eine Adresse umzubenennen bricht jedes Lesezeichen und jeden
Verweis, und der sichtbare Name ist das, was zaehlt -- dieselbe
Entscheidung wie bei "Unsere Seiten" -> "Draussen". */
ok(treffer.length === 1 && treffer[0].name === "Dogi-Media",
`${r} hat genau eine Kachel dorthin (${treffer.length}, "${treffer[0]?.name}")`);
}
}
/* =====================================================================
9. VON WANN BIS WANN (22.09.2026)
=====================================================================
Filipe: "mach kategorien welche sind benutzt welche nicht welche sind
noch offen, welche laufen von wan bis wann, das muss man auch machen
koennen und detailliert perfektioniert."
GERECHNET WIRD RELATIV ZU HEUTE, nie mit einem festen Datum. Ein
Test, der "2026-10-01" als Zukunft annimmt, ist am 2. Oktober rot,
ohne dass irgendetwas kaputt waere -- und ein Fehlalarm, den niemand
nachstellen kann, schaltet den ganzen Satz ab.
===================================================================== */
melde("");
melde("=== 9. Der Zeitraum: gesetzt, gespeichert, gerechnet ===");
const { tagLokal } = await import("./helfer-tag.mjs");
const HEUTE = tagLokal(0);
const GESTERN = tagLokal(-1);
const VORGESTERN = tagLokal(-2);
const MORGEN = tagLokal(1);
const IN10 = tagLokal(10);
{
/* Vier Stuecke, eines je Zustand -- und zwar wirklich vier, nicht
drei und eine Annahme. Die Zaehlung unten prueft das. */
const faelle = [
["ohne-fenster.png", {}, "frei"],
["laeuft-schon.png", { ab: VORGESTERN, bis: IN10 }, "frei"],
["kommt-noch.png", { ab: MORGEN, bis: IN10 }, "spaeter"],
["ist-vorbei.png", { ab: VORGESTERN, bis: GESTERN }, "abgelaufen"],
];
for (const [name, f, erwartet] of faelle) {
const r = await einstellen(chef.keks, name, "Probe", f);
ok(r.code === 201 && Number.isInteger(r.json?.id),
`"${name}" angelegt (${r.code})`);
}
const l = await liste(chef.keks);
const finde = (n) => (l.json?.material || []).find((m) => m.name === n);
for (const [name, f, erwartet] of faelle) {
const m = finde(name);
ok(!!m && m.zustand === erwartet,
`"${name}" steht als "${erwartet}" da (${m?.zustand})`);
ok(!!m && (m.gilt_ab || null) === (f.ab || null)
&& (m.gilt_bis || null) === (f.bis || null),
`"${name}" gibt sein Fenster unveraendert zurueck `
+ `(${m?.gilt_ab} / ${m?.gilt_bis})`);
}
/* DER HEUTIGE TAG KOMMT MIT UND IST EIN ECHTES DATUM.
Genau hier lag der Fehler, der diese Pruefung ausgeloest hat:
`tagLokal()` ohne Argument gab "NaN-NaN-NaN" zurueck. Beim
Zeichenkettenvergleich gewinnt das grosse N gegen jede Ziffer --
also galt jedes Stueck mit Enddatum sofort als abgelaufen, und
"Kommt noch" gab es nie. Kein Absturz, keine Meldung.
Deshalb wird die FORM geprueft, nicht nur die Anwesenheit. */
ok(/^\d{4}-\d{2}-\d{2}$/.test(String(l.json?.heute || "")),
`die Liste nennt den heutigen Tag als Datum ("${l.json?.heute}")`);
ok(l.json?.heute === HEUTE,
`und es ist wirklich heute (${l.json?.heute} vs ${HEUTE})`);
/* GEGENPROBE: Wuerde "heute" nicht stimmen, muesste die Rechnung
ein anderes Ergebnis liefern. Sonst misst der Test nur, dass
irgendetwas zurueckkommt. */
const { zustandVon } = await import("./workspace-material.js");
ok(zustandVon({ gilt_ab: MORGEN }, HEUTE) === "spaeter"
&& zustandVon({ gilt_ab: MORGEN }, "NaN-NaN-NaN") !== "spaeter",
"mit einem kaputten Tag faellt die Rechnung um -- die Probe kann also anschlagen");
/* ALLE VIER ZUSTAENDE KOMMEN AUCH WIRKLICH VOR. Ohne diese Zeile
waeren drei gruene Haken auch dann gruen, wenn ein Zustand gar
nicht mehr erreichbar ist. */
const NOETIG = ["frei", "spaeter", "abgelaufen"];
const gezaehlt = new Set((l.json?.material || []).map((m) => m.zustand));
const fehlend = NOETIG.filter((z) => !gezaehlt.has(z));
/* DIE ZAHL IM SATZ WIRD GEZAEHLT, NICHT GETIPPT. Der erste Entwurf
schrieb "drei Zustaende sind besetzt" und zaehlte daneben vier auf
-- ein Satz, der schon beim ersten Lesen nicht zu seiner eigenen
Klammer passte. */
ok(fehlend.length === 0,
`alle ${NOETIG.length} Zustaende aus diesem Abschnitt sind besetzt; `
+ `gefunden: ${[...gezaehlt].sort().join(", ")}`
+ (fehlend.length ? ` -- es fehlt: ${fehlend.join(", ")}` : ""));
}
melde("");
melde("=== 9b. Ein Fenster, das nicht geht ===");
{
const verkehrt = await einstellen(chef.keks, "verkehrt.png", "", { ab: IN10, bis: GESTERN });
ok(verkehrt.code === 400 && verkehrt.json?.fehler === "fenster_verkehrt",
`Ende vor Anfang wird abgelehnt (${verkehrt.code}/${verkehrt.json?.fehler})`);
const quatsch = await einstellen(chef.keks, "quatsch.png", "", { ab: "morgen frueh" });
ok(quatsch.code === 400 && quatsch.json?.fehler === "datum_unbrauchbar",
`ein Datum, das keines ist, wird abgelehnt (${quatsch.code}/${quatsch.json?.fehler})`);
/* GEGENPROBE zu beiden: Dasselbe ohne Fenster muss durchgehen --
sonst koennte die Ablehnung auch an etwas ganz anderem liegen. */
const sauber = await einstellen(chef.keks, "sauber.png", "", { ab: HEUTE, bis: IN10 });
ok(sauber.code === 201, `dasselbe mit gueltigem Fenster geht (${sauber.code})`);
/* UND NICHTS DAVON IST LIEGENGEBLIEBEN. Eine abgelehnte Anfrage darf
keine halbe Datei im Ordner hinterlassen. */
const l = await liste(chef.keks);
const namen = (l.json?.material || []).map((m) => m.name);
ok(!namen.includes("verkehrt.png") && !namen.includes("quatsch.png"),
"die abgelehnten Stuecke stehen nirgends in der Liste");
}
/* =====================================================================
10. BEARBEITEN -- wer darf, und was bleibt unberuehrt
=====================================================================
Filipe: "wenn wir in der kategorie material was hochladen will ich
dass die rechte und linke hand es auch bearbeiten und loeschen
koennen. dogfather auch fals es ein fehler gab."
===================================================================== */
melde("");
melde("=== 10. Bearbeiten ===");
const aendern = (id, keks, was) =>
roh(`/workspace/api/material/${id}`, { methode: "PATCH", keks, body: was });
{
/* Das Stueck gehoert der RECHTEN HAND -- damit ist jede Aenderung
durch jemand anderen eine FREMDE Aenderung. Haette es DogFather
eingestellt, waere sein eigener Zugriff kein Nachweis. */
const r = await einstellen(hand.keks, "fremdes-stueck.png", "Erster Text");
const id = r.json?.id;
ok(Number.isInteger(id), `Stueck der rechten Hand liegt (${r.code})`);
for (const [wer, s2] of [["DogFather", chef], ["rechte Hand", hand], ["linke Hand", linke]]) {
const a = await aendern(id, s2.keks, { text: `Geaendert von ${wer}` });
ok(a.code === 200 && a.json?.text === `Geaendert von ${wer}`,
`${wer} darf fremden Text aendern (${a.code})`);
}
for (const [wer, s2] of [["Modi", modi], ["Kessi (Community)", kessi]]) {
const a = await aendern(id, s2.keks, { text: "heimlich" });
ok(a.code === 403 || a.code === 404,
`${wer} darf nicht (${a.code}/${a.json?.fehler})`);
}
/* GEGENPROBE ZUR ABLEHNUNG: Der Text muss danach noch der von vorhin
sein. Eine 403, nach der die Aenderung trotzdem drinsteht, waere
der eigentliche Schaden -- und sie saehe von aussen richtig aus. */
const l = await liste(chef.keks);
const m = (l.json?.material || []).find((x) => x.id === id);
ok(m?.text === "Geaendert von linke Hand",
`und der Text ist unveraendert geblieben ("${m?.text}")`);
/* DAS FENSTER LAESST SICH NACHTRAEGLICH SETZEN UND WIEDER LEEREN.
Das Leeren ist der Fall, den man vergisst: Wer ein Enddatum
falsch getippt hat, muss es LOESCHEN koennen, nicht nur
ueberschreiben. */
const setzen = await aendern(id, hand.keks, { gilt_ab: MORGEN, gilt_bis: IN10 });
ok(setzen.code === 200 && setzen.json?.zustand === "spaeter",
`Fenster nachtraeglich gesetzt, Zustand "${setzen.json?.zustand}"`);
const leeren = await aendern(id, hand.keks, { gilt_ab: "", gilt_bis: "" });
ok(leeren.code === 200 && !leeren.json?.gilt_ab && !leeren.json?.gilt_bis
&& leeren.json?.zustand === "frei",
`und wieder geleert, Zustand "${leeren.json?.zustand}"`);
const verkehrt = await aendern(id, hand.keks, { gilt_ab: IN10, gilt_bis: GESTERN });
ok(verkehrt.code === 400 && verkehrt.json?.fehler === "fenster_verkehrt",
`ein verkehrtes Fenster wird auch beim Aendern abgelehnt (${verkehrt.code})`);
/* WAS NICHT MITGESCHICKT WIRD, BLEIBT. Sonst loescht jeder, der nur
den Text aendert, nebenbei das Fenster -- und merkt es nie. */
await aendern(id, hand.keks, { gilt_ab: MORGEN, gilt_bis: IN10 });
const nurText = await aendern(id, hand.keks, { text: "Nur der Text" });
ok(nurText.code === 200 && nurText.json?.gilt_ab === MORGEN
&& nurText.json?.gilt_bis === IN10,
`eine Aenderung nur am Text laesst das Fenster stehen `
+ `(${nurText.json?.gilt_ab} / ${nurText.json?.gilt_bis})`);
}
melde("");
melde("=== 10b. Was vergeben ist, bleibt, wie es ist ===");
{
const r = await einstellen(chef.keks, "schon-weg.png", "Steht so da");
const id = r.json?.id;
const n = await nehmen(id, modi.keks);
ok(n.code === 200, `ein Modi hat es genommen (${n.code})`);
const a = await aendern(id, chef.keks, { text: "nachtraeglich umgeschrieben" });
ok(a.code === 409 && a.json?.fehler === "schon_im_umlauf",
`selbst DogFather aendert es nicht mehr (${a.code}/${a.json?.fehler})`);
const l = await liste(chef.keks);
const m = (l.json?.material || []).find((x) => x.id === id);
ok(m?.text === "Steht so da", `der Text von damals steht noch ("${m?.text}")`);
ok(m?.zustand === "benutzt", `und der Zustand heisst "benutzt" (${m?.zustand})`);
/* Der vierte Zustand wird hier NEU erzeugt und nicht nur mitgezaehlt:
Weiter oben gibt es schon vergebene Stuecke aus Abschnitt 6, aber
dass AUSGERECHNET DIESES nach dem Nehmen "benutzt" heisst, ist die
Aussage -- und die gilt nur fuer das Stueck von eben. */
ok((l.json?.material || []).filter((x) => x.zustand === "benutzt").length >= 1,
"es gibt mindestens ein Stueck im Zustand \"benutzt\"");
}
/* =====================================================================
11. ENTFERNEN -- dieselbe Runde, andere Tuer
===================================================================== */
melde("");
melde("=== 11. Entfernen ===");
const wegnehmen = (id, keks) =>
roh(`/workspace/api/material/${id}`, { methode: "DELETE", keks });
{
for (const [wer, s2] of [["DogFather", chef], ["rechte Hand", hand], ["linke Hand", linke]]) {
/* Jedes Mal ein frisches Stueck von jemand anderem -- sonst
entfernte der Zweite nur noch eine Nummer, die es nicht gibt,
und bekaeme 404 statt eines echten Nachweises. */
const r = await einstellen(hand.keks, `weg-${wer}.png`, "");
const id = r.json?.id;
const w = await wegnehmen(id, s2.keks);
ok(w.code === 200, `${wer} darf ein fremdes Stueck entfernen (${w.code})`);
const l = await liste(chef.keks);
ok(!(l.json?.material || []).some((x) => x.id === id),
`und es ist danach wirklich weg`);
}
const r = await einstellen(hand.keks, "bleibt-liegen.png", "");
const id = r.json?.id;
for (const [wer, s2] of [["Modi", modi], ["Kessi (Community)", kessi]]) {
const w = await wegnehmen(id, s2.keks);
ok(w.code === 403 || w.code === 404,
`${wer} darf nicht entfernen (${w.code}/${w.json?.fehler})`);
}
const l = await liste(chef.keks);
ok((l.json?.material || []).some((x) => x.id === id),
"und das Stueck liegt danach immer noch da");
}
/* =====================================================================
12. WAS DIE LISTE UEBER DIE RECHTE SAGT
=====================================================================
Die Oberflaeche rechnet NICHT nach, wer was darf -- sie liest
`darf_ich` und `darf_verwalten`. Waeren die Angaben falsch, staenden
Knoepfe da, die beim Druecken eine Absage bringen; oder sie fehlten
dort, wo jemand darf. Beides ist schlimmer als ein Serverfehler,
weil es aussieht, als sei alles in Ordnung.
===================================================================== */
melde("");
melde("=== 12. Was die Liste ueber die Rechte sagt ===");
{
const r = await einstellen(hand.keks, "rechte-probe.png", "");
const id = r.json?.id;
const darf = { admin: true, hand: true, linke: true };
for (const [wer, s2, rolle] of [["DogFather", chef, "admin"], ["rechte Hand", hand, "hand"],
["linke Hand", linke, "linke"], ["Modi", modi, "modi"], ["Kessi", kessi, "gast"]]) {
const l = await liste(s2.keks);
const soll = darf[rolle] === true;
ok(l.json?.darf_verwalten === soll,
`${wer}: darf_verwalten = ${l.json?.darf_verwalten} (erwartet ${soll})`);
const m = (l.json?.material || []).find((x) => x.id === id);
ok(!!m && m.darf_ich === soll,
`${wer}: darf_ich am fremden Stueck = ${m?.darf_ich} (erwartet ${soll})`);
}
/* GEGENPROBE: Am EIGENEN Stueck muss `darf_ich` auch fuer jemanden
wahr sein, der fremde nicht anfassen darf. Sonst koennte das Feld
schlicht `darf_verwalten` wiederholen und niemandem auffallen.
Ein Modi stellt nichts ein -- also nimmt die Probe die rechte
Hand, deren eigenes Stueck das hier ist. */
const l = await liste(hand.keks);
const m = (l.json?.material || []).find((x) => x.id === id);
ok(m?.darf_ich === true, "die rechte Hand darf ihr eigenes Stueck (darf_ich = true)");
}
/* =====================================================================
13. AM ECHTEN BILDSCHIRM
=====================================================================
Die zwoelf Abschnitte davor messen die Schnittstelle. Keiner von
ihnen haette gemerkt, wenn der Knopf "Bearbeiten" gar nicht
erscheint, das Formular hinter der Karte verschwindet oder die
Datumsfelder am Handy aus dem Bild laufen.
Genau daran ist die Teilnehmerwahl am 05.09. gescheitert: vierzig
gruene Pruefungen, und auf dem Bildschirm klebten die Namen
aneinander. Niemand hatte gefragt, ob das Ergebnis auch AUSSIEHT wie
gedacht.
WARUM EIN HTTPS-VORBAU: Team Dogi wohnt auf crew.dogfather-universe.com,
und welche Wand gilt, entscheidet der Host-Kopf. Chromium setzt den
selbst und hebt diese Domain ausserdem von sich aus auf https --
also bekommt sie hier einen echten, selbst unterschriebenen
Vorbau davor. Derselbe Weg wie in pruef-willkommen.
===================================================================== */
melde("");
melde("=== 13. Am echten Bildschirm ===");
{
const { execFileSync } = await import("node:child_process");
const { createServer: httpsServer } = await import("node:https");
const { readFileSync } = await import("node:fs");
const schluessel = join(ordner, "pruef.key");
const zertifikat = join(ordner, "pruef.crt");
execFileSync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes",
"-keyout", schluessel, "-out", zertifikat, "-days", "2",
"-subj", `/CN=${CREW}`, "-addext", `subjectAltName=DNS:${CREW}`],
{ stdio: "ignore" });
const HTTPS_PORT = PORT + 1;
const vorbau = httpsServer({
key: readFileSync(schluessel), cert: readFileSync(zertifikat),
}, (von, nach) => {
const weiter = httpAnfrage({
host: "127.0.0.1", port: PORT, path: von.url, method: von.method,
headers: { ...von.headers, host: `${CREW}:${HTTPS_PORT}` },
}, (antwort) => {
nach.writeHead(antwort.statusCode || 502, antwort.headers);
antwort.pipe(nach);
});
von.pipe(weiter);
});
await new Promise((r) => vorbau.listen(HTTPS_PORT, "127.0.0.1", r));
const SEITE = `https://${CREW}:${HTTPS_PORT}`;
const pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
const browser = await pw.chromium.launch({
args: [`--host-resolver-rules=MAP ${CREW} 127.0.0.1`, "--ignore-certificate-errors"],
});
/* Ein sauberer Ausgangszustand fuer die Augen: ein Stueck mit
laufendem Fenster, eines fuer spaeter, eines abgelaufen. Alles im
Wegwerfordner -- an die echte Datenbank kommt hier nichts. */
await einstellen(chef.keks, "schau-laeuft.png", "Laeuft gerade", { ab: VORGESTERN, bis: IN10 });
await einstellen(chef.keks, "schau-spaeter.png", "Kommt noch", { ab: MORGEN, bis: IN10 });
await einstellen(chef.keks, "schau-vorbei.png", "War einmal", { ab: VORGESTERN, bis: GESTERN });
const meckern = [];
async function seiteAls(rolle, code, breite) {
const ctx = await browser.newContext({ viewport: { width: breite, height: 950 } });
const s2 = await ctx.newPage();
s2.on("pageerror", (e) => meckern.push(`${rolle}: Absturz ${String(e).slice(0, 120)}`));
s2.on("console", (m) => {
if (m.type() === "error" && !/favicon|ERR_CERT|net::ERR/i.test(m.text())) {
meckern.push(`${rolle}: Konsole ${m.text().slice(0, 120)}`);
}
});
await s2.goto(`${SEITE}/workspace/`, { waitUntil: "networkidle" });
await s2.click(`.rolle[data-rolle="${rolle}"]`);
await s2.fill("#code", code);
await s2.click("button[type=submit]");
await s2.waitForTimeout(900);
await s2.goto(`${SEITE}/workspace/material.html`, { waitUntil: "networkidle" });
await s2.waitForTimeout(1200);
return { ctx, s: s2 };
}
try {
/* ---- DogFather am Rechner ------------------------------------ */
const a = await seiteAls("admin", "CODE-DOGI-0001", 1280);
try {
const bild = await a.s.evaluate(() => {
const knoepfe = [...document.querySelectorAll("#m-kat .schritt")];
const karte = document.querySelector(".m-karte");
const zeit = document.querySelector(".m-karte__zeit");
return {
ueberschrift: document.querySelector("h1")?.textContent?.trim(),
kategorien: knoepfe.map((b) => ({
wort: b.textContent.replace(/\d+$/, "").trim(),
zahl: b.querySelector(".m-kat__zahl")?.textContent,
gedrueckt: b.getAttribute("aria-pressed"),
})),
/* Sieht der Knopf nach Knopf aus? Ein `.schritt` ohne
Polsterung waere nackter Text -- genau der Fehler von der
Teilnehmerwahl. */
knopfHoehe: knoepfe[0] ? Math.round(knoepfe[0].getBoundingClientRect().height) : 0,
verwalten: !!karte?.querySelector(".m-karte__verwalten"),
verwaltenKnoepfe: [...(karte?.querySelectorAll(".m-karte__verwalten button") || [])]
.map((b) => b.textContent.trim()),
zeitMarke: zeit?.querySelector(".m-karte__zeit-marke")?.textContent?.trim() || null,
zeitFarbe: zeit ? getComputedStyle(zeit.querySelector(".m-karte__zeit-marke")).color : null,
zeitText: zeit?.textContent?.replace(/\s+/g, " ").trim() || null,
fensterFelder: document.querySelectorAll(".m-neu__fenster input[type=date]").length,
};
});
ok(bild.ueberschrift === "Dogi-Media",
`die Seite heisst "${bild.ueberschrift}"`);
ok(bild.kategorien.length === 5,
`fuenf Kategorieknoepfe stehen da (${bild.kategorien.length}: `
+ `${bild.kategorien.map((k) => `${k.wort} ${k.zahl}`).join(" | ")})`);
ok(bild.kategorien[0]?.gedrueckt === "true",
`"Alle" ist beim Aufschlagen gewaehlt (${bild.kategorien[0]?.gedrueckt})`);
ok(bild.knopfHoehe >= 26,
`und sie sehen aus wie Knoepfe, nicht wie Text (${bild.knopfHoehe} px hoch)`);
ok(bild.fensterFelder === 2,
`der Einstellkasten hat zwei Datumsfelder (${bild.fensterFelder})`);
ok(bild.verwalten && bild.verwaltenKnoepfe.join("/") === "Bearbeiten/Entfernen",
`DogFather sieht beide Verwaltungsknoepfe (${bild.verwaltenKnoepfe.join(", ")})`);
ok(!!bild.zeitMarke && !!bild.zeitText,
`der Zeitraum steht an der Karte ("${bild.zeitText}")`);
ok(bild.zeitFarbe !== null && bild.zeitFarbe !== "rgb(0, 0, 0)",
`und die Zustandsmarke hat ihre Farbe (${bild.zeitFarbe})`);
/* ---- Der Filter filtert wirklich, und beide Listen ---- */
const vorher = await a.s.evaluate(() => ({
oben: document.querySelectorAll("#frei .m-karte").length,
unten: document.querySelectorAll("#weg .m-karte").length,
}));
await a.s.click('#m-kat .schritt[data-wert="spaeter"]');
await a.s.waitForTimeout(400);
const nachher = await a.s.evaluate(() => ({
oben: document.querySelectorAll("#frei .m-karte").length,
unten: document.querySelectorAll("#weg .m-karte").length,
gedrueckt: document.querySelector('#m-kat .schritt[data-wert="spaeter"]')
?.getAttribute("aria-pressed"),
/* AM ZUSTAND GEMESSEN, NICHT AM DATEINAMEN. Der erste Entwurf
prueft, ob jeder Name "spaeter" enthaelt -- und wurde rot,
weil ein Stueck aus Abschnitt 10 voellig zu Recht dabei war:
Dort hat die rechte Hand ihm ein Fenster in der Zukunft
gegeben. Die Pruefung hatte recht behalten wollen, nicht
gemessen. */
zustaende: [...document.querySelectorAll("#frei .m-karte")]
.map((k) => k.querySelector(".m-karte__zeit")?.dataset.zustand || "ohne"),
}));
ok(nachher.gedrueckt === "true" && nachher.oben < vorher.oben && nachher.oben > 0,
`"Kommt noch" filtert die obere Liste (${vorher.oben} -> ${nachher.oben})`);
ok(nachher.unten === 0 && vorher.unten > 0,
`und die untere gleich mit (${vorher.unten} -> ${nachher.unten}) `
+ `-- ein Filter, der nur die halbe Seite betrifft, sieht kaputt aus`);
ok(nachher.zustaende.length > 0
&& nachher.zustaende.every((z) => z === "spaeter"),
`uebrig bleibt nur, was spaeter gilt `
+ `(${nachher.zustaende.length} Karten, alle: ${[...new Set(nachher.zustaende)].join(", ")})`);
/* Noch einmal auf denselben Knopf heisst "alle". */
await a.s.click('#m-kat .schritt[data-wert="spaeter"]');
await a.s.waitForTimeout(400);
const zurueck = await a.s.evaluate(() =>
document.querySelectorAll("#frei .m-karte").length);
ok(zurueck === vorher.oben,
`ein zweiter Druck fuehrt zurueck zu allen (${zurueck} von ${vorher.oben})`);
/* ---- BEARBEITEN: Formular IN der Karte, vorbelegt ---- */
await a.s.click(".m-karte .m-karte__verwalten button");
await a.s.waitForTimeout(400);
const form = await a.s.evaluate(() => {
const k = document.querySelector(".m-karte");
const f = k?.querySelector(".m-bearb");
if (!f) return null;
return {
inKarte: !!f && k.contains(f),
text: f.querySelector("textarea")?.value,
kartenText: k.querySelector(".m-karte__text")?.textContent,
datumsfelder: f.querySelectorAll("input[type=date]").length,
ab: f.querySelectorAll("input[type=date]")[0]?.value,
knoepfe: [...f.querySelectorAll("button")].map((b) => b.textContent.trim()),
};
});
ok(!!form && form.inKarte, "das Formular steht in der Karte, nicht davor");
ok(!!form && form.text === form.kartenText,
`das Textfeld ist mit dem bisherigen Text vorbelegt ("${form?.text}")`);
ok(!!form && form.datumsfelder === 2 && !!form.ab,
`und die zwei Datumsfelder auch (${form?.ab})`);
ok(!!form && form.knoepfe.join("/") === "Speichern/Abbrechen",
`Speichern und Abbrechen stehen da (${form?.knoepfe.join(", ")})`);
/* GEGENPROBE ZUM VORBELEGEN: Genau das konnte `frageNach` nicht,
und genau deshalb steht hier ein eigenes Formular. Ein leeres
Feld waere kein Bearbeiten, sondern ein Neuschreiben. */
/* ---- Ein verkehrtes Fenster wird schon hier gesagt ---- */
const felder = ".m-karte .m-bearb input[type=date]";
await a.s.evaluate((wahl) => {
const d2 = document.querySelectorAll(wahl);
d2[0].value = "2030-01-01"; d2[1].value = "2029-01-01";
}, felder);
await a.s.click(".m-karte .m-bearb button[type=submit]");
await a.s.waitForTimeout(500);
const gemeckert = await a.s.evaluate(() =>
document.querySelector(".m-karte .m-bearb__fehler")?.textContent?.trim());
ok(!!gemeckert && gemeckert.length > 10,
`ein verkehrtes Fenster wird im Formular gesagt ("${gemeckert}")`);
/* ---- Speichern geht wirklich durch ---- */
await a.s.evaluate(() => {
const f = document.querySelector(".m-karte .m-bearb");
f.querySelector("textarea").value = "Am Bildschirm geaendert";
for (const d2 of f.querySelectorAll("input[type=date]")) d2.value = "";
});
await a.s.click(".m-karte .m-bearb button[type=submit]");
await a.s.waitForTimeout(1200);
const danach = await a.s.evaluate(() => ({
formWeg: !document.querySelector(".m-karte .m-bearb"),
text: document.querySelector(".m-karte .m-karte__text")?.textContent,
}));
ok(danach.formWeg, "nach dem Speichern ist das Formular zu");
ok(danach.text === "Am Bildschirm geaendert",
`und der neue Text steht auf der Karte ("${danach.text}")`);
} finally { await a.ctx.close(); }
/* ---- Ein Modi am Handy ----------------------------------------
ZWEI ANNAHMEN HIER WAREN FALSCH, und beide standen vier Zeilen
weiter oben im selben Lauf richtig da:
"ein Modi stellt etwas bereit (201, Nummer 4)"
Ein Modi GEHOERT zum Team Dogi. Er darf einstellen, und an
seinen EIGENEN Stuecken darf er selbstverstaendlich auch
aendern. Die erste Fassung verlangte "kein einziger
Verwaltungsknopf" und "kein Einstellkasten" -- das waere keine
Pruefung gewesen, sondern der Wunsch, recht zu behalten.
Was wirklich zaehlt, ist die Grenze: seine eigenen ja, fremde
nein. Und die wird nicht geschaetzt, sondern gegen die Liste
gerechnet, die der Server ihm selbst schickt. */
const b = await seiteAls("modi", "CODE-MODI-0001", 390);
try {
const seinStand = (await liste(modi.keks)).json || {};
const darfIds = new Set((seinStand.material || [])
.filter((m) => m.darf_ich && !m.genommen).map((m) => String(m.id)));
const fremdIds = new Set((seinStand.material || [])
.filter((m) => !m.darf_ich && !m.genommen).map((m) => String(m.id)));
const handy = await b.s.evaluate(() => ({
karten: document.querySelectorAll(".m-karte").length,
mitVerwalten: [...document.querySelectorAll(".m-karte")]
.filter((k) => k.querySelector(".m-karte__verwalten"))
.map((k) => k.dataset.id),
einstellen: !document.getElementById("neu-block").hidden,
breite: document.documentElement.scrollWidth,
sichtbar: document.documentElement.clientWidth,
/* Jeder Kategorieknopf muss am Finger zu treffen sein. */
kleinsteKat: Math.min(...[...document.querySelectorAll("#m-kat .schritt")]
.map((x) => Math.round(x.getBoundingClientRect().height))),
}));
ok(handy.karten > 0, `der Modi sieht Stuecke (${handy.karten})`);
const gezeigt = new Set(handy.mitVerwalten);
const zuViel = [...gezeigt].filter((id) => fremdIds.has(id));
const zuWenig = [...darfIds].filter((id) => !gezeigt.has(id));
/* DIE ANZAHL GEHOERT IN DIE BEDINGUNG: Ohne `darfIds.size > 0`
waeren beide Listen leer und die Zeile gruen, ohne dass je
ein Knopf geprueft wurde. */
ok(darfIds.size > 0 && fremdIds.size > 0
&& zuViel.length === 0 && zuWenig.length === 0,
`Verwaltungsknoepfe genau an seinen eigenen `
+ `(${gezeigt.size} gezeigt, ${darfIds.size} erlaubt, `
+ `${fremdIds.size} fremde daneben)`
+ (zuViel.length ? ` -- zu viel an: ${zuViel.join(", ")}` : "")
+ (zuWenig.length ? ` -- es fehlt an: ${zuWenig.join(", ")}` : ""));
ok(handy.einstellen === true,
"der Einstellkasten steht da -- ein Modi gehoert zum Team und stellt bereit");
ok(handy.breite <= handy.sichtbar + 1,
`nichts laeuft seitlich aus dem Bild (${handy.breite} von ${handy.sichtbar} px)`);
ok(handy.kleinsteKat >= 26,
`die Kategorieknoepfe sind am Finger zu treffen (${handy.kleinsteKat} px)`);
} finally { await b.ctx.close(); }
/* ---- Und die Community: gar kein Kasten -----------------------
DAS IST DIE GEGENPROBE zur Zeile darueber. Waere der Kasten
einfach immer da, waere "er steht da" genauso gruen. */
const c = await seiteAls("gast", "CODE-GAST-0001", 390);
try {
const gast = await c.s.evaluate(() => ({
karten: document.querySelectorAll(".m-karte").length,
einstellen: !document.getElementById("neu-block").hidden,
verwalten: document.querySelectorAll(".m-karte__verwalten").length,
breite: document.documentElement.scrollWidth,
sichtbar: document.documentElement.clientWidth,
}));
ok(gast.karten > 0, `die Community sieht die Stuecke (${gast.karten})`);
ok(gast.einstellen === false,
"aber keinen Einstellkasten -- ein Formular, das eine Absage bringt, ist schlimmer als keins");
ok(gast.verwalten === 0,
`und keinen einzigen Verwaltungsknopf (${gast.verwalten})`);
ok(gast.breite <= gast.sichtbar + 1,
`auch bei ihr laeuft nichts aus dem Bild (${gast.breite} von ${gast.sichtbar} px)`);
} finally { await c.ctx.close(); }
ok(meckern.length === 0, meckern.length
? `der Browser meldet: ${meckern.slice(0, 3).join(" | ")}`
: "kein Absturz und keine Fehlermeldung im Browser");
} finally {
await browser.close();
await new Promise((r) => vorbau.close(r));
}
}
/* =====================================================================
ERGEBNIS
===================================================================== */
melde("");
/* Die Zahl gehoert in die Bedingung, nicht nur in den Text: Ein Lauf,
der nichts geprueft hat, ist kein bestandener Lauf. */
if (geprueft < 40) {
console.log(` FEHL nur ${geprueft} Pruefungen gelaufen -- erwartet waren 40+`);
/* Von 40 ueber 90 auf 145 angehoben (22.09.2026), als das Bearbeiten,
das Zeitfenster und der Blick am echten Bildschirm dazukamen. Die
Zahl ist keine Schaetzung: Sie steht knapp unter dem, was der Lauf
danach tatsaechlich gemeldet hat (155). Bei 90 waere der ganze
Browserabschnitt still ausfallen koennen, ohne dass die Zahl etwas
gesagt haette -- und genau das soll sie fangen. */
if (geprueft < 145) {
console.log(` FEHL nur ${geprueft} Pruefungen gelaufen -- erwartet waren 145+`);
fehler++;
}
melde(fehler === 0
+182 -7
View File
@@ -62,6 +62,11 @@ import {
db, protokolliere, echteIp, sitzungLesen, DATEN_ORDNER,
istDogFather, TEAM_DOGI_ROLLEN, TREFF_ROLLEN,
} from "./workspace.js";
/* DIE UHR DES HAUSES, nicht `new Date().toISOString().slice(0,10)`.
Das waere UTC -- zwischen Mitternacht und zwei Uhr laege der Tag
damit einen zurueck, und ein Stueck, das heute anfaengt, staende
noch als "spaeter" da. */
import { tagLokal } from "./helfer-zeit.mjs";
export const materialRouter = express.Router();
@@ -103,9 +108,69 @@ function tabellen() {
CREATE INDEX IF NOT EXISTS idx_material_frei
ON material (genommen_von, erstellt);
`);
/* VON WANN BIS WANN (22.09.2026).
===================================================================
Filipe: "welche sind benutzt welche nicht welche sind noch offen,
welche laufen von wan bis wann, das muss man auch machen koennen."
Ein Bild zur Halloween-Aktion ist am 2. November kein Angebot mehr,
sondern ein Stolperstein. Ohne Fenster bleibt es bis in alle
Ewigkeit in der Liste, und irgendwann postet es jemand.
BEIDE FELDER SIND FREIWILLIG. Der haeufigste Fall ist "gilt
einfach" -- ein Pflichtfeld erzwaenge hier ein erfundenes Datum,
und ein erfundenes Datum ist schlechter als keins.
ERGAENZT STATT ANGENOMMEN: Die Tabelle steht auf echten Rechnern
schon mit Daten. `ALTER TABLE` waere beim zweiten Start ein
Fehler, ein neues CREATE wuerde die vorhandenen Zeilen nicht
erreichen. Also nachsehen, was da ist, und nur ergaenzen, was
fehlt -- dieselbe Bauart wie bei den Personen-Spalten. */
const da = new Set(d.prepare("PRAGMA table_info(material)").all().map((c) => c.name));
for (const [spalte, form] of [["gilt_ab", "TEXT"], ["gilt_bis", "TEXT"]]) {
if (da.has(spalte)) continue;
try {
d.exec(`ALTER TABLE material ADD COLUMN ${spalte} ${form}`);
console.log(`[material] Spalte '${spalte}' ergaenzt.`);
} catch (f) { console.error(`[material] Spalte '${spalte}':`, f?.message); }
}
bereit = true;
}
/* ---------------------------------------------------------------------
IN WELCHEM ZUSTAND IST EIN STUECK?
---------------------------------------------------------------------
Filipe will die Liste nach Zustand sortieren koennen. Der Zustand
wird GERECHNET und nicht gespeichert: Eine Spalte "zustand" muesste
jemand taeglich nachfuehren, und am Tag, an dem das vergessen wird,
steht "laeuft" an etwas, das seit drei Wochen abgelaufen ist.
Vier Zustaende, und die Reihenfolge der Fragen entscheidet:
benutzt -- jemand hat es genommen. Schlaegt alles andere; ein
vergebenes Stueck ist weg, auch wenn sein Fenster
noch laeuft.
spaeter -- das Fenster faengt erst an.
abgelaufen -- das Fenster ist vorbei.
frei -- alles andere. Auch alles ohne Fenster: "kein Datum"
heisst "gilt", nicht "gilt nicht".
--------------------------------------------------------------------- */
export function zustandVon(z, heute) {
if (z.genommen_von) return "benutzt";
if (z.gilt_ab && z.gilt_ab > heute) return "spaeter";
if (z.gilt_bis && z.gilt_bis < heute) return "abgelaufen";
return "frei";
}
/** Ein Datum im Format JJJJ-MM-TT -- oder null. Nichts dazwischen. */
function datumOderNull(roh) {
const t = String(roh ?? "").trim();
if (!t) return null;
if (!/^\d{4}-\d{2}-\d{2}$/.test(t)) return undefined; /* undefined = ungueltig */
const d = new Date(`${t}T12:00:00Z`);
return Number.isNaN(d.getTime()) ? undefined : t;
}
/* ---------------------------------------------------------------------
WER DARF WAS
---------------------------------------------------------------------
@@ -127,6 +192,24 @@ export const darfMaterialNehmen = (person) =>
export const siehtWerGenommenHat = (person) =>
!!person && (istDogFather(person) || person.rolle === "hand");
/* WER FREMDES BEARBEITEN UND ENTFERNEN DARF (22.09.2026).
---------------------------------------------------------------------
Filipe: "wenn wir in der kategorie material was hochladen will ich
dass die rechte und linke hand es auch bearbeiten und loeschen
koennen. dogfather auch fals es ein fehler gab."
Bis heute kam nur der Einsteller selbst und DogFather an ein Stueck.
Wer einen Tippfehler im Text hatte oder das falsche Bild erwischte,
musste warten, bis jemand anders Zeit hat -- und in der Zwischenzeit
steht das Falsche da, wo die Community sich bedient.
NICHT ueber `darfMaterialEinstellen`: Dort stehen auch die Modis
drin, und die sollen ihr eigenes Stueck zuruecknehmen koennen, aber
nicht das von jemand anderem. Wer fremdes anfasst, ist die Leitung. */
export const darfFremdesVerwalten = (person) =>
!!person && (istDogFather(person)
|| person.rolle === "hand" || person.rolle === "linke");
function angemeldet(req, res, next) {
const person = sitzungLesen(req);
if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" });
@@ -148,7 +231,7 @@ materialRouter.get("/workspace/api/material", (req, res) => {
const zeigtNamen = siehtWerGenommenHat(req.person);
const reihen = db().prepare(`
SELECT m.id, m.dateiname, m.art, m.groesse, m.text, m.erstellt,
m.genommen_am, m.genommen_von,
m.genommen_am, m.genommen_von, m.von_id, m.gilt_ab, m.gilt_bis,
v.name AS von_name,
g.name AS genommen_name
FROM material m
@@ -157,9 +240,17 @@ materialRouter.get("/workspace/api/material", (req, res) => {
ORDER BY (m.genommen_von IS NOT NULL), m.erstellt DESC
`).all();
/* HEUTE WIRD EINMAL GERECHNET, NICHT JE ZEILE. Sonst koennte eine
Liste, die ueber Mitternacht gelesen wird, zwei verschiedene
Tage benutzen -- und ein Stueck waere in derselben Antwort
gleichzeitig "laeuft" und "abgelaufen". */
const heute = tagLokal(0);
res.json({
darf_einstellen: darfMaterialEinstellen(req.person),
darf_verwalten: darfFremdesVerwalten(req.person),
sieht_wer: zeigtNamen,
heute,
max_bytes: MAX_BYTES,
material: reihen.map((z) => ({
id: z.id,
@@ -180,6 +271,14 @@ materialRouter.get("/workspace/api/material", (req, res) => {
/* Und jeder sieht, ob ER es war -- sonst wuesste er nicht mehr,
was er selbst schon geholt hat. */
von_mir_genommen: z.genommen_von === req.person.id,
gilt_ab: z.gilt_ab || null,
gilt_bis: z.gilt_bis || null,
zustand: zustandVon(z, heute),
/* DARF ICH DIESES STUECK ANFASSEN? Die Antwort steht beim
Stueck und wird nicht in der Oberflaeche nachgerechnet --
zwei Rechnungen fuer dieselbe Frage laufen auseinander, und
die im Browser ist die, der man nicht trauen darf. */
darf_ich: z.von_id === req.person.id || darfFremdesVerwalten(req.person),
})),
});
} catch (f) {
@@ -229,11 +328,30 @@ materialRouter.post(
const datei = `${Date.now().toString(36)}-${randomBytes(8).toString("hex")}${endung}`;
writeFileSync(join(ORDNER, datei), req.body, { flag: "wx" });
/* DAS FENSTER KOMMT WIE NAME UND TEXT IN KOPFZEILEN.
Derselbe Weg wie alles andere an diesem Aufruf -- die Datei
liegt roh im Rumpf, also ist fuer Angaben nur der Kopf uebrig.
Ein zweiter Aufruf danach waere ein zweiter Weg, der beim
Abbrechen ein halbes Stueck hinterliesse. */
const ab = datumOderNull(req.get("x-gilt-ab"));
const bis = datumOderNull(req.get("x-gilt-bis"));
if (ab === undefined || bis === undefined) {
return res.status(400).json({ fehler: "datum_unbrauchbar" });
}
/* EIN FENSTER, DAS RUECKWAERTS LAEUFT, IST KEINS. Es waere in
jedem Zustand gleichzeitig "spaeter" und "abgelaufen" -- und
die Liste zeigte dann, was die Reihenfolge der Fragen
zufaellig ergibt, statt was jemand gemeint hat. */
if (ab && bis && ab > bis) {
return res.status(400).json({ fehler: "fenster_verkehrt" });
}
const { lastInsertRowid } = db().prepare(`
INSERT INTO material (datei, dateiname, typ, art, groesse, text, von_id, erstellt)
VALUES (?,?,?,?,?,?,?,?)
INSERT INTO material (datei, dateiname, typ, art, groesse, text, von_id, erstellt,
gilt_ab, gilt_bis)
VALUES (?,?,?,?,?,?,?,?,?,?)
`).run(datei, name, typ, art, req.body.length, text, req.person.id,
new Date().toISOString());
new Date().toISOString(), ab, bis);
protokolliere(req.person.id, "material_eingestellt",
`${art} "${name}" (${req.body.length} Bytes)`, echteIp(req));
@@ -277,7 +395,7 @@ materialRouter.post("/workspace/api/material/:id/nehmen", (req, res) => {
});
}
protokolliere(req.person.id, "material_genommen", `Material ${id}`, echteIp(req));
protokolliere(req.person.id, "material_genommen", `Dogi-Media ${id}`, echteIp(req));
res.json({ ok: true, weg: `/workspace/api/material/${id}/datei` });
} catch (f) {
console.error("[material] Nehmen:", f?.message);
@@ -362,17 +480,74 @@ materialRouter.get("/workspace/api/material/:id/datei", (req, res) => {
/* ---------------------------------------------------------------------
WEGNEHMEN
--------------------------------------------------------------------- */
/* ---------------------------------------------------------------------
BEARBEITEN (22.09.2026)
---------------------------------------------------------------------
Filipe: "will ich dass die rechte und linke hand es auch bearbeiten
und loeschen koennen. dogfather auch fals es ein fehler gab."
GEAENDERT WERDEN TEXT UND FENSTER -- die DATEI nicht. Wer ein
anderes Bild will, stellt ein anderes Stueck ein: Sonst zeigte die
Liste nach der Aenderung etwas anderes als das, was jemand sich
gerade angesehen hat, unter derselben Nummer.
EIN VERGEBENES STUECK BLEIBT, WIE ES IST. Wer es genommen hat, hat
sich auf diesen Text und dieses Fenster verlassen; es hinterher zu
aendern hiesse, die Absprache nachtraeglich umzuschreiben.
--------------------------------------------------------------------- */
materialRouter.patch("/workspace/api/material/:id", express.json({ limit: "32kb" }),
(req, res) => {
try {
const id = Number(req.params.id);
const z = db().prepare("SELECT * FROM material WHERE id = ?").get(id);
if (!z) return res.status(404).json({ fehler: "nicht_gefunden" });
if (z.von_id !== req.person.id && !darfFremdesVerwalten(req.person)) {
return res.status(403).json({ fehler: "nicht_deins" });
}
/* EIGENER CODE, NICHT `schon_vergeben`: Der ist im Haus schon
vergeben -- fuer Aufgaben ("die Aufgabe ist schon uebernommen").
Ein Code, der zwei Dinge bedeutet, zeigt frueher oder spaeter
an einer der beiden Stellen den falschen Satz an. */
if (z.genommen_von) return res.status(409).json({ fehler: "schon_im_umlauf" });
const text = String(req.body?.text ?? z.text ?? "").trim().slice(0, 600);
const ab = req.body?.gilt_ab === undefined
? z.gilt_ab : datumOderNull(req.body.gilt_ab);
const bis = req.body?.gilt_bis === undefined
? z.gilt_bis : datumOderNull(req.body.gilt_bis);
if (ab === undefined || bis === undefined) {
return res.status(400).json({ fehler: "datum_unbrauchbar" });
}
if (ab && bis && ab > bis) {
return res.status(400).json({ fehler: "fenster_verkehrt" });
}
db().prepare("UPDATE material SET text = ?, gilt_ab = ?, gilt_bis = ? WHERE id = ?")
.run(text, ab, bis, id);
protokolliere(req.person.id, "material_geaendert", `Dogi-Media ${id}`, echteIp(req));
res.json({ ok: true, id, text, gilt_ab: ab, gilt_bis: bis,
zustand: zustandVon({ ...z, gilt_ab: ab, gilt_bis: bis }, tagLokal(0)) });
} catch (f) {
console.error("[material] Aendern:", f?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
materialRouter.delete("/workspace/api/material/:id", (req, res) => {
try {
const id = Number(req.params.id);
const z = db().prepare("SELECT * FROM material WHERE id = ?").get(id);
if (!z) return res.status(404).json({ fehler: "nicht_gefunden" });
if (z.von_id !== req.person.id && !istDogFather(req.person)) {
/* ERWEITERT AM 22.09.2026: auch rechte und linke Hand.
Vorher kam nur der Einsteller und DogFather an ein Stueck. Wer
das falsche Bild erwischt hatte, musste warten -- und bis dahin
stand das Falsche dort, wo die Community sich bedient. */
if (z.von_id !== req.person.id && !darfFremdesVerwalten(req.person)) {
return res.status(403).json({ fehler: "nicht_deins" });
}
db().prepare("DELETE FROM material WHERE id = ?").run(id);
try { unlinkSync(join(ORDNER, z.datei)); } catch { /* schon weg */ }
protokolliere(req.person.id, "material_entfernt", `Material ${id}`, echteIp(req));
protokolliere(req.person.id, "material_entfernt", `Dogi-Media ${id}`, echteIp(req));
res.json({ ok: true });
} catch (f) {
console.error("[material] Entfernen:", f?.message);
+26 -3
View File
@@ -1318,7 +1318,7 @@ const TREFF_BEREICHE = [
Ton 42 ist GERECHNET, nicht gegriffen -- tools/kachel-farbe-
einzeln.mjs, Abstand 0,0823 zum naechsten Nachbarn (1,3-fach
besser als der erste Vorschlag), Kontrast 6,08:1. */
{ ...TREFF_GRUPPE, name: "Material", unter: "Bilder und Videos zum Posten – jedes nur einmal",
{ ...TREFF_GRUPPE, name: "Dogi-Media", unter: "Bilder und Videos zum Posten – jedes nur einmal",
zeichen: "galerie", ton: 42, ziel: "material.html", szene: "studio" },
/* DIE FARBE, DIE "REGELN & HILFE" HATTE (22.09.2026).
Filipes screen5: "die farbe dieser kachel soll die farbe von der
@@ -5849,8 +5849,31 @@ export function heuteLokal() {
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
}
/** Derselbe Tag, um n Tage verschoben. */
export function tagLokal(versatz) {
/** Derselbe Tag, um `versatz` Tage verschoben. Negativ heißt zurück.
*
* ZWEI DINGE AM 22.09.2026 NACHGEZOGEN, beide durch einen echten Schaden:
*
* (1) `versatz = 0`. Dogi-Media rief `tagLokal()` ohne Argument auf und
* bekam `"NaN-NaN-NaN"` zurück -- eine Zeichenkette, die aussieht
* wie ein Datum und sich wie keines verhält. Im Vergleich
* `"2026-12-31" < "NaN-NaN-NaN"` gewinnt das N, also galt JEDES
* Stück mit Enddatum vom ersten Tag an als abgelaufen, und
* "Kommt noch" gab es nie. Kein Absturz, keine Meldung, keine
* Zeile im Protokoll -- nur eine Seite, die etwas anderes zeigt
* als die Wahrheit. Die drei Kopien dieser Funktion waren an
* dieser Stelle auseinandergelaufen: helfer-tag.mjs hatte die
* Vorbelegung, die beiden anderen nicht.
*
* (2) Der Wurf bei einer Zahl, die keine ist. Eine Vorbelegung deckt
* nur den leeren Aufruf ab; `tagLokal(irgendwas)` mit einer
* undefinierten Variablen läge weiter still daneben. Ein Datum,
* das sich nicht ausrechnen lässt, muss SCHEITERN und nicht
* schweigen -- sonst wandert der Unsinn in die Datenbank und in
* die Anzeige, und gefunden wird er Wochen später. */
export function tagLokal(versatz = 0) {
if (!Number.isFinite(Number(versatz))) {
throw new TypeError(`tagLokal: "${versatz}" ist keine Zahl von Tagen.`);
}
const d = new Date(Date.now() + versatz * 86400_000);
const p = (n) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
+4 -4
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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<style>
/* Bewusst in der Seite und nicht in einer eigenen Datei: Diese Seite
soll auch dann noch etwas anzeigen, wenn genau das schiefgeht,
@@ -125,6 +125,6 @@
</main>
␍
<script src="assets/js/anruf-probe.js?v=202609221325" defer></script>
<script src="assets/js/anruf-probe.js?v=202609221359" defer></script>
</body>
</html>
+4 -4
View File
@@ -22,25 +22,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/workspace-192.png?v=202609221325",
"src": "/assets/img/app-symbole/workspace-192.png?v=202609221359",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-512.png?v=202609221325",
"src": "/assets/img/app-symbole/workspace-512.png?v=202609221359",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609221325",
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609221359",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609221325",
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609221359",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+2 -7
View File
@@ -779,13 +779,8 @@
.abgebrochen__zahl, .abbruch-karte__vorher { border: 1px solid CanvasText; }
}
/* Hinweis unter einem Formularfeld -- erklaert das Feld, statt es
kommentarlos wegzunehmen. */
.feld-hinweis {
margin: 5px 0 0;
font-size: .76rem; line-height: 1.45;
color: var(--text-still);
}
/* `.feld-hinweis` steht seit 22.09.2026 in start.css -- er wird auf
drei Seiten gebraucht, und start.css laedt jede davon. */
/* =====================================================================
+5 -13
View File
@@ -169,19 +169,11 @@
.treff-will { transition: none; }
}
.filter { display: flex; gap: 8px; margin: 0 0 20px; flex-wrap: wrap; }
.filter .schritt[aria-pressed="true"] {
/* Gedrueckt = der "voll"-Auftritt des Knopf-Systems. Vorher stand
hier eine eigene Flaeche, die den geschliffenen Rand ueberschrieb. */
--f: var(--akzent);
color: #fff;
background:
linear-gradient(color-mix(in srgb, var(--f) 20%, #121926),
color-mix(in srgb, var(--f) 12%, #0d1420)) padding-box,
linear-gradient(150deg, var(--f),
color-mix(in srgb, var(--f) 45%, transparent)) border-box;
box-shadow: 0 4px 16px -9px var(--f);
}
/* Die Filterleiste steht seit 22.09.2026 in gate.css -- sie wird
inzwischen auf drei Seiten gebraucht, und gate.css laedt jede.
Sie hier zu lassen hiesse, sie beim vierten Mal wieder zu
kopieren; genau so ist .knopf-still schon einmal auf einer
Seite als nacktes Kaestchen erschienen. */
@media (max-width: 620px) {
+5 -13
View File
@@ -49,19 +49,11 @@
font-size: .86rem; color: var(--text-leise);
}
.filter { display: flex; gap: 8px; margin: 0 0 20px; flex-wrap: wrap; }
.filter .schritt[aria-pressed="true"] {
/* Gedrueckt = der "voll"-Auftritt des Knopf-Systems. Vorher stand
hier eine eigene Flaeche, die den geschliffenen Rand ueberschrieb. */
--f: var(--akzent);
color: #fff;
background:
linear-gradient(color-mix(in srgb, var(--f) 20%, #121926),
color-mix(in srgb, var(--f) 12%, #0d1420)) padding-box,
linear-gradient(150deg, var(--f),
color-mix(in srgb, var(--f) 45%, transparent)) border-box;
box-shadow: 0 4px 16px -9px var(--f);
}
/* Die Filterleiste steht seit 22.09.2026 in gate.css -- sie wird
inzwischen auf drei Seiten gebraucht, und gate.css laedt jede.
Sie hier zu lassen hiesse, sie beim vierten Mal wieder zu
kopieren; genau so ist .knopf-still schon einmal auf einer
Seite als nacktes Kaestchen erschienen. */
/* ---------- Liste ------------------------------------------------------- */
+20
View File
@@ -1223,6 +1223,26 @@ body.suche-offen { overflow: hidden; }
auf der Anmeldeseite gibt es nichts anderes zu tun. */
.gate .knopf { width: 100%; margin-top: 18px; padding: 13px 18px; font-size: .95rem; }
/* ---------- Filterleiste --------------------------------------------
Eine Reihe von `.schritt`-Knoepfen, von denen genau einer gedrueckt
ist. Stand bis 22.09.2026 doppelt in dateien.css und bereich.css --
Zeichen fuer Zeichen gleich. Als Dogi-Media die dritte Seite wurde,
die sie braucht, waere es die dritte Kopie geworden.
-------------------------------------------------------------------- */
.filter { display: flex; gap: 8px; margin: 0 0 20px; flex-wrap: wrap; }
.filter .schritt[aria-pressed="true"] {
/* Gedrueckt = der "voll"-Auftritt des Knopf-Systems. Vorher stand
hier eine eigene Flaeche, die den geschliffenen Rand ueberschrieb. */
--f: var(--akzent);
color: #fff;
background:
linear-gradient(color-mix(in srgb, var(--f) 20%, #121926),
color-mix(in srgb, var(--f) 12%, #0d1420)) padding-box,
linear-gradient(150deg, var(--f),
color-mix(in srgb, var(--f) 45%, transparent)) border-box;
box-shadow: 0 4px 16px -9px var(--f);
}
.schritt[disabled], .knopf[disabled] { opacity: .45; cursor: default; box-shadow: none; }
.knopf[disabled] { cursor: progress; }
.knopf[disabled]:hover { transform: none; }
+4 -3
View File
@@ -410,9 +410,10 @@
max-width: 190px;
font: inherit; font-size: .88rem;
}
.feld-hinweis {
margin: 5px 0 0; font-size: .76rem; color: var(--text-still);
}
/* `.feld-hinweis` steht seit 22.09.2026 in start.css. Die Fassung hier
hatte kein `line-height` und war damit schon einen Hauch anders als
die in aufgaben.css -- zwei Kopien laufen auseinander, auch wenn sie
am Anfang gleich aussahen. */
/* "… oder direkt die Datei": steht UNTER dem Einfuegefeld und gehoert
sichtbar dazu, ohne ihm den Rang abzulaufen. Das Dateifeld selbst
bleibt klein -- es ist der zweite Weg, nicht der erste. */
+196
View File
@@ -329,6 +329,195 @@
font-size: .92rem;
}
/* ---------------------------------------------------------------------
DAS FENSTER BEIM EINSTELLEN (22.09.2026)
---------------------------------------------------------------------
Zwei Datumsfelder nebeneinander, solange Platz ist. `1fr 1fr` waere
hier falsch: Ein Datumsfeld hat eine natuerliche Breite (es zeigt
immer TT.MM.JJJJ und daneben das Kalendersymbol), und auf 400 px
ergaeben zwei Spalten zwei zu enge. `auto-fit` mit einer Mindest-
breite bricht genau dann um, wenn es noetig ist -- gemessen, nicht
an einer Zahl von gestern geraten.
--------------------------------------------------------------------- */
.m-neu__fenster {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
}
.m-neu__fenster-feld { min-width: 0; }
.m-neu input[type="date"] {
display: block;
width: 100%;
box-sizing: border-box;
min-height: 44px;
padding: 9px 11px;
border: 1px solid var(--rand-hell);
border-radius: var(--radius-klein, 10px);
background: color-mix(in srgb, var(--tinte) 90%, #ffffff 10%);
color: var(--text);
font: inherit;
font-size: .92rem;
}
/* Das Kalendersymbol kommt vom Browser und ist dunkel -- auf dunklem
Grund unsichtbar. `invert` dreht es um, ohne ein eigenes Bild
mitzuliefern, das bei jedem Browser anders sitzen wuerde. */
.m-neu input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(1);
opacity: .62;
cursor: pointer;
}
.m-neu input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
.m-neu__fenster-satz { margin: 8px 0 14px; }
/* ---------------------------------------------------------------------
DIE KATEGORIELEISTE (22.09.2026)
---------------------------------------------------------------------
Die Knoepfe selbst sind `.schritt` aus gate.css -- Groesse, Rand,
Fokusring und der gedrueckte Auftritt kommen von dort. Hier steht
nur, was diese Leiste zusaetzlich hat: die Zahl daneben.
--------------------------------------------------------------------- */
.m-kat__knopf { display: inline-flex; align-items: center; gap: 7px; }
.m-kat__zahl {
font-size: .72rem;
font-variant-numeric: tabular-nums;
color: var(--text-leise);
}
.m-kat__knopf[aria-pressed="true"] .m-kat__zahl { color: inherit; }
/* EINE LEERE KATEGORIE WIRD GRAU, NICHT VERSTECKT. Wer "Abgelaufen"
sucht und den Knopf nicht findet, weiss nicht, ob es nichts gibt
oder ob er ihn uebersieht. Eine 0 ist eine Antwort.
Nicht `disabled`: Ein leerer Filter bleibt anklickbar, sonst kaeme
man aus ihm auch nicht wieder heraus, wenn das letzte Stueck darin
gerade jemand genommen hat. */
.m-kat__knopf[data-leer="ja"]:not([aria-pressed="true"]) { opacity: .55; }
/* ---------------------------------------------------------------------
VON WANN BIS WANN, AUF DER KARTE
---------------------------------------------------------------------
Der Zustand traegt die Farbe, der Zeitraum den Text. Gemessen auf
der Kartenflaeche (rgba(9,13,22,.89) zu 94 %) ueber dem hellsten
Punkt der Buehne: 7,8 / 7,4 / 6,5 / 5,7 zu 1 -- alle deutlich ueber
den geforderten 4,5.
--------------------------------------------------------------------- */
.m-karte__zeit {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 6px;
margin: 8px 0 0;
font-size: .82rem;
color: var(--text-leise);
}
.m-karte__zeit-marke {
padding: 2px 8px;
border: 1px solid color-mix(in srgb, var(--zustandsfarbe) 45%, transparent);
border-radius: 999px;
background: color-mix(in srgb, var(--zustandsfarbe) 12%, transparent);
color: var(--zustandsfarbe);
font-size: .72rem;
font-weight: 600;
letter-spacing: .02em;
}
.m-karte__zeit { --zustandsfarbe: var(--k-neutral); }
.m-karte__zeit[data-zustand="frei"] { --zustandsfarbe: var(--k-gut); }
.m-karte__zeit[data-zustand="spaeter"] { --zustandsfarbe: var(--akzent); }
.m-karte__zeit[data-zustand="abgelaufen"] { --zustandsfarbe: var(--k-warn); }
.m-karte__zeit[data-zustand="benutzt"] { --zustandsfarbe: var(--k-neutral); }
/* ---------------------------------------------------------------------
BEARBEITEN UND ENTFERNEN (22.09.2026)
---------------------------------------------------------------------
Filipe: "will ich dass die rechte und linke hand es auch bearbeiten
und loeschen koennen."
Die zwei Knoepfe stehen UNTER dem Nehmen-Knopf und sind leise
(`.knopf-still`). Wer auf diese Seite kommt, will etwas holen --
verwalten tun zwei oder drei Leute. Gleich laute Knoepfe machten aus
jeder Karte eine Entscheidung mit drei Ausgaengen.
--------------------------------------------------------------------- */
.m-karte__verwalten {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 10px 0 0;
padding-top: 10px;
border-top: 1px solid color-mix(in srgb, var(--rand) 70%, transparent);
}
/* ---------------------------------------------------------------------
DAS FORMULAR IN DER KARTE
---------------------------------------------------------------------
Kein Kasten vor der Seite: Der bisherige Text muss sichtbar sein,
waehrend man ihn aendert, und daneben soll stehen, welches Stueck
gemeint ist. Ein Dialog haette beides verdeckt.
--------------------------------------------------------------------- */
.m-bearb {
margin: 10px 0 0;
padding: 12px;
border: 1px solid var(--rand-hell);
border-radius: var(--radius-klein, 10px);
background: color-mix(in srgb, var(--tinte) 88%, #ffffff 12%);
}
.m-bearb__feld { margin-bottom: 10px; }
.m-bearb input,
.m-bearb textarea {
display: block;
width: 100%;
box-sizing: border-box;
min-height: 42px;
padding: 8px 10px;
border: 1px solid var(--rand-hell);
border-radius: var(--radius-klein, 10px);
background: color-mix(in srgb, var(--tinte) 92%, #ffffff 8%);
color: var(--text);
font: inherit;
font-size: .88rem;
line-height: 1.5;
}
.m-bearb textarea { resize: vertical; }
.m-bearb input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(1);
opacity: .62;
cursor: pointer;
}
.m-bearb__hinweis {
margin: 0 0 10px;
font-size: .8rem;
line-height: 1.5;
color: var(--text-leise);
}
/* LEER HEISST UNSICHTBAR -- kein leerer Absatz, der die Knoepfe
verschiebt, sobald ein Fehler kommt. `:empty` braucht dafuer keine
zweite Klasse, die jemand vergessen kann. */
.m-bearb__fehler {
margin: 0 0 10px;
font-size: .84rem;
line-height: 1.5;
color: var(--k-warn);
}
.m-bearb__fehler:empty { display: none; }
.m-bearb__knoepfe {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
}
/* ---------------------------------------------------------------------
KONTRASTMODUS UND BEWEGUNGSARMUT
--------------------------------------------------------------------- */
@@ -337,6 +526,13 @@
.m-neu { border: 1px solid CanvasText; }
.m-raster--weg .m-karte { border-style: dashed; }
.m-karte__marke { border: 1px solid CanvasText; }
/* Ohne Farben traegt der Rand die Unterscheidung -- die
Zustandsmarke waere sonst ein Wort ohne Umriss. */
.m-karte__zeit-marke { border: 1px solid CanvasText; }
.m-kat__knopf[aria-pressed="true"] { border: 2px solid Highlight; }
.m-kat__knopf[data-leer="ja"] { opacity: 1; }
.m-bearb { border: 1px solid CanvasText; }
.m-karte__verwalten { border-top: 1px solid CanvasText; }
}
@media (prefers-reduced-motion: reduce) {
+81 -32
View File
@@ -4060,6 +4060,27 @@ body.start #protokoll {
color: var(--text-leise);
}
/* Der Hinweis UNTER einem Feld -- erklaert es, statt es kommentarlos
wegzunehmen.
HIERHER GEZOGEN AM 22.09.2026. Er stand doppelt: in aufgaben.css und
in leistung.css, und die beiden waren schon auseinandergelaufen (die
eine hatte `line-height`, die andere nicht). Dogi-Media war die
dritte Seite, die ihn braucht, und laedt keine der beiden -- der
Hinweis stand dort nackt und in voller Textgroesse da.
Es ist derselbe Fehler wie bei `.knopf-still`, beim Schalter und bei
der Filterleiste: ein gemeinsamer Baustein in einer Seitendatei. Er
faellt jedes Mal erst dort auf, wo die Datei nicht geladen wird.
`start.css` laedt jede Seite ausser den zwei Weiterleitungen
(index.html, crew-index.html) -- dort gibt es keine Formulare. */
.feld-hinweis {
margin: 5px 0 0;
font-size: .76rem;
line-height: 1.45;
color: var(--text-still);
}
/* AUF DEM HANDY 16 PIXEL. Das ist keine Geschmacksfrage: Safari auf dem
iPhone zoomt beim Antippen automatisch in die Seite hinein, sobald ein
Feld kleiner als 16px schreibt -- und zoomt danach NICHT von selbst
@@ -5524,41 +5545,69 @@ body[data-fremde-sicht="ja"]::after {
Die SILHOUETTE dieser Karten (Schraege, Kantenlicht, Eckwinkel) steht
im Abschnitt HUD-MODULE am Ende der Datei. Hier steht nur noch, wie
der Inhalt darin angeordnet ist.
=====================================================================
.kacheln {
/* 214 px ist gemessen, nicht geraten: Bei 1380 px Inhaltsbreite und
12 px Abstand ergeben sich damit genau sechs Spalten (6 x 214 +
5 x 12 = 1344). Darunter greift auto-fill von selbst auf fünf,
vier, drei -- ohne eine einzige Umbruchschwelle, die man beim
nächsten Element nachziehen müsste. */
grid-template-columns: repeat(auto-fill, minmax(min(214px, 100%), 1fr));
gap: 12px;
}
NACHGETRAGEN AM 22.09.2026: Hier fehlten die zwei Zeichen, die
diesen Kommentar schliessen. CSS-Kommentare schachteln nicht -- der
Block lief deshalb weiter bis zum naechsten `*` mit Schraegstrich,
und der stand MITTEN IN `.kacheln`. Verschluckt wurde damit die
oeffnende Klammer; die Fehlerbehebung des Browsers hat danach auch
noch die naechste Regel (`.kachel`) mitgenommen, weil sie deren
Rumpf als Block einer ungueltigen Auswahl gelesen hat.
.kachel {
border-radius: 16px;
/* Die Schiene liegt jetzt oben -- also gehört die Lichtkante des
Materials mit nach oben und der farbige Saum weg von links. */
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .50),
0 2px 5px -2px rgba(0, 0, 0, .55),
0 16px 34px -20px rgba(0, 0, 0, .88);
background:
/* Das Licht der Schiene fällt jetzt von OBEN in die Platte. */
linear-gradient(180deg,
color-mix(in srgb, var(--ton) 30%, transparent) 0%,
color-mix(in srgb, var(--ton) 11%, transparent) 12%,
color-mix(in srgb, var(--ton) 3%, transparent) 30%,
transparent 58%),
linear-gradient(163deg,
rgba(23, 31, 45, .95) 0%,
rgba(11, 15, 24, .95) 58%,
rgba(8, 11, 18, .95) 100%);
}
Gemessen in Chromium, beide Fassungen nacheinander: 738 statt 740
Regeln. Sichtbar war es als Kachelreihe mit DREI Spalten zu 413 px
statt fuenf zu 243 px -- die Regel von Zeile 836 sprang ein, und
genau deshalb ist es niemandem aufgefallen: Es sah nicht kaputt
aus, nur anders als gemeint.
===================================================================== */
/* Schiene und Glanz stehen jetzt im Abschnitt HUD-MODULE.
/* ---------------------------------------------------------------------
UND WARUM HIER TROTZDEM KEINE REGEL MEHR STEHT
---------------------------------------------------------------------
Nach dem Schliessen des Kommentars waren die zwei Regeln wieder da --
und `pruef-kachelfarben` wurde sofort rot:
FEHL mindestens ein Drittel der Rohfarbe kommt an (4.1 %)
FEHL kein Paar sieht auf dem Bildschirm gleich aus
(69 von 465 Paaren unter 0,02)
Der Grund steht oben im Quelltext: Die Flaeche mischte den Kachelton
mit 30 / 11 / 3 Prozent ein und lief bei 58 % in Durchsichtigkeit
aus, darunter eine fast deckende dunkle Platte. Von der Farbe kam
damit fast nichts mehr an, und einunddreissig verschiedene Toene
sahen auf dem Bildschirm gleich aus.
Das ist das Gegenteil dessen, was Filipe am 22.09. verlangt hat:
"ich will dass die farben viel klarer und staerker sind" und "soll
komplett farbig sein und ultra geil aussehen".
DIE REGEL IST ALSO KEIN VERLUST, DEN MAN WIEDERHERSTELLT, SONDERN EIN
ENTWURF VOM 07.09., DEN DIE HEUTIGE GESTALTUNG UEBERHOLT HAT. Weil
sie nie gewirkt hat, ist alles, was seither an den Kacheln gebaut
und gemessen wurde, OHNE sie entstanden -- Flaeche, Schatten und
Rundung kommen laengst aus dem Abschnitt HUD-MODULE am Dateiende.
Sie jetzt nachtraeglich einzuschalten hiesse, zwei Wochen Arbeit an
den Farben zurueckzudrehen, und zwar ohne dass jemand darum gebeten
haette.
Sie einfach stehen zu lassen waere aber genauso falsch gewesen: Dann
staende im Quelltext eine Kachelgestaltung, die es auf dem
Bildschirm nicht gibt -- und der Naechste, der die Kacheln aendert,
trifft die falsche Stelle. Genau davor warnt der Abschnitt weiter
oben ("ZWEI Stellen, an denen dieselbe Kachel beschrieben wird").
Deshalb: geloescht, mit dem Grund daneben.
WAS DAMIT OFFEN BLEIBT -- eine Frage an Filipe, keine Entscheidung
von mir: Zur Regel gehoerte auch ein anderes Raster,
`repeat(auto-fill, minmax(214px, 1fr))` statt der festen drei
Spalten aus Zeile 836. Gemessen sind das fuenf bis sechs schmalere
Kacheln pro Reihe statt drei breiten. Auch das hat nie gewirkt, und
auch das aendert das Aussehen der Startseite spuerbar -- deshalb
bleibt es, wie es ist, bis er es gesehen und entschieden hat.
--------------------------------------------------------------------- */
/* Schiene und Glanz stehen im Abschnitt HUD-MODULE. */
/* ---------- Der Aufbau der Karte ------------------------------------- */
.kachel__link {
+351 -36
View File
@@ -49,6 +49,210 @@
nicht in einer Messung: Kein Prüfprogramm hätte danach gefragt. */
const punkt = (t) => (/[.!?]$/.test(t) ? t : t + '.');
/* ===================================================================
DIE VIER ZUSTÄNDE (22.09.2026)
-------------------------------------------------------------------
Filipe: „mach kategorien welche sind benutzt welche nicht welche
sind noch offen, welche laufen von wan bis wann."
Gerechnet wird der Zustand auf dem SERVER (`zustandVon`), nicht
hier. Zwei Rechnungen für dieselbe Frage laufen auseinander — und
spätestens um Mitternacht zeigte die Seite einen anderen Zustand
als die Datenbank.
Die Reihenfolge hier ist die, in der man sie liest: erst was jetzt
geht, dann was kommt, dann was vorbei ist, dann was weg ist.
=================================================================== */
const ZUSTAENDE = [
{ wert: '', wort: 'Alle' },
{ wert: 'frei', wort: 'Jetzt frei' },
{ wert: 'spaeter', wort: 'Kommt noch' },
{ wert: 'abgelaufen', wort: 'Abgelaufen' },
{ wert: 'benutzt', wort: 'Schon benutzt' },
];
const ZUSTAND_WORT = Object.fromEntries(
ZUSTAENDE.filter((z) => z.wert).map((z) => [z.wert, z.wort]));
/* Welche Kategorie gerade gewählt ist. Steht außerhalb von `laden()`:
Wäre sie drin, spränge die Liste nach jedem Nehmen zurück auf
„Alle" — und man müsste jedes Mal neu suchen, wo man war. */
let katFilter = '';
function tagText(iso) {
if (!iso) return '';
const t = String(iso).slice(0, 10).split('-');
return t.length === 3 ? `${t[2]}.${t[1]}.${t[0]}` : String(iso);
}
/* „ab 01.10.2026", „bis 07.10.2026" oder „01.10. – 07.10.2026".
Ein Zeitraum, bei dem eine Seite fehlt, ist trotzdem einer — und
„ab 01.10." sagt mehr als ein Gedankenstrich ins Leere. */
function zeitraum(m) {
if (m.gilt_ab && m.gilt_bis) return `${tagText(m.gilt_ab)} – ${tagText(m.gilt_bis)}`;
if (m.gilt_ab) return `ab ${tagText(m.gilt_ab)}`;
if (m.gilt_bis) return `bis ${tagText(m.gilt_bis)}`;
return '';
}
/* ===================================================================
BEARBEITEN — ein Formular IN der Karte, kein Kasten davor
-------------------------------------------------------------------
Erster Entwurf stellte drei Nachfragen hintereinander: Text, dann
„gilt ab", dann „gilt bis". Das ist dreimal Lesen und dreimal
Bestätigen für eine Sache, die auf eine Karte passt — und wer beim
dritten abbricht, hat die ersten zwei umsonst getippt.
Zweiter Fund beim Messen der echten Schnittstelle: `frageNach`
kennt kein vorbelegtes Textfeld. Eine Bearbeitung, die den
bisherigen Text nicht zeigt, ist keine Bearbeitung, sondern ein
Neuschreiben.
Also hier: Die Karte klappt auf, drei Felder stehen mit ihren
heutigen Werten darin, ein Knopf speichert. Abbrechen schließt
wieder — es wurde nichts angefasst, deshalb braucht es auch keine
Rückfrage.
=================================================================== */
function bearbeiten(m) {
const karteEl = document.querySelector(`.m-karte[data-id="${m.id}"]`);
if (!karteEl || karteEl.querySelector('.m-bearb')) return;
const f = el('form', 'm-bearb');
const zeile = (schild, art, wert, id) => {
const d = el('div', 'm-bearb__feld');
const l = el('label', 'feld-schild', schild);
l.htmlFor = id;
const i = art === 'text'
? el('textarea') : el('input');
i.id = id;
if (art !== 'text') i.type = art;
i.value = wert || '';
if (art === 'text') { i.rows = 2; i.maxLength = 600; }
d.append(l, i);
f.append(d);
return i;
};
const tText = zeile('Wofür ist es?', 'text', m.text, `b-text-${m.id}`);
const tAb = zeile('Gilt ab (freiwillig)', 'date', m.gilt_ab, `b-ab-${m.id}`);
const tBis = zeile('Gilt bis (freiwillig)', 'date', m.gilt_bis, `b-bis-${m.id}`);
const hinweis = el('p', 'm-bearb__hinweis',
'Die Datei selbst bleibt, wie sie ist. Wer ein anderes Bild will, '
+ 'stellt ein neues Stück bereit.');
const fehlerZeile = el('p', 'm-bearb__fehler');
fehlerZeile.setAttribute('role', 'alert');
const knoepfe = el('p', 'm-bearb__knoepfe');
const speichern = el('button', 'knopf knopf--klein', 'Speichern');
speichern.type = 'submit';
const ab = el('button', 'knopf-still', 'Abbrechen');
ab.type = 'button';
ab.addEventListener('click', () => f.remove());
knoepfe.append(speichern, ab);
f.append(hinweis, fehlerZeile, knoepfe);
f.addEventListener('submit', async (ev) => {
ev.preventDefault();
/* VORHER PRUEFEN, WAS DER SERVER OHNEHIN PRUEFT. Nicht statt
seiner — er bleibt die Regel. Aber ein Fenster, das rückwärts
läuft, hier schon zu sagen, spart den Weg hin und zurück. */
if (tAb.value && tBis.value && tAb.value > tBis.value) {
fehlerZeile.textContent = 'Das Ende liegt vor dem Anfang. Dreh die zwei Daten um.';
tBis.focus();
return;
}
speichern.disabled = true;
try {
const a = await fetch(`/workspace/api/material/${m.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: tText.value, gilt_ab: tAb.value, gilt_bis: tBis.value,
}),
});
const r = await a.json().catch(() => ({}));
if (!a.ok) {
fehlerZeile.textContent = window.sagWas?.(r.fehler, 'Ging nicht.') || 'Ging nicht.';
speichern.disabled = false;
return;
}
await laden();
} catch {
fehlerZeile.textContent = 'Das hat gerade nicht geklappt. Versuch es gleich noch einmal.';
speichern.disabled = false;
}
});
karteEl.querySelector('.m-karte__koerper')?.append(f);
tText.focus();
}
async function entfernen(m) {
/* `frageNach` liefert bei einer reinen Rückfrage `true`, nicht
`{ ok: true }` — das Objekt kommt nur, wenn ein Feld dabei ist.
Der erste Entwurf prüfte auf `erg?.ok`; damit wäre „Entfernen"
ein Knopf gewesen, der nichts tut, und niemand hätte den Grund
gesehen. Gemessen an der Quelle, nicht angenommen. */
const erg = await window.frageNach?.({
titel: 'Wirklich entfernen?',
was: `„${m.name}" verschwindet aus der Liste, und die Datei wird gelöscht.`,
bleibt: 'Was schon jemand genommen hat, ist davon nicht betroffen — '
+ 'das liegt längst auf seinem Gerät.',
endgueltig: true,
ja: 'Entfernen', nein: 'Doch nicht',
});
if (!erg) return;
try {
const a = await fetch(`/workspace/api/material/${m.id}`, { method: 'DELETE' });
const r = await a.json().catch(() => ({}));
if (!a.ok) { melde(window.sagWas?.(r.fehler, 'Ging nicht.') || 'Ging nicht.'); return; }
melde('');
await laden();
} catch { melde('Das hat gerade nicht geklappt. Versuch es gleich noch einmal.'); }
}
/* ===================================================================
DIE KATEGORIEN
-------------------------------------------------------------------
Die Zahl neben jedem Wort kommt aus den echten Daten. Eine Zahl im
HTML wäre die, die beim nächsten Stück falsch dasteht.
EINE KATEGORIE OHNE INHALT WIRD NICHT VERSTECKT, sondern grau: Wer
„Abgelaufen" sucht und den Knopf nicht findet, weiß nicht, ob es
nichts gibt oder ob er ihn übersieht. Eine 0 ist eine Antwort.
=================================================================== */
function katLeisteBauen(alle) {
const ziel = $('m-kat');
if (!ziel) return;
ziel.replaceChildren();
for (const z of ZUSTAENDE) {
const n = z.wert ? alle.filter((m) => m.zustand === z.wert).length : alle.length;
const b = el('button', 'schritt m-kat__knopf');
b.type = 'button';
b.dataset.wert = z.wert;
b.setAttribute('aria-pressed', String(katFilter === z.wert));
if (!n) b.dataset.leer = 'ja';
/* Das Wort als blosser Text, nicht in einer eigenen Huelle: Die
Huelle haette einen Klassennamen ohne eine einzige Regel
dahinter -- und niemand weiss beim naechsten Umbau, ob er sie
anfassen darf. Anonymer Text in einer Flex-Reihe ist selbst
ein Flex-Kind, `gap` wirkt also trotzdem. */
b.append(document.createTextNode(z.wort));
b.append(el('span', 'm-kat__zahl', String(n)));
b.addEventListener('click', () => {
/* NOCH EINMAL AUF DASSELBE HEISST „ALLE". Sonst gibt es keinen
Weg zurueck ausser dem Knopf ganz links -- und wer zweimal
tippt, erwartet das Gegenteil, nicht nichts.
„Alle" selbst bleibt dabei „Alle": `'' === ''` waere sonst
ein Klick, der den Zustand nicht aendert und trotzdem neu
zeichnet. */
katFilter = (z.wert && katFilter === z.wert) ? '' : z.wert;
zeichnen();
});
ziel.append(b);
}
}
/* ===================================================================
EINE KARTE
=================================================================== */
@@ -92,6 +296,18 @@
fuss.append(el('span', 'm-karte__leise', `von ${m.von}`));
koerper.append(fuss);
/* VON WANN BIS WANN (22.09.2026).
Steht nur da, WENN es ein Fenster gibt. Eine Zeile "ohne
Zeitraum" auf jeder zweiten Karte waere Rauschen -- und Rauschen
liest niemand, auch nicht die eine Zeile, auf die es ankommt. */
if (m.gilt_ab || m.gilt_bis) {
const z = el('p', 'm-karte__zeit');
z.dataset.zustand = m.zustand;
z.append(el('span', 'm-karte__zeit-marke', ZUSTAND_WORT[m.zustand] || ''));
z.append(document.createTextNode(' ' + zeitraum(m)));
koerper.append(z);
}
/* ---- Der Zustand ---- */
const meldung = el('p', 'm-karte__meldung');
meldung.hidden = true;
@@ -120,6 +336,30 @@
koerper.append(knopf);
}
/* BEARBEITEN UND ENTFERNEN (22.09.2026).
Filipe: "will ich dass die rechte und linke hand es auch
bearbeiten und loeschen koennen. dogfather auch fals es ein
fehler gab."
OB JEMAND DARF, SAGT DER SERVER (`m.darf_ich`) -- hier wird es
nicht nachgerechnet. Zwei Rechnungen fuer dieselbe Frage laufen
auseinander, und die im Browser ist die, der man ohnehin nicht
trauen darf.
Ein vergebenes Stueck bleibt unangetastet: Wer es genommen hat,
hat sich auf diesen Text verlassen. */
if (m.darf_ich && !m.genommen) {
const reihe = el('p', 'm-karte__verwalten');
const bearb = el('button', 'knopf-still', 'Bearbeiten');
bearb.type = 'button';
bearb.addEventListener('click', () => bearbeiten(m));
const weg = el('button', 'knopf-still knopf-still--warn', 'Entfernen');
weg.type = 'button';
weg.addEventListener('click', () => entfernen(m));
reihe.append(bearb, weg);
koerper.append(reihe);
}
koerper.append(meldung);
k.append(koerper);
return k;
@@ -200,6 +440,20 @@
+ `Mehr als ${groesse(stand.max_bytes)} geht nicht.`;
return;
}
/* DAS FENSTER WIRD VOR DEM HOCHLADEN GEPRÜFT, NICHT DANACH.
Der Server lehnt ein verkehrtes Fenster ohnehin ab — aber
erst, nachdem 60 MB durch das Handynetz gewandert sind. Wer
das erlebt, lädt zweimal hoch für einen Zahlendreher. */
const abFeld = $('m-ab');
const bisFeld = $('m-bis');
if (abFeld?.value && bisFeld?.value && abFeld.value > bisFeld.value) {
stand2.textContent = window.sagWas?.('fenster_verkehrt', '')
|| 'Das Ende liegt vor dem Anfang.';
bisFeld.focus();
return;
}
knopf.disabled = true;
/* ÜBER DEN GEMEINSAMEN HOCHLADER -- er zeigt den Fortschritt und
@@ -217,6 +471,10 @@
'Content-Type': datei.type || 'application/octet-stream',
'X-Datei-Name': encodeURIComponent(datei.name || ''),
'X-Text': encodeURIComponent(($('m-text')?.value || '').slice(0, 600)),
/* Leer ist erlaubt und heißt „gilt immer" — der Server macht
aus einer leeren Kopfzeile `null`, nicht einen Fehler. */
'X-Gilt-Ab': abFeld?.value || '',
'X-Gilt-Bis': bisFeld?.value || '',
},
beiFortschritt: (anteil, gesendet, gesamt) => anzeige?.fortschritt(anteil, gesendet, gesamt),
beiVerarbeitung: () => anzeige?.verarbeiten(),
@@ -241,6 +499,8 @@
stand2.textContent = 'Steht jetzt bereit.';
feld.value = '';
const t = $('m-text'); if (t) t.value = '';
if (abFeld) abFeld.value = '';
if (bisFeld) bisFeld.value = '';
await laden();
} finally {
knopf.disabled = false;
@@ -251,6 +511,96 @@
/* ===================================================================
LADEN
=================================================================== */
/* ===================================================================
ZEICHNEN — getrennt vom Holen (22.09.2026)
-------------------------------------------------------------------
Bis heute war beides eine Funktion. Mit den Kategorien geht das
nicht mehr: Ein Klick auf „Abgelaufen" darf nicht die ganze Liste
neu vom Server holen -- das wäre ein Abruf für eine Frage, deren
Antwort schon im Browser liegt, und am Handy im Funkloch ein
Zustand, in dem man nichts sieht.
=================================================================== */
/* WARUM OBEN NICHTS STEHT, HAT DREI GRÜNDE — und der dritte fehlte.
Wer „Schon benutzt" antippt, bekommt oben immer eine leere Liste,
weil benutzte Stücke unten stehen. „Ist gerade nichts" wäre dort
schlicht gelogen und schickte jemanden los, der schon am Ziel ist. */
function leerSatz(untenAnzahl) {
if (katFilter && untenAnzahl) {
return `Unter „${ZUSTAND_WORT[katFilter] || katFilter}" steht nichts zum `
+ 'Mitnehmen — was dazu passt, findest du weiter unten.';
}
if (katFilter) {
return `In „${ZUSTAND_WORT[katFilter] || katFilter}" ist gerade nichts. `
+ 'Tipp oben auf „Alle", um wieder alles zu sehen.';
}
return stand.darf_einstellen
? 'Gerade nichts frei. Stell oben etwas bereit — dann können die anderen es sich holen.'
: 'Gerade ist nichts frei. Schau später noch einmal rein — hier kommt regelmäßig Neues dazu.';
}
function zeichnen() {
if (!stand) return;
$('neu-block').hidden = !stand.darf_einstellen;
const alle = stand.material || [];
katLeisteBauen(alle);
/* DER FILTER GILT FÜR BEIDE ABSCHNITTE — sonst ist er keiner.
Im ersten Entwurf filterte nur die obere Liste. „Schon benutzt"
anzutippen ergab damit oben zwangsläufig nichts (ein benutztes
Stück steht nie zum Mitnehmen) und unten unverändert alles: Der
Knopf sah aus, als täte er nichts, und die Zahl daneben passte
zu keiner der beiden Listen. */
const passt = (m) => !katFilter || m.zustand === katFilter;
const frei = alle.filter((m) => !m.genommen && passt(m));
const weg = alle.filter((m) => m.genommen && passt(m));
const zielFrei = $('frei');
zielFrei.replaceChildren();
zielFrei.setAttribute('aria-busy', 'false');
if (!frei.length) {
/* KEIN LEERER BILDSCHIRM. Ob das gut oder schlecht ist, hängt
davon ab, wer liest -- deshalb drei Sätze statt einem. Der
dritte ist neu: Eine leere Liste nach einem Klick auf eine
Kategorie ist etwas anderes als eine leere Liste. */
zielFrei.append(el('p', 'm-leer', leerSatz(weg.length)));
}
for (const m of frei) zielFrei.append(karte(m));
/* ZWEI ZAHLEN FÜR FAST DASSELBE, DIE SICH WIDERSPRECHEN.
Auf dem ersten Bildschirmfoto stand oben „4 Stück zum
Mitnehmen" und eine Zeile darunter „Jetzt frei 2". Beide
stimmten — die eine zählt alles Freie, die andere nur das, was
heute schon gilt —, aber wer sie zum ersten Mal sieht, hält
eine davon für falsch und traut ab da keiner mehr.
Also stehen sie jetzt in EINEM Satz und erklären sich
gegenseitig. Und nur dann, wenn sie sich unterscheiden: Steht
„4, davon 4 sofort", ist das keine Auskunft, sondern Lärm. */
const sofort = frei.filter((m) => m.zustand === 'frei').length;
$('frei-satz').textContent = !frei.length ? ''
: katFilter
? `${frei.length} in „${ZUSTAND_WORT[katFilter] || katFilter}". `
+ 'Wer es nimmt, hat es — danach ist es für alle anderen weg.'
: `${frei.length} Stück zum Mitnehmen`
+ (sofort === frei.length ? '. ' : `, davon ${sofort} sofort. `)
+ 'Wer es nimmt, hat es — danach ist es für alle anderen weg.';
$('weg-block').hidden = !weg.length;
const zielWeg = $('weg');
zielWeg.replaceChildren();
for (const m of weg) zielWeg.append(karte(m));
if (weg.length) {
$('weg-satz').textContent = stand.sieht_wer
? `${weg.length} schon vergeben — mit Namen, damit du weißt, wer was postet.`
: `${weg.length} schon vergeben. Damit nichts zweimal gepostet wird.`;
}
$('laedt').hidden = true;
$('haupt')?.removeAttribute('aria-busy');
melde('');
}
async function laden() {
try {
const a = await fetch('/workspace/api/material');
@@ -259,42 +609,7 @@
return;
}
stand = await a.json();
$('neu-block').hidden = !stand.darf_einstellen;
const frei = (stand.material || []).filter((m) => !m.genommen);
const weg = (stand.material || []).filter((m) => m.genommen);
const zielFrei = $('frei');
zielFrei.replaceChildren();
zielFrei.setAttribute('aria-busy', 'false');
if (!frei.length) {
/* KEIN LEERER BILDSCHIRM. Ob das gut oder schlecht ist, hängt
davon ab, wer liest -- deshalb zwei Sätze. */
zielFrei.append(el('p', 'm-leer', stand.darf_einstellen
? 'Gerade nichts frei. Stell oben etwas bereit — dann können die anderen es sich holen.'
: 'Gerade ist nichts frei. Schau später noch einmal rein — hier kommt regelmäßig Neues dazu.'));
}
for (const m of frei) zielFrei.append(karte(m));
$('frei-satz').textContent = frei.length
? `${frei.length} ${frei.length === 1 ? 'Stück' : 'Stück'} zum Mitnehmen. `
+ 'Wer es nimmt, hat es — danach ist es für alle anderen weg.'
: '';
$('weg-block').hidden = !weg.length;
const zielWeg = $('weg');
zielWeg.replaceChildren();
for (const m of weg) zielWeg.append(karte(m));
if (weg.length) {
$('weg-satz').textContent = stand.sieht_wer
? `${weg.length} schon vergeben — mit Namen, damit du weißt, wer was postet.`
: `${weg.length} schon vergeben. Damit nichts zweimal gepostet wird.`;
}
$('laedt').hidden = true;
$('haupt')?.removeAttribute('aria-busy');
melde('');
zeichnen();
} catch {
window.ladefehler?.({ nochmal: laden });
}
+27 -3
View File
@@ -188,7 +188,9 @@
'Das geht nur in einer Gruppe oder einem Kanal, nicht im Zweiergespräch.',
/* ---- MATERIAL ZUM POSTEN (22.09.2026) ------------------------
Acht Kennungen kamen mit workspace-material.js dazu.
Die Kennungen stammen aus workspace-material.js. Hier steht
KEINE Anzahl daneben: Der erste Entwurf sagte "Acht
Kennungen" und war beim naechsten Auftrag still falsch.
DER WICHTIGSTE SATZ IST „schon_genommen" — und er ist bewusst
KEIN Fehler. Wer ihn liest, hat nichts falsch gemacht; jemand
@@ -220,9 +222,31 @@
datei_weg:
'Die Datei liegt nicht mehr da. Sag DogFather Bescheid, dann '
+ 'stellt er sie neu ein.',
/* GEAENDERT AM 22.09.2026, WEIL DER SATZ NICHT MEHR STIMMTE.
Er lautete: „wegnehmen kann es nur, wer es hergegeben hat."
Seit die Hände und DogFather fremde Stücke bearbeiten und
entfernen dürfen, ist das schlicht falsch — und hätte jemanden
losgeschickt, den Einsteller zu suchen, obwohl neben ihm jemand
sitzt, der es in zwei Sekunden kann.
Er nennt bewusst keine Rollennamen: Wer darf, entscheidet der
Server, und diese Datei lädt jeder herunter. */
nicht_deins:
'Das hat jemand anders eingestellt – wegnehmen kann es nur, wer '
+ 'es hergegeben hat.'
'Das darfst du hier nicht ändern. Sag kurz DogFather oder einer '
+ 'der Hände Bescheid — sie können jedes Stück bearbeiten und '
+ 'entfernen.',
/* ---- Zeitraum und vergebene Stücke (22.09.2026) ------------- */
schon_im_umlauf:
'Das hat sich schon jemand genommen und postet es vielleicht '
+ 'gerade. Ändern lässt es sich deshalb nicht mehr — stell lieber '
+ 'ein neues Stück ein.',
datum_unbrauchbar:
'Mit dem Datum kann ich nichts anfangen. Nimm den Kalender im '
+ 'Feld, dann passt das Format von allein.',
fenster_verkehrt:
'Das Ende liegt vor dem Anfang. Dreh die beiden Daten um — oder '
+ 'lass eins davon leer, wenn es nur nach einer Seite begrenzt ist.'
};
/* Sieht das wie eine Maschinenkennung aus?
+17 -17
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -367,16 +367,16 @@
<!-- 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=202609221325"></script>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/textform.js?v=202609221359"></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/zuteilung.js?v=202609221325" defer></script>
<script src="assets/js/aufgaben.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/zuteilung.js?v=202609221359" defer></script>
<script src="assets/js/aufgaben.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -168,13 +168,13 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/automation.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/automation.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -180,13 +180,13 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/befinden.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/befinden.js?v=202609221359" defer></script>
</body>
</html>
+20 -20
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -304,17 +304,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=202609221325"></script>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/textform.js?v=202609221359"></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/checkliste.js?v=202609221325" defer></script>
<script src="assets/js/ampel.js?v=202609221325" defer></script>
<script src="assets/js/schulung.js?v=202609221325" defer></script>
<script src="assets/js/bereich.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/checkliste.js?v=202609221359" defer></script>
<script src="assets/js/ampel.js?v=202609221359" defer></script>
<script src="assets/js/schulung.js?v=202609221359" defer></script>
<script src="assets/js/bereich.js?v=202609221359" defer></script>
</body>
</html>
+17 -17
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -108,12 +108,12 @@
</main>
<!-- Der Fuß gehört zu jeder Seite - siehe pruef-css-klassen. -->
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/auskunft.js?v=202609221325" defer></script>
<script src="assets/js/bewerben.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/auskunft.js?v=202609221359" defer></script>
<script src="assets/js/bewerben.js?v=202609221359" defer></script>
</body>
</html>
+16 -16
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- haus.css MUSS die letzte Stilvorlage sein - siehe treff-regeln.html. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -80,13 +80,13 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/auskunft.js?v=202609221325" defer></script>
<script src="assets/js/bewerbungen.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/auskunft.js?v=202609221359" defer></script>
<script src="assets/js/bewerbungen.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -89,14 +89,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/ki.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/calls.js?v=202609221325" defer></script>
<script src="assets/js/ki.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/calls.js?v=202609221359" defer></script>
</body>
</html>
+18 -18
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -415,24 +415,24 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609221325"></script>
<script src="assets/js/bereiche.js?v=202609221359"></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=202609221325"></script>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325"></script>
<script src="assets/js/glocke.js?v=202609221325"></script>
<script src="assets/js/textform.js?v=202609221359"></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359"></script>
<script src="assets/js/glocke.js?v=202609221359"></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=202609221325"></script>
<script src="assets/js/chat.js?v=202609221325"></script>
<script src="assets/js/anruf.js?v=202609221359"></script>
<script src="assets/js/chat.js?v=202609221359"></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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/content.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/content.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -179,14 +179,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/checkliste.js?v=202609221325" defer></script>
<script src="assets/js/content.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/checkliste.js?v=202609221359" defer></script>
<script src="assets/js/content.js?v=202609221359" defer></script>
</body>
</html>
+5 -5
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609221359" />
</head>
<body class="gate gate--crew">
@@ -381,6 +381,6 @@
<script src="assets/js/gate.js?v=202609221325" defer></script>
<script src="assets/js/gate.js?v=202609221359" defer></script>
</body>
</html>
+4 -4
View File
@@ -22,25 +22,25 @@
},
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609221325",
"src": "/assets/img/app-symbole/crew-192.png?v=202609221359",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609221325",
"src": "/assets/img/app-symbole/crew-512.png?v=202609221359",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609221325",
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609221359",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609221325",
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609221359",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -108,14 +108,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/dateien.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/dateien.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -132,13 +132,13 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/entwicklung.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/entwicklung.js?v=202609221359" defer></script>
</body>
</html>
+13 -13
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/hilfe.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -146,12 +146,12 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/hilfe.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/hilfe.js?v=202609221359" defer></script>
</body>
</html>
+4 -4
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
</head>
<body class="gate">
@@ -411,6 +411,6 @@
</div>
␍␍
<script src="assets/js/gate.js?v=202609221325" defer></script>
<script src="assets/js/gate.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -383,14 +383,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/kalender.js?v=202609221325" defer></script>
<script src="assets/js/kalender-abo.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/kalender.js?v=202609221359" defer></script>
<script src="assets/js/kalender-abo.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -444,12 +444,12 @@
</form>
</dialog>
<script src="assets/js/meldung.js?v=202609221325"></script>
<script src="assets/js/nachfrage.js?v=202609221325"></script>
<script src="assets/js/wahl.js?v=202609221325"></script>
<script src="assets/js/bereiche.js?v=202609221325"></script>
<script src="assets/js/kopf.js?v=202609221325"></script>
<script src="assets/js/glocke.js?v=202609221325"></script>
<script src="assets/js/leistung.js?v=202609221325"></script>
<script src="assets/js/meldung.js?v=202609221359"></script>
<script src="assets/js/nachfrage.js?v=202609221359"></script>
<script src="assets/js/wahl.js?v=202609221359"></script>
<script src="assets/js/bereiche.js?v=202609221359"></script>
<script src="assets/js/kopf.js?v=202609221359"></script>
<script src="assets/js/glocke.js?v=202609221359"></script>
<script src="assets/js/leistung.js?v=202609221359"></script>
</body>
</html>
+56 -18
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>Material · Team Dogi</title>
<title>Dogi-Media · Team Dogi</title>
<meta name="robots" content="noindex, nofollow" />
<!-- app.webmanifest, NICHT crew.webmanifest -- die Adresse biegt es um.
Der Server ersetzt den Pfad auf crew. an EINER Stelle
@@ -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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/material.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/material.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start" data-ton="42" data-buehne="studio">
@@ -29,7 +29,7 @@
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 5l-7 7 7 7"/></svg>
<span class="zurueck-knopf__text">Übersicht</span>
</button>
<p class="marke"><span class="marke__text"><a class="zurueck" href="start.html">Team&nbsp;Dogi</a> · Material</span></p>
<p class="marke"><span class="marke__text"><a class="zurueck" href="start.html">Team&nbsp;Dogi</a> · Dogi-Media</span></p>
<div class="kopfleiste__rechts">
<span class="wer" id="wer">…</span>
<button type="button" class="abmelden" id="abmelden">Abmelden</button>
@@ -41,7 +41,7 @@
<section class="kopf-zeile">
<div>
<p class="marke" id="ober">Community</p>
<h1 class="titel">Material</h1>
<h1 class="titel">Dogi-Media</h1>
<p class="unterzeile">
Bilder und Videos zum Posten. <strong>Jedes nur einmal</strong> — wer es
nimmt, hat es; danach ist es für alle anderen weg.
@@ -69,6 +69,30 @@
<textarea id="m-text" rows="2"
placeholder="z. B. „Für TikTok, passt zum Stream von gestern“"></textarea>
</div>
<!-- VON WANN BIS WANN (22.09.2026). Filipe: "welche laufen von
wan bis wann, das muss man auch machen koennen."
BEIDES FREIWILLIG: Der haeufigste Fall ist "gilt einfach".
Ein Pflichtfeld erzwaenge ein erfundenes Datum, und ein
erfundenes Datum ist schlechter als keins.
STEHT AUSSERHALB VON .m-neu__knoepfe -- das ist eine
Flex-Reihe fuer Knopf und Stand. Zwei Datumsfelder und ein
Hinweissatz darin waeren vier Flex-Kinder nebeneinander und
auf dem Handy eine Treppe. -->
<div class="m-neu__zeile m-neu__fenster">
<div class="m-neu__fenster-feld">
<label class="feld-schild" for="m-ab">Gilt ab (freiwillig)</label>
<input type="date" id="m-ab" />
</div>
<div class="m-neu__fenster-feld">
<label class="feld-schild" for="m-bis">Gilt bis (freiwillig)</label>
<input type="date" id="m-bis" />
</div>
</div>
<p class="feld-hinweis m-neu__fenster-satz">
Ohne Datum gilt es einfach — bis es jemand nimmt.
</p>
<div class="m-neu__knoepfe">
<button type="button" class="knopf knopf--klein" id="m-hoch">Bereitstellen</button>
<span class="m-neu__stand" id="m-stand" aria-live="polite"></span>
@@ -83,6 +107,20 @@
<div class="m-kopf">
<h2 class="m-kopf__titel" id="frei-titel">Zum Mitnehmen</h2>
<p class="m-kopf__satz" id="frei-satz"></p>
<!-- KATEGORIEN (22.09.2026). Filipe: "mach kategorien welche sind
benutzt welche nicht welche sind noch offen, welche laufen
von wan bis wann."
Die Knoepfe werden im Skript gebaut, damit die Zahl daneben
aus den echten Daten kommt und nicht aus dem HTML -- eine
Zahl im Markup waere die, die beim naechsten Stueck falsch
dasteht.
DIE LEISTE IST DIE DES HAUSES (.filter mit .schritt), nicht
eine eigene. Auf dateien.html und bereich.html steht dieselbe
Reihe; eine dritte Bauart haette dasselbe anders ausgesehen
und beim naechsten Umbau nur an zwei von drei Stellen
mitgeaendert. -->
<div class="filter" id="m-kat" role="group" aria-label="Kategorie"></div>
</div>
<div class="m-raster" id="frei" aria-busy="true"></div>
</section>
@@ -100,13 +138,13 @@
<p class="m-laedt" id="laedt">Einen Moment …</p>
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/material.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/material.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -453,13 +453,13 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/personen.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/personen.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -214,15 +214,15 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/steckbrief.js?v=202609221325" defer></script>
<script src="assets/js/profil.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/steckbrief.js?v=202609221359" defer></script>
<script src="assets/js/profil.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -134,11 +134,11 @@
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=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/rechte.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/rechte.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/report.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/report.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -106,14 +106,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/ki.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/report.js?v=202609221325" defer></script>
<script src="assets/js/ki.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/report.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -173,13 +173,13 @@
</div>
</div>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/scouting.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/scouting.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -678,15 +678,15 @@
</p>
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/live.js?v=202609221325" defer></script>
<script src="assets/js/start.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/live.js?v=202609221359" defer></script>
<script src="assets/js/start.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -85,14 +85,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/ki.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/startcheck.js?v=202609221325" defer></script>
<script src="assets/js/ki.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/startcheck.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -150,15 +150,15 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/auskunft.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/steckbrief.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/auskunft.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/steckbrief.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bewerbung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -111,12 +111,12 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/talente.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/talente.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/team.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/team.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -110,12 +110,12 @@
</main>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/team.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/team.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/team.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/team.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<!-- `data-buehne` steht hier fest und nicht im Skript: Die Kachel zu
@@ -84,11 +84,11 @@
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=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/teamlage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/teamlage.js?v=202609221359" defer></script>
</body>
</html>
+13 -13
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -112,12 +112,12 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/teilen.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/teilen.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -126,12 +126,12 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/treff-moderation.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/treff-moderation.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- haus.css MUSS die letzte Stilvorlage sein. Auf der Adresse des
Treffs 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -221,11 +221,11 @@
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=202609221325" defer></script>␍
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/auskunft.js?v=202609221325" defer></script>
<script src="assets/js/treff-regeln.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/auskunft.js?v=202609221359" defer></script>
<script src="assets/js/treff-regeln.js?v=202609221359" defer></script>
</body>
</html>
+15 -15
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -149,14 +149,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>␍
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>␍
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/uebersicht.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/uebersicht.js?v=202609221359" defer></script>
</body>
</html>
+13 -13
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/unsere-seiten.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -335,12 +335,12 @@
</main>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/live.js?v=202609221325" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/live.js?v=202609221359" defer></script>
<script src="assets/js/unsere-seiten.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/entwicklung.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/werdegang.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -144,11 +144,11 @@
</main>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/werdegang.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/werdegang.js?v=202609221359" defer></script>
</body>
</html>
+14 -14
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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/willkommen.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<!-- KOERPERKLASSE "start", NICHT "gate" (berichtigt 21.09.2026).
`body.gate` ist die Anmeldewand: `display:flex; align-items:center`,
@@ -75,12 +75,12 @@
<p class="fehler" id="fehler" hidden></p>
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/willkommen.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/willkommen.js?v=202609221359" 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=202609221325" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221325" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609221325" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221325" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609221359" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609221359" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/start.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609221359" />
<link rel="stylesheet" href="assets/css/module.css?v=202609221359" />
<!-- 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=202609221325" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609221359" />
</head>
<body class="start">
@@ -190,14 +190,14 @@
</main>
<script src="assets/js/meldung.js?v=202609221325" defer></script>
<script src="assets/js/hochladen.js?v=202609221325" defer></script>
<script src="assets/js/nachfrage.js?v=202609221325" defer></script>
<script src="assets/js/meldung.js?v=202609221359" defer></script>
<script src="assets/js/hochladen.js?v=202609221359" defer></script>
<script src="assets/js/nachfrage.js?v=202609221359" defer></script>
<script src="assets/js/wahl.js?v=202609221325" defer></script>
<script src="assets/js/bereiche.js?v=202609221325" defer></script>
<script src="assets/js/kopf.js?v=202609221325" defer></script>
<script src="assets/js/glocke.js?v=202609221325" defer></script>
<script src="assets/js/wissen.js?v=202609221325" defer></script>
<script src="assets/js/wahl.js?v=202609221359" defer></script>
<script src="assets/js/bereiche.js?v=202609221359" defer></script>
<script src="assets/js/kopf.js?v=202609221359" defer></script>
<script src="assets/js/glocke.js?v=202609221359" defer></script>
<script src="assets/js/wissen.js?v=202609221359" defer></script>
</body>
</html>