* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    padding: 20px;
}

.container {
    max-width: 1600px;
    margin: 0 auto;
    background: white;
    border-radius: 20px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    overflow: hidden;
}

header {
    background: linear-gradient(to right, #4a6fa5, #2c5282);
    color: white;
    padding: 30px;
    text-align: center;
}

header h1 {
    font-size: 2.5rem;
    margin-bottom: 10px;
}

header p {
    font-size: 1.1rem;
    opacity: 0.9;
}

.main-content {
    display: flex;
    min-height: 700px;
}

.left-panel {
    width: 35%;
    background: #f7fafc;
    padding: 25px;
    border-right: 2px solid #e2e8f0;
    display: flex;
    flex-direction: column;
    gap: 25px;
}

.right-panel {
    width: 65%;
    padding: 25px;
    background: white;
    display: flex;
    flex-direction: column;
}

.file-upload-section h2,
.controls-section h2,
.voices-section h2,
.score-header h2 {
    color: #2d3748;
    margin-bottom: 15px;
    font-size: 1.4rem;
    border-bottom: 2px solid #4a6fa5;
    padding-bottom: 8px;
}

.upload-area {
    border: 3px dashed #cbd5e0;
    border-radius: 12px;
    padding: 40px 20px;
    text-align: center;
    cursor: pointer;
    transition: all 0.3s;
    background: white;
    position: relative;
}

.upload-area:hover {
    border-color: #4a6fa5;
    background: #f0f7ff;
}

#fileInput {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    opacity: 0;
    cursor: pointer;
}

.upload-prompt {
    pointer-events: none;
}

.upload-icon {
    font-size: 48px;
    display: block;
    margin-bottom: 15px;
}

.file-info {
    font-size: 0.9rem;
    color: #718096;
    margin-top: 10px;
}

.sample-files {
    margin-top: 20px;
}

.sample-buttons {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.sample-btn {
    padding: 10px 20px;
    background: #4a6fa5;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.3s;
    flex: 1;
    min-width: 120px;
}

.sample-btn:hover {
    background: #2c5282;
}

.control-group {
    background: white;
    padding: 20px;
    border-radius: 12px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.transport-controls {
    display: flex;
    gap: 10px;
    margin-bottom: 25px;
}

.control-btn {
    padding: 12px 24px;
    font-size: 1rem;
    background: #4a6fa5;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.control-btn:hover {
    background: #2c5282;
    transform: translateY(-2px);
}

.control-btn:active {
    transform: translateY(0);
}

.slider-control {
    margin-bottom: 20px;
}

.slider-control label {
    display: block;
    margin-bottom: 8px;
    color: #4a5568;
    font-weight: 500;
}

.slider-control input[type="range"] {
    width: 100%;
    height: 8px;
    border-radius: 4px;
    background: #e2e8f0;
    outline: none;
    -webkit-appearance: none;
}

.slider-control input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #4a6fa5;
    cursor: pointer;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

.info-display {
    background: #edf2f7;
    padding: 15px;
    border-radius: 8px;
    margin-top: 20px;
}

.info-item {
    display: flex;
    justify-content: space-between;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid #cbd5e0;
}

.info-item:last-child {
    margin-bottom: 0;
    border-bottom: none;
}

.info-item span:first-child {
    font-weight: 600;
    color: #4a5568;
}

.info-item span:last-child {
    color: #2d3748;
}

.voices-list {
    background: white;
    padding: 20px;
    border-radius: 12px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    max-height: 200px;
    overflow-y: auto;
}

.voice-item {
    display: flex;
    align-items: center;
    margin-bottom: 12px;
    padding: 10px;
    background: #f8fafc;
    border-radius: 6px;
    transition: background 0.3s;
}

.voice-item:hover {
    background: #e6fffa;
}

.voice-item input[type="checkbox"] {
    margin-right: 12px;
    width: 18px;
    height: 18px;
}

.voice-item label {
    flex: 1;
    cursor: pointer;
    color: #2d3748;
    font-weight: 500;
}

.score-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}

.score-info {
    display: flex;
    align-items: center;
    gap: 20px;
}

.system-nav {
    display: flex;
    gap: 10px;
}

.nav-btn {
    padding: 8px 16px;
    background: #4a6fa5;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.3s;
}

.nav-btn:hover {
    background: #2c5282;
}

.score-container {
    flex: 1;
    background: #f8fafc;
    border: 2px solid #e2e8f0;
    border-radius: 12px;
    overflow: auto;
    padding: 20px;
    min-height: 500px;
    display: flex;
    align-items: center;
    justify-content: center;
}

#vexflowOutput {
    width: 100%;
    overflow-x: auto;
}

