Zum Inhalt
← Glas & Material

Animierter Verlaufsrahmen

Ein Lichtstreif läuft über die 1,5-px-Kante der einen Karte, die zählen soll: conic-gradient mit registriertem Winkel, ohne Fläche zu beanspruchen.

Ein einzelnes Angebot auf deckender Karte hervorheben, läuft in allen Browsern: Hotel, Gastro, Kurs, Shop. Unterumschalter Licht: Lichtlauf, Lichtpunkt, Bei Hover.

Ein Licht läuft um den Rahmen eines einzelnen Elements. Technik: Die Custom Property --angle per @property registrieren (syntax '<angle>', inherits: false, initial-value 0deg). Der Rahmen besteht aus zwei Hintergründen: innen die Kartenfarbe als padding-box, darunter ein conic-gradient(from var(--angle), transparent 70%, var(--accent), transparent) als border-box. Dazu border: 1px solid transparent. Eine @keyframes-Animation dreht --angle linear von 0 auf 360deg, eine Umdrehung dauert 3 bis 6 Sekunden.

Das Auge folgt Bewegung, und hier bewegt sich nur eine Kante. So bekommt ein Element Aufmerksamkeit, ohne mehr Fläche zu brauchen. Es wirkt wie Licht, das über eine Kante wandert.

Wann einsetzen

Für genau ein hervorgehobenes Element pro Ansicht: empfohlener Tarif, Hauptangebot, Call-to-Action, aktives Feature. Außerdem für ein Eingabefeld im Fokus und für KI- oder Ladezustände.

Wann nicht

Nicht auf allen Karten gleichzeitig, das wirkt wie ein Rummelplatz. Nicht als Daueranimation direkt neben langem Lesetext. Nicht für ruhige Marken, die auf Verläufe verzichten, außer sehr leise und in Hausfarben. Am Button nicht als Daueranimation und nie auf mehreren Buttons einer Seite.

Varianten

  • Lichtlauf: breiter Lichtstreif dreht dauerhaft
  • Border-Beam: nur ein kurzer Lichtpunkt wandert um den Rahmen, optional mit Glow über ein unscharfes Duplikat
  • Nur bei Hover oder Fokus: das Licht steht und läuft erst bei Berührung
  • Statischer Verlaufsrahmen mit Lichtkante oben
  • Pulsierender Rahmen (Paper Shaders: Pulsing border)
  • background-clip: border-area (ab Chrome 150): Verlauf nur in der Rahmenlinie, die Karte darf durchscheinen (Glas), gestrichelte Verlaufsrahmen möglich; Rückfall per Maske (mask-composite: exclude)
  • Als Button: Lichtlauf um eine Pille nur bei Hover, Fokus und Laden, in Ruhe eine stehende Lichtkante (Prinzip Shimmer- und Moving-Border-Button)

Umsetzung

@property wird seit 2024 von allen Engines unterstützt. Ohne Registrierung kann der Browser den Winkel nicht interpolieren, er springt dann nur. Die padding-box/border-box-Technik funktioniert sauber mit border-radius. Alternative: ein Pseudo-Element mit mask-composite: exclude. Für einen Glow ein unscharfes Duplikat des Verlaufs mit filter: blur() hinter das Element legen. Weil inherits: false gilt, braucht das Duplikat dieselbe Animation. Außerhalb des Bildschirms die Animation per IntersectionObserver anhalten. Resend nutzt die Technik an Buttons, mit hover:scale-105 in 150 ms.

Robust umsetzen

Telefon. Läuft unverändert. Eine Hover-Variante braucht auf Touch einen Ersatz, etwa eine Umdrehung nach dem Antippen.

Ohne Bewegung. Keine Rotation. Stattdessen ein stehender Verlaufsrahmen mit Lichtkante oben.

Barrierefrei. Nicht als einziges Fokus-Signal verwenden. Zusätzlich einen echten outline-Fokus setzen. Der Rahmen ist Schmuck und braucht keinen Text für Screenreader.

Code

<!DOCTYPE html>
<!--
  Animierter Verlaufsrahmen
  Fundus · Glas & Material · https://cecodesign.de/lab/fundus/glas-material/verlaufs-rahmen/
  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>Animierter Verlaufsrahmen · 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: 'Newsreader'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/newsreader:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 200 800; font-style: normal; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/newsreader:vf@latest/latin-opsz-italic.woff2') format('woff2-variations'); font-weight: 200 800; font-style: italic; font-display: swap; }
@font-face { font-family: 'Mona Sans'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/mona-sans:vf@latest/latin-wdth-normal.woff2') format('woff2-variations'); font-weight: 200 900; font-stretch: 75% 125%; font-display: swap; }
@font-face { font-family: 'Geist'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist:vf@latest/latin-wght-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; }
@font-face { font-family: 'Bricolage Grotesque'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/bricolage-grotesque:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 200 800; font-display: swap; }
@font-face { font-family: 'Onest'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/onest:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }

/* Der Winkel muss registriert sein, sonst springt er statt zu drehen */
@property --winkel { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

:root {
  /* Remise Seelinde: Abendkarte. Warmes Dunkel statt Schwarz, Creme, ein Schilfton vom Seeufer */
  --grund: #2b2724; --karte: #35302c; --karte-hervor: #3a3430;
  --text: #fef2e3; --leise: #a79f94; --linie: rgba(254, 242, 227, .13); --linie-stark: rgba(254, 242, 227, .26);
  --schilf: #a3b08f; --licht: #fef2e3;
  --ui: cubic-bezier(0.4, 0, 0.2, 1);       /* Rezept: UI 150–250 ms */
  --rahmen: 1.5px;
  --runde: 6000ms;                           /* eine Umdrehung, linear */
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--grund); color: var(--text); font-family: 'Mona Sans', system-ui, sans-serif; font-stretch: 100%; -webkit-font-smoothing: antialiased; }
body { min-height: 100svh; overflow-x: hidden; }
.seite { max-width: 1180px; margin: 0 auto; padding: clamp(18px, 3.4vw, 40px) clamp(16px, 4vw, 48px) clamp(28px, 5vw, 64px); }
.label { font: 520 .75rem/1.2 'Mona Sans', system-ui, sans-serif; font-stretch: 125%; letter-spacing: .06em; text-transform: uppercase; color: var(--leise); }
.mono { font: 500 11px/1.35 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); }

/* Kopf */
.kopf { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding-bottom: clamp(18px, 3vw, 28px); border-bottom: 1px solid var(--linie); }
.marke { display: flex; align-items: center; gap: 12px; color: inherit; text-decoration: none; }
.marke svg { width: 30px; height: 30px; flex: none; }
.marke b { display: block; font: 400 1.375rem/1 'Newsreader', Georgia, serif; font-variation-settings: 'opsz' 36; letter-spacing: -.01em; }
.marke small { display: block; margin-top: 4px; font-size: .625rem; font-stretch: 125%; letter-spacing: .08em; text-transform: uppercase; color: var(--leise); }
.nav { display: flex; align-items: center; gap: clamp(14px, 2.2vw, 28px); list-style: none; padding: 0; }
.nav a { color: var(--leise); text-decoration: none; transition: color .2s var(--ui); }
.nav a:hover, .nav a[aria-current] { color: var(--text); }
.nav .sprache { color: var(--leise); }
.nav .sprache b { color: var(--text); font-weight: 520; }
.buchen { display: inline-flex; align-items: center; height: 38px; padding: 0 18px; border-radius: 999px; background: var(--text); color: var(--grund) !important; }

/* Einleitung */
.intro { display: grid; grid-template-columns: 1.7fr 1fr; gap: clamp(20px, 5vw, 72px); align-items: end; padding: clamp(28px, 4vw, 52px) 0 clamp(22px, 3vw, 32px); }
h1 { margin-top: 16px; font: 300 clamp(2.5rem, 1.5rem + 4vw, 4.25rem)/1.05 'Newsreader', Georgia, serif; font-variation-settings: 'opsz' 72; letter-spacing: -.015em; text-wrap: balance; }
h1 em { font-style: italic; font-weight: 300; color: var(--schilf); }
.intro p.lauf { font-size: 1.0625rem; line-height: 1.6; color: rgba(254, 242, 227, .78); max-width: 38ch; text-wrap: pretty; }
.intro p.lauf strong { font-weight: 540; color: var(--text); }

/* Buchungsleiste: schnell, ruhig, ohne Licht (nur ein Element pro Ansicht leuchtet) */
.leiste-buchung { display: grid; grid-template-columns: repeat(3, 1fr) auto; border: 1px solid var(--linie); border-radius: 14px; margin-top: clamp(28px, 4vw, 48px); }
.feld { display: grid; gap: 5px; padding: 12px 20px; border: 0; border-right: 1px solid var(--linie); background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; transition: background .2s var(--ui); }
.feld:hover { background: rgba(254, 242, 227, .04); }
.feld:first-child { border-radius: 13px 0 0 13px; }
.feld span:last-child { font: 400 1.125rem/1.2 'Newsreader', Georgia, serif; font-variation-settings: 'opsz' 24; }
.feld:focus-visible, .knopf:focus-visible, .umschalter button:focus-visible, .nav a:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
.leiste-buchung .pruefen { margin: 8px; padding: 0 22px; border: 0; border-radius: 10px; background: var(--text); color: var(--grund); font: 560 .75rem/1 'Mona Sans', sans-serif; font-stretch: 125%; letter-spacing: .06em; text-transform: uppercase; cursor: pointer; }

