<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Stereo Air — Electronic Pop • Retro Future</title>
<meta name="description" content="Stereo Air — electronic pop with retro future vibes. Music, videos, live, press & contact." />
<!-- Open Graph -->
<meta property="og:title" content="Stereo Air" />
<meta property="og:description" content="Electronic Pop • Retro Future — Listen, watch, book." />
<meta property="og:type" content="website" />
<style>
:root{
--bg:#07090f;
--panel: rgba(255,255,255,.06);
--panel2: rgba(255,255,255,.09);
--text: rgba(255,255,255,.92);
--muted: rgba(255,255,255,.70);
--faint: rgba(255,255,255,.45);
--line: rgba(255,255,255,.12);
--accent: #9ff3ff;
--accent2:#c6b4ff;
--good:#8dffb3;
--warn:#ffd28d;
--shadow: 0 18px 60px rgba(0,0,0,.55);
--radius: 18px;
--radius2: 28px;
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji","Segoe UI Emoji";
}
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
font-family: var(--sans);
color: var(--text);
background:
radial-gradient(1200px 800px at 10% 10%, rgba(159,243,255,.18), transparent 60%),
radial-gradient(900px 700px at 80% 20%, rgba(198,180,255,.16), transparent 55%),
radial-gradient(900px 700px at 40% 90%, rgba(141,255,179,.10), transparent 55%),
linear-gradient(180deg, #050610 0%, #07090f 60%, #050610 100%);
overflow-x:hidden;
}
a{color:inherit}
.wrap{max-width:1100px;margin:0 auto;padding:28px 18px 64px}
header{
position:sticky; top:0; z-index:20;
backdrop-filter: blur(10px);
background: linear-gradient(180deg, rgba(7,9,15,.88), rgba(7,9,15,.55));
border-bottom: 1px solid var(--line);
}
.nav{
max-width:1100px;margin:0 auto;
display:flex;align-items:center;justify-content:space-between;
padding:14px 18px;
gap:14px;
}
.brand{
display:flex;align-items:center;gap:12px;text-decoration:none;
letter-spacing:.08em;text-transform:uppercase;
font-weight:700;
}
.logo{
width:34px;height:34px;border-radius:12px;
background: radial-gradient(circle at 30% 30%, rgba(159,243,255,.95), rgba(198,180,255,.75) 45%, rgba(255,255,255,.10) 75%);
box-shadow: 0 12px 35px rgba(159,243,255,.10);
border: 1px solid rgba(255,255,255,.18);
}
.navlinks{
display:flex;flex-wrap:wrap;gap:10px;align-items:center;justify-content:flex-end;
}
.navlinks a{
text-decoration:none;
padding:8px 10px;
border-radius:12px;
color:var(--muted);
border:1px solid transparent;
}
.navlinks a:hover{
color:var(--text);
border-color:var(--line);
background: rgba(255,255,255,.04);
}
.cta{
display:flex;gap:10px;align-items:center;
}
.btn{
display:inline-flex;align-items:center;justify-content:center;
gap:10px;
padding:10px 12px;
border-radius:14px;
background: rgba(255,255,255,.06);
border:1px solid rgba(255,255,255,.14);
text-decoration:none;
color:var(--text);
box-shadow: 0 10px 30px rgba(0,0,0,.25);
transition: transform .12s ease, background .12s ease;
white-space:nowrap;
}
.btn:hover{transform: translateY(-1px); background: rgba(255,255,255,.08)}
.btn.primary{
background: linear-gradient(135deg, rgba(159,243,255,.22), rgba(198,180,255,.18));
border-color: rgba(159,243,255,.35);
}
.pill{
font-family: var(--mono);
font-size:12px;
padding:6px 10px;
border-radius:999px;
border:1px solid rgba(255,255,255,.14);
color:var(--muted);
background: rgba(255,255,255,.04);
}
.hero{
padding:44px 0 22px;
display:grid;
grid-template-columns: 1.2fr .8fr;
gap:18px;
align-items:stretch;
}
.card{
background: var(--panel);
border:1px solid var(--line);
border-radius: var(--radius2);
box-shadow: var(--shadow);
}
.hero-left{padding:26px}
h1{
margin:0 0 10px;
font-size: clamp(34px, 5vw, 56px);
letter-spacing:.02em;
line-height:1.05;
}
.sub{
margin:0 0 16px;
color:var(--muted);
max-width:60ch;
font-size: 16px;
line-height:1.5;
}
.tags{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0 0}
.grid{
display:grid;
grid-template-columns: repeat(12, 1fr);
gap:14px;
margin-top:14px;
}
.span-6{grid-column: span 6}
.span-4{grid-column: span 4}
.span-8{grid-column: span 8}
.span-12{grid-column: span 12}
section{margin-top:18px}
.section-title{
padding:14px 16px;
display:flex;align-items:center;justify-content:space-between;
border-bottom:1px solid var(--line);
}
.section-title h2{
margin:0;font-size:14px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)
}
.content{padding:16px}
.kicker{
font-family: var(--mono);
font-size:12px;
color: var(--faint);
}
.two-col{display:grid;grid-template-columns: 1fr 1fr; gap:14px}
.list{
display:flex;flex-direction:column;gap:10px
}
.item{
padding:12px 12px;
border-radius: 16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.10);
}
.item strong{display:block;margin-bottom:4px}
.item .meta{color:var(--muted);font-size:14px;line-height:1.4}
.muted{color:var(--muted)}
.small{font-size:13px;color:var(--muted);line-height:1.55}
.divider{height:1px;background:var(--line);margin:14px 0}
/* Player */
.player{
padding:18px;
display:flex;
flex-direction:column;
gap:12px;
}
.np{
display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
}
.np .title{font-weight:700;font-size:16px}
.np .artist{color:var(--muted);font-size:13px}
.art{
width:54px;height:54px;border-radius:16px;
background: radial-gradient(circle at 30% 30%, rgba(159,243,255,.85), rgba(198,180,255,.55) 55%, rgba(255,255,255,.06) 80%);
border:1px solid rgba(255,255,255,.16);
box-shadow: 0 14px 40px rgba(0,0,0,.35);
flex:0 0 auto;
}
.controls{
display:flex;align-items:center;gap:10px;flex-wrap:wrap
}
.iconbtn{
width:44px;height:44px;border-radius:16px;
background: rgba(255,255,255,.06);
border:1px solid rgba(255,255,255,.14);
display:inline-flex;align-items:center;justify-content:center;
cursor:pointer;
transition: transform .12s ease, background .12s ease;
user-select:none;
}
.iconbtn:hover{transform: translateY(-1px); background: rgba(255,255,255,.08)}
.iconbtn.primary{
width:54px;height:54px;border-radius:20px;
background: linear-gradient(135deg, rgba(159,243,255,.22), rgba(198,180,255,.18));
border-color: rgba(159,243,255,.35);
}
.bar{
display:flex;align-items:center;gap:10px;
width:100%;
}
.time{font-family:var(--mono);font-size:12px;color:var(--muted);min-width:92px;text-align:center}
input[type="range"]{
-webkit-appearance:none;
appearance:none;
width:100%;
height:8px;
border-radius:999px;
background: rgba(255,255,255,.12);
outline:none;
cursor:pointer;
}
input[type="range"]::-webkit-slider-thumb{
-webkit-appearance:none;
appearance:none;
width:16px;height:16px;border-radius:999px;
background: rgba(255,255,255,.92);
border: 2px solid rgba(159,243,255,.45);
box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.vol{
display:flex;align-items:center;gap:10px;
width:220px;max-width:100%;
margin-left:auto;
}
.playlist{
display:flex;flex-direction:column;gap:8px;
padding-top:6px;
}
.track{
display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:10px 12px;
border-radius: 16px;
background: rgba(255,255,255,.03);
border: 1px solid rgba(255,255,255,.10);
cursor:pointer;
}
.track:hover{background: rgba(255,255,255,.05)}
.track.active{
border-color: rgba(159,243,255,.35);
background: linear-gradient(135deg, rgba(159,243,255,.10), rgba(198,180,255,.06));
}
.track .left{display:flex;flex-direction:column;gap:2px}
.track .name{font-weight:650}
.track .info{font-size:12px;color:var(--muted);font-family:var(--mono)}
.track .dur{font-family:var(--mono);font-size:12px;color:var(--muted)}
/* Footer */
footer{
margin-top:26px;
padding-top:18px;
border-top:1px solid var(--line);
color:var(--muted);
font-size:13px;
display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
}
.socials{display:flex;gap:10px;flex-wrap:wrap}
.socials a{
text-decoration:none;
padding:8px 10px;
border-radius:12px;
border:1px solid rgba(255,255,255,.12);
background: rgba(255,255,255,.04);
}
.socials a:hover{background: rgba(255,255,255,.06)}
.note{
border-left: 3px solid rgba(159,243,255,.35);
padding:10px 12px;
border-radius: 14px;
background: rgba(255,255,255,.04);
color: var(--muted);
font-size: 13px;
line-height: 1.5;
}
@media (max-width: 920px){
.hero{grid-template-columns:1fr; padding-top:22px}
.two-col{grid-template-columns:1fr}
.span-6,.span-4,.span-8{grid-column: span 12}
.vol{margin-left:0; width:100%}
.nav{flex-wrap:wrap}
.cta{width:100%; justify-content:flex-start}
}
</style>
</head>
<body>
<header>
<nav class="nav" aria-label="Hauptnavigation">
<a class="brand" href="#top">
<span class="logo" aria-hidden="true"></span>
<span>Stereo Air</span>
<span class="pill">Electronic Pop</span>
</a>
<div class="navlinks">
<a href="#music">Music</a>
<a href="#video">Video</a>
<a href="#live">Live</a>
<a href="#press">Press</a>
<a href="#contact">Contact</a>
</div>
<div class="cta">
<a class="btn primary" href="#contact" title="Booking / Kontakt">Booking</a>
<a class="btn" href="#music" title="Direkt zum Player">Listen</a>
</div>
</nav>
</header>
<main id="top" class="wrap">
<div class="hero">
<div class="card hero-left">
<div class="kicker">Retro future. French touch energy. Berlin night air.</div>
<h1>Stereo Air</h1>
<p class="sub">
Elektronischer Pop mit Retro-Vibes, klaren Hooks und dieser einen Mischung aus
<strong>urbaner Nacht</strong> und <strong>luftiger Melancholie</strong>, die du angeblich “zufällig”
auf Repeat hörst.
</p>
<div class="tags" aria-label="Tags">
<span class="pill">Synth Pop</span>
<span class="pill">French Touch</span>
<span class="pill">Berlin / Paris</span>
<span class="pill">Live & DJ Hybrid</span>
<span class="pill">Licensing ready</span>
</div>
<div class="divider"></div>
<div class="two-col">
<div class="item">
<strong>Next Release</strong>
<div class="meta">Single: <em>“Night Passenger”</em> • <span class="muted">TBA</span></div>
</div>
<div class="item">
<strong>For Bookings</strong>
<div class="meta">Email: <a href="mailto:booking@stereoair.com">booking@stereoair.com</a></div>
</div>
</div>
<div class="divider"></div>
<div class="note">
<strong>Hinweis:</strong> Diese Seite ist absichtlich „clean“. Du kannst später Merch, EPK-Download,
Newsletter-Double-Opt-In, Spotify-Widget, Bandsintown etc. dranhängen, wenn du Lust auf mehr Formulare hast.
</div>
</div>
<aside class="card" id="music" aria-label="Media Player">
<div class="section-title">
<h2>Music Player</h2>
<span class="pill" id="playerStatus">ready</span>
</div>
<div class="player">
<div class="np">
<div style="display:flex;gap:12px;align-items:center">
<div class="art" id="art" aria-hidden="true"></div>
<div>
<div class="title" id="nowTitle">—</div>
<div class="artist" id="nowMeta">Stereo Air</div>
</div>
</div>
<div class="pill" id="nowTag">00:00</div>
</div>
<div class="controls" aria-label="Player Controls">
<button class="iconbtn" id="prevBtn" aria-label="Previous track" title="Previous">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M7 6v12M19 6l-10 6 10 6V6z" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button class="iconbtn primary" id="playBtn" aria-label="Play/Pause" title="Play/Pause">
<svg id="playIcon" width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M9 7l10 5-10 5V7z" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button class="iconbtn" id="nextBtn" aria-label="Next track" title="Next">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M17 6v12M5 6l10 6-10 6V6z" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<span class="pill" id="qualityPill">MP3</span>
<div class="vol" aria-label="Volume">
<span class="pill" aria-hidden="true">VOL</span>
<input id="volRange" type="range" min="0" max="1" step="0.01" value="0.9" aria-label="Volume slider" />
</div>
</div>
<div class="bar" aria-label="Timeline">
<span class="time" id="curTime">00:00</span>
<input id="seekRange" type="range" min="0" max="1000" step="1" value="0" aria-label="Seek slider" />
<span class="time" id="durTime">00:00</span>
</div>
<div class="playlist" id="playlist" aria-label="Playlist"></div>
<audio id="audio" preload="metadata" crossorigin="anonymous"></audio>
<div class="small">
Tipp: Lege deine Audiodateien in <code>media/</code> ab (z.B. <code>media/track1.mp3</code>)
und trage sie unten in der Playlist ein.
</div>
</div>
</aside>
</div>
<div class="grid">
<section class="card span-6" id="about">
<div class="section-title">
<h2>About</h2>
<span class="pill">Short bio</span>
</div>
<div class="content">
<p class="muted" style="margin-top:0;line-height:1.6">
<strong>Stereo Air</strong> ist ein elektronisches Popprojekt zwischen <em>Paris-Flair</em> und <em>Berlin-Nacht</em>:
analoge Wärme, moderne Kante, klare Vocals und dieses Gefühl, dass ein Song gleichzeitig
nach Club, Autofahrt und Kopfkino klingen darf.
</p>
<div class="two-col">
<div class="item">
<strong>Sound</strong>
<div class="meta">Synth Pop • Nu-Disco • French Touch • Dreamy Hooks</div>
</div>
<div class="item">
<strong>Use Cases</strong>
<div class="meta">Sync • Trailer • Fashion • Doku • Games (ja, wirklich)</div>
</div>
</div>
<div class="divider"></div>
<div class="item">
<strong>One-liner</strong>
<div class="meta"><em>“Airy synth pop for neon nights.”</em></div>
</div>
</div>
</section>
<section class="card span-6" id="video">
<div class="section-title">
<h2>Video</h2>
<span class="pill">Embed</span>
</div>
<div class="content">
<div class="item">
<strong>Music Video / Visualizer</strong>
<div class="meta">
Ersetze den Iframe-Link durch deinen YouTube/Vimeo Embed.
</div>
</div>
<div style="margin-top:12px;border-radius:18px;overflow:hidden;border:1px solid rgba(255,255,255,.12)">
<!-- Beispiel-Embed: ersetzen -->
<iframe
title="Stereo Air Visualizer"
width="100%" height="315"
src="about:blank"
style="border:0;background:rgba(255,255,255,.03)"
loading="lazy"
referrerpolicy="no-referrer"
></iframe>
</div>
<div class="small" style="margin-top:10px">
Wenn du hier was sehen willst: in <code>src</code> eine echte Embed-URL eintragen.
</div>
</div>
</section>
<section class="card span-6" id="live">
<div class="section-title">
<h2>Live</h2>
<span class="pill">Dates</span>
</div>
<div class="content">
<div class="list">
<div class="item">
<strong>Berlin • Venue TBA</strong>
<div class="meta">TBA • Doors 20:00 • Set 45–60 min</div>
</div>
<div class="item">
<strong>Paris • Showcase</strong>
<div class="meta">TBA • Hybrid Live/DJ</div>
</div>
<div class="item">
<strong>Festivals / Brand Events</strong>
<div class="meta">Bookings open • Rider auf Anfrage</div>
</div>
</div>
</div>
</section>
<section class="card span-6" id="press">
<div class="section-title">
<h2>Press / EPK</h2>
<span class="pill">Assets</span>
</div>
<div class="content">
<div class="two-col">
<div class="item">
<strong>Press Quote</strong>
<div class="meta">„…ein Sound wie Neonlicht auf nassem Asphalt.“ <span class="muted">— Placeholder Magazine</span></div>
</div>
<div class="item">
<strong>EPK</strong>
<div class="meta">
<a class="btn" href="#" onclick="alert('EPK-Link eintragen.');return false;">Download EPK</a>
</div>
</div>
</div>
<div class="divider"></div>
<div class="item">
<strong>Tech Notes</strong>
<div class="meta">
Stereo Out • In-Ear optional • Stageplot auf Anfrage • Backing Tracks möglich
</div>
</div>
</div>
</section>
<section class="card span-12" id="contact">
<div class="section-title">
<h2>Contact</h2>
<span class="pill">Booking / Sync</span>
</div>
<div class="content">
<div class="two-col">
<div class="item">
<strong>Booking</strong>
<div class="meta"><a href="mailto:booking@stereoair.com">booking@stereoair.com</a></div>
</div>
<div class="item">
<strong>Sync / Licensing</strong>
<div class="meta"><a href="mailto:sync@stereoair.com">sync@stereoair.com</a></div>
</div>
</div>
<div class="divider"></div>
<div class="item">
<strong>Socials</strong>
<div class="meta">
<span class="socials">
<a href="#" title="Instagram (Link eintragen)">Instagram</a>
<a href="#" title="YouTube (Link eintragen)">YouTube</a>
<a href="#" title="Spotify (Link eintragen)">Spotify</a>
<a href="#" title="Apple Music (Link eintragen)">Apple Music</a>
<a href="#" title="SoundCloud (Link eintragen)">SoundCloud</a>
</span>
</div>
</div>
</div>
</section>
</div>
<footer>
<div>© <span id="year"></span> Stereo Air • <span class="muted">All rights reserved (weil Menschen).</span></div>
<div class="muted">
<a href="#" onclick="alert('Impressum/Datenschutz-Link eintragen.');return false;">Impressum</a> ·
<a href="#" onclick="alert('Datenschutz-Link eintragen.');return false;">Datenschutz</a>
</div>
</footer>
</main>
<script>
// ========= Stereo Air One-Page Player =========
// Trage hier deine echten Files/URLs ein.
// Empfehlung: Lege MP3s in /media/ ab und nutze relative Pfade wie "media/track1.mp3".
const tracks = [
{
title: "Night Passenger",
meta: "Single • 2026",
src: "media/night-passenger.mp3",
tag: "Synth Pop"
},
{
title: "Neon Balcony",
meta: "EP • 2026",
src: "media/neon-balcony.mp3",
tag: "Nu-Disco"
},
{
title: "Rue des Échos",
meta: "Demo • 2025",
src: "media/rue-des-echos.mp3",
tag: "French Touch"
}
];
const $ = (sel) => document.querySelector(sel);
const audio = $("#audio");
const playBtn = $("#playBtn");
const prevBtn = $("#prevBtn");
const nextBtn = $("#nextBtn");
const playIcon = $("#playIcon");
const seekRange = $("#seekRange");
const volRange = $("#volRange");
const curTime = $("#curTime");
const durTime = $("#durTime");
const nowTitle = $("#nowTitle");
const nowMeta = $("#nowMeta");
const nowTag = $("#nowTag");
const playerStatus = $("#playerStatus");
const playlistEl = $("#playlist");
let idx = 0;
let isSeeking = false;
function fmtTime(sec){
if (!isFinite(sec) || sec < 0) return "00:00";
const m = Math.floor(sec / 60);
const s = Math.floor(sec % 60);
return String(m).padStart(2,"0") + ":" + String(s).padStart(2,"0");
}
function setStatus(text){
playerStatus.textContent = text;
}
function renderPlaylist(){
playlistEl.innerHTML = "";
tracks.forEach((t, i) => {
const row = document.createElement("div");
row.className = "track" + (i === idx ? " active" : "");
row.setAttribute("role", "button");
row.setAttribute("tabindex", "0");
row.setAttribute("aria-label", "Play " + t.title);
row.innerHTML = `
<div class="left">
<div class="name">${t.title}</div>
<div class="info">${t.meta} • ${t.tag}</div>
</div>
<div class="dur" id="dur-${i}">--:--</div>
`;
row.addEventListener("click", () => loadTrack(i, true));
row.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
loadTrack(i, true);
}
});
playlistEl.appendChild(row);
});
}
async function probeDurations(){
// Optional: versucht die Dauer pro Track zu laden (funktioniert, wenn Files erreichbar sind)
tracks.forEach((t, i) => {
const tmp = new Audio();
tmp.preload = "metadata";
tmp.src = t.src;
tmp.addEventListener("loadedmetadata", () => {
const el = document.getElementById("dur-" + i);
if (el) el.textContent = fmtTime(tmp.duration);
});
tmp.addEventListener("error", () => {
const el = document.getElementById("dur-" + i);
if (el) el.textContent = "--:--";
});
});
}
function setPlayIcon(playing){
playIcon.innerHTML = playing
? `<path d="M8 6h3v12H8zM13 6h3v12h-3z" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>`
: `<path d="M9 7l10 5-10 5V7z" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>`;
}
function highlightActive(){
[...document.querySelectorAll(".track")].forEach((el, i) => {
el.classList.toggle("active", i === idx);
});
}
function loadTrack(i, autoplay=false){
idx = (i + tracks.length) % tracks.length;
const t = tracks[idx];
nowTitle.textContent = t.title;
nowMeta.textContent = "Stereo Air • " + t.meta;
nowTag.textContent = t.tag;
setStatus("loading");
audio.src = t.src;
audio.load();
highlightActive();
if (autoplay){
audio.play().then(() => {
setStatus("playing");
setPlayIcon(true);
}).catch(() => {
// Autoplay wird oft geblockt, weil Browser Menschen hasst.
setStatus("ready");
setPlayIcon(false);
});
} else {
setStatus("ready");
setPlayIcon(false);
}
}
function togglePlay(){
if (!audio.src){
loadTrack(idx, true);
return;
}
if (audio.paused){
audio.play().then(() => {
setStatus("playing");
setPlayIcon(true);
}).catch(() => {
setStatus("ready");
setPlayIcon(false);
});
} else {
audio.pause();
setStatus("paused");
setPlayIcon(false);
}
}
// Events
playBtn.addEventListener("click", togglePlay);
prevBtn.addEventListener("click", () => loadTrack(idx - 1, true));
nextBtn.addEventListener("click", () => loadTrack(idx + 1, true));
volRange.addEventListener("input", () => {
audio.volume = Number(volRange.value);
});
seekRange.addEventListener("input", () => {
isSeeking = true;
const pct = Number(seekRange.value) / 1000;
const target = pct * (audio.duration || 0);
curTime.textContent = fmtTime(target);
});
seekRange.addEventListener("change", () => {
const pct = Number(seekRange.value) / 1000;
if (audio.duration){
audio.currentTime = pct * audio.duration;
}
isSeeking = false;
});
audio.addEventListener("loadedmetadata", () => {
durTime.textContent = fmtTime(audio.duration);
setStatus(audio.paused ? "ready" : "playing");
});
audio.addEventListener("timeupdate", () => {
if (!isSeeking && audio.duration){
const pct = (audio.currentTime / audio.duration) * 1000;
seekRange.value = String(Math.floor(pct));
curTime.textContent = fmtTime(audio.currentTime);
}
});
audio.addEventListener("ended", () => loadTrack(idx + 1, true));
audio.addEventListener("play", () => { setStatus("playing"); setPlayIcon(true); });
audio.addEventListener("pause", () => { setStatus("paused"); setPlayIcon(false); });
audio.addEventListener("error", () => {
setStatus("missing file?");
// Wenn hier "missing file?" steht: Pfad/Dateiname stimmt nicht oder Server liefert nix.
});
// Keyboard shortcuts (weil praktisch)
window.addEventListener("keydown", (e) => {
const tag = (e.target && e.target.tagName) ? e.target.tagName.toLowerCase() : "";
if (tag === "input" || tag === "textarea") return;
if (e.key === " "){
e.preventDefault();
togglePlay();
}
if (e.key === "ArrowRight") loadTrack(idx + 1, true);
if (e.key === "ArrowLeft") loadTrack(idx - 1, true);
});
// Init
$("#year").textContent = new Date().getFullYear();
audio.volume = Number(volRange.value);
renderPlaylist();
probeDurations();
loadTrack(0, false);
</script>
</body>
</html>