.progress-container {
    margin-top: 20px;
    padding: 15px;
    background: #f8fafc;
    border-radius: 12px;
}

.progress-bar {
    width: 100%;
    height: 10px;
    background: #e2e8f0;
    border-radius: 5px;
    overflow: hidden;
    margin-bottom: 10px;
}

.progress-fill {
    height: 100%;
    background: linear-gradient(to right, #4a6fa5, #2c5282);
    width: 0%;
    transition: width 0.1s linear;
}

.time-display {
    display: flex;
    justify-content: space-between;
    color: #4a5568;
    font-weight: 500;
}

.status-bar {
    background: #2d3748;
    color: white;
    padding: 15px 30px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.loading-indicator {
    display: flex;class MusicXMLPlayer {
    constructor() {
        this.VF = Vex.Flow;
        this.scoreData = null;
        this.currentSystem = 0;
        this.totalSystems = 1;
        this.isPlaying = false;
        this.isPaused = false;
        this.startTime = 0;
        this.pausedTime = 0;
        this.tempo = 120;
        this.voices = [];
        this.activeVoices = new Set();
        this.synth = null;
        this.scheduleId = null;
        this.currentNoteIndex = 0;
        this.totalNotes = 0;
        this.noteEvents = [];
        
        this.init();
    }

    init() {
        this.initUI();
        this.initAudio();
        this.loadSampleFile();
    }

    initUI() {
        // File input handler
        document.getElementById('fileInput').addEventListener('change', (e) => {
            this.loadFile(e.target.files[0]);
        });

        // Drop handler
        const dropArea = document.getElementById('dropArea');
        dropArea.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropArea.style.borderColor = '#4a6fa5';
            dropArea.style.background = '#e6f7ff';
        });

        dropArea.addEventListener('dragleave', () => {
            dropArea.style.borderColor = '#cbd5e0';
            dropArea.style.background = 'white';
        });

        dropArea.addEventListener('drop', (e) => {
            e.preventDefault();
            dropArea.style.borderColor = '#cbd5e0';
            dropArea.style.background = 'white';
            
            const files = e.dataTransfer.files;
            if (files.length > 0) {
                this.loadFile(files[0]);
            }
        });

        // Sample buttons
        document.querySelectorAll('.sample-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const fileName = e.target.dataset.file;
                this.loadSampleFile(fileName);
            });
        });

        // Transport controls
        document.getElementById('playBtn').addEventListener('click', () => this.play());
        document.getElementById('pauseBtn').addEventListener('click', () => this.pause());
        document.getElementById('stopBtn').addEventListener('click', () => this.stop());

        // Tempo slider
        const tempoSlider = document.getElementById('tempoSlider');
        const tempoValue = document.getElementById('tempoValue');
        tempoSlider.addEventListener('input', (e) => {
            this.tempo = parseInt(e.target.value);
            tempoValue.textContent = this.tempo;
            if (this.isPlaying) {
                this.stop();
                this.play();
            }
        });

        // Volume slider
        const volumeSlider = document.getElementById('volumeSlider');
        const volumeValue = document.getElementById('volumeValue');
        volumeSlider.addEventListener('input', (e) => {
            const volume = parseInt(e.target.value) / 100;
            volumeValue.textContent = Math.round(volume * 100);
            if (this.synth) {
                this.synth.volume.value = 20 * Math.log10(volume);
            }
        });

        // System navigation
        document.getElementById('prevSystem').addEventListener('click', () => this.prevSystem());
        document.getElementById('nextSystem').addEventListener('click', () => this.nextSystem());

        // Update status
        this.updateStatus('Bereit');
    }

    initAudio() {
        // Initialize Tone.js
        Tone.start();
        this.synth = new Tone.PolySynth(Tone.Synth, {
            oscillator: {
                type: 'triangle'
            },
            envelope: {
                attack: 0.005,
                decay: 0.1,
                sustain: 0.3,
                release: 0.5
            }
        }).toDestination();

        this.synth.volume.value = -6; // Default volume
    }

    async loadFile(file) {
        if (!file) return;

        this.updateStatus('Lade Datei...', true);
        
        try {
            const text = await file.text();
            await this.parseMusicXML(text);
            this.updateStatus('Datei erfolgreich geladen');
        } catch (error) {
            console.error('Error loading file:', error);
            this.updateStatus('Fehler beim Laden der Datei', false, true);
        }
    }

    async loadSampleFile(fileName = 'sample1.xml') {
        this.updateStatus('Lade Beispieldatei...', true);
        
        try {
            // Simple sample music data for demonstration
            const sampleXML = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.0">
  <work>
    <work-title>Beispielmelodie</work-title>
  </work>
  <identification>
    <creator type="composer">Demo Komponist</creator>
  </identification>
  <part-list>
    <score-part id="P1">
      <part-name>Klavier</part-name>
    </score-part>
  </part-list>
  <part id="P1">
    <measure number="1">
      <attributes>
        <divisions>24</divisions>
        <key>
          <fifths>0</fifths>
        </key>
        <time>
          <beats>4</beats>
          <beat-type>4</beat-type>
        </time>
        <clef>
          <sign>G</sign>
          <line>2</line>
        </clef>
      </attributes>
      <note>
        <pitch>
          <step>C</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>E</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>F</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
    </measure>
    <measure number="2">
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
      <note>
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <duration>24</duration>
        <type>quarter</type>
      </note>
    </measure>
  </part>
</score-partwise>`;
            
            await this.parseMusicXML(sampleXML);
            this.updateStatus('Beispieldatei geladen');
        } catch (error) {
            console.error('Error loading sample:', error);
            this.updateStatus('Fehler beim Laden der Beispieldatei', false, true);
        }
    }

    async parseMusicXML(xmlText) {
        try {
            const parser = new DOMParser();
            const xmlDoc = parser.parseFromString(xmlText, "text/xml");
            
            // Extract metadata
            const title = xmlDoc.querySelector('work-title')?.textContent || 'Unbekannt';
            const composer = xmlDoc.querySelector('creator[type="composer"]')?.textContent || 'Unbekannt';
            
            document.getElementById('songTitle').textContent = title;
            document.getElementById('songComposer').textContent = composer;
            
            // Parse notes
            this.parseNotes(xmlDoc);
            
            // Render score
            this.renderScore();
            
        } catch (error) {
            console.error('Error parsing MusicXML:', error);
            throw error;
        }
    }

    parseNotes(xmlDoc) {
        this.voices = [];
        this.noteEvents = [];
        
        const parts = xmlDoc.querySelectorAll('part');
        
        parts.forEach((part, partIndex) => {
            const partName = part.querySelector('part-name')?.textContent || `Stimme ${partIndex + 1}`;
            const notes = [];
            
            // Get divisions per quarter note
            const divisions = parseInt(part.querySelector('divisions')?.textContent) || 24;
            
            // Parse measures
            part.querySelectorAll('measure').forEach(measure => {
                measure.querySelectorAll('note').forEach(note => {
                    const pitch = note.querySelector('pitch');
                    const rest = note.querySelector('rest');
                    const duration = parseInt(note.querySelector('duration')?.textContent) || 24;
                    
                    if (pitch) {
                        const step = pitch.querySelector('step').textContent;
                        const octave = parseInt(pitch.querySelector('octave').textContent);
                        const alter = pitch.querySelector('alter');
                        const accidental = alter ? parseInt(alter.textContent) : 0;
                        
                        const noteObj = {
                            type: 'note',
                            step: step,
                            octave: octave,
                            accidental: accidental,
                            duration: duration,
                            durationInSeconds: (duration / divisions) * (60 / this.tempo),
                            isRest: false
                        };
                        
                        notes.push(noteObj);
                        this.noteEvents.push({
                            ...noteObj,
                            partIndex: partIndex,
                            time: 0 // Will be calculated later
                        });
                    } else if (rest) {
                        notes.push({
                            type: 'rest',
                            duration: duration,
                            durationInSeconds: (duration / divisions) * (60 / this.tempo),
                            isRest: true
                        });
                    }
                });
            });
            
            this.voices.push({
                name: partName,
                notes: notes,
                active: true
            });
            
            this.activeVoices.add(partIndex);
        });
        
        // Calculate cumulative times for note events
        let currentTime = 0;
        this.noteEvents.forEach(event => {
            event.time = currentTime;
            currentTime += event.durationInSeconds;
        });
        
        this.totalNotes = this.noteEvents.length;
        
        // Update UI
        this.updateVoicesList();
        document.getElementById('voiceCount').textContent = this.voices.length;
    }

    updateVoicesList() {
        const voicesList = document.getElementById('voicesList');
        voicesList.innerHTML = '';
        
        this.voices.forEach((voice, index) => {
            const voiceItem = document.createElement('div');
            voiceItem.className = 'voice-item';
            
            const checkboxId = `voice-${index}`;
            voiceItem.innerHTML = `
                <input type="checkbox" id="${checkboxId}" ${voice.active ? 'checked' : ''}>
                <label for="${checkboxId}">${voice.name}</label>
            `;
            
            const checkbox = voiceItem.querySelector('input');
            checkbox.addEventListener('change', (e) => {
                if (e.target.checked) {
                    this.activeVoices.add(index);
                } else {
                    this.activeVoices.delete(index);
                }
            });
            
            voicesList.appendChild(voiceItem);
        });
    }

    renderScore() {
        const container = document.getElementById('vexflowOutput');
        container.innerHTML = '';
        
        const renderer = new this.VF.Renderer(container, this.VF.Renderer.Backends.SVG);
        const width = Math.max(800, container.clientWidth - 40);
        renderer.resize(width, 400);
        const context = renderer.getContext();
        
        const staveWidth = width - 100;
        const stave = new this.VF.Stave(50, 50, staveWidth);
        
        // Set clef and time signature
        stave.addClef("treble");
        stave.addTimeSignature("4/4");
        
        stave.setContext(context).draw();
        
        // Create notes for display
        const notes = [];
        this.voices[0]?.notes.forEach(noteData => {
            if (noteData.isRest) {
                notes.push(new this.VF.StaveNote({
                    keys: ["b/4"],
                    duration: "q",
                    clef: "treble"
                }).setStyle({ fillStyle: "transparent", strokeStyle: "transparent" }));
            } else {
                const key = `${noteData.step.toLowerCase()}${noteData.octave}`;
                let note = new this.VF.StaveNote({
                    keys: [key],
                    duration: "q",
                    clef: "treble"
                });
                
                if (noteData.accidental !== 0) {
                    note.addAccidental(0, new this.VF.Accidental(noteData.accidental > 0 ? "#" : "b"));
                }
                
                notes.push(note);
            }
        });
        
        // Create voice and format
        const voice = new this.VF.Voice({ num_beats: 4, beat_value: 4 });
        voice.addTickables(notes);
        
        new this.VF.Formatter().joinVoices([voice]).format([voice], staveWidth - 100);
        
        voice.draw(context, stave);
    }

    play() {
        if (this.isPlaying && !this.isPaused) return;
        
        if (this.isPaused) {
            // Resume from pause
            this.isPaused = false;
            this.startTime = Tone.now() - this.pausedTime;
        } else {
            // Start from beginning
            this.isPlaying = true;
            this.isPaused = false;
            this.startTime = Tone.now();
            this.pausedTime = 0;
            this.currentNoteIndex = 0;
            
            // Clear any existing schedule
            if (this.scheduleId) {
                Tone.Transport.clear(this.scheduleId);
            }
            
            // Schedule notes
            this.scheduleId = Tone.Transport.scheduleRepeat((time) => {
                this.playNextNote(time);
            }, "8n");
        }
        
        Tone.Transport.start();
        this.updateStatus('Spielt ab...');
        this.updatePlaybackProgress();
    }

    playNextNote(time) {
        if (this.currentNoteIndex >= this.noteEvents.length) {
            this.stop();
            return;
        }
        
        const noteEvent = this.noteEvents[this.currentNoteIndex];
        
        if (!noteEvent.isRest && this.activeVoices.has(noteEvent.partIndex)) {
            const noteName = this.getNoteName(noteEvent.step, noteEvent.octave, noteEvent.accidental);
            this.synth.triggerAttackRelease(noteName, noteEvent.durationInSeconds, time);
        }
        
        this.currentNoteIndex++;
        
        // Update progress
        const progress = (this.currentNoteIndex / this.noteEvents.length) * 100;
        document.getElementById('progressFill').style.width = `${progress}%`;
        
        const currentTime = noteEvent.time;
        const minutes = Math.floor(currentTime / 60);
        const seconds = Math.floor(currentTime % 60);
        document.getElementById('currentTime').textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
    }

    getNoteName(step, octave, accidental) {
        let note = step;
        if (accidental > 0) note += '#';
        if (accidental < 0) note += 'b';
        return note + octave;
    }

    pause() {
        if (!this.isPlaying) return;
        
        if (this.isPaused) {
            // Already paused, resume
            this.play();
        } else {
            this.isPaused = true;
            this.pausedTime = Tone.now() - this.startTime;
            Tone.Transport.pause();
            this.updateStatus('Pausiert');
        }
    }

    stop() {
        this.isPlaying = false;
        this.isPaused = false;
        this.currentNoteIndex = 0;
        
        Tone.Transport.stop();
        Tone.Transport.cancel();
        
        // Reset progress
        document.getElementById('progressFill').style.width = '0%';
        document.getElementById('currentTime').textContent = '0:00';
        
        this.updateStatus('Gestoppt');
    }

    updatePlaybackProgress() {
        if (!this.isPlaying || this.isPaused) return;
        
        const elapsed = Tone.now() - this.startTime;
        const totalDuration = this.noteEvents.reduce((sum, event) => sum + event.durationInSeconds, 0);
        
        const progress = (elapsed / totalDuration) * 100;
        document.getElementById('progressFill').style.width = `${Math.min(100, progress)}%`;
        
        // Update current time display
        const minutes = Math.floor(elapsed / 60);
        const seconds = Math.floor(elapsed % 60);
        document.getElementById('currentTime').textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
        
        // Update total time
        const totalMinutes = Math.floor(totalDuration / 60);
        const totalSeconds = Math.floor(totalDuration % 60);
        document.getElementById('totalTime').textContent = `${totalMinutes}:${totalSeconds.toString().padStart(2, '0')}`;
        
        requestAnimationFrame(() => this.updatePlaybackProgress());
    }

    prevSystem() {
        if (this.currentSystem > 0) {
            this.currentSystem--;
            this.updateSystemDisplay();
        }
    }

    nextSystem() {
        if (this.currentSystem < this.totalSystems - 1) {
            this.currentSystem++;
            this.updateSystemDisplay();
        }
    }

    updateSystemDisplay() {
        document.getElementById('currentSystem').textContent = this.currentSystem + 1;
        document.getElementById('totalSystems').textContent = this.totalSystems;
    }

    updateStatus(message, loading = false, error = false) {
        const statusElement = document.getElementById('statusMessage');
        const loadingElement = document.getElementById('loadingIndicator');
        
        statusElement.textContent = message;
        statusElement.style.color = error ? '#e53e3e' : '#2d3748';
        
        if (loading) {
            loadingElement.style.display = 'flex';
        } else {
            loadingElement.style.display = 'none';
        }
    }
}

// Initialize the application when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    window.musicPlayer = new MusicXMLPlayer();
});
    align-items: center;
    gap: 10px;
}

.spinner {
    width: 20px;
    height: 20px;
    border: 3px solid rgba(255, 255, 255, 0.3);
    border-top: 3px solid white;
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

@media (max-width: 1200px) {
    .main-content {
        flex-direction: column;
    }
    
    .left-panel, .right-panel {
        width: 100%;
    }
    
    .left-panel {
        border-right: none;
        border-bottom: 2px solid #e2e8f0;
    }
}