Zum Inhalt
← Hover

Hovercard / Vorschau per Interest Invoker

Fachbegriffe und Namen öffnen nach kurzem Verweilen eine Erklär- oder Profilkarte, nativ per interestfor und popover=hint, ohne Seitenwechsel.

Ein normaler Link bekommt interestfor mit der ID einer Karte. Die Karte ist ein Element mit popover="hint". Der Browser öffnet sie bei Interesse: Hover, Tastaturfokus oder langes Drücken. Eine eingebaute Verzögerung (Standard 0,5 s rein und raus) verhindert Flackern beim Drüberstreifen und erlaubt den Weg vom Link in die Karte. Anchor Positioning setzt die Karte an den Link und klappt sie am Rand um. Ein- und Ausblenden laufen über @starting-style und transition-behavior: allow-discrete.

Kontext ohne Seitenwechsel: Glossar, Profil oder Artikelvorschau erscheinen genau dort, wo die Frage entsteht. Seit 2026 geht das in Chromium ohne JavaScript, mit Tastatur und mit korrekter Verknüpfung für Screenreader. Es ist das Hover-Muster der Plattform.

Wann einsetzen

Glossarbegriffe und Fachwörter, Personen- und Autorenlinks, Fußnoten, Projekt-Teaser in Listen, Referenzen in Case Studies.

Wann nicht

Für kurze Tooltips an Symbolen (eigenes Tooltip-Muster). Für Informationen, die man unbedingt sehen muss: Sie gehören in den Text. Wo langes Drücken auf Touch mit dem Systemmenü kollidiert.

Varianten

  • Reiner Erklärtext ohne Links (der Browser setzt aria-describedby)
  • Karte mit Links und Knopf, etwa Profil mit „Termin anfragen“ (der Browser setzt aria-details)
  • Kürzere Verzögerung, z. B. interest-delay: .2s .1s
  • Skip-Delay: Verzögerung 0, wenn schon eine Karte offen ist (:root:has(:interest-source))
  • Karte morpht beim Klick per View Transition in die Zielseite
  • Polyfill für Browser ohne interestfor

Umsetzung

HTML: <a href="/glossar#sprechstunde" interestfor="hc1">Sprechstunde</a> und <div id="hc1" popover="hint" class="hc">…</div>.

CSS: .hc { position-area: block-end span-inline-end; position-try-fallbacks: flip-block, flip-inline; inset: auto; margin: 10px 0 0; opacity: 0; transform: translateY(-8px) scale(.95); transition: opacity .4s, transform .4s, display .4s allow-discrete, overlay .4s allow-discrete } .hc:popover-open { opacity: 1; transform: none } @starting-style { .hc:popover-open { opacity: 0; transform: translateY(-8px) scale(.95) } } [interestfor] { interest-delay: .2s .1s } :root:has(:interest-source) [interestfor] { interest-delay-start: 0s }. Die Transition nur unter prefers-reduced-motion: no-preference setzen.

Fallstricke: Die UA-Styles von [popover] (inset: 0, margin: auto) zurücksetzen, sonst steht die Karte in der Mitte. role=tooltip und aria-describedby nicht selbst setzen, das macht der Browser. Rückfall ohne interestfor: dieselbe Zeitlogik per pointerenter/leave und focus/blur, Öffnen mit showPopover({ source: link }), damit der Link der Anker wird. Polyfill nur bei Bedarf laden.

Robust umsetzen

Telefon. Laut Spezifikation öffnet langes Drücken; ein normales Tippen navigiert. Für Glossar und Profile ist Tippen zum Öffnen verständlicher. Die Erklärung muss außerdem auf der Seite stehen (Glossar, FAQ).

Ohne Bewegung. Ohne Transition: Die Karte ist sofort da und sofort weg. Die Verzögerung bleibt, weil sie kein Bewegungseffekt ist.

Barrierefrei. Der Browser verknüpft Link und Karte selbst: aria-describedby bei reinem Text, aria-details bei interaktivem Inhalt. Tastaturfokus öffnet ebenfalls, Esc schließt. Inhalte der Karte zusätzlich auf der Zielseite oder im Glossar anbieten.

Code

<!DOCTYPE html>
<!--
  Hovercard / Vorschau per Interest Invoker
  Fundus · Hover · https://cecodesign.de/lab/fundus/hover/hovercard-interest-invoker/
  Eigenständige Datei. Bilder liegen hier unter bilder/ – eigene einsetzen.
