Zum Inhalt
← Sektionen & Funktionen

Plattform-Bewertungen mit Echtheitshinweis

Google- oder Plattform-Bewertungen auf der eigenen Seite: Kopfzeile mit Schnitt, Anzahl und Stand, drei Stimmen mit Antwort, Echtheitshinweis direkt daneben und Live-Ansicht nur per 2-Klick.

Gastro, Friseur, Fitness: Bewertungen als eigene Sektion direkt nach dem ersten Bildschirm, neben Reservieren oder Termin.

Bewertungen aus dem Google-Profil oder von einer Plattform auf der eigenen Seite, ohne Live-Widget vor dem Klick. Oben steht eine Kopfzeile wie „4,7 von 5 · 312 Bewertungen bei Google · Stand 01.11.2026“. Darunter stehen 3 bis 6 ausgewählte Stimmen mit Quelle, Datum und Antwort des Betriebs. Direkt daneben steht der Echtheitshinweis: ob und wie geprüft wird, auch wenn nicht geprüft wird. Dazu kommen die Links „Alle Bewertungen ansehen“ und „Bewertung schreiben“ zum Profil. Ein Live-Widget lädt erst nach einem Klick.

Gäste und Kunden suchen den Stern-Schnitt ohnehin bei Google. Auf der eigenen Seite steht er dort, wo die Entscheidung fällt: neben Reservieren, Termin oder Anfrage. Stand-Datum, echte Namen und eine kritische Stimme mit Antwort machen die Auswahl glaubwürdig. Der offene Hinweis „wir prüfen nicht“ wirkt ehrlicher als „verifiziert“. Ohne Live-Widget lädt die Seite schneller und schickt keine Daten an Dritte.

Wann einsetzen

Wenn die Bewertungen bei Google oder einer Plattform liegen und der Betrieb kein eigenes Bewertungssystem hat: Gastro, Friseur, Handwerk, Praxis (mit Heilmittelwerberecht prüfen), Fahrschule, Fitness, Makler. Beim Hotel statt bewertungen-verteilung, wenn die Stimmen von Plattformen kommen.

Wann nicht

Wenn der Betrieb eigene Bewertungen sammelt und prüft (nach Aufenthalt, Kauf oder Termin): dann bewertungen-verteilung mit Filter und Verteilung. Nicht mit wenigen, alten oder nur ausgesuchten Fünf-Sterne-Stimmen; dann lieber nur den Link zum Profil. Kein Live-Widget, das ohne Klick lädt. Keine Schnitte mehrerer Plattformen zu einer Zahl verrechnen. Nie „echte“ oder „verifizierte“ Bewertungen schreiben, wenn niemand prüft.

Varianten

  • Band unter dem Hero: Kopfzeile, drei Stimmen und Hinweis in einer Zeile (Gastro, Friseur)
  • Kopfzeilen-Pille: Schnitt und Hinweis im Seitenkopf, Stimmen klappen per Klick auf (Handwerk, Praxis)
  • Mehrere Plattformen: getrennte Kopfzeilen je Plattform, Stimmen nach Quelle filterbar (Hotel, Gastro mit Tourismus)
  • Live-Widget nur per 2-Klick, mit „für diesen Besuch merken“

Umsetzung

Bewertungen als gepflegte Daten (Schnitt, Anzahl, Stand-Datum, Profil-Link, 3 bis 6 Stimmen mit Name, Datum, Sternen, Text, Antwort), nicht live beim Seitenaufruf. Kopfzeile mit Sternen als Text (nur-sr „4,7 von 5 Sternen“, Einzelsterne role="img"), Zahlen per Intl, Datum als <time>. Der Echtheitshinweis steht als sichtbarer Absatz direkt an Kopfzeile und Stimmen und nennt die Auswahlregel. Links „Alle … ansehen“ und „Bewertung schreiben“ sagen, dass sie die Plattform in neuem Tab öffnen. Antworten als <details>. Variante Pille: <button popovertarget> mit Hinweiszeile darunter (aria-describedby), Popover mit allen Angaben. Live-Ansicht nur nach Klick auf den Platzhalter (Text zur Datenübertragung), Fehler lassen die Auswahl stehen und bieten „Erneut versuchen“ und den Profil-Link. Hinweistexte vom Kunden rechtlich prüfen lassen.

Robust umsetzen

Telefon. Kopfzeile und Hinweis zuerst, darunter die Stimmen untereinander (höchstens drei sichtbar, Rest über „Weitere Stimmen“). Die Pille im Kopf zeigt nur Schnitt und Anzahl, der Hinweis steht darunter in einer eigenen Zeile. Links als volle Knöpfe mit mindestens 44 px Höhe.

Ohne Bewegung. Stimmen und Widget erscheinen ohne Versatz, das Popover öffnet ohne Übergang.

Barrierefrei. Sterne nie nur als Grafik: Text „4,7 von 5 Sternen“ (WCAG 1.1.1). Jede Stimme als <article> mit Name, <time> und Quelle. Externe Links sagen „öffnet Google in neuem Tab“ (3.2.5). Der Platzhalter des Widgets ist ein echter Knopf mit Beschreibung, nach dem Laden geht der Fokus in den neuen Bereich, der Ladezustand steht in role="status" (4.1.3). Popover der Pille mit aria-expanded am Auslöser, schließt mit Esc. Text mindestens 4,5:1, auch der Echtheitshinweis (1.4.3).

Code

