Zum Inhalt
← Hero & Section-Layouts

Karte per 2-Klick (Anfahrt ohne vorab geladene Karte)

Kartenbild mit Einwilligungsleiste: Die Anfahrt steht sofort da, die interaktive Karte lädt erst nach Klick und nennt vorher den Anbieter.

Ein Standort mit Ortsbezug (Praxis, Restaurant, Handwerk): Kartenbild sofort, interaktive Karte erst nach Klick.

Statt eines Karten-iframes steht ein selbst gehostetes Kartenbild oder eine gezeichnete Lageskizze. Daneben stehen Adresse, Sprech- oder Öffnungszeiten und ein Link „Route planen“, der die Karten-App öffnet. Erst ein Klick auf „Karte laden“ setzt das iframe ein. Der Hinweis daneben nennt vorher den Anbieter. Die Adresse steht zusätzlich als Text und als strukturierte Daten (schema.org LocalBusiness).

Lokale Betriebe brauchen die Anfahrt. Eingebettete Karten übertragen aber schon vor jeder Einwilligung Daten an den Anbieter und laden viel JavaScript. Ein statisches Bild mit Routen-Link reicht den meisten Besuchern und kostet fast nichts. Wer mehr braucht, holt sich die interaktive Karte mit einem Klick.

Wann einsetzen

Überall mit Ortsbezug: Praxen, Restaurants, Handwerk, Kanzleien, Boutiquen, Hotels, Vereine mit Treffpunkten. Die Variante Social Feed passt zu Gastronomie, Mode, Fotografie, Friseur und Fitness, wenn das Profil gepflegt wird und auf die Seite soll.

Wann nicht

Bei rein digitalen Angeboten. Nie als einzige Ortsangabe: Die Adresse gehört immer auch als Text auf die Seite.

Varianten

  • Statisches Kartenbild mit Hinweis und Button „Karte laden“
  • Lageskizze als SVG im Markenstil mit Routen-Link
  • Mehrere Standorte als Liste mit je eigenem Routen-Link
  • Social Feed: selbst gehostete Auswahl von Beiträgen mit Link zum Profil, der Live-Feed des Anbieters lädt erst per 2-Klick

Umsetzung

Kartenbild als AVIF oder WebP mit gesetztem width und height, damit nichts springt. Routen-Link als Karten-URL mit Zielparameter (destination) oder als geo:-Link. Der Button ersetzt den Platzhalter durch das iframe mit loading="lazy" und title. Bei OpenStreetMap-Kacheln steht „© OpenStreetMap-Mitwirkende“ am Bild. Die Einwilligung mit dem Consent-Banner abgleichen. Gegen Sprünge beim Nachladen hilft neben der festen Höhe die Scroll-Verankerung (overflow-anchor, seit Safari 27 Baseline): Wächst ein Platzhalter oder ein spät geladener Block über dem sichtbaren Bereich, hält der Browser die Leseposition; overflow-anchor: none nur dort setzen, wo ein Element bewusst nicht als Anker dienen soll. Social Feeds genauso bauen: eine Auswahl von Beiträgen (Bild, Datum, Text) liegt auf dem eigenen Server, jeder Beitrag verlinkt auf das Profil, das Script oder iframe des Anbieters kommt erst nach Klick.

Robust umsetzen

Telefon. Der Routen-Link ist mobil wichtiger als die eingebettete Karte. Er gehört groß unter die Adresse. Der Button muss groß genug für Touch sein.

Ohne Bewegung. Kein Effekt nötig. Wechsel zwischen Platzhalter und Karte geschehen sofort.

Barrierefrei. Adresse immer als Text. Das Kartenbild bekommt einen sinnvollen alt-Text, der die Lage beschreibt. Das iframe bekommt einen title.

Code

<!DOCTYPE html>
<!--
  Karte per 2-Klick (Anfahrt ohne vorab geladene Karte)
  Fundus · Hero & Section-Layouts · https://cecodesign.de/lab/fundus/hero-layouts/karte-zwei-klick/
  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>Karte per 2-Klick (Anfahrt ohne vorab geladene Karte) · Fundus-Demo</title>
<script>document.documentElement.classList.add('js');if(matchMedia('(prefers-reduced-motion: reduce)').matches)document.documentElement.classList.add('reduziert')</script>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Physiotherapy",
  "name": "Lendwerk Physiotherapie",
  "telephone": "+43 316 723418",
  "address": { "@type": "PostalAddress", "streetAddress": "Mariahilferstraße 24", "postalCode": "8020", "addressLocality": "Graz", "addressCountry": "AT" },
  "geo": { "@type": "GeoCoordinates", "latitude": 47.0726, "longitude": 15.4342 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"], "opens": "07:30", "closes": "19:00" },
    { "@type": "OpeningHoursSpecification", "dayOfWeek": "Friday", "opens": "07:30", "closes": "14:00" }
  ]
}
</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; }

/* Rezept „Praxis & Therapie: ruhig und zugewandt“: gedecktes Petrol statt Klinikblau,
   warme Off-Whites, dunkles Grüngrau statt Schwarz, Apricot nur für Hinweise */
:root {
  --grund: #f5f7f7; --flaeche: #e2e0de; --karte: #ffffff;
  --marke: #005450; --marke-tief: #003e3b; --minz: #cfe5df;
  --text: #363b3b; --leise: #596666; --linie: rgba(54, 59, 59, .14);
  --akzent: #ffc776;
  --ui: cubic-bezier(0.2, 0, 0.38, 0.9);        /* Token tech-präzise: Buttons, Zustände, 200 ms */
  --bild: cubic-bezier(0.37, 0, 0.63, 1);       /* easeInOutSine: nur Bild-Überblendungen, 700 ms */
}
* { 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; display: grid; grid-template-rows: auto 1fr; }
.mono { font: 500 11px/1.35 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); }
.serif { font-family: 'Hedvig Letters Serif', Georgia, serif; font-variation-settings: 'opsz' 24; font-weight: 400; }
a { color: inherit; }
:focus-visible { outline: 2.5px solid var(--marke); outline-offset: 3px; border-radius: 4px; }

