Zum Inhalt
← Galerien & Slider

Radial- und Bogen-Slider (Karten auf Kreisbahn)

Uhrenkarten liegen auf einem großen Kreis, dessen Mitte weit unter der Bühne sitzt: Man zieht den Bogen, er rastet auf der obersten Karte ein.

Karten liegen auf einem großen Kreis, dessen Mittelpunkt weit unter (oder neben) dem Viewport liegt. Sichtbar ist nur ein flacher Bogen. Jede Karte ist um ihren Winkel gedreht und steht damit tangential zur Bahn. Ziehen, Pfeile oder Tasten drehen den ganzen Kreis; danach rastet die oberste Karte ein. Als Laufband dreht sich der Kreis mit CSS gleichmäßig weiter.

Die Geometrie ist ungewohnt und bleibt trotzdem lesbar. Der Bogen gibt der Bewegung eine natürliche Richtung, und die oberste Karte ist ohne weitere Auszeichnung die wichtigste.

Wann einsetzen

Produkt- oder Featurekarten, Kollektionen, Testimonials und Kategorien. Gut, wenn eine Auswahl mit gleich großen Bildern gezeigt werden soll.

Wann nicht

Bei langen Texten auf den Karten, in streng rasterbasierten Layouts und bei weniger als sechs Elementen, weil der Kreis dann Lücken zeigt.

Varianten

  • Bogen mit Ziehen und Einrasten (GSAP Draggable)
  • Laufband: der Kreis dreht sich mit reinem CSS
  • 3D: Karten als Spirale oder Tornado
  • Orbit-Kacheln als Endlosschleife

Umsetzung

Ein Ring ohne Größe sitzt im Kreismittelpunkt. Karte i bekommt rotate(i × Winkelschritt) translateY(−R), der Ring wird als Ganzes gedreht. Bei vollem Kreis (Anzahl × Schritt = 360°) braucht es keine Wrap-Logik. Ziehen über Draggable auf einem Proxy, Weg in Grad umrechnen (180 / (π · R) je Pixel). Einrasten: Math.round(winkel / schritt) × schritt. Laufband: @keyframes rotate 0 → −360deg, linear, infinite, auf einem inneren Element, damit es sich nicht mit der GSAP-Drehung stört. Fallstricke: große Transform-Flächen und Clipping am Container (overflow hidden).

Robust umsetzen

Telefon. Flacherer Bogen, größere Karten und Wischen. Nachbarkarten sollen sichtbar anschneiden, damit die Bahn erkennbar bleibt.

Ohne Bewegung. Laufband anhalten, Einrasten ohne Animation.

Barrierefrei. Logische DOM-Reihenfolge, Buttons für Vor und Zurück, Pfeiltasten auf dem fokussierten Bogen, aria-live für die Angaben der aktiven Karte. Das Laufband braucht einen Knopf zum Anhalten.

Code

<!DOCTYPE html>
<!--
  Radial- und Bogen-Slider (Karten auf Kreisbahn)
  Fundus · Galerien & Slider · https://cecodesign.de/lab/fundus/galerien-slider/radial-bogen-slider/
  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>Radial- und Bogen-Slider · 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: 'Bodoni Moda'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/bodoni-moda:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 400 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Bodoni Moda'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/bodoni-moda:vf@latest/latin-opsz-italic.woff2') format('woff2-variations'); font-weight: 400 900; font-style: italic; font-display: swap; }
@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: 'Geist Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist-mono:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }

:root {
  /* Rezept „Manufaktur-Stille“: Anthrazit und Weiß, Produktfläche Hellgrau, Messing nur als Linie */
  --anthrazit: #23282f; --weiss: #fff; --flaeche: #f4f4f2; --meta: #8b9097; --linie: rgba(255, 255, 255, .14); --messing: #a88a5a;
  --auf: cubic-bezier(0.1, 0.9, 0.3, 1);     /* NOMOS: Öffnen 300 ms */
  --zu: cubic-bezier(0.1, 0.6, 0.4, 1);      /* NOMOS: Schließen 200 ms, UI */
  --kw: clamp(150px, 13.2vw, 196px);         /* Kartenbreite */
  --kh: calc(var(--kw) * 1.3);
  --r: 900px;                                 /* Radius, per JS aus Kartenbreite und Winkelschritt */
  --rand: clamp(18px, 3.6vw, 52px);
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--anthrazit); color: var(--weiss); font-family: 'Instrument Sans', system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
body { overflow-x: hidden; }
button { font: inherit; color: inherit; }
.versal { font-size: .75rem; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; }
.mono { font: 500 10.5px/1.4 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--meta); }

.buehne { position: relative; min-height: 100svh; overflow: hidden; display: flex; flex-direction: column; isolation: isolate; }