-->
<html lang="de" data-tempo="kurz">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hovercard / Vorschau per Interest Invoker · 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: 'Hedvig Letters Serif'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/hedvig-letters-serif:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Google Sans Flex'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/google-sans-flex:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 1000; 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: #f5f7f7; --flaeche: #e2e0de; --karte: #fbfbfa;
  --marke: #005450; --marke-tief: #003f3c; --text: #363b3b; --leise: #596666;
  --akzent: #ffc776; --linie: rgba(54, 59, 59, .14);
  --kurve: cubic-bezier(0.25, 0.1, 0.25, 1);   /* ease, gemessen in der Chrome-Anleitung */
  --dauer: 400ms;
  --ui: cubic-bezier(0.2, 0, 0.38, 0.9);       /* Rezept: UI-Feedback */
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--grund); color: var(--text); font-family: 'Google Sans Flex', system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
body { min-height: 100svh; font-size: 17px; line-height: 1.6; }
a { color: inherit; }
.serif { font-family: 'Hedvig Letters Serif', Georgia, serif; font-weight: 400; font-optical-sizing: auto; }
.rubrik { font-size: 13px; font-weight: 560; letter-spacing: .08em; text-transform: uppercase; color: var(--marke); }

/* Kopfzeile: Termin und Telefon immer sichtbar */
.kopf { display: flex; align-items: center; gap: 32px; padding: 18px clamp(18px, 4vw, 56px); border-bottom: 1px solid var(--linie); }
.logo { display: flex; align-items: center; gap: 12px; text-decoration: none; margin-right: auto; }
.logo svg { width: 26px; height: 30px; flex: none; }
.logo b { font-family: 'Hedvig Letters Serif', Georgia, serif; font-weight: 400; font-size: 23px; letter-spacing: -.01em; line-height: 1; color: var(--marke-tief); }
.logo small { display: block; font-size: 12.5px; color: var(--leise); letter-spacing: .01em; margin-top: 3px; }
.nav { display: flex; gap: 28px; list-style: none; padding: 0; font-size: 15px; }
.nav a { text-decoration: none; color: var(--text); transition: color 150ms var(--ui); }
.nav a:hover { color: var(--marke); }
.tel { font-size: 15px; font-weight: 500; text-decoration: none; color: var(--marke-tief); font-variant-numeric: tabular-nums; }
.knopf { display: inline-flex; align-items: center; gap: 10px; height: 44px; padding: 0 20px; border-radius: 999px; background: var(--marke); color: #f5f7f7; text-decoration: none; font-size: 15px; font-weight: 520; transition: background-color 150ms var(--ui); white-space: nowrap; }
.knopf:hover { background: var(--marke-tief); }
.knopf.klein { height: 38px; padding: 0 16px; font-size: 14px; }
:focus-visible { outline: 2px solid var(--marke); outline-offset: 3px; border-radius: 4px; }

/* Abschnitt „Wobei wir helfen“ */
.abschnitt { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(32px, 6vw, 104px); padding: clamp(36px, 6vw, 84px) clamp(18px, 4vw, 56px) clamp(40px, 6vw, 88px); max-width: 1440px; margin: 0 auto; }
h1 { font-size: clamp(2.25rem, 1.4rem + 3.2vw, 4.5rem); line-height: 1.08; letter-spacing: -.01em; margin: 18px 0 28px; color: var(--marke-tief); text-wrap: balance; }
h1 em { font-style: normal; color: #4a8a81; }
.lead { font-size: clamp(17px, 1rem + .3vw, 20px); line-height: 1.65; max-width: 60ch; text-wrap: pretty; }
.lead + .lead { margin-top: 1em; }
.hinweis { display: flex; gap: 12px; align-items: baseline; margin-top: 30px; font-size: 14.5px; color: var(--leise); max-width: 56ch; }
.hinweis i { flex: none; width: 22px; height: 1px; background: currentColor; translate: 0 -4px; }
.hinweis .touch { display: none; }

/* Auslöser: Fachbegriff gepunktet, Person durchgezogen */
[interestfor] { color: var(--marke-tief); text-decoration-line: underline; text-underline-offset: .24em; text-decoration-thickness: 1.5px; border-radius: 3px; transition: background-color 150ms var(--ui), text-decoration-color 150ms var(--ui); }
.begriff { text-decoration-style: dotted; text-decoration-color: color-mix(in srgb, var(--marke) 70%, transparent); }
.person { text-decoration-color: color-mix(in srgb, var(--marke) 35%, transparent); font-weight: 520; }
[interestfor]:interest-source, [interestfor].zeigt { background: rgba(0, 84, 80, .09); box-shadow: 0 0 0 3px rgba(0, 84, 80, .09); text-decoration-color: var(--marke); }

/* Zeitlogik nativ: interest-delay (rein raus) */
:root[data-tempo="standard"] [interestfor] { interest-delay: .5s .5s; }
:root[data-tempo="kurz"] [interestfor], :root[data-tempo="skip"] [interestfor] { interest-delay: .2s .1s; }
:root[data-tempo="skip"]:has(:interest-source) [interestfor] { interest-delay-start: 0s; }

/* Die Karten: popover="hint", per Anchor Positioning am Auslöser */
.hc {
  position: fixed; inset: auto; margin: 10px 0 0; padding: 0; border: 0;
  position-area: block-end span-inline-end;
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
  color: var(--text); background: var(--karte); border-radius: 16px;
  box-shadow: 0 0 0 1px rgba(0, 63, 60, .08), 0 18px 48px -12px rgba(0, 40, 38, .28), 0 4px 12px -4px rgba(0, 40, 38, .12);
  opacity: 0; transform: translateY(-8px) scale(.95); transform-origin: 24px 0;
  transition: opacity var(--dauer) var(--kurve), transform var(--dauer) var(--kurve), display var(--dauer) allow-discrete, overlay var(--dauer) allow-discrete;
}
.hc:popover-open { opacity: 1; transform: none; }
@starting-style { .hc:popover-open { opacity: 0; transform: translateY(-8px) scale(.95); } }
.reduziert .hc { transition: none; transform: none; }

/* Glossar-Hinweis: reiner Text, dunkel */
.glossar { width: min(356px, calc(100vw - 32px)); padding: 18px 20px 19px; background: var(--marke-tief); color: #e9efee; box-shadow: 0 18px 44px -14px rgba(0, 40, 38, .5); }
.glossar .wort { display: block; font-family: 'Hedvig Letters Serif', Georgia, serif; font-size: 20px; line-height: 1.2; color: #fff; margin-bottom: 8px; }
.glossar p { font-size: 15px; line-height: 1.55; }
.glossar .fakt { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.glossar .fakt span { font-size: 12.5px; padding: 3px 10px; border-radius: 999px; background: rgba(255, 199, 118, .16); color: var(--akzent); font-variant-numeric: tabular-nums; }

/* Personenkarte: mit Links und Knopf (der Browser verknüpft per aria-details) */
.profil { width: min(372px, calc(100vw - 32px)); padding: 20px; }
.profil header { display: grid; grid-template-columns: 56px 1fr; gap: 16px; align-items: center; }
.profil svg { width: 56px; height: 64px; display: block; }
.profil .name { font-family: 'Hedvig Letters Serif', Georgia, serif; font-size: 22px; line-height: 1.15; color: var(--marke-tief); }
.profil .rolle { font-size: 14px; line-height: 1.4; color: var(--leise); margin-top: 3px; }
.profil dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--linie); font-size: 14.5px; line-height: 1.45; }
.profil dt { color: var(--leise); }
.profil dd { margin: 0; }
.profil .frei { display: flex; align-items: center; gap: 10px; margin-top: 14px; padding: 10px 12px; border-radius: 10px; background: #f0eeeb; font-size: 14px; }
.profil .frei b { font-weight: 560; font-variant-numeric: tabular-nums; }
.profil .frei i { width: 8px; height: 8px; border-radius: 50%; background: #2f9a6a; box-shadow: 0 0 0 4px rgba(47, 154, 106, .16); flex: none; }
.profil .aktionen { display: flex; align-items: center; gap: 16px; margin-top: 16px; }
.profil .aktionen a:not(.knopf) { font-size: 14.5px; color: var(--marke-tief); text-underline-offset: .22em; }

/* Rechte Spalte: Anliegen in Alltagssprache, Fachbegriff als Unterzeile */
.anliegen { align-self: start; }
.anliegen ul { list-style: none; padding: 0; margin-top: 18px; border-top: 1px solid var(--linie); }
.anliegen li a { display: grid; grid-template-columns: 1fr auto; gap: 2px 16px; padding: 18px 0 17px; border-bottom: 1px solid var(--linie); text-decoration: none; }
.anliegen li strong { font-family: 'Hedvig Letters Serif', Georgia, serif; font-weight: 400; font-size: clamp(20px, 1.1rem + .5vw, 24px); line-height: 1.25; color: var(--marke-tief); }
.anliegen li span { grid-column: 1; font-size: 14.5px; color: var(--leise); }
.anliegen li svg { grid-row: 1 / 3; grid-column: 2; align-self: center; width: 18px; height: 18px; color: var(--marke); transition: translate 150ms var(--ui); }
.anliegen li a:hover svg { translate: 4px 0; }
.wartezeit { margin-top: 26px; padding: 20px 22px; border-radius: 16px; background: var(--flaeche); font-size: 15.5px; line-height: 1.55; }
.wartezeit .marke { display: inline-block; font-size: 12.5px; font-weight: 560; padding: 3px 10px; border-radius: 999px; background: var(--akzent); color: #3d2c0f; margin-bottom: 10px; letter-spacing: .02em; }
.wartezeit b { font-weight: 560; font-variant-numeric: tabular-nums; }

/* Unterhalb: Glossar und Team – die Erklärungen stehen auch ohne Hover auf der Seite */
.unten { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(32px, 6vw, 104px); padding: clamp(40px, 6vw, 80px) clamp(18px, 4vw, 56px); border-top: 1px solid var(--linie); max-width: 1440px; margin: 0 auto; }
.unten h2 { font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.75rem); line-height: 1.12; color: var(--marke-tief); margin: 14px 0 22px; }
.unten dl { display: grid; gap: 18px; }
.unten dt { font-weight: 560; color: var(--marke-tief); }
.unten dd { margin: 2px 0 0; max-width: 62ch; }
.unten :target { scroll-margin-top: 24px; }
.team { list-style: none; padding: 0; display: grid; gap: 16px; }
.team li { display: grid; grid-template-columns: 44px 1fr; gap: 14px; align-items: center; }
.team svg { width: 44px; height: 50px; }
.team b { display: block; font-weight: 560; color: var(--marke-tief); }
.team span { font-size: 14.5px; color: var(--leise); }
.notfall { grid-column: 1 / -1; font-size: 14.5px; color: var(--leise); padding-top: 22px; border-top: 1px solid var(--linie); }
.notfall a { font-weight: 560; color: var(--marke-tief); text-decoration: none; font-variant-numeric: tabular-nums; }

/* Pult: Verzögerung umschalten, Werte zeigen */
.pult { position: fixed; right: 16px; bottom: 16px; z-index: 20; display: grid; gap: 8px; padding: 12px 14px 12px; border-radius: 12px; background: rgba(251, 251, 250, .92); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: 0 0 0 1px var(--linie), 0 8px 28px -10px rgba(0, 40, 38, .25); }
.pult .mono, .pult button { font: 500 10.5px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; }
.pult .mono { color: var(--leise); }
.pult .knoepfe { display: flex; gap: 4px; }
.pult button { padding: 8px 10px; border-radius: 999px; border: 1px solid var(--linie); background: none; color: var(--text); cursor: pointer; transition: background-color 150ms var(--ui), color 150ms var(--ui); }
.pult button[aria-pressed="true"] { background: var(--marke); border-color: var(--marke); color: #f5f7f7; }
.pult .werte { letter-spacing: .06em; text-transform: none; font-size: 11px; color: var(--leise); font-variant-numeric: tabular-nums; }

/* Gezeichneter Zeiger für die Vorführung */
/* als popover="manual", damit er über den Karten im Top Layer liegt */
.zeiger { position: fixed; inset: auto; left: 0; top: 0; margin: 0; padding: 0; border: 0; background: none; overflow: visible; width: 20px; height: 20px; pointer-events: none; }
.zeiger svg { display: block; width: 20px; height: 20px; }
.vorschau body { overflow: hidden; }
.vorschau .unten { display: none; }
.vorschau .abschnitt { padding-top: 34px; }
.vorschau h1 { font-size: 48px; margin: 12px 0 22px; }
.mobilleiste { display: none; }

@media (max-width: 1100px) { .nav { display: none; } }
@media (max-width: 860px) {
  .abschnitt, .unten { grid-template-columns: 1fr; }
  .tel { display: none; }
}
@media (max-width: 560px) {
  .kopf { gap: 12px; padding: 14px 18px; }
  .kopf .knopf { display: none; }
  .logo small { font-size: 11.5px; }
  h1 { margin: 12px 0 20px; }
  .mobilleiste { display: grid; grid-template-columns: repeat(3, 1fr); position: fixed; left: 0; right: 0; bottom: 0; z-index: 15; background: var(--karte); border-top: 1px solid var(--linie); padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); }
  .mobilleiste a { display: grid; justify-items: center; gap: 2px; padding: 6px 0; text-decoration: none; font-size: 12.5px; font-weight: 520; color: var(--marke-tief); }
  .mobilleiste a.haupt { background: var(--marke); color: #f5f7f7; border-radius: 12px; }
  .mobilleiste svg { width: 20px; height: 20px; }
  body { padding-bottom: 72px; }
  .pult { bottom: 84px; }
}
/* Touch: kein Hover. Tippen öffnet die Karte, der Link führt nicht weg. */
@media (hover: none) {
  .hinweis .maus { display: none; }
  .hinweis .touch { display: inline; }
  .begriff { text-decoration-style: dotted; }
}
</style>
</head>
<body>
<header class="kopf">
  <a class="logo" href="#" aria-label="Tiefburg, Praxis für Psychotherapie, Startseite">
    <svg viewBox="0 0 26 30" aria-hidden="true"><path d="M1 29V13a12 12 0 0 1 24 0v16" fill="none" stroke="#005450" stroke-width="2"/><path d="M8 29v-9a5 5 0 0 1 10 0v9" fill="#005450"/></svg>
    <span><b>Tiefburg</b><small>Praxis für Psychotherapie · Heidelberg</small></span>
  </a>
  <ul class="nav">
    <li><a href="#" aria-current="page">Wobei wir helfen</a></li>
    <li><a href="#">Ablauf</a></li>
    <li><a href="#team">Team</a></li>
    <li><a href="#glossar">Kosten &amp; Kasse</a></li>
  </ul>
  <a class="tel" href="tel:+496221438712">06221 43 87 12</a>
  <a class="knopf" href="#">Erstgespräch anfragen</a>
</header>

<main>
<section class="abschnitt" aria-labelledby="titel">
  <div>
    <p class="rubrik">Wobei wir helfen</p>
    <h1 id="titel" class="serif">Reden hilft. <em>Der Weg zu uns ist leichter, als Sie denken.</em></h1>
    <p class="lead">Sie brauchen keine Überweisung. Ihr erster Termin ist eine <a class="begriff" href="#gl-sprechstunde" interestfor="hc-sprechstunde">psychotherapeutische Sprechstunde</a>: Sie erzählen, wir hören zu. Passt es, folgen zwei bis vier <a class="begriff" href="#gl-probatorik" interestfor="hc-probatorik">probatorische Sitzungen</a>. Danach stellen wir den Antrag bei Ihrer Krankenkasse gemeinsam.</p>
    <p class="lead">Bei <a class="person" href="#team-sauerwein" interestfor="hc-sauerwein">Henrike Sauerwein</a> arbeiten Sie verhaltenstherapeutisch, bei <a class="person" href="#team-haddou" interestfor="hc-haddou">Tarek Haddou</a> tiefenpsychologisch fundiert.</p>
    <p class="hinweis"><i></i><span class="maus">Unterstrichene Begriffe und Namen öffnen eine kurze Erklärung, wenn Sie mit der Maus darauf bleiben oder per Tab dorthin springen. Alles steht auch unten im Glossar.</span><span class="touch">Tippen Sie auf einen unterstrichenen Begriff oder Namen. Alles steht auch unten im Glossar.</span></p>
  </div>

  <aside class="anliegen" aria-label="Häufige Anliegen">
    <p class="rubrik">Häufige Anliegen</p>
    <ul>
      <li><a href="#"><strong>Wenn die Gedanken nachts kreisen</strong><span>Schlafstörungen, Insomnie</span><svg viewBox="0 0 18 18" aria-hidden="true"><path d="M3 9h11M10 4.5 14.5 9 10 13.5" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></a></li>
      <li><a href="#"><strong>Wenn Angst den Alltag bestimmt</strong><span>Angst- und Panikstörung</span><svg viewBox="0 0 18 18" aria-hidden="true"><path d="M3 9h11M10 4.5 14.5 9 10 13.5" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></a></li>
      <li><a href="#"><strong>Wenn alles zu viel wird</strong><span>Erschöpfung, Depression</span><svg viewBox="0 0 18 18" aria-hidden="true"><path d="M3 9h11M10 4.5 14.5 9 10 13.5" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></a></li>
      <li><a href="#"><strong>Nach einem schweren Erlebnis</strong><span>Posttraumatische Belastung (PTBS)</span><svg viewBox="0 0 18 18" aria-hidden="true"><path d="M3 9h11M10 4.5 14.5 9 10 13.5" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></a></li>
    </ul>
    <div class="wartezeit">
      <span class="marke">Stand November</span><br>
      Wartezeit auf eine Sprechstunde: <b>etwa 5 Wochen</b>. In einer Krise ist eine <a class="begriff" href="#gl-akut" interestfor="hc-akut">Akutbehandlung</a> meist innerhalb von <b>14 Tagen</b> möglich.
    </div>
  </aside>
</section>

<section class="unten">
  <div id="glossar">
    <p class="rubrik">Glossar</p>
    <h2 class="serif">Begriffe kurz erklärt</h2>
    <dl>
      <div id="gl-sprechstunde"><dt>Psychotherapeutische Sprechstunde</dt><dd>Das erste Gespräch, bevor eine Therapie beginnt. Bis zu 50 Minuten, ohne Überweisung, die Krankenkasse zahlt. Danach wissen Sie, ob und welche Behandlung passt.</dd></div>
      <div id="gl-probatorik"><dt>Probatorische Sitzungen</dt><dd>Probestunden vor der eigentlichen Therapie. Zwei bis vier Termine, in denen Sie prüfen, ob Sie mit uns arbeiten möchten. Sie verpflichten sich damit zu nichts.</dd></div>
      <div id="gl-akut"><dt>Akutbehandlung</dt><dd>Schnelle Hilfe in einer Krise: bis zu zwölf Termine zu je 50 Minuten, ohne Antrag bei der Kasse.</dd></div>
    </dl>
  </div>
  <div id="team">
    <p class="rubrik">Team</p>
    <h2 class="serif">Zwei Wege, ein Ziel</h2>
    <ul class="team">
      <li id="team-sauerwein"><svg viewBox="0 0 56 64" aria-hidden="true"><path d="M0 64V28a28 28 0 0 1 56 0v36z" fill="#e2e0de"/><text x="28" y="47" text-anchor="middle" font-family="Hedvig Letters Serif, Georgia, serif" font-size="21" fill="#003f3c">HS</text></svg><span><b>Henrike Sauerwein</b>Psychologische Psychotherapeutin, Verhaltenstherapie</span></li>
      <li id="team-haddou"><svg viewBox="0 0 56 64" aria-hidden="true"><path d="M0 64V28a28 28 0 0 1 56 0v36z" fill="#cfe0dc"/><text x="28" y="47" text-anchor="middle" font-family="Hedvig Letters Serif, Georgia, serif" font-size="21" fill="#003f3c">TH</text></svg><span><b>Tarek Haddou</b>Psychologischer Psychotherapeut, tiefenpsychologisch fundiert</span></li>
    </ul>
  </div>
  <p class="notfall">In einer akuten Krise: Telefonseelsorge <a href="tel:08001110111">0800 111 0 111</a> · ärztlicher Bereitschaftsdienst <a href="tel:116117">116 117</a> · Notruf <a href="tel:112">112</a></p>
</section>
</main>

<!-- Die Karten. popover="hint" schließt keine offenen auto-Popover und wird bei Esc oder Klick daneben geschlossen. -->
<div id="hc-sprechstunde" class="hc glossar" popover="hint">
  <span class="wort">Psychotherapeutische Sprechstunde</span>
  <p>Das erste Gespräch, bevor eine Therapie beginnt. Danach wissen Sie, ob und welche Behandlung passt.</p>
  <p class="fakt"><span>bis 50 Min.</span><span>ohne Überweisung</span><span>Kasse zahlt</span></p>
</div>
<div id="hc-probatorik" class="hc glossar" popover="hint">
  <span class="wort">Probatorische Sitzungen</span>
  <p>Probestunden vor der eigentlichen Therapie. Sie prüfen, ob Sie mit uns arbeiten möchten, und verpflichten sich zu nichts.</p>
  <p class="fakt"><span>2 bis 4 Termine</span><span>vor dem Antrag</span></p>
</div>
<div id="hc-akut" class="hc glossar" popover="hint">
  <span class="wort">Akutbehandlung</span>
  <p>Schnelle Hilfe in einer Krise, ohne Antrag bei der Krankenkasse.</p>
  <p class="fakt"><span>bis 12 × 50 Min.</span><span>Beginn meist in 14 Tagen</span></p>
</div>
<div id="hc-sauerwein" class="hc profil" popover="hint">
  <header>
    <svg viewBox="0 0 56 64" aria-hidden="true"><path d="M0 64V28a28 28 0 0 1 56 0v36z" fill="#e2e0de"/><text x="28" y="47" text-anchor="middle" font-family="Hedvig Letters Serif, Georgia, serif" font-size="21" fill="#003f3c">HS</text></svg>
    <div><p class="name">Henrike Sauerwein</p><p class="rolle">Psychologische Psychotherapeutin<br>Verhaltenstherapie</p></div>
  </header>
  <dl><dt>Schwerpunkte</dt><dd>Schlaf, Angst, Zwang</dd><dt>Sprachen</dt><dd>Deutsch, Englisch, Schwedisch</dd></dl>
  <p class="frei"><i></i><span>Nächste Sprechstunde <b>Do 13.11., 9:00</b></span></p>
  <p class="aktionen"><a class="knopf klein" href="#">Termin anfragen</a><a href="#team-sauerwein">Zum Profil</a></p>
</div>
<div id="hc-haddou" class="hc profil" popover="hint">
  <header>
    <svg viewBox="0 0 56 64" aria-hidden="true"><path d="M0 64V28a28 28 0 0 1 56 0v36z" fill="#cfe0dc"/><text x="28" y="47" text-anchor="middle" font-family="Hedvig Letters Serif, Georgia, serif" font-size="21" fill="#003f3c">TH</text></svg>
    <div><p class="name">Tarek Haddou</p><p class="rolle">Psychologischer Psychotherapeut<br>tiefenpsychologisch fundiert</p></div>
  </header>
  <dl><dt>Schwerpunkte</dt><dd>Trauer, Beziehungen, Krisen nach Trennung</dd><dt>Sprachen</dt><dd>Deutsch, Arabisch, Französisch</dd></dl>
  <p class="frei"><i></i><span>Nächste Sprechstunde <b>Di 18.11., 16:30</b></span></p>
  <p class="aktionen"><a class="knopf klein" href="#">Termin anfragen</a><a href="#team-haddou">Zum Profil</a></p>
</div>

<nav class="mobilleiste" aria-label="Schnellzugriff">
  <a href="tel:+496221438712"><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M5.5 2.5h3l1.2 3.6-2 1.4a10 10 0 0 0 4.8 4.8l1.4-2 3.6 1.2v3a1.5 1.5 0 0 1-1.6 1.5A14.5 14.5 0 0 1 4 4.1 1.5 1.5 0 0 1 5.5 2.5Z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>Anrufen</a>
  <a class="haupt" href="#"><svg viewBox="0 0 20 20" aria-hidden="true"><rect x="3" y="4" width="14" height="13" rx="2" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M3 8h14M7 2.5v3M13 2.5v3" stroke="currentColor" stroke-width="1.5"/></svg>Termin</a>
  <a href="#"><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M10 18s5.5-5.2 5.5-9.5a5.5 5.5 0 0 0-11 0C4.5 12.8 10 18 10 18Z" fill="none" stroke="currentColor" stroke-width="1.5"/><circle cx="10" cy="8.5" r="2" fill="currentColor"/></svg>Anfahrt</a>
</nav>

<div class="pult">
  <span class="mono">interest-delay</span>
  <div class="knoepfe" role="group" aria-label="Verzögerung">
    <button type="button" data-tempo="standard" aria-pressed="false">0,5 s Standard</button>
    <button type="button" data-tempo="kurz" aria-pressed="true">0,2 / 0,1 s</button>
    <button type="button" data-tempo="skip" aria-pressed="false">+ Skip</button>
  </div>
  <span class="mono werte" data-werte>.2s .1s · 400 ms ease · −8 px · scale .95</span>
</div>

<div class="zeiger" data-zeiger popover="manual" aria-hidden="true"><svg viewBox="0 0 20 20"><path d="M2 1.5 16.5 10l-6.6 1.4-3.2 6.1Z" fill="#003f3c" stroke="#f5f7f7" stroke-width="1.3" stroke-linejoin="round"/></svg></div>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const ausloeser = [...document.querySelectorAll('[interestfor]')];
  const karte = a => document.getElementById(a.getAttribute('interestfor'));
  const nativ = 'interestForElement' in HTMLAnchorElement.prototype;
  const anker = CSS.supports('position-area', 'block-end');
  const touch = matchMedia('(hover: none)');
  const zeiger = document.querySelector('[data-zeiger]');

  /* Tempo: Werte der drei Stufen (Sekunden rein / raus) */
  const TEMPO = { standard: [500, 500, '.5s .5s'], kurz: [200, 100, '.2s .1s'], skip: [200, 100, '.2s .1s · offen → 0s'] };
  const tempo = () => TEMPO[html.dataset.tempo] || TEMPO.kurz;
  const werte = document.querySelector('[data-werte]');
  document.querySelectorAll('.pult button').forEach(b => b.addEventListener('click', () => {
    html.dataset.tempo = b.dataset.tempo;
    document.querySelectorAll('.pult button').forEach(x => x.setAttribute('aria-pressed', x === b));
    werte.textContent = tempo()[2] + ' · 400 ms ease · −8 px · scale .95';
  }));

  /* Ohne Anchor Positioning: Karte per JS unter den Auslöser setzen */
  function lege(a, k) {
    if (anker) return;
    const r = a.getBoundingClientRect(), w = k.offsetWidth, h = k.offsetHeight;
    let x = Math.min(r.left, innerWidth - w - 12), y = r.bottom + 10;
    if (y + h > innerHeight - 12) y = r.top - h - 10;
    k.style.left = Math.max(12, x) + 'px'; k.style.top = Math.max(12, y) + 'px'; k.style.margin = '0';
  }
  function oeffne(a) {
    const k = karte(a);
    if (k.matches(':popover-open')) return;
    try { k.showPopover({ source: a }); } catch (e) { k.showPopover(); }
    lege(a, k);
    if (zeiger.matches(':popover-open')) { zeiger.hidePopover(); zeiger.showPopover(); }   // Zeiger bleibt obenauf
  }
  function schliesse(a) { const k = karte(a); if (k.matches(':popover-open')) k.hidePopover(); a.classList.remove('zeigt'); }
  const offene = () => ausloeser.some(a => karte(a).matches(':popover-open'));

  /* Rückfall ohne Interest Invokers: dieselbe Zeitlogik per Pointer- und Fokus-Ereignissen */
  if (!nativ) {
    ausloeser.forEach(a => {
      const k = karte(a); let rein = null, raus = null;
      const an = () => { clearTimeout(raus); const [ein] = tempo(); const d = html.dataset.tempo === 'skip' && offene() ? 0 : ein; rein = setTimeout(() => { a.classList.add('zeigt'); oeffne(a); }, d); };
      const ab = () => { clearTimeout(rein); raus = setTimeout(() => schliesse(a), tempo()[1]); };
      a.addEventListener('pointerenter', e => { if (e.pointerType === 'mouse') an(); });
      a.addEventListener('pointerleave', e => { if (e.pointerType === 'mouse') ab(); });
      a.addEventListener('focus', an); a.addEventListener('blur', ab);
      k.addEventListener('pointerenter', () => clearTimeout(raus));
      k.addEventListener('pointerleave', ab);
    });
  }
  /* Touch: Tippen öffnet die Karte statt zu navigieren (Long-Press kollidiert mit dem Systemmenü) */
  ausloeser.forEach(a => a.addEventListener('click', e => {
    if (!touch.matches) return;
    e.preventDefault();
    ausloeser.forEach(b => b !== a && schliesse(b));
    oeffne(a);
  }));

  /* Vorführung: ein gedachter Zeiger fährt Begriffe und Namen ab; dieselbe Zeitlogik wie nativ */
  let uhr = null, p = { x: 0, y: 0 }, aktiv = null, kand = null, seit = 0, weg = 0;
  const mitte = (el, fx = .5, fy = .55) => { const r = el.getBoundingClientRect(); return { x: r.left + r.width * fx, y: r.top + r.height * fy }; };
  function stationen() {
    const A = id => document.querySelector(`[interestfor="${id}"]`);
    const S = [];
    const add = (pt, ms) => S.push({ ...pt, ms });
    const spalte = document.querySelector('.anliegen').getBoundingClientRect();
    const luecke = el => ({ x: spalte.left - 24, y: mitte(el).y });   // freie Fläche zwischen den Spalten
    add({ x: spalte.left - 24, y: innerHeight * .96 }, 700);
    add(mitte(A('hc-sprechstunde'), .55), 2100);
    add(luecke(A('hc-sprechstunde')), 800);
    add(mitte(A('hc-probatorik'), .45), 1900);
    add(luecke(A('hc-probatorik')), 700);
    const s = A('hc-sauerwein');
    add(mitte(s, .5), 1100);
    S.push({ karte: karte(s), fx: .3, fy: .87, ms: 1600 });   // hinein in die Karte, auf den Knopf
    add(luecke(A('hc-haddou')), 800);
    add(mitte(A('hc-haddou'), .5), 2000);
    add({ x: spalte.left - 24, y: innerHeight * .96 }, 900);
    return S;
  }
  let S = [], i = 0, ab = 0, von = { x: 0, y: 0 };
  function ziel(s) {
    if (s.karte) { const r = s.karte.matches(':popover-open') ? s.karte.getBoundingClientRect() : null; return r ? { x: r.left + r.width * s.fx, y: r.top + r.height * s.fy } : von; }
    return s;
  }
  function schritt(t) {
    if (t - ab > S[i].ms) { von = { ...p }; i = (i + 1) % S.length; ab = t; if (i === 0) S = stationen(); }
    const z = ziel(S[i]), q = Math.min(1, (t - ab) / 650), e = q < .5 ? 2 * q * q : 1 - Math.pow(-2 * q + 2, 2) / 2;
    p.x = von.x + (z.x - von.x) * e; p.y = von.y + (z.y - von.y) * e;
    zeiger.style.transform = `translate(${p.x - 2}px, ${p.y - 1}px)`;
    /* Über welchem Auslöser bzw. welcher Karte steht der Zeiger? */
    const unter = document.elementFromPoint(p.x, p.y);
    const a = unter && unter.closest('[interestfor]');
    const inKarte = unter && aktiv && karte(aktiv).contains(unter);
    const [ein, aus] = tempo();
    if (a && a !== aktiv) {
      if (a !== kand) { kand = a; seit = t; }
      const d = html.dataset.tempo === 'skip' && offene() ? 0 : ein;
      if (t - seit >= d) { if (aktiv) schliesse(aktiv); aktiv = a; a.classList.add('zeigt'); oeffne(a); kand = null; weg = 0; }
    } else kand = null;
    if (aktiv && !inKarte && a !== aktiv) { if (!weg) weg = t; if (t - weg >= aus) { schliesse(aktiv); aktiv = null; weg = 0; } }
    else weg = 0;
    uhr = requestAnimationFrame(schritt);
  }
  function vorfuehren() {
    pause();
    html.classList.add('vorfuehrung');
    if (!zeiger.matches(':popover-open')) zeiger.showPopover();
    S = stationen(); i = 0; ab = performance.now(); p = { ...S[0] }; von = { ...p };
    uhr = requestAnimationFrame(schritt);
  }
  function pause() { cancelAnimationFrame(uhr); uhr = null; }
  function neustart() {
    pause(); html.classList.remove('vorfuehrung');
    if (zeiger.matches(':popover-open')) zeiger.hidePopover();
    ausloeser.forEach(schliesse); aktiv = kand = null; seit = weg = 0;
  }

})();
</script>