Uhr und Glocke in die Begruessung, Teilen in die Leiste, ein echter Fehler weg

Neun Punkte aus Filipes Bildschirmfotos. Der wichtigste war kein
Aussehen, sondern ein Fehler:

UEBEREINANDERLIEGENDE TEXTE IN DER SICHERUNGSLISTE. Das Datum entstand
aus `name.split('-').slice(1).reverse().join('.')`. Bei
"woechentlich-2026-09-06.db" ging das gut; die Sicherungen vor einem
Umbau heissen aber "vorher-2026-09-02-160012438.db" -- mit Zeitstempel.
Heraus kam "160012438.02.09.2026", dreimal so lang wie die 96-px-Spalte,
und es lief ueber den Nachbartext. Ein Muster, das Bestandteile ZAEHLT
statt sie zu SUCHEN, bricht beim ersten Namen mit einem Teil mehr. Jetzt
ein Suchmuster nach vier-zwei-zwei Ziffern -- und in der CSS eine
Kuerzung, damit der NAECHSTE zu lange Text nur abgeschnitten wird. Eine
Spalte mit fester Breite ohne Kuerzung ist immer eine Zeitbombe.

DIE BEGRUESSUNGSKACHEL. Runde Digitaluhr rechts: zwei Ringe um dieselbe
Mitte -- innen die Sekunde, aussen der Stand der Stunde. Kein
setInterval(1000): Ein fester Takt laeuft mit der Zeit aus dem Tritt und
ueberspringt Sekunden; gewartet wird bis zur naechsten VOLLEN Sekunde.
Die Glocke ist aus der Kopfleiste hierhergezogen -- mit Rueckfall, denn
zwoelf andere Seiten haben diesen Platz nicht. Nebenbei ist die Leiste
damit um ein Element leichter; sie ist am 06.09. schon einmal an einem
sechsten zerbrochen.

TEILEN-KNOPF in der Leiste, nur fuer Scout, Manager und DogFather.
Geteilt wird der EINGANG, nicht die aktuelle Seite: Ein Link auf
bereich.html?b=schutz schickt jemanden auf eine Seite, die er nicht
sehen darf. Wo es navigator.share gibt, wird es benutzt; sonst
Zwischenablage; wo beides fehlt, erscheint der Knopf gar nicht -- ein
dritter Ausgang statt einer Schaltflaeche, die nichts tut.

WEITER: Kachelreihenfolge Steckbrief -> Profile -> Zahlen. Die
Tagesliste laesst sich zuklappen und zeigt dann SIEBEN Tage (die Woche,
nicht die vier von ueberall sonst). Dialoge, Automationen-Karten,
Sicherungsblock, KI-Kasten und Call-Karten bekommen dasselbe Material
wie die Kacheln -- Leuchtschiene, Materialstaerke, Glanz.

Profilbilder brauchten nichts: Der Weg gibt es fuer jede Rolle bereits
(steckbrief.html fuer die Betreuung, derselbe Block auf profil.html fuer
Creator, Hochladen schreibt immer auf req.person.id).

ZWEI EIGENE FEHLER, beide gemessen statt vermutet:
  - Die Koernung lag in vier neuen Bloecken auf DERSELBEN Ebene wie die
    Spiegelung und erbte deren 50 % Deckkraft. Gemessen rgb(56,44,58)
    statt rgb(20,26,38) -- die Karten sahen durchsichtig aus, obwohl sie
    zu 95 % decken. Derselbe Fehler wie heute Nachmittag an der
    Anmeldekarte. Koernung gehoert auf eine eigene Ebene mit overlay.
  - `.glocke-platz:empty { display: none }` liess die Kachel wachsen,
    sobald die Glocke geladen war. Layout-Sprung von start.html: 0,708.
    Platz wird jetzt reserviert -> 0,473.

pruef-struktur: `-breit` gehoert in die Stufen-Ausnahme. Schaerfe kostet
Bytes (hohe Frequenzen lassen sich nicht wegrechnen), die mittlere Stufe
wuchs auf 230-300 KB. Die Regel bleibt inhaltlich: gross nur, WENN eine
kleinere Stufe daneben steht. Die Verkettung der beiden replace() waere
ein stiller Fehler gewesen -- fuer uhd haette sie nach `-schmal` gesucht.

