diff --git a/server/pruef-entwicklung-kacheln.mjs b/server/pruef-entwicklung-kacheln.mjs new file mode 100644 index 00000000..b7c0c25f --- /dev/null +++ b/server/pruef-entwicklung-kacheln.mjs @@ -0,0 +1,250 @@ +/* ===================================================================== + DIE PERSONENKACHELN AUF DER ENTWICKLUNGSSEITE (17.09.2026) + + Filipe, mit zwei Bildschirmfotos nebeneinander: "wieso ist diese + seite noch nicht im stil und perfektioniert wie die auf screen2 ... + aber so dass ich die leute in einer kachel aussuchen kann alle + einzel." + + Der Unterschied zur Checkliste lag nicht im Aufbau -- der stimmte -- + sondern an zwei Stellen: + + 1. Die Zahlen standen als graue Textzeilen da, drueben als + abgesetzte Kaesten mit grosser Ziffer (`bilanz-zahl`). + 2. Eine angeklickte Person sah aus wie eine nicht angeklickte. Wer + scrollte, wusste nicht mehr, wen er offen hat. + + --------------------------------------------------------------------- + WAS HIER GEPRUEFT WIRD -- UND WARUM NICHT DAS AUSSEHEN + + Ob etwas "gleich aussieht", laesst sich nicht messen. Die drei Fragen + darunter schon, und sie sind das, was das Aussehen traegt: + + - Benutzt die Kachel den HAUSBAUSTEIN (`bilanz-zahl`) oder einen + Nachbau? Ein Nachbau laeuft auseinander, sobald jemand eins von + beiden anfasst. + - Stimmen die Zahlen? "angesehen" plus "noch offen" MUSS die + Gesamtzahl ergeben. Zwei Zahlen, die nebeneinander stehen und + nicht zusammenpassen, sind schlimmer als eine. + - Sieht man, wer gewaehlt ist? Und zwar so, dass es auch ein + Vorleseprogramm sagen kann. + + MIT GEGENPROBE: Vor dem ersten Klick darf KEINE Kachel gewaehlt sein. + Sonst hiesse "eine ist gewaehlt" nur, dass immer eine gewaehlt ist. + + Aufrufen mit: node server/pruef-entwicklung-kacheln.mjs + Bild: SCHIRM=1 node server/pruef-entwicklung-kacheln.mjs + ===================================================================== */ + +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { portMussFreiSein } from "./helfer-port.mjs"; + +const PORT = await portMussFreiSein(4475, "pruef-entwicklung-kacheln"); +const ordner = mkdtempSync(join(tmpdir(), "ws-ekach-")); +process.env.WORKSPACE_DB = join(ordner, "workspace.db"); +process.env.PORT = String(PORT); +process.env.SITE_ACCESS_SECRET = "lokaler-test"; +process.env.SITE_ACCESS_CODE_DOGI = "DOGI-TEST-1"; +process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00"; + +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 }); }; +import { notbremse } from "./helfer-notbremse.mjs"; +await import("./index.js"); +notbremse(180_000, "pruef-entwicklung-kacheln"); +await new Promise((r) => setTimeout(r, 700)); +const BASIS = `http://127.0.0.1:${PORT}`; + +process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f); process.exit(7); }); +process.on("unhandledRejection", (f) => { console.error("ABSTURZ (Versprechen):", f); process.exit(7); }); + +let fehler = 0, geprueft = 0; +const melde = (t) => console.log(t); +const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; }; + +const { DatabaseSync } = await import("node:sqlite"); +const { scryptSync, randomBytes, createHmac } = await import("node:crypto"); +const d = new DatabaseSync(process.env.WORKSPACE_DB); +const jetzt = new Date().toISOString(); +const schluessel = randomBytes(32).toString("hex"); +d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)" + + " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING") + .run("code_kennung_schluessel", schluessel, jetzt); + +function anlegen(name, rolle, code) { + const salt = randomBytes(16).toString("hex"); + const hash = scryptSync(code, salt, 64, + { N: 32768, r: 8, p: 1, maxmem: 96 * 1024 * 1024 }).toString("hex"); + d.prepare("INSERT INTO personen" + + " (name, rolle, code_hash, code_salt, code_n, code_kennung, aktiv, erstellt)" + + " VALUES (?,?,?,?,?,?,1,?)") + .run(name, rolle, hash, salt, 32768, + createHmac("sha256", schluessel).update(code).digest("hex"), jetzt); + return d.prepare("SELECT last_insert_rowid() AS id").get().id; +} +anlegen("Filipe", "admin", "CODE-DOGI-0001"); +anlegen("VanVan", "hand", "CODE-HAND-0001"); +anlegen("Diene", "modi", "CODE-MODI-0001"); +d.close(); + +const an = await fetch(BASIS + "/workspace/api/anmelden", { + method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ rolle: "admin", code: "CODE-DOGI-0001" }), +}); +const keks = (an.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; "); + +const { chromium } = await import( + "file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs"); +const browser = await chromium.launch(); +try { + const kontext = await browser.newContext({ viewport: { width: 1280, height: 900 } }); + await kontext.addCookies(keks.split("; ").map((k) => { + const [name, ...rest] = k.split("="); + return { name, value: rest.join("="), domain: "127.0.0.1", path: "/" }; + })); + const seite = await kontext.newPage(); + const konsole = []; + seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); }); + await seite.goto(`${BASIS}/workspace/entwicklung.html`, { waitUntil: "networkidle" }); + await seite.waitForSelector("#personen .e-person", { timeout: 15_000 }); + await seite.waitForTimeout(400); + + /* ===================================================================== + 1. DIE REIHE UND IHRE KACHELN + ===================================================================== */ + melde(""); + melde("=== 1. Die Reihe ==="); + { + const b = await seite.evaluate(() => { + const reihe = document.getElementById("personen"); + const kacheln = [...reihe.querySelectorAll(".e-person")]; + return { + schild: reihe.getAttribute("aria-label") || "", + anzahl: kacheln.length, + namen: kacheln.map((k) => k.querySelector(".e-person__name")?.textContent || ""), + /* Der Hausbaustein, nicht ein Nachbau. */ + bilanzJe: kacheln.map((k) => k.querySelectorAll(".bilanz-zahl").length), + eigeneKlassen: kacheln.map((k) => k.querySelectorAll( + "[class*='e-person__bilanz'] > :not(.bilanz-zahl)").length), + }; + }); + ok(b.schild === "Person wählen", `die Reihe sagt, was sie ist ("${b.schild}")`); + ok(b.anzahl === 2, `zwei Kacheln (${b.namen.join(", ")})`); + /* DREI KAESTEN JE KACHEL -- dieselben drei wie auf der Checkliste. */ + ok(b.bilanzJe.length > 0 && b.bilanzJe.every((n) => n === 3), + `jede Kachel traegt drei Bilanz-Kaesten (${b.bilanzJe.join(", ")})`); + /* UND NICHTS DANEBEN: Ein eigener Nachbau neben dem Hausbaustein + waere genau die zweite Wahrheit, die hier vermieden wird. */ + ok(b.eigeneKlassen.every((n) => n === 0), + "und nichts Selbstgebautes daneben"); + } + + /* ===================================================================== + 2. STIMMEN DIE ZAHLEN? + ===================================================================== */ + melde(""); + melde("=== 2. Die Zahlen ==="); + { + const z = await seite.evaluate(() => [...document.querySelectorAll("#personen .e-person")] + .map((k) => { + const werte = [...k.querySelectorAll(".bilanz-zahl")].map((b) => ({ + n: Number(b.querySelector(".bilanz-zahl__n")?.textContent || "x"), + text: b.querySelector(".bilanz-zahl__text")?.textContent || "", + stufe: b.dataset.stufe || "", + })); + return { name: k.querySelector(".e-person__name")?.textContent || "", werte }; + })); + + ok(z.every((k) => k.werte.every((w) => Number.isFinite(w.n))), + "jede Ziffer ist eine Zahl"); + ok(z.every((k) => k.werte[0].text === "angesehen" + && k.werte[1].text === "noch offen" + && k.werte[2].text === "verschieden gesehen"), + `die drei heissen ueberall gleich (${z[0]?.werte.map((w) => w.text).join(" · ")})`); + + /* DIE ENTSCHEIDENDE RECHNUNG: Die ersten beiden teilen dasselbe + Ganze. Gehen sie nicht auf, stehen zwei Zahlen nebeneinander, die + einander widersprechen -- genau das, was auf der Startseite + repariert wurde. Die Gesamtzahl kommt aus der Auskunft selbst, + nicht aus einer festen Zahl hier. */ + const gesamt = await seite.evaluate(async () => { + const a = await fetch("/workspace/api/entwicklung/lage", { credentials: "same-origin" }); + return a.ok ? (await a.json()).gesamt_fremd : -1; + }); + ok(gesamt > 0, `die Seite kennt ${gesamt} Punkte insgesamt`); + const summenOk = z.every((k) => k.werte[0].n + k.werte[1].n === gesamt); + ok(summenOk, + `angesehen + noch offen = ${gesamt} bei jeder Kachel ` + + `(${z.map((k) => `${k.name}: ${k.werte[0].n}+${k.werte[1].n}`).join(", ")})`); + + /* Der Ton gehoert zur Aussage: fertig ist gruen, halb ist es nicht. */ + ok(z.every((k) => k.werte[0].stufe === (k.werte[1].n === 0 ? "gut" : "offen")), + "fertig Angesehenes ist gruen, Halbes nicht"); + } + + /* ===================================================================== + 3. EINZELN AUSWAEHLBAR -- UND MAN SIEHT ES + ===================================================================== */ + melde(""); + melde("=== 3. Auswaehlen ==="); + { + /* GEGENPROBE ZUERST: Vorher darf keine gewaehlt sein. */ + const vorher = await seite.evaluate(() => [...document.querySelectorAll("#personen .e-person")] + .map((k) => k.getAttribute("aria-pressed"))); + ok(vorher.length > 0 && vorher.every((w) => w === "false"), + `vor dem Klick ist keine gewaehlt (${vorher.join(", ")})`); + + await seite.click("#personen .e-person:nth-of-type(2)"); + await seite.waitForTimeout(900); + + const nachher = await seite.evaluate(() => ({ + gedrueckt: [...document.querySelectorAll("#personen .e-person")] + .map((k) => k.getAttribute("aria-pressed")), + wer: document.querySelector('#personen .e-person[aria-pressed="true"] .e-person__name') + ?.textContent || "", + karteOffen: !document.getElementById("karte")?.hidden, + })); + ok(nachher.gedrueckt.filter((w) => w === "true").length === 1, + `genau eine ist gewaehlt (${nachher.gedrueckt.join(", ")})`); + ok(nachher.wer === "Diene", `und zwar die angeklickte (${nachher.wer})`); + ok(nachher.karteOffen, "ihre Karte steht offen"); + + /* UND DIE AUSWAHL WANDERT, statt sich zu sammeln. */ + await seite.click("#personen .e-person:nth-of-type(1)"); + await seite.waitForTimeout(900); + const um = await seite.evaluate(() => + document.querySelector('#personen .e-person[aria-pressed="true"] .e-person__name') + ?.textContent || ""); + const wieViele = await seite.evaluate(() => + document.querySelectorAll('#personen .e-person[aria-pressed="true"]').length); + ok(um === "VanVan" && wieViele === 1, + `ein Klick weiter ist nur noch sie gewaehlt (${um}, ${wieViele} gewaehlt)`); + } + + /* ===================================================================== + 4. NICHTS KAPUTT + ===================================================================== */ + melde(""); + melde("=== 4. Die Konsole ==="); + ok(konsole.length === 0, + konsole.length ? `Fehler in der Konsole: ${konsole[0]}` : "keine Fehler in der Konsole"); + + if (process.env.SCHIRM) { + const pfad = fileURLToPath(new URL("pruef-entwicklung-kacheln.png", import.meta.url)); + await seite.screenshot({ path: pfad, fullPage: false }); + melde(" -- Bildschirmfoto: server/pruef-entwicklung-kacheln.png"); + } + await kontext.close(); +} finally { + await browser.close(); +} + +melde(""); +melde(`${geprueft} Pruefungen, ${fehler} Fehler`); +melde(fehler ? "NICHT IN ORDNUNG" : "ALLES IN ORDNUNG"); +try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Aufraeumrest */ } +process.exit(fehler ? 1 : 0); diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 65ae51fb..2038374c 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609170226", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609170241", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609170226", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609170241", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609170226", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609170241", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609170226", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609170241", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/css/entwicklung.css b/workspace/assets/css/entwicklung.css index ed293405..89d7dc8d 100644 --- a/workspace/assets/css/entwicklung.css +++ b/workspace/assets/css/entwicklung.css @@ -68,7 +68,10 @@ .e-person { display: flex; flex-direction: column; gap: 3px; - min-width: 210px; flex: 1 1 210px; + /* Seit die drei Bilanz-Kaesten darin stehen, braucht die Kachel + mehr Grundbreite -- bei 210px wurde jeder Kasten einzeilig + gequetscht und die Ziffer rutschte unter ihr Wort. */ + min-width: 260px; flex: 1 1 300px; padding: 13px 15px; text-align: left; cursor: pointer; font: inherit; background: color-mix(in srgb, var(--tinte) 94%, #ffffff 6%); @@ -85,7 +88,44 @@ /* Die Abweichung ist das Ergebnis dieser Seite — sie darf als Einzige auffallen. */ .e-person__zahl--wichtig { color: var(--text); font-weight: 620; } -.e-person__zahl--alt { color: var(--text-still); } +.e-person__zahl--alt { color: var(--text-still); margin-top: 8px; } + +/* --------------------------------------------------------------------- + DIE DREI ZAHLEN AUF DER KACHEL (17.09.2026) + + Filipe, mit zwei Bildschirmfotos nebeneinander: „wieso ist diese seite + noch nicht im stil und perfektioniert wie die auf screen2". Der + Unterschied lag an den Zahlen: hier graue Textzeilen, drüben die + abgesetzten Kästen mit großer Ziffer. + + `.bilanz-zahl` kommt aus start.css und wird hier nur gesetzt — nicht + nachgebaut. Ein zweites Aussehen für dieselbe Sache läuft auseinander, + sobald jemand eins davon anfasst. + + AUTO-FIT STATT DREI SPALTEN: Auf dem Handy ist eine Kachel schmal, + am Rechner breit. `minmax` bricht genau dann um, wenn der Platz nicht + reicht — eine feste Spaltenzahl wäre wieder eine Rechnung von gestern. + ------------------------------------------------------------------- */ +.e-person__bilanz { + display: grid; gap: 8px; margin-top: 10px; + grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); +} +/* Die Kästen sitzen in einem Knopf und dürfen ihn nicht abfangen — + sonst trifft ein Tippen auf die Zahl die Kachel nicht. */ +.e-person__bilanz .bilanz-zahl { pointer-events: none; padding: 9px 11px; } +.e-person__bilanz .bilanz-zahl__n { font-size: 1.35rem; } +.e-person__bilanz .bilanz-zahl__text { font-size: .74rem; } + +/* WEN HABE ICH GERADE OFFEN? Vorher sah die Kachel nach dem Klick aus + wie vorher; wer scrollte, verlor den Faden. Gedämpft hell statt + grell — die Karte darunter ist die Hauptsache, die Kachel sagt nur, + wozu sie gehört. */ +.e-person[aria-pressed="true"] { + border-color: color-mix(in srgb, var(--akzent) 58%, transparent); + background: + linear-gradient(180deg, color-mix(in srgb, var(--akzent) 11%, transparent), transparent 62%), + color-mix(in srgb, var(--tinte) 90%, #ffffff 10%); +} /* --------------------------------------------------------------------- Die Karte diff --git a/workspace/assets/js/entwicklung.js b/workspace/assets/js/entwicklung.js index 37f76d03..9f360cc0 100644 --- a/workspace/assets/js/entwicklung.js +++ b/workspace/assets/js/entwicklung.js @@ -99,7 +99,14 @@ const kopf = document.querySelector('#karte .e-karte__stand'); if (kopf) kopf.textContent = satz; const kachel = personZahlen.get(letzteKarte.id); - if (kachel) kachel.textContent = satz; + if (kachel) { + /* Zwei Ziffern statt eines Satzes -- und der Ton wechselt auf + gruen, sobald nichts mehr offen ist. Ohne das bliebe eine + fertig angesehene Person blaugrau wie eine halbe. */ + kachel.angesehen.textContent = String(gesetzt); + kachel.offen.textContent = String(Math.max(0, r.gesamt - gesetzt)); + kachel.kasten.dataset.stufe = gesetzt >= r.gesamt ? 'gut' : 'offen'; + } /* Und die Köpfe der Kategorien -- sonst steht zugeklappt „0 / 7“ über sieben beantworteten Fragen. */ @@ -164,35 +171,65 @@ } /* ---- Die Personen --------------------------------------------------- */ + /* EIN BILANZ-KASTEN, wie ihn die Checkliste benutzt (17.09.2026). + + Filipe, mit zwei Bildschirmfotos nebeneinander: "wieso ist diese + seite noch nicht im stil und perfektioniert wie die auf screen2". + + Der Unterschied war nicht der Aufbau -- der stimmte -- sondern die + Zahlen: Hier standen sie als graue Textzeilen, drueben als + abgesetzte Kaesten mit grosser Ziffer und eigenem Ton. Zwei + Bretter, die dasselbe tun und verschieden aussehen, wirken wie + zwei verschiedene Sachen. + + `bilanz-zahl` steht in start.css und gehoert damit dem ganzen Haus, + nicht der Checkliste. Nachbauen waere eine zweite Wahrheit ueber + dasselbe Aussehen gewesen. */ + function bilanzZahl(n, text, stufe, hinweis) { + const kasten = el('div', 'bilanz-zahl'); + kasten.dataset.stufe = stufe; + if (hinweis) kasten.title = hinweis; + const ziffer = el('span', 'bilanz-zahl__n', String(n)); + kasten.append(ziffer); + kasten.append(el('span', 'bilanz-zahl__text', text)); + return { kasten, ziffer }; + } + function personKarte(p, lage) { const k = el('button', 'e-person'); k.type = 'button'; + /* JEDE PERSON IST EINZELN WAEHLBAR -- UND MAN SIEHT ES. + Vorher war die Kachel ein Knopf ohne Zustand: Man klickte jemanden + an, die Karte ging auf, und die Kachel sah aus wie vorher. Wer + dann scrollte, wusste nicht mehr, wen er offen hat. */ + k.setAttribute('aria-pressed', 'false'); + k.dataset.person = String(p.id); k.append(el('span', 'e-person__name', p.name)); k.append(el('span', 'e-person__rolle', p.rolle_name)); - const zahlen = el('span', 'e-person__zahlen'); - const wieViele = el('span', 'e-person__zahl', - `${p.gesetzt} von ${lage.gesamt_fremd} angesehen`); - /* Die Kachel merkt sich ihr Zahlenfeld -- daran zieht - zaehlerNachziehen() sie nach, ohne die Liste neu zu holen. */ - personZahlen.set(p.id, wieViele); - zahlen.append(wieViele); - /* DIE ABWEICHUNG STEHT VORNE UND NICHT IM DETAIL. Sie ist das - Ergebnis dieser Seite: Wo zwei Leute dasselbe sehen, gibt es + const gesamt = Number(lage.gesamt_fremd) || 0; + const gesetzt = Number(p.gesetzt) || 0; + const zahlen = el('div', 'e-person__bilanz'); + /* DIESELBEN DREI WIE DRUEBEN, und die ersten beiden teilen dasselbe + Ganze: angesehen + noch offen = alle Punkte. Die dritte ist das + Ergebnis dieser Seite -- wo zwei Leute dasselbe sehen, gibt es nichts zu besprechen. */ - if (p.abweichungen) { - const z = el('span', 'e-person__zahl e-person__zahl--wichtig', - `${p.abweichungen} × verschieden gesehen`); - z.title = 'Hier lohnt das Gespräch – nicht dort, wo ihr einig seid.'; - zahlen.append(z); - } + const a = bilanzZahl(gesetzt, 'angesehen', + gesamt && gesetzt >= gesamt ? 'gut' : 'offen'); + const o = bilanzZahl(Math.max(0, gesamt - gesetzt), 'noch offen', 'offen'); + const v = bilanzZahl(Number(p.abweichungen) || 0, 'verschieden gesehen', + 'verbessern', 'Hier lohnt das Gespräch – nicht dort, wo ihr einig seid.'); + zahlen.append(a.kasten, o.kasten, v.kasten); + /* Die Kachel merkt sich ihre Ziffern -- daran zieht + zaehlerNachziehen() sie nach, ohne die Liste neu zu holen. */ + personZahlen.set(p.id, { angesehen: a.ziffer, offen: o.ziffer, kasten: a.kasten }); + k.append(zahlen); if (p.veraltet) { const z = el('span', 'e-person__zahl e-person__zahl--alt', `${p.veraltet} älter als ${lage.verblasst_nach} Tage`); z.title = 'Eine alte Einschätzung ist keine Einschätzung mehr.'; - zahlen.append(z); + k.append(z); } - k.append(zahlen); /* NUR HIER WIRD GESPRUNGEN: Wer eine Person anklickt, will zu ihrer Karte. Überall sonst bleibt die Seite stehen, wo sie steht. */ k.addEventListener('click', () => karte(p.id, true)); @@ -220,6 +257,13 @@ alles darunter weg. */ async function karte(id, springen = false) { offen = id; + /* WER IST GERADE OFFEN? Die Antwort gehoert auf die Kacheln, nicht + nur in eine Variable. `aria-pressed` sagt es zugleich einem + Vorleseprogramm -- eine Umrandung allein kann das nicht. */ + for (const kachel of document.querySelectorAll('#personen .e-person')) { + kachel.setAttribute('aria-pressed', + kachel.dataset.person === String(id) ? 'true' : 'false'); + } const ziel = $('karte'); const vorherY = window.scrollY; ziel.hidden = false; diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index f59e20f0..c2803481 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - + @@ -282,10 +282,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index 606cc01f..a184ec09 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -168,10 +168,10 @@ - - - - - + + + + + diff --git a/workspace/befinden.html b/workspace/befinden.html index f6c004fe..201259fe 100644 --- a/workspace/befinden.html +++ b/workspace/befinden.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -105,9 +105,9 @@ - - - - + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 8c109af7..85acfaa4 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -181,14 +181,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 4361a17b..ca61d471 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 0d4989eb..32b51899 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,10 +341,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index 07e766f2..65589591 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index 8cf884d4..26e18ad7 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -339,6 +339,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index 7c6b5bc3..1eb99c70 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609170226", + "src": "/assets/img/app-symbole/crew-192.png?v=202609170241", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609170226", + "src": "/assets/img/app-symbole/crew-512.png?v=202609170241", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609170226", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609170241", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609170226", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609170241", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index c462efc7..6665e836 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index 4d8da6bc..3628505d 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -67,7 +67,7 @@ @@ -102,9 +102,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index 89d6d6a6..7af99ca2 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 90ae37b5..7ba09d55 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index a12a807f..d74e6ba8 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -444,10 +444,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index 29704a35..02158f66 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index 42982555..f3f8434d 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index 95d6b605..4ccfdea7 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ 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. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index 4ad30399..7ab9bbe3 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index cae27e82..1017869d 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index 383463e5..35635c71 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -674,10 +674,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 215a4089..4ca54d31 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 3dd94b09..312efc55 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -146,11 +146,11 @@ - - - - - - + + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index b8cf18d5..89b3cb6f 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -94,9 +94,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index f01ec918..aee10061 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index 6260e97f..7b5c8bfe 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index 2f10b351..31b1af30 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -110,9 +110,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index 047088a5..755809cb 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -211,10 +211,10 @@ 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. --> - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index 3745424c..974cbde2 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index ca703a17..0f49becc 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +