Native Dropdowns mit Popover-API, Anchor Positioning und Invokern
Kursmenü, Coaching-Menü und Sprachwahl als native Popover: Der Invoker öffnet, Anchor Positioning platziert und klappt am Rand um, @starting-style blendet ein.
Untermenüs und Hovercards sind HTML-Popover: popover=auto für Menüs, popover=hint für Hinweise und Hovercards. Ein Button öffnet sie ohne JavaScript per command/commandfor oder popovertarget. Klick daneben und Escape schließen (Light-Dismiss), das liefert der Browser. Die Lage am Auslöser regelt CSS Anchor Positioning mit position-area. Am Rand klappt das Popover per position-try-fallbacks um. Ein- und Ausblenden laufen über @starting-style und transition-behavior: allow-discrete auf display und overlay. Öffnen beim Hover geht künftig deklarativ mit interestfor.
Weniger JavaScript, robuste Fokus- und Schließlogik, Darstellung im Top-Layer ohne z-index-Kämpfe. Man spürt diese technische Qualität als Ruhe und Zuverlässigkeit.
Wann einsetzen
Dropdowns, Sprachauswahl, Account-Menüs und Hovercards in der Navigation. Auch als Grundlage für Mega-Menüs.
Wann nicht
Wenn ältere Browser ohne Fallback bedient werden müssen. Bei Mega-Menüs mit morphendem Viewport, dort bleibt eine Messung per JavaScript nötig.
Varianten
- popover=auto mit popovertarget (Baseline)
- Invoker: command="toggle-popover" mit commandfor
- Hover-Intent per Skript: showPopover() beim Hover, hidePopover() nach 200 ms (Warp)
- popover=hint mit interestfor für Hovercards (experimentell)
- Implizite Anker-Verknüpfung zwischen Popover und Auslöser (Chrome 133)
Umsetzung
HTML: <button commandfor="m1" command="toggle-popover">Kurse</button> <div id="m1" popover><ul>…Links…</ul></div>. CSS: button { anchor-name: --m1 } #m1 { margin: 0; inset: auto; position-anchor: --m1; position-area: bottom span-right; position-try-fallbacks: flip-inline; margin-top: 10px; opacity: 0; translate: 0 -6px; transition: opacity .15s, translate .15s, display .15s allow-discrete, overlay .15s allow-discrete } #m1:popover-open { opacity: 1; translate: 0; transition-duration: .2s } @starting-style { #m1:popover-open { opacity: 0; translate: 0 -6px } }. Kurve cubic-bezier(0.22, 1, 0.36, 1). Fallbacks: @supports (position-area: bottom) für die Lage, Abfrage von HTMLElement.prototype.showPopover für Popover und von 'commandForElement' in HTMLButtonElement.prototype für Invoker (sonst popovertarget setzen). Fallstrick: Popover sind kein Menü im Sinne von ARIA. Links in einer <ul> lassen, kein role=menu für Seitennavigation.
Robust umsetzen
Telefon. Tippen öffnet, Tippen daneben schließt. Auf schmalen Bildschirmen das Popover über die volle Breite legen und nur die Oberkante am Anker ausrichten (top: calc(anchor(bottom) + 8px)). Wie interestfor auf Touch reagiert, ist laut Chrome noch offen. Hinweise deshalb zusätzlich per Tippen öffnen. Light-Dismiss: Seit Chrome 154 schließen Popover (popover=auto) und Dialog erst beim click, nicht mehr bei pointerdown. Wer auf dem Telefon in der Seite wischt oder mit rechts klickt, schließt ein offenes Menü dort nicht mehr; in älteren Versionen konnte das passieren. Eigene Schließ-Logik (etwa der Fallback ohne Popover-API) deshalb ebenfalls auf click legen (Chrome-154-Versionshinweise).
Ohne Bewegung. Weg und Skalierung entfernen. Höchstens kurz überblenden.
Barrierefrei. Der Browser setzt aria-expanded am Invoker selbst und gibt den Fokus beim Schließen zurück. Der Popover-Inhalt folgt in der Tab-Reihenfolge direkt auf den Auslöser. Für Navigationsmenüs Disclosure-Semantik statt role=menu. Hinweise mit role=tooltip und aria-describedby an den Auslöser binden.
Code
<!DOCTYPE html>
<!--
Native Dropdowns mit Popover-API, Anchor Positioning und Invokern
Fundus · Navigation · https://cecodesign.de/lab/fundus/navigation/native-popover-dropdowns/
Eigenständige Datei. Bilder liegen hier unter bilder/ – eigene einsetzen.
-->
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Native Dropdowns mit Popover-API, Anchor Positioning und Invokern · Fundus-Demo</title>
<script>document.documentElement.classList.add('js');if(matchMedia('(prefers-reduced-motion: reduce)').matches)document.documentElement.classList.add('reduziert')</script>
<style>
@font-face { font-family: 'Bricolage Grotesque'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/bricolage-grotesque:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 200 800; font-display: swap; }
@font-face { font-family: 'Onest'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/onest:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }
@font-face { font-family: 'Shantell Sans'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/shantell-sans:vf@latest/latin-full-normal.woff2') format('woff2-variations'); font-weight: 300 800; font-display: swap; }
@font-face { font-family: 'Geist Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist-mono:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }
:root {
--grund: #f3f5f9; --karte: #ffffff; --tinte: #15172a; --leise: rgba(21, 23, 42, .6); --linie: rgba(21, 23, 42, .1);
--marke: #2b3fd6; /* Königsblau wie Füllertinte: Aktionen */
--marke-hell: #e8ebfd;
--erfolg: #10bf7a; /* nur Fortschritt und Häkchen */
--gelb: #f7c325; /* Hervorhebung „Nächster Start“ */
--kurve: cubic-bezier(0.22, 1, 0.36, 1); /* easeOutQuint */
--auf: 200ms; /* Popover öffnet */
--zu: 150ms; /* Popover schließt */
--stagger: 25ms;
--schatten: 0 1px 1px rgba(21, 23, 42, .04), 0 6px 16px -4px rgba(21, 23, 42, .1), 0 24px 48px -12px rgba(21, 23, 42, .16);
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--grund); color: var(--tinte); font-family: 'Onest', system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
body { min-height: 100svh; display: grid; grid-template-rows: auto 1fr auto; overflow-x: clip; }
a { color: inherit; }
button { font: inherit; color: inherit; }
.mono { font: 500 11px/1.35 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); }
.hand { font-family: 'Shantell Sans', 'Onest', sans-serif; font-variation-settings: 'INFM' 40, 'BNCE' 0; font-weight: 500; }
/* ── Kopf ─────────────────────────────────────────────────────────────── */
.kopf { position: relative; z-index: 2; background: color-mix(in srgb, var(--grund) 88%, white); border-bottom: 1px solid var(--linie); }
.kopf-innen { max-width: 1240px; margin: 0 auto; padding: 14px clamp(16px, 3vw, 40px); display: flex; align-items: center; gap: clamp(16px, 3vw, 40px); }
.marke { display: flex; align-items: center; gap: 10px; text-decoration: none; flex: none; }
.marke svg { width: 34px; height: 34px; }
.marke b { display: block; font: 700 19px/1 'Bricolage Grotesque', sans-serif; letter-spacing: -.02em; }
.marke small { display: block; font-size: 11.5px; color: var(--leise); margin-top: 3px; letter-spacing: .01em; }
.hauptnav { flex: 1; }
.hauptnav > ul, .nebennav { list-style: none; padding: 0; display: flex; align-items: center; gap: 2px; }
.nebennav { gap: 6px; }
.navknopf, .navlink {
display: inline-flex; align-items: center; gap: 6px; height: 38px; padding: 0 12px; border-radius: 10px;
font-size: 15px; font-weight: 500; text-decoration: none; background: none; border: 0; cursor: pointer;
transition: background-color .15s var(--kurve), color .15s var(--kurve);
}
.navknopf:hover, .navlink:hover, .navknopf.ist-offen { background: rgba(21, 23, 42, .06); }
.navknopf:focus-visible, .navlink:focus-visible, .knopf:focus-visible, .chip:focus-visible, .menue a:focus-visible { outline: 2px solid var(--marke); outline-offset: 2px; }
.navknopf svg { width: 10px; height: 10px; transition: rotate var(--auf) var(--kurve); }
.navknopf.ist-offen svg { rotate: 180deg; }
.navknopf.sprache { font-size: 13px; font-weight: 600; letter-spacing: .04em; gap: 5px; }
.navknopf.sprache .globus { width: 15px; height: 15px; rotate: none !important; }
.knopf { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 42px; padding: 0 18px; border-radius: 12px; border: 0; cursor: pointer; font-size: 15px; font-weight: 600; text-decoration: none; transition: background-color .15s var(--kurve), translate .15s var(--kurve); }
.knopf.voll { background: var(--marke); color: #fff; }
.knopf.voll:hover { background: #2333b8; }
.knopf.leer { background: var(--karte); box-shadow: inset 0 0 0 1px var(--linie); }
.knopf.leer:hover { background: #fafbfd; }
.knopf:active { translate: 0 1px; }
/* Anker: jeder Auslöser benennt sich, das Popover verweist darauf */
[data-menu="m-kurse"] { anchor-name: --kurse; }
[data-menu="m-coaching"] { anchor-name: --coaching; }
[data-menu="m-sprache"] { anchor-name: --sprache; }
.chip { anchor-name: --raten; }
#m-kurse { position-anchor: --kurse; }
#m-coaching { position-anchor: --coaching; }
#m-sprache { position-anchor: --sprache; }
#h-raten { position-anchor: --raten; }
/* ── Popover: Top-Layer, Lage per Anchor Positioning, Ein/Aus per @starting-style ── */
.menue[popover] {
margin: 0; inset: auto; padding: 8px; border: 0; border-radius: 16px;
background: var(--karte); color: var(--tinte); box-shadow: var(--schatten), 0 0 0 1px var(--linie);
position-area: bottom span-right; /* unter dem Auslöser, nach rechts aufgehend */
position-try-fallbacks: flip-inline; /* am rechten Rand nach links umklappen */
margin-top: 10px;
transform-origin: top center;
opacity: 0; translate: 0 -6px; scale: .98;
transition: opacity var(--zu) var(--kurve), translate var(--zu) var(--kurve), scale var(--zu) var(--kurve),
display var(--zu) allow-discrete, overlay var(--zu) allow-discrete;
}
.menue[popover]:popover-open {
opacity: 1; translate: 0 0; scale: 1;
transition-duration: var(--auf);
}
@starting-style { .menue[popover]:popover-open { opacity: 0; translate: 0 -6px; scale: .98; } }
.menue::backdrop { background: transparent; }
/* Einträge laufen leicht gestaffelt ein, schließen aber ohne Verzögerung */
.menue li { opacity: 0; translate: 0 4px; transition: opacity var(--zu) var(--kurve), translate var(--zu) var(--kurve); }
.menue:popover-open li { opacity: 1; translate: 0 0; transition-duration: var(--auf); transition-delay: calc(var(--i, 0) * var(--stagger) + 40ms); }
@starting-style { .menue:popover-open li { opacity: 0; translate: 0 4px; } }
.menue ul { list-style: none; padding: 0; }
.menue a { display: grid; text-decoration: none; border-radius: 10px; padding: 10px 12px; transition: background-color .15s var(--kurve); }
.menue a:hover, .menue a.gezeigt { background: var(--grund); }
.menue .titel { font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
.menue .zeile { font-size: 13.5px; color: var(--leise); margin-top: 2px; line-height: 1.4; }
.menue .etikett { font-size: 12.5px; color: var(--marke); margin-bottom: 3px; }
.menue .kopfzeile { display: flex; justify-content: space-between; align-items: baseline; padding: 8px 12px 6px; }
.badge { font: 600 11px/1 'Onest', sans-serif; padding: 4px 7px; border-radius: 999px; background: var(--gelb); color: var(--tinte); letter-spacing: .01em; }
/* Kurse: zweispaltig mit Hinweis-Karte */
#m-kurse { width: min(620px, calc(100vw - 32px)); }
.kurse-raster { display: grid; grid-template-columns: 1.35fr 1fr; gap: 6px; }
.kurse-raster ul a { grid-template-columns: 1fr; }
.schnupper { position: relative; border-radius: 12px; background: var(--marke); color: #fff; padding: 16px; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; min-height: 100%; }
.schnupper .hand { font-size: 13px; color: rgba(255, 255, 255, .8); }
.schnupper strong { display: block; font: 650 20px/1.15 'Bricolage Grotesque', sans-serif; letter-spacing: -.01em; margin-top: 6px; max-width: 13ch; }
.schnupper p { font-size: 13.5px; line-height: 1.45; color: rgba(255, 255, 255, .82); margin-top: 8px; }
.schnupper a { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px; background: #fff; color: var(--tinte); padding: 9px 12px; border-radius: 10px; font-size: 14px; font-weight: 600; width: max-content; }
.schnupper a:hover { background: #fff; }
.schnupper svg.feder { position: absolute; right: -18px; top: -10px; width: 120px; opacity: .18; }
/* Coaching */
#m-coaching { width: min(380px, calc(100vw - 32px)); }
.person { display: flex; align-items: center; gap: 12px; margin: 4px 4px 2px; padding: 12px; border-top: 1px solid var(--linie); }
.person .bild { width: 40px; height: 40px; border-radius: 50%; flex: none; }
.person p { font-size: 13.5px; line-height: 1.4; color: var(--leise); }
.person b { color: var(--tinte); font-weight: 600; }
/* Sprache: schmal, sitzt am rechten Rand und klappt nach links um */
#m-sprache { width: 220px; }
#m-sprache a { grid-template-columns: 1fr auto; align-items: center; }
#m-sprache .haken { width: 16px; height: 16px; color: var(--erfolg); }
#m-sprache .titel { flex-direction: column; align-items: flex-start; gap: 0; }
#m-sprache small { display: block; font-size: 12.5px; color: var(--leise); font-weight: 400; }
/* Hint-Popover über dem Raten-Chip */
.hinweis[popover] {
margin: 0; inset: auto; border: 0; padding: 12px 14px; border-radius: 12px; width: 250px;
background: var(--tinte); color: #fff; font-size: 13.5px; line-height: 1.45; box-shadow: var(--schatten);
position-area: top; position-try-fallbacks: flip-block; margin-bottom: 10px;
opacity: 0; translate: 0 4px;
transition: opacity var(--zu) var(--kurve), translate var(--zu) var(--kurve), display var(--zu) allow-discrete, overlay var(--zu) allow-discrete;
}
.hinweis[popover]:popover-open { opacity: 1; translate: 0 0; transition-duration: var(--auf); }
@starting-style { .hinweis[popover]:popover-open { opacity: 0; translate: 0 4px; } }
.hinweis b { font-weight: 600; }
.hinweis .hand { display: block; font-size: 12.5px; color: rgba(255, 255, 255, .65); margin-bottom: 4px; }
/* ── Bühne: Kurs-Hero ────────────────────────────────────────────────── */
.buehne { max-width: 1240px; width: 100%; margin: 0 auto; padding: clamp(36px, 6vw, 88px) clamp(16px, 3vw, 40px) clamp(32px, 4vw, 56px); display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr); gap: clamp(28px, 5vw, 80px); align-items: center; }
.vorspann { font-size: 15px; color: var(--marke); }
h1 { font: 700 clamp(2.25rem, 1.4rem + 3.4vw, 4.25rem)/1.04 'Bricolage Grotesque', sans-serif; font-optical-sizing: auto; letter-spacing: -.025em; margin-top: 14px; text-wrap: balance; }
h1 mark { background: linear-gradient(transparent 62%, color-mix(in srgb, var(--gelb) 70%, transparent) 62% 92%, transparent 92%); color: inherit; padding: 0 .04em; }
.einleitung { font-size: clamp(1.0625rem, 1rem + .25vw, 1.125rem); line-height: 1.6; color: rgba(21, 23, 42, .78); max-width: 52ch; margin-top: 20px; text-wrap: pretty; }
.eckdaten { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 26px; font-size: 14.5px; color: rgba(21, 23, 42, .78); font-variant-numeric: tabular-nums; }
.eckdaten span { display: inline-flex; align-items: center; gap: 7px; }
.eckdaten svg { width: 16px; height: 16px; color: var(--marke); }
.kauf { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 18px; margin-top: 30px; }
.preis { font: 650 30px/1 'Bricolage Grotesque', sans-serif; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.preis small { font: 400 13px/1 'Onest', sans-serif; color: var(--leise); letter-spacing: 0; margin-left: 4px; }
.chip { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px; border-radius: 999px; border: 0; background: var(--marke-hell); color: var(--marke); font-size: 13.5px; font-weight: 600; cursor: help; }
.chip svg { width: 14px; height: 14px; }
.chip.gezeigt, .chip:hover { background: #dce1fb; }
.ctas { display: flex; gap: 10px; flex-wrap: wrap; width: 100%; }
/* Bildwelt: Manuskriptseite mit Randnotiz und Lernweg */
.bildwelt { position: relative; aspect-ratio: 1 / 1.02; max-width: 500px; justify-self: end; width: 100%; }
.blatt { position: absolute; inset: 4% 8% 18% 2%; background: var(--karte); border-radius: 18px; box-shadow: var(--schatten); rotate: -2.2deg; padding: clamp(18px, 2.4vw, 30px); display: flex; flex-direction: column; }
.blatt .hand.etikett { font-size: 13px; color: var(--marke); }
.blatt h2 { font: 650 clamp(18px, 1.6vw, 22px)/1.2 'Bricolage Grotesque', sans-serif; letter-spacing: -.01em; margin-top: 8px; }
.blatt p { font-size: clamp(14px, 1.15vw, 15.5px); line-height: 1.7; margin-top: 12px; color: rgba(21, 23, 42, .82); }
.blatt p mark { background: color-mix(in srgb, var(--gelb) 55%, transparent); color: inherit; border-radius: 3px; padding: 0 2px; }
.blatt .geist { flex: 1; display: grid; align-content: end; gap: 9px; margin-top: 16px; }
.blatt .geist i { display: block; height: 7px; border-radius: 4px; background: rgba(21, 23, 42, .07); }
.notiz { position: absolute; left: 30%; top: 54%; width: 46%; color: var(--marke); rotate: -3deg; display: flex; align-items: flex-start; gap: 6px; }
/* Auch die Randnotiz hängt per Anchor Positioning an der markierten Stelle */
@supports (top: anchor(bottom)) {
.blatt p mark { anchor-name: --stelle; }
.notiz { position-anchor: --stelle; top: calc(anchor(bottom) + 8px); left: calc(anchor(center) - 30px); width: auto; max-width: 52%; }
}
.notiz span { font-size: clamp(13px, 1.15vw, 15.5px); line-height: 1.25; display: block; padding-top: 34px; }
.notiz svg { width: 54px; flex: none; }
.lernweg { position: absolute; left: 14%; right: 0; bottom: 0; background: var(--karte); border-radius: 16px; box-shadow: var(--schatten); padding: 16px 18px; rotate: 1.2deg; }
.lernweg .oben { display: flex; justify-content: space-between; align-items: baseline; font-size: 13.5px; }
.lernweg .oben b { font-weight: 600; }
.lernweg .oben span { color: var(--leise); font-variant-numeric: tabular-nums; }
.schritte { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(8, 1fr); gap: 5px; margin-top: 12px; }
.schritte li { height: 8px; border-radius: 4px; background: rgba(21, 23, 42, .08); }
.schritte li.fertig { background: var(--erfolg); }
.schritte li.jetzt { background: linear-gradient(90deg, var(--erfolg) 40%, rgba(21, 23, 42, .08) 40%); }
.lernweg .modul { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 14px; }
.lernweg .modul svg { width: 18px; height: 18px; color: var(--erfolg); flex: none; }
.lernweg .modul .hand { color: var(--leise); font-size: 13px; margin-left: auto; white-space: nowrap; }
/* ── Steuerung (Fundus) ──────────────────────────────────────────────── */
.steuerung { max-width: 1240px; width: 100%; margin: 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px; padding: 14px clamp(16px, 3vw, 40px) 18px; border-top: 1px solid var(--linie); }
.schalter { display: flex; flex-wrap: wrap; gap: 4px; }
.schalter button { font: 500 11px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); background: none; border: 1px solid transparent; border-radius: 999px; padding: 8px 12px; cursor: pointer; transition: color .15s var(--kurve), border-color .15s var(--kurve), background-color .15s var(--kurve); }
.schalter button[aria-pressed="true"] { color: var(--tinte); border-color: var(--linie); background: var(--karte); }
.schalter button:hover { color: var(--tinte); }
.schalter button:focus-visible { outline: 2px solid var(--marke); outline-offset: 2px; }
.werte { display: flex; flex-wrap: wrap; gap: 4px 18px; text-transform: none; letter-spacing: .02em; flex: 1 1 340px; min-width: 0; }
.werte span { transition: color .15s var(--kurve); }
.werte b { font-weight: 500; color: var(--tinte); }
.werte span.jetzt { color: var(--marke); }
.werte span.jetzt b { color: var(--marke); }
/* Vorführung: gezeichneter Zeiger im Top-Layer, damit er über den Popovern liegt */
.zeiger[popover] { position: fixed; inset: auto; left: 0; top: 0; margin: 0; padding: 0; border: 0; background: none; overflow: visible; pointer-events: none; width: 20px; height: 20px; transition: transform .7s var(--kurve); }
.zeiger svg { display: block; width: 20px; height: 20px; filter: drop-shadow(0 2px 3px rgba(21, 23, 42, .25)); }
.zeiger i { position: absolute; left: -11px; top: -11px; width: 24px; height: 24px; border-radius: 50%; border: 2px solid var(--marke); opacity: 0; scale: .4; }
.zeiger.drueckt i { animation: druck .5s var(--kurve); }
@keyframes druck { 0% { opacity: .9; scale: .4; } 100% { opacity: 0; scale: 1.5; } }
.zeiger .taste { position: absolute; left: 22px; top: 16px; font: 600 11px/1 'Geist Mono', monospace; letter-spacing: .06em; background: var(--tinte); color: #fff; padding: 6px 8px 5px; border-radius: 6px; box-shadow: 0 2px 0 rgba(0, 0, 0, .35); opacity: 0; translate: 0 3px; transition: opacity .15s var(--kurve), translate .15s var(--kurve); }
.zeiger.esc .taste { opacity: 1; translate: 0 0; }
.vorschau body { overflow: hidden; }
.vorschau .steuerung { display: none; }
/* ── Reduzierte Bewegung: kein Weg, kein Scale, nur kurzes Überblenden ── */
.reduziert .menue[popover], .reduziert .menue[popover]:popover-open, .reduziert .hinweis[popover], .reduziert .hinweis[popover]:popover-open {
translate: none; scale: none;
transition: opacity 100ms linear, display 100ms allow-discrete, overlay 100ms allow-discrete;
}
@starting-style { .reduziert .menue[popover]:popover-open, .reduziert .hinweis[popover]:popover-open { translate: none; scale: none; } }
.reduziert .menue li, .reduziert .menue:popover-open li { opacity: 1; translate: none; transition: none; }
@starting-style { .reduziert .menue:popover-open li { opacity: 1; translate: none; } }
.reduziert .navknopf svg, .reduziert .zeiger[popover] { transition: none; }
.reduziert .zeiger.drueckt i { animation: none; }
/* ── Schmale Fenster ─────────────────────────────────────────────────── */
@media (max-width: 1080px) {
.nebennav .navlink.anmelden { display: none; }
}
@media (max-width: 860px) {
.kopf-innen { flex-wrap: wrap; row-gap: 6px; }
.hauptnav { order: 3; flex-basis: 100%; margin: 0 -12px; }
.nebennav { margin-left: auto; }
.buehne { grid-template-columns: 1fr; }
.bildwelt { justify-self: center; max-width: 440px; }
}
@media (max-width: 640px) {
/* Popover über die ganze Breite, nur die Oberkante hängt am Anker */
.menue[popover] { position-area: none; position-try-fallbacks: none; top: calc(anchor(bottom) + 8px); left: 16px; right: 16px; width: auto !important; margin: 0; }
#m-sprache { left: auto; width: 230px !important; }
.kurse-raster { grid-template-columns: 1fr; }
.schnupper { min-height: 0; }
.schnupper strong { max-width: none; }
.nebennav .knopf { display: none; }
.hauptnav .navlink.ueber { display: none; }
.navknopf, .navlink { padding: 0 10px; }
.kauf .ctas .knopf { flex: 1; }
.hinweis[popover] { width: min(260px, calc(100vw - 32px)); }
}
@media (hover: none) {
.chip { cursor: pointer; }
}
</style>
</head>
<body>
<header class="kopf">
<div class="kopf-innen">
<a class="marke" href="#start" aria-label="Kernberg Schreibschule, Startseite">
<svg viewBox="0 0 34 34" aria-hidden="true"><rect width="34" height="34" rx="10" fill="#2b3fd6"/><path d="M5 23.5c3.2-5.6 5.6-8.4 8-8.4s3.4 3.4 5.6 3.4 3.3-6.5 5.9-6.5c1.7 0 3.4 3.6 4.5 6" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round"/><circle cx="24.5" cy="8.6" r="2.1" fill="#f7c325"/></svg>
<span><b>Kernberg</b><small>Schreibschule · Jena</small></span>
</a>
<nav class="hauptnav" aria-label="Hauptnavigation">
<ul>
<li><button type="button" class="navknopf" data-menu="m-kurse">Kurse <svg viewBox="0 0 10 10" aria-hidden="true"><path d="M1.5 3.5 5 7l3.5-3.5" fill="none" stroke="currentColor" stroke-width="1.5"/></svg></button></li>
<li><button type="button" class="navknopf" data-menu="m-coaching">Coaching <svg viewBox="0 0 10 10" aria-hidden="true"><path d="M1.5 3.5 5 7l3.5-3.5" fill="none" stroke="currentColor" stroke-width="1.5"/></svg></button></li>
<li><a class="navlink" href="#termine">Termine</a></li>
<li><a class="navlink ueber" href="#ueber">Über uns</a></li>
</ul>
</nav>
<ul class="nebennav">
<li><button type="button" class="navknopf sprache" data-menu="m-sprache" aria-label="Sprache wählen, aktuell Deutsch"><svg class="globus" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="none" stroke="currentColor" stroke-width="1.3"/><path d="M1.8 8h12.4M8 1.7c-2.2 2.4-2.2 10.2 0 12.6M8 1.7c2.2 2.4 2.2 10.2 0 12.6" fill="none" stroke="currentColor" stroke-width="1.3"/></svg>DE <svg viewBox="0 0 10 10" aria-hidden="true"><path d="M1.5 3.5 5 7l3.5-3.5" fill="none" stroke="currentColor" stroke-width="1.5"/></svg></button></li>
<li><a class="navlink anmelden" href="#anmelden">Anmelden</a></li>
<li><a class="knopf voll" href="#buchen">Platz sichern</a></li>
</ul>
</div>
</header>
<!-- Popover-Inhalte: Links bleiben Links in Listen (Disclosure, kein role=menu) -->
<div class="menue" id="m-kurse" popover>
<div class="kurse-raster">
<div>
<div class="kopfzeile"><span class="hand etikett">Kurse · Winter 2027</span></div>
<ul>
<li style="--i:0"><a href="#erzaehlen"><span class="hand etikett">8 Wochen · live</span><span class="titel">Erzählen lernen <span class="badge">Start 13.01.</span></span><span class="zeile">Vom Einfall zur fertigen Kurzgeschichte</span></a></li>
<li style="--i:1"><a href="#biografisch"><span class="hand etikett">6 Wochen · live</span><span class="titel">Biografisch schreiben</span><span class="zeile">Erinnerungen ordnen, Familiengeschichten erzählen</span></a></li>
<li style="--i:2"><a href="#sachbuch"><span class="hand etikett">5 Module · im eigenen Tempo</span><span class="titel">Sachbuch planen</span><span class="zeile">Exposé, Gliederung und das erste Kapitel</span></a></li>
<li style="--i:3"><a href="#beruf"><span class="hand etikett">4 Abende · live</span><span class="titel">Schreiben im Beruf</span><span class="zeile">Klar formulieren in Mails, Berichten, Anträgen</span></a></li>
</ul>
</div>
<div class="schnupper">
<svg class="feder" viewBox="0 0 120 120" aria-hidden="true"><path d="M104 8C60 14 30 44 22 96l8 4C40 58 66 32 104 8Z" fill="#fff"/><path d="M22 96 12 114" stroke="#fff" stroke-width="4" stroke-linecap="round"/></svg>
<div>
<span class="hand">Noch unsicher?</span>
<strong>Kostenlose Schnupperstunde</strong>
<p>Donnerstags um 19 Uhr, 45 Minuten per Video. Mit einer kleinen Schreibübung.</p>
</div>
<a href="#schnuppern">Termin wählen <svg viewBox="0 0 12 12" width="12" height="12" aria-hidden="true"><path d="M2 6h8M6.5 2.5 10 6l-3.5 3.5" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></a>
</div>
</div>
</div>
<div class="menue" id="m-coaching" popover>
<div class="kopfzeile"><span class="hand etikett">Persönlich begleitet</span></div>
<ul>
<li style="--i:0"><a href="#manuskript"><span class="hand etikett">60 Min. · per Video</span><span class="titel">Manuskript-Coaching 1:1</span><span class="zeile">Ehrliche Rückmeldung zu bis zu 30 Seiten</span></a></li>
<li style="--i:1"><a href="#gruppe"><span class="hand etikett">monatlich · höchstens 6</span><span class="titel">Schreibgruppe mit Feedback</span><span class="zeile">Texte vorlesen, besprechen, weiterschreiben</span></a></li>
<li style="--i:2"><a href="#sprechstunde"><span class="hand etikett">20 Min. · kostenlos</span><span class="titel">Sprechstunde</span><span class="zeile">Welcher Weg passt zu deinem Projekt?</span></a></li>
</ul>
<div class="person">
<svg class="bild" viewBox="0 0 40 40" aria-hidden="true"><circle cx="20" cy="20" r="20" fill="#e8ebfd"/><circle cx="20" cy="16" r="6.5" fill="#2b3fd6"/><path d="M8 34c2.4-6 7-9 12-9s9.6 3 12 9" fill="#2b3fd6"/><path d="M13.5 13.5c1.5-4 11.5-4.5 13 0" stroke="#15172a" stroke-width="2.4" fill="none" stroke-linecap="round"/></svg>
<p><b>Judith Brenner</b> leitet die Schreibschule seit 2016 und hat drei Romane veröffentlicht.</p>
</div>
</div>
<div class="menue" id="m-sprache" popover>
<ul>
<li style="--i:0"><a href="#de" aria-current="true"><span class="titel">Deutsch</span><svg class="haken" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8.5 6.5 12 13 4.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></a></li>
<li style="--i:1"><a href="#en" lang="en"><span class="titel">English</span></a></li>
<li style="--i:2"><a href="#ls"><span class="titel">Leichte Sprache<small>Kurz und einfach erklärt</small></span></a></li>
</ul>
</div>
<div class="hinweis" id="h-raten" popover="hint" role="tooltip">
<span class="hand">Ratenzahlung</span>
<b>3 × 140 €</b> ohne Aufpreis. Die erste Rate ist zum Kursstart fällig, Rücktritt bis 14 Tage vorher kostenlos.
</div>
<main class="buehne" id="start">
<div class="text">
<p class="vorspann hand">Online-Schreibkurs · 8 Wochen · live aus Jena</p>
<h1>In acht Wochen vom Einfall zur <mark>fertigen</mark> Kurzgeschichte.</h1>
<p class="einleitung">Für alle, die schon lange schreiben wollen und einen festen Rahmen brauchen. Jede Woche eine Szene, jede Szene mit persönlicher Rückmeldung von Judith Brenner.</p>
<p class="eckdaten">
<span><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2" y="3" width="12" height="11" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M2 6.5h12M5.5 1.5v3M10.5 1.5v3" stroke="currentColor" stroke-width="1.4"/></svg>Start 13. Januar 2027</span>
<span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M8 4.5V8l2.5 1.5" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>mittwochs 19–20:30 Uhr</span>
<span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6" r="2.6" fill="none" stroke="currentColor" stroke-width="1.4"/><circle cx="11.5" cy="7" r="2" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M1.5 14c.6-2.6 2.3-4 4.5-4s3.9 1.4 4.5 4M10.5 10.6c2 0 3.3 1.1 4 3.4" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>12 Plätze</span>
</p>
<div class="kauf">
<p class="preis">420 €<small>inkl. MwSt.</small></p>
<button type="button" class="chip" interestfor="h-raten" aria-describedby="h-raten">in 3 Raten <svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.8" fill="none" stroke="currentColor" stroke-width="1.3"/><path d="M7 6.2v3.6M7 4.2v.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
<div class="ctas"><a class="knopf voll" href="#buchen">Platz sichern</a><a class="knopf leer" href="#schnuppern">Schnupperstunde</a></div>
</div>
</div>
<div class="bildwelt" aria-hidden="true">
<div class="blatt">
<span class="hand etikett">Modul 03 · Die erste Szene · 45 Min.</span>
<h2>Stufen</h2>
<p>Am Fuchsturm war es windstill. Marie zählte die Stufen, wie sie es als Kind getan hatte, und kam wieder nur bis <mark>neunundachtzig</mark>.</p>
<div class="geist"><i style="width:94%"></i><i style="width:88%"></i><i style="width:58%"></i></div>
</div>
<div class="notiz">
<svg viewBox="0 0 54 60"><path d="M44 56C22 50 10 34 12 6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/><path d="M4 14 12 5l8 9" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span class="hand">schönes Detail! genau so weiter</span>
</div>
<div class="lernweg">
<div class="oben"><b>Dein Lernweg</b><span>Modul 3 von 8</span></div>
<ol class="schritte"><li class="fertig"></li><li class="fertig"></li><li class="jetzt"></li><li></li><li></li><li></li><li></li><li></li></ol>
<p class="modul"><svg viewBox="0 0 18 18"><circle cx="9" cy="9" r="8" fill="currentColor"/><path d="M5.5 9.2 8 11.6l4.6-5" fill="none" stroke="#fff" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg>Figuren, die etwas wollen<span class="hand">Feedback da</span></p>
</div>
</div>
</main>
<div class="steuerung">
<span class="mono">Öffnen per</span>
<div class="schalter" role="group" aria-label="Variante">
<button type="button" data-variante="klick" aria-pressed="true">Klick · command</button>
<button type="button" data-variante="hover" aria-pressed="false">Hover · 200 ms</button>
</div>
<p class="mono werte" data-werte aria-live="polite"></p>
</div>
<div class="zeiger" popover="manual" data-zeiger aria-hidden="true"><svg viewBox="0 0 20 20"><path d="M2.5 1.8 17 10.2l-6.5 1.4-3.1 6.1Z" fill="#15172a" stroke="#ffffff" stroke-width="1.3" stroke-linejoin="round"/></svg><i></i><span class="taste">Esc</span></div>
<script>
(() => {
const html = document.documentElement;
const reduziert = () => html.classList.contains('reduziert');
const $ = s => document.querySelector(s), $$ = s => [...document.querySelectorAll(s)];
const ausloeser = $$('[data-menu]');
const menues = ausloeser.map(b => document.getElementById(b.dataset.menu));
const chip = $('.chip'), hint = $('#h-raten');
const zeiger = $('[data-zeiger]'), werteZeile = $('[data-werte]');
const knoepfe = $$('[data-variante]');
const kannPopover = typeof HTMLElement.prototype.showPopover === 'function';
const kannCommand = 'commandForElement' in HTMLButtonElement.prototype;
const kannInterest = 'interestForElement' in HTMLButtonElement.prototype;
const kannAnker = CSS.supports('position-area: bottom') && CSS.supports('top: anchor(bottom)');
const SCHLIESSEN_MS = 200; // Hover-Intent: Schließverzögerung wie bei Warp gemessen
let variante = 'klick';
const WERTE = {
klick: [['command', '<b>command</b>="toggle-popover" · commandfor'], ['auto', '<b>popover</b>=auto · Light-Dismiss'], ['anker', '<b>position-area</b>: bottom span-right'], ['flip', '<b>position-try-fallbacks</b>: flip-inline'], ['zeit', '<b>200 / 150 ms</b> · cubic-bezier(0.22, 1, 0.36, 1)'], ['hint', '<b>popover</b>=hint · interestfor']],
hover: [['command', '<b>showPopover</b>({ source }) beim Hover'], ['auto', 'schließt nach <b>200 ms</b> · Light-Dismiss bleibt'], ['anker', '<b>position-area</b>: bottom span-right'], ['flip', '<b>position-try-fallbacks</b>: flip-inline'], ['zeit', '<b>200 / 150 ms</b> · cubic-bezier(0.22, 1, 0.36, 1)'], ['hint', '<b>popover</b>=hint · interestfor']],
};
const REDUZIERT = [['command', 'gleiche Auslöser'], ['auto', 'nur <b>opacity</b> · 100 ms linear'], ['anker', 'kein Weg, kein Scale, keine Staffel']];
function zeigeWerte() {
knoepfe.forEach(k => k.setAttribute('aria-pressed', String(k.dataset.variante === variante)));
werteZeile.innerHTML = (reduziert() ? REDUZIERT : WERTE[variante]).map(([k, t]) => `<span data-wert="${k}">${t}</span>`).join('');
}
function hebeHervor(k) { werteZeile.querySelectorAll('span').forEach(s => s.classList.toggle('jetzt', s.dataset.wert === k)); }
/* Fallback ohne Anchor Positioning: Lage beim Öffnen messen */
function platziere(menue, knopf) {
if (kannAnker) return;
const r = knopf.getBoundingClientRect(), w = menue.offsetWidth, rand = 16;
let x = r.left; if (x + w > innerWidth - rand) x = Math.max(rand, r.right - w);
menue.style.left = x + 'px'; menue.style.top = (r.bottom + 10) + 'px'; menue.style.right = 'auto';
}
function zeigerNachOben() { if (html.classList.contains('vorfuehrung') && kannPopover) { try { zeiger.hidePopover(); zeiger.showPopover(); } catch (e) {} } }
menues.forEach((m, i) => {
const b = ausloeser[i];
m.addEventListener('beforetoggle', e => { if (e.newState === 'open') { m.style.display = 'block'; platziere(m, b); m.style.display = ''; } });
m.addEventListener('toggle', e => {
const offen = e.newState === 'open';
b.classList.toggle('ist-offen', offen);
if (!kannCommand) b.setAttribute('aria-expanded', String(offen)); // sonst setzt der Browser aria-expanded selbst
if (offen) zeigerNachOben();
});
});
/* Variante Klick: deklarativ per Invoker, ältere Browser per popovertarget */
function aufKlick() {
ausloeser.forEach(b => {
if (kannCommand) { b.setAttribute('commandfor', b.dataset.menu); b.setAttribute('command', 'toggle-popover'); }
else if (kannPopover) b.setAttribute('popovertarget', b.dataset.menu);
});
}
/* Variante Hover: Intent per Skript wie bei Warp (öffnen sofort, schließen nach 200 ms) */
const uhren = {};
function aufHover() {
ausloeser.forEach(b => { b.removeAttribute('commandfor'); b.removeAttribute('command'); b.removeAttribute('popovertarget'); });
}
function oeffne(b, quelle) {
const m = document.getElementById(b.dataset.menu);
clearTimeout(uhren[m.id]);
if (!m.matches(':popover-open')) { try { m.showPopover({ source: b }); } catch (e) { m.showPopover(); } }
m.dataset.durch = quelle;
}
function schliesseSpaeter(m) { clearTimeout(uhren[m.id]); uhren[m.id] = setTimeout(() => { if (m.matches(':popover-open')) m.hidePopover(); }, SCHLIESSEN_MS); }
ausloeser.forEach((b, i) => {
const m = menues[i];
b.addEventListener('pointerenter', e => { if (variante === 'hover' && e.pointerType === 'mouse') oeffne(b, 'hover'); });
b.addEventListener('pointerleave', e => { if (variante === 'hover' && e.pointerType === 'mouse' && m.dataset.durch === 'hover') schliesseSpaeter(m); });
m.addEventListener('pointerenter', () => clearTimeout(uhren[m.id]));
m.addEventListener('pointerleave', e => { if (variante === 'hover' && e.pointerType === 'mouse' && m.dataset.durch === 'hover') schliesseSpaeter(m); });
// Im Hover-Modus fixiert ein Klick das Menü bzw. schaltet es (Touch, Tastatur)
b.addEventListener('click', () => {
if (variante !== 'hover') return;
if (m.matches(':popover-open') && m.dataset.durch === 'hover') { m.dataset.durch = 'klick'; clearTimeout(uhren[m.id]); }
else if (m.matches(':popover-open')) m.hidePopover();
else oeffne(b, 'klick');
});
});
/* Hint-Popover: interestfor macht Hover und Fokus nativ, sonst ein kleines Skript */
if (!kannInterest) {
let u = null;
const auf = () => { clearTimeout(u); if (kannPopover && !hint.matches(':popover-open')) hint.showPopover(); };
const zu = () => { clearTimeout(u); u = setTimeout(() => { if (hint.matches(':popover-open')) hint.hidePopover(); }, SCHLIESSEN_MS); };
chip.addEventListener('pointerenter', auf); chip.addEventListener('pointerleave', zu);
chip.addEventListener('focus', auf); chip.addEventListener('blur', zu);
}
hint.addEventListener('beforetoggle', e => {
if (e.newState === 'open' && !kannAnker) { const r = chip.getBoundingClientRect(); hint.style.left = r.left + 'px'; hint.style.top = Math.max(8, r.top - 110) + 'px'; }
});
hint.addEventListener('toggle', e => { chip.classList.toggle('gezeigt', e.newState === 'open'); if (e.newState === 'open') zeigerNachOben(); });
// Touch: Tippen auf den Chip schaltet den Hinweis
chip.addEventListener('click', () => { if (matchMedia('(hover: none)').matches && kannPopover) hint.togglePopover(); });
function setzeVariante(v) {
variante = v;
menues.forEach(m => { if (kannPopover && m.matches(':popover-open')) m.hidePopover(); });
v === 'klick' ? aufKlick() : aufHover();
zeigeWerte();
}
knoepfe.forEach(k => k.addEventListener('click', () => { const lief = html.classList.contains('vorfuehrung'); setzeVariante(k.dataset.variante); if (lief) vorfuehren(); }));
$$('a[href^="#"]').forEach(a => a.addEventListener('click', e => e.preventDefault()));
/* ── Vorführung: gedachter Zeiger, echte Auslöser ─────────────────── */
let uhr = [], laeuft = false, pos = { x: 0, y: 0 };
const mitte = el => { const r = el.getBoundingClientRect(); return { x: r.left + r.width * .5, y: r.top + r.height * .5 }; };
function fahre(p) { pos = p; zeiger.style.transform = `translate(${p.x - 3}px, ${p.y - 2}px)`; }
function druecke() { zeiger.classList.remove('drueckt'); void zeiger.offsetWidth; zeiger.classList.add('drueckt'); }
function zeigeEintrag(el) { $$('.menue a.gezeigt').forEach(a => a.classList.remove('gezeigt')); if (el) el.classList.add('gezeigt'); }
function alleZu() { menues.forEach(m => { if (m.matches(':popover-open')) m.hidePopover(); }); if (hint.matches(':popover-open')) hint.hidePopover(); zeigeEintrag(null); }
function klickAuf(b) { druecke(); if (variante === 'klick') b.click(); else oeffne(b, 'hover'); }
function hoverWeg(b) { if (variante === 'hover') { const m = document.getElementById(b.dataset.menu); schliesseSpaeter(m); } }
function schritte() {
const [kurse, coaching, sprache] = ausloeser;
const mk = $('#m-kurse'), ms = $('#m-sprache');
const leer = () => { const r = $('.buehne').getBoundingClientRect(); return { x: r.left + r.width * .3, y: Math.min(innerHeight - 60, r.top + r.height * .82) }; };
const imMenue = (m, n) => mitte(m.querySelectorAll('a')[n]);
const hover = variante === 'hover';
return [
[300, () => { hebeHervor('command'); fahre(mitte(kurse)); }],
[800, () => klickAuf(kurse)],
[1500, () => { hebeHervor('anker'); fahre({ x: imMenue(mk, 0).x - 60, y: imMenue(mk, 0).y }); zeigeEintrag(mk.querySelectorAll('a')[0]); }],
[2200, () => { fahre({ x: imMenue(mk, 1).x - 40, y: imMenue(mk, 1).y }); zeigeEintrag(mk.querySelectorAll('a')[1]); }],
[2900, () => { fahre({ x: imMenue(mk, 2).x - 70, y: imMenue(mk, 2).y }); zeigeEintrag(mk.querySelectorAll('a')[2]); }],
[3700, () => { hebeHervor('auto'); zeigeEintrag(null); if (hover) { hoverWeg(kurse); } fahre(mitte(coaching)); }],
[4300, () => klickAuf(coaching)],
[5600, () => { fahre(leer()); if (hover) hoverWeg(coaching); }],
[6300, () => { druecke(); if (!hover) alleZu(); }],
[7000, () => { hebeHervor('flip'); fahre(mitte(sprache)); }],
[7600, () => klickAuf(sprache)],
[8300, () => { const a = ms.querySelectorAll('a')[2]; fahre({ x: mitte(a).x - 30, y: mitte(a).y }); zeigeEintrag(a); }],
[9200, () => { zeiger.classList.add('esc'); alleZu(); }],
[9900, () => { zeiger.classList.remove('esc'); hebeHervor('hint'); fahre(mitte(chip)); }],
[10500, () => { if (kannPopover) { try { hint.showPopover({ source: chip }); } catch (e) { hint.showPopover(); } } }],
[12400, () => { fahre(leer()); }],
[12700, () => { if (hint.matches(':popover-open')) hint.hidePopover(); hebeHervor(null); }],
];
}
const RUNDE = 13600;
function runde() {
uhr.forEach(clearTimeout); uhr = [];
schritte().forEach(([t, f]) => uhr.push(setTimeout(f, t)));
uhr.push(setTimeout(runde, RUNDE));
}
function vorfuehren() {
pause();
alleZu();
html.classList.add('vorfuehrung');
if (kannPopover) { try { zeiger.showPopover(); } catch (e) {} }
const r = $('.buehne').getBoundingClientRect();
zeiger.style.transition = 'none'; fahre({ x: r.left + r.width * .45, y: r.top + r.height * .6 }); void zeiger.offsetWidth; zeiger.style.transition = '';
laeuft = true; runde();
}
function pause() { uhr.forEach(clearTimeout); uhr = []; laeuft = false; }
function weiter() { if (!laeuft && html.classList.contains('vorfuehrung')) runde(); }
function neustart() {
pause(); alleZu(); html.classList.remove('vorfuehrung'); zeiger.classList.remove('esc', 'drueckt');
if (kannPopover && zeiger.matches(':popover-open')) zeiger.hidePopover();
hebeHervor(null); zeigeWerte();
}
setzeVariante('klick');
new MutationObserver(zeigeWerte).observe(html, { attributes: true, attributeFilter: ['class'] });
})();
</script>
</body>
</html>