/* Demo-Leiste */
.werkbank { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin-bottom: 18px; }
.werkbank .werte { flex: 1 1 280px; }
.umschalter[hidden] { display: none; }
.umschalter { justify-self: start; display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--linie); border-radius: 10px; background: rgba(0, 0, 0, .14); }
.umschalter button { padding: 7px 11px; border: 0; border-radius: 7px; background: none; color: var(--leise); cursor: pointer; font: 500 10.5px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .12em; text-transform: uppercase; transition: color .15s var(--ui), background .15s var(--ui); }
.umschalter button:hover { color: var(--text); }
.umschalter button[aria-pressed="true"] { color: var(--text); background: rgba(254, 242, 227, .09); }
.werte { display: flex; align-items: center; justify-content: flex-end; min-height: 2.7em; text-align: right; text-transform: none; letter-spacing: .03em; font-size: 10.5px; color: rgba(167, 159, 148, .85); text-wrap: balance; }

/* Karten */
.karten { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(14px, 1.8vw, 22px); isolation: isolate; align-items: stretch; }
.karte { position: relative; display: flex; flex-direction: column; border: 1px solid var(--linie); border-radius: 18px; background: var(--karte); transition: border-color .4s var(--ui); }
.karte:hover { border-color: var(--linie-stark); }
.bild { margin: 8px 8px 0; border-radius: 12px; overflow: hidden; aspect-ratio: 16 / 9.4; background: #4a423b; }
.bild svg { display: block; width: 100%; height: 100%; }
.inhalt { display: flex; flex-direction: column; gap: 10px; flex: 1; padding: 18px 20px 20px; }
.karte h2 { font: 400 1.75rem/1.08 'Newsreader', Georgia, serif; font-variation-settings: 'opsz' 48; letter-spacing: -.012em; }
.karte .text { font-size: .9375rem; line-height: 1.55; color: rgba(254, 242, 227, .72); }
.fakten { display: flex; flex-wrap: wrap; gap: 6px; padding: 0; list-style: none; font-stretch: 106%; letter-spacing: .04em; }
.fakten li { padding: 5px 8px 4px; border: 1px solid var(--linie); border-radius: 6px; white-space: nowrap; }
.fuss { display: flex; align-items: end; justify-content: space-between; gap: 12px; margin-top: auto; padding-top: 14px; border-top: 1px solid var(--linie); }
.preis { font: 400 1.625rem/1 'Newsreader', Georgia, serif; font-variation-settings: 'opsz' 36; white-space: nowrap; }
.preis small { display: block; margin-bottom: 6px; font: 500 .625rem/1 'Mona Sans', sans-serif; font-stretch: 125%; letter-spacing: .07em; text-transform: uppercase; color: var(--leise); }
.knopf { display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 16px; border: 1px solid var(--linie-stark); border-radius: 999px; color: var(--text); text-decoration: none; font: 540 .6875rem/1 'Mona Sans', sans-serif; font-stretch: 125%; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; transition: background .2s var(--ui), color .2s var(--ui), border-color .2s var(--ui); }
.knopf:hover { background: rgba(254, 242, 227, .08); }
.knopf svg { width: 12px; height: 12px; }

/* ===== Der Effekt =====
   Zwei Hintergründe: innen die Kartenfarbe (padding-box), darunter ein drehender
   conic-gradient (border-box). Der transparente Rand lässt nur den Ring durchscheinen. */
.hervor {
  --ring: conic-gradient(from var(--winkel), var(--linie-stark) 0%, var(--linie-stark) 52%, var(--schilf) 70%, var(--licht) 83%, var(--licht) 89%, var(--linie-stark) 97%, var(--linie-stark) 100%);
  --glanz: conic-gradient(from var(--winkel), transparent 0%, transparent 56%, var(--schilf) 72%, var(--licht) 84%, var(--licht) 89%, transparent 97%, transparent 100%);
  border: var(--rahmen) solid transparent;
  background: linear-gradient(var(--karte-hervor), var(--karte-hervor)) padding-box, var(--ring) border-box;
  animation: drehen var(--runde) linear infinite;
}
.hervor:hover { border-color: transparent; }
/* Glow: unscharfes Duplikat des Rings hinter der Karte */
.hervor::before {
  content: ''; position: absolute; inset: calc(var(--rahmen) * -1); z-index: -1; border-radius: inherit;
  background: var(--glanz); filter: blur(16px); opacity: .95; pointer-events: none;
  animation: drehen var(--runde) linear infinite;
}
@keyframes drehen { to { --winkel: 360deg; } }

/* Variante Lichtpunkt (Border-Beam): kurzes Segment, schneller, stärkerer Glow */
[data-variante="lichtpunkt"] { --runde: 4000ms; }
[data-variante="lichtpunkt"] .hervor {
  --ring: conic-gradient(from var(--winkel), var(--linie-stark) 0%, var(--linie-stark) 86%, var(--schilf) 90%, var(--licht) 93%, var(--linie-stark) 96%, var(--linie-stark) 100%);
  --glanz: conic-gradient(from var(--winkel), transparent 0%, transparent 86%, var(--schilf) 90%, var(--licht) 93%, transparent 96%, transparent 100%);
}
[data-variante="lichtpunkt"] .hervor::before { filter: blur(10px); opacity: 1; }

/* Variante Bei Hover: Licht steht, bis Zeiger oder Fokus kommt */
[data-variante="hover"] .hervor, [data-variante="hover"] .hervor::before { animation-play-state: paused; }
[data-variante="hover"] .hervor::before { opacity: .2; transition: opacity .4s var(--ui); }
[data-variante="hover"] .hervor:is(:hover, :focus-within, .an), [data-variante="hover"] .hervor:is(:hover, :focus-within, .an)::before { animation-play-state: running; }
[data-variante="hover"] .hervor:is(:hover, :focus-within, .an)::before { opacity: .95; }

/* Außerhalb des Bildschirms oder angehalten: nicht rechnen */
.hervor.ruht, .hervor.ruht::before, [data-halt] .hervor, [data-halt] .hervor::before { animation-play-state: paused !important; }

.plakette { position: absolute; top: -11px; left: 22px; display: inline-flex; align-items: center; gap: 8px; height: 22px; padding: 0 11px; border-radius: 999px; background: var(--grund); border: 1px solid var(--linie-stark); font: 560 .625rem/1 'Mona Sans', sans-serif; font-stretch: 125%; letter-spacing: .07em; text-transform: uppercase; color: var(--text); }
.plakette i { width: 5px; height: 5px; border-radius: 50%; background: var(--schilf); }
.hervor .knopf { background: var(--text); color: var(--grund); border-color: var(--text); }
.hervor .knopf:hover { background: #fff8ee; }

.unten { display: flex; justify-content: space-between; gap: 16px; margin-top: 14px; }

/* ===== Variante „border-area“ (Rezept saas-produkt-praezise) =====
   background-clip: border-area (ab Chrome 150) malt einen Hintergrund nur in die Rahmenlinie.
   Die Karte selbst darf deshalb durchscheinen (Glas über der Produktoberfläche), und border-style
   wird beachtet: auch gestrichelte Verlaufsrahmen gehen. Ohne Unterstützung: Ring per Maske
   (mask-composite: exclude) auf ::after, gestrichelte Zone mit einfarbigem Strich. */
html:not([data-v="saas"]) [data-welt="saas"], html:not([data-v="button"]) [data-welt="button"], html:is([data-v="saas"], [data-v="button"]) [data-welt="basis"] { display: none !important; }
html[data-v="saas"] {
  --grund: #08090a; --text: #f7f8f8; --leise: #8a8f98; --linie: #242728; --linie-stark: #34383b;
  --marke: #7170ff; --glas: rgba(22, 23, 24, .58); --ui-saas: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  font-family: 'Geist', system-ui, sans-serif;
}
html[data-v="saas"] .umschalter { background: rgba(255, 255, 255, .03); }
html[data-v="saas"] .umschalter button[aria-pressed="true"] { background: rgba(247, 248, 248, .08); }
html[data-v="saas"] :focus-visible { outline: 2px solid var(--marke); outline-offset: 3px; }
.s-kopf { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding-bottom: 18px; border-bottom: 1px solid var(--linie); font-size: 14px; }
.s-marke { display: inline-flex; align-items: center; gap: 10px; font-weight: 600; letter-spacing: -.02em; font-size: 16px; color: var(--text); text-decoration: none; }
.s-marke i { width: 20px; height: 20px; border-radius: 6px; background: linear-gradient(#f7f8f8, #f7f8f8) 4px 4px / 5px 12px no-repeat, linear-gradient(#f7f8f8, #f7f8f8) 11px 4px / 5px 7px no-repeat, var(--marke); }
.s-nav { display: flex; gap: 22px; list-style: none; padding: 0; }
.s-nav a { color: var(--leise); text-decoration: none; transition: color 160ms var(--ui-saas); }
.s-nav a:hover, .s-nav a[aria-current] { color: var(--text); }
.s-nav .s-anmelden { display: inline-flex; align-items: center; height: 32px; padding: 0 14px; border-radius: 8px; background: var(--text); color: var(--grund); font-weight: 500; text-decoration: none; }
.s-intro { padding: clamp(30px, 4.5vw, 56px) 0 clamp(20px, 3vw, 30px); max-width: 760px; }
.s-intro .s-label { font: 500 12px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .08em; text-transform: uppercase; color: var(--leise); }
.s-intro h1 { margin-top: 14px; font: 600 clamp(2.5rem, 1.6rem + 3.6vw, 4.5rem)/1 'Geist', system-ui, sans-serif; letter-spacing: -.022em; text-wrap: balance; }
.s-intro p { margin-top: 16px; font-size: 1.0625rem; line-height: 1.6; letter-spacing: -.006em; color: var(--leise); max-width: 52ch; }
.s-buehne { position: relative; isolation: isolate; padding: clamp(18px, 3vw, 34px); border: 1px solid var(--linie); border-radius: 20px; overflow: hidden; background: #0c0d0e; }
.s-ui { position: absolute; inset: 0; z-index: -1; width: 100%; height: 100%; opacity: .9; }
.plaene { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 18px); align-items: stretch; }
.plan { position: relative; display: flex; flex-direction: column; gap: 14px; padding: 22px 22px 20px; border: 1.5px solid var(--linie); border-radius: 16px;
  background: var(--glas); -webkit-backdrop-filter: blur(14px) saturate(1.2); backdrop-filter: blur(14px) saturate(1.2); }
.plan h2 { font: 600 1.125rem/1.2 'Geist', sans-serif; letter-spacing: -.012em; display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.plan h2 small { font: 500 11px/1 'Geist Mono', monospace; letter-spacing: .06em; text-transform: uppercase; color: var(--marke); padding: 5px 7px; border-radius: 6px; background: rgba(113, 112, 255, .14); }
.plan .betrag { font: 600 2.5rem/1 'Geist', sans-serif; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.plan .betrag span { font: 400 .875rem/1.3 'Geist', sans-serif; letter-spacing: 0; color: var(--leise); margin-left: 6px; }
.plan ul { list-style: none; padding: 0; display: grid; gap: 7px; font-size: .9375rem; line-height: 1.45; color: #c9ccd1; }
.plan li { display: flex; gap: 9px; }
.plan li::before { content: ''; flex: none; width: 10px; height: 6px; margin-top: 6px; border-left: 1.5px solid var(--leise); border-bottom: 1.5px solid var(--leise); rotate: -45deg; }
.plan .s-knopf { margin-top: auto; display: inline-flex; justify-content: center; align-items: center; height: 38px; border-radius: 9px; border: 1px solid var(--linie-stark); color: var(--text); text-decoration: none; font-weight: 500; font-size: .9375rem; transition: background-color 160ms var(--ui-saas), border-color 160ms var(--ui-saas); }
.plan .s-knopf:hover { background: rgba(247, 248, 248, .06); }
.plan.leuchtet .s-knopf { background: var(--marke); border-color: var(--marke); color: #fff; }
.plan.leuchtet .s-knopf:hover { background: #8382ff; }
.s-klein { font-size: .8125rem; color: var(--leise); }

/* Ring: Verlauf nur in der Rahmenlinie, Karteninhalt bleibt Glas */
.plan.leuchtet {
  --ring: conic-gradient(from var(--winkel), #34383b 0%, #34383b 48%, #5554e8 66%, #c9c8ff 80%, #ffffff 87%, #34383b 97%, #34383b 100%);
  border-color: transparent;
}
body[data-variante="lichtpunkt"] .plan.leuchtet { --ring: conic-gradient(from var(--winkel), #34383b 0%, #34383b 85%, #7170ff 89.5%, #ffffff 93%, #34383b 96.5%, #34383b 100%); }
/* Rückfall (auch per Schalter „Maske“): ::after mit Maske */
.plan.leuchtet::after {
  content: ''; position: absolute; inset: -1.5px; z-index: 1; border-radius: inherit; padding: 1.5px; pointer-events: none;
  background: var(--ring) border-box;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  animation: drehen var(--runde) linear infinite;
}
.ablage { display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap; margin-top: clamp(12px, 1.6vw, 18px); padding: 18px 22px; border: 1.5px dashed #3a3e43; border-radius: 14px; background: rgba(12, 13, 14, .72); color: #c9ccd1; font-size: .9375rem; transition: border-color 160ms var(--ui-saas); }
.ablage b { color: var(--text); font-weight: 500; }
.ablage .s-label { font: 500 11px/1 'Geist Mono', monospace; letter-spacing: .08em; text-transform: uppercase; color: var(--leise); }
.ablage:is(:hover, .ueber) { border-color: var(--marke); }
@supports (background-clip: border-area) {
  html[data-v="saas"]:not([data-technik="maske"]) .plan.leuchtet {
    background-image: var(--ring), linear-gradient(var(--glas), var(--glas));
    background-origin: border-box; background-clip: border-area, padding-box; background-color: transparent;
    animation: drehen var(--runde) linear infinite;
  }
  html[data-v="saas"]:not([data-technik="maske"]) .plan.leuchtet::after { display: none; }
  html[data-v="saas"]:not([data-technik="maske"]) .ablage {
    --ring: conic-gradient(from var(--winkel), #2c2f33 0%, #2c2f33 40%, #4f4ee0 70%, #c9c8ff 85%, #2c2f33 100%);
    border-color: transparent;
    background-image: linear-gradient(90deg, #4a4d53, #6d6cf0 50%, #4a4d53), linear-gradient(rgba(12, 13, 14, .72), rgba(12, 13, 14, .72));
    background-origin: border-box; background-clip: border-area, padding-box; background-color: transparent;
  }
  html[data-v="saas"]:not([data-technik="maske"]) .ablage:is(:hover, .ueber) {
    background-image: var(--ring), linear-gradient(rgba(12, 13, 14, .72), rgba(12, 13, 14, .72));
    animation: drehen 4000ms linear infinite;
  }
}
body[data-variante="hover"] .plan.leuchtet:not(:hover, :focus-within, .an), body[data-variante="hover"] .plan.leuchtet:not(:hover, :focus-within, .an)::after { animation-play-state: paused; }
.plan.ruht, .plan.ruht::after, [data-halt] .plan.leuchtet, [data-halt] .plan.leuchtet::after { animation-play-state: paused !important; }
.reduziert .plan.leuchtet, .reduziert .plan.leuchtet::after, .reduziert .ablage { animation: none !important; }
.s-hinweis { display: none; }
.ohne-ba .s-hinweis { display: block; }
@media (max-width: 900px) { .plaene { grid-template-columns: 1fr 1fr; } .plaene .leuchtet { grid-column: 1 / -1; order: -1; } .s-nav li:not(.behalten) { display: none; } }
@media (max-width: 620px) { .plaene { grid-template-columns: 1fr; } .s-buehne { padding: 14px; border-radius: 16px; } .ablage { padding: 16px; } }
.vorschau .s-kopf, .vorschau .s-intro p, .vorschau .ablage { display: none; }
.vorschau .s-intro { padding: 0 0 22px; }
.vorschau .s-intro h1 { font-size: 3.1rem; }

/* ===== Variante „button“ (Rezept kurs-coaching-lernweg) =====
   Lichtlauf um eine Pille, nur bei Hover, Fokus und während des Ladens. In Ruhe steht eine Lichtkante oben.
   Gleiche Technik wie die Karte: Füllung als padding-box, Verlauf als border-box, Glow als unscharfes ::before. */
html[data-v="button"] {
  --grund: #f4f6fa; --text: #141414; --leise: #555b69; --linie: rgba(20, 20, 20, .12); --linie-stark: rgba(20, 20, 20, .28);
  --b-tinte: #141414; --b-marke: #7491ff; --b-gelb: #f7c325; --b-erfolg: #10bf7a; --b-karte: #ffffff;
  --b-feder: cubic-bezier(0.34, 1.56, 0.64, 1);   /* token-federnd-verspielt, nur für den Druck */
  font-family: 'Onest', system-ui, sans-serif;
}
html[data-v="button"] .umschalter { background: rgba(20, 20, 20, .03); }
html[data-v="button"] .werte { color: var(--leise); }
html[data-v="button"] .umschalter button[aria-pressed="true"] { background: rgba(20, 20, 20, .08); }
html[data-v="button"] :focus-visible { outline: 2px solid var(--b-tinte); outline-offset: 3px; }
.k-kopf { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding-bottom: 18px; border-bottom: 1px solid var(--linie); font-size: 15px; }
.k-marke { display: inline-flex; align-items: center; gap: 10px; color: var(--text); text-decoration: none; font: 700 1.125rem/1 'Bricolage Grotesque', sans-serif; font-variation-settings: 'opsz' 36; letter-spacing: -.02em; }
.k-marke svg { width: 28px; height: 28px; flex: none; }
.k-nav { display: flex; gap: 24px; list-style: none; padding: 0; }
.k-nav a { color: var(--leise); text-decoration: none; transition: color 150ms var(--ui); }
.k-nav a:hover, .k-nav a[aria-current] { color: var(--text); }
.k-held { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, .95fr); gap: clamp(24px, 5vw, 72px); align-items: center; padding: clamp(28px, 4.5vw, 60px) 0 clamp(12px, 2vw, 20px); }
.k-label { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; font-size: .875rem; color: var(--leise); }
.k-badge { display: inline-flex; align-items: center; height: 26px; padding: 0 10px; border-radius: 999px; background: var(--b-gelb); color: var(--b-tinte); font-weight: 600; font-size: .8125rem; }
.k-held h1 { margin-top: 16px; font: 700 clamp(2.25rem, 1.4rem + 3.4vw, 4.25rem)/1.05 'Bricolage Grotesque', sans-serif; font-variation-settings: 'opsz' 96; letter-spacing: -.02em; text-wrap: balance; }
.k-lead { margin-top: 18px; max-width: 48ch; font-size: 1.0625rem; line-height: 1.6; color: #2f333d; text-wrap: pretty; }
.k-fakten { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 22px; padding: 0; list-style: none; font-size: .9375rem; color: var(--leise); }
.k-fakten b { font: 700 1.125rem/1 'Bricolage Grotesque', sans-serif; color: var(--text); margin-right: 4px; font-variant-numeric: tabular-nums; }
.k-knoepfe { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; margin-top: 28px; }
.k-zweit { display: inline-flex; align-items: center; height: 48px; padding: 0 22px; border: 1.5px solid var(--b-tinte); border-radius: 999px; color: var(--b-tinte); text-decoration: none; font-weight: 600; transition: background-color 150ms var(--ui); }
.k-zweit:hover { background: rgba(20, 20, 20, .06); }
.k-link { color: var(--text); font-weight: 500; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .25em; }

.k-karte { position: relative; isolation: isolate; display: grid; gap: 18px; padding: clamp(20px, 2.4vw, 28px); border: 1px solid var(--linie); border-radius: 22px; background: var(--b-karte); box-shadow: 0 24px 48px -32px rgba(20, 20, 20, .25); }
.k-karte h2 { font: 700 1.5rem/1.1 'Bricolage Grotesque', sans-serif; font-variation-settings: 'opsz' 48; letter-spacing: -.015em; }
.k-karte fieldset { display: grid; gap: 8px; border: 0; padding: 0; min-width: 0; }
.k-karte legend { margin-bottom: 8px; font-size: .8125rem; font-weight: 600; letter-spacing: .02em; color: var(--leise); }
.k-wahlen { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); gap: 8px; }
.k-wahl { display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 10px 14px; border: 1.5px solid var(--linie); border-radius: 14px; cursor: pointer; transition: border-color 150ms var(--ui), background-color 150ms var(--ui); }
.k-wahl:hover { border-color: var(--linie-stark); }
.k-wahl:has(:checked) { border-color: var(--b-tinte); background: #f7f8fb; }
.k-wahl input { flex: none; width: 18px; height: 18px; margin: 0; accent-color: var(--b-tinte); }
.k-wahl b { display: block; font-weight: 600; font-size: .9375rem; }
.k-wahl small { display: block; margin-top: 2px; font-size: .8125rem; color: var(--leise); }
.k-wahl small.frei::before { content: ''; display: inline-block; width: 7px; height: 7px; margin-right: 6px; border-radius: 50%; background: var(--b-erfolg); vertical-align: 1px; }
.k-klein { font-size: .8125rem; line-height: 1.5; color: var(--leise); }
.k-status { min-height: 1.5em; font-size: .9375rem; line-height: 1.5; color: var(--text); }
.k-status:empty { display: none; }
.k-status svg { width: 16px; height: 16px; margin-right: 6px; vertical-align: -3px; }
.k-status .k-zweit { height: 44px; margin-top: 10px; font-size: .9375rem; }

/* Der Button: Pille 52 px, Rahmen 1,5 px. Ruhe: Lichtkante oben (linear-gradient), Hover/Fokus/Laden: Lichtlauf */
.k-cta {
  --b-flaeche: var(--b-tinte);
  --ring: linear-gradient(180deg, #b9c5ff 0%, #5d6aa8 22%, #2b2f3d 48%, #2b2f3d 100%);
  --glanz: conic-gradient(from var(--winkel), transparent 0%, transparent 70%, var(--b-marke) 82%, var(--b-gelb) 90%, transparent 97%, transparent 100%);
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 10px; width: 100%; height: 52px; padding: 0 26px;
  border: 1.5px solid transparent; border-radius: 999px; color: #fff; cursor: pointer;
  background: linear-gradient(var(--b-flaeche), var(--b-flaeche)) padding-box, var(--ring) border-box;
  font: 600 1rem/1 'Onest', sans-serif; letter-spacing: .005em;
  transition: transform 150ms var(--ui);
}
.k-cta svg { width: 16px; height: 16px; flex: none; transition: translate 150ms var(--ui); }
.k-cta::before {
  content: ''; position: absolute; inset: -1.5px; z-index: -1; border-radius: inherit; pointer-events: none;
  background: var(--glanz); filter: blur(12px); opacity: 0; transition: opacity 400ms var(--ui);
}
.k-cta:is(:hover, :focus-visible, .an, [data-laedt]):not([aria-disabled="true"]) {
  --ring: conic-gradient(from var(--winkel), #2b2f3d 0%, #2b2f3d 68%, var(--b-marke) 80%, var(--b-gelb) 88%, #ffffff 92%, #2b2f3d 97%, #2b2f3d 100%);
  animation: drehen 3000ms linear infinite;
}
.k-cta:is(:hover, :focus-visible, .an, [data-laedt]):not([aria-disabled="true"])::before { opacity: .8; animation: drehen 3000ms linear infinite; }
.k-cta:is(:hover, .an):not([aria-disabled="true"], [data-laedt]) svg { translate: 3px 0; }
.k-cta:active:not([aria-disabled="true"]), .k-cta.druck { transform: scale(.985) translateY(1px); transition: transform 90ms var(--ui); }
.k-cta:not(:active, .druck) { transition: transform 450ms var(--b-feder); }
.k-cta.fokus { outline: 2px solid var(--b-tinte); outline-offset: 3px; }
/* Deaktiviert: aria-disabled statt disabled, damit der Knopf fokussierbar bleibt und seinen Grund nennen kann */
.k-cta[aria-disabled="true"] { --b-flaeche: #e4e7ee; --ring: linear-gradient(#cdd2dc, #cdd2dc); color: #464c59; cursor: not-allowed; }
.k-cta[aria-disabled="true"] svg { display: none; }
/* Laden: Text wechselt, Spinner statt Pfeil, Licht läuft weiter */
.k-spinner { display: none; width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(255, 255, 255, .3); border-top-color: #fff; animation: kreisen 800ms linear infinite; }
.k-cta[data-laedt] .k-spinner { display: block; }
.k-cta[data-laedt] svg { display: none; }
.k-cta[data-laedt] { cursor: progress; }
@keyframes kreisen { to { rotate: 360deg; } }
[data-halt] .k-cta, [data-halt] .k-cta::before { animation-play-state: paused !important; }
.reduziert .k-cta, .reduziert .k-cta::before { animation: none !important; }
.reduziert .k-cta:is(:hover, :focus-visible, .an, [data-laedt]):not([aria-disabled="true"]) { --ring: linear-gradient(180deg, #ffffff 0%, var(--b-gelb) 20%, var(--b-marke) 48%, #2b2f3d 100%); }
.reduziert .k-cta:is(:hover, :focus-visible, .an, [data-laedt]):not([aria-disabled="true"])::before { background: linear-gradient(180deg, var(--b-marke), transparent 60%); opacity: .45; }
.reduziert .k-spinner { animation-duration: 2400ms; }
@media (forced-colors: active) {
  .k-cta, .k-zweit, .k-wahl { border: 2px solid ButtonText; }
  .umschalter button, .leiste-buchung .feld, .leiste-buchung .pruefen { border: 1px solid ButtonText; }
  .k-cta[aria-disabled="true"] { border-color: GrayText; color: GrayText; }
  .k-cta::before { display: none; }
}
@media (max-width: 900px) { .k-held { grid-template-columns: 1fr; } .k-nav li:not(.behalten) { display: none; } }
@media (max-width: 520px) { .k-karte { border-radius: 18px; } }
@media (hover: none) { .k-wahl:hover { border-color: var(--linie); } }
.vorschau .k-kopf, .vorschau .k-lead, .vorschau .k-fakten, .vorschau .k-klein { display: none; }
.vorschau .k-held { padding-top: 6px; }
.vorschau .k-held h1 { font-size: 3.4rem; }

/* Gedachter Zeiger für die Vorführung */
.zeiger { position: fixed; left: 0; top: 0; z-index: 9; width: 18px; height: 18px; pointer-events: none; opacity: 0; transition: transform .9s var(--ui), opacity .3s var(--ui); }
.vorfuehrung .zeiger.an { opacity: 1; }

/* Vorschau: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .kopf, .vorschau .leiste-buchung, .vorschau .intro p.lauf, .vorschau .unten { display: none; }
.vorschau .seite { padding-top: 28px; }
.vorschau .intro { padding: 0 0 24px; grid-template-columns: 1fr; }
.vorschau h1 { font-size: 3.1rem; margin-top: 12px; }

/* Reduzierte Bewegung: stehender Verlaufsrahmen, Lichtkante oben */
.reduziert .hervor, .reduziert [data-variante] .hervor {
  animation: none;
  background: linear-gradient(var(--karte-hervor), var(--karte-hervor)) padding-box,
              linear-gradient(180deg, var(--licht) 0%, var(--schilf) 18%, var(--linie-stark) 46%, var(--linie-stark) 100%) border-box;
}
.reduziert .hervor::before { animation: none; background: linear-gradient(180deg, var(--schilf), transparent 30%); opacity: .25; filter: blur(14px); }
:root.reduziert * { transition-duration: .01ms !important; }

/* Telefon: Liebling zuerst, ohne Hover läuft die Hover-Variante nach Tippen eine Runde */
@media (max-width: 900px) {
  .intro { grid-template-columns: 1fr; align-items: start; }
  .karten { grid-template-columns: 1fr 1fr; }
  .karten .hervor { grid-column: 1 / -1; order: -1; }
  .nav li:not(.behalten) { display: none; }
}
@media (max-width: 620px) {
  .karten { grid-template-columns: 1fr; gap: 22px; }
  .leiste-buchung { grid-template-columns: 1fr 1fr; }
  .feld:nth-child(2) { border-right: 0; }
  .feld:nth-child(3) { grid-column: 1 / -1; border-right: 0; border-top: 1px solid var(--linie); }
  .feld:first-child { border-radius: 13px 0 0 0; }
  .leiste-buchung .pruefen { grid-column: 1 / -1; height: 46px; margin: 0 8px 8px; }
  .feld { border-bottom: 0; }
  .werkbank { grid-template-columns: 1fr; }
  .werte { justify-content: flex-start; text-align: left; }
  .unten { flex-direction: column; gap: 6px; }
  .marke small { display: none; }
}
@media (hover: none) {
  .karte:hover { border-color: var(--linie); }
  .hervor:hover { border-color: transparent; }
}
</style>
</head>
<body>
<div class="seite">
  <header class="kopf" data-welt="basis">
    <a class="marke" href="#start" aria-label="Remise Seelinde, Startseite">
      <svg viewBox="0 0 30 30" fill="none" aria-hidden="true">
        <path d="M4 14.5 15 5l11 9.5" stroke="#fef2e3" stroke-width="1.3" stroke-linejoin="round"/>
        <path d="M7 12.5V20h16v-7.5" stroke="#fef2e3" stroke-width="1.3"/>
        <path d="M12.5 20v-4.6a2.5 2.5 0 0 1 5 0V20" stroke="#fef2e3" stroke-width="1.3"/>
        <path d="M3 23.5c2 0 2-1 4-1s2 1 4 1 2-1 4-1 2 1 4 1 2-1 4-1 2 1 4 1" stroke="#a3b08f" stroke-width="1.3" stroke-linecap="round"/>
      </svg>
      <span><b>Remise Seelinde</b><small>Gästehaus am Heiligen See · Potsdam</small></span>
    </a>
    <ul class="nav label">
      <li><a href="#zimmer">Zimmer</a></li>
      <li><a href="#garten">Garten &amp; Küche</a></li>
      <li><a href="#umgebung">Umgebung</a></li>
      <li><a href="#angebote" aria-current="page">Angebote</a></li>
      <li class="sprache"><b>DE</b> / EN</li>
      <li class="behalten"><a class="buchen" href="#buchen">Buchen</a></li>
    </ul>
  </header>

  <section class="intro" id="angebote" data-welt="basis">
    <div>
      <p class="label">Angebote · Winter 2026/27</p>
      <h1>Drei Arten, am <em>Heiligen&nbsp;See</em> anzukommen.</h1>
    </div>
    <p class="lauf">Elf Zimmer, ein Garten, ein Steg. Wer direkt bei uns bucht, zahlt nie mehr als auf Portalen und bekommt den <strong>späten Check-out bis 13 Uhr</strong> dazu.</p>
  </section>


  <header class="s-kopf" data-welt="saas">
    <a class="s-marke" href="#start" aria-label="Schichtbrett, Startseite"><i aria-hidden="true"></i>Schichtbrett</a>
    <ul class="s-nav">
      <li><a href="#produkt">Produkt</a></li>
      <li><a href="#preise" aria-current="page">Preise</a></li>
      <li><a href="#changelog">Changelog</a></li>
      <li><a href="#doku">Doku</a></li>
      <li class="behalten"><a class="s-anmelden" href="#anmelden">Anmelden</a></li>
    </ul>
  </header>
  <section class="s-intro" id="preise" data-welt="saas">
    <p class="s-label">Preise · Schichtplanung</p>
    <h1>Ein Plan, der mit dem Betrieb wächst.</h1>
    <p>Dienstpläne, Tausch und Urlaub für Teams von 5 bis 200 Leuten. Monatlich kündbar, Daten in Frankfurt.</p>
  </section>

  <header class="k-kopf" data-welt="button" style="margin-bottom:18px">
    <a class="k-marke" href="#start" aria-label="Podcastwerkstatt Feldmann, Startseite">
      <svg viewBox="0 0 28 28" fill="none" aria-hidden="true"><rect x="9" y="3" width="10" height="15" rx="5" fill="#141414"/><path d="M5 13a9 9 0 0 0 18 0M14 22v4" stroke="#141414" stroke-width="2" stroke-linecap="round"/><circle cx="21.5" cy="5.5" r="3.5" fill="#f7c325"/></svg>
      Podcastwerkstatt Feldmann
    </a>
    <ul class="k-nav">
      <li><a href="#kurs" aria-current="page">Kurs</a></li>
      <li><a href="#lehrplan">Lehrplan</a></li>
      <li><a href="#jana">Über Jana</a></li>
      <li class="behalten"><a href="#fragen">Fragen</a></li>
    </ul>
  </header>

  <div class="werkbank">
    <div class="umschalter" role="group" aria-label="Variante" data-v-gruppe>
      <button type="button" data-v-wahl="basis" aria-pressed="true">Padding-Box</button>
      <button type="button" data-v-wahl="saas" aria-pressed="false">border-area</button>
      <button type="button" data-v-wahl="button" aria-pressed="false">Button</button>
    </div>
    <div class="umschalter" role="group" aria-label="Technik" data-t-gruppe hidden>
      <button type="button" data-t-wahl="border-area" aria-pressed="true">border-area</button>
      <button type="button" data-t-wahl="maske" aria-pressed="false">Rückfall: Maske</button>
    </div>
    <div class="umschalter" role="group" aria-label="Licht" data-umschalter>
      <button type="button" data-v="lichtlauf" aria-pressed="true">Lichtlauf</button>
      <button type="button" data-v="lichtpunkt" aria-pressed="false">Lichtpunkt</button>
      <button type="button" data-v="hover" aria-pressed="false">Bei Hover</button>
    </div>
    <p class="mono werte" data-werte aria-live="polite"></p>
  </div>

  <div class="karten" data-karten data-variante="lichtlauf" data-welt="basis">
    <article class="karte">
      <div class="bild" aria-hidden="true">
        <!-- Gewächshaus im Garten, abends beleuchtet -->
        <svg viewBox="0 0 320 188" preserveAspectRatio="xMidYMid slice">
          <rect width="320" height="188" fill="#574b41"/>
          <rect y="0" width="320" height="64" fill="#4d433b"/>
          <circle cx="262" cy="44" r="9" fill="#e9d2b0" opacity=".85"/>
          <path d="M0 132c18-22 30-38 52-38s30 18 40 32V188H0Z" fill="#3a3f34"/>
          <path d="M250 134c6-30 22-52 40-52s30 20 30 40v66h-70Z" fill="#343a30"/>
          <rect y="150" width="320" height="38" fill="#2e2a26"/>
          <g>
            <path d="M96 150V98l64-40 64 40v52Z" fill="#e5c79c"/>
            <path d="M96 150V98l64-40 64 40v52Z" fill="none" stroke="#2b2724" stroke-width="3" stroke-linejoin="round"/>
            <path d="M118 150V85M139 150V72M160 150V58M181 150V72M202 150V85M96 118h128M96 98h128" stroke="#2b2724" stroke-width="2"/>
            <path d="M132 150v-14h56v14" fill="#b8956c"/>
            <path d="M128 136h64" stroke="#5a4636" stroke-width="2.5" stroke-linecap="round"/>
            <circle cx="112" cy="140" r="9" fill="#6f7d5f"/><circle cx="208" cy="138" r="11" fill="#6f7d5f"/><circle cx="214" cy="128" r="7" fill="#83926f"/>
            <path d="M150 128c0-6 4-9 10-9s10 3 10 9" fill="none" stroke="#5a4636" stroke-width="2"/>
          </g>
          <path d="M84 150h152" stroke="#e5c79c" stroke-width="1" opacity=".35"/>
          <path d="M96 156h128l26 32H70Z" fill="#e5c79c" opacity=".1"/>
        </svg>
      </div>
      <div class="inhalt">
        <p class="label">01 · Für Frühaufsteher</p>
        <h2>Gartenfrühstück</h2>
        <p class="text">Zwei Nächte im Gartenzimmer, Frühstück unter Glas und Räder für eine Runde durch den Neuen Garten.</p>
        <ul class="fakten label"><li>24 m²</li><li>Doppelbett</li><li>Gartenblick</li></ul>
        <div class="fuss">
          <p class="preis"><small>pro Nacht ab</small>168 €</p>
          <a class="knopf" href="#gartenfruehstueck">Ansehen</a>
        </div>
      </div>
    </article>

    <article class="karte hervor" data-hervor>
      <span class="plakette"><i></i>Nur bei Direktbuchung</span>
      <div class="bild" aria-hidden="true">
        <!-- Steg im Abendlicht -->
        <svg viewBox="0 0 320 188" preserveAspectRatio="xMidYMid slice">
          <rect width="320" height="188" fill="#5d4f44"/>
          <rect y="70" width="320" height="42" fill="#76604d"/>
          <rect y="96" width="320" height="16" fill="#8e735a"/>
          <circle cx="214" cy="110" r="21" fill="#f0d7b2"/>
          <path d="M0 112c22-8 40-12 62-10 18 2 30-6 48-6 22 0 34 8 58 8s38-8 62-8 40 6 54 8 26-2 36-2v10H0Z" fill="#3a3430"/>
          <rect y="112" width="320" height="76" fill="#34302c"/>
          <g fill="#f0d7b2" stroke="none">
            <rect x="196" y="118" width="36" height="2.4" rx="1.2" opacity=".75"/>
            <rect x="200" y="125" width="28" height="2.2" rx="1.1" opacity=".55"/>
            <rect x="190" y="132" width="44" height="2" rx="1" opacity=".42"/>
            <rect x="203" y="140" width="22" height="2" rx="1" opacity=".32"/>
            <rect x="186" y="149" width="52" height="1.8" rx=".9" opacity=".24"/>
            <rect x="198" y="159" width="30" height="1.6" rx=".8" opacity=".16"/>
          </g>
          <path d="M20 188 104 128h22l-30 60Z" fill="#221f1c"/>
          <path d="M33 179h60M47 169h53M60 159h45M72 150h38M84 141h31M95 133h26" stroke="#3a3430" stroke-width="1.4"/>
          <path d="M106 128v12M124 128v10M86 145v16M44 175v13" stroke="#221f1c" stroke-width="3"/>
          <g stroke="#55604e" stroke-width="1.6" stroke-linecap="round" fill="none">
            <path d="M268 188c-2-20 0-36 4-52M276 188c0-16 3-30 8-42M284 188c1-14 0-26-3-38M292 188c2-18 6-30 12-40M300 188c0-12-2-22-6-30M308 188c1-16 4-26 9-34"/>
          </g>
          <g fill="#6c7861"><ellipse cx="272" cy="134" rx="2.2" ry="6"/><ellipse cx="304" cy="148" rx="2.2" ry="6"/></g>
        </svg>
      </div>
      <div class="inhalt">
        <p class="label">02 · Unser Liebling</p>
        <h2>Seezimmer mit Steg</h2>
        <p class="text">Das Eckzimmer im ersten Stock, Fenster nach drei Seiten. Morgens gehört der Steg Ihnen, abends bringen wir Tee hinunter.</p>
        <ul class="fakten label"><li>31 m²</li><li>Kingsize</li><li>Seeblick</li></ul>
        <div class="fuss">
          <p class="preis"><small>pro Nacht ab</small>238 €</p>
          <a class="knopf" href="#seezimmer">Anfragen <svg viewBox="0 0 12 12" fill="none" aria-hidden="true"><path d="M2 6h8M6.5 2.5 10 6l-3.5 3.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg></a>
        </div>
      </div>
    </article>

    <article class="karte">
      <div class="bild" aria-hidden="true">
        <!-- Bootshaus mit Sauna, Dampf über dem Dach -->
        <svg viewBox="0 0 320 188" preserveAspectRatio="xMidYMid slice">
          <rect width="320" height="188" fill="#4b4540"/>
          <rect y="74" width="320" height="40" fill="#5a4f46"/>
          <g fill="#2f332c">
            <path d="M18 116 38 52l20 64Z"/><path d="M44 116 60 66l16 50Z"/><path d="M250 116l22-72 22 72Z"/><path d="M280 116l18-54 18 54Z"/><path d="M226 116l14-40 14 40Z"/>
          </g>
          <rect y="114" width="320" height="74" fill="#33302c"/>
          <g fill="none" stroke="#e9d6bb" stroke-linecap="round" opacity=".5">
            <path d="M176 50c-6-8 6-12 0-20s6-12 0-20" stroke-width="3"/>
            <path d="M186 54c-5-7 5-10 0-17s5-10 0-17" stroke-width="2" opacity=".6"/>
          </g>
          <path d="M108 74h104l18 26H90Z" fill="#26231f"/>
          <rect x="172" y="52" width="10" height="22" fill="#26231f"/>
          <rect x="100" y="100" width="120" height="30" fill="#4a3d33"/>
          <path d="M112 100v30M124 100v30M136 100v30M184 100v30M196 100v30M208 100v30" stroke="#3d322a" stroke-width="2"/>
          <rect x="146" y="106" width="28" height="16" fill="#ecc896"/>
          <path d="M160 106v16" stroke="#4a3d33" stroke-width="2"/>
          <path d="M104 130v12M136 130v12M184 130v12M216 130v12" stroke="#26231f" stroke-width="3"/>
          <g fill="#ecc896"><rect x="148" y="146" width="24" height="2.2" rx="1.1" opacity=".5"/><rect x="152" y="153" width="16" height="2" rx="1" opacity=".32"/><rect x="146" y="160" width="28" height="1.8" rx=".9" opacity=".2"/></g>
          <path d="M0 150h60M240 160h80M30 172h70" stroke="#4b4540" stroke-width="1.4" stroke-linecap="round"/>
        </svg>
      </div>
      <div class="inhalt">
        <p class="label">03 · Für dunkle Monate</p>
        <h2>Winterruhe im Bootshaus</h2>
        <p class="text">Drei Nächte, Sauna im alten Bootshaus am Ufer und danach ein Abendessen am Kachelofen.</p>
        <ul class="fakten label"><li>27 m²</li><li>Doppelbett</li><li>Uferblick</li></ul>
        <div class="fuss">
          <p class="preis"><small>pro Nacht ab</small>198 €</p>
          <a class="knopf" href="#winterruhe">Ansehen</a>
        </div>
      </div>
    </article>
  </div>

  <form class="leiste-buchung" aria-label="Verfügbarkeit prüfen" onsubmit="return false" data-welt="basis">
    <button type="button" class="feld"><span class="label">Anreise</span><span>Fr, 11. Dezember</span></button>
    <button type="button" class="feld"><span class="label">Abreise</span><span>So, 13. Dezember</span></button>
    <button type="button" class="feld"><span class="label">Gäste</span><span>2 Erwachsene</span></button>
    <button type="submit" class="pruefen">Verfügbarkeit prüfen</button>
  </form>

  <div class="unten" data-welt="basis">
    <p class="label">Mindestaufenthalt am Wochenende: zwei Nächte</p>
    <p class="label">Preise pro Zimmer, inkl. Frühstück</p>
  </div>

  <div class="s-buehne" data-welt="saas">
    <svg class="s-ui" data-s-ui viewBox="0 0 1100 420" preserveAspectRatio="xMidYMid slice" aria-hidden="true"></svg>
    <div class="plaene">
      <article class="plan">
        <h2>Solo</h2>
        <p class="betrag">0 €<span>bis 5 Personen</span></p>
        <ul><li>Wochenplan und Vorlagen</li><li>Tausch per App</li><li>Export als PDF</li></ul>
        <a class="s-knopf" href="#solo">Kostenlos starten</a>
      </article>
      <article class="plan leuchtet" data-plan>
        <h2>Team <small>Beliebt</small></h2>
        <p class="betrag">4 €<span>pro Person und Monat</span></p>
        <ul><li>Urlaub und Krankmeldung im Plan</li><li>Zeiterfassung mit Pausenregel</li><li>Lohnexport für DATEV</li></ul>
        <a class="s-knopf" href="#team">14 Tage testen</a>
      </article>
      <article class="plan">
        <h2>Betrieb</h2>
        <p class="betrag">Anfrage<span>ab 50 Personen</span></p>
        <ul><li>Mehrere Standorte</li><li>Betriebsrat-Freigaben</li><li>SSO und Auftragsverarbeitung</li></ul>
        <a class="s-knopf" href="#betrieb">Gespräch vereinbaren</a>
      </article>
    </div>
    <div class="ablage" data-ablage>
      <p><b>Alten Dienstplan übernehmen:</b> Excel- oder CSV-Datei hierher ziehen</p>
      <p class="s-label">.xlsx · .csv · bis 10 MB</p>
    </div>
  </div>
  <p class="mono s-hinweis" data-welt="saas" style="margin-top:12px">Dein Browser kennt background-clip: border-area noch nicht (ab Chrome 150, Safari 18.2): Der Ring kommt per Maske, die gestrichelte Zone bleibt einfarbig.</p>

  <section class="k-held" id="kurs" data-welt="button" aria-labelledby="k-titel">
    <div>
      <p class="k-label"><span class="k-badge">Nächster Start 12. Januar</span>Online-Kurs · 6 Wochen · Fürth und überall</p>
      <h1 id="k-titel">In sechs Wochen zum eigenen Podcast.</h1>
      <p class="k-lead">Für Vereine, Praxen und kleine Betriebe, die ihre Geschichten selbst erzählen wollen. Jede Woche ein Modul, zwei Live-Termine am Abend. Am Ende ist Folge 1 online.</p>
      <ul class="k-fakten"><li><b>6</b>Module à 45 Minuten</li><li><b>2</b>Live-Termine pro Woche</li><li><b>412</b>Teilnehmende seit 2022</li></ul>
      <div class="k-knoepfe">
        <a class="k-zweit" href="#lehrplan">Lehrplan ansehen</a>
        <a class="k-link" href="#probe">Probelektion hören (12 min)</a>
      </div>
    </div>
    <form class="k-karte" aria-labelledby="k-anmeldung" data-k-form novalidate>
      <h2 id="k-anmeldung">Anmeldung</h2>
      <fieldset>
        <legend>Kursstart</legend>
        <div class="k-wahlen">
          <label class="k-wahl"><input type="radio" name="start" value="jan" checked><span><b>Mo, 12. Januar 2027</b><small class="frei">noch 4 Plätze</small></span></label>
          <label class="k-wahl"><input type="radio" name="start" value="maerz"><span><b>Mo, 8. März 2027</b><small>ausgebucht</small></span></label>
        </div>
      </fieldset>
      <fieldset>
        <legend>Zahlung</legend>
        <div class="k-wahlen">
          <label class="k-wahl"><input type="radio" name="zahlung" value="einmal" checked><span><b>Einmal 290 €</b><small>inkl. 19 % MwSt.</small></span></label>
          <label class="k-wahl"><input type="radio" name="zahlung" value="raten"><span><b>3 Raten à 99 €</b><small>monatlich</small></span></label>
        </div>
      </fieldset>
      <button type="submit" class="k-cta" data-k-cta aria-describedby="k-status"><span data-k-text>Platz sichern</span><span class="k-spinner" aria-hidden="true"></span><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M2 8h11M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
      <p class="k-status" id="k-status" role="status" data-k-status></p>
      <p class="k-klein">14 Tage Widerrufsrecht. Den Platz halten wir 30 Minuten frei, bezahlt wird erst im nächsten Schritt.</p>
    </form>
  </section>

</div>

<svg class="zeiger" data-zeiger viewBox="0 0 18 18" aria-hidden="true"><path d="M2 1.5 15.5 9.2l-6 1.3-2.9 5.6Z" fill="#fef2e3" stroke="#2b2724" stroke-width="1.2" stroke-linejoin="round"/></svg>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const karten = document.querySelector('[data-karten]');
  const hervor = document.querySelector('[data-hervor]');
  const knoepfe = [...document.querySelectorAll('[data-umschalter] button')];
  const werteEl = document.querySelector('[data-werte]');
  const zeiger = document.querySelector('[data-zeiger]');

  const WERTE = {
    lichtlauf: 'conic-gradient · from var(--winkel) · 6000 ms linear · Rahmen 1,5 px · Licht 52–97 % · Glow blur 16 px',
    lichtpunkt: 'Border-Beam · 4000 ms linear · Segment 86–96 % · Glow blur 10 px',
    hover: '6000 ms linear · läuft bei :hover / :focus-within · sonst steht das Licht'
  };
  let variante = 'lichtlauf';

  // ---- Varianten nach Regel 13: ?v=basis|saas (unbekannt oder leer: basis)
  const VARIANTEN = ['basis', 'saas', 'button'];
  const lGruppe = document.querySelector('[data-umschalter]');
  const plan = document.querySelector('[data-plan]'), ablage = document.querySelector('[data-ablage]');
  const kannBa = !!(window.CSS && CSS.supports('background-clip', 'border-area'));
  if (!kannBa) html.classList.add('ohne-ba');
  const vKnoepfe = [...document.querySelectorAll('[data-v-wahl]')], tKnoepfe = [...document.querySelectorAll('[data-t-wahl]')];
  const tGruppe = document.querySelector('[data-t-gruppe]');
  let welt = 'basis', technik = 'border-area';
  function setzeWelt(v, url = true) {
    welt = v; html.dataset.v = v;
    vKnoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.vWahl === v)));
    tGruppe.hidden = v !== 'saas';
    lGruppe.hidden = v === 'button';
    if (url) { const u = new URL(location.href); u.searchParams.set('v', v); history.replaceState(history.state, '', u); }
    setzeVariante(variante);
  }
  function setzeTechnik(t) {
    technik = t; html.dataset.technik = t;
    tKnoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.tWahl === t)));
    setzeVariante(variante);
  }
  vKnoepfe.forEach(b => b.addEventListener('click', () => { neustart(); setzeWelt(b.dataset.vWahl); }));
  tKnoepfe.forEach(b => b.addEventListener('click', () => { neustart(); setzeTechnik(b.dataset.tWahl); }));
  function werteSaas(v) {
    const echt = kannBa && technik === 'border-area';
    const dauer = v === 'lichtpunkt' ? '4000 ms' : '6000 ms';
    if (reduziert()) return (echt ? 'background-clip: border-area' : 'Maske') + ' · Ring steht · Karte Glas rgba(22,23,24,.58) + blur 14px';
    return (echt
      ? 'background-clip: border-area · Rahmen 1,5 px · '
      : (kannBa ? 'Rückfall gezeigt: ' : 'Rückfall: ') + 'mask-composite: exclude · ')
      + dauer + ' linear' + (v === 'hover' ? ' · läuft bei :hover / :focus-within' : '') + ' · Glas';
  }
  // Produktoberfläche hinter den Karten (Schichtplan), damit das Glas etwas zum Durchscheinen hat
  (function zeichneUi() {
    const svg = document.querySelector('[data-s-ui]'); if (!svg) return;
    const farben = ['#4f4ee0', '#2f8f6b', '#b07d2a', '#3a3e43', '#7170ff'];
    let z = 7, inhalt = '<rect width="1100" height="420" fill="#0c0d0e"/>';
    const tage = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
    tage.forEach((t, i) => { inhalt += `<text x="${190 + i * 128}" y="34" fill="#5d6168" font-family="Geist Mono, monospace" font-size="12">${t} ${9 + i}.11.</text><path d="M${180 + i * 128} 46V420" stroke="#1b1d1f"/>`; });
    for (let r = 0; r < 9; r++) {
      const y = 58 + r * 40;
      inhalt += `<path d="M0 ${y + 34}H1100" stroke="#16181a"/><rect x="24" y="${y + 10}" width="${70 + (r * 23) % 60}" height="9" rx="4" fill="#2a2d31"/>`;
      for (let d = 0; d < 7; d++) {
        z = (z * 37 + 11) % 97;
        if (z % 5 === 0) continue;
        const b = 60 + (z % 4) * 16, x = 186 + d * 128 + (z % 3) * 12;
        inhalt += `<rect x="${x}" y="${y + 6}" width="${b}" height="22" rx="6" fill="${farben[z % farben.length]}" opacity=".55"/>`;
      }
    }
    svg.innerHTML = inhalt;
  })();
  // Ablage: Ziehen über die Zone zeigt den laufenden Ring
  ['dragenter', 'dragover'].forEach(t => ablage.addEventListener(t, e => { e.preventDefault(); ablage.classList.add('ueber'); }));
  ['dragleave', 'drop'].forEach(t => ablage.addEventListener(t, e => { e.preventDefault(); ablage.classList.remove('ueber'); }));

  // Ring und Glow-Duplikat laufen getrennt; beim Wechsel gemeinsam auf null, damit sie deckungsgleich bleiben
  function gleichtakt() {
    if (!hervor.getAnimations) return;
    [hervor, document.querySelector('[data-plan]')].forEach(el => el && el.getAnimations({ subtree: true }).forEach(a => { a.currentTime = 0; }));
  }
  function setzeVariante(v) {
    variante = v;
    karten.dataset.variante = v; document.body.dataset.variante = v;
    knoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.v === v)));
    werteEl.textContent = welt === 'button' ? (reduziert()
      ? 'Reduziert · kein Lauf · Hover/Fokus: stehende Lichtkante Weiß → Gelb → Blau · Glow .45'
      : 'Pille 52 px · Rahmen 1,5 px · Ruhe: Lichtkante oben · Hover, Fokus, Laden: conic-gradient 3000 ms linear · Glow blur 12 px / .8 · Druck scale .985')
      : welt === 'saas' ? werteSaas(v) : reduziert() ? 'Reduziert · stehender Verlauf 180deg · Lichtkante oben · Rahmen 1,5 px' : WERTE[v];
    gleichtakt();
  }
  knoepfe.forEach(b => b.addEventListener('click', () => { neustart(); setzeVariante(b.dataset.v); }));

  // Nur rechnen, solange die Karte sichtbar ist
  if ('IntersectionObserver' in window) {
    const io = new IntersectionObserver(es => es.forEach(e => e.target.classList.toggle('ruht', !e.isIntersecting)));
    io.observe(hervor); io.observe(plan);
  }

  // Touch: kein Hover, also läuft die Hover-Variante nach dem Antippen eine Umdrehung
  let tippUhr = null;
  [hervor, plan].forEach(el => el.addEventListener('pointerdown', e => {
    if (e.pointerType === 'mouse' || variante !== 'hover') return;
    el.classList.add('an');
    clearTimeout(tippUhr);
    tippUhr = setTimeout(() => el.classList.remove('an'), 6000);
  }));
  document.querySelectorAll('a[href^="#"], .leiste-buchung button').forEach(a => a.addEventListener('click', e => e.preventDefault()));

  // ---- Variante button: Anmeldeformular mit einem Lichtlauf-Button (Zustände: Ruhe, Hover/Fokus, Druck, deaktiviert, Laden)
  const kForm = document.querySelector('[data-k-form]'), kCta = document.querySelector('[data-k-cta]');
  const kText = kCta.querySelector('[data-k-text]'), kStatus = document.querySelector('[data-k-status]');
  const HAKEN = '<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><circle cx="8" cy="8" r="8" fill="#10bf7a"/><path d="m4.6 8.2 2.2 2.2 4.6-4.8" stroke="#141414" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>';
  let kUhr = null;
  function kZustand() {
    const maerz = kForm.elements.start.value === 'maerz';
    clearTimeout(kUhr); delete kCta.dataset.laedt;
    if (maerz) {
      kCta.setAttribute('aria-disabled', 'true'); kText.textContent = 'Ausgebucht';
      kStatus.innerHTML = 'Der März-Kurs ist voll. Wir schreiben Ihnen, sobald ein Platz frei wird.<br><a class="k-zweit" href="#warteliste">Auf die Warteliste</a>';
    } else {
      kCta.removeAttribute('aria-disabled'); kText.textContent = 'Platz sichern'; kStatus.textContent = '';
    }
  }
  function kAbsenden() {
    if (kCta.getAttribute('aria-disabled') === 'true' || kCta.dataset.laedt !== undefined) return;
    kCta.dataset.laedt = ''; kText.textContent = 'Wird reserviert …'; kStatus.textContent = '';
    kUhr = setTimeout(() => {
      delete kCta.dataset.laedt; kText.textContent = 'Platz sichern';
      kStatus.innerHTML = HAKEN + '<b>Reserviert:</b> Ihr Platz am 12. Januar ist 30 Minuten für Sie frei.';
    }, reduziert() ? 900 : 1800);
  }
  kForm.addEventListener('change', kZustand);
  kForm.addEventListener('submit', e => { e.preventDefault(); kAbsenden(); });
  kStatus.addEventListener('click', e => { if (e.target.closest('a')) e.preventDefault(); });
  // Touch: kein Hover, also läuft das Licht nach dem Antippen eine Runde (3000 ms)
  let kTipp = null;
  kCta.addEventListener('pointerdown', e => {
    if (e.pointerType === 'mouse') return;
    kCta.classList.add('an'); clearTimeout(kTipp); kTipp = setTimeout(() => kCta.classList.remove('an'), 3000);
  });

  // Vorführung: Lichtlauf, Lichtpunkt, dann fährt ein gedachter Zeiger auf die Karte
  let uhren = [];
  const spaeter = (fn, ms) => uhren.push(setTimeout(fn, ms));
  function zeigerNach(x, y) { zeiger.style.transform = `translate(${x}px, ${y}px)`; }
  function mitte(el, fx = .62, fy = .58) { const r = el.getBoundingClientRect(); return [r.left + r.width * fx, r.top + r.height * fy]; }

  // Vorführung border-area: Lichtpunkt läuft, Zeiger fährt über die gestrichelte Ablage, dann Rückfall (Maske) zum Vergleich
  function rundeSaas() {
    setzeTechnik('border-area'); setzeVariante('lichtlauf');
    spaeter(() => setzeVariante('lichtpunkt'), 5000);
    spaeter(() => {
      zeiger.style.transition = 'none'; zeigerNach(innerWidth * .86, innerHeight * .98); zeiger.getBoundingClientRect(); zeiger.style.transition = '';
      zeiger.classList.add('an');
    }, 8500);
    spaeter(() => { const [x, y] = mitte(ablage, .5, .55); zeigerNach(x, y); }, 9000);
    spaeter(() => ablage.classList.add('ueber'), 9800);
    spaeter(() => { ablage.classList.remove('ueber'); zeigerNach(innerWidth * .9, innerHeight * .98); }, 14000);
    spaeter(() => { zeiger.classList.remove('an'); setzeTechnik('maske'); }, 14700);
    spaeter(() => setzeTechnik('border-area'), 19500);
    spaeter(rundeSaas, 20000);
  }
  // Vorführung button: Zeiger fährt auf den Button (Licht läuft), geht wieder, Tastaturfokus (Licht + Ring), Klick (Laden, Erfolg)
  function rundeButton() {
    kForm.elements.start.value = 'jan'; kZustand();
    zeiger.style.transition = 'none'; zeigerNach(innerWidth * .9, innerHeight * .98); zeiger.getBoundingClientRect(); zeiger.style.transition = '';
    spaeter(() => zeiger.classList.add('an'), 300);
    spaeter(() => { const [x, y] = mitte(kCta, .6, .55); zeigerNach(x, y); }, 500);
    spaeter(() => kCta.classList.add('an'), 1300);
    spaeter(() => { kCta.classList.remove('an'); zeigerNach(innerWidth * .9, innerHeight * .98); }, 5200);
    spaeter(() => { zeiger.classList.remove('an'); kCta.classList.add('an', 'fokus'); }, 5900);
    spaeter(() => kCta.classList.remove('an', 'fokus'), 9200);
    spaeter(() => { zeiger.classList.add('an'); const [x, y] = mitte(kCta, .45, .6); zeigerNach(x, y); }, 9600);
    spaeter(() => kCta.classList.add('an', 'druck'), 10500);
    spaeter(() => { kCta.classList.remove('druck'); kAbsenden(); }, 10650);
    spaeter(() => { kCta.classList.remove('an'); zeigerNach(innerWidth * .9, innerHeight * .98); }, 11200);
    spaeter(() => zeiger.classList.remove('an'), 11900);
    spaeter(() => kZustand(), 15500);
    spaeter(rundeButton, 16000);
  }
  function runde() {
    if (welt === 'button') return rundeButton();
    if (welt === 'saas') return rundeSaas();
    setzeVariante('lichtlauf');
    spaeter(() => setzeVariante('lichtpunkt'), 6500);
    spaeter(() => {
      setzeVariante('hover');
      zeiger.style.transition = 'none';
      zeigerNach(innerWidth * .86, innerHeight * .96);
      zeiger.getBoundingClientRect();
      zeiger.style.transition = '';
      zeiger.classList.add('an');
    }, 12500);
    spaeter(() => { const [x, y] = mitte(hervor); zeigerNach(x, y); }, 13900);
    spaeter(() => hervor.classList.add('an'), 14700);
    spaeter(() => { hervor.classList.remove('an'); zeigerNach(innerWidth * .9, innerHeight * .98); }, 19700);
    spaeter(() => zeiger.classList.remove('an'), 20400);
    spaeter(runde, 21000);
  }
  function pause() { uhren.forEach(clearTimeout); uhren = []; document.body.dataset.halt = ''; }
  function weiter() { delete document.body.dataset.halt; if (html.classList.contains('vorfuehrung')) runde(); }
  function neustart() {
    pause(); delete document.body.dataset.halt;
    html.classList.remove('vorfuehrung');
    zeiger.classList.remove('an'); hervor.classList.remove('an'); plan.classList.remove('an'); ablage.classList.remove('ueber');
    kCta.classList.remove('an', 'fokus', 'druck'); kZustand();
    setzeVariante(variante);
  }
  function vorfuehren() {
    neustart();
    html.classList.add('vorfuehrung');
    runde();
  }
  setzeTechnik('border-area');
  const ausUrl = new URLSearchParams(location.search).get('v');
  setzeWelt(VARIANTEN.includes(ausUrl) ? ausUrl : VARIANTEN[0], false);
  // Schalter „reduziert“ der Detailseite kann später kommen: Werte-Anzeige nachziehen
  let warReduziert = reduziert();
  new MutationObserver(() => { if (reduziert() !== warReduziert) { warReduziert = reduziert(); setzeVariante(variante); } }).observe(html, { attributes: true, attributeFilter: ['class'] });

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