<!DOCTYPE html>
<!--
  Plattform-Bewertungen mit Echtheitshinweis
  Fundus · Sektionen & Funktionen · https://cecodesign.de/lab/fundus/sektionen/bewertungsprofil-mit-echtheitshinweis/
  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>Plattform-Bewertungen mit Echtheitshinweis · 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: 'Fraunces'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/fraunces:vf@latest/latin-full-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Commissioner'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/commissioner:vf@latest/latin-full-normal.woff2') format('woff2-variations'); font-weight: 100 900; 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 {
  /* Rezept gastro-warm-appetitlich: Papier-Weiß, warme Tinte, Salbei, Dunkelgrün, Senf */
  --grund: #F0ECE0; --papier: #F7F4EC; --text: #353839; --leise: #5B5D58; --linie: #D6D0BF;
  --salbei: #7F937A; --tief: #293E3A; --tief-2: #334A45; --senf: #EAC16E; --gold: #8A5F0E; --rose: #E1A894;
  --creme: #F3EFE4; --creme-leise: rgba(243, 239, 228, .8);
  --kurve: cubic-bezier(0.16, 1, 0.3, 1);
  --t-ui: 200ms; --t-pop: 400ms; --t-ein: 700ms; --staffel: 80ms;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
html { background: var(--grund); color: var(--text); font-family: 'Commissioner', system-ui, sans-serif; font-variation-settings: 'FLAR' 0; -webkit-font-smoothing: antialiased; }
body { min-height: 100svh; }
button, input { font: inherit; color: inherit; }
a { color: inherit; }
.label { font-size: .75rem; font-weight: 600; letter-spacing: .15em; text-transform: uppercase; font-variation-settings: 'FLAR' 80; }
.mono { font: 500 10.5px/1.45 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; }
.serif { font-family: 'Fraunces', Georgia, serif; font-optical-sizing: auto; font-variation-settings: 'SOFT' 100, 'WONK' 0; }
.ziffern { font-variant-numeric: tabular-nums lining-nums; }
.nur-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
:focus-visible { outline: 2px solid var(--tief); outline-offset: 3px; }
.dunkel :focus-visible { outline-color: var(--senf); }

/* Sterne */
.sterne { display: inline-flex; gap: 2px; vertical-align: middle; }
.sterne svg { width: 14px; height: 14px; display: block; }
.sterne .an { fill: var(--senf); } .sterne .halb { fill: url(#halb); } .sterne .aus { fill: none; stroke: currentColor; stroke-width: 1.2; opacity: .55; }
.hell .sterne .an { fill: var(--gold); } .hell .sterne .halb { fill: url(#halb-hell); }

/* ── Kopf ─────────────────────────────── */
.kopf { display: flex; align-items: center; gap: 18px 28px; flex-wrap: wrap; padding: 16px clamp(16px, 4vw, 56px); border-bottom: 1px solid var(--linie); }
.marke { display: grid; text-decoration: none; }
.marke b { font: 520 27px/1 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; letter-spacing: -.01em; }
.marke span { color: var(--leise); margin-top: 5px; font-size: .68rem; }
.kopf nav { display: flex; gap: 22px; font-size: 15.5px; }
.kopf nav a { text-decoration: none; padding: 6px 0; }
.kopf nav a:hover { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }
.rechts { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.offen { font-size: 14px; display: inline-flex; gap: 8px; align-items: center; }
.offen::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: #3F7A4C; box-shadow: 0 0 0 3px rgba(63, 122, 76, .18); }
.knopf { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 46px; padding: 0 20px; border-radius: 999px; background: var(--tief); color: var(--creme); border: 1px solid var(--tief); text-decoration: none; font-size: 15px; font-weight: 600; cursor: pointer; transition: background-color var(--t-ui) var(--kurve), color var(--t-ui) var(--kurve); }
.knopf:hover { background: #1D2E2B; }
.knopf.zweit { background: transparent; color: var(--text); border-color: var(--text); }
.knopf.zweit:hover { background: rgba(53, 56, 57, .07); }

/* Variante Pille: Schnitt + Hinweis im Kopf */
.pille-block { display: grid; gap: 4px; justify-items: start; }
.pille { display: inline-flex; align-items: center; gap: 8px; min-height: 38px; padding: 0 14px 0 12px; border-radius: 999px; background: var(--papier); border: 1px solid var(--linie); cursor: pointer; font-size: 14px; transition: border-color var(--t-ui) var(--kurve), background-color var(--t-ui) var(--kurve); }
.pille:hover { border-color: var(--text); }
.pille b { font-weight: 650; }
.pille svg.pfeil { width: 10px; height: 10px; transition: rotate var(--t-ui) var(--kurve); }
.pille[aria-expanded="true"] { border-color: var(--text); background: #fff; }
.pille[aria-expanded="true"] svg.pfeil { rotate: 180deg; }
.pille-hinweis { font-size: 12px; color: var(--leise); padding-left: 14px; }

.pop { position: fixed; inset: 84px clamp(16px, 4vw, 56px) auto auto; margin: 0; width: min(460px, calc(100vw - 32px)); max-height: calc(100vh - 100px); overflow: auto; background: var(--papier); color: var(--text); border: 1px solid var(--linie); border-radius: 14px; padding: 22px 22px 18px; box-shadow: 0 30px 60px -28px rgba(41, 62, 58, .45);
  opacity: 0; translate: 0 -8px; transition: opacity var(--t-pop) var(--kurve), translate var(--t-pop) var(--kurve), display var(--t-pop) allow-discrete, overlay var(--t-pop) allow-discrete; }
.pop:popover-open { opacity: 1; translate: 0 0; }
@starting-style { .pop:popover-open { opacity: 0; translate: 0 -8px; } }
.reduziert .pop { transition: none; }
.pop .zu { position: absolute; top: 12px; right: 12px; width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--linie); background: transparent; cursor: pointer; font-size: 18px; line-height: 1; }
.pop .stimmen, .vorschau .pop .stimmen { grid-template-columns: minmax(0, 1fr); }
.pop .stimme { padding: 16px 0; border-left: 0; border-top: 1px solid var(--linie); }
.pop .stimme:first-child { padding-left: 0; }

/* ── Hero ─────────────────────────────── */
.hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: clamp(24px, 4vw, 64px); align-items: center; padding: clamp(28px, 5vw, 64px) clamp(16px, 4vw, 56px); max-width: 1360px; margin: 0 auto; }
.hero .label { color: #4F5F4B; }
.hero h1 { font: 480 clamp(2.5rem, 1.6rem + 4vw, 5rem)/1.02 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100, 'WONK' 0; letter-spacing: -.01em; margin: 14px 0 18px; text-wrap: balance; }
.hero p.text { font-size: 1.0625rem; line-height: 1.55; max-width: 42ch; }
.hero .knoepfe { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 24px; }
.hero .zeiten { margin-top: 22px; font-size: 14px; color: var(--leise); line-height: 1.6; }
.hero figure { position: relative; border-radius: 4px; overflow: hidden; aspect-ratio: 3 / 2; background: #3B3B38; }
.hero img { width: 100%; height: 100%; object-fit: cover; display: block; animation: bild var(--t-ein) var(--kurve) both; }
@keyframes bild { from { opacity: 0; scale: .96; } }
.reduziert .hero img { animation: none; }
.hero figcaption { position: absolute; left: 14px; bottom: 12px; font-size: 12.5px; color: #F3EFE4; background: rgba(30, 34, 33, .62); padding: 5px 10px; border-radius: 999px; }

/* ── Bewertungsband ─────────────────────── */
.band { background: var(--tief); color: var(--creme); }
.band-innen { max-width: 1360px; margin: 0 auto; padding: clamp(32px, 4.5vw, 56px) clamp(16px, 4vw, 56px); display: grid; grid-template-columns: minmax(260px, 330px) minmax(0, 1fr); gap: clamp(28px, 4vw, 64px); }
.profil { display: grid; gap: 16px; align-content: start; }
.profil .label { color: var(--senf); }
.schnitt { display: flex; align-items: flex-end; gap: 14px; }
.schnitt .zahl { font: 400 clamp(64px, 5vw + 30px, 96px)/.82 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; letter-spacing: -.03em; }
.schnitt .von { display: grid; gap: 8px; padding-bottom: 4px; font-size: 14px; color: var(--creme-leise); }
.schnitt .sterne svg { width: 17px; height: 17px; }
.profil .meta { font-size: 14.5px; color: var(--creme-leise); line-height: 1.5; }
.profil .meta strong { color: var(--creme); font-weight: 600; }
.echtheit { border-top: 1px solid rgba(243, 239, 228, .22); padding-top: 14px; display: grid; gap: 8px; font-size: 14px; line-height: 1.55; }
.echtheit h3 { font-size: .72rem; display: flex; gap: 8px; align-items: center; color: var(--creme); }
.echtheit h3 svg { width: 15px; height: 15px; flex: none; }
.echtheit p { color: var(--creme-leise); text-wrap: pretty; }
.echtheit .mono { font-size: 9.5px; color: rgba(243, 239, 228, .7); }
.hell .schnitt .von, .hell .profil .meta { color: var(--leise); }
.hell .profil .meta strong { color: var(--text); }
.hell .profil .label { color: var(--gold); }
.hell .echtheit { border-top-color: var(--linie); }
.hell .echtheit h3 { color: var(--text); }
.hell .echtheit p { color: var(--leise); }
.hell .echtheit .mono { color: var(--leise); }
.links { display: grid; gap: 4px; }
.links a { display: inline-flex; gap: 8px; align-items: center; min-height: 36px; font-size: 15px; font-weight: 600; color: var(--senf); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 5px; width: fit-content; }
.links a svg { width: 12px; height: 12px; flex: none; }
.links a:hover { text-decoration-thickness: 2px; }
.hell .links a { color: var(--tief); }

.stimmen { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); list-style: none; align-content: start; }
.stimme { padding: 4px clamp(16px, 2vw, 28px) 4px; border-left: 1px solid rgba(243, 239, 228, .22); display: grid; gap: 12px; align-content: start; }
.stimme:first-child { padding-left: 0; border-left: 0; }
.stimme .zeile { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; font-size: 13px; color: var(--creme-leise); }
.stimme blockquote { font: 400 19px/1.45 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; font-optical-sizing: auto; text-wrap: pretty; }
.stimme .wer { font-size: 14px; display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.stimme .wer b { font-weight: 600; }
.stimme .quelle { font-size: .66rem; color: var(--senf); }
.hell .stimme { border-left-color: var(--linie); }
.hell .stimme .zeile { color: var(--leise); }
.hell .stimme .quelle { color: var(--gold); }
.antwort { border-left: 2px solid var(--senf); padding-left: 14px; }
.antwort summary { cursor: pointer; list-style: none; font-size: 13.5px; font-weight: 600; display: inline-flex; gap: 8px; align-items: center; min-height: 32px; }
.antwort summary::-webkit-details-marker { display: none; }
.antwort summary::after { content: ''; width: 7px; height: 7px; border: solid currentColor; border-width: 0 1.5px 1.5px 0; rotate: 45deg; translate: 0 -2px; transition: rotate var(--t-ui) var(--kurve); }
.antwort[open] summary::after { rotate: 225deg; translate: 0 2px; }
.antwort p { font-size: 14.5px; line-height: 1.55; color: var(--creme-leise); margin-top: 4px; }
.antwort small { display: block; font-size: 12.5px; color: rgba(243, 239, 228, .72); margin-top: 6px; }
.hell .antwort { border-left-color: var(--gold); }
.hell .antwort p, .hell .antwort small { color: var(--leise); }
.stimme.neu { animation: rein var(--t-ein) var(--kurve) both; animation-delay: calc(var(--i, 0) * var(--staffel)); }
@keyframes rein { from { opacity: 0; translate: 0 8px; } }
.reduziert .stimme.neu { animation: none; }

/* Filter nach Plattform (Variante mehrere) */
.profile { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.profile .profil { gap: 10px; }
.profile .schnitt .zahl { font-size: 60px; }
.filter { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 22px; }
.filter button { min-height: 40px; padding: 0 16px; border-radius: 999px; border: 1px solid rgba(243, 239, 228, .4); background: transparent; color: var(--creme); cursor: pointer; font-size: 14.5px; transition: background-color var(--t-ui) var(--kurve), color var(--t-ui) var(--kurve); }
.filter button:hover { border-color: var(--creme); }
.filter button[aria-pressed="true"] { background: var(--creme); color: var(--tief); border-color: var(--creme); }
.filter button small { font-size: 12.5px; opacity: .8; }
[data-variante="mehrere"] .band-innen { grid-template-columns: minmax(0, 1fr); gap: 30px; }
[data-variante="mehrere"] .stimmen { row-gap: 30px; }
[data-variante="mehrere"] .stimme:nth-child(3n + 1) { padding-left: 0; border-left: 0; }
.getrennt { font-size: 13.5px; color: var(--creme-leise); max-width: 70ch; }

/* ── 2-Klick: Live-Ansicht ─────────────── */
.live { max-width: 1360px; margin: 0 auto; padding: clamp(28px, 4vw, 48px) clamp(16px, 4vw, 56px) clamp(48px, 6vw, 88px); }
.live-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 12px 24px; flex-wrap: wrap; margin-bottom: 14px; }
.live-kopf h2 { font: 480 clamp(1.5rem, 1.1rem + 1.2vw, 2rem)/1.15 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; }
.live-kopf p { font-size: 13.5px; color: var(--leise); }
.buehne { position: relative; height: 300px; border: 1px solid var(--linie); border-radius: 10px; overflow: hidden; background: var(--papier); overflow-anchor: none; }
.platzhalter { position: absolute; inset: 0; display: grid; place-items: center; padding: 20px;
  background: repeating-linear-gradient(180deg, transparent 0 70px, rgba(53, 56, 57, .06) 70px 71px), linear-gradient(90deg, rgba(53, 56, 57, .05) 0 22%, transparent 22%); }
.platzhalter::before { content: ''; position: absolute; inset: 22px 22px auto 24%; height: 230px; background: repeating-linear-gradient(180deg, rgba(53, 56, 57, .09) 0 10px, transparent 10px 24px, rgba(53, 56, 57, .06) 24px 34px, transparent 34px 71px); mask: linear-gradient(90deg, #000 40%, transparent); filter: blur(1.5px); }
.einwilligung { position: relative; background: #fff; border: 1px solid var(--linie); border-radius: 12px; padding: 20px 22px; max-width: 520px; display: grid; gap: 10px; box-shadow: 0 20px 40px -26px rgba(41, 62, 58, .5); }
.einwilligung h3 { font: 500 19px/1.25 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; }
.einwilligung p { font-size: 14px; line-height: 1.5; color: var(--leise); }
.einwilligung .zeile { display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; margin-top: 4px; }
.merken { display: inline-flex; gap: 9px; align-items: center; font-size: 14px; color: var(--leise); cursor: pointer; min-height: 32px; }
.merken input { width: 18px; height: 18px; accent-color: var(--tief); margin: 0; }
.kreisel { width: 15px; height: 15px; border-radius: 50%; border: 2px solid rgba(243, 239, 228, .35); border-top-color: var(--creme); animation: dreh .8s linear infinite; display: none; }
[aria-busy="true"] .kreisel { display: inline-block; }
@keyframes dreh { to { rotate: 1turn; } }
.reduziert .kreisel { animation-duration: 2.4s; }
.widget { position: absolute; inset: 0; display: grid; grid-template-rows: auto minmax(0, 1fr); animation: rein var(--t-ein) var(--kurve) both; }
.reduziert .widget { animation: none; }
.widget-kopf { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid #E3E3E3; background: #fff; font: 14px/1.3 system-ui, sans-serif; color: #202124; }
.widget-kopf .punkt { width: 8px; height: 8px; border-radius: 50%; background: #2E8B57; }
.widget-kopf b { font-weight: 600; }
.widget-kopf button { margin-left: auto; }
.widget ol { list-style: none; background: #fff; overflow: hidden; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.widget li { padding: 14px 16px; border-right: 1px solid #EEE; font: 14px/1.45 system-ui, sans-serif; color: #202124; display: grid; gap: 6px; align-content: start; }
.widget li:last-child { border-right: 0; }
.widget li .meta { color: #5F6368; font-size: 12.5px; }
.widget li .sterne .an { fill: #B26B00; }
.leise-knopf { background: none; border: 1px solid var(--linie); border-radius: 999px; min-height: 34px; padding: 0 14px; cursor: pointer; font-size: 13.5px; color: var(--text); }
.leise-knopf:hover { border-color: var(--text); }
.fehler { position: absolute; inset: 0; display: grid; place-items: center; padding: 20px; text-align: center; }
.fehler div { display: grid; gap: 10px; justify-items: center; max-width: 46ch; }
.fehler h3 { font: 500 19px/1.25 'Fraunces', Georgia, serif; }
.fehler p { font-size: 14px; color: var(--leise); line-height: 1.5; }
.status { min-height: 1.4em; font-size: 13.5px; color: var(--leise); margin-top: 10px; }

/* Mittagstisch (Kontext der Variante Pille) */
.mittag { max-width: 1360px; margin: 0 auto; padding: 0 clamp(16px, 4vw, 56px) clamp(48px, 6vw, 88px); display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: clamp(24px, 4vw, 64px); }
.mittag h2 { font: 480 clamp(1.6rem, 1.1rem + 1.4vw, 2.2rem)/1.1 'Fraunces', Georgia, serif; font-variation-settings: 'SOFT' 100; }
.mittag ul { list-style: none; border-top: 1px solid var(--text); }
.mittag li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 20px; padding: 14px 0; border-bottom: 1px solid var(--linie); }
.mittag li b { font-weight: 500; font-size: 1.125rem; }
.mittag li span { font-size: .9375rem; color: var(--leise); }
.mittag li em { font-style: normal; font-variant-numeric: tabular-nums; grid-row: 1; grid-column: 2; font-size: 1.0625rem; }

.toast { position: fixed; left: 50%; bottom: 24px; translate: -50% 0; z-index: 40; background: var(--text); color: var(--creme); padding: 12px 18px; border-radius: 10px; font-size: 14px; max-width: min(460px, calc(100vw - 32px)); box-shadow: 0 16px 34px -18px rgba(0, 0, 0, .5); }

/* Gedachter Klick der Vorführung */
.tipp { position: relative; }
.tipp::before { content: ''; position: absolute; inset: -5px; border-radius: 999px; border: 2px solid var(--senf); animation: tipp 600ms var(--kurve) forwards; pointer-events: none; }
@keyframes tipp { from { opacity: 1; scale: .94; } to { opacity: 0; scale: 1.06; } }
.reduziert .tipp::before { animation: none; opacity: 0; }

/* Pult */
.pult { position: fixed; right: 16px; bottom: 16px; z-index: 30; display: grid; gap: 8px; background: rgba(41, 62, 58, .96); color: var(--creme); padding: 12px 14px; border-radius: 8px; box-shadow: 0 12px 30px rgba(0, 0, 0, .25); max-width: calc(100vw - 32px); }
.pult .reihe { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.pult .mono { color: rgba(243, 239, 228, .72); min-width: 6.2em; }
.pult .gruppe { display: flex; flex-wrap: wrap; border: 1px solid rgba(243, 239, 228, .3); border-radius: 3px; }
.pult button { background: none; border: 0; padding: 8px 10px; min-height: 30px; font: 500 10.5px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .1em; text-transform: uppercase; color: rgba(243, 239, 228, .82); cursor: pointer; }
.pult .gruppe button + button { border-left: 1px solid rgba(243, 239, 228, .3); }
.pult button[aria-pressed="true"] { background: var(--creme); color: var(--tief); }
.pult button:focus-visible { outline: 2px solid var(--senf); outline-offset: 2px; }

@media (forced-colors: active) {
  button, [role=button], [role=tab], .knopf, .pille { border: 1px solid ButtonText; }
  .sterne svg { forced-color-adjust: auto; }
}
@media (hover: none) {
  .knopf:hover { background: var(--tief); }
  .knopf.zweit:hover { background: transparent; }
  .pille:hover { border-color: var(--linie); }
  .antwort summary { min-height: 44px; }
  .links a { min-height: 44px; }
}

@media (max-width: 1080px) {
  .kopf nav { display: none; }
  .band-innen { grid-template-columns: minmax(0, 1fr); }
  .stimmen, [data-variante="mehrere"] .stimmen { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .stimme:nth-child(odd), [data-variante="mehrere"] .stimme:nth-child(odd) { padding-left: 0; border-left: 0; }
  .stimme:nth-child(even), [data-variante="mehrere"] .stimme:nth-child(3n + 1):nth-child(even) { padding-left: clamp(16px, 2vw, 28px); border-left: 1px solid rgba(243, 239, 228, .22); }
  .stimmen { row-gap: 26px; }
  .profil { grid-template-columns: minmax(0, auto) minmax(0, 1fr); column-gap: 32px; }
  .profil > .label, .profil > .echtheit, .profil > .links { grid-column: 1 / -1; }
  .profile .profil { grid-template-columns: minmax(0, 1fr); }
  .widget ol { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .widget li:nth-child(3) { display: none; }
}
@media (max-width: 760px) {
  .hero, .mittag { grid-template-columns: minmax(0, 1fr); }
  .hero figure { grid-row: 1; aspect-ratio: 4 / 3; }
  .rechts .offen { display: none; }
  .pille-block { order: 5; width: 100%; }
  .stimmen, [data-variante="mehrere"] .stimmen { grid-template-columns: minmax(0, 1fr); }
  .stimme, .stimme:nth-child(even), [data-variante="mehrere"] .stimme:nth-child(3n + 1):nth-child(even) { padding: 18px 0 0; border-left: 0; border-top: 1px solid rgba(243, 239, 228, .22); }
  .stimme:first-child { border-top: 0; padding-top: 0; }
  .profil { grid-template-columns: minmax(0, 1fr); }
  .profile { grid-template-columns: minmax(0, 1fr); }
  .buehne { height: auto; min-height: 340px; }
  .platzhalter, .fehler { position: relative; min-height: 340px; }
  .widget { position: relative; }
  .widget ol { grid-template-columns: minmax(0, 1fr); }
  .widget li { border-right: 0; border-bottom: 1px solid #EEE; }
  .widget li:nth-child(3) { display: grid; }
  .pop { inset: auto 0 0 0; width: 100%; max-height: 85vh; border-radius: 16px 16px 0 0; translate: 0 0; }
  .pop:popover-open { translate: 0 0; }
  @starting-style { .pop:popover-open { translate: 0 24px; } }
  .pult { left: 12px; right: 12px; bottom: 12px; }
}
@media (max-width: 400px) {
  .kopf { gap: 12px 14px; }
  .rechts .knopf { padding: 0 14px; }
  .schnitt .zahl { font-size: 60px; }
}

/* Vorschau 960 × 720: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .kopf nav, .vorschau .offen { display: none; }
.vorschau .hero { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); padding-block: 24px; }
.vorschau .hero h1 { font-size: 44px; margin: 8px 0 10px; }
.vorschau .hero .zeiten { display: none; }
.vorschau [data-variante="band"] .hero { display: block; padding: 0; }
.vorschau [data-variante="band"] .hero > div { display: none; }
.vorschau [data-variante="band"] .hero figure { aspect-ratio: auto; height: 120px; border-radius: 0; }
.vorschau [data-variante="band"] .hero figcaption { display: none; }
.vorschau .band-innen { padding: 30px 32px; grid-template-columns: 270px minmax(0, 1fr); gap: 32px; }
.vorschau .band .stimmen { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.vorschau .band .stimme { padding: 4px 14px 4px 18px; border-left: 1px solid rgba(243, 239, 228, .22); border-top: 0; }
.vorschau .band .stimme:first-child { padding-left: 0; border-left: 0; }
.vorschau .stimme blockquote { font-size: 16.5px; }
.vorschau .schnitt .zahl { font-size: 76px; }
.vorschau .profil { grid-template-columns: minmax(0, 1fr); }
.vorschau .profile .profil { gap: 8px; }
.vorschau .stimme .zeile { gap: 4px 10px; }
.vorschau [data-variante="mehrere"] .hero { display: none; }
.vorschau [data-variante="mehrere"] .band-innen { grid-template-columns: minmax(0, 1fr); gap: 20px; }
.vorschau [data-variante="mehrere"] .stimme { padding-left: 18px; border-left: 1px solid rgba(243, 239, 228, .22); }
.vorschau [data-variante="mehrere"] .stimme:nth-child(3n + 1) { padding-left: 0; border-left: 0; }
.vorschau [data-variante="mehrere"] .live { display: none; }
.vorschau .live { padding-top: 22px; }
.vorschau .pop { inset: 84px 24px auto auto; }
</style>
</head>
<body>
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
  <defs>
    <linearGradient id="halb"><stop offset="50%" stop-color="#EAC16E"/><stop offset="50%" stop-color="#EAC16E" stop-opacity=".22"/></linearGradient>
    <linearGradient id="halb-hell"><stop offset="50%" stop-color="#8A5F0E"/><stop offset="50%" stop-color="#8A5F0E" stop-opacity=".2"/></linearGradient>
  </defs>
  <symbol id="stern" viewBox="0 0 20 20"><path d="M10 1.6l2.47 5.35 5.86.62-4.38 3.96 1.23 5.77L10 14.37 4.82 17.3l1.23-5.77L1.67 7.57l5.86-.62z"/></symbol>
  <symbol id="raus" viewBox="0 0 12 12"><path d="M4.5 2.5h5v5M9.5 2.5 3 9" fill="none" stroke="currentColor" stroke-width="1.5"/></symbol>
</svg>

<header class="kopf" data-kopf>
  <a class="marke" href="#start"><b>Kinzigstube</b><span class="label">Weinstube · Offenburg</span></a>
  <nav aria-label="Hauptnavigation"><a href="#start">Karte</a><a href="#start">Mittagstisch</a><a href="#start">Weine</a><a href="#start">Anfahrt</a></nav>
  <div class="pille-block" data-pille-block hidden>
    <button class="pille" type="button" popovertarget="stimmen-pop" data-pille aria-describedby="pille-hinweis">
      <span class="sterne hell" aria-hidden="true" data-sterne-klein></span>
      <span><b class="ziffern" data-schnitt-text>4,7</b> · <span class="ziffern" data-anzahl-text>312</span> Google-Bewertungen</span>
      <svg class="pfeil" 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.4"/></svg>
    </button>
    <span class="pille-hinweis" id="pille-hinweis">Von uns nicht auf Echtheit geprüft · Stand <time datetime="2026-11-01">01.11.2026</time></span>
  </div>
  <div class="rechts"><span class="offen">Heute bis 23 Uhr geöffnet</span><a class="knopf" href="#start">Reservieren</a></div>
</header>

<div class="pop hell" id="stimmen-pop" popover aria-labelledby="pop-titel" data-pop></div>

<main data-seite>
  <section class="hero" aria-labelledby="hero-titel">
    <div>
      <p class="label">Badische Küche · Weine aus der Ortenau</p>
      <h1 id="hero-titel">Ehrlich gekocht, gern gegessen.</h1>
      <p class="text">Mittags drei Gerichte, abends die ganze Karte. Gemüse vom Offenburger Wochenmarkt, Wein von Winzern, die wir mit Namen kennen.</p>
      <div class="knoepfe"><a class="knopf" href="#start">Tisch reservieren</a><a class="knopf zweit" href="#start">Zur Karte</a></div>
      <p class="zeiten ziffern">Di bis Sa 11.30 bis 14 und 17.30 bis 23 Uhr · So 11.30 bis 15 Uhr</p>
    </div>
    <figure><img src="bilder/zitronen-tisch.jpg" width="1200" height="800" alt="Heller Steingutteller mit einer halben Zitrone, daneben ganze Zitronen auf dunklem Schiefer" fetchpriority="high"><figcaption>Zitronen für die Rahmtarte</figcaption></figure>
  </section>

  <section class="band dunkel" aria-labelledby="band-titel" data-band></section>

  <section class="live" aria-labelledby="live-titel" data-live>
    <div class="live-kopf"><h2 id="live-titel">Noch mehr Stimmen, live von Google</h2><p>Lädt erst nach Ihrem Klick.</p></div>
    <div class="buehne" data-buehne></div>
    <p class="status" role="status" data-status></p>
  </section>

  <section class="mittag" aria-labelledby="mittag-titel" data-mittag hidden>
    <div><p class="label" style="color:var(--leise)">Diese Woche</p><h2 id="mittag-titel">Mittagstisch</h2></div>
    <ul>
      <li><b>Flädlesuppe, Schäufele mit Kartoffelsalat</b><em>14,50 €</em><span>Di und Mi</span></li>
      <li><b>Kürbis-Maultaschen mit brauner Butter und Bergkäse</b><em>12,80 €</em><span>Do und Fr, vegetarisch</span></li>
      <li><b>Zander auf Rahmsauerkraut, Salzkartoffeln</b><em>16,90 €</em><span>Samstag</span></li>
    </ul>
  </section>
</main>

<p class="toast" role="status" data-toast hidden></p>

<div class="pult">
  <div class="reihe"><span class="mono">Variante</span>
    <div class="gruppe" role="group" aria-label="Variante">
      <button type="button" data-v="band" aria-pressed="true">Band</button>
      <button type="button" data-v="pille" aria-pressed="false">Pille</button>
      <button type="button" data-v="mehrere" aria-pressed="false">Mehrere</button>
    </div>
  </div>
  <div class="reihe"><span class="mono">Live-Dienst</span>
    <div class="gruppe" role="group" aria-label="Antwort des Live-Dienstes">
      <button type="button" data-dienst="ok" aria-pressed="true">Erreichbar</button>
      <button type="button" data-dienst="aus" aria-pressed="false">Gestört</button>
    </div>
  </div>
</div>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const $ = (s, r = document) => r.querySelector(s);

  // Erfundene Weinstube, erfundene Stimmen. Gepflegt als Daten mit Stand-Datum.
  const PROFILE = {
    google: { name: 'Google', schnitt: 4.7, anzahl: 312, stand: '2026-11-01',
      hinweis: 'Diese Bewertungen stammen aus unserem Google-Unternehmensprofil. Wir prüfen nicht, ob die Verfassenden bei uns zu Gast waren. Gezeigt sind die drei neuesten Bewertungen mit Text, unabhängig von der Sternzahl.' },
    trip: { name: 'Tripadvisor', schnitt: 4.5, anzahl: 86, stand: '2026-11-01',
      hinweis: 'Diese Bewertungen stammen von Tripadvisor. Wir prüfen nicht, ob die Verfassenden bei uns zu Gast waren.' }
  };
  const STIMMEN = [
    { q: 'google', s: 5, d: '2026-10-28', name: 'Sabine R.', text: 'Schäufele mit Kartoffelsalat wie bei meiner Oma, nur besser. Der Grauburgunder passt perfekt dazu. Der Service war herzlich, obwohl jeder Tisch besetzt war.', a: { d: '2026-10-29', text: 'Danke, Frau R.! Den Grauburgunder gibt es übrigens auch zum Mitnehmen.' } },
    { q: 'google', s: 3, d: '2026-10-21', name: 'Jonas M.', text: 'Das Essen war sehr gut. Am Samstag haben wir aber 40 Minuten auf die Hauptspeise gewartet. Ein kurzer Hinweis vom Service wäre nett gewesen.', a: { d: '2026-10-23', text: 'Lieber Herr M., Sie haben recht, das hätten wir sagen müssen. Samstags steht jetzt eine zweite Person am Herd. Danke für die offenen Worte.' } },
    { q: 'google', s: 5, d: '2026-10-14', name: 'Aylin T.', text: 'Mittagstisch mit Suppe, schnell und frisch gekocht. Endlich ein Ort in der Altstadt, an dem man mittags nicht hetzen muss.', a: { d: '2026-10-15', text: 'Das freut uns sehr. Bis bald am Mittagstisch!' } },
    { q: 'trip', s: 4, d: '2026-10-09', name: 'Peter W.', text: 'Auf der Durchreise eingekehrt. Flammkuchen dünn und knusprig, Weinkarte mit vielen Ortenauer Winzern. Parkplätze in der Nähe sind knapp.', a: { d: '2026-10-11', text: 'Danke! Ein Tipp für das nächste Mal: Das Parkhaus am Marktplatz ist fünf Minuten zu Fuß.' } },
    { q: 'google', s: 4, d: '2026-10-05', name: 'Hannes B.', text: 'Rehragout mit Spätzle, kräftig und nicht zu schwer. Der Raum ist gemütlich, an voll besetzten Abenden aber laut.', a: null },
    { q: 'trip', s: 5, d: '2026-09-30', name: 'Marieke D.', text: 'Wir wurden auf Deutsch und Niederländisch begrüßt und bekamen Tipps für den Weinweg am nächsten Tag. Die Rahmtarte war ein Gedicht.', a: { d: '2026-10-02', text: 'Hartelijk dank! Wir hoffen, der Weinweg hat Ihnen gefallen.' } }
  ];
  const LIVE = [
    { s: 5, d: 'vor 2 Tagen', name: 'K. Schäfer', text: 'Bester Zwiebelrostbraten in Offenburg.' },
    { s: 4, d: 'vor 5 Tagen', name: 'Lea', text: 'Lecker, nur die Musik war etwas laut.' },
    { s: 5, d: 'vor 1 Woche', name: 'Familie Huber', text: 'Kinderteller und Malbuch, alle waren zufrieden.' }
  ];
  const INHABERIN = 'Theresa Isele, Inhaberin';

  const zahl1 = new Intl.NumberFormat('de-DE', { minimumFractionDigits: 1, maximumFractionDigits: 1 });
  const zahl = new Intl.NumberFormat('de-DE');
  const lang = new Intl.DateTimeFormat('de-DE', { day: 'numeric', month: 'long', year: 'numeric' });
  const kurz = new Intl.DateTimeFormat('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' });
  const RAUS = '<svg aria-hidden="true"><use href="#raus"/></svg>';

  const z = { v: 'band', filter: 'alle', dienst: 'ok', live: 'zu', merken: false };

  function sterne(n) {
    return Array.from({ length: 5 }, (_, i) => { const k = n >= i + 1 ? 'an' : n > i + .25 ? 'halb' : 'aus'; return `<svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><use href="#stern" class="${k}"/></svg>`; }).join('');
  }
  const sternText = n => `${zahl1.format(n)} von 5 Sternen`;

  function profilBlock(key, { titel = true, hinweis = true, links = true, id = '' } = {}) {
    const p = PROFILE[key];
    return `<div class="profil">
      ${titel ? `<p class="label">Gäste bei ${p.name}</p>` : ''}
      <div class="schnitt"><span class="zahl ziffern" aria-hidden="true">${zahl1.format(p.schnitt)}</span>
        <span class="von"><span class="sterne" aria-hidden="true">${sterne(p.schnitt)}</span><span>von 5</span></span>
        <span class="nur-sr">${sternText(p.schnitt)}</span></div>
      <p class="meta ziffern"><strong>${zahl.format(p.anzahl)} Bewertungen bei ${p.name}</strong><br>Stand <time datetime="${p.stand}">${kurz.format(new Date(p.stand))}</time></p>
      ${hinweis ? `<div class="echtheit"${id ? ` id="${id}"` : ''}><h3 class="label"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.6" fill="none" stroke="currentColor" stroke-width="1.2"/><path d="M8 7v4.2M8 4.6v.1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>Zur Echtheit</h3><p>${p.hinweis}</p><p class="mono">Textbaustein · vom Kunden rechtlich prüfen lassen</p></div>` : ''}
      ${links ? `<div class="links"><a href="#profil" data-extern="${key}">Alle ${zahl.format(p.anzahl)} Bewertungen ansehen ${RAUS}<span class="nur-sr"> (öffnet ${p.name} in neuem Tab)</span></a><a href="#profil" data-extern="${key}">Bewertung schreiben ${RAUS}<span class="nur-sr"> (öffnet ${p.name} in neuem Tab)</span></a></div>` : ''}
    </div>`;
  }

  function stimme(b, i, { offen = false } = {}) {
    const p = PROFILE[b.q];
    return `<li class="stimme neu" style="--i:${i}"><article aria-label="Bewertung von ${b.name}" style="display:grid;gap:12px">
      <div class="zeile"><span class="sterne" role="img" aria-label="${b.s} von 5 Sternen">${sterne(b.s)}</span><time datetime="${b.d}">${lang.format(new Date(b.d))}</time></div>
      <blockquote><p>${b.text}</p></blockquote>
      <p class="wer"><b>${b.name}</b><span class="quelle label">bei ${p.name}</span></p>
      ${b.a ? `<details class="antwort"${offen ? ' open' : ''}><summary>Antwort der Kinzigstube</summary><p>${b.a.text}</p><small>${INHABERIN} · <time datetime="${b.a.d}">${lang.format(new Date(b.a.d))}</time></small></details>` : ''}
    </article></li>`;
  }

  /* ── Varianten ── */
  const band = $('[data-band]'), live = $('[data-live]'), mittag = $('[data-mittag]'), pop = $('[data-pop]'), pilleBlock = $('[data-pille-block]'), pille = $('[data-pille]');

  function zeichneBand() {
    if (z.v === 'band') {
      const auswahl = STIMMEN.filter(b => b.q === 'google').slice(0, 3);
      band.innerHTML = `<h2 class="nur-sr" id="band-titel">Bewertungen bei Google</h2><div class="band-innen">${profilBlock('google')}
        <ol class="stimmen" aria-label="Die drei neuesten Bewertungen mit Text">${auswahl.map((b, i) => stimme(b, i, { offen: i === 1 && !matchMedia('(max-width: 760px)').matches })).join('')}</ol></div>`;
    } else if (z.v === 'mehrere') {
      const n = q => STIMMEN.filter(b => q === 'alle' || b.q === q).length;
      band.innerHTML = `<div class="band-innen">
        <div><h2 class="nur-sr" id="band-titel">Bewertungen bei Google und Tripadvisor</h2>
          <div class="profile">${profilBlock('google')}${profilBlock('trip')}</div></div>
        <div>
          <p class="getrennt">Wir zeigen die Schnitte getrennt, weil jede Plattform anders zählt. Auswahl: die neuesten Bewertungen mit Text je Plattform.</p>
          <div class="filter" role="group" aria-label="Nach Plattform filtern" style="margin-top:16px">
            ${[['alle', 'Alle'], ['google', 'Google'], ['trip', 'Tripadvisor']].map(([k, t]) => `<button type="button" data-filter="${k}" aria-pressed="${z.filter === k}">${t} <small class="ziffern">${n(k)}</small></button>`).join('')}
          </div>
          <ol class="stimmen" data-liste aria-label="Ausgewählte Bewertungen"></ol>
          <p class="nur-sr" role="status" data-filter-status></p>
        </div></div>`;
      zeichneListe();
    } else band.innerHTML = '';
    band.hidden = z.v === 'pille';
  }
  function zeichneListe(neu = true) {
    const liste = $('[data-liste]', band); if (!liste) return;
    const treffer = STIMMEN.filter(b => z.filter === 'alle' || b.q === z.filter);
    liste.innerHTML = treffer.map((b, i) => stimme(b, i)).join('');
    if (!neu) liste.querySelectorAll('.neu').forEach(li => li.classList.remove('neu'));
    $('[data-filter-status]', band).textContent = `${treffer.length} Bewertungen ${z.filter === 'alle' ? 'aus beiden Quellen' : 'von ' + PROFILE[z.filter].name}`;
    band.querySelectorAll('[data-filter]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.filter === z.filter)));
  }
  function zeichnePop() {
    const auswahl = STIMMEN.filter(b => b.q === 'google').slice(0, 3);
    pop.innerHTML = `<button class="zu" type="button" popovertarget="stimmen-pop" popovertargetaction="hide" aria-label="Schließen">×</button>
      <h2 class="nur-sr" id="pop-titel">Bewertungen bei Google</h2>
      ${profilBlock('google', { links: false })}
      <ol class="stimmen" aria-label="Die drei neuesten Bewertungen mit Text">${auswahl.map((b, i) => stimme(b, i)).join('')}</ol>
      <div class="links" style="margin-top:10px">${profilBlock('google', { titel: false, hinweis: false }).match(/<div class="links">([\s\S]*?)<\/div>/)[1]}</div>`;
    $('.schnitt .zahl', pop).style.fontSize = '64px';
  }
  pop.addEventListener('toggle', e => {
    pille.setAttribute('aria-expanded', String(e.newState === 'open'));
    if (e.newState === 'open') pop.querySelectorAll('.stimme').forEach((li, i) => { li.classList.remove('neu'); void li.offsetWidth; li.classList.add('neu'); li.style.setProperty('--i', i); });
  });

  /* ── 2-Klick ── */
  const buehne = $('[data-buehne]'), status = $('[data-status]');
  let ladeUhr = null;
  function zeichneBuehne() {
    clearTimeout(ladeUhr);
    if (z.live === 'zu' || z.live === 'laedt') {
      buehne.innerHTML = `<div class="platzhalter"><div class="einwilligung">
        <h3>Live-Ansicht von Google laden?</h3>
        <p>Dann lädt Ihr Browser Inhalte von Google. Dabei werden Daten wie Ihre IP-Adresse an Google übertragen. Mehr dazu in der Datenschutzerklärung.</p>
        <p>Auch für die Live-Ansicht gilt: Wir prüfen die Bewertungen dort nicht auf Echtheit.</p>
        <div class="zeile"><button class="knopf" type="button" data-laden${z.live === 'laedt' ? ' aria-busy="true"' : ''}><span class="kreisel" aria-hidden="true"></span>${z.live === 'laedt' ? 'Lädt …' : 'Live-Ansicht laden'}</button>
          <label class="merken"><input type="checkbox" data-merken${z.merken ? ' checked' : ''}> Für diesen Besuch merken</label></div>
      </div></div>`;
    } else if (z.live === 'fehler') {
      buehne.innerHTML = `<div class="fehler"><div><h3 tabindex="-1">Die Live-Ansicht ließ sich nicht laden.</h3><p>Google antwortet gerade nicht. Die Auswahl oben bleibt gültig, alle Bewertungen finden Sie auch direkt im Profil.</p><div class="zeile" style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center"><button class="knopf" type="button" data-laden>Erneut versuchen</button><a class="leise-knopf" style="display:inline-flex;align-items:center;text-decoration:none" href="#profil" data-extern="google">Profil öffnen ${RAUS}</a></div></div></div>`;
    } else {
      buehne.innerHTML = `<div class="widget" tabindex="-1" aria-label="Live-Ansicht der Google-Bewertungen">
        <div class="widget-kopf"><span class="punkt" aria-hidden="true"></span><span><b>Kinzigstube</b> · ${zahl1.format(PROFILE.google.schnitt)} <span class="sterne" aria-hidden="true">${sterne(PROFILE.google.schnitt)}</span> · ${zahl.format(PROFILE.google.anzahl)} Rezensionen</span><button class="leise-knopf" type="button" data-entfernen>Live-Ansicht entfernen</button></div>
        <ol>${LIVE.map(l => `<li><span class="sterne" role="img" aria-label="${l.s} von 5 Sternen">${sterne(l.s)}</span><span>${l.text}</span><span class="meta">${l.name} · ${l.d}</span></li>`).join('')}</ol>
      </div>`;
    }
  }
  function laden() {
    if (z.live === 'laedt') return;
    z.live = 'laedt'; zeichneBuehne(); status.textContent = 'Live-Ansicht wird geladen …';
    ladeUhr = setTimeout(() => {
      z.live = z.dienst === 'aus' ? 'fehler' : 'offen'; zeichneBuehne();
      status.textContent = z.live === 'offen' ? 'Live-Ansicht geladen.' : 'Live-Ansicht nicht geladen. Google antwortet nicht.';
      const ziel = $('.widget, .fehler h3', buehne); if (ziel && !html.classList.contains('vorfuehrung')) ziel.focus({ preventScroll: true });
    }, reduziert() ? 200 : 900);
  }
  function entfernen() { z.live = 'zu'; zeichneBuehne(); status.textContent = 'Live-Ansicht entfernt. Es werden keine Daten mehr an Google übertragen.'; }

  /* ── Bedienung ── */
  let toastUhr = null;
  function toast(t) { const el = $('[data-toast]'); el.textContent = t; el.hidden = false; clearTimeout(toastUhr); toastUhr = setTimeout(() => { el.hidden = true; }, 3200); }
  document.addEventListener('click', e => {
    const ex = e.target.closest('[data-extern]');
    if (ex) { e.preventDefault(); toast(`Auf der Kundenseite öffnet sich hier das Profil bei ${PROFILE[ex.dataset.extern].name} in einem neuen Tab. In der Demo ohne Ziel.`); return; }
    if (e.target.closest('[data-laden]')) { laden(); return; }
    if (e.target.closest('[data-entfernen]')) { entfernen(); $('[data-laden]', buehne)?.focus(); return; }
    const f = e.target.closest('[data-filter]');
    if (f) { z.filter = f.dataset.filter; zeichneListe(); return; }
    if (e.target.closest('a[href="#start"]')) e.preventDefault();
  });
  document.addEventListener('change', e => { if (e.target.matches('[data-merken]')) z.merken = e.target.checked; });

  const VARIANTEN = ['band', 'pille', 'mehrere'];
  function variante(v) {
    if (!VARIANTEN.includes(v)) v = VARIANTEN[0];
    z.v = v; z.filter = 'alle';
    document.body.dataset.variante = v;
    document.querySelectorAll('[data-v]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.v === v)));
    const q = new URLSearchParams(location.search);
    if (q.get('v') !== v) { q.set('v', v); history.replaceState(null, '', '?' + q.toString().replace(/=(&|$)/g, '$1')); }
    if (pop.matches(':popover-open')) pop.hidePopover();
    pilleBlock.hidden = v !== 'pille';
    pilleBlock.inert = v !== 'pille';
    live.hidden = v === 'pille';
    mittag.hidden = v !== 'pille';
    zeichneBand();
    if (!z.merken) z.live = 'zu';
    zeichneBuehne(); status.textContent = '';
  }
  function dienst(d) { z.dienst = d; document.querySelectorAll('[data-dienst]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.dienst === d))); if (z.live !== 'zu') { z.live = 'zu'; zeichneBuehne(); } }
  document.querySelectorAll('[data-v]').forEach(b => b.addEventListener('click', () => { pause(); html.classList.remove('vorfuehrung'); variante(b.dataset.v); }));
  document.querySelectorAll('[data-dienst]').forEach(b => b.addEventListener('click', () => { pause(); html.classList.remove('vorfuehrung'); dienst(b.dataset.dienst); }));

  $('[data-sterne-klein]').innerHTML = sterne(PROFILE.google.schnitt);
  $('[data-schnitt-text]').textContent = zahl1.format(PROFILE.google.schnitt);
  zeichnePop();

  /* ── Vorführung ── */
  let zeitgeber = [], laeuft = false;
  function nach(ms, f) { zeitgeber.push(setTimeout(f, ms)); }
  function tippe(el) { if (!el) return; el.classList.remove('tipp'); void el.offsetWidth; el.classList.add('tipp'); setTimeout(() => el.classList.remove('tipp'), 650); }
  function klick(el) { if (!el) return; tippe(el); el.click(); }
  function insBild(el) { if (!el) return; const r = el.getBoundingClientRect(); if (r.bottom > innerHeight - 10 || r.top < 0) scrollTo({ top: scrollY + r.top - 40, behavior: reduziert() ? 'auto' : 'smooth' }); }
  function rundeBand() {
    zeichneBand(); z.live = 'zu'; zeichneBuehne();
    nach(1800, () => { const d = band.querySelectorAll('.antwort')[2]; if (d) { tippe(d.querySelector('summary')); d.open = true; } });
    nach(3600, () => insBild($('.einwilligung', buehne)));
    nach(4600, () => klick($('[data-laden]', buehne)));
    nach(8600, () => klick($('[data-entfernen]', buehne)));
    nach(9800, () => scrollTo({ top: 0, behavior: reduziert() ? 'auto' : 'smooth' }));
    nach(10800, runde);
  }
  function rundePille() {
    nach(900, () => { tippe(pille); pop.showPopover(); });
    nach(4200, () => { const d = pop.querySelectorAll('.antwort')[1]; if (d) d.open = true; });
    nach(6800, () => pop.hidePopover());
    nach(7800, () => { const d = pop.querySelectorAll('.antwort')[1]; if (d) d.open = false; runde(); });
  }
  function rundeMehrere() {
    z.filter = 'alle'; zeichneListe();
    nach(1600, () => klick($('[data-filter="trip"]', band)));
    nach(3800, () => klick($('[data-filter="google"]', band)));
    nach(6000, () => klick($('[data-filter="alle"]', band)));
    nach(8200, runde);
  }
  function runde() { ({ band: rundeBand, pille: rundePille, mehrere: rundeMehrere })[z.v](); }
  function pause() { zeitgeber.forEach(clearTimeout); zeitgeber = []; laeuft = false; }
  function neustart() { pause(); html.classList.remove('vorfuehrung'); z.merken = false; variante(z.v); scrollTo(0, 0); }
  function vorfuehren() { neustart(); html.classList.add('vorfuehrung'); laeuft = true; runde(); }

  variante(new URLSearchParams(location.search).get('v'));

})();
</script>
</body>
</html>