Vollbild-Overlay-Menü mit Riesentypo und Bildvorschau
Ein Wort öffnet eine dunkle Bühne: Riesige Links steigen aus ihren Masken, und jeder Hover zeigt sein Bild, als kippendes Cursor-Thumbnail, als vollflächiger Wipe oder als Daumen in der Zeile.
- Ein Textknopf „Menü“ rechts oben öffnet eine Ebene über den ganzen Viewport. Der Knopf bleibt sichtbar und wird zu „Schließen“.
- Die Ebene zeigt drei bis sechs Hauptlinks in sehr großer Schrift (etwa 8–14vw), oft nummeriert und mit hochgestellten Zählern. Daneben steht eine Spalte mit Kontakt, Adresse, Newsletter oder Social-Links.
- Die Links steigen zeilenweise aus einer Maske auf (overflow: hidden, translateY 100 % → 0, gestaffelt).
- Beim Hover erscheint ein Bild zum Link: als Thumbnail, das der Maus verzögert folgt und je nach Tempo kippt und aufhellt, als vollflächiger Hintergrund oder als kleines Bild in der Zeile.
- Die übrigen Links treten zurück, der gezeigte steht im Fokus.
- Geschlossen wird über den Knopf, mit Escape oder per Klick auf einen Link, meist mit Seitenübergang.
Die Navigation wird selbst zur Bühne und zum Markenmoment. Große Typo und Bildvorschau wecken für jeden Bereich eine Erwartung, bevor man klickt. Geschlossen ist die Navigation nur ein Wort, der Hero bleibt frei.
Wann einsetzen
Portfolios, Studios und Marken mit wenigen Hauptbereichen (bis etwa sieben) und starkem Bildmaterial. Passt zu Kulturinstitutionen, Mode und Architektur.
Wann nicht
Shops und Produktseiten mit tiefer Informationsarchitektur. Seiten, auf denen Nutzer oft zwischen vielen Unterseiten wechseln: Ein verstecktes Menü kostet jedes Mal einen Klick.
Varianten
- Cursor-Thumbnail: Das Bild folgt der Maus per Lerp, kippt und hellt auf, je schneller die Maus ist (Codrops-Technik)
- Hintergrund: Das Bild füllt die ganze Fläche und wechselt per Crossfade oder Clip-Wipe
- Daumenleiste: kleine Bilder direkt neben den Links (Lando Norris)
- Menü mit Newsletter-Feld und Kontakt-CTA (Lusion)
- Nummerierte Einträge mit hochgestellter Anzahl (basement.studio: Showcase 26, Blog 29)
Umsetzung
Overlay als <nav> in einem Container mit position: fixed; inset: 0, Zustand über aria-expanded am Knopf. Jede Zeile bekommt overflow: hidden (oder clip-path: inset(0)) und einen inneren Span, der von yPercent 100 auf 0 fährt. Braucht die Maske unten Luft für Unterlängen, muss der Startwert höher liegen (in der Demo 120). Cursor-Variante: ein Reveal-Element je Link mit pointer-events: none. Position, Rotation und filter: brightness() in requestAnimationFrame per Lerp (Faktor 0,08) nachführen. Rotation und Helligkeit aus dem horizontalen Mausweg seit dem letzten Frame ableiten. Für das Aufdecken von der Seite laufen Innenwrapper und Bild gegenläufig von ±100 % auf 0. Bilder vorladen, sonst flackert der erste Hover. Laufende Tweens beim schnellen Wechsel abbrechen (overwrite bzw. killTweensOf). Die Seite dahinter sperren (overflow: hidden am html, Lenis stoppen). Fallstrick: Geschlossen darf das Overlay nicht im Tab-Fluss liegen (inert oder visibility: hidden). Seitenübergang: In der Demo wechselt der Inhalt, solange das Overlay deckt, danach schließt es. Bei echten Seitenwechseln übernimmt das ein Cross-Document-View-Transition (@view-transition { navigation: auto; }) oder ein Router mit Übergang.
Robust umsetzen
Telefon. Ohne Hover wird die Bildvorschau zum festen Daumenbild je Eintrag oder entfällt. Typo etwa 12–16vw, Kontaktblock unten in Daumenreichweite.
Ohne Bewegung. Overlay nur einblenden (opacity 150–200 ms), keine Zeilen-Slides, kein Cursor-Folgen. Das Bild steht fest und wechselt per Crossfade oder gar nicht.
Barrierefrei. Echter <button> mit aria-expanded, aria-controls und Textlabel. Im offenen Menü den Rest der Seite inert setzen (oder <dialog> nutzen), damit der Fokus im Menü bleibt. Beim Öffnen per Tastatur Fokus auf den ersten Link. Escape schließt, der Fokus kehrt auf den Knopf zurück. Vorschaubilder sind dekorativ (alt="" bzw. aria-hidden). Zähler wie „26“ für Screenreader mit verstecktem Text ergänzen („Projekte“).
Code
<!DOCTYPE html>
<!--
Vollbild-Overlay-Menü mit Riesentypo und Bildvorschau
Fundus · Navigation · https://cecodesign.de/lab/fundus/navigation/vollbild-overlay-menue-bildvorschau/
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>Vollbild-Overlay-Menü mit Riesentypo und Bildvorschau · 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: 'Instrument Sans'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/instrument-sans:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 400 700; font-display: swap; }
@font-face { font-family: 'Instrument Serif'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/instrument-serif@latest/latin-400-italic.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'Geist Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist-mono:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }
:root {
--papier: #ebe6dc; --tinte: #161513; --leise: rgba(22, 21, 19, .66); --linie: rgba(22, 21, 19, .16);
--nacht: #121110; --hell: #f2eee6; --hell-leise: rgba(242, 238, 230, .56); --hell-linie: rgba(242, 238, 230, .15);
--messing: #e3bf78; --messing-dunkel: #7f5c1d;
--sine: cubic-bezier(0.61, 1, 0.88, 1); /* sine.out: Bild-Reveal, Abdunkeln, UI (200 ms) */
--expo: cubic-bezier(0.16, 1, 0.3, 1); /* expo.out: Zeilen, Daumen, Knopf */
--rand: clamp(16px, 3.2vw, 44px);
--gross: clamp(46px, min(9.4vw, 13.6vh), 148px);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--papier); color: var(--tinte); font-family: 'Instrument Sans', system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
body { min-height: 100svh; overflow-x: hidden; }
html.gesperrt, html.gesperrt body { overflow: hidden; }
a { color: inherit; text-decoration: none; }
button, input { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
img { display: block; }
.mono { font: 500 11px/1.35 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; }
em { font-family: 'Instrument Serif', Georgia, serif; font-style: italic; font-weight: 400; letter-spacing: -.01em; }
:focus-visible { outline: 2px solid var(--messing); outline-offset: 4px; border-radius: 2px; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* ---------- Seite unter dem Menü ---------- */
.kopf { position: fixed; inset: 0 0 auto; z-index: 10; height: 84px; padding: 0 var(--rand); display: flex; align-items: center; gap: 24px; }
.marke { font-size: 19px; font-weight: 600; letter-spacing: -.035em; display: flex; align-items: baseline; gap: .26em; white-space: nowrap; }
.marke em { font-size: 1.16em; color: var(--messing-dunkel); }
.marke small { font: 500 10px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--leise); margin-left: .9em; }
.anfrage { margin-left: auto; margin-right: 128px; color: var(--leise); display: inline-flex; align-items: center; gap: 8px; transition: color .2s var(--sine); }
.anfrage::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #5fae6e; }
.anfrage:hover { color: var(--tinte); }
.seite { min-height: 100svh; padding: 112px var(--rand) 116px; display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); grid-template-rows: 1fr auto; column-gap: clamp(24px, 5vw, 80px); row-gap: 28px; }
.text { align-self: end; display: grid; gap: clamp(18px, 2.6vh, 28px); padding-bottom: 6px; }
.kicker { color: var(--leise); }
h1 { font-size: clamp(42px, 6.4vw, 108px); font-weight: 500; line-height: .95; letter-spacing: -.05em; max-width: 12ch; text-wrap: balance; }
h1 em { color: var(--messing-dunkel); }
.intro { font-size: clamp(15px, 1.15vw, 17px); line-height: 1.55; color: var(--leise); max-width: 36ch; }
.titelbild { align-self: end; display: grid; gap: 10px; }
.titelbild img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 4px; background: #d9d3c6; }
.titelbild figcaption { display: flex; justify-content: space-between; gap: 12px; color: var(--leise); }
.leiste-unten { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 20px; padding-top: 16px; border-top: 1px solid var(--linie); color: var(--leise); }
/* ---------- Menüknopf (bleibt über dem Overlay) ---------- */
.knopf { position: fixed; top: 20px; right: calc(var(--rand) - 8px); z-index: 40; height: 44px; padding: 0 8px; display: flex; align-items: center; gap: 12px; color: var(--tinte); transition: color .2s var(--sine) .5s; }
.knopf.offen { color: var(--hell); transition-delay: .12s; }
.knopf kbd { font: inherit; font-size: 9px; padding: 3px 5px 2px; border: 1px solid var(--hell-linie); border-radius: 3px; color: var(--hell-leise); opacity: 0; transition: opacity .2s var(--sine); }
.knopf.offen kbd { opacity: 1; transition-delay: .35s; }
.knopf-text { position: relative; display: block; height: 1.35em; overflow: hidden; text-align: right; }
.knopf-text span { display: block; transition: translate .6s var(--expo); }
.knopf.offen .knopf-text span { translate: 0 -100%; }
.knopf-icon { position: relative; width: 24px; height: 24px; }
.knopf-icon i { position: absolute; left: 1px; right: 1px; top: 50%; height: 1.5px; background: currentColor; transition: translate .6s var(--expo), rotate .6s var(--expo); }
.knopf-icon i:first-child { translate: 0 -4px; }
.knopf-icon i:last-child { translate: 0 3px; }
.knopf.offen .knopf-icon i:first-child { translate: 0 0; rotate: 45deg; }
.knopf.offen .knopf-icon i:last-child { translate: 0 0; rotate: -45deg; }
/* ---------- Overlay ---------- */
.menue { position: fixed; inset: 0; z-index: 30; visibility: hidden; }
.grund { position: absolute; inset: 0; background: var(--nacht); clip-path: inset(0% 0% 100% 0%); overflow: hidden; }
/* Variante Hintergrund: Bild füllt die Fläche, Clip-Wipe von unten */
.buehne { position: absolute; inset: 0; display: none; }
.menue[data-variante='hintergrund'] .buehne { display: block; }
.buehne-bilder { position: absolute; inset: 0; isolation: isolate; overflow: hidden; }
.buehne-bilder img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; clip-path: inset(100% 0% 0% 0%); will-change: clip-path, transform; }
.buehne-bilder img { filter: saturate(.7); }
.schleier { position: absolute; inset: 0; background: linear-gradient(90deg, rgba(18, 17, 16, .9) 0%, rgba(18, 17, 16, .76) 50%, rgba(18, 17, 16, .88) 100%); }
.inhalt { position: absolute; inset: 0; color: var(--hell); display: grid; grid-template-columns: minmax(0, 1fr) clamp(200px, 22vw, 300px); grid-template-rows: 84px minmax(0, 1fr) 76px; column-gap: clamp(20px, 3.6vw, 64px); padding: 0 var(--rand); overflow-x: hidden; overflow-y: auto; }
.zeile-oben { grid-column: 1 / -1; display: flex; align-items: center; gap: 24px; }
.zeile-oben .marke em { color: var(--messing); }
.zeile-oben .marke small { color: var(--hell-leise); }
.liste { grid-column: 1; grid-row: 2; align-self: center; list-style: none; position: relative; isolation: isolate; }
.eintrag a { position: relative; z-index: 1; display: flex; width: fit-content; max-width: 100%; overflow: hidden; padding: .02em .04em .16em 0; margin-bottom: -.14em; transition: opacity .2s var(--sine); }
.zeile { display: flex; align-items: flex-start; font-size: var(--gross); font-weight: 500; line-height: .96; letter-spacing: -.05em; white-space: nowrap; will-change: transform; }
.nr { flex: none; width: 46px; padding-top: 1.05em; font: 500 11px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; color: var(--hell-leise); }
.wort { display: block; }
.eintrag sup { font: 500 11px/1 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; color: var(--messing); margin: .9em 0 0 .5em; }
.liste.fokus .eintrag a { opacity: .26; }
.liste.fokus .eintrag.an a, .eintrag a:focus-visible { opacity: 1; }
.eintrag a[aria-current='page'] .nr { color: var(--messing); }
/* Variante Cursor: ein Bild je Eintrag, folgt der Maus (Lerp), kippt nach Tempo */
.reveal { position: absolute; left: 0; top: 0; z-index: 0; width: clamp(170px, 17vw, 260px); aspect-ratio: 4 / 5; pointer-events: none; opacity: 0; will-change: transform, opacity; }
.reveal-innen { width: 100%; height: 100%; overflow: hidden; }
.reveal-bild { width: 100%; height: 100%; object-fit: cover; will-change: transform, filter; }
.menue:not([data-variante='cursor']) .reveal { display: none; }
.menue[data-variante='cursor'] .eintrag a { mix-blend-mode: difference; }
/* Variante Leiste: Daumenbild in der Zeile, das gezeigte wird breit */
.daumen { position: relative; flex: none; display: block; width: 0; height: .7em; margin-top: .15em; overflow: hidden; border-radius: .05em; transition: width .8s var(--expo), margin .8s var(--expo); }
.daumen img { position: absolute; top: 0; left: 50%; height: 100%; width: 1.3em; max-width: none; translate: -50% 0; object-fit: cover; }
.menue[data-variante='leiste'] .daumen { width: .5em; margin-right: .14em; }
.menue[data-variante='leiste'] .eintrag.an .daumen { width: 1.3em; }
/* Nebenspalte */
.neben { grid-column: 2; grid-row: 2; align-self: end; display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; padding-bottom: 6px; }
.neben .mono { color: var(--hell-leise); margin-bottom: 7px; }
.neben p, .neben a { font-size: 14px; line-height: 1.5; }
.neben a { display: block; width: fit-content; padding-block: 2px; margin-block: -2px; transition: color .2s var(--sine); } /* Zielhöhe 25 px, Satz unverändert */
.neben a:hover { color: var(--messing); }
.im-bild { padding-bottom: 20px; border-bottom: 1px solid var(--hell-linie); }
.im-bild p:last-child { font-size: 17px; letter-spacing: -.01em; min-height: 1.5em; }
.brief .feld { display: flex; border-bottom: 1px solid var(--hell-linie); }
.brief input { flex: 1; width: 0; min-width: 0; background: none; border: 0; padding: 6px 0 8px; font-size: 14px; outline-offset: 2px; }
.brief input::placeholder { color: var(--hell-leise); }
.brief button { color: var(--messing); padding: 0 0 2px 12px; }
.sozial { display: flex; gap: 16px; flex-wrap: wrap; }
.sozial a { font-size: 11px; }
@media (max-width: 1100px) { .fuss span { display: none; } }
.fuss { grid-column: 1 / -1; grid-row: 3; display: flex; justify-content: flex-end; align-items: center; gap: 18px; color: var(--hell-leise); }
/* ---------- Pult: Varianten und Werte ---------- */
.pult { position: fixed; left: var(--rand); bottom: 18px; z-index: 50; max-width: min(520px, calc(100% - 2 * var(--rand))); padding: 9px 12px 10px; border-radius: 10px; background: rgba(22, 21, 19, .82); color: var(--hell); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); display: grid; gap: 8px; box-shadow: 0 10px 30px -14px rgba(0, 0, 0, .5); }
.varianten { display: flex; gap: 4px; flex-wrap: wrap; }
.varianten button { color: var(--hell-leise); border: 1px solid var(--hell-linie); border-radius: 999px; height: 26px; padding: 0 10px; transition: color .2s var(--sine), background-color .2s var(--sine), border-color .2s var(--sine); }
.varianten button:hover { color: var(--hell); border-color: rgba(242, 238, 230, .34); }
.varianten button[aria-pressed='true'] { background: var(--hell); color: var(--tinte); border-color: var(--hell); }
.werte { display: flex; flex-wrap: wrap; gap: 2px 14px; color: var(--hell-leise); font-size: 10px; }
.werte b { color: var(--hell); font-weight: 500; }
.touch-hinweis { display: none; }
/* Vorführung: gezeichneter Zeiger */
.zeiger { position: fixed; left: 0; top: 0; z-index: 60; width: 20px; height: 20px; pointer-events: none; display: none; }
.zeiger path { transition: scale .15s var(--sine); transform-origin: 3px 2px; }
.zeiger.klick path { scale: .74; }
.vorfuehrung .zeiger { display: block; }
.vorschau body { overflow: hidden; }
.vorschau .werte { display: none; }
/* Touch: kein Hover, Daumenbild fest in jeder Zeile */
@media (hover: none) {
.menue .buehne, .menue .reveal { display: none !important; }
.menue[data-variante] .daumen { width: .5em; margin-right: .14em; }
.menue[data-variante] .eintrag a { mix-blend-mode: normal; }
.im-bild, .knopf kbd, .varianten { display: none; }
.touch-hinweis { display: block; }
}
/* Reduzierte Bewegung: Overlay nur einblenden, kein Folgen, kein Kippen */
:root.reduziert .knopf, :root.reduziert .knopf-text span, :root.reduziert .knopf-icon i, :root.reduziert .daumen, :root.reduziert .eintrag a { transition: none; }
@media (max-width: 860px) {
.seite { grid-template-columns: 1fr; padding-bottom: 120px; }
.titelbild img { aspect-ratio: 16 / 10; }
.leiste-unten { display: none; }
.inhalt { grid-template-columns: 1fr; grid-template-rows: 84px minmax(0, 1fr) auto; }
.liste { grid-row: 2; align-self: center; margin-block: 24px; }
.neben { grid-column: 1; grid-row: 3; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; margin-top: 36px; padding-bottom: 116px; align-self: end; }
.im-bild, .brief, .sozial { grid-column: 1 / -1; }
.fuss { display: none; }
}
@media (max-width: 600px) {
:root { --gross: clamp(40px, 14vw, 72px); }
.kopf { height: 72px; }
.knopf { top: 14px; }
.marke small, .anfrage { display: none; }
.seite { padding-top: 92px; }
.inhalt { grid-template-rows: 72px minmax(0, 1fr) auto; }
.nr { width: 30px; padding-top: .9em; font-size: 10px; }
.eintrag sup { font-size: 10px; margin-left: .35em; }
.brief { display: none; }
}
@media (forced-colors: active) {
button, [role=button], [role=tab], [role=switch] { border: 1px solid ButtonText !important; }
}
</style>
</head>
<body>
<header class="kopf" data-kopf>
<a class="marke" href="#start">Lindner <em>&</em> Kiesel <small>Büro für Marken · Leipzig</small></a>
<a class="anfrage mono" href="#kontakt">Projekt anfragen</a>
</header>
<button class="knopf mono" type="button" aria-expanded="false" aria-controls="menue" data-knopf>
<kbd aria-hidden="true">Esc</kbd>
<span class="knopf-text" aria-hidden="true"><span>Menü</span><span>Schließen</span></span>
<span class="knopf-icon" aria-hidden="true"><i></i><i></i></span>
<span class="sr" data-sr>Menü öffnen</span>
</button>
<main class="seite" id="start" data-seite>
<div class="text">
<p class="mono kicker" data-kicker>Büro für Marken · Seit 2012 · Spinnerei Leipzig</p>
<h1 data-titel>Wir geben kleinen Marken <em>eine große Stimme</em>.</h1>
<p class="intro" data-intro>Erscheinungsbilder für Cafés, Handwerk und Kultur. Zwei Gestalter, ein Werkraum in der alten Baumwollspinnerei und kein Projekt von der Stange.</p>
</div>
<figure class="titelbild">
<img src="bilder/marke-roestkontor.jpg" alt="Wortmarke Röstkontor in Creme auf Ziegelrot, darüber eine Kaffeebohne" data-titelbild>
<figcaption class="mono"><span data-unterschrift>Röstkontor · Marke</span><span data-jahr>2024</span></figcaption>
</figure>
<p class="leiste-unten mono"><span>Spinnereistraße 7, Halle 14</span><span>Mo–Fr 9–17 Uhr</span><span>Frei ab Februar 2027</span></p>
</main>
<nav class="menue" id="menue" aria-label="Hauptmenü" data-menue data-variante="cursor" inert>
<div class="grund" data-grund>
<div class="buehne" aria-hidden="true">
<div class="buehne-bilder" data-buehne>
<img src="bilder/magazin-doppelseite.jpg" alt=""><img src="bilder/fenster-licht.jpg" alt="">
<img src="bilder/marke-krume.jpg" alt=""><img src="bilder/typo-plakat.jpg" alt="">
<img src="bilder/marke-eselsohr.jpg" alt="">
</div>
<div class="schleier"></div>
</div>
</div>
<div class="inhalt">
<div class="zeile-oben" data-fade><span class="marke" aria-hidden="true">Lindner <em>&</em> Kiesel <small>Navigation (05)</small></span></div>
<ol class="liste" data-liste>
<li class="eintrag"><a href="#arbeiten"><span class="zeile" data-zeile><span class="nr">01</span><span class="daumen" aria-hidden="true"><img src="bilder/magazin-doppelseite.jpg" alt=""></span><span class="wort">Arbeiten</span><sup>26<span class="sr"> Projekte</span></sup></span></a>
<div class="reveal" aria-hidden="true"><div class="reveal-innen"><img class="reveal-bild" src="bilder/magazin-doppelseite-hoch.jpg" alt=""></div></div></li>
<li class="eintrag"><a href="#studio"><span class="zeile" data-zeile><span class="nr">02</span><span class="daumen" aria-hidden="true"><img src="bilder/fenster-licht.jpg" alt=""></span><span class="wort">Studio</span></span></a>
<div class="reveal" aria-hidden="true"><div class="reveal-innen"><img class="reveal-bild" src="bilder/fenster-licht-hoch.jpg" alt=""></div></div></li>
<li class="eintrag"><a href="#leistungen"><span class="zeile" data-zeile><span class="nr">03</span><span class="daumen" aria-hidden="true"><img src="bilder/marke-krume.jpg" alt=""></span><span class="wort">Leistungen</span><sup>06<span class="sr"> Leistungen</span></sup></span></a>
<div class="reveal" aria-hidden="true"><div class="reveal-innen"><img class="reveal-bild" src="bilder/marke-krume-hoch.jpg" alt=""></div></div></li>
<li class="eintrag"><a href="#journal"><span class="zeile" data-zeile><span class="nr">04</span><span class="daumen" aria-hidden="true"><img src="bilder/typo-plakat.jpg" alt=""></span><span class="wort">Journal</span><sup>14<span class="sr"> Beiträge</span></sup></span></a>
<div class="reveal" aria-hidden="true"><div class="reveal-innen"><img class="reveal-bild" src="bilder/typo-plakat-hoch.jpg" alt=""></div></div></li>
<li class="eintrag"><a href="#kontakt"><span class="zeile" data-zeile><span class="nr">05</span><span class="daumen" aria-hidden="true"><img src="bilder/marke-eselsohr.jpg" alt=""></span><span class="wort">Kontakt</span></span></a>
<div class="reveal" aria-hidden="true"><div class="reveal-innen"><img class="reveal-bild" src="bilder/marke-eselsohr-hoch.jpg" alt=""></div></div></li>
</ol>
<aside class="neben">
<div class="im-bild" data-fade aria-hidden="true"><p class="mono">Im Bild</p><p data-bildtext>Fahren Sie über einen Eintrag.</p></div>
<div data-fade><p class="mono">Anfragen</p><a href="#mail">post@lindner-kiesel.de</a><a href="#telefon">+49 341 2290 418</a></div>
<div data-fade><p class="mono">Atelier</p><p>Spinnereistraße 7, Halle 14<br>04179 Leipzig</p></div>
<form class="brief" data-fade data-brief><label class="mono" for="brief">Ein Brief im Quartal</label><div class="feld"><input id="brief" type="email" placeholder="ihre@adresse.de" autocomplete="email"><button type="submit" class="mono">Abonnieren</button></div></form>
<p class="sozial mono" data-fade><a href="#instagram">Instagram</a><a href="#behance">Behance</a><a href="#linkedin">LinkedIn</a></p>
</aside>
<p class="fuss mono" data-fade><span>© 2026 Lindner & Kiesel</span><a href="#impressum">Impressum</a><a href="#datenschutz">Datenschutz</a></p>
</div>
</nav>
<aside class="pult mono" aria-label="Demo-Steuerung">
<div class="varianten" role="group" aria-label="Bildvorschau">
<button type="button" data-variante="cursor" aria-pressed="true">Cursor</button>
<button type="button" data-variante="hintergrund" aria-pressed="false">Hintergrund</button>
<button type="button" data-variante="leiste" aria-pressed="false">Leiste</button>
</div>
<p class="touch-hinweis">Touch: Daumenbild fest in jeder Zeile</p>
<p class="werte" data-werte></p>
</aside>
<svg class="zeiger" data-zeiger viewBox="0 0 20 20" aria-hidden="true"><path d="M3 2 17 10.2l-6.4 1.4-3 6Z" fill="#161513" stroke="#f2eee6" stroke-width="1.3" stroke-linejoin="round"/></svg>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script>
(() => {
const html = document.documentElement;
const reduziert = () => html.classList.contains('reduziert');
const touch = matchMedia('(hover: none)');
const $ = (s, w = document) => w.querySelector(s), $$ = (s, w = document) => [...w.querySelectorAll(s)];
const menue = $('[data-menue]'), knopf = $('[data-knopf]'), sr = $('[data-sr]');
const seite = $('[data-seite]'), kopf = $('[data-kopf]'), grund = $('[data-grund]');
const liste = $('[data-liste]'), eintraege = $$('.eintrag'), links = eintraege.map(e => $('a', e));
const zeilen = $$('[data-zeile]'), fades = $$('[data-fade]', menue);
const buehne = $$('img', $('[data-buehne]')), bildtext = $('[data-bildtext]');
const zeiger = $('[data-zeiger]'), werteFeld = $('[data-werte]');
const knoepfe = $$('.varianten button');
// Inhalte der „Seiten“ hinter den Links (Seitenwechsel wird in der Demo simuliert)
const SEITEN = [
{ kicker: 'Arbeiten (26)', titel: 'Sechsundzwanzig Marken, <em>keine von der Stange</em>.', intro: 'Vom Magazin bis zur Wortmarke: eine Auswahl aus zwölf Jahren, sortiert nach dem, was uns am meisten gefordert hat.', bild: 'magazin-doppelseite', alt: 'Aufgeschlagenes Magazin mit Stillleben und der Überschrift „Die Ruhe der Dinge“', titelbild: 'Gefüge · Editorial', jahr: '2025' },
{ kicker: 'Studio', titel: 'Zwei Gestalter, <em>eine Werkbank</em>.', intro: 'Anne Lindner kommt aus der Typografie, Jonas Kiesel aus dem Handwerk. Fotografie und Text holen wir uns ins Haus, wenn ein Projekt es braucht.', bild: 'fenster-licht', alt: 'Holzbank mit Vase und Zweigen vor grüner Wand im Sonnenlicht', titelbild: 'Werkraum · Halle 14', jahr: '2026' },
{ kicker: 'Leistungen (06)', titel: 'Von der Wortmarke <em>bis zum Etikett</em>.', intro: 'Strategie, Logo, Schrift und Farbe, Verpackung, Editorial und Websites. Alles aus einer Hand, damit am Ende alles zusammenpasst.', bild: 'marke-krume', alt: 'Wortmarke krume in Dunkelbraun auf Senfgelb, darüber ein Brotlaib', titelbild: 'Krume · Wortmarke & Etikett', jahr: '2025' },
{ kicker: 'Journal (14)', titel: 'Notizen aus der <em>Spinnerei</em>.', intro: 'Werkstattberichte, Fehlversuche und das eine oder andere Plädoyer für gute Schrift. Etwa einmal im Monat.', bild: 'typo-plakat', alt: 'Plakat Licht mit schwarzen Versalien und oranger Scheibe auf Neongelb', titelbild: 'Licht, Halle 4 · Plakat', jahr: '2025' },
{ kicker: 'Kontakt', titel: 'Erzählen Sie uns <em>von Ihrer Marke</em>.', intro: 'Ein Anruf genügt für den Anfang. Wir melden uns innerhalb von zwei Werktagen, auch wenn es nur ein erster Gedanke ist.', bild: 'marke-eselsohr', alt: 'Bildmarke Eselsohr mit rosa Eselsohr auf Anthrazit', titelbild: 'Eselsohr · Marke', jahr: '2023' },
];
const START = { kicker: $('[data-kicker]').textContent, titel: $('[data-titel]').innerHTML, intro: $('[data-intro]').textContent, bild: 'marke-roestkontor', alt: $('[data-titelbild]').alt, titelbild: 'Röstkontor · Marke', jahr: '2024' };
const WERTE = {
gemeinsam: '<span>Zeilen <b>1200 ms expo.out</b></span><span>Stagger <b>60 ms</b></span><span>Abdunkeln <b>0,26 · 200 ms</b></span>',
cursor: '<span>Reveal <b>200 ms sine.out · ±100 %</b></span><span>Lerp <b>0,08</b></span><span>Kippen <b>0–60°</b></span><span>Helligkeit <b>1–4</b></span>',
hintergrund: '<span>Clip-Wipe <b>1000 ms expo.out</b></span><span>Scale <b>1,12 → 1</b></span><span>Ausblenden <b>400 ms</b></span>',
leiste: '<span>Daumen <b>0,5 → 1,3 em · 800 ms expo.out</b></span>',
reduziert: '<span>Reduziert: <b>Overlay 150 ms linear</b></span><span><b>Bilder überblenden 150 ms</b></span>',
};
let offen = false, variante = 'cursor', aktiv = -1, tl = null, autoUhr = null;
// ---------- Öffnen und Schließen ----------
function grundzustand() {
gsap.set(menue, { autoAlpha: 0 });
gsap.set(grund, { clipPath: 'inset(0% 0% 100% 0%)' });
gsap.set(zeilen, { yPercent: 120 });
gsap.set(fades, { autoAlpha: 0, y: 16 });
}
function sperren(an) {
menue.inert = !an; seite.inert = an; kopf.inert = an;
html.classList.toggle('gesperrt', an);
knopf.classList.toggle('offen', an);
knopf.setAttribute('aria-expanded', String(an));
sr.textContent = an ? 'Menü schließen' : 'Menü öffnen';
}
function oeffnen(perTastatur) {
if (offen) return;
offen = true; sperren(true);
if (tl) tl.kill();
if (reduziert()) {
gsap.set(grund, { clipPath: 'inset(0% 0% 0% 0%)' }); gsap.set(zeilen, { yPercent: 0 }); gsap.set(fades, { autoAlpha: 1, y: 0 });
tl = gsap.fromTo(menue, { autoAlpha: 0 }, { autoAlpha: 1, duration: 0.15, ease: 'none' });
} else {
gsap.set(menue, { autoAlpha: 1 });
tl = gsap.timeline()
.fromTo(grund, { clipPath: 'inset(0% 0% 100% 0%)' }, { clipPath: 'inset(0% 0% 0% 0%)', duration: 0.8, ease: 'expo.out' }, 0)
.fromTo(zeilen, { yPercent: 120 }, { yPercent: 0, duration: 1.2, ease: 'expo.out', stagger: 0.06 }, 0.15)
.fromTo(fades, { autoAlpha: 0, y: 16 }, { autoAlpha: 1, y: 0, duration: 0.8, ease: 'expo.out', stagger: 0.06 }, 0.5);
}
if (perTastatur) links[0].focus();
}
function schliessen(fokusZurueck) {
if (!offen) return;
offen = false;
const fertig = () => { gsap.set(menue, { autoAlpha: 0 }); sperren(false); aktivSetzen(-1, true); };
if (fokusZurueck && menue.contains(document.activeElement)) knopf.focus();
knopf.classList.remove('offen'); knopf.setAttribute('aria-expanded', 'false');
if (tl) tl.kill();
if (reduziert()) { tl = gsap.to(menue, { autoAlpha: 0, duration: 0.15, ease: 'none', onComplete: fertig }); return; }
tl = gsap.timeline({ onComplete: fertig })
.to(zeilen, { yPercent: -120, duration: 0.45, ease: 'power3.in', stagger: 0.03 }, 0)
.to(fades, { autoAlpha: 0, duration: 0.2, ease: 'sine.out' }, 0)
.to(grund, { clipPath: 'inset(100% 0% 0% 0%)', duration: 0.7, ease: 'expo.inOut' }, 0.25);
}
// Simulierter Seitenwechsel: Inhalt tauschen, solange das Overlay deckt, dann schließen
function wechseln(i) {
const d = i < 0 ? START : SEITEN[i];
$('[data-kicker]').textContent = d.kicker;
$('[data-titel]').innerHTML = d.titel;
$('[data-intro]').textContent = d.intro;
const bild = $('[data-titelbild]'); bild.src = `bilder/${d.bild}.jpg`; bild.alt = d.alt;
$('[data-unterschrift]').textContent = d.titelbild; $('[data-jahr]').textContent = d.jahr;
links.forEach((a, j) => j === i ? a.setAttribute('aria-current', 'page') : a.removeAttribute('aria-current'));
}
// ---------- Hover: welcher Eintrag ist gemeint? ----------
const maus = { x: -999, y: -999 }, cache = { x: -999, y: -999 };
let richtungX = 1;
function treffer(x, y) {
const el = document.elementFromPoint(x, y), a = el && el.closest('.eintrag a');
return a ? links.indexOf(a) : -1;
}
function zeigerBei(x, y) {
const dx = x - maus.x; if (Math.abs(dx) > 0.5) richtungX = Math.sign(dx);
maus.x = x; maus.y = y;
if (!offen) return;
let i = treffer(x, y);
if (i < 0) {
// Zwischen zwei Zeilen nichts ändern, erst beim Verlassen der Liste zurücksetzen
const r = liste.getBoundingClientRect();
if (x > r.left && x < r.right && y > r.top && y < r.bottom && aktiv >= 0) i = aktiv;
}
aktivSetzen(i);
if (variante === 'cursor') loopStarten();
}
function aktivSetzen(i, still) {
if (i === aktiv) return;
const alt = aktiv; aktiv = i;
liste.classList.toggle('fokus', i >= 0);
eintraege.forEach((e, j) => e.classList.toggle('an', j === i));
bildtext.textContent = i >= 0 ? `${SEITEN[i].titelbild} · ${SEITEN[i].jahr}` : 'Fahren Sie über einen Eintrag.';
if (variante === 'cursor') { if (alt >= 0) revealAus(alt, still); if (i >= 0) revealAn(i); }
if (variante === 'hintergrund') { if (i >= 0) buehneAn(i); else buehneAus(still); }
}
// ---------- Variante Cursor (Lerp 0,08, Kippen und Helligkeit nach Tempo) ----------
const LERP = 0.08;
const R = eintraege.map(e => ({ el: $('.reveal', e), innen: $('.reveal-innen', e), bild: $('.reveal-bild', e), tx: 0, ty: 0, rot: 0, hell: 1, erster: true, sichtbar: false }));
const map = (v, a, b, c, d) => c + (d - c) * (v - a) / (b - a);
function revealAn(i) {
const r = R[i]; r.sichtbar = true; r.erster = true;
gsap.killTweensOf([r.el, r.innen, r.bild]);
if (reduziert()) { festSetzen(i); gsap.set([r.innen, r.bild], { xPercent: 0 }); gsap.fromTo(r.el, { opacity: 0 }, { opacity: 1, duration: 0.15, ease: 'none' }); return; }
const von = richtungX > 0 ? -100 : 100; // aufgedeckt von der Seite, von der die Maus kam
gsap.fromTo(r.el, { opacity: 0 }, { opacity: 1, duration: 0.2, ease: 'sine.out' });
gsap.fromTo(r.innen, { xPercent: von }, { xPercent: 0, duration: 0.2, ease: 'sine.out' });
gsap.fromTo(r.bild, { xPercent: -von }, { xPercent: 0, duration: 0.2, ease: 'sine.out' });
loopStarten();
}
function revealAus(i, still) {
const r = R[i];
gsap.killTweensOf([r.el, r.innen, r.bild]);
const weg = () => { r.sichtbar = false; };
if (still || reduziert()) { gsap.to(r.el, { opacity: 0, duration: still ? 0 : 0.15, ease: 'none', onComplete: weg }); return; }
const nach = richtungX > 0 ? 100 : -100;
gsap.to(r.el, { opacity: 0, duration: 0.2, ease: 'sine.out', onComplete: weg });
gsap.to(r.innen, { xPercent: nach, duration: 0.2, ease: 'sine.out' });
gsap.to(r.bild, { xPercent: -nach, duration: 0.2, ease: 'sine.out' });
}
// Ohne Folgen (Tastatur, reduzierte Bewegung): Bild rechts neben dem Wort
function festSetzen(i) {
const r = R[i], lr = liste.getBoundingClientRect(), ar = links[i].getBoundingClientRect();
const w = r.el.offsetWidth, h = r.el.offsetHeight;
r.tx = Math.min(ar.right - lr.left + 24, innerWidth - lr.left - w - 16);
r.ty = ar.top - lr.top + ar.height / 2 - h / 2; r.rot = 0; r.hell = 1; r.erster = false;
r.el.style.transform = `translate3d(${r.tx}px, ${r.ty}px, 0)`; r.bild.style.filter = 'none';
}
let loopAn = false, letzte = 0, angehalten = false;
function loopStarten() { if (!loopAn && !angehalten) { loopAn = true; letzte = performance.now(); requestAnimationFrame(rahmen); } }
function rahmen(t) {
if (angehalten) { loopAn = false; return; }
const dt = Math.max(0.25, Math.min(64, t - letzte) / 16.667); letzte = t;
const k = 1 - Math.pow(1 - LERP, dt);
const lr = liste.getBoundingClientRect();
// Mausweg pro Bild (auf 60 Hz umgerechnet), 0–100 px → 0–60° und Helligkeit 1–4
const weg = Math.min(100, Math.abs(maus.x - cache.x) / dt);
const seite = cache.x < maus.x ? 1 : -1;
cache.x = maus.x; cache.y = maus.y;
let laeuft = false;
R.forEach((r, i) => {
if (!r.sichtbar) return;
laeuft = true;
if (reduziert() || document.activeElement === links[i] && maus.x < -900) return;
const zx = maus.x - lr.left - r.el.offsetWidth / 2, zy = maus.y - lr.top - r.el.offsetHeight / 2;
const zr = r.erster ? 0 : map(weg, 0, 100, 0, 60 * seite), zh = r.erster ? 1 : map(weg, 0, 100, 1, 4);
if (r.erster) { r.tx = zx; r.ty = zy; r.rot = 0; r.hell = 1; r.erster = false; }
else { r.tx += (zx - r.tx) * k; r.ty += (zy - r.ty) * k; r.rot += (zr - r.rot) * k; r.hell += (zh - r.hell) * k; }
r.el.style.transform = `translate3d(${r.tx}px, ${r.ty}px, 0) rotate(${r.rot}deg)`;
r.bild.style.filter = `brightness(${r.hell})`;
});
if (laeuft || (offen && variante === 'cursor')) requestAnimationFrame(rahmen); else loopAn = false;
}
// ---------- Variante Hintergrund (Clip-Wipe von unten, 1000 ms expo.out) ----------
let zOben = 1;
function buehneAn(i) {
const b = buehne[i];
if (zOben > 900) { zOben = 1; buehne.forEach(x => x.style.zIndex = 1); }
b.style.zIndex = ++zOben;
gsap.killTweensOf(b);
if (reduziert()) gsap.fromTo(b, { opacity: 0, clipPath: 'inset(0% 0% 0% 0%)', scale: 1 }, { opacity: 1, duration: 0.15, ease: 'none' });
else gsap.fromTo(b, { opacity: 1, clipPath: 'inset(100% 0% 0% 0%)', scale: 1.12 }, { clipPath: 'inset(0% 0% 0% 0%)', scale: 1, duration: 1, ease: 'expo.out' });
}
function buehneAus(still) {
buehne.forEach(b => {
gsap.killTweensOf(b);
const zurueck = () => gsap.set(b, { clipPath: 'inset(100% 0% 0% 0%)', opacity: 1 });
if (still) zurueck(); else gsap.to(b, { opacity: 0, duration: reduziert() ? 0.15 : 0.4, ease: 'sine.out', onComplete: zurueck });
});
}
// ---------- Varianten ----------
function werteZeigen() {
werteFeld.innerHTML = reduziert() ? WERTE.reduziert : WERTE.gemeinsam + WERTE[touch.matches ? 'leiste' : variante];
}
function varianteSetzen(v) {
aktivSetzen(-1, true);
variante = v; menue.dataset.variante = v;
knoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.variante === v)));
werteZeigen();
if (offen && maus.x > -900) zeigerBei(maus.x, maus.y);
}
knoepfe.forEach(b => b.addEventListener('click', () => { vfStopp(); varianteSetzen(b.dataset.variante); }));
// ---------- Bedienung ----------
knopf.addEventListener('click', e => { vfStopp(); clearTimeout(autoUhr); offen ? schliessen(true) : oeffnen(e.detail === 0); });
addEventListener('keydown', e => { if (e.key === 'Escape' && offen) { vfStopp(); schliessen(true); } });
links.forEach((a, i) => {
a.addEventListener('click', e => { e.preventDefault(); vfStopp(); aktivSetzen(i); wechseln(i); schliessen(true); });
a.addEventListener('focus', () => { if (a.matches(':focus-visible')) { aktivSetzen(i); if (variante === 'cursor') festSetzen(i); } });
a.addEventListener('blur', () => { setTimeout(() => { if (!liste.contains(document.activeElement)) aktivSetzen(-1); }, 0); });
});
$('.kopf .marke').addEventListener('click', e => { e.preventDefault(); wechseln(-1); });
$('.anfrage').addEventListener('click', e => { e.preventDefault(); wechseln(4); });
$('[data-brief]').addEventListener('submit', e => e.preventDefault());
document.addEventListener('pointermove', e => { if (e.pointerType === 'mouse' && !html.classList.contains('vorfuehrung')) zeigerBei(e.clientX, e.clientY); });
document.addEventListener('pointerout', e => { if (!e.relatedTarget && e.pointerType === 'mouse' && !html.classList.contains('vorfuehrung')) aktivSetzen(-1); });
touch.addEventListener('change', werteZeigen);
new MutationObserver(werteZeigen).observe(html, { attributes: true, attributeFilter: ['class'] });
// ---------- Vorführung: gedachter Zeiger öffnet, fährt die Zeilen ab, klickt ----------
const REIHE = ['cursor', 'hintergrund', 'leiste'];
const zp = { x: 0, y: 0 };
const knopfPunkt = () => { const r = knopf.getBoundingClientRect(); return { x: r.right - 20, y: r.top + r.height / 2 }; };
const linkPunkt = (i, f) => { const r = links[i].getBoundingClientRect(); return { x: r.left + r.width * f, y: r.top + r.height * 0.52 }; };
const skript = v => [
['variante', v], ['warte', 350],
['gehe', knopfPunkt, 650], ['klick', 'knopf'], ['warte', 600],
['gehe', () => linkPunkt(0, 0.22), 520], ['gehe', () => linkPunkt(0, 0.88), 560],
['gehe', () => linkPunkt(1, 0.3), 540], ['gehe', () => linkPunkt(2, 0.82), 620],
['gehe', () => linkPunkt(3, 0.18), 620], ['gehe', () => linkPunkt(4, 0.7), 600],
['gehe', () => linkPunkt(2, 0.45), 760], ['warte', 450],
['klick', 'link'], ['warte', 1700],
];
const vf = { uhr: null, zeit: 0, letzte: 0, i: 0, start: 0, von: null, nach: null, liste: [], v: 0 };
function zeigerSetzen(x, y) { zp.x = x; zp.y = y; zeiger.style.transform = `translate(${x - 3}px, ${y - 2}px)`; zeigerBei(x, y); }
function klicken(was) {
zeiger.classList.add('klick'); setTimeout(() => zeiger.classList.remove('klick'), 160);
if (was === 'knopf') { offen ? schliessen() : oeffnen(false); }
else if (aktiv >= 0) { wechseln(aktiv); schliessen(); }
}
function vfRahmen(t) {
vf.zeit += Math.min(50, t - vf.letzte); vf.letzte = t;
let s = vf.liste[vf.i];
while (s) {
const lauf = vf.zeit - vf.start;
if (s[0] === 'gehe') {
if (!vf.von) { vf.von = { ...zp }; vf.nach = s[1](); }
const p = Math.min(1, lauf / s[2]), e = 0.5 - 0.5 * Math.cos(Math.PI * p);
zeigerSetzen(vf.von.x + (vf.nach.x - vf.von.x) * e, vf.von.y + (vf.nach.y - vf.von.y) * e);
if (p < 1) break;
vf.von = null; vf.start += s[2];
} else if (s[0] === 'warte') { if (lauf < s[1]) break; vf.start += s[1]; }
else if (s[0] === 'klick') klicken(s[1]);
else if (s[0] === 'variante') varianteSetzen(s[1]);
s = vf.liste[++vf.i];
}
if (!s) { vf.v = (vf.v + 1) % REIHE.length; vf.liste = skript(touch.matches ? 'leiste' : REIHE[vf.v]); vf.i = 0; vf.start = vf.zeit; }
vf.uhr = requestAnimationFrame(vfRahmen);
}
function vorfuehren() {
vfStopp(); clearTimeout(autoUhr); ruhe();
html.classList.add('vorfuehrung');
zeigerSetzen(innerWidth * 0.62, innerHeight * 0.7);
vf.v = 0; vf.liste = skript(touch.matches ? 'leiste' : REIHE[0]); vf.i = 0; vf.zeit = 0; vf.start = 0; vf.von = null;
vf.letzte = performance.now(); vf.uhr = requestAnimationFrame(vfRahmen);
}
function vfStopp() { if (vf.uhr) cancelAnimationFrame(vf.uhr); vf.uhr = null; html.classList.remove('vorfuehrung'); }
// Alles auf Anfang: Menü zu, Startseite, keine Bilder
function ruhe() {
if (tl) tl.kill();
offen = false; sperren(false); aktivSetzen(-1, true); buehneAus(true);
R.forEach(r => { gsap.killTweensOf([r.el, r.innen, r.bild]); gsap.set(r.el, { opacity: 0 }); r.sichtbar = false; });
grundzustand(); wechseln(-1);
}
function neustart() {
vfStopp(); clearTimeout(autoUhr); ruhe();
autoUhr = setTimeout(() => oeffnen(false), 700); // einmal von selbst öffnen, damit man den Effekt sieht
}
function pause() {
angehalten = true; gsap.globalTimeline.pause();
if (vf.uhr) { cancelAnimationFrame(vf.uhr); vf.uhr = null; vf.pausiert = true; }
}
function weiter() {
angehalten = false; gsap.globalTimeline.resume(); loopStarten();
if (vf.pausiert && html.classList.contains('vorfuehrung')) { vf.pausiert = false; vf.letzte = performance.now(); vf.uhr = requestAnimationFrame(vfRahmen); }
}
if (touch.matches) varianteSetzen('leiste'); else werteZeigen();
neustart();
})();
</script>
</body>
</html>