Personenkachel: Rollenfarben, kein Leerband, dunklerer Grund

Filipe, mit Bildschirmfoto: "mach die ganze kachel perfekter
detailliert schoenes. der hintergrund soll auch bissl dunkler sein von
der kachel."

--- 29 PIXEL NICHTS, FUENFMAL UNTEREINANDER ---

Auf dem Bild stand unter jeder zugeklappten Rolle ein leerer Streifen.
Nachgemessen: Abschnitt 74 px, Zeile darin 45 -- 29 px Leerraum.

Sie kamen aus ZWEI Quellen, und nur eine stand in personen.css:
padding-bottom: 14px am Abschnitt, plus margin-bottom: 14px an
.gruppe__kopf aus start.css Zeile 765. Letzteres ist fuer die
freistehenden Abschnitte der STARTSEITE geschrieben, wo unter der
Ueberschrift wirklich gleich Karten kommen. Zugeklappt kommt hier aber
nichts, und dann ist der Abstand Abstand zu nichts.

Beide haengen jetzt am Zustand: offen -> Luft, zu -> keine. Die Kachel
ist damit 383 px hoch statt 293 -- pardon, 293 statt 383.

--- DIE ROLLEN HABEN FARBEN, NUR HIER NICHT ---

Fuenf Zeilen sahen fuenfmal gleich aus. Das Haus fuehrt fuer jede Rolle
eine Farbe (Anmeldeseite, Marken, Bereiche); ausgerechnet in der Liste,
in der es NUR um Rollen geht, hoerten sie auf.

Jeder Abschnitt traegt jetzt `data-rolle`, setzt daraus EIN --r, und
alles Weitere liest davon: der Streifen links, die Anzahl, die
Namenszeichen, der Pfeil, das Licht beim Aufklappen. Und `--ton`, die
Variable, aus der module.css das Kantenlicht jeder Kachel zieht -- die
Personenkarten in einem Manager-Abschnitt sind damit lila statt orange.
Eine Zeile, und der Abschnitt wird ein Stueck.

NEU: WER DRINSTEHT, OHNE AUFZUKLAPPEN. Vier Namenszeichen, ab dem
fuenften "+n". Zugeklappt sagte die Zeile bisher nur, WIE VIELE es
sind; wer wissen wollte, ob Patrick dabei ist, musste aufklappen.

--- DER STREIFEN, DEN getComputedStyle NICHT SIEHT ---

Erster Anlauf: 3 px breit, left: 0, volle Hoehe. Im Bild war nichts.
getComputedStyle meldete trotzdem "3 px, sichtbar, Deckkraft 0,55".

Der Grund steht in module.css: Jede Kachel traegt auf ::before ein
Kantenlicht mit inset: 0 und z-index: 2 -- eine 1,6 px breite Linie
UEBER allen Kindern. Vom Streifen blieben 1,4 px, und die lagen genau
in der Kante. Er sitzt jetzt bei 3 px, gerundet, mit Luft oben und
unten.

Die Pruefung misst ihn deshalb an echten BILDPUNKTEN, und zwar
dieselbe Stelle zweimal: einmal wie sie ist, einmal mit
ausgeschaltetem Streifen. Was sich aendert, IST der Streifen -- und was
sich nicht aendert, ist die Gegenprobe, ohne dass man sie erfinden
muss.

--- UND EINE PRUEFUNG, DIE GRUEN GELOGEN HAT ---

Die Kontrastmessung las die Textfarbe mit
`getComputedStyle(e).color.match(/\d+/g)`. Das geht, solange dort
"rgb(148, 165, 187)" steht. Alle neuen Stellen kommen aus color-mix(),
und Chromium antwortet darauf mit "color(srgb 0.36 0.51 0.42)". Aus
dem Muster fielen "0", "510588", "0" -- die Pruefung meldete
775929299:1 und war gruen.

Die Farbe wird jetzt in ein Canvas GEMALT und als Punkt zurueckgelesen;
das versteht jede Schreibweise, die der Browser versteht. Davor steht
eine Gegenprobe mit zwei bekannten Farben: Stimmt das Messgeraet nicht,
ist alles darunter wertlos. Echte Werte jetzt: 7,95 bis 15,71:1.

--- AM HANDY STAND DER PFEIL IN EINER DRITTEN ZEILE ---

Der Zusatztext bekommt dort eine eigene Rasterzeile -- richtig, er
passt sonst nicht. Der Pfeil bekam dadurch eine dritte und stand mittig
unter dem Text wie ein vergessenes Zeichen: 106 px je Rolle. Er hat
jetzt eine eigene Spalte und ueberspannt beide Zeilen: 75 px, und er
steht da, wo die Hand ihn sucht.

--- Pruefung ---

