{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "wochen-kursplan",
 "name": "Wochen-Kursplan mit Live-Status",
 "name_en": "Recurring weekly class timetable with live now/next status, filters, cancellations and per-class ICS",
 "kurz": "Wiederkehrender Wochenplan als Raster aus Tagen und Stunden, mobil mit Tages-Reitern, mit Filtern, „läuft gerade“ und „als Nächstes“ in Ortszeit, Ausfällen am Termin, Probetraining je Termin und .ics je Kurs.",
 "kategorie": "Sektionen & Funktionen",
 "kategorie_slug": "sektionen",
 "kategorie_nr": 16,
 "bau_chat": "D",
 "prioritaet": "D",
 "trendstatus": "etabliert",
 "belegstatus": "teilbelegt",
 "website_belege": 1,
 "stimmung": [
  "präzise",
  "laut"
 ],
 "stimmung_roh": [
  "funktional",
  "strukturiert",
  "kraftvoll"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "intl",
  "css-grid",
  "subgrid",
  "dialog",
  "view-transitions"
 ],
 "technik_gruppen": [
  "css",
  "js"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Ein wiederkehrender Wochenplan für Kurse und Trainingsgruppen. Auf dem Desktop ist er ein Raster aus Wochentagen und Uhrzeiten, auf dem Telefon eine Leiste mit Tages-Reitern. Filter nach Kurs oder Abteilung, Trainer:in, Niveau oder Alter und Halle bzw. Raum wirken auf beide Ansichten. Oben steht in Ortszeit, was gerade läuft und was als Nächstes beginnt. Jeder Termin nennt freie Plätze als Text, Ausfälle und Vertretungen stehen direkt am Termin. Je Termin gibt es Probetraining oder Anmeldung, je Kurs eine .ics-Datei mit Wiederholungsregel und Ausnahmen.",
  "warum_es_wirkt": "Wer einen Kurs sucht, fragt zuerst: An welchem Tag, um wie viel Uhr, wo und für wen? Das Raster beantwortet das auf einen Blick, die Filter machen aus 40 Gruppen die drei passenden. „Läuft gerade“ und „als Nächstes“ helfen kurz vor dem Losgehen. Ausfälle am Termin selbst ersparen den Blick in Messenger-Gruppen. Die Kalenderdatei mit Wiederholung macht aus Interesse einen festen Wochentermin.",
  "wann_einsetzen": "Sportverein mit Abteilungen und Hallenzeiten, Fitness-, Yoga- oder Pilatesstudio, Tanzschule, Kampfsportschule, Schwimmschule, Physio- und Präventionskurse, Volkshochschule mit festen Wochenkursen, Theorieunterricht der Fahrschule. Immer dann, wenn sich die Termine jede Woche wiederholen.",
  "wann_nicht": "Für Einzeltermine wie Konzerte, Workshops oder Tage der offenen Tür ist programm-kalender da (Liste und Monat). Bei weniger als etwa acht Wochenterminen reicht eine Tabelle oder Liste. Liefert eine Buchungssoftware schon einen gepflegten Plan, die Sektion nur als Teaser mit „läuft gerade“ und Link bauen, statt Daten doppelt zu pflegen.",
  "varianten": [
   "Sportverein: Abteilungen, Hallen, Altersgruppen, Probetraining, Hallenpause in den Ferien",
   "Fitness- oder Yogastudio: Kursarten, Räume, Niveau, Probestunde und Warteliste",
   "Teaser „Heute im Studio“: nur läuft gerade und die nächsten drei Termine mit Link zum Plan",
   "Ein Raum als Belegungsplan (Halle, Studio), nur lesbar ohne Anmeldung"
  ],
  "umsetzung": "Daten als Liste wiederkehrender Kurse (id, wochentag, beginn, dauer, rubrik, titel, trainer, gruppe, halle, plaetze, belegt, anmeldung, info) plus Ausnahmen je Woche oder Datum (fällt aus, Vertretung, anderer Raum) und Ferienpause. Ein Filterzustand für beide Ansichten.\n\nDesktop: CSS-Grid mit Zeitspalte und 7 Tagesspalten. Zeilen sind nur die Stunden, in denen nach dem Filter etwas beginnt; laufen an einem Tag zwei Kurse in derselben Stunde, bekommt diese Stunde zwei Unterzeilen. Jede Tagesspalte ist ein <section> mit Überschrift und <ol>, beide mit grid-template-rows: subgrid. So bleibt die Lese- und Tab-Reihenfolge Tag für Tag, die Karten stehen trotzdem in gemeinsamen Stundenzeilen. Spalten explizit setzen (grid-column), sonst schiebt die Auto-Platzierung die Tage in implizite Spalten.\n\nTelefon: dieselben Abschnitte als Tab-Panels, darüber eine Tab-Leiste Mo bis So mit Datum. Pfeiltasten mit Umlauf, Pos1 und Ende wie in tabs-pfeiltasten-focusgroup.\n\nLive-Status wie in oeffnungszeiten-status: Ortszeit über Intl.DateTimeFormat mit timeZone 'Europe/Berlin' und formatToParts, Datumsrechnung in UTC. Neu rechnen zur vollen Minute und bei visibilitychange. Screenreader hören nur Wechsel.\n\nFilter und Wochenwechsel per document.startViewTransition, jede Karte mit view-transition-name je Kurs.\n\nTermin öffnet ein natives <dialog> mit allen Angaben, Status (Ausfall, Vertretung, Raum) und dem Formular für Probetraining oder Warteliste.\n\nICS je Kurs: VEVENT mit RRULE:FREQ=WEEKLY;BYDAY=…;UNTIL=… (Saisonende, UNTIL in UTC), EXDATE;TZID=Europe/Berlin für Ausfälle und Ferienpause, Vertretung und Raumwechsel als zweite VEVENT mit gleicher UID und RECURRENCE-ID. VTIMEZONE, CRLF, Faltung nach 75 Oktetten, Blob mit <a download>.\n\nIm Einsatz: Plan und Ausnahmen aus CMS oder Vereinsverwaltung, Ausnahmen mit echtem Datum statt Wochen-Versatz, Filter in der URL (?abteilung=turnen&halle=glacis), Anmeldung an das Buchungssystem oder per Mail an die Übungsleitung.",
  "mobil": "Tages-Reiter Mo bis So mit Datum, heute vorgewählt. Darunter die Termine des Tages als Liste mit Uhrzeit links und großen Zielen. Filter klappen hinter einem Knopf „Filter“ mit Zähler ein.",
  "reduzierte_bewegung": "Kein Einblenden und keine Neuordnung per Übergang; Raster, Reiter und Dialog wechseln sofort. Zustände und Texte bleiben gleich.",
  "barrierefreiheit": "Status nie nur über Farbe: „läuft“, „als Nächstes“, „fällt aus“, „Vertretung“ und freie Plätze stehen als Text. Tagesspalten als Abschnitte mit Überschrift (Wochentag und Datum), Termine als Listen. Mobil echtes Tab-Muster mit Pfeiltasten. Filter als Schalter mit aria-pressed bzw. native select, Trefferzahl in aria-live. Termin-Knöpfe nennen Kurs, Tag und Uhrzeit im zugänglichen Namen. Dialog nativ mit Fokus auf der Überschrift und Rückkehr zum Termin. Live-Status sagt nur Wechsel an, nicht jede Minute."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.645, 0.045, 0.355, 1)",
  "dauer_ms": "180 UI (Filter, Reiter, Karten), 600 Neuordnung des Rasters nach Filter",
  "stagger_ms": "",
  "distanz": "",
  "sonstiges": "Kurve und Dauern aus dem Rezept verein-nonprofit-wirkung (easeInOutCubic, 150–200 ms UI, 600–1000 ms große Zustandswechsel). Variante Studio: cubic-bezier(0.22, 1, 0.36, 1) aus kurs-coaching-lernweg.",
  "herkunft": "eigene Festlegung",
  "quelle": "Rezepte verein-nonprofit-wirkung und kurs-coaching-lernweg"
 },
 "kurve": {
  "bezier": [
   0.645,
   0.045,
   0.355,
   1.0
  ],
  "css": "cubic-bezier(0.645, 0.045, 0.355, 1)",
  "name": "eigene Kurve",
  "dauer_ms": 180
 },
 "gesehen_bei": [
  {
   "seite": "Eversports Manager: Kalender-Widget",
   "url": "https://helpcenter.eversportsmanager.com/how-to-integrate-the-new-eversports-calendar-widget",
   "auszeichnung": "",
   "beobachtung": "Das Kalender-Widget der Studio-Software zeigt den Plan als Woche, wahlweise nach Vormittag, Nachmittag und Abend geteilt, mobil als kompakte Karten. Karten nennen Trainer:in, Raum, „Spots remaining“ und das Niveau (Beginner bis All Levels). Vorfilter nach Lehrer:in, Aktivitätsgruppe oder Sportart; per WebFetch am 02.11.2026 gelesen.",
   "art": "artikel"
  },
  {
   "seite": "Fitness First Freiburg: Kursplan",
   "url": "https://www.fitnessfirst.de/clubs/freiburg",
   "auszeichnung": "",
   "beobachtung": "Kursplan mit Tages-Auswahl („Heute“), Filtern nach Club und Kursart, „Alle Filter löschen“, Trefferzahl und Leerzustand „Hier gibt's heute keine Kurse.“ Karten mit Zeitspanne, Titel, Niveau-Symbol und Kategorie. Buchung über die App, für Nichtmitglieder „Probetraining sichern“. Per WebFetch am 02.11.2026 gelesen (Daten im abgerufenen HTML nur als Vorlage, Kurse werden nachgeladen).",
   "art": "website"
  },
  {
   "seite": "WordPress-Forum: Wochenübersicht für Sportvereine",
   "url": "https://de.wordpress.org/support/topic/woechentliche-kalenderuebersicht-fuer-sportvereine-mit-angebotenen-kursen/",
   "auszeichnung": "",
   "beobachtung": "Ein Turnverein sucht eine Wochenansicht statt Monat, mit Kursen, die nur in einem Zeitraum laufen (Winterkurs). Vorgeschlagen werden Monatsansicht und wiederkehrende Termine eines Kalender-Plugins, deren Pflege als „seltsam“ beschrieben wird. Thema ungelöst (Februar bis März 2024). Belegt den Bedarf nach einem eigenen Wochenplan für Vereine.",
   "art": "artikel"
  },
  {
   "seite": "DSSV Eckdaten 2026",
   "url": "https://www.dssv.de/wp-content/uploads/2026/03/03_18_pm_eckdaten.pdf",
   "auszeichnung": "",
   "beobachtung": "9.647 Fitnessanlagen und 12,36 Mio. Mitglieder in Deutschland (laut Lückenanalyse vom 02.11.2026). Belegt die Größe der Zielgruppe, nicht die Gestaltung.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "RFC 5545: iCalendar (RRULE, EXDATE)",
   "url": "https://www.rfc-editor.org/rfc/rfc5545"
  },
  {
   "titel": "W3C APG: Tabs Pattern",
   "url": "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/"
  },
  {
   "titel": "MDN: Subgrid",
   "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid"
  }
 ],
 "kombinierbar_mit": [
  "oeffnungszeiten-status",
  "programm-kalender",
  "tabs-pfeiltasten-focusgroup",
  "dialog-modal-nativ",
  "toast-stapel",
  "termin-buchung-zwei-klick",
  "vergleichstabelle-sticky",
  "sticky-shrink-header"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/sektionen/wochen-kursplan/",
  "meta": "https://cecodesign.de/lab/fundus/sektionen/wochen-kursplan/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/sektionen/wochen-kursplan/demo"
 },
 "herkunft": {
  "quelldateien": [
   "Lückenanalyse 02.11.2026 (N5)"
  ],
  "pruefnotizen": [
   "Eversports-Hilfeseite, Fitness First Freiburg und WordPress-Forum am 02.11.2026 per WebFetch gelesen. DSSV-Zahlen aus der Lückenanalyse übernommen, nicht selbst geöffnet.",
   "Kurve und Dauern stammen aus den Rezepten, keine Messung an einem Kursplan.",
   "Abgrenzung: programm-kalender für Einzeltermine, wochen-kursplan für wiederkehrende Wochentermine."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Wiederkehrender Wochenplan als Raster aus Tagen und Stunden, mobil mit Tages-Reitern, mit Filtern, „läuft gerade“ und „als Nächstes“ in Ortszeit, Ausfällen am Termin, Probetraining je Termin und .ics je Kurs.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.645, 0.045, 0.355, 1) (easeInOutCubic aus verein-nonprofit-wirkung)",
   "dauer_ms": {
    "ui": 180,
    "neuordnung_view_transition": 600,
    "dialog_einblenden": 600,
    "root_ueberblendung": 180,
    "meldung": 180,
    "meldung_sichtbar": 3600
   },
   "stagger_ms": "",
   "distanz": "Dialog translateY 14px → 0 mit Deckkraft 0 → 1; Meldung 12px",
   "raster": "grid-template-columns: 4.25rem repeat(7, minmax(0, 1fr)), column-gap 6px (≤ 1180px: 3.4rem, 4px, Kurzname des Wochentags). Zeilen nur für Stunden mit Beginn im Filter; je Stunde so viele Unterzeilen wie Kurse parallel an einem Tag. Tagesspalte <section> und <ol> mit grid-template-rows: subgrid, Tageskopf sticky top 0",
   "telefon": "ab ≤ 860px Tab-Leiste 7 Spalten, Reiter min. 58px hoch (Kürzel, Datum, Anzahl), sticky; Filter hinter Knopf „Filter“ mit Zähler; Termin zweispaltig 4.6rem Uhrzeit + Inhalt",
   "tastatur": "Reiter: focusgroup=\"tablist nomemory\" wenn 'focusGroup' in HTMLElement.prototype, sonst roving tabindex; Pfeile links/rechts mit Umlauf, Pos1, Ende, Auswahl folgt Fokus",
   "zeit": "Intl.DateTimeFormat('de-DE', { timeZone: 'Europe/Berlin', hourCycle: 'h23' }).formatToParts, Datumsrechnung in UTC-Mittag; neu rechnen zur vollen Minute und bei visibilitychange; „als Nächstes“ = früheste Startzeit über diese und nächste Woche ohne Ausfälle, im Filter",
   "zustaende": "läuft: Fläche Markenton, weiße Schrift, Marke „Läuft · noch X“; als Nächstes: 2px Innenrahmen Markenton + Marke (Verein #dbebf5, Studio #f7c325); vorbei: gestrichelter Rand, Titel #5c6066, Ort und Plätze aus; fällt aus: 135°-Schraffur #fff4f2, Titel durchgestrichen, Text „Fällt aus · Grund“ #b42318; Vertretung/Raum: Zeile in Markenton mit ↻",
   "plaetze": "ohne Anmeldung · ab 4 frei „N Plätze frei“ · 1 bis 3 „Noch N Plätze frei“ #9a3412 · 0 „Ausgebucht · Warteliste“",
   "ics": "eine VEVENT je Kurs: DTSTART/DTEND;TZID=Europe/Berlin (Termin dieser Woche), RRULE:FREQ=WEEKLY;BYDAY=..;UNTIL=Saisonende 23.59 Ortszeit in UTC, EXDATE;TZID für Ausfälle und Ferienpause, Vertretung und Raumwechsel als zweite VEVENT mit gleicher UID und RECURRENCE-ID; VTIMEZONE, CRLF, Faltung 75 Oktette, Blob text/calendar + <a download>",
   "farben": "Verein: Grund #fff, Fläche #edf5fa, Text #222520, leise #5c6066 (6,3:1), Marke #002e6d, CTA #ffca0a mit #222520 (10,1:1); Abteilungen #002e6d, #0077a8, #a8461a, #00707a, #6e5a3a",
   "schriften": "Verein: Big Shoulders 800 versal (h1 clamp(2.75rem, 1.6rem + 5vw, 6rem)/.92), Archivo Text 1.0625rem; Pult Geist Mono",
   "vorfuehrung": "Uhr Mo 16.20 → 17.25 in 2600ms (Studio 16.50 → 17.45), Filter Handball + Gesundheitssport (Studio Pilates + Yin), Alter Ältere 60+ (Studio Einsteiger), Termin öffnen, Probetraining/Warteliste, Schließen, Filter löschen, nächste Woche, zurück; Zeiger 620ms; Schleife"
  },
  "ausloeser": "klick",
  "touch": "Unter 860px Tages-Reiter Mo bis So mit Datum und Terminzahl, heute vorgewählt; Termine als Liste mit großer Uhrzeit links. Filter klappen hinter „Filter“ ein (hidden, Zähler am Knopf). Dialog als Blatt von unten. Hover-Ränder entfallen, Antippen skaliert die Karte kurz auf .985.",
  "reduziert": "Keine View Transition beim Filtern, kein Einblenden des Dialogs, Wochen-Pille und Meldung springen, der Zeiger der Vorführung springt. Zustände, Texte und Live-Status bleiben gleich. Es gibt keine Dauerbewegung (kein Pulsieren).",
  "korrekturen": {
   "umsetzung": "Daten als Liste wiederkehrender Kurse (id, wochentag, beginn, dauer, rubrik, titel, trainer, gruppe, halle, plaetze, belegt, anmeldung, info) plus Ausnahmen je Woche oder Datum (fällt aus, Vertretung, anderer Raum) und Ferienpause. Ein Filterzustand für beide Ansichten.\n\nDesktop: CSS-Grid mit Zeitspalte und 7 Tagesspalten. Zeilen sind nur die Stunden, in denen nach dem Filter etwas beginnt; laufen an einem Tag zwei Kurse in derselben Stunde, bekommt diese Stunde zwei Unterzeilen. Jede Tagesspalte ist ein <section> mit Überschrift und <ol>, beide mit grid-template-rows: subgrid. So bleibt die Lese- und Tab-Reihenfolge Tag für Tag, die Karten stehen trotzdem in gemeinsamen Stundenzeilen. Spalten explizit setzen (grid-column), sonst schiebt die Auto-Platzierung die Tage in implizite Spalten.\n\nTelefon: dieselben Abschnitte als Tab-Panels, darüber eine Tab-Leiste Mo bis So mit Datum. Pfeiltasten mit Umlauf, Pos1 und Ende wie in tabs-pfeiltasten-focusgroup.\n\nLive-Status wie in oeffnungszeiten-status: Ortszeit über Intl.DateTimeFormat mit timeZone 'Europe/Berlin' und formatToParts, Datumsrechnung in UTC. Neu rechnen zur vollen Minute und bei visibilitychange. Screenreader hören nur Wechsel.\n\nFilter und Wochenwechsel per document.startViewTransition, jede Karte mit view-transition-name je Kurs.\n\nTermin öffnet ein natives <dialog> mit allen Angaben, Status (Ausfall, Vertretung, Raum) und dem Formular für Probetraining oder Warteliste.\n\nICS je Kurs: VEVENT mit RRULE:FREQ=WEEKLY;BYDAY=…;UNTIL=… (Saisonende, UNTIL in UTC), EXDATE;TZID=Europe/Berlin für Ausfälle und Ferienpause, Vertretung und Raumwechsel als zweite VEVENT mit gleicher UID und RECURRENCE-ID. VTIMEZONE, CRLF, Faltung nach 75 Oktetten, Blob mit <a download>.\n\nIm Einsatz: Plan und Ausnahmen aus CMS oder Vereinsverwaltung, Ausnahmen mit echtem Datum statt Wochen-Versatz, Filter in der URL (?abteilung=turnen&halle=glacis), Anmeldung an das Buchungssystem oder per Mail an die Übungsleitung."
  },
  "geprueft": "02.11.2026",
  "notiz": "Welt: Rezept verein-nonprofit-wirkung, erfundener Turn- und Sportverein TuS Weserbogen Minden 1889 e.V. mit fünf Abteilungen und vier Hallen plus Lauftreff (Namen, Adressen, Domain .example erfunden). Variante Yogastudio im Rezept kurs-coaching-lernweg (Atemhaus Minden, Bricolage Grotesque, Onest, Shantell Sans für Randnotizen). Gelb nur für Probetraining wie die Spende im Rezept. Zustände: läuft, als Nächstes, vorbei, fällt aus (mit Grund), Vertretung, Raumwechsel, knapp, ausgebucht mit Warteliste, ohne Anmeldung, Leerzustand mit Weg zur anderen Woche, Formular mit Fehlern und Erfolg, Ferienpause. Echtzeit standardmäßig, Uhr im Pult simulierbar; Ausnahmen hängen in der Demo an der Woche von heute. ICS ist echt (Blob); in der Vorführung nur erzeugt. Anmeldung wird nicht gesendet. Grenze: programm-kalender für Einzeltermine, hier Dauertermine. Referenzen: helpcenter.eversportsmanager.com, fitnessfirst.de, de.wordpress.org. AD-Review 02.11.2026: Note 5. Tab-Leiste (Pfeile, Pos1, Ende, Umlauf), Filter, Dialog mit Fokus-Rückkehr und ICS (RRULE, EXDATE, VTIMEZONE) geprüft.",
  "varianten": [
   {
    "id": "verein",
    "name": "Sportverein",
    "wann": "Turn- und Sportverein mit Abteilungen, Hallen und Altersgruppen, Probetraining ohne Buchungssystem.",
    "werte": {
     "rezept": "verein-nonprofit-wirkung",
     "filter": "Abteilung, Trainer:in, Alter, Halle",
     "cta": "Probetraining #ffca0a mit #222520",
     "kurve": "cubic-bezier(0.645, 0.045, 0.355, 1)",
     "dauer_ms": {
      "ui": 180,
      "neuordnung": 600
     },
     "ecken": "4px / 6px"
    }
   },
   {
    "id": "studio",
    "name": "Yoga- und Fitnessstudio",
    "wann": "Studio mit Kursarten, Räumen und Niveaus, begrenzten Plätzen, Probestunde und Warteliste (Yoga, Pilates, Fitness, Tanz).",
    "werte": {
     "rezept": "kurs-coaching-lernweg",
     "filter": "Kursart, Lehrer:in, Niveau, Raum",
     "cta": "Probestunde #3f4fc4 mit Weiß (6,7:1)",
     "als_naechstes": "Marke #f7c325 mit #141414",
     "kurve": "cubic-bezier(0.22, 1, 0.36, 1)",
     "dauer_ms": {
      "ui": 150,
      "neuordnung": 500
     },
     "ecken": "14px / 22px, Pillen 999px",
     "schriften": "Bricolage Grotesque 700 (h1, opsz 96), Onest Text, Shantell Sans für Randnotizen",
     "farben": "Grund #f4f6fa, Karten #fff, Text #141414, leise #555b66; Kursarten #3f4fc4, #0b7a4f, #8a3fb0, #a8461a, #b4547a"
    }
   }
  ]
 }
}