/* Kopf */
.kopf { position: relative; z-index: 3; display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 22px var(--rand); border-bottom: 1px solid var(--linie); }
.marke { display: grid; gap: 3px; color: inherit; text-decoration: none; }
.marke b { font: 500 21px/1 'Bodoni Moda', Georgia, serif; letter-spacing: .2em; }
.marke span { font-size: 9.5px; font-weight: 500; letter-spacing: .24em; text-transform: uppercase; color: var(--meta); }
.nav { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 36px); list-style: none; padding: 0; }
.nav a { color: rgba(255,255,255,.78); text-decoration: none; background: linear-gradient(var(--messing) 0 0) 0 100% / 0 1px no-repeat; padding-bottom: 4px; transition: background-size .2s var(--zu), color .2s var(--zu); }
.nav a:hover { color: #fff; background-size: 100% 1px; transition-duration: .3s; transition-timing-function: var(--auf); }
.nav .termin { border: 1px solid rgba(255,255,255,.4); padding: 10px 16px; color: #fff; background: none; transition: border-color .2s var(--zu), background-color .2s var(--zu); }
.nav .termin:hover { border-color: var(--messing); background: rgba(168,138,90,.12); }
.menue { display: none; width: 42px; height: 42px; border: 1px solid rgba(255,255,255,.3); border-radius: 50%; background: none; }
.menue i { display: block; width: 14px; height: 1px; margin: 4px auto; background: #fff; }

/* Einleitung */
.einleitung { position: relative; z-index: 3; display: flex; justify-content: space-between; align-items: flex-end; gap: 20px 40px; padding: clamp(22px, 4vh, 48px) var(--rand) 0; }
.einleitung .versal { color: var(--meta); margin-bottom: 14px; }
h1 { font: 400 clamp(2.25rem, 1.2rem + 3.2vw, 4.25rem)/1.02 'Bodoni Moda', Georgia, serif; font-optical-sizing: auto; letter-spacing: -.01em; }
h1 em { font-style: italic; }
.steuer { display: flex; align-items: center; gap: 20px; padding-bottom: 6px; }
.zaehler { font-variant-numeric: tabular-nums; font-size: 13px; letter-spacing: .08em; color: var(--meta); white-space: nowrap; }
.zaehler b { color: #fff; font-weight: 500; }
.pfeile { display: flex; gap: 8px; }
.pfeil { width: 46px; height: 46px; border-radius: 50%; border: 1px solid rgba(255,255,255,.28); background: none; display: grid; place-items: center; cursor: pointer; transition: border-color .2s var(--zu), background-color .2s var(--zu); }
.pfeil:hover { border-color: var(--messing); background: rgba(168,138,90,.12); }
.pfeil svg { width: 16px; height: 16px; }
.pfeil:focus-visible, .modi button:focus-visible, .nav a:focus-visible { outline: 1px solid var(--messing); outline-offset: 3px; }
.bogen:focus-visible .karte.aktiv { outline: 1px solid var(--messing); outline-offset: 5px; }

/* Der Bogen: Kreismittelpunkt liegt weit unter der Bühne, sichtbar ist nur die Kuppe */
.bogen { position: relative; z-index: 1; height: calc(var(--kh) + 64px); margin-top: clamp(14px, 3vh, 34px); cursor: grab; user-select: none; -webkit-user-select: none; outline: none; touch-action: pan-y; }
.bogen.zieht { cursor: grabbing; }
.ring { position: absolute; left: 50%; top: calc(46px + var(--kh) / 2 + var(--r)); width: 0; height: 0; will-change: transform; }
.lauf { position: absolute; inset: 0; }
.karte { position: absolute; left: calc(var(--kw) / -2); top: calc(var(--kh) / -2); width: var(--kw); height: var(--kh); transform: rotate(var(--a)) translateY(calc(var(--r) * -1)); background: linear-gradient(180deg, #f7f7f5, #ecece9); border-radius: 2px; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 30px 50px -28px rgba(0, 0, 0, .7); }
.karte svg { display: block; width: 100%; flex: 1; min-height: 0; }
.karte figcaption { display: flex; justify-content: space-between; padding: 0 9% 8%; font-size: 9px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--meta); font-variant-numeric: tabular-nums; }
.karte::after { content: ''; position: absolute; left: 9%; right: 9%; bottom: 0; height: 2px; background: var(--messing); scale: 0 1; transition: scale .2s var(--zu); }
.karte.aktiv::after { scale: 1 1; transition: scale .3s var(--auf); }
.strich { position: absolute; left: -.5px; top: -4px; width: 1px; height: 8px; background: rgba(255,255,255,.26); transform: rotate(var(--a)) translateY(calc(var(--r) * -1 - var(--kh) / 2 - 26px)); }
.strich.gross { height: 14px; top: -7px; background: rgba(255,255,255,.55); }
/* Messing-Index auf zwölf Uhr, steht still */
.marker { position: absolute; left: 50%; top: 0; translate: -50% 0; display: grid; justify-items: center; gap: 3px; pointer-events: none; }
.marker i { display: block; width: 1px; height: 12px; background: var(--messing); }
.marker b { display: block; width: 7px; height: 7px; rotate: 45deg; border: 1px solid var(--messing); }

/* Laufband: reines CSS, eine Umdrehung in 48 s */
@keyframes drehen { to { transform: rotate(-360deg); } }
.modus-laufband .lauf { animation: drehen 48s linear infinite; }
.modus-laufband .bogen { cursor: default; }
.modus-laufband .bogen:hover .lauf, .laufband-pause .lauf { animation-play-state: paused; }

/* Seitliche Abblendung: Karten laufen in die Fläche aus */
.buehne::after { content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(90deg, var(--anthrazit) 0, rgba(35,40,47,0) 24%, rgba(35,40,47,0) 76%, var(--anthrazit) 100%), linear-gradient(0deg, var(--anthrazit) 4%, rgba(35,40,47,0) 34%); }

/* Angaben zur aktiven Uhr: unter der Kuppe, wo der Bogen abfällt */
.info { position: relative; z-index: 3; width: min(560px, calc(100% - 2 * var(--rand))); margin: 22px auto 0; text-align: center; display: grid; justify-items: center; gap: 12px; }
.info > * { transition: opacity .3s var(--auf), translate .3s var(--auf); }
.info.wechselt > * { opacity: 0; translate: 0 4px; transition: opacity .2s var(--zu), translate .2s var(--zu); }
.info .versal { color: var(--meta); font-variant-numeric: tabular-nums; }
.info h2 { font: 400 clamp(1.75rem, 1.2rem + 1.4vw, 2.5rem)/1.05 'Bodoni Moda', Georgia, serif; letter-spacing: -.01em; }
.info h2 em { font-style: italic; color: rgba(255,255,255,.72); }
.daten { display: grid; grid-template-columns: repeat(4, auto); justify-content: center; margin-top: 6px; border-top: 1px solid var(--linie); padding-top: 14px; font-variant-numeric: tabular-nums; }
.daten div { padding: 0 clamp(12px, 1.8vw, 24px); text-align: left; }
.daten div + div { border-left: 1px solid var(--linie); }
.daten dt { font-size: 10px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--meta); margin-bottom: 5px; }
.daten dd { font-size: 15px; line-height: 1.2; white-space: nowrap; }
.mehr { font-size: .75rem; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: #fff; text-decoration: none; padding-bottom: 5px; background: linear-gradient(var(--messing) 0 0) 0 100% / 100% 1px no-repeat; margin-top: 4px; }

/* Fuß mit Varianten und Werten (fließt mit, liegt nicht über der Seite) */
.fuss { position: relative; z-index: 3; margin-top: auto; display: flex; justify-content: space-between; align-items: center; gap: 12px 24px; flex-wrap: wrap; padding: 26px var(--rand) 22px; }
.modi { display: flex; gap: 4px; align-items: center; }
.modi button { letter-spacing: inherit; text-transform: inherit; color: var(--meta); background: none; border: 1px solid var(--linie); border-radius: 999px; height: 28px; padding: 0 12px; cursor: pointer; transition: color .2s var(--zu), background-color .2s var(--zu), border-color .2s var(--zu); }
.modi button:hover { color: #fff; }
.modi button[aria-pressed='true'] { background: #fff; color: var(--anthrazit); border-color: #fff; }
.modi [data-pause] { display: none; }
.modus-laufband .modi [data-pause] { display: inline-block; }
.werte b { color: #fff; font-weight: 500; }

/* Gezeichneter Zeiger für die Vorführung */
.zeiger { position: fixed; left: 0; top: 0; z-index: 9; width: 22px; height: 22px; pointer-events: none; display: none; transition: scale .2s var(--zu); }
.vorfuehrung .zeiger { display: block; }
.zeiger.druck { scale: .82; }

/* Vorschau 960 × 720: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .kopf, .vorschau .fuss, .vorschau .mehr { display: none; }
.vorschau .einleitung { padding-top: 34px; }

@media (max-width: 900px) {
  .nav li:not(:last-child) { display: none; }
}
@media (max-width: 640px) {
  :root { --kw: min(52vw, 220px); }
  .nav { display: none; }
  .menue { display: block; }
  .kopf { padding-block: 16px; }
  .einleitung { flex-direction: column; align-items: flex-start; }
  h1 { font-size: clamp(2.1rem, 9.4vw, 2.6rem); }
  .steuer { width: 100%; justify-content: space-between; }
  .bogen { margin-top: 8px; }
  .buehne::after { background: linear-gradient(90deg, var(--anthrazit) 0, rgba(35,40,47,0) 14%, rgba(35,40,47,0) 86%, var(--anthrazit) 100%), linear-gradient(0deg, var(--anthrazit) 2%, rgba(35,40,47,0) 20%); }
  .daten { grid-template-columns: repeat(2, auto); row-gap: 14px; }
  .daten div:nth-child(3) { border-left: 0; }
  .fuss { flex-direction: column; align-items: flex-start; }
}
@media (hover: none) {
  .bogen { cursor: default; }
  .modus-laufband .bogen:hover .lauf { animation-play-state: running; }
  .modus-laufband.laufband-pause .bogen .lauf { animation-play-state: paused; }
}
/* Reduzierte Bewegung: Laufband steht, Einrasten ohne Animation, Texte wechseln ohne Versatz */
.reduziert .modus-laufband .lauf, .reduziert .lauf { animation-play-state: paused !important; }
.reduziert .info > *, .reduziert .info.wechselt > * { transition: none; translate: none; }
.reduziert .karte::after { transition: none; }
</style>
</head>
<body>
<div class="buehne" data-buehne>
  <header class="kopf">
    <a class="marke" href="#start"><b>PRIESSNITZ</b><span>Glashütte i. Sa.</span></a>
    <ul class="nav versal">
      <li><a href="#kollektion">Kollektion</a></li>
      <li><a href="#manufaktur">Manufaktur</a></li>
      <li><a href="#service">Service</a></li>
      <li><a href="#termin" class="termin">Termin vereinbaren</a></li>
    </ul>
    <button class="menue" type="button" aria-label="Menü öffnen"><i></i><i></i></button>
  </header>

  <section class="einleitung" id="start">
    <div>
      <p class="versal">Kollektion 2026 · Zwölf Referenzen</p>
      <h1>Zwölf Uhren,<br><em>von Hand</em> reguliert.</h1>
    </div>
    <div class="steuer">
      <p class="zaehler" aria-hidden="true"><b data-nr>01</b> / 12</p>
      <div class="pfeile">
        <button class="pfeil" type="button" data-schritt="-1" aria-label="Vorherige Uhr"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10 3 5 8l5 5" fill="none" stroke="currentColor" stroke-width="1.1"/></svg></button>
        <button class="pfeil" type="button" data-schritt="1" aria-label="Nächste Uhr"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="m6 3 5 5-5 5" fill="none" stroke="currentColor" stroke-width="1.1"/></svg></button>
      </div>
    </div>
  </section>

  <div class="bogen" data-bogen tabindex="0" role="region" aria-roledescription="Karussell" aria-label="Kollektion, mit Pfeiltasten blättern">
    <div class="marker" aria-hidden="true"><b></b><i></i></div>
    <div class="ring" data-ring><div class="lauf" data-lauf></div></div>
  </div>

  <section class="info" data-info aria-live="polite">
    <p class="versal" data-ref></p>
    <h2 data-name></h2>
    <dl class="daten" data-daten></dl>
    <a class="mehr" href="#termin">Uhr in der Manufaktur ansehen</a>
  </section>

  <footer class="fuss">
    <div class="modi mono" role="group" aria-label="Variante">
      <button type="button" data-modus="bogen" aria-pressed="true">Bogen</button>
      <button type="button" data-modus="laufband" aria-pressed="false">Laufband</button>
      <button type="button" data-pause aria-pressed="false">Anhalten</button>
    </div>
    <p class="werte mono" data-werte></p>
  </footer>
</div>
<svg class="zeiger" data-zeiger viewBox="0 0 22 22" aria-hidden="true"><path d="M3 2 18 11l-6.6 1.5L8.2 19Z" fill="#fff" stroke="#23282f" stroke-width="1.2" stroke-linejoin="round"/></svg>

<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/Draggable.min.js"></script>
<script>
(() => {
  gsap.registerPlugin(Draggable);
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const $ = s => document.querySelector(s);
  const buehne = $('[data-buehne]'), bogen = $('[data-bogen]'), ring = $('[data-ring]'), lauf = $('[data-lauf]');
  const info = $('[data-info]'), zeiger = $('[data-zeiger]'), werteEl = $('[data-werte]');

  // Werte (Messwerte des Musters: Winkelschritt 8–15°, Einrasten power3.out 600–800 ms, Laufband 30–60 s)
  const W = { schritt: 15, karten: 24, einrasten: 0.7, ease: 'power3.out', umdrehung: 48, abstand: 1.38, abstandMobil: 1.1 };

  // Kollektion der (erfundenen) Manufaktur Prießnitz, Glashütte
  const UHREN = [
    { name: 'Müglitz', zusatz: 'Handaufzug', ref: '21.01', gehaeuse: 'stahl', blatt: '#ebe9e3', tief: '#d6d3cb', index: 'stab', farbe: '#2b2f36', zeiger: '#2a4a86', band: '#1d1e21', komp: ['sekunde'], kaliber: 'P-21', aufzug: 'Hand', gang: '72 h', d: '38,5 mm', zifferblatt: 'Silber gekörnt' },
    { name: 'Müglitz', zusatz: 'Datum', ref: '21.04', gehaeuse: 'stahl', blatt: '#363b43', tief: '#22262c', index: 'stab', farbe: '#eceae4', zeiger: '#eceae4', band: '#55585d', komp: ['sekunde', 'datum'], kaliber: 'P-21.1', aufzug: 'Hand', gang: '68 h', d: '39 mm', zifferblatt: 'Anthrazit' },
    { name: 'Müglitz', zusatz: 'Lachs', ref: '21.07', gehaeuse: 'stahl', blatt: '#e7bfa6', tief: '#cf9f84', index: 'arabisch', farbe: '#3a2a24', zeiger: '#2b2f36', band: '#5a3a2a', komp: ['sekunde'], kaliber: 'P-21', aufzug: 'Hand', gang: '72 h', d: '38,5 mm', zifferblatt: 'Lachs' },
    { name: 'Luchberg', zusatz: 'Mondphase', ref: '23.02', gehaeuse: 'rotgold', blatt: '#22345a', tief: '#131f38', index: 'punkt', farbe: '#d9b48c', zeiger: '#d9b48c', band: '#1d2638', komp: ['mond', 'sekunde'], kaliber: 'P-23', aufzug: 'Hand', gang: '72 h', d: '40 mm', zifferblatt: 'Nachtblau' },
    { name: 'Luchberg', zusatz: 'Weißgold', ref: '23.05', gehaeuse: 'weissgold', blatt: '#f1f0ec', tief: '#dcdad4', index: 'roemisch', farbe: '#23282f', zeiger: '#2a4a86', band: '#1d1e21', komp: ['mond'], kaliber: 'P-23', aufzug: 'Hand', gang: '72 h', d: '40 mm', zifferblatt: 'Weiß' },
    { name: 'Kohlhau', zusatz: 'Gangreserve', ref: '25.01', gehaeuse: 'stahl', blatt: '#a9aeb4', tief: '#878c93', index: 'stab', farbe: '#1f2329', zeiger: '#1f2329', band: '#1d1e21', komp: ['reserve', 'sekunde'], kaliber: 'P-25', aufzug: 'Hand', gang: '96 h', d: '40 mm', zifferblatt: 'Rhodiniert' },
    { name: 'Kohlhau', zusatz: 'Rotgold', ref: '25.03', gehaeuse: 'rotgold', blatt: '#ece1cb', tief: '#d8c7a8', index: 'roemisch', farbe: '#3b2c22', zeiger: '#8a5a3e', band: '#5a3a2a', komp: ['reserve'], kaliber: 'P-25', aufzug: 'Hand', gang: '96 h', d: '40 mm', zifferblatt: 'Champagner' },
    { name: 'Geising', zusatz: 'Automatik', ref: '27.01', gehaeuse: 'stahl', blatt: '#f7f6f1', tief: '#e5e3dc', index: 'arabisch', farbe: '#23282f', zeiger: '#2a4a86', band: '#1d1e21', komp: ['datum'], kaliber: 'P-27', aufzug: 'Automatik', gang: '60 h', d: '40,5 mm', zifferblatt: 'Email weiß' },
    { name: 'Geising', zusatz: 'Tannengrün', ref: '27.04', gehaeuse: 'stahl', blatt: '#34503f', tief: '#1f3328', index: 'stab', farbe: '#eceae4', zeiger: '#eceae4', band: '#5a3a2a', komp: ['datum'], kaliber: 'P-27', aufzug: 'Automatik', gang: '60 h', d: '40,5 mm', zifferblatt: 'Tannengrün' },
    { name: 'Schlottwitz', zusatz: 'Kleine Sekunde', ref: '19.02', gehaeuse: 'rotgold', blatt: '#f4ede6', tief: '#e2d6ca', index: 'punkt', farbe: '#6b4a36', zeiger: '#8a5a3e', band: '#7c6a5c', komp: ['sekunde'], kaliber: 'P-19', aufzug: 'Hand', gang: '55 h', d: '34 mm', zifferblatt: 'Perlweiß' },
    { name: 'Schlottwitz', zusatz: 'Eisblau', ref: '19.05', gehaeuse: 'stahl', blatt: '#c3d1dc', tief: '#a2b3c1', index: 'stab', farbe: '#1f2a36', zeiger: '#1f2a36', band: '#55585d', komp: [], kaliber: 'P-19', aufzug: 'Hand', gang: '55 h', d: '34 mm', zifferblatt: 'Eisblau' },
    { name: 'Cunnersdorf', zusatz: 'Chronometer', ref: '29.01', gehaeuse: 'platin', blatt: '#40464e', tief: '#2a2f35', index: 'roemisch', farbe: '#e6e4de', zeiger: '#e6e4de', band: '#1d1e21', komp: ['sekunde'], kaliber: 'P-29', aufzug: 'Hand', gang: '80 h', d: '41 mm', zifferblatt: 'Schiefer' }
  ];
  const GEHAEUSE = { stahl: ['#f4f5f6', '#b8bdc3', '#767c84', 'Edelstahl'], rotgold: ['#f6d9c2', '#c98f6a', '#80523a', 'Rotgold'], weissgold: ['#f7f7f5', '#cacbcd', '#8a8e93', 'Weißgold'], platin: ['#f0f2f4', '#b1b6bd', '#6c727a', 'Platin'] };

  // Zifferblatt als SVG zeichnen (eigene Grafik, kein Foto)
  function uhr(u, k) {
    const g = GEHAEUSE[u.gehaeuse], id = 'u' + k, cx = 100, cy = 116;
    const rot = (deg, r) => [cx + r * Math.sin(deg * Math.PI / 180), cy - r * Math.cos(deg * Math.PI / 180)];
    let s = `<svg viewBox="0 0 200 238" aria-hidden="true"><defs>
      <linearGradient id="${id}m" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${g[0]}"/><stop offset=".5" stop-color="${g[1]}"/><stop offset="1" stop-color="${g[2]}"/></linearGradient>
      <linearGradient id="${id}r" x1="1" y1="1" x2="0" y2="0"><stop offset="0" stop-color="${g[0]}"/><stop offset=".55" stop-color="${g[1]}"/><stop offset="1" stop-color="${g[2]}"/></linearGradient>
      <radialGradient id="${id}d" cx=".42" cy=".36" r=".78"><stop offset="0" stop-color="${u.blatt}"/><stop offset="1" stop-color="${u.tief}"/></radialGradient>
      <linearGradient id="${id}b" x1="0" x2="1"><stop offset="0" stop-color="#000" stop-opacity=".28"/><stop offset=".5" stop-color="#fff" stop-opacity=".08"/><stop offset="1" stop-color="#000" stop-opacity=".32"/></linearGradient>
      <radialGradient id="${id}s" cx=".5" cy=".5" r=".5"><stop offset=".6" stop-color="#000" stop-opacity=".22"/><stop offset="1" stop-color="#000" stop-opacity="0"/></radialGradient>
    </defs>`;
    // Band oben und unten mit Naht
    s += `<path d="M71 0H129V46Q129 54 121 54H79Q71 54 71 46Z" fill="${u.band}"/><path d="M71 0H129V46Q129 54 121 54H79Q71 54 71 46Z" fill="url(#${id}b)"/>`;
    s += `<path d="M71 238H129V190Q129 182 121 182H79Q71 182 71 190Z" fill="${u.band}"/><path d="M71 238H129V190Q129 182 121 182H79Q71 182 71 190Z" fill="url(#${id}b)"/>`;
    s += `<path d="M76 0V47M124 0V47M76 238V189M124 238V189" stroke="#fff" stroke-opacity=".22" stroke-width=".7" stroke-dasharray="2.6 2.2"/>`;
    // Schatten, Hörner, Gehäuse, Krone
    s += `<circle cx="${cx + 3}" cy="${cy + 6}" r="70" fill="url(#${id}s)"/>`;
    s += `<rect x="73" y="44" width="11" height="24" rx="3" fill="url(#${id}m)"/><rect x="116" y="44" width="11" height="24" rx="3" fill="url(#${id}m)"/><rect x="73" y="164" width="11" height="24" rx="3" fill="url(#${id}m)"/><rect x="116" y="164" width="11" height="24" rx="3" fill="url(#${id}m)"/>`;
    s += `<rect x="158" y="${cy - 7}" width="9" height="14" rx="2.2" fill="url(#${id}m)"/><path d="M160.5 ${cy - 6}v12M163 ${cy - 6}v12M165.5 ${cy - 6}v12" stroke="#000" stroke-opacity=".18" stroke-width=".6"/>`;
    s += `<circle cx="${cx}" cy="${cy}" r="61" fill="url(#${id}m)"/><circle cx="${cx}" cy="${cy}" r="57.5" fill="url(#${id}r)"/>`;
    s += `<circle cx="${cx}" cy="${cy}" r="54" fill="url(#${id}d)"/>`;
    // Minuterie
    let t = '';
    for (let i = 0; i < 60; i++) { const [x1, y1] = rot(i * 6, 51.6), [x2, y2] = rot(i * 6, i % 5 ? 49.8 : 48.6); t += `M${x1.toFixed(2)} ${y1.toFixed(2)}L${x2.toFixed(2)} ${y2.toFixed(2)}`; }
    s += `<path d="${t}" stroke="${u.farbe}" stroke-opacity=".55" stroke-width=".45"/>`;
    // Indizes
    const frei = h => !((h === 6 && u.komp.includes('sekunde')) || (h === 3 && u.komp.includes('datum')) || (h === 12 && u.komp.includes('mond')) || (h === 9 && u.komp.includes('reserve')));
    const ROEM = ['XII', 'I', 'II', 'III', 'IIII', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI'];
    for (let h = 0; h < 12; h++) {
      const std = h === 0 ? 12 : h;
      if (!frei(std)) continue;
      if (u.index === 'stab' || (u.index === 'arabisch' && std % 3)) {
        const breit = h === 0 && u.index === 'stab';
        s += `<g transform="rotate(${h * 30} ${cx} ${cy})">` + (breit ? `<rect x="${cx - 2.6}" y="${cy - 47}" width="1.8" height="9.5" fill="${u.farbe}"/><rect x="${cx + .8}" y="${cy - 47}" width="1.8" height="9.5" fill="${u.farbe}"/>` : `<rect x="${cx - 1}" y="${cy - 47}" width="2" height="${u.index === 'arabisch' ? 5 : 9}" fill="${u.farbe}"/>`) + `</g>`;
      } else if (u.index === 'punkt') {
        const [x, y] = rot(h * 30, 44.5);
        s += `<circle cx="${x.toFixed(2)}" cy="${y.toFixed(2)}" r="${h % 3 ? 1.5 : 2.3}" fill="${u.farbe}"/>`;
      } else {
        const txt = u.index === 'roemisch' ? ROEM[h] : String(std), [x, y] = rot(h * 30, u.index === 'roemisch' ? 41.5 : 40.5);
        s += `<text x="${x.toFixed(2)}" y="${(y + 3.2).toFixed(2)}" text-anchor="middle" font-family="Bodoni Moda, Georgia, serif" font-size="${u.index === 'roemisch' ? 8 : 10.5}" fill="${u.farbe}">${txt}</text>`;
      }
    }
    // Schriftzug
    const sy = u.komp.includes('mond') ? cy - 6 : cy - 19;
    s += `<text x="${cx}" y="${sy}" text-anchor="middle" font-family="Instrument Sans, sans-serif" font-weight="600" font-size="4.6" letter-spacing="1.3" fill="${u.farbe}">PRIESSNITZ</text>`;
    s += `<text x="${cx}" y="${sy + 5.6}" text-anchor="middle" font-family="Instrument Sans, sans-serif" font-weight="500" font-size="2.6" letter-spacing=".9" fill="${u.farbe}" fill-opacity=".7">GLASHÜTTE I/SA</text>`;
    // Komplikationen
    if (u.komp.includes('mond')) {
      s += `<path d="M86 ${cy - 22}a14 14 0 0 1 28 0Z" fill="#14203a" stroke="${u.farbe}" stroke-opacity=".5" stroke-width=".5"/><circle cx="${cx + 3}" cy="${cy - 28}" r="4.4" fill="#e3c79a"/><circle cx="${cx - 7}" cy="${cy - 31}" r=".6" fill="#e3c79a"/><circle cx="${cx + 9}" cy="${cy - 33}" r=".5" fill="#e3c79a"/>`;
    }
    if (u.komp.includes('sekunde')) {
      const sx = cx, sy2 = cy + 25;
      let st = '';
      for (let i = 0; i < 12; i++) { const a = i * 30 * Math.PI / 180; st += `M${(sx + 11.5 * Math.sin(a)).toFixed(2)} ${(sy2 - 11.5 * Math.cos(a)).toFixed(2)}L${(sx + 9.8 * Math.sin(a)).toFixed(2)} ${(sy2 - 9.8 * Math.cos(a)).toFixed(2)}`; }
      s += `<circle cx="${sx}" cy="${sy2}" r="12.5" fill="#000" fill-opacity=".05" stroke="${u.farbe}" stroke-opacity=".4" stroke-width=".4"/><path d="${st}" stroke="${u.farbe}" stroke-width=".5"/>`;
      s += `<g transform="rotate(${(k * 47) % 360} ${sx} ${sy2})"><path d="M${sx - .35} ${sy2 + 3}L${sx} ${sy2 - 11}L${sx + .35} ${sy2 + 3}Z" fill="${u.zeiger}"/></g><circle cx="${sx}" cy="${sy2}" r="1" fill="${u.zeiger}"/>`;
    }
    if (u.komp.includes('datum')) {
      s += `<rect x="${cx + 27}" y="${cy - 5}" width="13" height="10" rx="1" fill="#fbfaf7" stroke="url(#${id}m)" stroke-width="1.2"/><text x="${cx + 33.5}" y="${cy + 2.7}" text-anchor="middle" font-family="Instrument Sans, sans-serif" font-weight="500" font-size="7" fill="#23282f">${String(3 + (k * 5) % 27)}</text>`;
    }
    if (u.komp.includes('reserve')) {
      const px = cx - 28, py = cy;
      let st = '';
      for (let i = 0; i <= 6; i++) { const a = (-60 + i * 20) * Math.PI / 180; st += `M${(px + 13 * Math.sin(a)).toFixed(2)} ${(py - 13 * Math.cos(a)).toFixed(2)}L${(px + (i % 3 ? 11.4 : 10.4) * Math.sin(a)).toFixed(2)} ${(py - (i % 3 ? 11.4 : 10.4) * Math.cos(a)).toFixed(2)}`; }
      s += `<path d="${st}" stroke="${u.farbe}" stroke-width=".55"/><text x="${px - 9}" y="${py - 1}" font-family="Instrument Sans, sans-serif" font-size="2.6" fill="${u.farbe}" text-anchor="middle">AB</text><text x="${px + 9}" y="${py - 1}" font-family="Instrument Sans, sans-serif" font-size="2.6" fill="${u.farbe}" text-anchor="middle">AUF</text>`;
      s += `<g transform="rotate(34 ${px} ${py})"><path d="M${px - .5} ${py}L${px} ${py - 11}L${px + .5} ${py}Z" fill="${u.zeiger}"/></g><circle cx="${px}" cy="${py}" r="1.2" fill="${u.zeiger}"/>`;
    }
    // Zeiger auf 10:09
    s += `<g transform="rotate(304.5 ${cx} ${cy})"><path d="M${cx} ${cy + 7}L${cx - 2.3} ${cy - 6}L${cx} ${cy - 31}L${cx + 2.3} ${cy - 6}Z" fill="${u.zeiger}"/></g>`;
    s += `<g transform="rotate(54 ${cx} ${cy})"><path d="M${cx} ${cy + 9}L${cx - 1.8} ${cy - 8}L${cx} ${cy - 46}L${cx + 1.8} ${cy - 8}Z" fill="${u.zeiger}"/></g>`;
    s += `<circle cx="${cx}" cy="${cy}" r="2.6" fill="${u.zeiger}"/><circle cx="${cx}" cy="${cy}" r=".9" fill="url(#${id}m)"/>`;
    // Glas-Reflex
    s += `<path d="M58 92A47 47 0 0 1 122 70" stroke="#fff" stroke-opacity=".28" stroke-width="7" fill="none" stroke-linecap="round"/>`;
    return s + '</svg>';
  }

  // Karten und Minuterie auf den Ring setzen
  const N = W.karten, M = UHREN.length;
  const karten = [];
  for (let i = 0; i < N; i++) {
    const u = UHREN[i % M], f = document.createElement('figure');
    f.className = 'karte'; f.style.setProperty('--a', i * W.schritt + 'deg'); f.dataset.i = i;
    f.setAttribute('role', 'group'); f.setAttribute('aria-roledescription', 'Slide');
    f.setAttribute('aria-label', `${u.name} ${u.zusatz}, Referenz ${u.ref}`);
    if (i >= M) f.setAttribute('aria-hidden', 'true');
    f.innerHTML = uhr(u, i) + `<figcaption><span>${u.ref}</span><span>${u.d.replace(' mm', '')}</span></figcaption>`;
    lauf.append(f); karten.push(f);
  }
  for (let i = 0; i < 120; i++) {
    const s = document.createElement('i');
    s.className = 'strich' + (i % 5 ? '' : ' gross'); s.style.setProperty('--a', i * 3 + 'deg');
    lauf.append(s);
  }

  // Radius aus Kartenbreite und Winkelschritt: Sehne = Kartenbreite × 1,38 (Telefon 1,1)
  let R = 900, gradProPx = 0.06;
  function mass() {
    const kw = karten[0].offsetWidth;
    R = Math.round(kw * (innerWidth <= 640 ? W.abstandMobil : W.abstand) / (2 * Math.sin(W.schritt / 2 * Math.PI / 180)));
    buehne.style.setProperty('--r', R + 'px');
    gradProPx = 180 / (Math.PI * R);
    zeigeWerte();
  }

  // Zustand
  let modus = 'bogen', aktiv = -1, laufPause = false;
  const nrEl = $('[data-nr]'), refEl = $('[data-ref]'), nameEl = $('[data-name]'), datenEl = $('[data-daten]');
  const mod = (a, n) => ((a % n) + n) % n;
  const laufWinkel = () => {
    const a = lauf.getAnimations()[0];
    return a && a.currentTime != null ? -((a.currentTime / (W.umdrehung * 1000)) % 1) * 360 : 0;
  };
  const drehung = () => gsap.getProperty(ring, 'rotation') + (modus === 'laufband' ? laufWinkel() : 0);

  function fuelle(m) {
    const u = UHREN[m];
    nrEl.textContent = String(m + 1).padStart(2, '0');
    refEl.textContent = `Ref. ${u.ref} · ${GEHAEUSE[u.gehaeuse][3]} · ${u.zifferblatt}`;
    nameEl.innerHTML = `${u.name} <em>${u.zusatz}</em>`;
    datenEl.innerHTML = `<div><dt>Kaliber</dt><dd>${u.kaliber}</dd></div><div><dt>Aufzug</dt><dd>${u.aufzug}</dd></div><div><dt>Gangreserve</dt><dd>${u.gang}</dd></div><div><dt>Durchmesser</dt><dd>${u.d}</dd></div>`;
  }
  // Text wechselt asymmetrisch: aus 200 ms, ein 300 ms
  let wechselUhr = null, erst = true;
  function pruefe() {
    const idx = mod(Math.round(-drehung() / W.schritt), N);
    if (idx === aktiv) return;
    if (aktiv >= 0) karten[aktiv].classList.remove('aktiv');
    aktiv = idx; karten[idx].classList.add('aktiv');
    if (erst || reduziert()) { erst = false; fuelle(idx % M); return; }
    if (wechselUhr) return;
    info.classList.add('wechselt');
    wechselUhr = setTimeout(() => { fuelle(aktiv % M); info.classList.remove('wechselt'); wechselUhr = null; }, 200);
  }

  // Einrasten: power3.out 700 ms auf ein Vielfaches des Winkelschritts
  function rasteEin(ziel, dauer = W.einrasten) {
    gsap.killTweensOf(ring);
    const z = Math.round(ziel / W.schritt) * W.schritt;
    if (reduziert()) { gsap.set(ring, { rotation: z }); pruefe(); return Promise.resolve(); }
    return new Promise(res => gsap.to(ring, { rotation: z, duration: dauer, ease: W.ease, onUpdate: pruefe, onComplete: res }));
  }
  const schritt = d => { if (modus !== 'bogen') setzeModus('bogen'); const r = gsap.getProperty(ring, 'rotation'); return rasteEin(Math.round(r / W.schritt) * W.schritt - d * W.schritt); };
  document.querySelectorAll('[data-schritt]').forEach(b => b.addEventListener('click', () => { stoppVorfuehrung(); schritt(+b.dataset.schritt); }));
  bogen.addEventListener('keydown', e => {
    if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
    e.preventDefault(); stoppVorfuehrung(); schritt(e.key === 'ArrowRight' ? 1 : -1);
  });

  // Ziehen: Draggable auf einem Stellvertreter, Weg in Grad umgerechnet (Karte folgt dem Finger auf der Kuppe)
  const proxy = document.createElement('div');
  let start = 0, proben = [];
  const zug = Draggable.create(proxy, {
    type: 'x', trigger: bogen, minimumMovement: 4, zIndexBoost: false,
    onPress() { stoppVorfuehrung(); gsap.killTweensOf(ring); start = gsap.getProperty(ring, 'rotation'); proben = []; },
    onDragStart() { bogen.classList.add('zieht'); },
    onDrag() {
      const r = start + (this.x - this.startX) * gradProPx;
      gsap.set(ring, { rotation: r }); pruefe();
      const t = performance.now(); proben.push([t, r]); while (proben.length > 2 && t - proben[0][0] > 100) proben.shift();
    },
    onDragEnd() {
      bogen.classList.remove('zieht');
      const r = gsap.getProperty(ring, 'rotation');
      let v = 0;
      if (proben.length > 1) { const [t0, r0] = proben[0], [t1, r1] = proben[proben.length - 1]; v = t1 > t0 ? (r1 - r0) / (t1 - t0) * 1000 : 0; }
      const wurf = Math.max(-2 * W.schritt, Math.min(2 * W.schritt, v * 0.12));   // Schwung höchstens zwei Karten
      rasteEin(r + wurf);
    },
    onClick(e) {
      const k = e.target.closest && e.target.closest('.karte');
      if (!k) return;
      const r = gsap.getProperty(ring, 'rotation'), w = mod(+k.dataset.i * W.schritt + r + 180, 360) - 180;
      rasteEin(r - w);
    }
  })[0];

  // Varianten
  const pauseKnopf = $('[data-pause]');
  let laufUhr = 0;
  function laufBild() { if (modus !== 'laufband') return; pruefe(); laufUhr = requestAnimationFrame(laufBild); }
  function setzeModus(m) {
    if (m === modus) return;
    if (m === 'bogen') {
      const r = drehung();
      cancelAnimationFrame(laufUhr);
      buehne.classList.remove('modus-laufband', 'laufband-pause'); laufPause = false;
      modus = m; gsap.set(ring, { rotation: r }); zug.enable(); rasteEin(r);
    } else {
      modus = m; zug.disable();
      gsap.killTweensOf(ring);
      buehne.classList.add('modus-laufband');
      laufBild();
    }
    pauseKnopf.setAttribute('aria-pressed', 'false'); pauseKnopf.textContent = 'Anhalten';
    document.querySelectorAll('[data-modus]').forEach(b => b.setAttribute('aria-pressed', b.dataset.modus === m));
    zeigeWerte();
  }
  document.querySelectorAll('[data-modus]').forEach(b => b.addEventListener('click', () => { stoppVorfuehrung(); setzeModus(b.dataset.modus); }));
  pauseKnopf.addEventListener('click', () => {
    laufPause = !laufPause; buehne.classList.toggle('laufband-pause', laufPause);
    pauseKnopf.setAttribute('aria-pressed', laufPause); pauseKnopf.textContent = laufPause ? 'Weiter' : 'Anhalten';
  });

  function zeigeWerte() {
    werteEl.innerHTML = modus === 'bogen'
      ? `Winkelschritt <b>${W.schritt}°</b> · Radius <b>${R} px</b> · Einrasten <b>power3.out ${W.einrasten * 1000} ms</b>`
      : `Laufband <b>${W.umdrehung} s</b> je Umdrehung · <b>linear</b> · Hover hält an` + (reduziert() ? ' · steht (reduzierte Bewegung)' : '');
  }

  // ——— Vorführung: gedachter Zeiger zieht den Bogen, dann läuft das Laufband ———
  let lauf2 = 0, vorfuehrt = false;
  const zp = { x: 0, y: 0 };
  const lebt = id => id === lauf2 && vorfuehrt;
  const warte = (ms, id) => new Promise(r => setTimeout(() => r(lebt(id)), ms));
  const zeigerAuf = (x, y) => { zp.x = x; zp.y = y; zeiger.style.transform = `translate(${x - 3}px, ${y - 2}px)`; };
  function tween(fn, dauer, ease, id) {
    if (reduziert()) { fn(1); return warte(0, id); }
    return new Promise(res => { const o = { p: 0 }; gsap.to(o, { p: 1, duration: dauer / 1000, ease, onUpdate: () => { if (!lebt(id)) { gsap.killTweensOf(o); return res(false); } fn(o.p); }, onComplete: () => res(lebt(id)) }); });
  }
  async function ziehe(dx, id) {
    const r0 = gsap.getProperty(ring, 'rotation'), x0 = zp.x;
    zeiger.classList.add('druck');
    if (!await tween(p => { zeigerAuf(x0 + dx * p, zp.y); gsap.set(ring, { rotation: r0 + dx * p * gradProPx }); pruefe(); }, Math.abs(dx) * 3.4 + 300, 'power2.inOut', id)) return false;
    zeiger.classList.remove('druck');
    await rasteEin(gsap.getProperty(ring, 'rotation'));
    return lebt(id);
  }
  async function runde(id) {
    setzeModus('bogen');
    const b = bogen.getBoundingClientRect(), mitte = b.left + b.width / 2, y = b.top + b.height * .55;
    if (reduziert()) {
      for (const d of [1, 1, -1]) { schritt(d); if (!await warte(1800, id)) return; }
      return runde(id);
    }
    if (!zp.x) zeigerAuf(mitte + b.width * .32, b.bottom + 60);
    if (!await tween((p => { const ax = zp.x, ay = zp.y; return q => zeigerAuf(ax + (mitte + 150 - ax) * q, ay + (y - ay) * q); })(), 700, W.ease, id)) return;
    if (!await ziehe(-300, id) || !await warte(900, id)) return;
    if (!await ziehe(-150, id) || !await warte(900, id)) return;
    if (!await tween((p => { const ax = zp.x; return q => zeigerAuf(ax + (mitte - 170 - ax) * q, y); })(), 600, W.ease, id)) return;
    if (!await ziehe(420, id) || !await warte(700, id)) return;
    if (!await tween((p => { const ax = zp.x, ay = zp.y; return q => zeigerAuf(ax + (mitte + b.width * .3 - ax) * q, ay + (b.bottom + 80 - ay) * q); })(), 700, W.ease, id)) return;
    setzeModus('laufband');
    if (!await warte(4800, id)) return;
    setzeModus('bogen');
    if (!await warte(900, id)) return;
    runde(id);
  }
  function stoppVorfuehrung() {
    if (!vorfuehrt) return;
    vorfuehrt = false; lauf2++; html.classList.remove('vorfuehrung'); zeiger.classList.remove('druck');
  }
  function neustart() {
    stoppVorfuehrung(); setzeModus('bogen'); gsap.killTweensOf(ring);
    gsap.set(ring, { rotation: 0 }); pruefe();
  }
  function vorfuehren() {
    neustart(); vorfuehrt = true; zp.x = 0; html.classList.add('vorfuehrung');
    runde(++lauf2);
  }
  function pause() { if (vorfuehrt) { vorfuehrt = false; lauf2++; } if (modus === 'laufband' && !laufPause) pauseKnopf.click(); }
  function weiter() { if (laufPause) pauseKnopf.click(); if (html.classList.contains('vorfuehrung') && !vorfuehrt) { vorfuehrt = true; runde(++lauf2); } }

  mass(); pruefe();
  addEventListener('resize', mass);
  document.fonts && document.fonts.ready.then(mass);

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