Zum Inhalt
← Navigation

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>