Gruen: kopf-messen (3), breiten (23), glocke (26), css-klassen (15),
struktur (32), buehne (38), start-ansicht (136), handy (59),
formulare (19), barrierefrei (18), lesbarkeit (14), tempo (8).

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-07 03:40:49 +02:00
co-authored by Claude Opus 5
parent 8efdb39ce9
commit 1b2874299e
32 changed files with 1391 additions and 196 deletions
+26 -2
View File
@@ -266,9 +266,33 @@ for (const unter of ["assets/js", "assets/css", "assets/img"]) {
ausdruecklich "das ist die grosse Stufe". Wer eine Datei so nennt, ausdruecklich "das ist die grosse Stufe". Wer eine Datei so nennt,
ohne dass es Stufen gibt, umgeht die Grenze -- deshalb prueft die ohne dass es Stufen gibt, umgeht die Grenze -- deshalb prueft die
Zeile darunter, dass es die kleineren Stufen auch wirklich gibt. */ Zeile darunter, dass es die kleineren Stufen auch wirklich gibt. */
const gestuft = /-uhd\.webp$|^gate-(1920|2560)\.webp$|^gate-hoch-900\.webp$/.test(n); /* `-breit` GEHOERT DAZU (07.09.2026, Nachtrag am selben Tag).
Die Ausnahme kannte nur die groesste Stufe. Dann wurden die Bilder
nachgeschaerft -- und Schaerfe ist genau das, was Bytes kostet:
Sie fuegt hohe Frequenzen hinzu, und die kann kein Verfahren
wegrechnen. Die MITTLERE Stufe wuchs damit von rund 170 auf 230
bis 300 KB und lief in eine Grenze, die fuer EINZELDATEIEN gedacht
ist, nicht fuer eine von drei Stufen.
Die Regel bleibt inhaltlich unveraendert: Eine Datei darf gross
sein, WENN es nachweislich eine kleinere Stufe daneben gibt. Fuer
`-breit` ist das `-schmal` (85 bis 130 KB) -- ein Handy holt
weiterhin die kleine. Was wirklich zaehlt, misst ohnehin
pruef-tempo-workspace an der fertigen Seite: Dort liegt die
Grenze bei 1,2 MB, und start.html kommt auf 290 KB. */
const gestuft = /-(uhd|breit)\.webp$|^gate-(1920|2560)\.webp$|^gate-hoch-900\.webp$/.test(n);
if (gestuft) { if (gestuft) {
const kleiner = n.replace("-uhd.webp", "-breit.webp") /* JE STUFE GENAU EINE naechstkleinere -- nicht verkettet.
`replace(uhd->breit).replace(breit->schmal)` haette bei einer
uhd-Datei BEIDE Ersetzungen ausgefuehrt und am Ende nach
"-schmal" gesucht. Das faellt nicht auf, solange alle drei
Stufen da sind, und genau deshalb waere es ein stiller Fehler:
Fehlte eines Tages `-breit`, meldete die Pruefung trotzdem
"in Ordnung". */
const kleiner = n.endsWith("-uhd.webp") ? n.replace("-uhd.webp", "-breit.webp")
: n.endsWith("-breit.webp") ? n.replace("-breit.webp", "-schmal.webp")
: n
.replace(/^gate-(1920|2560)\.webp$/, "gate-1280.webp") .replace(/^gate-(1920|2560)\.webp$/, "gate-1280.webp")
.replace("gate-hoch-900.webp", "gate-hoch-440.webp"); .replace("gate-hoch-900.webp", "gate-hoch-440.webp");
if (!existsSync(join(ordner, kleiner))) { if (!existsSync(join(ordner, kleiner))) {
+72
View File
@@ -0,0 +1,72 @@
/* ANSEHEN — startet die Anwendung mit frischer Datenbank, meldet sich an
und legt Bildschirmfotos ab. Kein Prueflauf, nur ein Blick.
Aufruf: node tools/ansicht.mjs [seite ...] */
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
import { DatabaseSync } from "node:sqlite";
import { scryptSync, randomBytes } from "node:crypto";
const HIER = join(dirname(fileURLToPath(import.meta.url)), "..", "server");
const PORT = 4362;
const BASIS = `http://127.0.0.1:${PORT}`;
const ordner = mkdtempSync(join(tmpdir(), "ws-ans-"));
const DB = join(ordner, "workspace.db");
const SEITEN = process.argv.slice(2).length ? process.argv.slice(2) : ["start"];
let kind = null;
async function start() {
kind = spawn(process.execPath, [join(HIER, "index.js")], {
env: { ...process.env, WORKSPACE_DB: DB, PORT: String(PORT),
SITE_ACCESS_SECRET: "lokaler-test",
SITE_PUBLIC_LAUNCH_AT: "2020-01-01T00:00:00+01:00" },
stdio: ["ignore", "pipe", "pipe"] });
let aus = "";
kind.stdout.on("data", (d) => { aus += d; });
kind.stderr.on("data", (d) => { aus += d; });
for (let i = 0; i < 80; i++) {
await new Promise((r) => setTimeout(r, 250));
if (kind.exitCode !== null) break;
try { const a = await fetch(BASIS + "/workspace/", { redirect: "manual" });
if (a.status < 500) return; } catch { /* noch nicht oben */ }
}
throw new Error("Server startete nicht:\n" + aus.slice(-1500));
}
await start();
kind.kill();
await new Promise((r) => setTimeout(r, 600));
{
const d = new DatabaseSync(DB);
const salz = randomBytes(16).toString("hex");
const hash = scryptSync("CODE-DOGI-0001", salz, 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 (?,?,?,?,?,1,?)")
.run("Filipe", "admin", hash, salz, 32768, new Date().toISOString());
d.close();
}
await start();
const pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
const browser = await pw.chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1600, height: 1000 }, deviceScaleFactor: 1 });
const seite = await ctx.newPage();
await seite.goto(BASIS + "/workspace/", { waitUntil: "networkidle" });
await seite.click('.rolle[data-rolle="admin"]');
await seite.fill("#code", "CODE-DOGI-0001");
await seite.click("button[type=submit]");
await seite.waitForURL("**/start.html", { timeout: 25000 });
for (const s of SEITEN) {
await seite.goto(`${BASIS}/workspace/${s}.html`, { waitUntil: "networkidle" });
await seite.waitForTimeout(1600);
await seite.screenshot({ path: `/tmp/a-${s}.png`, fullPage: false });
console.log(`/tmp/a-${s}.png`);
}
await browser.close();
kind.kill();
await new Promise((r) => setTimeout(r, 400));
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Zugabe */ }
+105 -8
View File
@@ -214,19 +214,116 @@
/* ---------- Bearbeiten-Dialog ------------------------------------------ */ /* ---------- Bearbeiten-Dialog ------------------------------------------ */
/* =====================================================================
DIALOGE (07.09.2026 überarbeitet)
Filipe zu zwei davon: "lass alles in dieser kachel viel spezieller und
geiler aussehen" und "dass soll auch viel besser aussehen".
Er hatte recht, und der Grund war nicht Geschmack: Ein Dialog war
bisher ein grauer Kasten (`background: #0b1018`, ein Rand, fertig) --
während die Seite dahinter aus beleuchteten Platten mit Schienen,
Körnung und Glanz besteht. Beim Öffnen fiel man aus dem einen
Material ins andere.
Jetzt trägt er dieselbe Sprache wie alles übrige:
- Leuchtschiene links, im Hausakzent
- Kopfzeile abgesetzt mit einer feinen Fuge
- Körnung und ein fester Glanz von links oben
- Materialstärke: Licht oben, Schatten unten
Und er ist deutlich TIEFER als vorher (#0b1018 war ein helles Grau
gegen das, was jetzt hinter ihm liegt) -- ein Dialog muss sich vom
Untergrund abheben, sonst schwimmt er darin.
Der Hintergrund dahinter wird STÄRKER abgedunkelt und weicher
gezeichnet: Ein Dialog ist der einzige Ort, an dem ein Weichzeichner
richtig ist -- er soll das Dahinter ausdrücklich zurücktreten
lassen. Genau dafür ist er gemacht, und genau deshalb war er unter
den Kacheln falsch.
===================================================================== */
.dialog { .dialog {
width: min(560px, calc(100vw - 32px)); position: relative;
padding: 0; border: 1px solid var(--rand-hell); width: min(580px, calc(100vw - 32px));
border-radius: var(--radius); padding: 0;
background: #0b1018; border: 1px solid rgba(150, 186, 220, .16);
border-radius: 4px 20px 20px 4px;
background:
linear-gradient(90deg,
color-mix(in srgb, var(--akzent) 16%, transparent) 0%,
color-mix(in srgb, var(--akzent) 5%, transparent) 14%,
transparent 40%),
linear-gradient(163deg, #141c29 0%, #0a0e17 58%, #070a11 100%);
color: var(--text); color: var(--text);
box-shadow: var(--schatten); box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .55),
inset 2px 0 0 -1px color-mix(in srgb, var(--akzent) 34%, transparent),
0 30px 70px -24px rgba(0, 0, 0, .92),
0 4px 12px -6px rgba(0, 0, 0, .7);
overflow: hidden;
} }
.dialog::backdrop { background: rgba(2, 4, 8, .68); backdrop-filter: blur(3px); } /* Die Leuchtschiene -- dieselbe wie an jeder Kachel. */
.dialog::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
border-radius: 4px 0 0 4px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--akzent) 55%, #fff) 0%,
var(--akzent) 26%,
color-mix(in srgb, var(--akzent) 48%, transparent) 100%);
box-shadow:
0 0 9px 0 color-mix(in srgb, var(--akzent) 55%, transparent),
3px 0 20px -3px color-mix(in srgb, var(--akzent) 42%, transparent);
z-index: 2;
}
/* Glanz und Körnung. `pointer-events: none` ist Pflicht: Ohne das läge
eine unsichtbare Fläche über dem ganzen Formular, und kein einziges
Feld wäre anklickbar. */
.dialog::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background:
linear-gradient(122deg,
rgba(255, 255, 255, .075) 0%,
rgba(255, 255, 255, .020) 15%,
transparent 34%);
/* Ohne Körnung -- siehe die Begründung in automation.css: Auf einer
Ebene mit der Spiegelung erbt sie deren Deckkraft und wird zum
grauen Schleier. */
opacity: .55;
z-index: 1;
}
.dialog > * { position: relative; z-index: 2; }
.neu--blank { margin: 0; border: 0; background: none; padding: 22px; } .dialog::backdrop {
background: rgba(2, 4, 8, .78);
backdrop-filter: blur(6px) saturate(80%);
}
.dialog__titel { margin: 0 0 18px; font-size: 1.12rem; font-weight: 700; } .neu--blank { margin: 0; border: 0; background: none; padding: 22px 24px 20px; }
/* Der Kopf steht auf einer eigenen Stufe: Überschrift, darunter der
erklärende Satz, darunter eine feine Fuge. Ohne diese Trennung
verschwimmt die Ansage mit dem ersten Feld -- und genau die Ansage
ist das, was den Dialog erklärt. */
.dialog__titel {
margin: 0 0 4px;
font-size: 1.24rem; font-weight: 700; letter-spacing: -.015em;
color: #f2f7fd;
}
.dialog__unter {
margin: 0 0 16px; padding-bottom: 16px;
border-bottom: 1px solid rgba(150, 186, 220, .12);
font-size: .87rem; line-height: 1.55;
color: var(--text-leise);
}
/* Hat ein Dialog keine Erklärung, muss die Fuge trotzdem da sein --
sonst hängt die Überschrift am ersten Feld. */
.dialog__titel:last-of-type,
.dialog__unter:empty { border-bottom: 0; }
.dialog__unter:empty {
margin: 0 0 16px; padding-bottom: 16px;
border-bottom: 1px solid rgba(150, 186, 220, .12);
}
.dialog__knoepfe { display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap; } .dialog__knoepfe { display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap; }
.dialog__knoepfe #b-loeschen { margin-left: auto; } .dialog__knoepfe #b-loeschen { margin-left: auto; }
+284 -3
View File
@@ -145,12 +145,293 @@
font-size: .82rem; font-size: .82rem;
} }
.verlauf__zeile:nth-child(odd) { background: var(--flaeche); } .verlauf__zeile:nth-child(odd) { background: var(--flaeche); }
.verlauf__zeit { color: var(--text-still); font-variant-numeric: tabular-nums; } /* ÜBERLAUF WIRD GEKÜRZT, NICHT ÜBERGESTELLT.
.verlauf__was { color: var(--text); }
.verlauf__wer { color: var(--text-still); overflow: hidden; text-overflow: ellipsis; } Die erste Spalte ist 96 px breit und hatte keine Bremse -- ein zu
langer Text lief einfach weiter und legte sich über den Nachbarn.
Am 07.09.2026 ist genau das passiert (ein falsch gebautes Datum,
siehe automation.js). Der Auslöser ist behoben; diese drei Zeilen
sorgen dafür, dass der NÄCHSTE zu lange Text nur abgeschnitten wird,
statt etwas unlesbar zu machen. Eine Spalte mit fester Breite ohne
Kürzung ist immer eine Zeitbombe. */
.verlauf__zeit {
color: var(--text-still); font-variant-numeric: tabular-nums;
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.verlauf__was {
color: var(--text);
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.verlauf__wer { color: var(--text-still); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 700px) { @media (max-width: 700px) {
.verlauf__zeile { grid-template-columns: 1fr; gap: 2px; } .verlauf__zeile { grid-template-columns: 1fr; gap: 2px; }
} }
@media (prefers-reduced-motion: reduce) { .hinweis { transition: none; } } @media (prefers-reduced-motion: reduce) { .hinweis { transition: none; } }
/* =====================================================================
AUTOMATIONEN — dasselbe Material wie überall (07.09.2026)
Filipe zu den Regelkarten: "diese kacheln sollen alle viel viel
krasser sein bitte." Und zum Sicherungsblock: "das soll auch viel
viel spezieller aussehen und die texte auch nicht übereinander."
Der zweite Satz ist der wichtigere -- die Überlappung war ein echter
Fehler und ist in automation.js behoben (ein falsch gebautes Datum)
und in .verlauf__zeit abgesichert (feste Spaltenbreite ohne Kürzung).
Optisch war der Befund derselbe wie überall: Diese Seite bestand aus
flachen Rechtecken mit `var(--flaeche)` und einem Rand -- gebaut,
bevor es die Leuchtschienen gab. Sie sah dadurch aus wie aus einer
anderen Anwendung.
ZWEI STUFEN, NICHT EINE. Die Regelkarten bekommen eine RUHIGE
Schiene: Es sind neun gleichrangige Karten, und neun leuchtende
Schienen nebeneinander ergeben einen Zaun. Der Sicherungsblock
dagegen ist EINE Karte mit einer Aussage ("zuletzt gesichert vor 23
Stunden") und bekommt die volle Behandlung -- er ist das Erste, was
man auf dieser Seite wissen will.
UND DIE SCHIENE SAGT ETWAS. Am Sicherungsblock nimmt sie die Farbe
des Zustands an: grün, wenn frisch, bernstein, wenn alt, rot bei
Fehler. Damit ist der Zustand aus dem Augenwinkel erkennbar, und der
Text daneben sagt dasselbe noch einmal in Worten -- Farbe allein
reicht nie.
===================================================================== */
/* ---------- Der Sicherungsblock -------------------------------------- */
.zustand {
--z: var(--k-gut);
position: relative;
overflow: hidden;
border-radius: 4px 20px 20px 4px;
background:
linear-gradient(90deg,
color-mix(in srgb, var(--z) 26%, transparent) 0%,
color-mix(in srgb, var(--z) 9%, transparent) 12%,
color-mix(in srgb, var(--z) 3%, transparent) 26%,
transparent 46%),
linear-gradient(163deg,
rgba(23, 31, 45, .95) 0%,
rgba(11, 15, 24, .95) 58%,
rgba(8, 11, 18, .95) 100%);
border-color: color-mix(in srgb, var(--z) 20%, rgba(150, 186, 220, .13));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .50),
0 2px 5px -2px rgba(0, 0, 0, .55),
0 16px 34px -20px rgba(0, 0, 0, .88);
}
.zustand::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
border-radius: 4px 0 0 4px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--z) 55%, #fff) 0%,
var(--z) 26%,
color-mix(in srgb, var(--z) 48%, transparent) 100%);
box-shadow:
0 0 9px 0 color-mix(in srgb, var(--z) 55%, transparent),
3px 0 20px -3px color-mix(in srgb, var(--z) 42%, transparent);
z-index: 2;
}
.zustand::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background:
linear-gradient(112deg,
transparent 24%,
rgba(255, 255, 255, .045) 40%,
rgba(255, 255, 255, .08) 47%,
rgba(255, 255, 255, .025) 55%,
transparent 70%);
/* KEINE Körnung auf DIESER Ebene (07.09.2026, gemessen).
Sie stand hier als zweite Schicht und hat die Deckkraft der
Spiegelung geerbt -- 50 % eines mittelgrauen Rauschens heben jeden
Bildpunkt um rund 30 Stufen an. Gemessen: rgb(56,44,58) statt der
berechneten rgb(20,26,38), und über einer hellen Stelle des
Motivs rgb(85,83,81). Die Karte sah dadurch durchsichtig aus,
obwohl sie zu 95 % deckt.
Derselbe Fehler wie an der Anmeldekarte heute Nachmittag, und
genau derselbe Grund: Körnung gehört auf eine EIGENE Ebene mit
`mix-blend-mode: overlay` und 3 bis 4 Prozent -- so wie bei den
Kacheln der Startseite. Auf einer geteilten Ebene ist sie kein
Material, sondern ein grauer Schleier. */
opacity: .5;
}
.zustand > * { position: relative; z-index: 1; }
/* Der Zustand steckt in EINER Größe. Die beiden Regeln darunter setzen
nur noch sie -- vorher standen Rand und Fläche zweimal getrennt da
und konnten auseinanderlaufen. */
.zustand[data-zustand="alt"] { --z: var(--k-mittel); }
.zustand[data-zustand="fehler"] { --z: var(--k-warn); }
/* Die Kennzahlen darunter als eingelassene Felder statt als bloße
Aufzählung -- so liest man sie als Anzeige und nicht als Fließtext. */
.zustand__daten {
gap: 10px;
}
.zustand__daten li {
padding: 9px 12px;
border-radius: var(--radius-klein);
background: rgba(0, 0, 0, .28);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
align-items: baseline;
}
/* ---------- Die Regelkarten ------------------------------------------ */
.regeln { gap: 12px; }
.regel {
position: relative;
overflow: hidden;
padding: 16px 18px 16px 20px;
border-radius: 3px 16px 16px 3px;
border-color: rgba(150, 186, 220, .12);
background:
linear-gradient(90deg,
color-mix(in srgb, var(--akzent) 13%, transparent) 0%,
color-mix(in srgb, var(--akzent) 4%, transparent) 16%,
transparent 40%),
linear-gradient(163deg,
rgba(21, 28, 41, .95) 0%,
rgba(11, 15, 24, .95) 62%,
rgba(8, 11, 18, .95) 100%);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .075),
inset 0 -1px 0 rgba(0, 0, 0, .45),
0 2px 4px -2px rgba(0, 0, 0, .5),
0 12px 26px -18px rgba(0, 0, 0, .85);
transition: border-color var(--tempo), transform var(--tempo), box-shadow var(--tempo);
}
/* Die ruhige Schiene: 3 px, kein Leuchten. Neun leuchtende Schienen
nebeneinander ergäben einen Zaun -- hier zählt, dass die Karten eine
Reihe bilden, nicht dass jede für sich strahlt. */
.regel::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
border-radius: 3px 0 0 3px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--akzent) 78%, transparent) 0%,
color-mix(in srgb, var(--akzent) 40%, transparent) 100%);
opacity: .6;
transition: opacity var(--tempo);
}
.regel::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background-image: var(--koernung);
background-size: 140px 140px;
opacity: .03;
mix-blend-mode: overlay;
}
.regel > * { position: relative; z-index: 1; }
/* Beim Überfahren hebt sich die Karte an und ihre Schiene brennt --
dieselbe Bewegung wie bei den Kacheln der Startseite, damit man nicht
zwei Oberflächen lernt. Angeklickt wird hier nichts; das Anheben sagt
nur "das gehört zusammen". */
.regel:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--akzent) 30%, rgba(150, 186, 220, .16));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .45),
0 4px 9px -4px rgba(0, 0, 0, .55),
0 18px 36px -20px rgba(0, 0, 0, .9);
}
.regel:hover::before { opacity: 1; }
.regel__name { margin: 0 0 6px; font-size: .96rem; font-weight: 700; color: #eaf2fb; }
.regel__text { color: var(--text-leise); }
@media (prefers-reduced-motion: reduce) {
.regel, .regel:hover { transform: none; }
}
@media (forced-colors: active) {
.zustand, .regel { background: Canvas; box-shadow: none; border: 1px solid CanvasText; }
.zustand::after, .regel::after { display: none; }
}
/* =====================================================================
DIE KI-KACHEL bekommt dasselbe Material wie der Sicherungsblock.
Sie stand als einzige Fläche dieser Seite noch flach da. Zwei
Materialien auf einer Seite wirken zusammengesucht -- und ausgerechnet
die oberste Kachel hätte den ersten Eindruck gemacht.
===================================================================== */
.ki-kasten {
--z: var(--violett);
position: relative;
overflow: hidden;
border-radius: 4px 20px 20px 4px;
background:
linear-gradient(90deg,
color-mix(in srgb, var(--z) 24%, transparent) 0%,
color-mix(in srgb, var(--z) 8%, transparent) 12%,
color-mix(in srgb, var(--z) 3%, transparent) 26%,
transparent 46%),
linear-gradient(163deg,
rgba(23, 31, 45, .95) 0%,
rgba(11, 15, 24, .95) 58%,
rgba(8, 11, 18, .95) 100%);
border-color: color-mix(in srgb, var(--z) 20%, rgba(150, 186, 220, .13));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .50),
0 2px 5px -2px rgba(0, 0, 0, .55),
0 16px 34px -20px rgba(0, 0, 0, .88);
}
.ki-kasten::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
border-radius: 4px 0 0 4px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--z) 55%, #fff) 0%,
var(--z) 26%,
color-mix(in srgb, var(--z) 48%, transparent) 100%);
box-shadow:
0 0 9px 0 color-mix(in srgb, var(--z) 55%, transparent),
3px 0 20px -3px color-mix(in srgb, var(--z) 42%, transparent);
z-index: 2;
}
.ki-kasten::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background:
linear-gradient(112deg,
transparent 24%,
rgba(255, 255, 255, .045) 40%,
rgba(255, 255, 255, .08) 47%,
rgba(255, 255, 255, .025) 55%,
transparent 70%);
/* KEINE Körnung auf DIESER Ebene (07.09.2026, gemessen).
Sie stand hier als zweite Schicht und hat die Deckkraft der
Spiegelung geerbt -- 50 % eines mittelgrauen Rauschens heben jeden
Bildpunkt um rund 30 Stufen an. Gemessen: rgb(56,44,58) statt der
berechneten rgb(20,26,38), und über einer hellen Stelle des
Motivs rgb(85,83,81). Die Karte sah dadurch durchsichtig aus,
obwohl sie zu 95 % deckt.
Derselbe Fehler wie an der Anmeldekarte heute Nachmittag, und
genau derselbe Grund: Körnung gehört auf eine EIGENE Ebene mit
`mix-blend-mode: overlay` und 3 bis 4 Prozent -- so wie bei den
Kacheln der Startseite. Auf einer geteilten Ebene ist sie kein
Material, sondern ein grauer Schleier. */
opacity: .5;
}
.ki-kasten > * { position: relative; z-index: 1; }
/* Der Zustand steckt wieder in EINER Größe. */
.ki-kasten[data-zustand="laeuft"] { --z: var(--violett); }
.ki-kasten[data-zustand="weg"] { --z: var(--k-warn); }
.ki-kasten__daten { gap: 10px; }
.ki-kasten__daten li {
padding: 9px 12px;
border-radius: var(--radius-klein);
background: rgba(0, 0, 0, .28);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
align-items: baseline;
}
@media (forced-colors: active) {
.ki-kasten { background: Canvas; box-shadow: none; border: 1px solid CanvasText; }
.ki-kasten::after { display: none; }
}
+120
View File
@@ -224,3 +224,123 @@
.zeitblock { border: 1px solid CanvasText; } .zeitblock { border: 1px solid CanvasText; }
.zeitblock__zahl { border: 1px solid CanvasText; } .zeitblock__zahl { border: 1px solid CanvasText; }
} }
/* =====================================================================
CALLS & PROTOKOLLE — übersichtlicher (07.09.2026)
Wunsch Filipe: "ich will dass du diese komplette seite viel
übersichtlicher machst ... total übersichtlich und hoch profissionell."
---------------------------------------------------------------------
WAS AN DER SEITE UNÜBERSICHTLICH WAR
Nicht die Menge -- 27 anstehende Gespräche sind viele, aber sie waren
schon sauber gruppiert. Unübersichtlich waren DREI Dinge, und alle
drei sind Abstände, keine Inhalte:
1. ALLES STAND GLEICH WEIT AUSEINANDER. Zwischen zwei Karten
derselben Woche lag derselbe Abstand wie zwischen zwei Gruppen.
Damit sieht man die Gliederung nicht mehr -- man liest eine
lange Reihe statt drei Blöcke. Jetzt: 10 px innerhalb einer
Gruppe, 32 px zwischen Gruppen, und die Gruppenüberschrift
bekommt eine eigene Linie.
2. DIE KARTEN WAREN FAST DURCHSICHTIG. Auf einem Bild mit einem
großen hellen Logo bedeutet das: Der Untergrund kämpft mit dem
Text. Sie bekommen jetzt dasselbe Material wie überall --
beleuchtete Platte, Leuchtschiene in der Farbe ihres Zustands.
3. DER ZUSTAND STAND NUR IN DER FARBE. "Protokoll fehlt" war ein
bernsteinfarbener Strich am Rand. Farbe allein ist nie genug --
die Schiene bleibt, aber die Karte trägt den Zustand ohnehin
schon als Wort in ihrer Marke.
Die Farben sind dieselben wie im ganzen Haus: Bernstein = wartet,
Blau = steht an, Grün = erledigt.
===================================================================== */
.gruppe { margin-bottom: 34px; }
/* Die Gruppenüberschrift bekommt eine Grundlinie über die ganze Breite
-- das ist der billigste und stärkste Trick für Gliederung: Das Auge
sieht einen Block, bevor es ein Wort gelesen hat. */
.gruppe > .stufe {
padding-bottom: 10px;
border-bottom: 1px solid rgba(150, 186, 220, .12);
}
.gruppe__karten { gap: 10px; margin-top: 14px; }
.call {
--c: var(--akzent);
padding: 16px 18px 16px 22px;
border-radius: 3px 16px 16px 3px;
border-color: color-mix(in srgb, var(--c) 16%, rgba(150, 186, 220, .12));
background:
linear-gradient(90deg,
color-mix(in srgb, var(--c) 20%, transparent) 0%,
color-mix(in srgb, var(--c) 6%, transparent) 14%,
color-mix(in srgb, var(--c) 2%, transparent) 30%,
transparent 50%),
linear-gradient(163deg,
rgba(21, 28, 41, .95) 0%,
rgba(11, 15, 24, .95) 62%,
rgba(8, 11, 18, .95) 100%);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .075),
inset 0 -1px 0 rgba(0, 0, 0, .45),
0 2px 4px -2px rgba(0, 0, 0, .5),
0 12px 26px -18px rgba(0, 0, 0, .85);
transition: border-color var(--tempo), transform var(--tempo), box-shadow var(--tempo);
}
/* Die Schiene läuft über die ganze Höhe, nicht mit 10 px Luft oben und
unten. Ein Strich, der vor der Ecke aufhört, sieht aus wie ein
Fehler; einer, der durchgeht, sieht aus wie Bauweise. */
.call::before {
top: 0; bottom: 0; width: 3px;
border-radius: 3px 0 0 3px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--c) 80%, transparent) 0%,
color-mix(in srgb, var(--c) 42%, transparent) 100%);
opacity: .75;
transition: opacity var(--tempo);
}
.call[data-gruppe="offen"] { --c: #f0c48a; }
.call[data-gruppe="anstehend"] { --c: var(--akzent); }
.call[data-gruppe="erledigt"] { --c: #79d1a2; }
/* Die alten Sonderregeln setzten Fläche und Strichfarbe getrennt --
jetzt steckt beides in --c. Diese eine Zeile ersetzt vier. */
.call[data-gruppe="offen"]::before,
.call[data-gruppe="anstehend"]::before,
.call[data-gruppe="erledigt"]::before { background: linear-gradient(180deg,
color-mix(in srgb, var(--c) 80%, transparent) 0%,
color-mix(in srgb, var(--c) 42%, transparent) 100%); }
/* Erledigtes tritt zurück -- aber über die Fläche, nicht über die
Schriftdeckkraft. `opacity` auf der ganzen Karte hätte auch den Text
erfasst, und genau dieser Fehler hat am 07.09. an anderer Stelle
einen Kontrast unter die Schwelle gedrückt. */
.call[data-gruppe="erledigt"] {
opacity: 1;
border-color: rgba(150, 186, 220, .10);
}
.call[data-gruppe="erledigt"]::before { opacity: .5; }
.call:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--c) 34%, rgba(150, 186, 220, .16));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .45),
0 4px 9px -4px rgba(0, 0, 0, .55),
0 18px 36px -20px rgba(0, 0, 0, .9);
}
.call:hover::before { opacity: 1; }
.call__titel { font-size: 1.05rem; font-weight: 700; color: #eaf2fb; }
.call__zeit { color: var(--text-leise); font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
.call, .call:hover { transform: none; }
}
@media (forced-colors: active) {
.call { background: Canvas; box-shadow: none; border: 1px solid CanvasText; }
}
+71
View File
@@ -1679,3 +1679,74 @@ body.gate {
inset 0 0 18px -8px color-mix(in srgb, var(--akzent) 85%, transparent); inset 0 0 18px -8px color-mix(in srgb, var(--akzent) 85%, transparent);
} }
} }
/* =====================================================================
DER TEILEN-KNOPF (07.09.2026)
Er sitzt links in der rechten Knopfgruppe und sieht aus wie ihre
Nachbarn -- dieselbe Höhe, derselbe geschliffene Rand, dieselbe
Schrift. Ein Knopf, der aus der Reihe tanzt, sagt "nachträglich
eingebaut", und genau das soll er nicht sagen.
Der einzige Unterschied ist die Farbe: --f wird auf Violett gesetzt.
Alle anderen Knöpfe der Leiste tragen den Hausakzent; ein zweiter
Ton macht diesen einen auffindbar, ohne ihn lauter zu machen.
BEIM GELINGEN WECHSELT DER TEXT, NICHT DIE FARBE ALLEIN. "Kopiert"
steht als Wort da -- eine Rückmeldung, die nur aus einem Farbwechsel
besteht, kommt bei niemandem an, der Farben schlecht unterscheidet.
===================================================================== */
.teilen {
--f: var(--violett);
position: relative;
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
min-height: 38px; padding: 8px 14px;
border: 1px solid transparent;
border-radius: 11px;
background:
linear-gradient(#121926, #0d1420) padding-box,
linear-gradient(150deg,
color-mix(in srgb, var(--f) 70%, transparent),
rgba(255, 255, 255, .07) 52%,
color-mix(in srgb, var(--f) 28%, transparent)) border-box;
color: color-mix(in srgb, var(--f) 45%, #ffffff);
font: inherit; font-size: .85rem; font-weight: 600;
cursor: pointer;
transition: transform .16s ease, box-shadow .2s ease, color .16s ease;
}
.teilen:hover {
color: #fff;
transform: translateY(-1px);
box-shadow: 0 8px 20px -12px color-mix(in srgb, var(--f) 85%, transparent);
}
.teilen:active { transform: translateY(0); }
.teilen:focus-visible { outline: 2px solid var(--f); outline-offset: 2px; }
/* Geschafft: der Rand wird grün, das Wort sagt es zusätzlich. */
.teilen[data-fertig="ja"] {
--f: var(--k-gut);
color: color-mix(in srgb, var(--k-gut) 40%, #ffffff);
}
.teilen__zeichen {
width: 16px; height: 16px; flex: none;
fill: none; stroke: currentColor;
stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
@media (max-width: 720px) {
/* Auf schmalen Geräten nur das Zeichen. Die Kopfleiste ist am
06.09.2026 schon einmal an einem Element zu viel zerbrochen --
dieser Knopf kommt deshalb von vornherein mit 38 px aus, statt
eine feste Umbruchschwelle noch einmal zu verschieben. */
.teilen { padding: 8px 10px; }
.teilen__text {
position: absolute;
width: 1px; height: 1px; margin: -1px; padding: 0;
overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
}
@media (prefers-reduced-motion: reduce) {
.teilen, .teilen:hover, .teilen:active { transform: none; }
}
@media (forced-colors: active) {
.teilen { border: 1px solid ButtonText; background: ButtonFace; color: ButtonText; }
}
+280 -1
View File
@@ -646,6 +646,15 @@ body.start > main { position: relative; z-index: 1; }
gap: 12px; flex-wrap: wrap; margin-bottom: 8px; gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
} }
.klapp-kopf > .feldschild, .klapp-kopf > .block__titel { margin: 0; } .klapp-kopf > .feldschild, .klapp-kopf > .block__titel { margin: 0; }
/* Zwei Knöpfe rechts im Kopf einer Liste: der stille Schalter und die
Hauptaktion. Eigener Behälter, damit sie beim Umbruch ZUSAMMEN
umbrechen -- sonst steht auf schmalen Geräten der Schalter allein in
einer Zeile und die Hauptaktion in der nächsten. */
.klapp-kopf__knoepfe {
display: flex; align-items: center; gap: 10px;
flex-wrap: wrap; justify-content: flex-end;
margin-left: auto;
}
.klapp-pfeil { .klapp-pfeil {
width: 14px; height: 14px; flex: 0 0 auto; width: 14px; height: 14px; flex: 0 0 auto;
@@ -659,6 +668,15 @@ body.start > main { position: relative; z-index: 1; }
statt ueber das Entfernen von Zeilen: Das Aufklappen braucht dann statt ueber das Entfernen von Zeilen: Das Aufklappen braucht dann
weder einen neuen Aufbau noch eine zweite Abfrage. */ weder einen neuen Aufbau noch eine zweite Abfrage. */
[data-klapp="zu"] > *:nth-child(n+5) { display: none; } [data-klapp="zu"] > *:nth-child(n+5) { display: none; }
/* SIEBEN STATT VIER -- fuer Listen, bei denen die Woche die Einheit ist
(07.09.2026, Wunsch Filipe zur Tagesliste: "man soll immer noch die
letzten 7 tage sehen"). Vier Tage sind kein Zeitraum, ueber den man
etwas sagen kann; sieben sind eine Woche und damit vergleichbar.
Eine zweite Regel und keine gerechnete Zahl: `nth-child` nimmt keine
CSS-Variable. Zwei feste Werte, die beide im Quelltext stehen, sind
ehrlicher als eine Zahl, die man im Stil sucht und im Skript findet. */
[data-klapp="zu7"] > *:nth-child(n+8) { display: none; }
.willkommen { margin-bottom: 38px; } .willkommen { margin-bottom: 38px; }
.willkommen .titel { margin-bottom: 6px; } .willkommen .titel { margin-bottom: 6px; }
@@ -1231,7 +1249,12 @@ body.start > main { position: relative; z-index: 1; }
/* Die Seite ist breit, damit die Kacheln Platz haben. Eine Zeile Text /* Die Seite ist breit, damit die Kacheln Platz haben. Eine Zeile Text
ueber 1240 px zu ziehen macht sie aber nicht lesbarer, sondern ueber 1240 px zu ziehen macht sie aber nicht lesbarer, sondern
anstrengender -- Hinweise und Begruessung behalten deshalb ihr Mass. */ anstrengender -- Hinweise und Begruessung behalten deshalb ihr Mass. */
.willkommen, .dran__liste, .inhalt .fuss { max-width: 940px; } /* .willkommen ist seit dem 07.09.2026 eine KACHEL und keine Textzeile
mehr. Eine Textzeile begrenzt man auf 940 px, weil lange Zeilen
schlecht zu lesen sind; eine Kachel, die 200 px vor allen anderen
endet, sieht dagegen aus, als sei sie danebengerutscht. Der Text
darin bleibt kurz -- die Begrenzung hat er nie gebraucht. */
.dran__liste, .inhalt .fuss { max-width: 940px; }
.dran { margin-bottom: 30px; } .dran { margin-bottom: 30px; }
.dran__liste { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; } .dran__liste { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
@@ -4240,3 +4263,259 @@ body[data-fremde-sicht="ja"]::after {
.kachel > .kachel__link::before, .kachel > .kachel__link::before,
.kachel__zeichen::after { display: none; } .kachel__zeichen::after { display: none; }
} }
/* =====================================================================
DIE BEGRÜSSUNGSKACHEL — mit Uhr und Glocke (07.09.2026)
Wunsch Filipe: "ich will dass diese kacheln da auch übertrieben geil
gemacht wird, wirklich seeeeeehr hochwertig mit einer runden
digitalen uhr rechts in der kachel ... und der benachrichtigungs
button soll auch von der leiste in diese kachel gesetzt werden."
---------------------------------------------------------------------
WARUM DIE UHR HIER RICHTIG IST UND NICHT NUR SCHÖN
Eine Uhr ist die einzige Angabe auf dieser Seite, die sich ändert,
während man hinsieht. Genau das macht sie wertvoll: Sie sagt ohne ein
Wort, dass die Seite LEBT -- dass die Zahlen daneben von jetzt sind
und nicht von gestern Nacht. Eine Oberfläche, bei der man das nicht
weiß, prüft man ständig nach.
Und sie steht neben dem Datum, das ohnehin dort steht. Zwei Angaben
zur selben Frage gehören zusammen; das Datum oben und die Uhrzeit in
der Fußzeile wären zwei halbe Antworten.
---------------------------------------------------------------------
ZWEI RINGE, NICHT EINER
Der innere Ring füllt sich in einer Minute, der äußere in einer
Stunde. Das ist der Unterschied zwischen "eine Uhr, die tickt" und
"eine Uhr, an der man den Stand der Stunde sieht" -- man erkennt aus
dem Augenwinkel, ob die Stunde jung ist oder gleich vorbei.
Der Sekundenring läuft NICHT weich. Ein weicher Zeiger sieht teurer
aus, kostet aber eine Bildberechnung pro Bild statt einer pro
Sekunde, und auf einer Seite, die stundenlang offen steht, ist das
der Unterschied zwischen einem warmen und einem kalten Rechner.
Der Sprung ist außerdem ehrlicher: Die Anzeige ist digital.
===================================================================== */
/* Die Kachel selbst: dasselbe Material wie die Bereichskacheln, damit
nicht zwei Oberflächen nebeneinanderliegen. Sie hat KEINE eigene
Farbschiene -- sie gehört zu keiner Kategorie, sie ist der Anfang. */
.willkommen {
position: relative;
padding: 22px 24px;
border: 1px solid var(--rand);
border-radius: 4px 20px 20px 4px;
background:
linear-gradient(90deg,
rgba(63, 189, 245, .10) 0%,
rgba(63, 189, 245, .03) 14%,
transparent 40%),
linear-gradient(163deg,
rgba(23, 31, 45, .95) 0%,
rgba(11, 15, 24, .95) 58%,
rgba(8, 11, 18, .95) 100%);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
inset 0 -1px 0 rgba(0, 0, 0, .50),
inset 2px 0 0 -1px color-mix(in srgb, var(--akzent) 34%, transparent),
0 2px 5px -2px rgba(0, 0, 0, .55),
0 16px 34px -20px rgba(0, 0, 0, .88);
overflow: hidden;
}
/* Die Leuchtschiene links -- dieselbe Sprache wie überall, hier im
Hausakzent statt in einer Kategoriefarbe. */
.willkommen::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
border-radius: 4px 0 0 4px;
background: linear-gradient(180deg,
color-mix(in srgb, var(--akzent) 55%, #fff) 0%,
var(--akzent) 26%,
color-mix(in srgb, var(--akzent) 50%, transparent) 100%);
box-shadow:
0 0 9px 0 color-mix(in srgb, var(--akzent) 55%, transparent),
3px 0 20px -3px color-mix(in srgb, var(--akzent) 42%, transparent);
opacity: .9;
z-index: 2;
}
/* Körnung und ein fester Glanz. Kein wandernder wie bei den Kacheln:
Diese Fläche wird nicht angeklickt, also gibt es nichts zu quittieren. */
.willkommen::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
border-radius: inherit;
background:
linear-gradient(104deg,
transparent 26%,
rgba(255, 255, 255, .05) 40%,
rgba(255, 255, 255, .085) 47%,
rgba(255, 255, 255, .03) 55%,
transparent 70%);
/* KEINE Körnung auf DIESER Ebene (07.09.2026, gemessen).
Sie stand hier als zweite Schicht und hat die Deckkraft der
Spiegelung geerbt -- 50 % eines mittelgrauen Rauschens heben jeden
Bildpunkt um rund 30 Stufen an. Gemessen: rgb(56,44,58) statt der
berechneten rgb(20,26,38), und über einer hellen Stelle des
Motivs rgb(85,83,81). Die Karte sah dadurch durchsichtig aus,
obwohl sie zu 95 % deckt.
Derselbe Fehler wie an der Anmeldekarte heute Nachmittag, und
genau derselbe Grund: Körnung gehört auf eine EIGENE Ebene mit
`mix-blend-mode: overlay` und 3 bis 4 Prozent -- so wie bei den
Kacheln der Startseite. Auf einer geteilten Ebene ist sie kein
Material, sondern ein grauer Schleier. */
opacity: .5;
}
.willkommen > * { position: relative; z-index: 1; }
.willkommen__reihe {
display: flex; align-items: center; gap: 16px;
flex-wrap: wrap;
}
.willkommen__text { min-width: 0; flex: 1 1 260px; }
/* Rechts: Glocke neben der Uhr, beide rechtsbündig. `margin-left: auto`
statt `justify-content: space-between` am Elternteil -- so bleibt die
Gruppe auch dann rechts, wenn der Text davor kurz ist. */
.willkommen__rechts {
display: flex; align-items: center; gap: 14px;
margin-left: auto; flex: 0 0 auto;
}
/* DER PLATZ WIRD RESERVIERT, NICHT NACHTRÄGLICH GENOMMEN.
Hier stand `:empty { display: none }` -- und das ist genau der Fehler,
den die Kachel darunter schon einmal gemacht hat: Die Glocke wird
erst nach der ersten Abfrage eingehängt, und bis dahin war der Platz
0 px breit. In dem Moment, in dem sie erscheint, wächst die Zeile,
und alles darunter rutscht.
Ein Sprung ist kein Schönheitsfehler, sondern der Grund, warum man
auf den falschen Knopf drückt: Man zielt auf etwas, und im Moment des
Klicks rutscht es weg. Gemessen von pruef-tempo-workspace.
Also 46 px, immer -- ob die Glocke kommt oder nicht. Auf Geräten, auf
denen es sie gar nicht gibt (iPhone im Browser), bleibt ein leerer
Streifen neben der Uhr; das ist der Preis, und er ist niedriger als
ein springendes Bild. */
.glocke-platz { width: 46px; height: 46px; flex: none; }
/* ---------- Die Uhr -------------------------------------------------- */
.uhr {
position: relative;
width: 108px; height: 108px; flex: none;
display: grid; place-items: center;
border-radius: 50%;
/* Das Gehäuse: außen ein Lichtsaum, innen eine dunkle Scheibe. */
background:
radial-gradient(circle at 50% 34%, rgba(255, 255, 255, .05), transparent 62%),
radial-gradient(circle at 50% 50%, #0d131f 62%, #070a11 100%);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .12),
inset 0 -2px 6px -3px rgba(0, 0, 0, .9),
0 0 0 1px rgba(150, 186, 220, .10),
0 10px 24px -14px rgba(0, 0, 0, .9);
}
/* Die Skala: sechzig feine Striche, aus EINEM sich wiederholenden
Kegelverlauf. Sechzig Elemente im HTML wären dieselbe Optik mit
sechzig Elementen mehr im Baum. */
.uhr__skala {
position: absolute; inset: 7px; border-radius: 50%;
background: repeating-conic-gradient(from 0deg,
rgba(150, 186, 220, .30) 0deg 0.5deg,
transparent 0.5deg 6deg);
/* Nur ein schmaler Ring davon ist zu sehen -- der Rest wird
ausgestanzt. */
-webkit-mask: radial-gradient(circle, transparent 0 76%, #000 76% 84%, transparent 84%);
mask: radial-gradient(circle, transparent 0 76%, #000 76% 84%, transparent 84%);
opacity: .5;
pointer-events: none;
}
/* Die Glasscheibe: eine Spiegelung von oben links über der Kuppe. */
.uhr__glas {
position: absolute; inset: 0; border-radius: 50%;
background: linear-gradient(148deg,
rgba(255, 255, 255, .10) 0%,
rgba(255, 255, 255, .025) 22%,
transparent 46%);
pointer-events: none;
}
.uhr__ring {
position: absolute; inset: 0; width: 100%; height: 100%;
/* Bei Null soll der Ring OBEN beginnen, nicht rechts. */
transform: rotate(-90deg);
}
.uhr__bahn, .uhr__minute, .uhr__zeiger {
fill: none; stroke-linecap: round;
stroke-dasharray: 276.46;
}
.uhr__bahn { stroke: rgba(150, 186, 220, .11); stroke-width: 3.5; }
/* Der Stundenstand: gedeckt, breit, ruhig -- er ändert sich einmal pro
Minute und darf nicht um Aufmerksamkeit bitten. */
.uhr__minute {
stroke: color-mix(in srgb, var(--violett) 62%, transparent);
stroke-width: 3.5;
stroke-dashoffset: 276.46;
}
/* Die Sekunde: schmaler, heller, mit einem Hauch Leuchten. */
.uhr__zeiger {
stroke: var(--akzent); stroke-width: 2.2;
stroke-dashoffset: 276.46;
filter: drop-shadow(0 0 3px color-mix(in srgb, var(--akzent) 70%, transparent));
}
.uhr__mitte { display: grid; justify-items: center; gap: 1px; line-height: 1; }
.uhr__zeit {
font-size: 1.42rem; font-weight: 700; letter-spacing: -.01em;
/* Gleiche Zifferbreite: Ohne sie zappelt die Anzeige bei jedem
Minutenwechsel, weil die 1 schmaler ist als die 8. */
font-variant-numeric: tabular-nums;
color: #eaf2fb;
text-shadow: 0 0 18px rgba(63, 189, 245, .28);
}
.uhr__sek {
font-size: .72rem; font-weight: 600;
font-variant-numeric: tabular-nums;
letter-spacing: .16em; text-indent: .16em;
color: color-mix(in srgb, var(--akzent) 55%, #ffffff);
}
/* ---------- Die Glocke, wenn sie in der Kachel sitzt ------------------ */
/* In der Leiste ist sie ein Knopf unter Knöpfen. Hier steht sie allein
neben der Uhr und wird deshalb rund -- sie nimmt die Form ihrer
Nachbarin auf, statt als Rechteck danebenzustehen. */
.glocke--kachel {
width: 46px; height: 46px; padding: 0;
border-radius: 50%;
justify-content: center;
}
.glocke--kachel .glocke__text {
/* Der Text bleibt für Vorleseprogramme da, verschwindet aber vom
Bildschirm: Neben einer Uhr ist Platz für ein Zeichen, nicht für
eine Beschriftung. */
position: absolute;
width: 1px; height: 1px; margin: -1px; padding: 0;
overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.glocke--kachel .glocke__zeichen { width: 19px; height: 19px; }
@media (max-width: 620px) {
/* Auf dem Handy rückt die Gruppe unter den Gruß und die Uhr wird
kleiner -- 108 px neben einer Überschrift lassen für den Namen
keine Zeile mehr übrig. */
.willkommen { padding: 18px 16px; }
.willkommen__rechts { margin-left: 0; width: 100%; justify-content: flex-start; }
.uhr { width: 88px; height: 88px; }
.uhr__zeit { font-size: 1.18rem; }
}
@media (prefers-reduced-motion: reduce) {
/* Die Uhr springt ohnehin -- hier gibt es nichts abzuschalten. Die
Zeile steht trotzdem da, damit der nächste, der einen weichen
Zeiger einbaut, sie findet. */
.uhr__zeiger, .uhr__minute { transition: none; }
}
@media (forced-colors: active) {
.uhr { background: Canvas; box-shadow: none; border: 1px solid CanvasText; }
.uhr__skala, .uhr__glas { display: none; }
}
+22 -2
View File
@@ -267,11 +267,31 @@
$('sicherungen-schalter').hidden = true; $('sicherungen-schalter').hidden = true;
return; return;
} }
/* DAS DATUM WIRD GESUCHT, NICHT ZUSAMMENGESETZT (07.09.2026).
Hier stand `name.split('-').slice(1).reverse().join('.')`. Bei
"woechentlich-2026-09-06.db" ging das gut. Die Sicherungen vor
einem Umbau heissen aber "vorher-2026-09-02-160012438.db" -- mit
einem Zeitstempel hinten dran. Aus derselben Rechnung wurde dann
"160012438.02.09.2026": eine Zeichenkette, die dreimal so lang
ist wie die Spalte und ueber den Nachbartext lief. Genau das hat
Filipe im Bildschirmfoto gesehen.
Ein Muster, das die Bestandteile ZAEHLT statt sie zu SUCHEN,
bricht beim ersten Namen, der einen Teil mehr hat. Deshalb jetzt
ein Suchmuster nach vier-zwei-zwei Ziffern -- egal, was davor
oder dahinter steht. */
for (const s of z.sicherungen) { for (const s of z.sicherungen) {
const roh = s.name.replace(/\.db$/, '');
const t = roh.match(/(\d{4})-(\d{2})-(\d{2})/);
const zeile = el('div', 'verlauf__zeile'); const zeile = el('div', 'verlauf__zeile');
zeile.append(el('span', 'verlauf__zeit', s.name.replace(/\.db$/, '').split('-').slice(1).reverse().join('.'))); /* Findet sich kein Datum, wird das GESAGT und nicht geraten --
zeile.append(el('span', 'verlauf__was', s.name.split('-')[0])); ein erfundenes Datum an einer Sicherung waere schlimmer als
ein Strich. */
zeile.append(el('span', 'verlauf__zeit', t ? `${t[3]}.${t[2]}.${t[1]}` : '—'));
zeile.append(el('span', 'verlauf__was', roh.split('-')[0]));
zeile.append(el('span', 'verlauf__wer', bytes(s.groesse))); zeile.append(el('span', 'verlauf__wer', bytes(s.groesse)));
zeile.title = s.name; // der volle Name bleibt erreichbar
liste.append(zeile); liste.append(zeile);
} }
window.klappe?.(liste, $('sicherungen-schalter'), $('sicherungen-schalter-text')); window.klappe?.(liste, $('sicherungen-schalter'), $('sicherungen-schalter-text'));
+14 -3
View File
@@ -364,14 +364,25 @@
(Orangerot) darunter. Wer diese Gruppe umsortiert, lässt (Orangerot) darunter. Wer diese Gruppe umsortiert, lässt
tools/kachel-farben.mjs neu laufen -- die Nachbarschaften tools/kachel-farben.mjs neu laufen -- die Nachbarschaften
haben sich durch diese Kachel geändert. */ haben sich durch diese Kachel geändert. */
{ name: 'Zahlen', unter: 'Diamanten, LIVE-Tage, Verweildauer', zeichen: 'zahlen', ton: 2, /* REIHENFOLGE: STECKBRIEF, PROFILE, ZAHLEN (Wunsch Filipe,
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'leistung.html', szene: 'arena' }, 07.09.2026: "zuerst steckbrief, dan, profile, und dan erst
zahlen"). Das ist auch die Reihenfolge, in der man arbeitet:
erst wer jemand IST, dann was er vorhat, dann was dabei
herauskommt. Die Zahlen zuerst zu zeigen dreht das um. */
{ name: 'Mein Steckbrief', unter: 'Dein Bild und deine Kanäle', zeichen: 'steckbrief', ton: 10, { name: 'Mein Steckbrief', unter: 'Dein Bild und deine Kanäle', zeichen: 'steckbrief', ton: 10,
rollen: ['admin', 'manager', 'scout'], ziel: 'steckbrief.html', szene: 'halle' }, rollen: ['admin', 'manager', 'scout'], ziel: 'steckbrief.html', szene: 'halle' },
{ name: 'Creator-Profile', unter: 'Ziele und 90-Tage-Plan', zeichen: 'profil', ton: 20, { name: 'Creator-Profile', unter: 'Ziele und 90-Tage-Plan', zeichen: 'profil', ton: 20,
rollen: ['admin', 'manager', 'scout'], ziel: 'profil.html', szene: 'halle' }, rollen: ['admin', 'manager', 'scout'], ziel: 'profil.html', szene: 'halle' },
{ name: 'Mein Profil', unter: 'Dein Steckbrief, Ziele und Pläne', zeichen: 'profil', ton: 20, /* KEINE eigene Steckbrief-Kachel fuer Creator, und das ist
Absicht: Ihr Steckbrief samt Profilbild steht bereits auf
`profil.html` (der Block mit `data-nur-creator="ja"`). Eine
zweite Kachel fuehrte auf dieselbe Sache unter anderem Namen
-- und wer zwei Wege zu einer Einstellung anbietet, bekommt
die Frage, welcher der richtige ist. */
{ name: 'Mein Profil', unter: 'Dein Bild, deine Ziele und Pläne', zeichen: 'profil', ton: 20,
rollen: ['creator'], ziel: 'profil.html', szene: 'halle' }, rollen: ['creator'], ziel: 'profil.html', szene: 'halle' },
{ name: 'Zahlen', unter: 'Diamanten, LIVE-Tage, Verweildauer', zeichen: 'zahlen', ton: 2,
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'leistung.html', szene: 'arena' },
{ name: 'Start-Check', unter: 'Erstanalyse, 16 Punkte', zeichen: 'startcheck', ton: 16, { name: 'Start-Check', unter: 'Erstanalyse, 16 Punkte', zeichen: 'startcheck', ton: 16,
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'startcheck.html', szene: 'wald' }, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'startcheck.html', szene: 'wald' },
{ name: 'LIVE-Analyse', unter: 'Vorher, während, danach', zeichen: 'live', ton: 3, { name: 'LIVE-Analyse', unter: 'Vorher, während, danach', zeichen: 'live', ton: 3,
+21 -3
View File
@@ -174,7 +174,23 @@
} }
async function bauen() { async function bauen() {
const kopf = document.querySelector('.kopfleiste__rechts'); /* WO DIE GLOCKE HINGEHÖRT (07.09.2026, Wunsch Filipe: "der
benachrichtigungs button soll auch von der leiste in diese kachel
gesetzt werden").
Gibt es auf der Seite einen ausgewiesenen Platz, kommt sie
dorthin -- auf der Startseite in die Begrüßungskachel, neben die
Uhr. Das ist der richtige Ort: Benachrichtigungen sind eine
Einstellung zum eigenen Tag, keine Navigation.
Auf allen anderen Seiten gibt es diesen Platz nicht, und dort
bleibt die Leiste. Deshalb ein Rückfall und keine Umstellung:
Eine Glocke, die auf zwölf Seiten verschwindet, weil sie auf
einer umgezogen ist, wäre keine Verbesserung. Und weil die
Kopfleiste am 06.09. schon einmal an einem sechsten Element
zerbrochen ist, wird sie hier nebenbei um eines leichter. */
const platz = document.getElementById('glocke-platz');
const kopf = platz || document.querySelector('.kopfleiste__rechts');
if (!kopf || document.getElementById('glocke')) return; if (!kopf || document.getElementById('glocke')) return;
knopf = el('button', 'glocke'); knopf = el('button', 'glocke');
@@ -196,10 +212,12 @@
knopf.append(el('span', 'glocke__text', '…')); knopf.append(el('span', 'glocke__text', '…'));
/* VOR dem Abmelden-Knopf, nicht dahinter: Abmelden ist die letzte /* VOR dem Abmelden-Knopf, nicht dahinter: Abmelden ist die letzte
Handlung auf einer Seite und bleibt ganz rechts. */ Handlung auf einer Seite und bleibt ganz rechts. Im eigenen Platz
const abmeldenKnopf = kopf.querySelector('.abmelden'); gibt es nichts, wovor sie stehen müsste. */
const abmeldenKnopf = platz ? null : kopf.querySelector('.abmelden');
if (abmeldenKnopf) kopf.insertBefore(knopf, abmeldenKnopf); if (abmeldenKnopf) kopf.insertBefore(knopf, abmeldenKnopf);
else kopf.append(knopf); else kopf.append(knopf);
if (platz) knopf.classList.add('glocke--kachel');
knopf.addEventListener('click', async () => { knopf.addEventListener('click', async () => {
const l = lage(); const l = lage();
+110 -4
View File
@@ -54,8 +54,105 @@
/* Vorleseprogramme bekommen einen Satz statt drei Bruchstücke. */ /* Vorleseprogramme bekommen einen Satz statt drei Bruchstücke. */
ziel.setAttribute('aria-label', ziel.setAttribute('aria-label',
`Angemeldet als ${ich.name} in der Rolle ${ich.rolle_name || ich.rolle}`); `Angemeldet als ${ich.name} in der Rolle ${ich.rolle_name || ich.rolle}`);
teilenKnopf(ich);
}; };
/* ---------- Teilen ---------------------------------------------------
Wunsch Filipe (07.09.2026): "einen button oben in der leiste ... zum
teilen der seite, auch nur die scouts, manager und dogfather sollen
diesen button sehen und benutzen können."
WAS GETEILT WIRD, IST DIE ADRESSE DES WORKSPACE -- nicht die Seite,
auf der man gerade steht. Das ist kein Detail: Wer einen Link auf
`bereich.html?b=schutz` weitergibt, schickt jemanden auf eine Seite,
die er entweder gar nicht sehen darf oder die ohne Zusammenhang
verwirrt. Geteilt wird der Eingang.
WARUM NUR DIE LEITUNG. Ein Creator hat niemanden, dem er den
Workspace geben würde -- er ist der Eingeladene, nicht der
Einladende. Ein Knopf, den man hat und nie braucht, ist Ballast;
einer, den man drückt und der nichts Sinnvolles tut, ist schlimmer.
Durchgesetzt wird das an der Rolle aus /api/ich, also an derselben
Angabe, mit der der Server auch alles andere entscheidet.
ZWEI WEGE, EIN KNOPF. Wo es die Teilen-Funktion des Geräts gibt
(Handy, neuere Rechner), wird sie benutzt -- das ist der Weg, den
Filipe kennt. Wo nicht, landet die Adresse in der Zwischenablage
und der Knopf sagt "Kopiert". Kein Dialog, kein zweiter Klick.
Und wo auch das nicht geht (alte Browser, kein sicherer Kontext),
erscheint der Knopf gar nicht erst -- ein dritter Ausgang statt
einer Schaltfläche, die nichts tut. */
const DARF_TEILEN = new Set(['admin', 'manager', 'scout']);
function teilenKnopf(ich) {
const leiste = document.querySelector('.kopfleiste__rechts');
if (!leiste || document.getElementById('teilen')) return;
if (!DARF_TEILEN.has(ich.rolle)) return;
const kannTeilen = typeof navigator.share === 'function';
const kannKopieren = !!navigator.clipboard?.writeText;
if (!kannTeilen && !kannKopieren) return;
const k = document.createElement('button');
k.type = 'button';
k.id = 'teilen';
k.className = 'teilen';
k.title = 'Adresse des Workspace weitergeben';
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('class', 'teilen__zeichen');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('aria-hidden', 'true');
/* Drei Knoten, zwei Linien -- das Zeichen für "weitergeben". Als
Pfade und nicht als Schriftzeichen: Ein Emoji sieht auf jedem
Gerät anders aus und lässt sich nicht einfärben. */
svg.innerHTML =
'<circle cx="18" cy="5" r="2.6"/><circle cx="6" cy="12" r="2.6"/>'
+ '<circle cx="18" cy="19" r="2.6"/>'
+ '<path d="M8.3 10.8 15.7 6.6M8.3 13.2l7.4 4.2"/>';
k.append(svg);
const text = document.createElement('span');
text.className = 'teilen__text';
text.textContent = 'Teilen';
k.append(text);
const ZIEL = location.origin + '/workspace/';
let laeuft = false;
k.addEventListener('click', async () => {
if (laeuft) return;
laeuft = true;
try {
if (kannTeilen) {
await navigator.share({
title: 'Creator Workspace',
text: 'Der Creator Workspace von DogFather Universe',
url: ZIEL,
});
} else {
await navigator.clipboard.writeText(ZIEL);
const vorher = text.textContent;
text.textContent = 'Kopiert';
k.dataset.fertig = 'ja';
setTimeout(() => { text.textContent = vorher; delete k.dataset.fertig; }, 2200);
}
} catch (f) {
/* Ein Abbruch durch die Nutzerin ist KEIN Fehler und darf nicht
wie einer aussehen -- sie hat den Dialog absichtlich
geschlossen. Alles andere wird gemeldet. */
if (f?.name !== 'AbortError') {
text.textContent = 'Ging nicht';
setTimeout(() => { text.textContent = 'Teilen'; }, 2200);
}
} finally { laeuft = false; }
});
/* Ganz links in der rechten Gruppe: Teilen ist eine Nebenhandlung
und darf dem Abmelden nicht den Platz nehmen. */
leiste.prepend(k);
}
/* ---------- Auf- und Zuklappen langer Listen ------------------------- /* ---------- Auf- und Zuklappen langer Listen -------------------------
Lange Protokoll-Listen sind Nachschlagewerk, kein Startbild: Sie Lange Protokoll-Listen sind Nachschlagewerk, kein Startbild: Sie
@@ -69,14 +166,23 @@
Kinder die Zeilen sind), den Knopf und das Textfeld darin. Das Kinder die Zeilen sind), den Knopf und das Textfeld darin. Das
Ausblenden macht CSS ueber [data-klapp="zu"] -- ohne Neuaufbau und Ausblenden macht CSS ueber [data-klapp="zu"] -- ohne Neuaufbau und
ohne zweite Abfrage. */ ohne zweite Abfrage. */
/* Zwei Sichtbarkeitsstufen, beide mit einer Regel im CSS:
4 der Normalfall -- eine Liste zum Nachschlagen
7 wo die Woche die Einheit ist (die Tagesliste der Zahlen)
Die Zahl ist der Schluessel zum passenden `data-klapp`-Wert; eine
unbekannte Zahl faellt auf 4 zurueck, statt still gar nichts zu
verbergen. */
const KLAPP_STUFEN = { 4: 'zu', 7: 'zu7' };
const KLAPP_ZU = 4; /* dieselbe Zahl steht im CSS als nth-child(n+5) */ const KLAPP_ZU = 4; /* dieselbe Zahl steht im CSS als nth-child(n+5) */
window.klappe = function (liste, knopf, textfeld) { window.klappe = function (liste, knopf, textfeld, wieviele = KLAPP_ZU) {
if (!liste || !knopf) return; if (!liste || !knopf) return;
const anzahl = liste.children.length; const anzahl = liste.children.length;
const stufe = KLAPP_STUFEN[wieviele] || 'zu';
const zeigt = KLAPP_STUFEN[wieviele] ? wieviele : KLAPP_ZU;
/* Ein Knopf, der nichts zu verbergen hat, verwirrt nur. */ /* Ein Knopf, der nichts zu verbergen hat, verwirrt nur. */
knopf.hidden = anzahl <= KLAPP_ZU; knopf.hidden = anzahl <= zeigt;
if (knopf.hidden) { liste.removeAttribute('data-klapp'); return; } if (knopf.hidden) { liste.removeAttribute('data-klapp'); return; }
/* Liest die Anzahl bei jedem Aufruf frisch aus der Liste, statt sie /* Liest die Anzahl bei jedem Aufruf frisch aus der Liste, statt sie
@@ -86,13 +192,13 @@
an einer Liste mit dreissig Zeilen. */ an einer Liste mit dreissig Zeilen. */
const stand = (offen) => { const stand = (offen) => {
if (offen) liste.removeAttribute('data-klapp'); if (offen) liste.removeAttribute('data-klapp');
else liste.dataset.klapp = 'zu'; else liste.dataset.klapp = stufe;
knopf.setAttribute('aria-expanded', offen ? 'true' : 'false'); knopf.setAttribute('aria-expanded', offen ? 'true' : 'false');
/* Der Knopf sagt, was er TUT, nicht wo man gerade ist -- und nennt /* Der Knopf sagt, was er TUT, nicht wo man gerade ist -- und nennt
die Zahl, damit man weiss, was dahintersteckt. */ die Zahl, damit man weiss, was dahintersteckt. */
if (textfeld) { if (textfeld) {
textfeld.textContent = offen textfeld.textContent = offen
? `Nur die letzten ${KLAPP_ZU}` ? `Nur die letzten ${zeigt}`
: `Alle ${liste.children.length} zeigen`; : `Alle ${liste.children.length} zeigen`;
} }
}; };
+16
View File
@@ -271,6 +271,22 @@
} }
ziel.append(zeile); ziel.append(zeile);
} }
/* ZUGEKLAPPT AUF SIEBEN TAGE (07.09.2026, Wunsch Filipe).
Vierzehn Zeilen sind zu viel fuers Hinsehen und zu wenig fuers
Nachschlagen -- man scrollt an ihnen vorbei, statt sie zu lesen.
Sieben ist die Woche: der kuerzeste Zeitraum, ueber den man
ueberhaupt etwas sagen kann, und genau der, mit dem der
Wochenbericht rechnet. Die restlichen sieben Tage sind einen
Klick entfernt und verschwinden nicht.
Die Sieben steht nicht hier, sondern als eigene Regel im CSS
(`[data-klapp="zu7"]`) -- der Schalter kennt beide Stufen und
benennt sie im Knopftext, damit niemand raten muss, wie viel
gerade verborgen ist. */
window.klappe?.(ziel, document.getElementById('tage-schalter'),
document.getElementById('tage-schalter-text'), 7);
} }
function wert(name, text) { function wert(name, text) {
+41
View File
@@ -278,6 +278,46 @@
0: 'Wochenende', 0: 'Wochenende',
}; };
/* ---------- Die Uhr in der Begrüßungskachel -------------------------
Zwei Ringe um dieselbe Mitte: der äußere zeigt die Minute in der
Stunde, der innere die Sekunde. Beides als SVG-Kreis mit
`stroke-dasharray` -- ein Kegelverlauf (conic-gradient) hätte an
der Naht eine sichtbare Kante, ein Kreisbogen nicht.
UMFANG = 2 * pi * 44 = 276.46. Die Zahl steht hier ausgerechnet und
nicht als Formel im Stil: Ändert jemand den Radius im HTML, fällt
der Ring sofort auf, statt sich stillschweigend zu verrechnen.
KEIN setInterval(…, 1000). Ein Takt von genau einer Sekunde läuft
mit der Zeit aus dem Tritt (jeder Durchlauf kostet ein paar
Millisekunden), und die Anzeige springt dann gelegentlich zwei
Sekunden weiter. Stattdessen wird jedes Mal bis zur NÄCHSTEN vollen
Sekunde gewartet -- die Anzeige bleibt für immer im Takt der
Systemuhr. */
const UHR_UMFANG = 276.46;
function uhrStarten() {
const zeit = $('uhr-zeit'), sek = $('uhr-sek');
const zeiger = $('uhr-zeiger'), minute = $('uhr-minute');
if (!zeit || !zeiger) return;
const p = (n) => String(n).padStart(2, '0');
const takt = () => {
const j = new Date();
zeit.textContent = `${p(j.getHours())}:${p(j.getMinutes())}`;
sek.textContent = p(j.getSeconds());
/* Voll = kein Versatz. Der Ring wächst im Uhrzeigersinn, weil das
SVG im Stil um 90 Grad zurückgedreht ist. */
zeiger.style.strokeDashoffset = String(UHR_UMFANG * (1 - j.getSeconds() / 60));
if (minute) minute.style.strokeDashoffset = String(UHR_UMFANG * (1 - j.getMinutes() / 60));
/* Der volle Zeitpunkt für Vorleseprogramme -- sichtbar steht dort
nur die Uhrzeit, vorgelesen wird der ganze Satz. */
const uhr = $('uhr');
if (uhr) uhr.setAttribute('aria-label', `${p(j.getHours())}:${p(j.getMinutes())} Uhr`);
setTimeout(takt, 1000 - (Date.now() % 1000) + 8);
};
takt();
}
function grussZeigen() { function grussZeigen() {
const jetzt = new Date(); const jetzt = new Date();
const stunde = jetzt.getHours(); const stunde = jetzt.getHours();
@@ -391,6 +431,7 @@
window.werZeigen?.(ich); window.werZeigen?.(ich);
grussZeigen(); grussZeigen();
uhrStarten();
/* Die Hinweise zuerst -- die Kacheln brauchen ihre Zahlen. /* Die Hinweise zuerst -- die Kacheln brauchen ihre Zahlen.
Die Tagestermine laufen daneben her: Sie sind die rechte Hälfte Die Tagestermine laufen daneben her: Sie sind die rechte Hälfte
+8 -8
View File
@@ -9,9 +9,9 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -211,10 +211,10 @@
</form> </form>
</dialog> </dialog>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/aufgaben.js?v=202609070308" defer></script> <script src="assets/js/aufgaben.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/automation.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -134,10 +134,10 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/automation.js?v=202609070308" defer></script> <script src="assets/js/automation.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+13 -13
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/bereich.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -143,14 +143,14 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/checkliste.js?v=202609070308" defer></script> <script src="assets/js/checkliste.js?v=202609070334" defer></script>
<script src="assets/js/ampel.js?v=202609070308" defer></script> <script src="assets/js/ampel.js?v=202609070334" defer></script>
<script src="assets/js/schulung.js?v=202609070308" defer></script> <script src="assets/js/schulung.js?v=202609070334" defer></script>
<script src="assets/js/vorlagen.js?v=202609070308" defer></script> <script src="assets/js/vorlagen.js?v=202609070334" defer></script>
<script src="assets/js/bereich.js?v=202609070308" defer></script> <script src="assets/js/bereich.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+10 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/calls.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -76,11 +76,11 @@
</main> </main>
<script src="assets/js/ki.js?v=202609070308" defer></script> <script src="assets/js/ki.js?v=202609070334" defer></script>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/calls.js?v=202609070308" defer></script> <script src="assets/js/calls.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+8 -8
View File
@@ -9,16 +9,16 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog, <!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem .neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html. zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
Dialog zu sehen bekam. --> Dialog zu sehen bekam. -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/chat.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -154,9 +154,9 @@
</form> </form>
</dialog> </dialog>
<script src="assets/js/bereiche.js?v=202609070308"></script> <script src="assets/js/bereiche.js?v=202609070334"></script>
<script src="assets/js/kopf.js?v=202609070308"></script> <script src="assets/js/kopf.js?v=202609070334"></script>
<script src="assets/js/glocke.js?v=202609070308"></script> <script src="assets/js/glocke.js?v=202609070334"></script>
<script src="assets/js/chat.js?v=202609070308"></script> <script src="assets/js/chat.js?v=202609070334"></script>
</body> </body>
</html> </html>
+11 -11
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/content.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/content.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -166,12 +166,12 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/checkliste.js?v=202609070308" defer></script> <script src="assets/js/checkliste.js?v=202609070334" defer></script>
<script src="assets/js/vorlagen.js?v=202609070308" defer></script> <script src="assets/js/vorlagen.js?v=202609070334" defer></script>
<script src="assets/js/content.js?v=202609070308" defer></script> <script src="assets/js/content.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/dateien.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -95,10 +95,10 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/dateien.js?v=202609070308" defer></script> <script src="assets/js/dateien.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+2 -2
View File
@@ -27,7 +27,7 @@
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
</head> </head>
<body class="gate"> <body class="gate">
@@ -173,6 +173,6 @@
</main> </main>
</div> </div>
<script src="assets/js/gate.js?v=202609070308" defer></script> <script src="assets/js/gate.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+10 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/kalender.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -257,11 +257,11 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/kalender.js?v=202609070308" defer></script> <script src="assets/js/kalender.js?v=202609070334" defer></script>
<script src="assets/js/kalender-abo.js?v=202609070308" defer></script> <script src="assets/js/kalender-abo.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+22 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/leistung.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -77,7 +77,19 @@
<section class="leistung-tage" id="tage-block" hidden> <section class="leistung-tage" id="tage-block" hidden>
<div class="klapp-kopf"> <div class="klapp-kopf">
<p class="feldschild">Die letzten Tage</p> <p class="feldschild">Die letzten Tage</p>
<button type="button" class="knopf knopf--klein" id="import-oeffnen">Aus Datei einlesen</button> <!-- Zwei Knöpfe rechts: erst der Schalter (er ordnet die Liste),
dann die Hauptaktion. Der Schalter trägt bewusst die stille
Ausführung -- er verändert nichts an den Daten. -->
<div class="klapp-kopf__knoepfe">
<button type="button" class="knopf-still" id="tage-schalter"
aria-expanded="false" aria-controls="tagetabelle" hidden>
<span id="tage-schalter-text">Alle zeigen</span>
<svg class="klapp-pfeil" viewBox="0 0 24 24" aria-hidden="true">
<path d="m6 9.5 6 6 6-6" />
</svg>
</button>
<button type="button" class="knopf knopf--klein" id="import-oeffnen">Aus Datei einlesen</button>
</div>
</div> </div>
<div class="tagetabelle" id="tagetabelle"></div> <div class="tagetabelle" id="tagetabelle"></div>
</section> </section>
@@ -199,10 +211,10 @@
</form> </form>
</dialog> </dialog>
<script src="assets/js/wahl.js?v=202609070308"></script> <script src="assets/js/wahl.js?v=202609070334"></script>
<script src="assets/js/bereiche.js?v=202609070308"></script> <script src="assets/js/bereiche.js?v=202609070334"></script>
<script src="assets/js/kopf.js?v=202609070308"></script> <script src="assets/js/kopf.js?v=202609070334"></script>
<script src="assets/js/glocke.js?v=202609070308"></script> <script src="assets/js/glocke.js?v=202609070334"></script>
<script src="assets/js/leistung.js?v=202609070308"></script> <script src="assets/js/leistung.js?v=202609070334"></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/personen.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -123,10 +123,10 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/personen.js?v=202609070308" defer></script> <script src="assets/js/personen.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+10 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/profil.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -201,11 +201,11 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/steckbrief.js?v=202609070308" defer></script> <script src="assets/js/steckbrief.js?v=202609070334" defer></script>
<script src="assets/js/profil.js?v=202609070308" defer></script> <script src="assets/js/profil.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+10 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/report.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/report.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -93,11 +93,11 @@
</main> </main>
<script src="assets/js/ki.js?v=202609070308" defer></script> <script src="assets/js/ki.js?v=202609070334" defer></script>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/report.js?v=202609070308" defer></script> <script src="assets/js/report.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/scouting.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -126,10 +126,10 @@
</div> </div>
</div> </div>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/scouting.js?v=202609070308" defer></script> <script src="assets/js/scouting.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+34 -7
View File
@@ -9,8 +9,8 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -51,6 +51,33 @@
<span class="willkommen__lage" id="lage" hidden></span> <span class="willkommen__lage" id="lage" hidden></span>
</p> </p>
</div> </div>
<!-- ==== Rechts in der Kachel: Glocke und Uhr ==================
Die Glocke stand bisher in der Kopfleiste. Dort ist sie eine
von sechs Schaltflächen; hier ist sie das, was sie ist -- eine
Einstellung zum eigenen Tag, neben der Uhrzeit.
glocke.js setzt sie in `#glocke-platz`, wenn es den Platz auf
der Seite gibt, sonst weiterhin in die Leiste. -->
<div class="willkommen__rechts">
<div class="glocke-platz" id="glocke-platz"></div>
<!-- Die Uhr ist eine ANZEIGE, kein Bedienelement: role="timer"
mit aria-live="off". Eine Uhr, die sich jede Sekunde
vorlesen lässt, macht jede Vorleseausgabe unbenutzbar. -->
<div class="uhr" id="uhr" role="timer" aria-live="off">
<svg class="uhr__ring" viewBox="0 0 100 100" aria-hidden="true">
<circle class="uhr__bahn" cx="50" cy="50" r="44" />
<circle class="uhr__minute" cx="50" cy="50" r="44" id="uhr-minute" />
<circle class="uhr__zeiger" cx="50" cy="50" r="44" id="uhr-zeiger" />
</svg>
<span class="uhr__skala" aria-hidden="true"></span>
<span class="uhr__glas" aria-hidden="true"></span>
<div class="uhr__mitte">
<span class="uhr__zeit" id="uhr-zeit">--:--</span>
<span class="uhr__sek" id="uhr-sek">--</span>
</div>
</div>
</div>
</div> </div>
</section> </section>
@@ -160,10 +187,10 @@
</p> </p>
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/start.js?v=202609070308" defer></script> <script src="assets/js/start.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+10 -10
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/startcheck.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -72,11 +72,11 @@
</main> </main>
<script src="assets/js/ki.js?v=202609070308" defer></script> <script src="assets/js/ki.js?v=202609070334" defer></script>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/startcheck.js?v=202609070308" defer></script> <script src="assets/js/startcheck.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/profil.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -113,10 +113,10 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/steckbrief.js?v=202609070308" defer></script> <script src="assets/js/steckbrief.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+7 -7
View File
@@ -9,9 +9,9 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/uebersicht.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -82,10 +82,10 @@
</main> </main>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/uebersicht.js?v=202609070308" defer></script> <script src="assets/js/uebersicht.js?v=202609070334" defer></script>
</body> </body>
</html> </html>
+9 -9
View File
@@ -9,10 +9,10 @@
<meta name="theme-color" content="#0674b9" /> <meta name="theme-color" content="#0674b9" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" /> <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="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/gate.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/start.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/start.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/aufgaben.css?v=202609070334" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609070308" /> <link rel="stylesheet" href="assets/css/wissen.css?v=202609070334" />
</head> </head>
<body class="start"> <body class="start">
@@ -177,10 +177,10 @@
</main> </main>
<script src="assets/js/wahl.js?v=202609070308" defer></script> <script src="assets/js/wahl.js?v=202609070334" defer></script>
<script src="assets/js/bereiche.js?v=202609070308" defer></script> <script src="assets/js/bereiche.js?v=202609070334" defer></script>
<script src="assets/js/kopf.js?v=202609070308" defer></script> <script src="assets/js/kopf.js?v=202609070334" defer></script>
<script src="assets/js/glocke.js?v=202609070308" defer></script> <script src="assets/js/glocke.js?v=202609070334" defer></script>
<script src="assets/js/wissen.js?v=202609070308" defer></script> <script src="assets/js/wissen.js?v=202609070334" defer></script>
</body> </body>
</html> </html>