Kalender neu: vier Ansichten, Anlaesse und Feiertage, selbst gerechnet

Der Kalender war eine Liste mit drei Zeitraum-Knoepfen. Jetzt ist er
aufgebaut wie der Redaktionskalender in VanVans Hub -- mit denselben
Bauteilen, aber auf Creator zugeschnitten.

VIER ANSICHTEN auf DENSELBEN Daten. Der Server liefert einen Zeitraum,
hier wird er nur unterschiedlich dargestellt -- so kann keine Ansicht
etwas anderes zeigen als die andere. Monat (Ueberblick und Rhythmus),
Woche (die sieben Tage gross), Liste (was kommt als Naechstes),
Zeitstrahl (wo sich etwas ballt und wo Luft ist).

ANLAESSE UND FEIERTAGE, vollstaendig selbst gerechnet. Ein leerer
Kalender ist nicht nur kahl, er ist nutzlos: Die Frage beim Planen
lautet nie "was habe ich schon eingetragen", sondern "worauf muss ich
zuarbeiten". Ostern ueber die Gauss-Formel, davon abgeleitet Karfreitag,
Himmelfahrt und Pfingsten, dazu die beweglichen Termine (Muttertag,
Black Friday als Freitag nach dem VIERTEN Donnerstag im November, die
vier Advente rueckwaerts vom vierten). Kein Dienst, keine Liste zum
Nachpflegen, keine Kosten, funktioniert offline und im Jahr 2040.

Bewusst NUR die neun bundesweiten Feiertage. Fronleichnam,
Reformationstag und Allerheiligen gelten je nach Bundesland -- ein
Kalender, der sie ueberall anzeigt, waere fuer die Haelfte der Leute
schlicht falsch. Lieber weniger behaupten als etwas Falsches.

Zwei beschriftete Reihen, die zwei VERSCHIEDENE Fragen beantworten:
"Als Naechstes" blickt ab heute nach vorn und aendert sich beim
Blaettern NICHT, "Im September" beschreibt den Monat, den man ansieht.
Ohne Ueberschriften waeren zwei gleich aussehende Reihen verwirrend.

Farbe folgt der Sache, nicht dem Rang -- dieselbe Regel wie bei den
Kacheln: Call blau, Termin violett, Review gruen, Frist orange. Ueberall
gleich: Pille im Raster, Zeile in der Liste, Filterknopf, Balken im
Zeitstrahl. Die KW-Spalte ist kein Schmuck, sondern die uebliche
Waehrung in Absprachen ("machen wir in KW 42").

NEUE PRUEFUNG pruef-kalender.mjs. Sie prueft nicht nur, DASS etwas
dasteht, sondern die gerechneten Tage gegen nachschlagbare Werte:
Ostersonntag 2026/2027/2030, Karfreitag, Himmelfahrt, Muttertag, Black
Friday und den 4. Advent. Ohne das koennte die Osterformel um einen Tag
daneben liegen und niemand wuerde es merken -- bis irgendwann jemand
Karfreitag arbeitet. Dazu: ganze Wochen im Raster, genau ein "heute",
vier Arten in vier Farben, dass ein ausgeschalteter Filter WIRKLICH
etwas ausblendet (ein Filter, der nur die Knopffarbe aendert, ist
keiner), Blaettern in beide Richtungen und der Tagesdialog.

ZWEI FUNDE:
- "Sep" am Monatsersten lag bei 3,96:1, wenn der Erste zufaellig HEUTE
  ist -- dann liegt der Text auf der aufgehellten Zelle. Nur an echten
  Bildpunkten zu sehen, nie an der Farbangabe.
- Die eigene Pruefung blaetterte stur vorwaerts und erreichte April 2026
  nie (heute ist September). Zehn rote Meldungen, die wie ein
  Rechenfehler in der Osterformel aussahen. Jetzt wird die Richtung aus
  dem offenen Monat bestimmt.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-01 10:14:47 +02:00