/* ── Kopfzeile: Telefon und Termin immer sichtbar ───────────── */
.kopf { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px clamp(16px, 4vw, 48px); border-bottom: 1px solid var(--linie); background: var(--grund); }
.marke { display: flex; align-items: center; gap: 11px; text-decoration: none; }
.marke svg { width: 34px; height: 34px; flex: none; }
.marke b { display: block; font: 400 21px/1 'Hedvig Letters Serif', serif; font-variation-settings: 'opsz' 24; letter-spacing: -.01em; color: var(--marke-tief); }
.marke small { display: block; margin-top: 3px; font-size: 12.5px; color: var(--leise); letter-spacing: .01em; }
.kopf nav { display: flex; align-items: center; gap: 22px; }
.kopf .tel { font-size: 15px; font-weight: 500; text-decoration: none; font-variant-numeric: tabular-nums; display: inline-flex; gap: 8px; align-items: center; }
.kopf .tel svg { width: 16px; height: 16px; }
.knopf { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 48px; padding: 0 22px; border: 0; border-radius: 999px; background: var(--marke); color: #fff; font: 500 16px/1 'Google Sans Flex', sans-serif; text-decoration: none; cursor: pointer; transition: background-color .2s var(--ui), box-shadow .2s var(--ui); }
.knopf:hover { background: var(--marke-tief); }
.knopf svg { width: 18px; height: 18px; flex: none; }
.knopf.klein { min-height: 40px; padding: 0 18px; font-size: 15px; }
.knopf.hell { background: var(--karte); color: var(--marke-tief); box-shadow: inset 0 0 0 1.5px var(--linie); }
.knopf.hell:hover { background: #fff; box-shadow: inset 0 0 0 1.5px var(--marke); }
.knopf.gedrueckt { background: var(--marke-tief); box-shadow: 0 0 0 5px rgba(0, 84, 80, .18); }

/* ── Abschnitt Anfahrt ───────────────────────────────────── */
.anfahrt { width: 100%; max-width: 1280px; margin: 0 auto; padding: clamp(24px, 4.2vw, 64px) clamp(16px, 4vw, 48px); display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(28px, 4.5vw, 72px); align-items: center; }
.text { display: grid; gap: 22px; align-content: start; }
.text h1 { font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.75rem); line-height: 1.1; letter-spacing: -.01em; color: var(--marke-tief); text-wrap: balance; }
.text .lead { font-size: 17px; line-height: 1.6; max-width: 40ch; text-wrap: pretty; }
address { font-style: normal; font-size: 17px; line-height: 1.55; }
address b { font-weight: 600; }
.zeiten { display: grid; grid-template-columns: auto 1fr; gap: 4px 20px; font-size: 16px; line-height: 1.45; font-variant-numeric: tabular-nums; }
.zeiten dt { color: var(--leise); }
.wege { list-style: none; padding: 0; display: grid; gap: 10px; font-size: 16px; line-height: 1.45; }
.wege li { display: grid; grid-template-columns: 28px 1fr; gap: 10px; align-items: start; }
.wege .zeichen { width: 28px; height: 22px; border-radius: 6px; display: grid; place-items: center; font: 600 11px/1 'Google Sans Flex', sans-serif; letter-spacing: .02em; }
.wege .tram { background: var(--akzent); color: #3d2a00; }
.wege .lift { background: var(--minz); color: var(--marke-tief); }
.wege .lift svg { width: 14px; height: 14px; }
.aktionen { display: flex; flex-wrap: wrap; gap: 12px 18px; align-items: center; }
.textlink { font-size: 16px; font-weight: 500; color: var(--marke-tief); text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 5px; text-decoration-color: rgba(0, 84, 80, .4); transition: text-decoration-color .2s var(--ui); }
.textlink:hover { text-decoration-color: var(--marke); }
.trenn { height: 1px; background: var(--linie); }

/* Standortliste (Variante 3) */
.orte { list-style: none; padding: 0; display: grid; border-top: 1px solid var(--linie); }
.ort { border-bottom: 1px solid var(--linie); display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 4px 16px; padding: 14px 0; }
.ort button { all: unset; cursor: pointer; display: grid; grid-template-columns: 30px 1fr; gap: 2px 12px; align-items: baseline; border-radius: 6px; }
.ort .nr { grid-row: span 2; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font: 600 13px/1 'Google Sans Flex', sans-serif; box-shadow: inset 0 0 0 1.5px var(--marke); color: var(--marke); align-self: center; transition: background-color .2s var(--ui), color .2s var(--ui); }
.ort .ortname { font: 400 20px/1.2 'Hedvig Letters Serif', serif; font-variation-settings: 'opsz' 24; color: var(--marke-tief); }
.ort .ortinfo { font-size: 15px; line-height: 1.45; color: var(--leise); }
.ort[aria-current="true"] .nr { background: var(--marke); color: #fff; }
.ort .textlink { font-size: 15px; white-space: nowrap; }

/* Inhalte je Variante: einzelner Standort oder Liste */
.nur-orte { display: none; }
.anfahrt[data-v="standorte"] .nur-einzel { display: none; }
.anfahrt[data-v="standorte"] .nur-orte { display: grid; }
.wechsel > * { animation: rein .4s var(--ui) both; }
@keyframes rein { from { opacity: 0; translate: 0 8px; } }

/* ── Bühne: feste Maße, kein Layout-Sprung beim Nachladen ──── */
.spalte { display: grid; gap: 14px; min-width: 0; }
.buehne { position: relative; aspect-ratio: 6 / 5; border-radius: 18px; overflow: hidden; background: #ece8e1; box-shadow: 0 1px 0 rgba(255,255,255,.6) inset, 0 30px 60px -40px rgba(0, 62, 59, .45); isolation: isolate; }
.ebene { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity .7s var(--bild), visibility 0s linear .7s; }
.ebene.an { opacity: 1; visibility: visible; transition: opacity .7s var(--bild), visibility 0s; }
.ebene > svg, .live-innen > svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Karten-Stile: eine Geometrie, zwei Zeichnungen */
.kachel .land { fill: #efebe4; }
.kachel .haus { fill: #e2dcd2; }
.kachel .gruen { fill: #cfe4c3; }
.kachel .wald { fill: #bcd9ad; }
.kachel .platz { fill: #f7f3ec; stroke: #d9d2c6; stroke-width: 2; }
.kachel .fluss { fill: none; stroke: #a9d2dc; stroke-width: 56; }
.kachel .rand { fill: none; stroke: #d6cec1; stroke-linecap: round; }
.kachel .weg { fill: none; stroke: #fff; stroke-linecap: round; }
.kachel .weg.haupt { stroke: #fbefc6; }
.kachel .gleis { fill: none; stroke: #b9b1a5; stroke-width: 2; stroke-dasharray: 6 5; }
.kachel text { font-family: 'Google Sans Flex', sans-serif; font-size: 16px; fill: #6e6960; paint-order: stroke; stroke: #f7f4ef; stroke-width: 3.5px; stroke-linejoin: round; letter-spacing: .02em; }
.kachel text.ortstext { font-size: 19px; font-weight: 600; fill: #57524a; letter-spacing: .04em; }
.kachel text.wasser { fill: #4d8ea1; stroke: #a9d2dc; font-style: italic; letter-spacing: .35em; font-size: 18px; }
.kachel .poi circle { fill: #9b8f80; stroke: #fff; stroke-width: 2; }
.kachel .poi text { font-size: 15px; }

.skizze .land { fill: #ebe7e0; }
.skizze .gruen { fill: #d3e3c6; }
.skizze .wald { fill: #c4d9b6; }
.skizze .hoehe { fill: none; stroke: #aec8a0; stroke-width: 1.6; }
.skizze .baum { fill: #b6cea8; }
.skizze .platz { fill: #f6f3ee; }
.skizze .fluss { fill: none; stroke: #bcdcd4; stroke-width: 66; stroke-linecap: round; }
.skizze .welle { fill: none; stroke: #d9ece7; stroke-width: 2; stroke-dasharray: 18 26; stroke-linecap: round; }
.skizze .weg { fill: none; stroke: #fbfaf7; stroke-linecap: round; }
.skizze text { font-family: 'Google Sans Flex', sans-serif; font-size: 14.5px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; fill: #8a918e; }
.skizze text.ortstext { font: 400 29px 'Hedvig Letters Serif', serif; letter-spacing: 0; text-transform: none; fill: #5c6a67; }
.skizze text.wasser { font: 400 24px 'Hedvig Letters Serif', serif; letter-spacing: .4em; text-transform: none; fill: #5b8f86; }
.skizze .route { fill: none; stroke: var(--marke); stroke-width: 5; stroke-linecap: round; stroke-dasharray: .1 13; }
.skizze .routenmaske { fill: none; stroke: #fff; stroke-width: 18; stroke-linecap: round; stroke-dasharray: 1 1; stroke-dashoffset: 0; }
.skizze .halt rect { fill: var(--akzent); }
.skizze .halt text { fill: #3d2a00; font-size: 16px; letter-spacing: .06em; font-weight: 650; }
.skizze .marke-pin circle.aussen { fill: var(--marke); }
.skizze .marke-pin circle.hof { fill: var(--marke); opacity: .14; }
.skizze .schild rect { fill: #fff; }
.skizze .schild text { text-transform: none; letter-spacing: 0; }
.skizze .schild .s1 { font: 400 24px 'Hedvig Letters Serif', serif; fill: var(--marke-tief); }
.skizze .schild .s2 { font-size: 17px; font-weight: 450; fill: var(--leise); }
.skizze .zeit rect { fill: var(--marke-tief); }
.skizze .zeit text { fill: #fff; font-size: 16px; letter-spacing: .04em; text-transform: none; font-weight: 550; }

/* Übersicht (Variante 3): Stadtmaßstab, größere Schrift */
.uebersicht text { font-size: 19px; }
.uebersicht text.ortstext { font-size: 36px; }
.uebersicht text.wasser { font-size: 30px; }
/* Pins der Übersicht (Variante 3) */
.ortpin { transition: opacity .2s var(--ui); }
.ortpin circle { fill: #fff; stroke: var(--marke); stroke-width: 3; transition: fill .2s var(--ui); }
.ortpin text.n { font: 650 22px 'Google Sans Flex', sans-serif; fill: var(--marke); letter-spacing: 0; text-transform: none; text-anchor: middle; dominant-baseline: central; transition: fill .2s var(--ui); }
.ortpin .etikett { opacity: 0; transition: opacity .2s var(--ui); }
.ortpin.an circle { fill: var(--marke); }
.ortpin.an text.n { fill: #fff; }
.ortpin.an .etikett { opacity: 1; }
.ortpin .etikett rect { fill: #fff; }
.ortpin .etikett text { font: 400 27px 'Hedvig Letters Serif', serif; fill: var(--marke-tief); letter-spacing: 0; text-transform: none; }
.ortpin .ring { fill: var(--marke); opacity: 0; transition: opacity .2s var(--ui); }
.ortpin.an .ring { opacity: .14; }

/* Variante 1: Platzhalter-Karte mit Einwilligung */
.kachel .pin-schild rect { fill: #fff; }
.kachel .pin-schild text { font: 600 18px 'Google Sans Flex', sans-serif; fill: var(--marke-tief); stroke: none; letter-spacing: 0; }
.einwilligung { position: absolute; left: clamp(10px, 1.8vw, 16px); right: clamp(10px, 1.8vw, 16px); bottom: clamp(10px, 1.8vw, 16px); background: var(--karte); border-radius: 14px; padding: 16px 16px 16px 20px; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 22px; align-items: center; box-shadow: 0 18px 40px -22px rgba(0, 62, 59, .5), 0 0 0 1px rgba(54, 59, 59, .06); transition: opacity .2s var(--ui); }
.einwilligung .info { display: grid; gap: 5px; }
.einwilligung .wahl { display: grid; gap: 10px; justify-items: stretch; width: 196px; }
.einwilligung h2 { font: 400 20px/1.2 'Hedvig Letters Serif', serif; font-variation-settings: 'opsz' 24; color: var(--marke-tief); }
.einwilligung p { font-size: 14px; line-height: 1.5; color: var(--leise); max-width: 46ch; }
.einwilligung .knopf { width: 100%; padding: 0 26px; }
.merken { display: flex; gap: 10px; align-items: center; font-size: 14px; color: var(--leise); cursor: pointer; }
.merken input { width: 18px; height: 18px; accent-color: var(--marke); margin: 0; }
.laedt .einwilligung .knopf { pointer-events: none; }
.kreisel { width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(255,255,255,.35); border-top-color: #fff; display: none; animation: dreh .8s linear infinite; }
.laedt .kreisel { display: block; }
@keyframes dreh { to { rotate: 1turn; } }
.zuordnung { position: absolute; right: 0; top: 0; padding: 4px 8px; background: rgba(255, 255, 255, .82); font-size: 11px; color: #555; border-bottom-left-radius: 8px; }
.live-fuss .zuordnung { border-radius: 8px 0 0 0; }

/* Status: werden Daten an Dritte übertragen? */
.status { position: absolute; left: clamp(12px, 2.4vw, 22px); top: clamp(12px, 2.4vw, 22px); z-index: 3; display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px 7px 10px; border-radius: 999px; background: rgba(255, 255, 255, .92); font: 500 12.5px/1 'Google Sans Flex', sans-serif; color: var(--text); box-shadow: 0 0 0 1px rgba(54, 59, 59, .07); transition: opacity .2s var(--ui); }
.status i { width: 8px; height: 8px; border-radius: 50%; background: #2f8f6f; box-shadow: 0 0 0 3px rgba(47, 143, 111, .18); transition: background-color .2s var(--ui), box-shadow .2s var(--ui); }
.status.extern i { background: #d98b1c; box-shadow: 0 0 0 3px rgba(217, 139, 28, .2); }

/* „iframe“ (in der Demo nachgebildet): verschieben, zoomen */
.live { cursor: grab; touch-action: pan-y; }
.live.zieht { cursor: grabbing; }
.live-innen { position: absolute; inset: -12%; transform-origin: 50% 50%; transition: transform .25s var(--ui); will-change: transform; }
.live.zieht .live-innen, .live.direkt .live-innen { transition: none; }
.zoom { position: absolute; right: 12px; top: 12px; display: grid; background: #fff; border-radius: 8px; box-shadow: 0 1px 4px rgba(0,0,0,.2); overflow: hidden; z-index: 2; }
.zoom button { all: unset; width: 34px; height: 34px; display: grid; place-items: center; cursor: pointer; font: 400 22px/1 'Google Sans Flex', sans-serif; color: #333; transition: background-color .15s var(--ui); }
.zoom button + button { border-top: 1px solid #e6e6e6; }
.zoom button:hover { background: #f2f2f2; }
.zoom button.gedrueckt { background: #e4e4e4; }
.live-fuss { position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-between; align-items: end; pointer-events: none; z-index: 2; }
.live-fuss > * { pointer-events: auto; }
.entfernen { white-space: nowrap; margin: 0 0 10px 12px; font: 500 13px/1 'Google Sans Flex', sans-serif; color: var(--marke-tief); background: rgba(255,255,255,.92); border: 0; border-radius: 999px; padding: 8px 12px; cursor: pointer; box-shadow: 0 0 0 1px rgba(54, 59, 59, .08); }
.live-fuss .zuordnung { position: static; }
.tipp-hinweis { display: none; }

/* Leiste unter der Bühne: Varianten und verwendete Werte */
.leiste { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 18px; }
.schalter { display: flex; flex-wrap: wrap; gap: 2px; padding: 3px; background: var(--karte); border-radius: 999px; box-shadow: inset 0 0 0 1px var(--linie); }
.schalter button { font: 500 11px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); background: none; border: 0; border-radius: 999px; padding: 9px 12px; cursor: pointer; transition: color .15s var(--ui), background-color .15s var(--ui); }
.schalter button:hover { color: var(--marke-tief); }
.schalter button[aria-pressed="true"] { color: #fff; background: var(--marke); }
.schalter button.gedrueckt { box-shadow: 0 0 0 4px rgba(0, 84, 80, .16); }
.werte { display: flex; flex-wrap: wrap; gap: 4px 16px; text-transform: none; letter-spacing: .02em; }
.werte b { font-weight: 500; color: var(--text); }

/* Hinweis nach Klick auf „Route planen“ (in der Demo statt Sprung in die Karten-App) */
.toast { position: fixed; left: 50%; bottom: 24px; translate: -50% 8px; opacity: 0; z-index: 20; background: var(--marke-tief); color: #fff; padding: 12px 16px; border-radius: 12px; font-size: 14.5px; line-height: 1.4; max-width: min(440px, calc(100% - 32px)); pointer-events: none; transition: opacity .2s var(--ui), translate .4s var(--ui); }
.toast code { font: 500 12.5px 'Geist Mono', monospace; color: var(--akzent); }
.toast.an { opacity: 1; translate: -50% 0; }

/* Gedachter Zeiger für die Vorführung */
.zeiger { position: fixed; left: 0; top: 0; z-index: 30; width: 22px; height: 22px; pointer-events: none; display: none; }
:root.vorfuehrung .zeiger { display: block; }

/* Untere Leiste am Telefon: Anrufen, Termin, Route */
.unten { display: none; }

@media (max-width: 900px) {
  /* Einspaltig: Karte direkt unter Überschrift und Einleitung, Details danach */
  .anfahrt { grid-template-columns: minmax(0, 1fr); align-items: start; gap: 20px; }
  .text { display: contents; }
  .text > * { order: 3; }
  .text > .mono, .text > h1, .text > .lead { order: 1; }
  .spalte { order: 2; margin-bottom: 4px; }
  .buehne { aspect-ratio: 4 / 3; }
}
@media (max-width: 640px) {
  .kopf .tel span, .kopf .knopf { display: none; }
  .kopf .tel { width: 44px; height: 44px; justify-content: center; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--linie); }
  .kopf .tel svg { width: 19px; height: 19px; }
  body { padding-bottom: 78px; }
  .text { gap: 18px; }
  .aktionen .knopf { flex: 1 1 100%; min-height: 54px; font-size: 17px; }
  .aktionen .textlink { display: none; }
  .einwilligung { left: 10px; right: 10px; bottom: 10px; padding: 14px; gap: 10px; grid-template-columns: minmax(0, 1fr); }
  .buehne { aspect-ratio: 1 / 1; }
  .statisch > svg { top: -16%; height: 116%; }
  .einwilligung p { font-size: 13.5px; }
  .einwilligung .merken { display: none; }
  .einwilligung .wahl { width: auto; }
  .einwilligung .knopf { min-height: 48px; }
  .zuordnung { font-size: 10px; }
  .einwilligung h2 { font-size: 18px; }
  .nachbildung { display: none; }
  .leiste { justify-content: center; }
  .werte { justify-content: center; }
  .unten { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--linie); border-top: 1px solid var(--linie); padding-bottom: env(safe-area-inset-bottom); }
  .unten a { display: grid; justify-items: center; gap: 5px; padding: 11px 0 12px; background: var(--grund); text-decoration: none; font-size: 13px; font-weight: 500; color: var(--marke-tief); }
  .unten a svg { width: 22px; height: 22px; }
  .unten a.haupt { background: var(--marke); color: #fff; }
  .toast { bottom: 92px; }
}

/* Touch: Karte erst nach Antippen bedienen, damit die Seite weiter scrollt */
@media (hover: none) {
  .live .tipp-hinweis { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; background: rgba(0, 62, 59, .0); border: 0; cursor: pointer; }
  .live .tipp-hinweis span { background: rgba(0, 62, 59, .86); color: #fff; padding: 10px 14px; border-radius: 999px; font-size: 14px; }
  .live.bedienbar { touch-action: none; }
  .live.bedienbar .tipp-hinweis { display: none; }
}

/* ── Variante 4: Social Feed. Selbst gehostete Auswahl, Live-Einbettung erst per 2-Klick ── */
.nur-social { display: none; }
.anfahrt[data-v="social"] .nur-einzel, .anfahrt[data-v="social"] .nicht-social { display: none; }
.anfahrt[data-v="social"] .nur-social { display: grid; }
.anfahrt[data-v="social"] .aktionen.nur-social { display: flex; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.feed { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 12px; padding: clamp(12px, 2.4vw, 22px) clamp(10px, 1.8vw, 16px) clamp(10px, 1.8vw, 16px); background: #ebe7e0; }
.feed .einwilligung { position: static; }
.feed-kopf { display: flex; justify-content: flex-end; align-items: center; min-height: 28px; }
.feed-profil { font-size: 14px; font-weight: 500; color: var(--marke-tief); text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 4px; text-decoration-color: rgba(0, 84, 80, .4); transition: text-decoration-color .2s var(--ui); }
.feed-profil:hover { text-decoration-color: var(--marke); }
.beitraege { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 8px; min-height: 0; }
.beitraege li { min-width: 0; min-height: 0; }
.beitrag { position: relative; display: block; height: 100%; border-radius: 10px; overflow: hidden; text-decoration: none; container-type: size; background: var(--flaeche); }
.beitrag:focus-visible { outline: 3px solid var(--marke); outline-offset: -3px; }
.beitrag img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: scale .7s var(--bild); }
.beitrag:hover img, .beitrag.gezeigt img { scale: 1.04; }
.k-innen { position: absolute; inset: 0; display: grid; align-content: space-between; gap: 6px; padding: 9cqi; }
.k-innen span { font: 500 max(10px, 7.5cqi)/1.25 'Google Sans Flex', sans-serif; }
.k-innen b { font: 400 max(13px, 13cqi)/1.05 'Hedvig Letters Serif', serif; font-variation-settings: 'opsz' 24; }
.k-innen .b-gross { font-size: max(18px, 21cqi); letter-spacing: -.01em; }
.k-innen .zitat { font-size: max(12px, 12.5cqi); line-height: 1.12; align-self: center; }
.k-innen .mono-k { font: 500 max(9px, 6cqi)/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; }
.k-svg { display: block; width: 100%; height: 100%; min-height: 0; }
.k-innen:has(> .k-svg) { grid-template-rows: auto minmax(0, 1fr) auto; }
.k-innen:has(> .k-svg:first-child) { grid-template-rows: minmax(0, 1fr) auto; }
.mono-gramm { justify-self: start; width: 36cqi; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; font: 400 14cqi/1 'Hedvig Letters Serif', serif; font-style: normal; box-shadow: inset 0 0 0 1.5px currentColor; }
.k-marke { background: var(--marke); color: #fff; } .k-marke .k-svg { color: var(--minz); }
.k-apri { background: var(--akzent); color: #3d2a00; }
.k-minz { background: var(--minz); color: var(--marke-tief); }
.k-hell { background: #fff; color: var(--marke-tief); } .k-hell .k-svg { color: var(--marke); }
.k-tief { background: var(--marke-tief); color: #fff; }
.k-grund { background: var(--grund); color: var(--marke-tief); }
.neu-marke { position: absolute; right: 7px; top: 7px; padding: 4px 7px; border-radius: 999px; background: #fff; color: var(--marke-tief); font: 600 10px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .1em; text-transform: uppercase; }
.unterzeile { position: absolute; left: 0; right: 0; bottom: 0; display: grid; gap: 4px; padding: 26px 10px 9px; background: linear-gradient(rgba(0, 40, 38, 0), rgba(0, 40, 38, .92) 40%); color: #fff; font-size: 12.5px; line-height: 1.3; opacity: 0; translate: 0 6px; transition: opacity .2s var(--ui), translate .2s var(--ui); }
.unterzeile .uz-text { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
.unterzeile small { font: 500 10px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .12em; text-transform: uppercase; }
.beitrag:hover .unterzeile, .beitrag:focus-visible .unterzeile, .beitrag.gezeigt .unterzeile { opacity: 1; translate: 0 0; }
@container (max-height: 130px) { .unterzeile { padding-top: 16px; } .unterzeile small { display: none; } .unterzeile .uz-text { -webkit-line-clamp: 2; } }
.feed.laedt .einwilligung .knopf { pointer-events: none; }
.feed.laedt .kreisel { display: block; }
/* nachgebildete Einbettung des Anbieters (im Einsatz: dessen iframe oder Script) */
.feed-live { background: #ebe7e0; padding: calc(clamp(12px, 2.4vw, 22px) + 40px) clamp(10px, 1.8vw, 16px) 50px; }
.einbettung { height: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr); background: #fff; border-radius: 12px; box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); overflow: hidden; font-family: system-ui, sans-serif; }
.einb-kopf { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid #ececec; }
.einb-kopf svg { width: 30px; height: 30px; flex: none; }
.einb-kopf b { display: block; font: 600 14px/1.2 system-ui, sans-serif; color: #111; }
.einb-kopf small { display: block; font: 400 12.5px/1.2 system-ui, sans-serif; color: #555; }
.einb-folgen { margin-left: auto; padding: 8px 12px; border-radius: 8px; background: #262626; color: #fff; font: 600 13px/1 system-ui, sans-serif; text-decoration: none; white-space: nowrap; }
.einbettung .beitraege { gap: 3px; padding: 3px; }
.einbettung .beitrag { border-radius: 0; }
@media (max-width: 640px) {
  .anfahrt[data-v="social"] .buehne { aspect-ratio: 4 / 5; }
  .beitraege { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .beitraege li:nth-child(n+7) { display: none; }
  .einb-kopf small { display: none; }
}
@media (hover: none) {
  .unterzeile { display: none; }
  .beitrag:hover img { scale: none; }
}
.vorschau .nur-social.wege-block { display: none; }
@media (forced-colors: active) { button, [role=button], [role=tab] { border: 1px solid ButtonText; } }

/* Reduzierte Bewegung: alles sofort, keine Route, die sich zeichnet */
:root.reduziert *, :root.reduziert *::before, :root.reduziert *::after { transition-duration: .01ms !important; transition-delay: 0s !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
:root.reduziert .kreisel { animation: none; border-top-color: rgba(255,255,255,.35); }

/* Vorschau 960 × 720: nur die Bühne mit dem Nötigsten */
.vorschau body { overflow: hidden; }
.vorschau .anfahrt { padding-top: 34px; padding-bottom: 20px; gap: 44px; }
.vorschau main { display: grid; align-content: center; }
.vorschau .nur-einzel.wege-block, .vorschau .werte, .vorschau .textlink { display: none; }
</style>
</head>
<body>
<header class="kopf">
  <a class="marke" href="#start" aria-label="Lendwerk Physiotherapie, Startseite">
    <svg viewBox="0 0 34 34" aria-hidden="true"><circle cx="17" cy="17" r="16" fill="#005450"/><path d="M8.5 21c3-4.6 5.6-4.6 8.5 0s5.5 4.6 8.5 0" fill="none" stroke="#cfe5df" stroke-width="2.4" stroke-linecap="round"/><path d="M12 9.5v8.2h7" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
    <span><b>Lendwerk</b><small>Physiotherapie in Graz</small></span>
  </a>
  <nav aria-label="Kontakt">
    <a class="tel" href="tel:+43316723418"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 3.5h3l1.5 4-2 1.3a11 11 0 0 0 6.1 6.1l1.3-2 4 1.5v3a2 2 0 0 1-2.2 2A16.5 16.5 0 0 1 4.6 5.7a2 2 0 0 1 2-2.2Z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg><span>0316 72 34 18</span></a>
    <a class="knopf klein" href="#termin" data-demo-link>Termin vereinbaren</a>
  </nav>
</header>

<main>
<section class="anfahrt" id="anfahrt" data-v="bild" aria-labelledby="anfahrt-titel">
  <div class="text" data-text>
    <p class="mono nicht-social">Anfahrt &amp; Sprechzeiten</p>

    <!-- Ein Standort (Varianten 1 und 2) -->
    <h1 class="serif nur-einzel" id="anfahrt-titel">So finden Sie zu uns.</h1>
    <p class="lead nur-einzel">Vier Minuten vom Kunsthaus, im ersten Stock mit Lift. Die Karte lädt erst, wenn Sie es möchten.</p>
    <address class="nur-einzel"><b>Lendwerk Physiotherapie</b><br>Mariahilferstraße 24, 1. Stock<br>8020 Graz</address>
    <dl class="zeiten nur-einzel">
      <dt>Mo – Do</dt><dd>7:30 – 19:00 Uhr</dd>
      <dt>Freitag</dt><dd>7:30 – 14:00 Uhr</dd>
    </dl>
    <ul class="wege nur-einzel wege-block">
      <li><span class="zeichen tram" aria-hidden="true">Bim</span><span>Straßenbahn 1, 3, 6, 7 bis Südtiroler Platz / Kunsthaus</span></li>
      <li><span class="zeichen lift" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="M4 5.5 7 2.5l3 3M4 8.5l3 3 3-3" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span>Eingang über den Hof, ebenerdig zum Lift</span></li>
    </ul>
    <div class="aktionen nur-einzel">
      <a class="knopf" href="geo:47.0726,15.4342?q=Mariahilferstra%C3%9Fe%2024%2C%208020%20Graz" data-route data-ziel="Mariahilferstraße 24, 8020 Graz"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21s-6.5-6-6.5-11a6.5 6.5 0 0 1 13 0c0 5-6.5 11-6.5 11Z" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="12" cy="10" r="2.3" fill="currentColor"/></svg>Route planen</a>
      <a class="textlink" href="tel:+43316723418">Lieber anrufen</a>
    </div>

    <!-- Mehrere Standorte (Variante 3) -->
    <h1 class="serif nur-orte" aria-hidden="true">Drei Praxen in Graz.</h1>
    <p class="lead nur-orte">Jeder Standort hat eigene Zeiten und einen eigenen Routen-Link.</p>
    <ul class="orte nur-orte" data-orte>
      <li class="ort" aria-current="true">
        <button type="button" data-ort="0"><span class="nr">1</span><span class="ortname">Lend</span><span class="ortinfo">Mariahilferstraße 24 · Mo – Fr</span></button>
        <a class="textlink" href="geo:47.0726,15.4342" data-route data-ziel="Mariahilferstraße 24, 8020 Graz">Route</a>
      </li>
      <li class="ort">
        <button type="button" data-ort="1"><span class="nr">2</span><span class="ortname">St. Leonhard</span><span class="ortinfo">Leonhardstraße 58 · ebenerdig · Mo – Fr</span></button>
        <a class="textlink" href="geo:47.0745,15.4560" data-route data-ziel="Leonhardstraße 58, 8010 Graz">Route</a>
      </li>
      <li class="ort">
        <button type="button" data-ort="2"><span class="nr">3</span><span class="ortname">Andritz</span><span class="ortinfo">Andritzer Reichsstraße 41 · Di, Do abends</span></button>
        <a class="textlink" href="geo:47.1095,15.4220" data-route data-ziel="Andritzer Reichsstraße 41, 8045 Graz">Route</a>
      </li>
    </ul>

    <!-- Social Feed (Variante 4) -->
    <p class="mono nur-social">Aus der Praxis</p>
    <h1 class="serif nur-social">Neues aus dem Lendwerk.</h1>
    <p class="lead nur-social">Acht Beiträge aus unserem Instagram-Profil, gespeichert auf unserem eigenen Server. Den Live-Feed laden Sie nur, wenn Sie es möchten.</p>
    <ul class="wege nur-social wege-block">
      <li><span class="zeichen lift" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="m3 7.4 2.6 2.6L11 4.4" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span>Bilder und Texte liegen bei uns, beim Öffnen der Seite geht nichts an Instagram</span></li>
      <li><span class="zeichen lift" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="M5 3h6v6M11 3 3.5 10.5" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span>Jeder Beitrag führt per Link zum Original</span></li>
    </ul>
    <div class="aktionen nur-social">
      <a class="knopf" href="https://www.instagram.com/lendwerk.graz/" target="_blank" rel="noopener" data-extern>Profil @lendwerk.graz<span class="sr"> (öffnet in neuem Tab)</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 6h10v10M18 6 6.5 17.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></a>
      <a class="textlink" href="#termin" data-demo-link>Termin vereinbaren</a>
    </div>
  </div>

  <div class="spalte">
    <div class="buehne" data-buehne>
      <p class="status" data-status role="status"><i aria-hidden="true"></i><span data-status-text>Keine Daten an Dritte</span></p>

      <!-- Variante 1: selbst gehostetes Kartenbild, iframe erst nach Klick -->
      <div class="ebene an" data-ebene="bild">
        <div class="ebene an statisch" data-statisch>
          <div data-karte="statisch" role="img" aria-label="Kartenausschnitt Graz-Lend: Die Praxis liegt an der Mariahilferstraße, zwischen Lendplatz und Südtiroler Platz, westlich der Mur."></div>
          <span class="zuordnung">© OpenStreetMap-Mitwirkende</span>
          <div class="einwilligung" data-einwilligung>
            <div class="info">
              <h2>Interaktive Karte</h2>
              <p>Beim Laden gehen Daten wie Ihre IP-Adresse an die OpenStreetMap Foundation (Vereinigtes Königreich).</p>
            </div>
            <div class="wahl">
              <button class="knopf" type="button" data-laden><span class="kreisel" aria-hidden="true"></span><span data-laden-text>Karte laden</span></button>
              <label class="merken"><input type="checkbox" data-merken> Für diesen Besuch merken</label>
            </div>
          </div>
        </div>
        <div class="ebene live" data-live aria-hidden="true">
          <div class="live-innen" data-live-innen><div data-karte="live"></div></div>
          <div class="zoom"><button type="button" data-zoom="1" aria-label="Vergrößern">+</button><button type="button" data-zoom="-1" aria-label="Verkleinern">−</button></div>
          <button type="button" class="tipp-hinweis" data-tippen><span>Antippen, um die Karte zu bewegen</span></button>
          <div class="live-fuss"><button type="button" class="entfernen" data-entfernen>Karte entfernen</button><span class="zuordnung">© OpenStreetMap-Mitwirkende<span class="nachbildung"> · Nachbildung</span></span></div>
        </div>
      </div>

      <!-- Variante 2: Lageskizze im Markenstil -->
      <div class="ebene" data-ebene="skizze" role="img" aria-label="Lageskizze: Von der Haltestelle Südtiroler Platz / Kunsthaus vier Minuten zu Fuß die Mariahilferstraße hinauf bis zur Praxis Lendwerk."><div data-karte="skizze"></div></div>

      <!-- Variante 3: Übersicht mehrerer Standorte -->
      <div class="ebene" data-ebene="standorte" role="img" aria-label="Übersichtsskizze Graz mit drei Standorten: Lend, St. Leonhard und Andritz."><div data-karte="uebersicht"></div></div>

      <!-- Variante 4: Social Feed, Auswahl selbst gehostet, Live-Feed erst nach Klick -->
      <div class="ebene" data-ebene="social">
        <div class="ebene an feed" data-feed>
          <div class="feed-kopf"><a class="feed-profil" href="https://www.instagram.com/lendwerk.graz/" target="_blank" rel="noopener" data-extern>@lendwerk.graz<span class="sr"> auf Instagram (öffnet in neuem Tab)</span> ↗</a></div>
          <ul class="beitraege" data-beitraege="auswahl" aria-label="Ausgewählte Beiträge, selbst gehostet"></ul>
          <div class="einwilligung">
            <div class="info">
              <h2>Live-Feed</h2>
              <p>Beim Laden gehen Daten wie Ihre IP-Adresse an Meta Platforms Ireland. Die Auswahl oben liegt auf unserem Server.</p>
            </div>
            <div class="wahl">
              <button class="knopf" type="button" data-feed-laden><span class="kreisel" aria-hidden="true"></span><span data-feed-laden-text>Live-Feed laden</span></button>
            </div>
          </div>
        </div>
        <div class="ebene feed-live" data-feed-live aria-hidden="true">
          <div class="einbettung">
            <div class="einb-kopf">
              <svg viewBox="0 0 34 34" aria-hidden="true"><circle cx="17" cy="17" r="16" fill="#005450"/><path d="M8.5 21c3-4.6 5.6-4.6 8.5 0s5.5 4.6 8.5 0" fill="none" stroke="#cfe5df" stroke-width="2.4" stroke-linecap="round"/><path d="M12 9.5v8.2h7" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
              <span><b>lendwerk.graz</b><small>Lendwerk Physiotherapie</small></span>
              <a class="einb-folgen" href="https://www.instagram.com/lendwerk.graz/" target="_blank" rel="noopener" data-extern>Profil ansehen</a>
            </div>
            <ul class="beitraege" data-beitraege="live" aria-label="Neueste Beiträge, live geladen"></ul>
          </div>
          <div class="live-fuss"><button type="button" class="entfernen" data-feed-entfernen>Feed entfernen</button><span class="zuordnung">instagram.com<span class="nachbildung"> · Nachbildung</span></span></div>
        </div>
      </div>
    </div>

    <div class="leiste">
      <div class="schalter" role="group" aria-label="Variante">
        <button type="button" data-variante="bild" aria-pressed="true">Kartenbild</button>
        <button type="button" data-variante="skizze" aria-pressed="false">Lageskizze</button>
        <button type="button" data-variante="standorte" aria-pressed="false">Standorte</button>
        <button type="button" data-variante="social" aria-pressed="false">Social Feed</button>
      </div>
      <p class="mono werte" data-werte></p>
    </div>
  </div>
</section>
</main>

<nav class="unten" aria-label="Schnellzugriff">
  <a href="tel:+43316723418"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.6 3.5h3l1.5 4-2 1.3a11 11 0 0 0 6.1 6.1l1.3-2 4 1.5v3a2 2 0 0 1-2.2 2A16.5 16.5 0 0 1 4.6 5.7a2 2 0 0 1 2-2.2Z" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>Anrufen</a>
  <a class="haupt" href="#termin" data-demo-link><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="5.5" width="16" height="14" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M4 10h16M9 3.5v4M15 3.5v4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>Termin</a>
  <a href="geo:47.0726,15.4342" data-route data-ziel="Mariahilferstraße 24, 8020 Graz"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21s-6.5-6-6.5-11a6.5 6.5 0 0 1 13 0c0 5-6.5 11-6.5 11Z" fill="none" stroke="currentColor" stroke-width="1.7"/><circle cx="12" cy="10" r="2.3" fill="currentColor"/></svg>Route</a>
</nav>

<p class="toast" data-toast role="status" aria-live="polite"></p>
<svg class="zeiger" data-zeiger viewBox="0 0 22 22" aria-hidden="true"><path d="M3 2 18.5 11l-7 1.6-3.4 6.6Z" fill="#363b3b" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg>

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

  /* ── Geometrie (eigene Zeichnung, frei nach der Lage in Graz-Lend; 1200 × 900) ── */
  const G = {
    mur: 'M 690 -40 C 680 140, 640 260, 650 400 C 660 540, 700 640, 690 940',
    haupt: {
      mariahilf: 'M 600 668 C 585 590, 545 500, 538 420 C 532 340, 505 220, 468 118',
      annen: 'M 600 672 C 480 690, 300 700, -40 730',
      bruecke: 'M 600 668 L 800 652',
      murgasse: 'M 800 652 L 930 640',
      kepler: 'M 468 118 C 560 110, 680 100, 780 96',
      sack: 'M 780 96 C 772 300, 790 500, 800 652'
    },
    neben: {
      volksgarten: 'M 532 330 C 420 340, 300 352, -40 360',
      lendplatz: 'M 468 118 L -40 150',
      quer: 'M 547 520 C 420 535, 280 545, -40 560',
      roessl: 'M 360 -40 C 352 300, 345 600, 335 940',
      west: 'M 170 -40 L 150 940',
      sued: 'M 600 672 C 590 760, 560 850, 550 940',
      herren: 'M 930 640 L 960 940',
      burg: 'M 930 640 C 1000 600, 1100 580, 1240 570',
      nordost: 'M 780 96 L 1240 60',
      ostsued: 'M 800 652 C 820 760, 830 850, 840 940',
      sporgasse: 'M 930 640 C 960 520, 1000 470, 1060 440'
    },
    schlossberg: 'M 800 300 C 790 230, 860 200, 920 220 C 980 240, 990 320, 960 380 C 930 440, 850 440, 815 390 C 800 365, 805 330, 800 300 Z',
    stadtpark: 'M 1062 180 C 1120 170, 1250 170, 1250 260 L 1250 520 C 1180 540, 1090 520, 1072 450 C 1052 380, 1042 260, 1062 180 Z',
    volksgarten: 'M 190 400 C 250 385, 315 390, 322 420 L 318 512 C 300 532, 220 537, 195 517 C 178 482, 178 430, 190 400 Z',
    pin: [538, 420], halt: [566, 683]
  };
  const KAI = (dx) => `<path d="${G.mur}" transform="translate(${dx} 0)"`;

  function zufall(s) { return () => { s |= 0; s = s + 0x6D2B79F5 | 0; let t = Math.imul(s ^ s >>> 15, 1 | s); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }
  function haeuser() {
    const r = zufall(18), d = [];
    for (let y = -10; y < 920; y += 30) for (let x = -10; x < 1220; x += 36) {
      if (r() < .16) continue;
      const w = 14 + r() * 13, h = 12 + r() * 9;
      d.push(`M${(x + r() * 6).toFixed(1)} ${(y + r() * 5).toFixed(1)}h${w.toFixed(1)}v${h.toFixed(1)}h${(-w).toFixed(1)}Z`);
    }
    return `<path class="haus" d="${d.join('')}"/>`;
  }
  const strassen = (liste, cls, breite) => Object.values(liste).map(d => `<path class="${cls}" d="${d}" stroke-width="${breite}"/>`).join('');

  // Kachelkarte: so sähe ein selbst gehostetes Kartenbild bzw. das geladene iframe aus
  function kachelkarte(live) {
    const lbl = live ? 'k-live' : 'k-bild';
    return `<svg class="kachel" viewBox="170 40 880 733" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
      <defs>
        <path id="${lbl}-mh" d="M 586 610 C 572 540, 545 480, 538 440"/>
        <path id="${lbl}-an" d="M 120 712 C 300 700, 420 690, 560 676"/>
        <path id="${lbl}-vg" d="M 90 357 C 250 352, 380 341, 500 333"/>
        <path id="${lbl}-lk" d="M 624 250 C 595 330, 600 420, 606 470" />
        <path id="${lbl}-kp" d="M 520 110 C 600 104, 680 100, 760 96"/>
        <path id="${lbl}-ro" d="M 352 160 C 349 300, 346 400, 344 500"/>
        <path id="${lbl}-sa" d="M 772 200 C 776 300, 786 420, 794 560"/>
      </defs>
      <rect class="land" x="-200" y="-200" width="1600" height="1300"/>
      ${haeuser()}
      <path class="gruen" d="${G.volksgarten}"/><path class="gruen" d="${G.stadtpark}"/><path class="wald" d="${G.schlossberg}"/>
      <path class="fluss" d="${G.mur}"/>
      ${KAI(-54)} class="rand" stroke-width="14"/>${KAI(54)} class="rand" stroke-width="14"/>
      ${strassen(G.neben, 'rand', 12)}${strassen(G.haupt, 'rand', 19)}
      ${KAI(-54)} class="weg" stroke-width="10"/>${KAI(54)} class="weg" stroke-width="10"/>
      ${strassen(G.neben, 'weg', 8)}${strassen(G.haupt, 'weg haupt', 15)}
      <path class="gleis" d="M 600 676 C 480 694, 300 704, -40 734 M 600 664 L 930 644"/>
      <ellipse class="platz" cx="450" cy="126" rx="34" ry="20"/><rect class="platz" x="904" y="618" width="54" height="40" rx="4"/>
      <path class="wald" d="M 596 628 c -10 -16 6 -34 24 -30 c 16 4 20 24 8 34 c -10 8 -26 8 -32 -4 Z" style="fill:#b9c9d6"/>
      <text><textPath href="#${lbl}-mh" startOffset="2%">Mariahilferstraße</textPath></text>
      <text><textPath href="#${lbl}-an" startOffset="30%">Annenstraße</textPath></text>
      <text><textPath href="#${lbl}-vg" startOffset="8%">Volksgartenstraße</textPath></text>
      <text><textPath href="#${lbl}-lk">Lendkai</textPath></text>
      <text><textPath href="#${lbl}-kp" startOffset="18%">Keplerbrücke</textPath></text>
      <text><textPath href="#${lbl}-ro" startOffset="10%">Rösselmühlgasse</textPath></text>
      <text><textPath href="#${lbl}-sa" startOffset="12%">Sackstraße</textPath></text>
      <text class="wasser" transform="translate(668 300) rotate(84)">Mur</text>
      <text class="ortstext" x="214" y="465">Volksgarten</text>
      <text class="ortstext" x="838" y="318">Schlossberg</text>
      <text x="912" y="690">Hauptplatz</text>
      <text x="404" y="98">Lendplatz</text>
      <text x="636" y="604" style="font-size:12.5px">Kunsthaus</text>
      <g class="poi"><circle cx="${G.halt[0]}" cy="${G.halt[1]}" r="6"/><text x="${G.halt[0] - 12}" y="${G.halt[1] + 26}" text-anchor="middle">Südtiroler Platz</text></g>
      ${live ? `<g class="poi"><circle cx="478" cy="476" r="5"/><text x="470" y="498" text-anchor="end">Apotheke</text><circle cx="412" cy="292" r="5"/><text x="424" y="297">Bäckerei</text><circle cx="756" cy="420" r="5"/><text x="742" y="425" text-anchor="end">Schlossbergbahn</text><circle cx="250" cy="640" r="5"/><text x="262" y="645">Bus 40, 67</text></g>` : ''}
      <g class="pin-schild">
        <rect x="${G.pin[0] - 150}" y="${G.pin[1] - 62}" width="124" height="40" rx="20" style="filter:drop-shadow(0 4px 8px rgba(0,0,0,.14))"/>
        <text x="${G.pin[0] - 88}" y="${G.pin[1] - 36}" text-anchor="middle">Lendwerk</text>
      </g>
      <g transform="translate(${G.pin[0]} ${G.pin[1]})"><path d="M0 0c-6-10-18-20-18-34a18 18 0 0 1 36 0c0 14-12 24-18 34Z" fill="#005450" stroke="#fff" stroke-width="2.5"/><circle cy="-34" r="6.5" fill="#fff"/></g>
    </svg>`;
  }

  // Lageskizze im Markenstil: nur das, was man für den Weg braucht
  function skizze() {
    const [px, py] = G.pin, [hx, hy] = G.halt;
    const route = `M ${hx} ${hy} L 600 668 C 585 590, 545 500, 538 428`;
    const baeume = [[220, 430], [258, 448], [292, 420], [236, 486], [278, 500], [210, 470], [300, 470]].map(([x, y]) => `<circle class="baum" cx="${x}" cy="${y}" r="9"/>`).join('');
    return `<svg class="skizze" viewBox="170 40 880 733" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
      <defs>
        <mask id="routen-maske" maskUnits="userSpaceOnUse" x="0" y="0" width="1200" height="900"><path class="routenmaske" data-routenmaske d="${route}" pathLength="1"/></mask>
        <path id="s-mh" d="M 470 200 C 498 250, 520 330, 530 380"/>
        <path id="s-an" d="M 160 710 C 300 700, 400 693, 520 682"/>
        <path id="s-lk" d="M 618 250 C 594 330, 598 420, 604 470"/>
      </defs>
      <rect class="land" x="-200" y="-200" width="1600" height="1300"/>
      <path class="gruen" d="${G.volksgarten}"/>${baeume}
      <path class="gruen" d="${G.stadtpark}"/>
      <path class="wald" d="${G.schlossberg}"/>
      <path class="hoehe" d="${G.schlossberg}" transform="translate(882 318) scale(.66) translate(-882 -318)"/>
      <path class="hoehe" d="${G.schlossberg}" transform="translate(884 320) scale(.34) translate(-884 -320)"/>
      <path class="fluss" d="${G.mur}"/>
      <path class="welle" d="${G.mur}" transform="translate(-14 0)"/><path class="welle" d="${G.mur}" transform="translate(12 30)"/>
      ${KAI(-56)} class="weg" stroke-width="10"/>${KAI(56)} class="weg" stroke-width="10"/>
      ${['volksgarten', 'lendplatz', 'quer', 'roessl', 'sued', 'herren', 'burg', 'nordost'].map(k => `<path class="weg" d="${G.neben[k]}" stroke-width="8"/>`).join('')}
      ${strassen(G.haupt, 'weg', 17)}
      <ellipse class="platz" cx="450" cy="126" rx="38" ry="24"/>
      <text><textPath href="#s-mh">Mariahilferstraße</textPath></text>
      <text><textPath href="#s-an" startOffset="22%">Annenstraße</textPath></text>
      <text><textPath href="#s-lk">Lendkai</textPath></text>
      <text class="wasser" transform="translate(676 230) rotate(84)">Mur</text>
      <text class="ortstext" x="250" y="612">Volksgarten</text>
      <text class="ortstext" x="804" y="474">Schlossberg</text>
      <text class="ortstext" x="300" y="250">Lend</text>
      <text x="900" y="700">Hauptplatz</text>
      <path class="route" d="${route}" mask="url(#routen-maske)"/>
      <g class="zeit" transform="translate(420 556)"><rect width="100" height="36" rx="18"/><text x="50" y="24" text-anchor="middle">4 Min.</text></g>
      <g class="halt" transform="translate(${hx - 38} ${hy + 14})"><rect width="76" height="34" rx="9"/><text x="38" y="23" text-anchor="middle">1 3 6 7</text></g>
      <text x="${hx - 38}" y="${hy + 72}">Südtiroler Platz</text>
      <g class="marke-pin" transform="translate(${px} ${py})">
        <circle class="hof" r="34"/><circle class="aussen" r="17" stroke="#fff" stroke-width="3"/>
        <path d="M-4 -7v11h8" fill="none" stroke="#fff" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
      </g>
      <g class="schild" transform="translate(${px - 258} ${py - 84})">
        <rect width="214" height="78" rx="14" style="filter:drop-shadow(0 10px 18px rgba(0,62,59,.16))"/>
        <text class="s1" x="20" y="34">Lendwerk</text>
        <text class="s2" x="20" y="58">Hof · 1. Stock · Lift</text>
      </g>
    </svg>`;
  }

  // Übersicht für mehrere Standorte (eigene Zeichnung, Maßstab Stadt)
  const ORTE = [
    { x: 492, y: 452, name: 'Lendwerk Lend', unter: 'Mariahilferstraße 24' },
    { x: 902, y: 486, name: 'Lendwerk St. Leonhard', unter: 'Leonhardstraße 58' },
    { x: 590, y: 150, name: 'Lendwerk Andritz', unter: 'Andritzer Reichsstraße 41' }
  ];
  function uebersicht() {
    const mur = 'M 640 -40 C 630 100, 560 200, 560 330 C 560 470, 640 560, 620 700 C 605 800, 650 880, 660 940';
    const wege = ['M -40 540 C 200 520, 420 500, 560 480', 'M 600 476 C 760 470, 960 490, 1240 500', 'M 600 -40 C 590 120, 570 240, 545 330', 'M 560 480 C 520 600, 470 760, 440 940', 'M 640 520 C 740 620, 820 760, 860 940', 'M 360 -40 C 380 200, 400 380, 420 500', 'M 820 -40 C 800 160, 760 330, 720 470'];
    const LAGE = [[-170, -146], [-230, -146], [-380, -46]];   // Etikett über bzw. links vom Pin
    const pins = ORTE.map((o, i) => {
      return `<g class="ortpin${i === 0 ? ' an' : ''}" data-pin="${i}" transform="translate(${o.x} ${o.y})">
        <circle class="ring" r="50" style="fill:#005450;stroke:none"/>
        <circle r="25"/><text class="n">${i + 1}</text>
        <g class="etikett" transform="translate(${LAGE[i][0]} ${LAGE[i][1]})"><rect width="340" height="92" rx="16" style="filter:drop-shadow(0 10px 18px rgba(0,62,59,.16))"/><text x="24" y="40">${o.name}</text><text x="24" y="70" style="font:450 19px 'Google Sans Flex',sans-serif;fill:#596666">${o.unter}</text></g>
      </g>`;
    }).join('');
    return `<svg class="skizze uebersicht" viewBox="0 0 1200 900" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
      <rect class="land" x="-200" y="-200" width="1600" height="1300"/>
      <path class="gruen" d="M 690 330 C 700 300, 740 300, 760 330 C 790 380, 780 450, 740 460 C 700 465, 680 420, 690 330 Z"/>
      <path class="wald" d="M 610 340 c -6 -30 26 -48 50 -36 c 22 12 20 44 0 56 c -20 10 -44 6 -50 -20 Z"/>
      <path class="gruen" d="M 980 120 C 1060 90, 1200 100, 1240 140 L 1240 330 C 1150 330, 1040 300, 1000 240 C 970 200, 960 140, 980 120 Z"/>
      <path class="fluss" d="${mur}" style="stroke-width:40"/>
      <path class="welle" d="${mur}" transform="translate(-6 0)"/>
      ${wege.map(d => `<path class="weg" d="${d}" stroke-width="10"/>`).join('')}
      <text class="wasser" transform="translate(586 252) rotate(78)">Mur</text>
      <text class="ortstext" x="236" y="340">Lend</text>
      <text class="ortstext" x="300" y="680">Gries</text>
      <text class="ortstext" x="690" y="210">Geidorf</text>
      <text class="ortstext" x="820" y="620">St. Leonhard</text>
      <text class="ortstext" x="660" y="60">Andritz</text>
      <text class="ortstext" x="700" y="760">Jakomini</text>
      <text x="200" y="566">Hauptbahnhof</text>
      <text x="636" y="404">Schlossberg</text>
      ${pins}
    </svg>`;
  }

  const platzhalter = $('[data-karte="statisch"]');
  platzhalter.outerHTML = kachelkarte(false).replace('aria-hidden="true"', `role="img" aria-label="${platzhalter.getAttribute('aria-label')}"`);
  $('[data-karte="live"]').outerHTML = kachelkarte(true);
  $('[data-karte="skizze"]').outerHTML = skizze();
  $('[data-karte="uebersicht"]').outerHTML = uebersicht();

  /* ── Variante 4: Beiträge (Bilder und Texte liegen auf dem eigenen Server) ── */
  const PROFIL = 'https://www.instagram.com/lendwerk.graz/', MEDIEN = 'bilder/';
  const SVG_BRUECKE = `<svg class="k-svg" viewBox="0 0 120 72"><path d="M8 66h104" stroke="currentColor" stroke-opacity=".4" stroke-width="2"/><circle cx="20" cy="57" r="6" fill="currentColor"/><path d="M30 60 62 44l22-12 8 31h9M30 60l22 3" fill="none" stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><path d="M62 30V12m-6 7 6-7 6 7" fill="none" stroke="#ffc776" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
  const SVG_ROLLE = `<svg class="k-svg" viewBox="0 0 120 72"><path d="M8 64h104" stroke="currentColor" stroke-opacity=".3" stroke-width="2"/><rect x="24" y="22" width="74" height="32" rx="4" fill="currentColor"/><ellipse cx="24" cy="38" rx="8" ry="16" fill="#cfe5df"/><ellipse cx="24" cy="38" rx="3" ry="6" fill="currentColor" fill-opacity=".5"/><path d="M40 27v22M54 27v22M68 27v22M82 27v22" stroke="#fff" stroke-opacity=".55" stroke-width="3" stroke-linecap="round" stroke-dasharray="1 6"/></svg>`;
  const SVG_BUERO = `<svg class="k-svg" viewBox="0 0 120 72"><path d="M8 66h104M76 40h36M84 40l-4 26M106 40l4 26" fill="none" stroke="currentColor" stroke-opacity=".4" stroke-width="2" stroke-linecap="round"/><path d="M88 39l4-12h12l-2 12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linejoin="round"/><circle cx="50" cy="14" r="6" fill="currentColor"/><path d="M50 22v22M50 27 38 8M50 27l12-19M50 44h-10l-2 22M36 46h26M40 46l-4 20M60 46l4 20" fill="none" stroke="currentColor" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
  const BEITRAEGE = [
    { neu: true, art: 'k-apri', datum: '2. Nov.', text: 'Rückenkurs ausgebucht. Für die Warteliste reicht eine E-Mail.', inhalt: '<span class="mono-k">Kurs</span><b class="b-gross">Aus&shy;gebucht</b><span>Warteliste per E-Mail</span>' },
    { neu: true, art: 'k-hell', datum: '31. Okt.', text: 'Mobil im Büro: drei Übungen am Schreibtisch.', inhalt: `${SVG_BUERO}<span>Mobil im Büro: 3 Übungen</span>` },
    { art: 'foto', datum: '28. Okt.', text: 'Neuer Wartebereich im Hof, ebenerdig zum Lift.', bild: 'fenster-licht.jpg', b: 1200, h: 800 },
    { art: 'k-marke', datum: '24. Okt.', text: 'Übung der Woche: die Brücke. Dreimal zwölf, langsam absenken.', inhalt: `<span class="mono-k">Übung der Woche</span>${SVG_BRUECKE}<span>Die Brücke · 3 × 12</span>` },
    { art: 'k-apri', datum: '21. Okt.', text: 'Rückenkurs ab 12. November, dienstags 18 Uhr, acht Plätze.', inhalt: '<span class="mono-k">Kurs</span><b>Rücken&shy;kurs</b><span>ab 12. Nov. · Di 18 Uhr</span>' },
    { art: 'foto', datum: '17. Okt.', text: 'Gehen ist Therapie. Das Team am Schöckl.', bild: 'huegel-nebel-hoch.jpg', b: 800, h: 1000 },
    { art: 'k-minz', datum: '14. Okt.', text: 'Bewegung ist das beste Rezept.', inhalt: '<b class="zitat">„Bewegung ist das beste Rezept.“</b><span>Team Lendwerk</span>' },
    { art: 'k-hell', datum: '10. Okt.', text: 'Faszienrolle: drei Fehler, die fast alle machen.', inhalt: `${SVG_ROLLE}<span>Faszienrolle: 3 Fehler</span>` },
    { art: 'k-tief', datum: '7. Okt.', text: 'Neu im Team: Mira Holzer, Sportphysiotherapie.', inhalt: '<span class="mono-k">Neu im Team</span><i class="mono-gramm">MH</i><span>Mira Holzer</span>' },
    { art: 'k-grund', datum: '3. Okt.', text: 'Vier Minuten vom Kunsthaus zu uns.', inhalt: '<b class="b-gross">4 Min.</b><span>vom Kunsthaus zu uns</span>' }
  ];
  const kachel = p => `<li><a class="beitrag ${p.art}" href="${PROFIL}" target="_blank" rel="noopener" data-extern aria-label="${p.datum}: ${p.text} (öffnet Instagram in neuem Tab)">`
    + (p.bild ? `<img src="${MEDIEN}${p.bild}" alt="" width="${p.b}" height="${p.h}" decoding="async">` : `<span class="k-innen" aria-hidden="true">${p.inhalt}</span>`)
    + (p.neu ? '<span class="neu-marke" aria-hidden="true">Neu</span>' : '')
    + `<span class="unterzeile" aria-hidden="true"><small>${p.datum}</small><span class="uz-text">${p.text}</span></span></a></li>`;
  $('[data-beitraege="auswahl"]').innerHTML = BEITRAEGE.filter(p => !p.neu).slice(0, 8).map(kachel).join('');
  $('[data-beitraege="live"]').innerHTML = BEITRAEGE.slice(0, 8).map(kachel).join('');

  /* ── Zustand ─────────────────────────────────────────── */
  const abschnitt = $('.anfahrt'), text = $('[data-text]');
  const statischEl = $('[data-statisch]'), liveEl = $('[data-live]'), innen = $('[data-live-innen]');
  const status = $('[data-status]'), statusText = $('[data-status-text]');
  const ladenKnopf = $('[data-laden]'), ladenText = $('[data-laden-text]'), merken = $('[data-merken]');
  const werteEl = $('[data-werte]'), toast = $('[data-toast]'), zeiger = $('[data-zeiger]');
  const knoepfe = $$('[data-variante]');
  let variante = 'bild', geladen = false, ladeUhr = null, toastUhr = null;
  const sicht = { x: 0, y: 0, s: 1 };

  const WERTE = {
    bild: () => [['Kartenbild', '1200 × 900, feste Maße'], ['iframe', geladen ? 'geladen' : 'erst nach Klick'], ['Überblendung', '700 ms · cubic-bezier(0.37, 0, 0.63, 1)'], ['UI', '200 ms · cubic-bezier(0.2, 0, 0.38, 0.9)']],
    skizze: () => [['Lageskizze', 'SVG inline'], ['Dritte', 'keine'], ['Route', '800 ms · cubic-bezier(0.37, 0, 0.63, 1)']],
    standorte: () => [['Standorte', '3, je eigener Routen-Link'], ['Dritte', 'keine'], ['Wechsel', '400 ms, 8 px · UI 200 ms']],
    social: () => [['Auswahl', '8 Beiträge, selbst gehostet'], ['Live-Feed', feedGeladen ? 'geladen' : 'erst nach Klick'], ['Bildtext', '200 ms · cubic-bezier(0.2, 0, 0.38, 0.9)'], ['Überblendung', '700 ms']]
  };
  function werteZeigen() { werteEl.innerHTML = WERTE[variante]().map(([k, v]) => `<span>${k} <b>${v}</b></span>`).join(''); }
  function statusZeigen() {
    const karte = variante === 'bild' && geladen, feed = variante === 'social' && feedGeladen;
    status.classList.toggle('extern', karte || feed);
    statusText.textContent = karte ? 'Verbunden mit openstreetmap.org' : feed ? 'Verbunden mit instagram.com' : 'Keine Daten an Dritte';
  }

  /* Variante 4: Live-Feed erst nach Klick (in echt: Script oder iframe des Anbieters einsetzen) */
  const feedEl = $('[data-feed]'), feedLive = $('[data-feed-live]'), feedKnopf = $('[data-feed-laden]'), feedText = $('[data-feed-laden-text]');
  let feedGeladen = false, feedUhr = null;
  function feedLaden() {
    if (feedGeladen || feedUhr) return;
    feedEl.classList.add('laedt'); feedText.textContent = 'Lädt …';
    feedUhr = setTimeout(() => {
      feedUhr = null; feedGeladen = true;
      feedEl.classList.remove('laedt'); feedText.textContent = 'Live-Feed laden';
      feedEl.classList.remove('an'); feedEl.inert = true;
      feedLive.classList.add('an'); feedLive.inert = false; feedLive.removeAttribute('aria-hidden');
      statusZeigen(); werteZeigen();
    }, reduziert() ? 0 : 520);
  }
  function feedEntfernen() {
    clearTimeout(feedUhr); feedUhr = null; feedGeladen = false;
    feedEl.classList.remove('laedt'); feedText.textContent = 'Live-Feed laden';
    feedLive.classList.remove('an'); feedLive.inert = true; feedLive.setAttribute('aria-hidden', 'true');
    feedEl.classList.add('an'); feedEl.inert = false;
    $$('.beitrag.gezeigt').forEach(b => b.classList.remove('gezeigt'));
    statusZeigen(); werteZeigen();
  }
  feedKnopf.addEventListener('click', feedLaden);
  $('[data-feed-entfernen]').addEventListener('click', () => { feedEntfernen(); feedKnopf.focus(); });
  feedLive.inert = true;

  /* Variante 1: zwei Klicks bis zur Karte */
  function sichtSetzen(direkt) {
    liveEl.classList.toggle('direkt', !!direkt);
    innen.style.transform = `translate(${sicht.x}px, ${sicht.y}px) scale(${sicht.s})`;
  }
  function laden() {
    if (geladen || ladeUhr) return;
    statischEl.classList.add('laedt');
    ladenText.textContent = 'Lädt …';
    ladeUhr = setTimeout(() => {           // in echt: iframe einsetzen und auf load warten
      ladeUhr = null;
      geladen = true;
      statischEl.classList.remove('laedt');
      ladenText.textContent = 'Karte laden';
      sicht.x = 0; sicht.y = 0; sicht.s = 1; sichtSetzen(true);
      statischEl.classList.remove('an'); statischEl.inert = true;
      liveEl.classList.add('an'); liveEl.inert = false; liveEl.removeAttribute('aria-hidden');
      statusZeigen(); werteZeigen();
    }, reduziert() ? 0 : 520);
  }
  function entfernen() {
    clearTimeout(ladeUhr); ladeUhr = null;
    geladen = false;
    statischEl.classList.remove('laedt'); ladenText.textContent = 'Karte laden';
    liveEl.classList.remove('an', 'bedienbar'); liveEl.inert = true; liveEl.setAttribute('aria-hidden', 'true');
    statischEl.classList.add('an'); statischEl.inert = false;
    statusZeigen(); werteZeigen();
  }
  ladenKnopf.addEventListener('click', laden);
  $('[data-entfernen]').addEventListener('click', () => { entfernen(); ladenKnopf.focus(); });

  function zoomen(r) {
    sicht.s = Math.max(1, Math.min(2.4, +(sicht.s * (r > 0 ? 1.35 : 1 / 1.35)).toFixed(3)));
    begrenzen(); sichtSetzen(false);
  }
  function begrenzen() {
    const b = liveEl.clientWidth * (0.12 + (sicht.s - 1) * 0.5), h = liveEl.clientHeight * (0.12 + (sicht.s - 1) * 0.5);
    sicht.x = Math.max(-b, Math.min(b, sicht.x)); sicht.y = Math.max(-h, Math.min(h, sicht.y));
  }
  $$('[data-zoom]').forEach(k => k.addEventListener('click', () => zoomen(+k.dataset.zoom)));

  // Ziehen: Maus sofort, Touch erst nach Antippen (sonst blockiert die Karte das Scrollen)
  let zug = null;
  liveEl.addEventListener('pointerdown', e => {
    if (e.target.closest('button')) return;
    if (e.pointerType === 'touch' && !liveEl.classList.contains('bedienbar')) return;
    zug = { id: e.pointerId, x: e.clientX - sicht.x, y: e.clientY - sicht.y };
    liveEl.setPointerCapture(e.pointerId); liveEl.classList.add('zieht');
  });
  liveEl.addEventListener('pointermove', e => {
    if (!zug || e.pointerId !== zug.id) return;
    sicht.x = e.clientX - zug.x; sicht.y = e.clientY - zug.y; begrenzen(); sichtSetzen(true);
  });
  const loslassen = () => { zug = null; liveEl.classList.remove('zieht'); };
  liveEl.addEventListener('pointerup', loslassen); liveEl.addEventListener('pointercancel', loslassen);
  $('[data-tippen]').addEventListener('click', () => liveEl.classList.add('bedienbar'));

  /* Variante 2: Route zeichnet sich einmal (800 ms) */
  const maske = $('[data-routenmaske]');
  function routeZeichnen() {
    maske.getAnimations().forEach(a => a.cancel());
    if (reduziert()) return;
    maske.animate([{ strokeDashoffset: 1 }, { strokeDashoffset: 0 }], { duration: 800, delay: 350, easing: 'cubic-bezier(0.37, 0, 0.63, 1)', fill: 'backwards' });
  }

  /* Variante 3: Standort wählen */
  const orte = $$('.ort'), pins = $$('[data-pin]');
  function ortWaehlen(i) {
    orte.forEach((o, j) => o.setAttribute('aria-current', j === i ? 'true' : 'false'));
    pins.forEach((p, j) => p.classList.toggle('an', j === i));
  }
  $$('[data-ort]').forEach(b => b.addEventListener('click', () => ortWaehlen(+b.dataset.ort)));

  /* Variantenwechsel */
  function zeigen(v) {
    if (v === variante) return;
    variante = v;
    knoepfe.forEach(k => k.setAttribute('aria-pressed', k.dataset.variante === v ? 'true' : 'false'));
    $$('[data-ebene]').forEach(e => { const an = e.dataset.ebene === v; e.classList.toggle('an', an); e.inert = !an; });
    abschnitt.dataset.v = v;
    text.classList.remove('wechsel'); void text.offsetWidth; text.classList.add('wechsel');
    if (v === 'skizze') routeZeichnen();
    if (v !== 'bild' && !merken.checked) entfernen();   // ohne „merken“ fragt die Seite beim nächsten Mal wieder
    if (v !== 'social') feedEntfernen();
    statusZeigen(); werteZeigen();
  }
  // Variante in der URL (?v=), andere Parameter bleiben erhalten
  knoepfe.forEach(k => k.addEventListener('click', () => {
    zeigen(k.dataset.variante);
    const q = new URLSearchParams(location.search); q.set('v', k.dataset.variante);
    history.replaceState(null, '', location.pathname + '?' + q + location.hash);
  }));
  $$('[data-ebene]').forEach(e => { e.inert = !e.classList.contains('an'); });
  liveEl.inert = true;

  /* Routen-Link: in der Demo ein Hinweis statt Sprung in die Karten-App */
  function hinweis(t) {
    toast.innerHTML = t; toast.classList.add('an');
    clearTimeout(toastUhr); toastUhr = setTimeout(() => toast.classList.remove('an'), 2600);
  }
  document.addEventListener('click', e => {
    const r = e.target.closest('[data-route]');
    if (r) { e.preventDefault(); hinweis(`Öffnet die Karten-App mit dem Ziel ${r.dataset.ziel} <code>${r.getAttribute('href').split('?')[0]}</code>`); }
    const d = e.target.closest('[data-demo-link]');
    if (d) { e.preventDefault(); hinweis('Hier ginge es zur Terminbuchung.'); }
    const x = e.target.closest('[data-extern]');
    if (x) { e.preventDefault(); hinweis('Öffnet das Profil in neuem Tab: <code>instagram.com/lendwerk.graz</code>'); }
  });

  /* ── Vorführung: gedachter Zeiger klickt sich durch ───── */
  let uhren = [], rahmen = null, zp = { x: 0, y: 0 };
  const mitte = (el, fx = .5, fy = .5) => { const r = el.getBoundingClientRect(); return { x: r.left + r.width * fx, y: r.top + r.height * fy }; };
  const sinus = t => -(Math.cos(Math.PI * t) - 1) / 2;
  function zeigerSetzen(p) { zp = p; zeiger.style.transform = `translate(${p.x - 3}px, ${p.y - 2}px)`; }
  function fahren(ziel, dauer, beiSchritt) {
    cancelAnimationFrame(rahmen);
    const von = { ...zp }, t0 = performance.now();
    if (reduziert()) { zeigerSetzen(ziel); beiSchritt && beiSchritt(1, ziel); return; }
    const schritt = t => {
      const k = Math.min(1, (t - t0) / dauer), e = sinus(k);
      const p = { x: von.x + (ziel.x - von.x) * e, y: von.y + (ziel.y - von.y) * e };
      zeigerSetzen(p); beiSchritt && beiSchritt(e, p);
      if (k < 1) rahmen = requestAnimationFrame(schritt);
    };
    rahmen = requestAnimationFrame(schritt);
  }
  function druecken(el, aktion) {
    el.classList.add('gedrueckt');
    uhren.push(setTimeout(() => { el.classList.remove('gedrueckt'); aktion && aktion(); }, 160));
  }
  const nach = (ms, f) => uhren.push(setTimeout(f, ms));

  function ausgang() {
    clearTimeout(ladeUhr); ladeUhr = null;
    merken.checked = false;
    toast.classList.remove('an');
    if (variante === 'social') { feedEntfernen(); return; }
    zeigen('bild'); entfernen(); ortWaehlen(0);
  }
  // Social Feed: Bildtexte zeigen, Live-Feed laden, wieder entfernen, Profil-Link (Schleife 12 s)
  function feedVorfuehren() {
    const b = $('[data-buehne]'), aus = () => $$('[data-beitraege="auswahl"] .beitrag'), live = () => $$('[data-beitraege="live"] .beitrag');
    const zeige = el => { $$('.beitrag.gezeigt').forEach(k => k.classList.remove('gezeigt')); el && el.classList.add('gezeigt'); };
    zeigerSetzen(mitte(b, .82, .95));
    nach(150, () => fahren(mitte(aus()[0], .5, .45), 700));
    nach(900, () => zeige(aus()[0]));
    nach(1900, () => fahren(mitte(aus()[1], .5, .45), 550));
    nach(2500, () => zeige(aus()[1]));
    nach(3500, () => { zeige(null); fahren(mitte(feedKnopf, .6, .55), 750); });
    nach(4350, () => druecken(feedKnopf, feedLaden));
    nach(5600, () => fahren(mitte(live()[0], .5, .45), 600));
    nach(6250, () => zeige(live()[0]));
    nach(7400, () => { zeige(null); fahren(mitte($('[data-feed-entfernen]')), 700); });
    nach(8200, () => druecken($('[data-feed-entfernen]'), feedEntfernen));
    nach(9300, () => fahren(mitte($('.feed-profil'), .5, .55), 700));
    nach(10100, () => druecken($('.feed-profil'), () => $('.feed-profil').click()));
    nach(12000, vorfuehren);
  }
  function vorfuehren() {
    pause();
    html.classList.add('vorfuehrung');
    ausgang();
    if (variante === 'social') return feedVorfuehren();
    const b = $('[data-buehne]');
    zeigerSetzen(mitte(b, .82, .9));
    // 1) Platzhalter → Klick auf „Karte laden“ → iframe
    nach(150, () => fahren(mitte(ladenKnopf, .62, .55), 750));
    nach(1000, () => druecken(ladenKnopf, laden));
    // 2) Geladene Karte verschieben und zoomen
    nach(2350, () => fahren(mitte(b, .55, .42), 500));
    nach(2950, () => {
      const start = { ...zp }, s0 = { x: sicht.x, y: sicht.y };
      liveEl.classList.add('zieht');
      fahren({ x: start.x - 110, y: start.y + 46 }, 1100, (e, p) => { sicht.x = s0.x + (p.x - start.x); sicht.y = s0.y + (p.y - start.y); begrenzen(); sichtSetzen(true); });
      nach(1150, () => liveEl.classList.remove('zieht'));
    });
    nach(4300, () => fahren(mitte($('[data-zoom="1"]')), 500));
    nach(4900, () => druecken($('[data-zoom="1"]'), () => zoomen(1)));
    // 3) Lageskizze
    nach(6100, () => fahren(mitte(knoepfe[1]), 700));
    nach(6850, () => druecken(knoepfe[1], () => zeigen('skizze')));
    nach(8500, () => fahren(mitte($('.aktionen [data-route]'), .55, .55), 800));
    nach(9400, () => druecken($('.aktionen [data-route]'), () => $('.aktionen [data-route]').click()));
    // 4) Mehrere Standorte
    nach(10700, () => fahren(mitte(knoepfe[2]), 700));
    nach(11450, () => druecken(knoepfe[2], () => zeigen('standorte')));
    nach(12400, () => fahren(mitte($('[data-ort="1"]'), .3, .5), 650));
    nach(13100, () => druecken($('[data-ort="1"]'), () => ortWaehlen(1)));
    nach(14000, () => fahren(mitte($('[data-ort="2"]'), .3, .5), 550));
    nach(14600, () => druecken($('[data-ort="2"]'), () => ortWaehlen(2)));
    nach(16200, vorfuehren);
  }
  function pause() { uhren.forEach(clearTimeout); uhren = []; cancelAnimationFrame(rahmen); liveEl.classList.remove('zieht'); }
  function weiter() { if (html.classList.contains('vorfuehrung')) vorfuehren(); }
  function neustart() { pause(); html.classList.remove('vorfuehrung'); ausgang(); }

  werteZeigen(); statusZeigen();
  const vStart = new URLSearchParams(location.search).get('v');
  if (['skizze', 'standorte', 'social'].includes(vStart)) zeigen(vStart);

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