server/pruef-personen-kachel.mjs, neu, 43 Pruefungen, alle gruen.
Ausserdem gruen: pruef-personen-liste, pruef-css-klassen (die hat die
Namenszeichen bei 10,56 px erwischt, bevor sie jemand lesen musste).
Angesehen bei 1440 px und 390 px, zu und offen.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-09 13:37:28 +02:00
co-authored by Claude Opus 5
parent 14e9bbf7a5
commit d5570ee501
22 changed files with 986 additions and 203 deletions
+505
View File
@@ -0,0 +1,505 @@
/* DIE PERSONENKACHEL — Aufbau, Farben, Kontrast (09.09.2026)
Filipe, mit Bildschirmfoto: "mach die ganze kachel perfekter
detailliert schönes. der hintergrund soll auch bissl dunkler sein
von der kachel."
Auf seinem Bild stand unter jeder zugeklappten Rolle ein leerer
Streifen, und die fünf Zeilen sahen fünfmal gleich aus. Gemessen
waren es 29 px Nichts je Zeile, fünfmal untereinander.
WAS HIER GEMESSEN WIRD UND WARUM SO:
Der Rollenstreifen wird an ECHTEN BILDPUNKTEN geprüft, nicht am
Stylesheet. Der Grund steht im Code: Im ersten Anlauf sagte
getComputedStyle "3 px breit, sichtbar, Deckkraft 0,55" -- und zu
sehen war nichts, weil das Kantenlicht der Kachel (module.css,
z-index 2) genau darüber lag. Eine Prüfung, die den berechneten Stil
liest, hätte grün gemeldet.
Der dunklere Grund wird als Helligkeit gemessen UND gegen die Karten
darin gehalten: Eine Vitrine ist dunkler als das, was darin steht.
Eine feste Zahl allein wäre eine Rechnung von gestern.
DREI AUSGÄNGE: 0 in Ordnung · 1 Befunde · 2 konnte nicht arbeiten. */
import { mkdtempSync, rmSync, appendFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-perskachel-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
import { notbremse } from "./helfer-notbremse.mjs";
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4329, "die Personenkachel-Pruefung");
process.env.PORT = "4329";
process.env.SITE_ACCESS_SECRET = "lokaler-test";
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 }); };
await import("./index.js");
notbremse(420_000, "pruef-personen-kachel");
await new Promise((r) => setTimeout(r, 900));
const BASIS = "http://127.0.0.1:4329";
const PROTOKOLL = join(process.cwd(), "pruef-personen-kachel-lauf.txt");
try { rmSync(PROTOKOLL, { force: true }); } catch { /* gab es noch nicht */ }
const melde = (z) => { console.log(z); try { appendFileSync(PROTOKOLL, z + "\n"); } catch { /* Zugabe */ } };
let fehler = 0, geprueft = 0;
const ok = (b, t) => { geprueft++; melde((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
/* ---- Bestand ------------------------------------------------------------ */
await fetch(BASIS + "/workspace/api/anmelden", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ rolle: "admin", code: "x" }) }).catch(() => {});
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
for (let i = 0; i < 60; i++) {
try {
const p = new DatabaseSync(process.env.WORKSPACE_DB);
try { p.prepare("SELECT 1 FROM personen LIMIT 1").get(); break; } finally { p.close(); }
} catch { await new Promise((r) => setTimeout(r, 250)); }
}
const d = new DatabaseSync(process.env.WORKSPACE_DB);
const jetzt = new Date().toISOString();
function anlegen(name, rolle, code, aktiv = 1) {
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, aktiv, erstellt) VALUES (?,?,?,?,?,?,?)")
.run(name, rolle, hash, salt, 32768, aktiv, jetzt);
}
anlegen("Dogfather", "admin", "CODE-DOGI-0001");
anlegen("Spicy Media", "spicy", "CODE-SPIC-0001");
anlegen("Modis", "manager", "CODE-MODI-0001");
anlegen("BanaStift", "manager", "CODE-BSTF-0001", 0);
anlegen("BananaStift", "scout", "CODE-BANA-0001");
anlegen("Patrick", "scout", "CODE-PATR-0001");
/* SECHS Creator -- damit die Namenszeichen wirklich abgeschnitten
werden. Mit vier waere der "+n"-Fall nie geprueft. */
for (const n of ["Tili", "SpongBob", "Luna", "Mika", "Noa", "Robin"]) {
anlegen(n, "creator", "CODE-" + n.slice(0, 4).toUpperCase().padEnd(4, "X") + "-0001");
}
d.close();
const { chromium } = await import(
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
const browser = await chromium.launch();
const konsole = [];
async function alsDogi(breite = 1440) {
const ctx = await browser.newContext({ viewport: { width: breite, height: 1100 } });
const s = await ctx.newPage();
s.on("pageerror", (f) => konsole.push("Absturz: " + f.message));
s.on("console", (m) => { if (m.type() === "error") konsole.push("Konsole: " + m.text()); });
await s.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
await s.click('.rolle[data-rolle="admin"]');
await s.fill("#code", "CODE-DOGI-0001");
await s.click("button[type=submit]");
await s.waitForURL("**/start.html", { timeout: 20000 });
await s.evaluate(() => localStorage.setItem("dfw_personen_offen", "[]"));
await s.goto(BASIS + "/workspace/personen.html", { waitUntil: "networkidle" });
await s.waitForSelector(".gruppe", { timeout: 10000 });
await s.waitForTimeout(700);
return { ctx, s };
}
const gross = await alsDogi();
const seite = gross.s;
/* Punkte aus einem Bildschirmfoto lesen -- derselbe Weg wie in
pruef-lesbarkeit: das Bild in ein Canvas, dort jeden Punkt. */
async function mittelFarbe(clip) {
const bild = await seite.screenshot({ clip });
return seite.evaluate(async (b64) => {
const bild = new Image();
await new Promise((r) => { bild.onload = r; bild.src = "data:image/png;base64," + b64; });
const c = document.createElement("canvas");
c.width = bild.width; c.height = bild.height;
const g = c.getContext("2d", { willReadFrequently: true });
g.drawImage(bild, 0, 0);
const dd = g.getImageData(0, 0, c.width, c.height).data;
let r = 0, gr = 0, bl = 0, n = 0;
for (let i = 0; i < dd.length; i += 4) { r += dd[i]; gr += dd[i + 1]; bl += dd[i + 2]; n++; }
return [Math.round(r / n), Math.round(gr / n), Math.round(bl / n)];
}, bild.toString("base64"));
}
const leuchtkraft = ([r, g, b]) => {
const f = (w) => { const v = w / 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); };
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
};
const kontrast = (a, b) => {
const l1 = leuchtkraft(a), l2 = leuchtkraft(b);
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
};
/* =======================================================================
1. AUFBAU: fünf Rollen, jede mit ihrem Merkmal
======================================================================= */
melde("\n=== 1. Aufbau ===");
{
const g = await seite.$$eval(".liste-kachel > .gruppe", (b) => b.map((x) => ({
rolle: x.dataset.rolle, auf: x.dataset.auf,
name: x.querySelector(".gruppe__name")?.textContent,
zahl: x.querySelector(".gruppe__zahl")?.textContent,
})));
ok(g.length === 5, `fünf Rollenabschnitte (${g.length})`);
ok(g.every((x) => x.rolle), `jeder trägt seine Rolle (${g.map((x) => x.rolle).join(", ")})`);
ok(g.every((x) => x.auf === "ja" || x.auf === "nein"),
"und seinen Zustand als Merkmal — nicht nur im aria-expanded");
/* GEGENPROBE: Zustand am Merkmal und im aria-expanded müssen
dasselbe sagen. Zwei Wahrheiten wären schlimmer als eine. */
const einig = await seite.$$eval(".liste-kachel > .gruppe", (b) => b.every((x) =>
(x.dataset.auf === "ja") === (x.querySelector(".gruppe__kopf").getAttribute("aria-expanded") === "true")));
ok(einig, "Merkmal und aria-expanded stimmen überein");
}
/* =======================================================================
2. KEIN LEERES BAND MEHR
Das war der sichtbare Mangel auf Filipes Bild: 74 px Abschnitt,
45 px Zeile, 29 px Nichts.
======================================================================= */
melde("\n=== 2. Kein leeres Band ===");
{
const zu = await seite.$$eval('.liste-kachel > .gruppe[data-auf="nein"]', (b) => b.map((x) => {
const r = x.getBoundingClientRect();
const k = x.querySelector(".gruppe__kopf").getBoundingClientRect();
return { name: x.dataset.rolle, rest: Math.round(r.height - k.height), hoehe: Math.round(r.height) };
}));
ok(zu.length >= 4, `${zu.length} zugeklappte Abschnitte zum Messen`);
const schlimm = zu.filter((x) => x.rest > 3);
ok(schlimm.length === 0,
schlimm.length ? `leeres Band unter: ${schlimm.map((x) => `${x.name} ${x.rest} px`).join(", ")}`
: `unter keiner zugeklappten Zeile steht Leerraum (höchstens ${Math.max(...zu.map((x) => x.rest))} px)`);
ok(zu.every((x) => x.hoehe >= 46 && x.hoehe <= 66),
`die Zeilen sind gleich hoch und gut greifbar (${zu.map((x) => x.hoehe).join("/")} px)`);
/* GEGENPROBE: Ein OFFENER Abschnitt braucht Luft -- sonst hätte ich
das eine Übel gegen das andere getauscht. */
await seite.click('.gruppe[data-rolle="manager"] .gruppe__kopf');
await seite.waitForTimeout(400);
const auf = await seite.$eval('.gruppe[data-rolle="manager"]', (x) => {
const r = x.getBoundingClientRect();
const k = x.querySelector(".gruppe__kopf").getBoundingClientRect();
return { rest: Math.round(r.height - k.height), personen: x.querySelectorAll(".person").length };
});
ok(auf.personen === 2 && auf.rest > 100,
`offen stehen die Karten mit Abstand da (${auf.personen} Karten, ${auf.rest} px)`);
}
/* =======================================================================
3. DER ROLLENSTREIFEN — an echten Bildpunkten
getComputedStyle hilft hier nicht: Beim ersten Anlauf meldete es
tadellose Werte für einen Streifen, den das Kantenlicht der Kachel
vollständig verdeckte.
======================================================================= */
melde("\n=== 3. Der Rollenstreifen ===");
{
/* Erwartet wird der KANAL, der bei dieser Rollenfarbe führt --
nicht ein genauer Wert. Ein genauer Wert wäre eine Rechnung von
gestern: Sobald jemand die Rollenfarbe leicht verschiebt, wäre die
Prüfung rot, ohne dass etwas kaputt ist. */
const ERWARTET = {
spicy: "r", // #ef5f57
admin: "b", // #9ed3f4
manager: "b", // #8a76ff
scout: "g", // #5fc99a
creator: "r", // #c79a6d
};
/* DIESELBE STELLE, EINMAL MIT UND EINMAL OHNE STREIFEN.
Der erste Anlauf verglich den Streifen mit einem Punkt 40 px weiter
rechts -- und traf dort die Schrift. Der Unterschied war riesig und
sagte nichts über den Streifen. Zwei Stellen sind eben zwei
Stellen; es gibt keinen Grund, warum sie gleich aussehen sollten.
Richtig ist der Vergleich DERSELBEN Stelle mit sich selbst: einmal
wie sie ist, einmal mit ausgeschaltetem Streifen. Was sich dabei
ändert, IST der Streifen -- und was sich nicht ändert, ist die
Gegenprobe, ohne dass man sie eigens erfinden müsste. */
const AUS = "personen-kachel-probe";
const streifenAus = async (an) => seite.evaluate(([id, an]) => {
let s = document.getElementById(id);
if (!s) { s = document.createElement("style"); s.id = id; document.head.append(s); }
s.textContent = an ? ".liste-kachel > .gruppe::after { opacity: 0 !important; }" : "";
}, [AUS, an]);
const stellen = {};
for (const rolle of Object.keys(ERWARTET)) {
stellen[rolle] = await seite.$eval(`.gruppe[data-rolle="${rolle}"]`, (x) => {
const r = x.getBoundingClientRect();
return { x: Math.round(r.x) + 3, y: Math.round(r.y) + 18, width: 3, height: 10 };
});
}
const mit = {};
for (const [rolle, clip] of Object.entries(stellen)) mit[rolle] = await mittelFarbe(clip);
await streifenAus(true);
await seite.waitForTimeout(200);
const ohne = {};
for (const [rolle, clip] of Object.entries(stellen)) ohne[rolle] = await mittelFarbe(clip);
await streifenAus(false);
await seite.waitForTimeout(200);
const nochmal = await mittelFarbe(stellen.scout);
for (const [rolle, kanal] of Object.entries(ERWARTET)) {
const [r, g, b] = mit[rolle];
const o = ohne[rolle];
/* Welcher Kanal hat durch den Streifen am meisten GEWONNEN? Der
absolute Wert allein wäre irreführend: Auf einem bläulichen Grund
führt Blau auch dann, wenn der Streifen rot ist. */
const zu = [r - o[0], g - o[1], b - o[2]];
const fuehrt = zu[0] >= zu[1] && zu[0] >= zu[2] ? "r"
: zu[1] >= zu[0] && zu[1] >= zu[2] ? "g" : "b";
const abstand = zu.reduce((s, x) => s + Math.abs(x), 0);
ok(abstand > 25 && fuehrt === kanal,
`${rolle}: mit rgb(${mit[rolle]}) / ohne rgb(${o}) — Zuwachs ${JSON.stringify(zu)}, führend ${fuehrt}`);
}
/* GEGENPROBE: Ausgeschaltet und wieder eingeschaltet muss dieselbe
Stelle wieder aussehen wie am Anfang. Täte sie das nicht, hätte die
Messung etwas anderes gemessen als den Streifen. */
const zurueck = nochmal.reduce((s, x, i) => s + Math.abs(x - mit.scout[i]), 0);
ok(zurueck <= 6, `nach dem Wiedereinschalten sieht es aus wie vorher (Abweichung ${zurueck})`);
}
/* =======================================================================
4. DIE KACHEL IST DUNKLER — UND DUNKLER ALS IHR INHALT
======================================================================= */
melde("\n=== 4. Der Grund ===");
{
const lage = await seite.$eval('.gruppe[data-rolle="scout"]', (x) => {
const r = x.getBoundingClientRect();
return { x: Math.round(r.x), y: Math.round(r.y) };
});
const kachel = await mittelFarbe({ x: lage.x + 300, y: lage.y + 6, width: 120, height: 12 });
const hell = Math.round(leuchtkraft(kachel) * 1000) / 10;
ok(hell < 2.0, `der Kachelgrund ist dunkel (rgb(${kachel}), Leuchtkraft ${hell} %)`);
/* Die Vitrine muss dunkler sein als das, was darin steht -- sonst
sieht man die Vitrine statt des Inhalts. Manager ist offen. */
const karte = await seite.$eval('.gruppe[data-rolle="manager"] .person', (x) => {
const r = x.getBoundingClientRect();
return { x: Math.round(r.x) + 200, y: Math.round(r.y) + 6 };
});
const kartenFarbe = await mittelFarbe({ x: karte.x, y: karte.y, width: 120, height: 10 });
ok(leuchtkraft(kartenFarbe) > leuchtkraft(kachel),
`die Karten darin sind heller als die Kachel (Karte rgb(${kartenFarbe}) gegen Kachel rgb(${kachel}))`);
}
/* =======================================================================
5. LESBARKEIT — jede neue Textstelle gemessen
======================================================================= */
melde("\n=== 5. Lesbarkeit ===");
{
async function messen(waehler) {
const stelle = await seite.evaluate((w) => {
const e = document.querySelector(w);
if (!e) return null;
e.scrollIntoView({ block: "center" });
const r = e.getBoundingClientRect();
if (r.width < 8 || r.height < 6) return null;
/* DIE FARBE WIRD GEZEICHNET, NICHT GELESEN.
------------------------------------------------------------------
Hier stand `.color.match(/\d+/g).slice(0,3)`. Das geht gut,
solange getComputedStyle "rgb(148, 165, 187)" liefert. Sobald
eine Farbe aus `color-mix()` kommt -- und genau das tun hier
alle neuen Stellen --, antwortet Chromium mit
"color(srgb 0.36 0.51 0.42)". Aus dem Muster fielen dann die
Ziffernfolgen "0", "510588", "0" heraus, und die Prüfung meldete
775929299:1. Grün, und vollkommen wertlos.
Ein Canvas nimmt JEDE Schreibweise entgegen, die der Browser
versteht, und gibt drei Zahlen von 0 bis 255 zurück. Was der
Browser malt, ist per Definition das, was man sieht. */
const c = document.createElement("canvas");
c.width = 1; c.height = 1;
const gg = c.getContext("2d", { willReadFrequently: true });
gg.fillStyle = "#000000";
gg.fillStyle = getComputedStyle(e).color;
gg.fillRect(0, 0, 1, 1);
const px = gg.getImageData(0, 0, 1, 1).data;
const farbe = [px[0], px[1], px[2]];
e.dataset.messen = "ja";
e.style.color = "transparent";
return { x: Math.round(r.x), y: Math.round(r.y),
w: Math.round(r.width), h: Math.round(Math.min(r.height, 40)), farbe };
}, waehler);
if (!stelle) return null;
const hinten = await mittelFarbe({ x: stelle.x, y: stelle.y, width: stelle.w, height: stelle.h });
await seite.evaluate(() => {
const e = document.querySelector('[data-messen="ja"]');
if (e) { e.style.color = ""; delete e.dataset.messen; }
});
return { farbe: stelle.farbe, hinten, wert: kontrast(stelle.farbe, hinten) };
}
/* GEGENPROBE ZUM MESSGERÄT, VOR DER ERSTEN MESSUNG.
Der Umweg über das Canvas ist neu, weil der alte Weg falsche Zahlen
lieferte. Bevor ich ihm glaube: zwei Farben mit bekanntem Ergebnis
hindurchschicken -- eine in gewöhnlicher Schreibweise, eine aus
color-mix(). Kommt dabei nicht heraus, was herauskommen muss, ist
die ganze Lesbarkeitsprüfung darunter wertlos. */
{
const probe = await seite.evaluate(() => {
const c = document.createElement("canvas");
c.width = 1; c.height = 1;
const g = c.getContext("2d", { willReadFrequently: true });
const lies = (farbe) => {
g.fillStyle = "#000000";
g.fillStyle = farbe;
g.fillRect(0, 0, 1, 1);
const p = g.getImageData(0, 0, 1, 1).data;
return [p[0], p[1], p[2]];
};
return { klar: lies("rgb(148, 165, 187)"),
gemischt: lies("color-mix(in srgb, #ffffff 50%, #000000)") };
});
const nah = (a, b) => a.every((x, i) => Math.abs(x - b[i]) <= 3);
ok(nah(probe.klar, [148, 165, 187]) && nah(probe.gemischt, [128, 128, 128]),
`das Messgerät stimmt: rgb-Schreibweise ${probe.klar}, color-mix ${probe.gemischt}`);
}
for (const [name, waehler] of [
["Rollenname", '.gruppe[data-rolle="scout"] .gruppe__name'],
["Zusatztext", '.gruppe[data-rolle="scout"] .gruppe__unter'],
["Anzahl", '.gruppe[data-rolle="scout"] .gruppe__zahl'],
["Namenszeichen", '.gruppe[data-rolle="scout"] .gruppe__kopf-zeichen'],
["Namenszeichen (Creator, hellste Rolle)", '.gruppe[data-rolle="creator"] .gruppe__kopf-zeichen'],
["Anzahl (Creator)", '.gruppe[data-rolle="creator"] .gruppe__zahl'],
["Name offen", '.gruppe[data-rolle="manager"] .gruppe__name'],
]) {
const m = await messen(waehler);
ok(m !== null && m.wert >= 4.5,
`${name}: ${m ? m.wert.toFixed(2) + ":1 (" + m.farbe.join(",") + " auf " + m.hinten.join(",") + ")" : "nicht gefunden"}`);
}
/* GEGENPROBE: ein absichtlich zu dunkler Text MUSS durchfallen. */
await seite.evaluate(() => {
document.querySelector('.gruppe[data-rolle="scout"] .gruppe__name').style.color = "#141a22";
});
const schlecht = await messen('.gruppe[data-rolle="scout"] .gruppe__name');
ok(schlecht !== null && schlecht.wert < 4.5,
`absichtlich zu dunkler Text fällt durch (${schlecht?.wert.toFixed(2)}:1)`);
await seite.evaluate(() => {
document.querySelector('.gruppe[data-rolle="scout"] .gruppe__name').style.color = "";
});
}
/* =======================================================================
6. WER DRINSTEHT — die Namenszeichen
======================================================================= */
melde("\n=== 6. Namenszeichen ===");
{
const creator = await seite.$eval('.gruppe[data-rolle="creator"]', (x) => ({
zahl: x.querySelector(".gruppe__zahl").textContent,
zeichen: [...x.querySelectorAll(".gruppe__kopf-zeichen")].map((z) => ({
text: z.textContent, titel: z.title, mehr: z.dataset.mehr })),
versteckt: x.querySelector(".gruppe__leute").getAttribute("aria-hidden"),
}));
ok(creator.zahl === "6", `sechs Creator sind angelegt (${creator.zahl})`);
ok(creator.zeichen.length === 5,
`vier Zeichen plus eines für den Rest (${creator.zeichen.map((z) => z.text).join(" ")})`);
ok(creator.zeichen[4]?.mehr === "ja" && creator.zeichen[4]?.text === "+2",
`das letzte sagt, wie viele fehlen ("${creator.zeichen[4]?.text}")`);
/* WELCHE zwei fehlen, hängt an der Sortierung des Servers -- die
hier abzuschreiben hiesse, sie an zwei Stellen zu pflegen. Geprüft
wird die Eigenschaft: genau zwei Namen, und keiner davon steht
schon als eigenes Zeichen davor. */
const genannt = (creator.zeichen[4]?.titel || "").split(", ").filter(Boolean);
const vorne = creator.zeichen.slice(0, 4).map((z) => z.titel);
ok(genannt.length === 2 && genannt.every((n) => !vorne.includes(n)),
`und nennt beim Darüberfahren genau die zwei, die fehlen ("${creator.zeichen[4]?.titel}")`);
ok(creator.versteckt === "true",
"für das Vorleseprogramm sind sie ausgeblendet — die Anzahl steht als Zahl daneben");
/* Zwei Wörter geben zwei Buchstaben, ein Wort nur einen. */
const spicy = await seite.$eval('.gruppe[data-rolle="spicy"] .gruppe__kopf-zeichen',
(z) => ({ text: z.textContent, titel: z.title }));
ok(spicy.text === "SM", `"Spicy Media" wird SM (${spicy.text})`);
const scout = await seite.$$eval('.gruppe[data-rolle="scout"] .gruppe__kopf-zeichen',
(b) => b.map((z) => z.textContent));
ok(scout.join("") === "BP", `"BananaStift" und "Patrick" geben B und P (${scout.join(" ")})`);
/* Gesperrt wird gekennzeichnet -- und zwar leise. */
const manager = await seite.$$eval('.gruppe[data-rolle="manager"] .gruppe__kopf-zeichen',
(b) => b.map((z) => ({ text: z.textContent, gesperrt: z.dataset.gesperrt, titel: z.title })));
const dieGesperrte = manager.find((z) => z.gesperrt === "ja");
ok(!!dieGesperrte && /gesperrt/.test(dieGesperrte.titel),
`die gesperrte Person ist gekennzeichnet ("${dieGesperrte?.titel}")`);
ok(manager.filter((z) => z.gesperrt === "ja").length === 1,
"und nur sie — die aktive nicht");
}
/* =======================================================================
7. AM HANDY
======================================================================= */
melde("\n=== 7. Am Handy (390 px) ===");
{
const handy = await alsDogi(390);
const m = await handy.s.evaluate(() => {
const k = document.getElementById("liste");
const leute = document.querySelector(".gruppe__leute");
return {
ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth,
leuteSichtbar: leute ? getComputedStyle(leute).display !== "none" : null,
breiter: [...k.querySelectorAll(".gruppe__kopf")]
.filter((x) => x.getBoundingClientRect().right > 391).length,
zeilen: [...k.querySelectorAll(".gruppe__kopf")].map((x) => Math.round(x.getBoundingClientRect().height)),
};
});
ok(m.ueber <= 1, `kein seitlicher Überstand (${m.ueber} px)`);
ok(m.leuteSichtbar === false,
"die Namenszeichen treten am Handy zurück — die Zahl sagt es dort");
ok(m.breiter === 0, `keine Zeile ragt hinaus (${m.breiter})`);
ok(m.zeilen.every((h) => h >= 44), `die Zeilen bleiben greifbar (${m.zeilen.join("/")} px)`);
/* ZWEI ZEILEN, NICHT DREI.
Der Zusatztext bekommt am Handy eine eigene Zeile -- richtig, er
passt sonst nicht. Der PFEIL bekam dadurch eine dritte und stand
mittig unter dem Text wie ein vergessenes Zeichen: 106 px je Rolle,
fünfmal untereinander. Gemessen wird deshalb beides: die Höhe und
die Lage des Pfeils. */
ok(m.zeilen.every((h) => h <= 82),
`und werden nicht dreizeilig (${m.zeilen.join("/")} px)`);
const pfeil = await handy.s.evaluate(() => {
const k = document.querySelector(".gruppe__kopf");
const p = k.querySelector(".klapp-pfeil").getBoundingClientRect();
const n = k.querySelector(".gruppe__name").getBoundingClientRect();
const kr = k.getBoundingClientRect();
return { rechts: Math.round(kr.right - p.right),
mitte: Math.round((p.top + p.bottom) / 2 - (kr.top + kr.bottom) / 2),
nebenNamen: p.top < n.bottom + 4 };
});
ok(pfeil.rechts >= 0 && pfeil.rechts < 30,
`der Pfeil steht rechts (${pfeil.rechts} px vom Rand)`);
ok(Math.abs(pfeil.mitte) < 8,
`und mittig zwischen beiden Zeilen (${pfeil.mitte} px von der Mitte)`);
await handy.ctx.close();
}
/* =======================================================================
8. KEINE STILLEN FEHLER
======================================================================= */
melde("\n=== 8. Stille Fehler ===");
{
ok(konsole.length === 0, konsole.length ? "Fehler: " + konsole.slice(0, 3).join(" | ")
: "keine Skript- oder Konsolenfehler");
await seite.evaluate(() => { setTimeout(() => { throw new Error("Absicht"); }, 0); });
await seite.waitForTimeout(400);
ok(konsole.some((z) => /Absicht/.test(z)), `ein absichtlicher Fehler wird bemerkt (${konsole.length})`);
}
await gross.ctx.close();
await browser.close();
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
melde(`\n${geprueft} Prüfungen`);
melde(fehler === 0 ? "ALLES IN ORDNUNG" : `${fehler} FEHLER`);
process.exit(fehler ? 1 : 0);
+232 -11
View File
@@ -434,29 +434,56 @@ body[data-nur-lesen="ja"] select { display: none; }
Kalender. Eine Vitrine ist dunkler als das, was darin steht; sonst
sieht man die Vitrine statt des Inhalts.
===================================================================== */
/* DUNKLER, 09.09.2026. Filipe: "der hintergrund soll auch bissl
dunkler sein von der kachel."
Von rgba(9,13,20,.96) auf rgba(5,8,13,.985). Der Hintergrund schien
vorher merklich durch -- bei einem Motiv mit hellen Stellen sass
hinter der Liste mal ein dunkler, mal ein heller Fleck, und die
Kachel wirkte dadurch fleckig statt ruhig. Die Schrift wird davon
nur besser lesbar: Der Grund wird dunkler, die Farben bleiben. */
.liste-kachel {
padding: 4px 0 0;
margin-bottom: 24px;
background:
var(--raster),
linear-gradient(178deg, rgba(9, 13, 20, .96), rgba(4, 7, 12, .98));
linear-gradient(178deg, rgba(5, 8, 13, .985), rgba(2, 4, 8, .995));
}
/* Die Abschnitte werden Felder in einem Körper: keine eigenen Ränder,
keine Luft dazwischen, sondern eine Fuge. */
.liste-kachel > .gruppe {
margin: 0;
padding: 0 16px 14px;
border-bottom: 1px solid #05070c;
box-shadow: 0 1px 0 rgba(255, 255, 255, .035);
padding: 0 16px;
border-bottom: 1px solid #04060a;
box-shadow: 0 1px 0 rgba(255, 255, 255, .04);
}
.liste-kachel > .gruppe:last-child { border-bottom: 0; box-shadow: none; }
/* Der Kopf jeder Gruppe füllt die Breite der Kachel -- so ist die
ganze Zeile das Ziel, nicht nur der Text. */
/* ---------------------------------------------------------------------
DAS LEERE BAND UNTER JEDER ZEILE (gemessen, 09.09.2026)
Filipe: "mach die ganze kachel perfekter detailliert schoenes."
Auf seinem Bild stand unter jeder zugeklappten Rolle ein leerer
Streifen. Nachgemessen: Der Abschnitt war 74 px hoch, die Zeile
darin 45 -- 29 px Nichts, fuenfmal untereinander.
Sie kamen aus ZWEI Quellen, und nur eine davon stand hier:
* padding-bottom: 14px an .liste-kachel > .gruppe
* margin-bottom: 14px an .gruppe__kopf -- aus start.css, Zeile 765,
geschrieben fuer die freistehenden Abschnitte der Startseite, wo
unter der Ueberschrift wirklich gleich Karten kommen.
Zugeklappt kommt hier aber gar nichts, und dann ist der Abstand
Abstand zu nichts. Beide werden deshalb an den ZUSTAND gebunden:
offen -> Luft, zugeklappt -> keine. */
.liste-kachel > .gruppe > .gruppe__kopf {
width: calc(100% + 32px);
margin-left: -16px;
padding: 13px 16px 11px;
margin: 0 0 0 -16px;
padding: 15px 16px;
}
.liste-kachel > .gruppe[data-auf="ja"] > .gruppe__kopf { margin-bottom: 13px; }
.liste-kachel > .gruppe[data-auf="ja"] { padding-bottom: 15px; }
/* =====================================================================
DIE KOEPFE STEHEN IN SPALTEN, NICHT IN DER MITTE (screen3, 09.09.2026)
@@ -522,7 +549,201 @@ body[data-nur-lesen="ja"] select { display: none; }
.liste-kachel .gruppe__unter { grid-column: 1 / -1; }
}
/* Ein Abschnitt, der offen ist, hebt sich leicht ab -- so sieht man,
welcher gerade Platz einnimmt, ohne eine zweite Farbe. */
.liste-kachel > .gruppe:has(> .gruppe__kopf[aria-expanded="true"]) {
background: linear-gradient(180deg, rgba(255, 255, 255, .028), transparent 60%);
welcher gerade Platz einnimmt, ohne eine zweite Farbe. Der Ton kommt
aus der Rollenfarbe, ist aber so leise, dass er nicht als Farbe
auffaellt, sondern als Licht. */
.liste-kachel > .gruppe[data-auf="ja"] {
background:
linear-gradient(180deg, color-mix(in srgb, var(--r) 7%, transparent), transparent 62%);
}
/* =====================================================================
DIE KACHEL IM DETAIL (09.09.2026)
Filipe, mit Bildschirmfoto: "mach die ganze kachel perfekter
detailliert schönes. der hintergrund soll auch bissl dunkler sein
von der kachel."
Vorher waren die fünf Zeilen fünfmal dasselbe: Name, Zahl, Satz,
Pfeil, in Grau. Die Rollen haben im ganzen Haus eigene Farben --
auf der Anmeldeseite, an den Marken, in den Bereichen. Ausgerechnet
in der Liste, in der es NUR um Rollen geht, hörten sie auf.
Der Ton kommt deshalb aus derselben Quelle wie überall (--*-haupt in
gate.css) und wird an EINER Stelle je Rolle gesetzt. Alles Weitere
liest --r: Streifen, Zahl, Namenszeichen, Pfeil, das Licht beim
Aufklappen. Fünf Farbangaben je Rolle wären fünf Gelegenheiten,
dass eine nachgezogen wird und vier nicht.
AUGENSCHONEND HEISST HIER: die Farbe trägt, sie leuchtet nicht. Der
Streifen hat 3 px, die Fläche darunter höchstens 8 % Farbe. Fünf
kräftig eingefärbte Zeilen untereinander wären ein Regenbogen --
und einer, den man jeden Tag ansieht.
===================================================================== */
.liste-kachel > .gruppe { --r: var(--text-still); }
/* UND DIE KARTEN DARIN ERBEN SIE.
`--ton` ist die Variable, aus der die Modulliste (module.css) das
Kantenlicht und die Eckwinkel jeder Kachel zieht. Sie hier zu setzen
heisst: Die Personenkarten in einem Abschnitt tragen die Farbe ihrer
Rolle, nicht die allgemeine Hausfarbe. Vorher standen in einem
lila Manager-Abschnitt orange gerahmte Karten -- zwei Farben fuer
dieselbe Sache, und die aeussere hatte recht.
Eine Zeile, und der ganze Abschnitt wird ein Stueck. */
.liste-kachel > .gruppe { --ton: var(--r); }
.liste-kachel > .gruppe[data-rolle="spicy"] { --r: var(--spicy-haupt); }
.liste-kachel > .gruppe[data-rolle="admin"] { --r: var(--dogi-haupt); }
.liste-kachel > .gruppe[data-rolle="manager"] { --r: var(--manager-haupt); }
.liste-kachel > .gruppe[data-rolle="scout"] { --r: var(--scout-haupt); }
.liste-kachel > .gruppe[data-rolle="creator"] { --r: var(--creator-haupt); }
/* Der Streifen sitzt NEBEN dem Kantenlicht, nicht darunter.
Erster Anlauf: `left: 0`, volle Höhe. Im Bild war nichts zu sehen --
und die berechneten Werte sagten trotzdem "3 px breit, sichtbar,
Deckkraft 0,55". Der Grund steht in module.css: Jede Kachel trägt auf
::before ein Kantenlicht mit `inset: 0` und `z-index: 2`, also eine
1,6 px breite Linie ÜBER allen Kindern. Vom Streifen blieben 1,4 px,
und die lagen genau in der Kante.
Er beginnt deshalb bei 3 px, ist gerundet und lässt oben und unten
Luft: So liest er sich als Marke der Zeile und nicht als zweiter
Rahmen neben dem ersten. Zugeklappt reicht er über die Zeile, offen
über den ganzen Abschnitt -- man sieht am Rand, wie weit ein
geöffneter Bereich reicht. */
.liste-kachel > .gruppe { position: relative; }
.liste-kachel > .gruppe::after {
content: ""; position: absolute; left: 3px; top: 9px; bottom: 9px;
width: 3px; border-radius: 999px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--r) 85%, transparent),
color-mix(in srgb, var(--r) 30%, transparent));
opacity: .7;
transition: opacity var(--tempo);
pointer-events: none;
}
.liste-kachel > .gruppe[data-auf="ja"]::after { opacity: 1; }
/* Die Zeile reagiert als GANZE, nicht durch Verblassen. `opacity: .82`
auf dem Kopf (start.css) macht beim Überfahren den Text blasser --
das ist das Gegenteil von "hier bist du". Ein leiser Farbzug von
links sagt dasselbe, ohne etwas wegzunehmen. */
.liste-kachel > .gruppe > .gruppe__kopf--klappbar { opacity: 1; }
.liste-kachel > .gruppe > .gruppe__kopf--klappbar:hover {
opacity: 1;
background: linear-gradient(90deg,
color-mix(in srgb, var(--r) 11%, transparent), transparent 58%);
}
/* Die Anzahl trägt die Rollenfarbe. Sie ist der einzige Punkt in der
Zeile, der ohnehin schon ein Feld ist -- eine zweite eingefärbte
Fläche daneben wäre eine zu viel. */
.liste-kachel .gruppe__zahl {
color: color-mix(in srgb, var(--r) 78%, #ffffff);
background: color-mix(in srgb, var(--r) 15%, transparent);
border: 1px solid color-mix(in srgb, var(--r) 32%, transparent);
padding: 1px 8px;
}
/* Und der Rollenname bekommt eine Spur mehr Gewicht als vorher -- er
ist die Überschrift der Zeile, nicht ihre Beschriftung. */
.liste-kachel .gruppe__name { color: var(--text); letter-spacing: .11em; }
.liste-kachel > .gruppe[data-auf="ja"] .gruppe__name {
color: color-mix(in srgb, var(--r) 55%, var(--text));
}
/* ---- Wer drinsteht ---------------------------------------------------
Vier Namenszeichen, leicht überlappend wie ein Stapel Karten -- so
liest man sie als EINE Gruppe und nicht als vier Einzelteile. Sie
stehen rechts, kurz vor dem Pfeil: Der Blick geht von links (wer ist
das) nach rechts (wer ist drin, kann ich aufklappen). */
.gruppe__leute { display: flex; align-items: center; justify-self: end; }
.gruppe__kopf-zeichen {
width: 26px; height: 26px; border-radius: 50%;
display: grid; place-items: center;
margin-left: -7px;
/* 0,72 rem und nicht 0,66: Darunter faellt die Hausgrenze von
11,5 px, und zwei Grossbuchstaben in einem 26-px-Kreis haben den
Platz. Gemeldet von pruef-css-klassen, bevor es jemand lesen
musste. */
font-size: .72rem; font-weight: 700; letter-spacing: .01em;
color: color-mix(in srgb, var(--r) 72%, #ffffff);
background: color-mix(in srgb, var(--r) 17%, #070a11);
/* Der Ring in der Farbe der Kachel schneidet die Zeichen voneinander
frei -- ohne ihn verschwimmt der Stapel zu einem Fleck. */
border: 1.5px solid #05080d;
box-shadow: 0 0 0 1px color-mix(in srgb, var(--r) 26%, transparent);
}
.gruppe__kopf-zeichen:first-child { margin-left: 0; }
/* Gesperrt ist keine Farbe, sondern eine Abwesenheit von Farbe. Rot
wäre hier eine Warnung je Person; die Warnung steht schon einmal im
Zusatztext, und zweimal dasselbe zu rufen macht beides leiser. */
.gruppe__kopf-zeichen[data-gesperrt="ja"] {
color: var(--text-still);
background: rgba(255, 255, 255, .05);
box-shadow: 0 0 0 1px rgba(255, 255, 255, .1);
}
.gruppe__kopf-zeichen[data-mehr="ja"] {
color: var(--text-leise);
background: rgba(255, 255, 255, .06);
box-shadow: 0 0 0 1px rgba(255, 255, 255, .12);
font-weight: 600;
}
/* Der Pfeil bekommt die Rollenfarbe erst beim Überfahren -- fünf
farbige Pfeile untereinander wären fünfmal dieselbe Aussage. */
.liste-kachel > .gruppe > .gruppe__kopf--klappbar:hover .klapp-pfeil {
color: color-mix(in srgb, var(--r) 70%, var(--text));
}
.liste-kachel > .gruppe[data-auf="ja"] .klapp-pfeil {
color: color-mix(in srgb, var(--r) 60%, var(--text-leise));
}
/* Die Namenszeichen bekommen eine eigene Spalte im Raster (Name, Zahl,
Zusatztext, Leute, Pfeil). */
.liste-kachel > .gruppe > .gruppe__kopf--klappbar {
grid-template-columns: var(--namen-spalte, max-content) auto minmax(0, 1fr) auto auto;
align-items: center;
}
/* Der Zusatztext steht auf der Schriftlinie des Namens -- er ist Text,
die anderen drei sind Formen. */
.liste-kachel .gruppe__name, .liste-kachel .gruppe__unter { align-self: baseline; }
@media (max-width: 900px) {
/* Eng wird zuerst das Entbehrliche weggelassen: Die Zahl daneben sagt
schon, wie viele es sind. */
.gruppe__leute { display: none; }
.liste-kachel > .gruppe > .gruppe__kopf--klappbar {
grid-template-columns: var(--namen-spalte, max-content) auto minmax(0, 1fr) auto;
}
}
/* ---- Am Handy: zwei Zeilen, und der Pfeil bleibt rechts -------------
Hier stand nur `.gruppe__unter { grid-column: 1 / -1 }` (weiter oben
in dieser Datei). Der Zusatztext bekam damit eine eigene Rasterzeile
-- und schob den Pfeil in eine DRITTE, wo er mittig unter dem Text
stand wie ein vergessenes Zeichen. Gemessen: 106 px je Zeile, fuenfmal
untereinander, auf einem 390 px breiten Bildschirm.
Richtig ist: Der Pfeil bekommt seine eigene Spalte ganz rechts und
ueberspannt BEIDE Zeilen. Dann steht er dort, wo die Hand ihn sucht,
und die Zeile ist zwei Zeilen hoch statt drei. */
@media (max-width: 620px) {
.liste-kachel > .gruppe > .gruppe__kopf--klappbar {
grid-template-columns: max-content auto minmax(0, 1fr) auto;
row-gap: 3px;
}
.liste-kachel .gruppe__name { grid-column: 1; grid-row: 1; }
.liste-kachel .gruppe__zahl { grid-column: 2; grid-row: 1; }
.liste-kachel .gruppe__unter { grid-column: 1 / 4; grid-row: 2; }
.liste-kachel > .gruppe > .gruppe__kopf--klappbar .klapp-pfeil {
grid-column: 4; grid-row: 1 / span 2; align-self: center;
}
}
@media (prefers-reduced-motion: reduce) {
.liste-kachel > .gruppe::after { transition: none; }
}
@media (forced-colors: active) {
.liste-kachel > .gruppe::after { background: CanvasText; }
.gruppe__kopf-zeichen { border: 1px solid CanvasText; }
}
+58 -1
View File
@@ -204,6 +204,18 @@
let betreuerListe = [];
/** Ein oder zwei Buchstaben aus einem Namen.
*
* Zwei nur bei einem echten zweiten Wort: Aus "Spicy Media" wird SM,
* aus "BananaStift" ein B -- Binnenversalien als zweiten Namen zu
* lesen ergäbe "BS" für eine Person, die einen Namen hat. */
function initialen(name) {
const teile = String(name || '').trim().split(/[\s._-]+/).filter(Boolean);
if (!teile.length) return '?';
if (teile.length === 1) return teile[0].slice(0, 1).toUpperCase();
return (teile[0][0] + teile[teile.length - 1][0]).toUpperCase();
}
function zeile(p) {
const k = el('div', 'person');
k.dataset.aktiv = p.aktiv ? 'ja' : 'nein';
@@ -599,6 +611,18 @@
const auf = offen.has(abschnitt.rolle);
const block = document.createElement('section');
block.className = 'gruppe';
/* DIE ROLLE STEHT AM ABSCHNITT (09.09.2026).
Ohne sie sehen alle fünf Zeilen gleich aus, und die Farben, die
das Haus für die Rollen ohnehin führt (Anmeldeseite, Marken,
Bereiche), hören ausgerechnet in der Personenliste auf. Das
Merkmal ist die einzige Zeile Skript, die dafür nötig ist --
alles Weitere macht das CSS. */
block.dataset.rolle = abschnitt.rolle;
/* UND DER ZUSTAND, an derselben Stelle. Das CSS fragte ihn bisher
ueber `:has(> .gruppe__kopf[aria-expanded="true"])` ab -- das
geht, ist aber ein zweiter Weg zu einer Auskunft, die hier
ohnehin vorliegt. Ein Merkmal, drei Regeln, kein Suchen. */
block.dataset.auf = auf ? 'ja' : 'nein';
/* Die Überschrift IST der Knopf. Ein eigener kleiner Schalter
daneben wäre ein zweites Ziel für dieselbe Absicht -- und ein
@@ -635,7 +659,40 @@
pfad.setAttribute('d', 'm6 9.5 6 6 6-6');
pfeil.append(pfad);
kopf.append(h, zahl, unter, pfeil);
/* WER DRINSTEHT — SICHTBAR, OHNE AUFZUKLAPPEN.
Zugeklappt sagte die Zeile bisher nur, WIE VIELE es sind. Wer
wissen wollte, ob Patrick dabei ist, musste aufklappen. Vier
Namenszeichen beantworten das im Vorbeigehen; ab dem fünften
steht "+n" dahinter, damit die Zeile nicht wächst.
`aria-hidden`, weil es eine Wiederholung ist: Die Anzahl steht
als Zahl daneben, die Namen stehen beim Aufklappen vollständig
da. Ein Vorleseprogramm würde hier sonst Buchstabenpaare
vorlesen, die niemandem etwas sagen. Für die Maus steht der
volle Name im title. */
const leute = document.createElement('span');
leute.className = 'gruppe__leute';
leute.setAttribute('aria-hidden', 'true');
const ZEIGEN = 4;
for (const p of abschnitt.drin.slice(0, ZEIGEN)) {
const z = document.createElement('span');
z.className = 'gruppe__kopf-zeichen';
z.textContent = initialen(p.name);
z.title = p.aktiv ? p.name : `${p.name} (gesperrt)`;
if (!p.aktiv) z.dataset.gesperrt = 'ja';
leute.append(z);
}
if (abschnitt.drin.length > ZEIGEN) {
const mehr = document.createElement('span');
mehr.className = 'gruppe__kopf-zeichen';
mehr.dataset.mehr = 'ja';
mehr.textContent = `+${abschnitt.drin.length - ZEIGEN}`;
mehr.title = abschnitt.drin.slice(ZEIGEN).map((p) => p.name).join(', ');
leute.append(mehr);
}
kopf.append(h, zahl, unter, leute, pfeil);
kopf.addEventListener('click', () => {
if (offen.has(abschnitt.rolle)) offen.delete(abschnitt.rolle);
else offen.add(abschnitt.rolle);
+9 -9
View File
@@ -14,10 +14,10 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -231,10 +231,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/aufgaben.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/aufgaben.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -140,10 +140,10 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/automation.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/automation.js?v=202609091336" defer></script>
</body>
</html>
+14 -14
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -149,14 +149,14 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/checkliste.js?v=202609091251" defer></script>
<script src="assets/js/ampel.js?v=202609091251" defer></script>
<script src="assets/js/schulung.js?v=202609091251" defer></script>
<script src="assets/js/vorlagen.js?v=202609091251" defer></script>
<script src="assets/js/bereich.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/checkliste.js?v=202609091336" defer></script>
<script src="assets/js/ampel.js?v=202609091336" defer></script>
<script src="assets/js/schulung.js?v=202609091336" defer></script>
<script src="assets/js/vorlagen.js?v=202609091336" defer></script>
<script src="assets/js/bereich.js?v=202609091336" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -82,11 +82,11 @@
</main>
<script src="assets/js/ki.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/calls.js?v=202609091251" defer></script>
<script src="assets/js/ki.js?v=202609091336" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/calls.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,17 +14,17 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<!-- 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=202609091251" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -247,10 +247,10 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609091251"></script>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251"></script>
<script src="assets/js/glocke.js?v=202609091251"></script>
<script src="assets/js/chat.js?v=202609091251"></script>
<script src="assets/js/bereiche.js?v=202609091336"></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336"></script>
<script src="assets/js/glocke.js?v=202609091336"></script>
<script src="assets/js/chat.js?v=202609091336"></script>
</body>
</html>
+12 -12
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/content.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/content.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -172,12 +172,12 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/checkliste.js?v=202609091251" defer></script>
<script src="assets/js/vorlagen.js?v=202609091251" defer></script>
<script src="assets/js/content.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/checkliste.js?v=202609091336" defer></script>
<script src="assets/js/vorlagen.js?v=202609091336" defer></script>
<script src="assets/js/content.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -101,10 +101,10 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/dateien.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/dateien.js?v=202609091336" defer></script>
</body>
</html>
+2 -2
View File
@@ -32,7 +32,7 @@
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
</head>
<body class="gate">
@@ -401,6 +401,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609091251" defer></script>
<script src="assets/js/gate.js?v=202609091336" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -340,11 +340,11 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/kalender.js?v=202609091251" defer></script>
<script src="assets/js/kalender-abo.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/kalender.js?v=202609091336" defer></script>
<script src="assets/js/kalender-abo.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -217,10 +217,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609091251"></script>
<script src="assets/js/bereiche.js?v=202609091251"></script>
<script src="assets/js/kopf.js?v=202609091251"></script>
<script src="assets/js/glocke.js?v=202609091251"></script>
<script src="assets/js/leistung.js?v=202609091251"></script>
<script src="assets/js/wahl.js?v=202609091336"></script>
<script src="assets/js/bereiche.js?v=202609091336"></script>
<script src="assets/js/kopf.js?v=202609091336"></script>
<script src="assets/js/glocke.js?v=202609091336"></script>
<script src="assets/js/leistung.js?v=202609091336"></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -335,10 +335,10 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/personen.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/personen.js?v=202609091336" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -207,11 +207,11 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/steckbrief.js?v=202609091251" defer></script>
<script src="assets/js/profil.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/steckbrief.js?v=202609091336" defer></script>
<script src="assets/js/profil.js?v=202609091336" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/report.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/report.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -99,11 +99,11 @@
</main>
<script src="assets/js/ki.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/report.js?v=202609091251" defer></script>
<script src="assets/js/ki.js?v=202609091336" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/report.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -132,10 +132,10 @@
</div>
</div>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/scouting.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/scouting.js?v=202609091336" defer></script>
</body>
</html>
+9 -9
View File
@@ -14,12 +14,12 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<!-- 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=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -667,10 +667,10 @@
</p>
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/start.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/start.js?v=202609091336" defer></script>
</body>
</html>
+11 -11
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -78,11 +78,11 @@
</main>
<script src="assets/js/ki.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/startcheck.js?v=202609091251" defer></script>
<script src="assets/js/ki.js?v=202609091336" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/startcheck.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -119,10 +119,10 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/steckbrief.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/steckbrief.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,13 +14,13 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -142,11 +142,11 @@
</main>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/uebersicht.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/uebersicht.js?v=202609091336" defer></script>
</body>
</html>
+10 -10
View File
@@ -14,11 +14,11 @@
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091251" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/start.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609091336" />
<link rel="stylesheet" href="assets/css/module.css?v=202609091336" />
</head>
<body class="start">
@@ -183,10 +183,10 @@
</main>
<script src="assets/js/wahl.js?v=202609091251" defer></script>
<script src="assets/js/bereiche.js?v=202609091251" defer></script>
<script src="assets/js/kopf.js?v=202609091251" defer></script>
<script src="assets/js/glocke.js?v=202609091251" defer></script>
<script src="assets/js/wissen.js?v=202609091251" defer></script>
<script src="assets/js/wahl.js?v=202609091336" defer></script>
<script src="assets/js/bereiche.js?v=202609091336" defer></script>
<script src="assets/js/kopf.js?v=202609091336" defer></script>
<script src="assets/js/glocke.js?v=202609091336" defer></script>
<script src="assets/js/wissen.js?v=202609091336" defer></script>
</body>
</html>