co-authored by Claude Opus 5
parent e65827a6db
commit c01aeb4225
22 changed files with 1812 additions and 341 deletions
+528 -64
View File
@@ -1,83 +1,547 @@
/* ===================================================================
Kalender. Nach Tagen gruppiert statt als Monatsraster: Es geht um
wenige, dafür konkrete Termine -- eine Liste liest sich dabei besser
und funktioniert auf dem Handy ohne Umbau.
Kalender
Gebaut nach demselben Grundsatz wie die Kacheln auf der Startseite:
Die Farbe gehört zur SACHE, nicht zum Rang. Ein Call ist überall
blau, ein Review überall grün, eine Frist überall orange -- in der
Pille im Raster, in der Zeile in der Liste, im Filterknopf und im
Balken des Zeitstrahls. Wer die Farbe einmal gelernt hat, muss die
Beschriftung nicht mehr lesen.
Augenschonend: gedeckte Töne, keine Signalfarben, kein Blinken. Der
einzige laute Punkt ist "heute" -- und der darf laut sein, weil man
ihn sucht.
=================================================================== */
.zeitraum { display: flex; gap: 8px; margin: 0 0 22px; flex-wrap: wrap; }
.zeitraum .schritt[aria-pressed="true"] {
/* Gedrueckt = der "voll"-Auftritt des Knopf-Systems. Vorher stand
hier eine eigene Flaeche, die den geschliffenen Rand ueberschrieb. */
--f: var(--akzent);
color: #fff;
background:
linear-gradient(color-mix(in srgb, var(--f) 20%, #121926),
color-mix(in srgb, var(--f) 12%, #0d1420)) padding-box,
linear-gradient(150deg, var(--f),
color-mix(in srgb, var(--f) 45%, transparent)) border-box;
box-shadow: 0 4px 16px -9px var(--f);
/* ---------- Kopf: der Zeitraum als Überschrift --------------------------
Man liest zuerst, WO man ist, und bewegt sich dann. Deshalb steht der
Monat groß und die Navigation daneben, nicht umgekehrt. */
.k-kopf {
display: flex; align-items: flex-end; justify-content: space-between;
flex-wrap: wrap; gap: 16px;
margin-bottom: 22px;
}
.k-zeitraum {
margin: 0;
font-size: clamp(1.7rem, 3.2vw, 2.4rem);
letter-spacing: -.025em;
color: #f2f7fd;
text-shadow: 0 2px 26px rgba(63, 189, 245, .16);
/* Der Monatsname wechselt beim Blättern die Länge. Ohne feste
Zeichenbreite für die Jahreszahl springt die Zeile dabei. */
font-variant-numeric: tabular-nums;
}
.k-kopf__unter {
margin: 5px 0 0;
font-size: .82rem; letter-spacing: .1em; text-transform: uppercase;
color: var(--text-still);
font-variant-numeric: tabular-nums;
}
.k-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.k-pfeil {
min-width: 38px; padding-left: 0; padding-right: 0;
font-size: 1.15rem; line-height: 1;
justify-content: center;
}
.tag { margin-bottom: 22px; }
.tag__kopf {
display: flex; align-items: baseline; gap: 10px;
margin: 0 2px 9px; padding-bottom: 7px;
border-bottom: 1px solid var(--rand);
/* ---------- Die beiden Anlassreihen ------------------------------------
Oben "Als Nächstes" (blickt ab heute nach vorn, ändert sich beim
Blättern NICHT), darunter die Anlässe des angezeigten Zeitraums. Sie
sehen absichtlich gleich aus -- es sind dieselben Dinge, nur zu einer
anderen Frage. Die Überschriften sagen, welche. */
.k-leiste { margin-bottom: 20px; }
.k-leiste .feldschild { display: flex; align-items: center; gap: 9px; }
.k-leiste .feldschild::before {
content: "";
width: 18px; height: 2px; border-radius: 2px;
background: linear-gradient(90deg, var(--akzent), transparent);
opacity: .8;
}
.tag__datum { font-weight: 700; font-size: .95rem; }
.tag__wochentag { font-size: .8rem; color: var(--text-still); }
.tag__marke {
margin-left: auto; padding: 1px 9px; border-radius: 999px;
font-size: .7rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
background: rgba(63, 189, 245, .16); color: #7fd2fb;
.k-anlassreihe {
display: grid; gap: 9px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
margin-top: 10px;
}
/* Vergangene Tage treten zurück, bleiben aber lesbar. */
.tag[data-vergangen="ja"] .tag__datum,
.tag[data-vergangen="ja"] .tag__wochentag { color: var(--text-still); }
.eintrag {
display: grid; gap: 3px 14px;
grid-template-columns: 78px 1fr auto;
align-items: start;
padding: 11px 14px; margin-bottom: 8px;
background: rgba(255, 255, 255, .03);
border: 1px solid var(--rand);
border-left: 3px solid var(--rand);
.k-anlasskarte {
--afarbe: var(--akzent);
position: relative; overflow: hidden;
display: flex; align-items: center; gap: 12px;
padding: 11px 14px 11px 16px;
border: 1px solid color-mix(in srgb, var(--afarbe) 26%, var(--rand));
border-radius: var(--radius-klein);
background:
linear-gradient(90deg, color-mix(in srgb, var(--afarbe) 11%, transparent), transparent 58%),
rgba(255, 255, 255, .03);
cursor: pointer;
transition: border-color .18s ease, background .18s ease, transform .18s ease;
}
.k-anlasskarte::before {
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
background: linear-gradient(180deg, var(--afarbe),
color-mix(in srgb, var(--afarbe) 35%, transparent));
}
.k-anlasskarte:hover, .k-anlasskarte:focus-visible {
border-color: color-mix(in srgb, var(--afarbe) 46%, var(--rand));
transform: translateY(-1px);
}
/* Vorbei heißt: steht noch da, aber leiser. Ganz wegzulassen wäre
falsch -- man will sehen, dass der Tag gewesen ist. */
.k-anlasskarte.vorbei { opacity: .5; }
.k-anlasskarte__sym { font-size: 1.3rem; line-height: 1; flex: none; }
.k-anlasskarte__txt { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
/* Der Name darf umbrechen statt abzubrechen. Vorher stand hier
"Tag der Deutsc…" -- abgeschnittener Text sieht auf den ersten Blick
nach Absicht aus und ist deshalb der teuerste stille Fehler in einer
Karte. Zwei Zeilen kosten nichts, ein verlorener Name schon. */
.k-anlasskarte__name {
font-weight: 650; color: var(--text);
line-height: 1.25;
overflow-wrap: anywhere;
}
.k-anlasskarte__wann { font-size: .78rem; color: var(--text-leise); }
.k-anlasskarte__rest {
flex: none; text-align: right;
font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
color: var(--afarbe);
font-variant-numeric: tabular-nums;
}
.k-anlasskarte__rest small {
display: block; margin-top: 2px;
font-size: .64rem; letter-spacing: .06em;
color: var(--text-still); text-transform: none;
}
.k-anlassleer {
grid-column: 1 / -1;
margin: 0; padding: 13px 16px;
font-size: .88rem; color: var(--text-still);
border: 1px dashed var(--rand); border-radius: var(--radius-klein);
}
.eintrag[data-art="call"] { border-left-color: var(--akzent); }
.eintrag[data-art="review"] { border-left-color: #e0a33c; }
.eintrag[data-art="termin"] { border-left-color: var(--violett); }
.eintrag[data-art="frist"] { border-left-color: #d8656e; background: rgba(216, 101, 110, .05); }
.eintrag[data-erledigt="ja"] { opacity: .5; }
.eintrag__zeit {
font-variant-numeric: tabular-nums; font-weight: 600; font-size: .88rem;
/* ---------- Werkzeugleiste: Ansicht und Filter -------------------------- */
.k-werkzeuge {
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 12px;
margin: 4px 0 16px;
}
.k-ansichten { display: flex; gap: 6px; flex-wrap: wrap; }
.k-ansicht {
padding: 8px 15px;
border: 1px solid var(--rand); border-radius: 999px;
background: rgba(255, 255, 255, .03);
color: var(--text-leise);
font: inherit; font-size: .86rem;
cursor: pointer;
transition: border-color .18s ease, background .18s ease, color .18s ease;
}
.k-ansicht:hover { color: var(--text); border-color: var(--rand-hell); }
.k-ansicht[aria-pressed="true"] {
color: #eaf4fd;
border-color: color-mix(in srgb, var(--akzent) 46%, transparent);
background: color-mix(in srgb, var(--akzent) 15%, transparent);
}
.k-filter { display: flex; gap: 6px; flex-wrap: wrap; }
.k-chip {
--cfarbe: var(--akzent);
display: inline-flex; align-items: center; gap: 8px;
padding: 8px 14px;
border: 1px solid var(--rand); border-radius: 999px;
background: rgba(255, 255, 255, .03);
color: var(--text-still);
font: inherit; font-size: .84rem;
cursor: pointer;
font-variant-numeric: tabular-nums;
transition: border-color .18s ease, background .18s ease, color .18s ease, opacity .18s ease;
}
.k-chip__punkt {
width: 8px; height: 8px; border-radius: 50%;
background: var(--cfarbe);
transition: opacity .18s ease, box-shadow .18s ease;
}
.k-chip[aria-pressed="true"] {
color: var(--text);
border-color: color-mix(in srgb, var(--cfarbe) 40%, transparent);
background: color-mix(in srgb, var(--cfarbe) 11%, transparent);
}
.k-chip[aria-pressed="true"] .k-chip__punkt {
box-shadow: 0 0 8px color-mix(in srgb, var(--cfarbe) 70%, transparent);
}
/* Ausgeschaltet: der Punkt wird hohl. Nur die Deckkraft zu senken wäre
im Kontrastmodus nicht zu unterscheiden. */
.k-chip[aria-pressed="false"] .k-chip__punkt {
background: transparent;
box-shadow: inset 0 0 0 1.5px var(--cfarbe);
opacity: .55;
}
/* ---------- Monatsraster ------------------------------------------------
Eine Spalte für die Kalenderwoche, dann die sieben Tage. Die
KW-Spalte ist kein Schmuck: In Absprachen ("machen wir in KW 42")
ist sie die übliche Währung. */
.k-raster {
display: grid;
grid-template-columns: 46px repeat(7, minmax(0, 1fr));
gap: 1px;
background: var(--rand);
border: 1px solid var(--rand);
border-radius: var(--radius-klein);
overflow: hidden;
}
.k-spaltenkopf {
padding: 11px 10px;
background: rgba(12, 17, 28, .82);
font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
color: var(--text-leise);
}
.eintrag__titel { font-weight: 600; font-size: .93rem; }
.eintrag__zusatz {
grid-column: 2; display: flex; flex-wrap: wrap; gap: 8px;
font-size: .78rem; color: var(--text-still);
}
.eintrag__zusatz a { color: var(--akzent); }
.eintrag__knoepfe { display: flex; gap: 6px; align-items: center; }
.k-spaltenkopf--kw { color: var(--text-still); }
.eintrag__art {
padding: 1px 8px; border-radius: 999px;
font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
background: rgba(255, 255, 255, .06); color: var(--text-still);
.k-kw {
display: flex; align-items: flex-start; justify-content: center;
padding: 10px 4px;
background: rgba(9, 13, 22, .78);
font-size: .78rem; font-weight: 600;
color: var(--text-still);
font-variant-numeric: tabular-nums;
}
/* Die laufende Woche wird in der KW-Spalte markiert -- dadurch findet
man sich beim Blättern sofort zurecht. */
.k-kw[data-jetzt="ja"] {
color: var(--akzent);
background: color-mix(in srgb, var(--akzent) 12%, rgba(9, 13, 22, .78));
}
.leer-hinweis {
padding: 26px 20px; text-align: center;
color: var(--text-still); font-size: .9rem;
border: 1px dashed var(--rand); border-radius: var(--radius);
.k-tag {
min-height: 108px;
padding: 8px 9px 10px;
background: rgba(11, 15, 25, .74);
display: flex; flex-direction: column; gap: 4px;
cursor: pointer;
transition: background .16s ease;
}
.k-tag:hover { background: rgba(20, 27, 42, .85); }
.k-tag:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
/* Tage des Nachbarmonats: da, aber deutlich zurückgenommen. Sie ganz
wegzulassen würde das Raster zerreißen. */
.k-tag[data-fremd="ja"] { background: rgba(7, 10, 17, .72); }
.k-tag[data-fremd="ja"] .k-tag__zahl { color: var(--text-still); opacity: .6; }
.k-tag[data-wochenende="ja"] { background: rgba(9, 12, 20, .8); }
/* Gesetzlicher Feiertag: ein Hauch Rosé. Kein Signal, nur eine andere
Fläche -- man sieht ihn, ohne dass er ruft. */
.k-tag[data-feiertag="ja"] { background: color-mix(in srgb, #ff9aa2 9%, rgba(11, 15, 25, .74)); }
.k-tag[data-feiertag="ja"]:hover { background: color-mix(in srgb, #ff9aa2 14%, rgba(11, 15, 25, .74)); }
.k-tag[data-heute="ja"] {
background: color-mix(in srgb, var(--akzent) 13%, rgba(11, 15, 25, .74));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--akzent) 50%, transparent);
}
@media (max-width: 620px) {
.eintrag { grid-template-columns: 62px 1fr; }
.eintrag__knoepfe { grid-column: 1 / -1; margin-top: 8px; }
.eintrag__zusatz { grid-column: 1 / -1; }
.k-tag__kopf { display: flex; align-items: baseline; gap: 6px; }
.k-tag__zahl {
font-size: .95rem; font-weight: 650; color: var(--text);
font-variant-numeric: tabular-nums;
}
/* Am Monatsersten steht der Monatsname dabei -- sonst weiß man in der
letzten Rasterzeile nicht, ob die 1 schon zum nächsten Monat gehört.
Bewusst --text-leise statt --text-still: Wenn der Monatserste
zufällig HEUTE ist, liegt der Text auf der aufgehellten Heute-Zelle,
und dort kam der leiseste Grauton nur noch auf 3,96:1. Gemessen an
echten Bildpunkten, nicht an der Farbangabe -- die weiß nichts davon,
was hinter ihr liegt. Jetzt 5,9:1. */
.k-tag__monat { font-size: .7rem; color: var(--text-leise); }
.k-tag__heute {
margin-left: auto;
font-size: .62rem; letter-spacing: .1em; text-transform: uppercase;
color: var(--akzent);
}
/* ---------- Anlassmarke im Raster --------------------------------------- */
.k-anlass {
--afarbe: var(--akzent);
display: block;
padding: 2px 6px;
border-radius: 5px;
border-left: 2px solid var(--afarbe);
background: color-mix(in srgb, var(--afarbe) 13%, transparent);
color: color-mix(in srgb, var(--afarbe) 70%, #ffffff);
font-size: .68rem; line-height: 1.35;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Feiertage sind lauter als Anlässe: Sie sind eine Tatsache, kein
Vorschlag. */
.k-anlass.feiertag {
background: color-mix(in srgb, var(--afarbe) 20%, transparent);
font-weight: 600;
}
/* ---------- Pille: ein Eintrag im Raster -------------------------------- */
.k-pille {
--pfarbe: var(--akzent);
display: block;
padding: 3px 7px;
border-radius: 5px;
border-left: 2px solid var(--pfarbe);
background: color-mix(in srgb, var(--pfarbe) 16%, transparent);
color: var(--text);
font-size: .72rem; line-height: 1.4;
text-decoration: none;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
transition: background .16s ease;
}
.k-pille:hover { background: color-mix(in srgb, var(--pfarbe) 26%, transparent); }
.k-pille__zeit {
color: var(--pfarbe); font-weight: 650; margin-right: 5px;
font-variant-numeric: tabular-nums;
}
/* Erledigt: durchgestrichen UND blasser. Nur blasser wäre im
Kontrastmodus nicht zu erkennen. */
.k-pille.erledigt { opacity: .5; text-decoration: line-through; }
/* ---------- Wochenansicht ----------------------------------------------- */
.k-woche {
display: grid; gap: 1px;
grid-template-columns: repeat(7, minmax(0, 1fr));
background: var(--rand);
border: 1px solid var(--rand);
border-radius: var(--radius-klein);
overflow: hidden;
}
.k-wochentag {
min-height: 190px;
padding: 10px;
background: rgba(11, 15, 25, .74);
display: flex; flex-direction: column; gap: 5px;
cursor: pointer;
transition: background .16s ease;
}
.k-wochentag:hover { background: rgba(20, 27, 42, .85); }
.k-wochentag:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
.k-wochentag[data-feiertag="ja"] { background: color-mix(in srgb, #ff9aa2 9%, rgba(11, 15, 25, .74)); }
.k-wochentag[data-heute="ja"] {
background: color-mix(in srgb, var(--akzent) 13%, rgba(11, 15, 25, .74));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--akzent) 50%, transparent);
}
.k-wochentag__kopf {
display: flex; align-items: baseline; gap: 7px;
padding-bottom: 7px; margin-bottom: 3px;
border-bottom: 1px solid var(--rand);
}
.k-wochentag__name {
font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
color: var(--text-still);
}
.k-wochentag__zahl {
font-size: 1.25rem; font-weight: 700; color: var(--text);
font-variant-numeric: tabular-nums;
}
.k-wochentag__leer { margin: auto 0; color: var(--text-still); font-size: .8rem; }
/* ---------- Listenansicht ----------------------------------------------- */
.k-liste { display: grid; gap: 12px; }
.k-listentag {
padding: 14px 16px;
border: 1px solid var(--rand); border-radius: var(--radius-klein);
background: rgba(255, 255, 255, .026);
display: grid; gap: 7px;
}
.k-listentag[data-vergangen="ja"] { opacity: .62; }
.k-listentag[data-heute="ja"] {
border-color: color-mix(in srgb, var(--akzent) 40%, transparent);
background: color-mix(in srgb, var(--akzent) 7%, rgba(255, 255, 255, .026));
}
.k-listentag__kopf { display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap; }
.k-listentag__datum { font-weight: 650; color: var(--text); }
.k-listentag__kw {
font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
color: var(--text-still); font-variant-numeric: tabular-nums;
}
.k-listentag__marke {
margin-left: auto; padding: 2px 9px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--akzent) 34%, transparent);
background: color-mix(in srgb, var(--akzent) 13%, transparent);
color: var(--akzent);
font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
}
/* ---------- Eine ausführliche Zeile ------------------------------------- */
.k-zeile {
--zfarbe: var(--akzent);
position: relative;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center; gap: 12px;
padding: 9px 12px 9px 14px;
border-radius: 8px;
border: 1px solid var(--rand);
background:
linear-gradient(90deg, color-mix(in srgb, var(--zfarbe) 8%, transparent), transparent 50%),
rgba(255, 255, 255, .02);
}
.k-zeile::before {
content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
border-radius: 0 3px 3px 0;
background: var(--zfarbe);
}
.k-zeile[data-erledigt="ja"] { opacity: .55; }
.k-zeile[data-erledigt="ja"] .k-zeile__titel { text-decoration: line-through; }
.k-zeile__zeit {
font-size: .82rem; font-weight: 650; color: var(--zfarbe);
font-variant-numeric: tabular-nums;
min-width: 5.5ch;
}
.k-zeile__titel { color: var(--text); min-width: 0; }
.k-zeile__knoepfe { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.k-zeile__art {
padding: 2px 9px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--zfarbe) 32%, transparent);
color: var(--zfarbe);
font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
}
.k-zeile__zusatz {
grid-column: 1 / -1;
display: flex; flex-wrap: wrap; gap: 4px 10px;
font-size: .78rem; color: var(--text-leise);
}
.k-zeile__zusatz a { color: var(--akzent); }
/* ---------- Zeitstrahl ---------------------------------------------------
Sechs Wochen auf einer Achse. Die Höhe eines Strichs ist die Menge
des Tages -- man sieht Ballungen und Lücken, ohne zu zählen. */
.k-strahl-rahmen {
padding: 20px 18px 14px;
border: 1px solid var(--rand); border-radius: var(--radius-klein);
background: rgba(255, 255, 255, .026);
}
.k-strahl {
display: grid;
grid-auto-flow: column;
grid-auto-columns: minmax(0, 1fr);
align-items: end;
gap: 2px;
height: 150px;
}
.k-strahl__tag {
--menge: 0;
position: relative;
height: 100%;
display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
gap: 3px;
padding-bottom: 16px;
border-radius: 4px 4px 0 0;
cursor: pointer;
transition: background .16s ease;
}
.k-strahl__tag:hover { background: rgba(255, 255, 255, .05); }
.k-strahl__tag:focus-visible { outline: 2px solid var(--akzent); outline-offset: 1px; }
.k-strahl__tag[data-wochenende="ja"] { background: rgba(255, 255, 255, .022); }
.k-strahl__tag[data-feiertag="ja"] { background: color-mix(in srgb, #ff9aa2 10%, transparent); }
.k-strahl__tag[data-heute="ja"] { background: color-mix(in srgb, var(--akzent) 15%, transparent); }
.k-strahl__saeule {
--sfarbe: var(--akzent);
width: 100%;
/* Ein leerer Tag bekommt einen Sockel von 3 px statt gar nichts --
sonst sähe die Achse an ruhigen Stellen kaputt aus. */
height: calc(3px + var(--menge) * 20px);
border-radius: 3px 3px 0 0;
background: linear-gradient(180deg, var(--sfarbe),
color-mix(in srgb, var(--sfarbe) 30%, transparent));
opacity: .92;
}
.k-strahl__tag[style*="--menge: 0"] .k-strahl__saeule { opacity: .3; }
.k-strahl__sym { position: absolute; top: 2px; font-size: .8rem; }
.k-strahl__kw {
position: absolute; bottom: 0;
font-size: .62rem; color: var(--text-still);
font-variant-numeric: tabular-nums;
}
.k-strahl__fuss {
margin: 14px 0 0;
font-size: .76rem; color: var(--text-still);
}
/* ---------- Leerer Zeitraum --------------------------------------------- */
.k-leer {
padding: 26px 22px;
border: 1px dashed var(--rand); border-radius: var(--radius-klein);
text-align: center;
}
.k-leer__satz { margin: 0 0 6px; color: var(--text-leise); }
.k-leer__tipp { margin: 0; font-size: .82rem; color: var(--text-still); }
/* ---------- Tagesdialog -------------------------------------------------- */
.k-dialog {
width: min(560px, calc(100vw - 32px));
padding: 20px 22px;
border: 1px solid var(--rand-hell);
border-radius: var(--radius);
background: var(--glas-tief);
color: var(--text);
box-shadow: var(--schatten);
backdrop-filter: blur(14px);
}
.k-dialog::backdrop { background: rgba(3, 5, 10, .72); backdrop-filter: blur(3px); }
.k-dialog__kopf {
display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
margin-bottom: 14px;
}
.k-dialog__titel { display: block; font-size: 1.1rem; color: #eaf2fb; }
.k-dialog__unter {
display: block; margin-top: 3px;
font-size: .76rem; letter-spacing: .1em; text-transform: uppercase;
color: var(--text-still);
}
.k-dialog__anlaesse { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.k-dialog__anlaesse:empty { display: none; }
.k-dialog__anlaesse .k-anlass { font-size: .76rem; padding: 4px 9px; }
.k-dialog__liste { display: grid; gap: 8px; margin-bottom: 16px; }
.k-dialog__fuss {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
padding-top: 14px;
border-top: 1px solid var(--rand);
}
.k-dialog__tipp { font-size: .74rem; color: var(--text-still); }
/* ---------- Kleinere Bildschirme ----------------------------------------
Das Monatsraster ist auf einem Handy nicht sinnvoll zu quetschen: Bei
390 px wären die Zellen 46 px breit, und in einer 46-px-Zelle steht
kein Termin. Statt zu schrumpfen wird deshalb umgebaut -- die
KW-Spalte fällt weg, die Zellen werden flacher, und die Pillen zeigen
nur noch die Uhrzeit als Punkt. */
@media (max-width: 860px) {
.k-raster { grid-template-columns: 32px repeat(7, minmax(0, 1fr)); }
.k-tag { min-height: 76px; padding: 6px 5px 7px; }
.k-tag__monat, .k-tag__heute { display: none; }
.k-anlass, .k-pille {
font-size: .6rem; padding: 1px 4px;
border-left-width: 2px;
}
.k-pille__zeit { margin-right: 3px; }
.k-spaltenkopf { padding: 8px 4px; font-size: .66rem; letter-spacing: .06em; }
.k-kw { font-size: .66rem; padding: 7px 2px; }
.k-woche { grid-template-columns: 1fr; }
.k-wochentag { min-height: 0; }
.k-strahl { height: 110px; }
}
@media (max-width: 560px) {
.k-kopf { align-items: flex-start; }
.k-nav { width: 100%; }
.k-zeile { grid-template-columns: auto 1fr; }
.k-zeile__knoepfe { grid-column: 1 / -1; }
.k-anlassreihe { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.k-anlasskarte, .k-tag, .k-wochentag, .k-pille, .k-chip,
.k-ansicht, .k-strahl__tag { transition: none; }
.k-anlasskarte:hover { transform: none; }
}
/* Ohne Farbverläufe (Kontrastmodus, Druck) müssen Kante und Schrift
allein tragen -- deshalb bleiben die Ränder erhalten. */
@media (forced-colors: active) {
.k-zeile::before, .k-anlasskarte::before { background: CanvasText; }
.k-pille, .k-anlass { border: 1px solid CanvasText; }
.k-strahl__saeule { background: CanvasText; }
}