<script lang="ts">
  import { onMount } from "svelte";
  import WaveformDisplay from "./lib/components/WaveformDisplay.svelte";
  import VUMeter from "./lib/components/VUMeter.svelte";
  import WelcomeModal from "./lib/components/WelcomeModal.svelte";
  import ProcessorPopup from "./lib/components/ProcessorPopup.svelte";
  import { engines } from "./lib/audio/engines/registry";
  import type { SynthEngine, PitchLock } from "./lib/audio/engines/SynthEngine";
  import type { EngineType } from "./lib/audio/engines/SynthEngine";
  import { AudioService } from "./lib/audio/services/AudioService";
  import { downloadWAV } from "./lib/audio/utils/WAVEncoder";
  import { loadVolume, saveVolume, loadDuration, saveDuration, loadPitchLockEnabled, savePitchLockEnabled, loadPitchLockFrequency, savePitchLockFrequency } from "./lib/utils/settings";
  import { cropAudio, cutAudio, processSelection } from "./lib/audio/utils/AudioEdit";
  import { generateRandomColor } from "./lib/utils/colors";
  import { getRandomProcessor } from "./lib/audio/processors/registry";
  import type { AudioProcessor } from "./lib/audio/processors/AudioProcessor";
  import { Sample } from "./lib/audio/engines/Sample";
  import { Input } from "./lib/audio/engines/Input";
  import { createKeyboardHandler } from "./lib/utils/keyboard";
  import { parseFrequencyInput, formatFrequency } from "./lib/utils/pitch";
  import { UndoManager, type AudioState } from "./lib/utils/UndoManager";

  let currentEngineIndex = $state(0);
  const engine = $derived(engines[currentEngineIndex]);
  const engineType = $derived(engine.getType());
  const audioService = new AudioService();
  const undoManager = new UndoManager(20);

  let currentParams = $state<any>(null);
  let currentBuffer = $state<AudioBuffer | null>(null);
  let duration = $state(loadDuration());
  let volume = $state(loadVolume());
  let playbackPosition = $state(-1);
  let waveformColor = $state(generateRandomColor());
  let showModal = $state(true);
  let isProcessed = $state(false);
  let showProcessorPopup = $state(false);
  let popupTimeout = $state<ReturnType<typeof setTimeout> | null>(null);
  let isRecording = $state(false);
  let isDragOver = $state(false);
  let pitchLockEnabled = $state(loadPitchLockEnabled());
  let pitchLockFrequency = $state(loadPitchLockFrequency());
  let pitchLockInput = $state(formatFrequency(loadPitchLockFrequency()));
  let pitchLockInputValid = $state(true);
  let selectionStart = $state<number | null>(null);
  let selectionEnd = $state<number | null>(null);
  let canUndo = $state(false);

  const showDuration = $derived(engineType !== 'sample');
  const showRandomButton = $derived(engineType === 'generative');
  const showRecordButton = $derived(engineType === 'input');
  const showFileDropZone = $derived(engineType === 'sample' && !currentBuffer);
  const showMutateButton = $derived(engineType === 'generative' && !isProcessed && currentBuffer);
  const showPitchLock = $derived(engineType === 'generative');
  const pitchLock = $derived<PitchLock>({ enabled: pitchLockEnabled, frequency: pitchLockFrequency });
  const hasSelection = $derived(selectionStart !== null && selectionEnd !== null && currentBuffer !== null);
  const showEditButtons = $derived(hasSelection);

  $effect(() => {
    audioService.setVolume(volume);
    saveVolume(volume);
  });

  $effect(() => {
    saveDuration(duration);
  });

  $effect(() => {
    savePitchLockEnabled(pitchLockEnabled);
  });

  $effect(() => {
    savePitchLockFrequency(pitchLockFrequency);
  });

  onMount(() => {
    audioService.setPlaybackUpdateCallback((position) => {
      playbackPosition = position;
    });
    generateRandom();
  });

  function captureCurrentState(): AudioState | null {
    return UndoManager.captureState(
      currentBuffer,
      currentParams,
      isProcessed,
      waveformColor,
      currentEngineIndex
    );
  }

  function pushState(): void {
    const state = captureCurrentState();
    if (state) {
      undoManager.pushState(state);
      canUndo = true;
    }
  }

  function restoreState(state: AudioState): void {
    currentBuffer = audioService.createAudioBuffer([state.leftChannel, state.rightChannel]);
    currentParams = state.params;
    isProcessed = state.isProcessed;
    waveformColor = state.waveformColor;
    if (state.engineIndex !== currentEngineIndex) {
      currentEngineIndex = state.engineIndex;
    }
    clearSelection();
    audioService.play(currentBuffer);
  }

  function undo(): void {
    const previousState = undoManager.undo();
    if (previousState) {
      restoreState(previousState);
      canUndo = undoManager.canUndo();
    }
  }

  const keyboardHandler = createKeyboardHandler({
    onMutate: mutate,
    onRandom: generateRandom,
    onProcess: processSound,
    onDownload: download,
    onUndo: undo,
    onDurationDecrease: (large) => {
      duration = Math.max(0.05, duration - (large ? 1 : 0.05));
    },
    onDurationIncrease: (large) => {
      duration = Math.min(32, duration + (large ? 1 : 0.05));
    },
    onVolumeDecrease: (large) => {
      volume = Math.max(0, volume - (large ? 0.2 : 0.05));
    },
    onVolumeIncrease: (large) => {
      volume = Math.min(1, volume + (large ? 0.2 : 0.05));
    },
    onEscape: () => {
      if (hasSelection) {
        clearSelection();
      } else if (showModal) {
        closeModal();
      }
    },
  });

  function generateRandom() {
    pushState();

    currentParams = engine.randomParams(pitchLock);
    waveformColor = generateRandomColor();
    isProcessed = false;
    clearSelection();
    regenerateBuffer();
  }

  function mutate() {
    if (!currentParams) {
      generateRandom();
      return;
    }
    pushState();

    currentParams = engine.mutateParams(currentParams, 0.15, pitchLock);
    waveformColor = generateRandomColor();
    regenerateBuffer();
  }

  function handlePitchLockInput(event: Event) {
    const input = event.target as HTMLInputElement;
    pitchLockInput = input.value;

    const parsed = parseFrequencyInput(pitchLockInput);
    if (parsed !== null) {
      pitchLockFrequency = parsed;
      pitchLockInputValid = true;
    } else {
      pitchLockInputValid = false;
    }
  }

  function togglePitchLock() {
    pitchLockEnabled = !pitchLockEnabled;
  }

  function regenerateBuffer() {
    if (!currentParams) return;

    const sampleRate = audioService.getSampleRate();
    const data = engine.generate(currentParams, sampleRate, duration);
    currentBuffer = audioService.createAudioBuffer(data);
    audioService.play(currentBuffer);
  }

  function replaySound() {
    if (currentBuffer) {
      audioService.play(currentBuffer);
    }
  }

  function download() {
    if (!currentBuffer) return;
    downloadWAV(currentBuffer, "synth-sound.wav");
  }

  function processSound() {
    if (!currentBuffer) return;
    applyProcessor(getRandomProcessor());
  }

  async function applyProcessor(processor: AudioProcessor) {
    if (!currentBuffer) return;

    pushState();

    let processedLeft: Float32Array;
    let processedRight: Float32Array;

    if (hasSelection) {
      const start = Math.min(selectionStart!, selectionEnd!);
      const end = Math.max(selectionStart!, selectionEnd!);
      const sampleRate = audioService.getSampleRate();

      [processedLeft, processedRight] = await processSelection(
        currentBuffer,
        start,
        end,
        processor,
        sampleRate
      );
    } else {
      const leftChannel = currentBuffer.getChannelData(0);
      const rightChannel = currentBuffer.getChannelData(1);
      [processedLeft, processedRight] = await processor.process(leftChannel, rightChannel);
    }

    currentBuffer = audioService.createAudioBuffer([processedLeft, processedRight]);
    isProcessed = true;
    audioService.play(currentBuffer);
    hideProcessorPopup();
  }

  function switchEngine(index: number) {
    pushState();

    currentEngineIndex = index;
    currentBuffer = null;
    currentParams = null;
    isProcessed = false;
    clearSelection();

    if (engineType === 'generative') {
      generateRandom();
    }
  }

  async function handleFileInput(event: Event) {
    const input = event.target as HTMLInputElement;
    if (!input.files?.length) return;
    await loadAudioFile(input.files[0]);
  }

  async function loadAudioFile(file: File) {
    if (!(engine instanceof Sample)) return;

    pushState();

    try {
      await engine.loadFile(file);
      currentParams = engine.randomParams(pitchLock);
      waveformColor = generateRandomColor();
      isProcessed = false;
      regenerateBuffer();
    } catch (error) {
      console.error('Failed to load audio file:', error);
      alert(`Failed to load audio file: ${error}`);
    }
  }

  async function recordAudio() {
    if (!(engine instanceof Input) || isRecording) return;

    pushState();

    try {
      isRecording = true;
      await engine.record(duration);
      currentParams = engine.randomParams(pitchLock);
      waveformColor = generateRandomColor();
      isProcessed = false;
      regenerateBuffer();
    } catch (error) {
      console.error('Failed to record audio:', error);
      alert(`Failed to record audio: ${error}`);
    } finally {
      isRecording = false;
    }
  }

  function handleDrop(event: DragEvent) {
    event.preventDefault();
    isDragOver = false;

    const files = event.dataTransfer?.files;
    if (!files?.length) return;

    const file = files[0];
    if (!file.type.startsWith('audio/')) {
      alert('Please drop an audio file');
      return;
    }

    loadAudioFile(file);
  }

  function handleDragOver(event: DragEvent) {
    event.preventDefault();
    isDragOver = true;
  }

  function handleDragLeave(event: DragEvent) {
    event.preventDefault();
    isDragOver = false;
  }

  function showPopup() {
    if (popupTimeout) clearTimeout(popupTimeout);
    showProcessorPopup = true;
    popupTimeout = setTimeout(() => showProcessorPopup = false, 2000);
  }

  function scheduleHidePopup() {
    if (popupTimeout) clearTimeout(popupTimeout);
    popupTimeout = setTimeout(() => showProcessorPopup = false, 200);
  }

  function hideProcessorPopup() {
    if (popupTimeout) clearTimeout(popupTimeout);
    showProcessorPopup = false;
  }

  function handleSelectionChange(start: number | null, end: number | null) {
    selectionStart = start;
    selectionEnd = end;
  }

  function clearSelection() {
    selectionStart = null;
    selectionEnd = null;
  }

  function cropSelection() {
    if (!currentBuffer || selectionStart === null || selectionEnd === null) return;

    pushState();

    const start = Math.min(selectionStart, selectionEnd);
    const end = Math.max(selectionStart, selectionEnd);

    const sampleRate = audioService.getSampleRate();
    const [newLeft, newRight] = cropAudio(currentBuffer, start, end, sampleRate);

    currentBuffer = audioService.createAudioBuffer([newLeft, newRight]);
    clearSelection();
    audioService.play(currentBuffer);
  }

  function cutSelection() {
    if (!currentBuffer || selectionStart === null || selectionEnd === null) return;

    pushState();

    const start = Math.min(selectionStart, selectionEnd);
    const end = Math.max(selectionStart, selectionEnd);

    const sampleRate = audioService.getSampleRate();
    const [newLeft, newRight] = cutAudio(currentBuffer, start, end, sampleRate);

    currentBuffer = audioService.createAudioBuffer([newLeft, newRight]);
    clearSelection();
    audioService.play(currentBuffer);
  }

  async function closeModal() {
    showModal = false;
    await audioService.initialize();
  }
</script>

<svelte:window onkeydown={keyboardHandler} />

<div class="container">
  <div class="top-bar">
    <div class="mode-buttons">
      {#each engines as currentEngine, index}
        <button
          class="engine-button"
          class:active={currentEngineIndex === index}
          data-description={currentEngine.getDescription()}
          onclick={() => switchEngine(index)}
        >
          {currentEngine.getName()}
        </button>
      {/each}
    </div>
    <div class="controls-group">
      {#if showPitchLock}
        <div class="control-item pitch-lock-control">
          <div class="control-header">
            <label for="pitch">Pitch</label>
            <label class="custom-checkbox" title="Lock pitch across random/mutate">
              <input
                type="checkbox"
                bind:checked={pitchLockEnabled}
              />
              <span class="checkbox-box" class:checked={pitchLockEnabled}>
                {#if pitchLockEnabled}
                  <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                    <path d="M1 5L4 8L9 2" stroke="currentColor" stroke-width="2" stroke-linecap="square"/>
                  </svg>
                {/if}
              </span>
              <span class="checkbox-text">Lock</span>
            </label>
          </div>
          <input
            id="pitch"
            type="text"
            class="pitch-input"
            class:locked={pitchLockEnabled}
            class:invalid={!pitchLockInputValid}
            value={pitchLockInput}
            oninput={handlePitchLockInput}
            placeholder="440 or A4"
            title="Enter frequency (Hz) or note (e.g., A4, C#3)"
          />
        </div>
      {/if}
      {#if showDuration}
        <div class="control-item">
          <div class="control-header">
            <label for="duration">Duration</label>
            <span class="control-value-display">{duration.toFixed(2)}s</span>
          </div>
          <input
            id="duration"
            type="range"
            min="0.05"
            max="32"
            step="0.01"
            bind:value={duration}
          />
        </div>
      {/if}
      <div class="control-item">
        <div class="control-header">
          <label for="volume">Volume</label>
          <span class="control-value-display">{Math.round(volume * 100)}%</span>
        </div>
        <input
          id="volume"
          type="range"
          min="0"
          max="1"
          step="0.01"
          bind:value={volume}
        />
      </div>
    </div>
  </div>

  <div class="main-area">
    <div class="waveform-container">
      {#if showFileDropZone}
        <div
          class="file-drop-zone"
          class:drag-over={isDragOver}
          role="button"
          tabindex="0"
          ondrop={handleDrop}
          ondragover={handleDragOver}
          ondragleave={handleDragLeave}
        >
          <div class="drop-zone-content">
            <h2>Drop an audio file here</h2>
            <label for="file-input" class="file-input-label">
              <input
                id="file-input"
                type="file"
                accept="audio/*"
                onchange={handleFileInput}
                style="display: none;"
              />
              Choose a file
            </label>
          </div>
        </div>
      {:else}
        <WaveformDisplay
          buffer={currentBuffer}
          color={waveformColor}
          {playbackPosition}
          {selectionStart}
          {selectionEnd}
          onselectionchange={handleSelectionChange}
          onclick={replaySound}
        />
      {/if}

      <div class="bottom-controls">
        {#if showRandomButton}
          <button onclick={generateRandom}>Random (R)</button>
        {/if}
        {#if showRecordButton}
          <button onclick={recordAudio} disabled={isRecording}>
            {isRecording ? 'Recording...' : 'Record'}
          </button>
        {/if}
        {#if showMutateButton}
          <button onclick={mutate}>Mutate (M)</button>
        {/if}
        {#if showEditButtons}
          <button onclick={cropSelection}>Crop</button>
          <button onclick={cutSelection}>Cut</button>
        {/if}
        {#if currentBuffer}
          <div
            class="process-button-container"
            role="group"
            onmouseenter={showPopup}
            onmouseleave={scheduleHidePopup}
          >
            <button onclick={processSound}>Process (P)</button>
            {#if showProcessorPopup}
              <ProcessorPopup onselect={applyProcessor} />
            {/if}
          </div>
          <button onclick={download}>Download (D)</button>
          <button onclick={undo} disabled={!canUndo}>Undo (Z)</button>
        {/if}
      </div>
    </div>
    <div class="vu-meter-container">
      <VUMeter buffer={currentBuffer} {playbackPosition} />
    </div>
  </div>

  {#if showModal}
    <WelcomeModal onclose={closeModal} />
  {/if}
</div>

<style>
  .container {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
  }

  .top-bar {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.5rem;
    background-color: #1a1a1a;
    border-bottom: 1px solid #333;
  }

  .mode-buttons {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: #444 transparent;
    padding-bottom: 0.25rem;
  }

  .mode-buttons::-webkit-scrollbar {
    height: 4px;
  }

  .mode-buttons::-webkit-scrollbar-track {
    background: transparent;
  }

  .mode-buttons::-webkit-scrollbar-thumb {
    background: #444;
    border-radius: 0;
  }

  .engine-button {
    opacity: 0.7;
    position: relative;
    flex-shrink: 0;
    font-size: 0.85rem;
    padding: 0.5rem 0.75rem;
    white-space: nowrap;
    min-width: calc(25vw - 1rem);
  }

  .engine-button:hover {
    z-index: 1001;
  }

  .engine-button.active {
    opacity: 1;
    border-color: #646cff;
  }

  .engine-button::after {
    content: attr(data-description);
    position: absolute;
    top: 100%;
    left: 0;
    padding: 0.5rem 0.75rem;
    background-color: #0a0a0a;
    border: 1px solid #444;
    color: #ccc;
    font-size: 0.85rem;
    width: 200px;
    max-width: 90vw;
    white-space: normal;
    word-wrap: break-word;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
    z-index: 1000;
    display: none;
  }

  .controls-group {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: 100%;
  }

  .control-item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    background-color: #0f0f0f;
    padding: 0.5rem 0.65rem;
    border: 1px solid #2a2a2a;
    transition: border-color 0.2s;
  }

  .control-item:hover {
    border-color: #3a3a3a;
  }

  .control-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
  }

  .control-header label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #999;
    font-weight: 500;
    white-space: nowrap;
  }

  .control-value-display {
    font-size: 0.8rem;
    color: #fff;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 3.5rem;
    text-align: right;
  }

  .control-item input[type="range"] {
    width: 100%;
    margin: 0;
  }

  .custom-checkbox {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    cursor: pointer;
    user-select: none;
  }

  .custom-checkbox input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
  }

  .checkbox-box {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border: 1px solid #3a3a3a;
    background-color: #1a1a1a;
    transition: all 0.2s;
    color: #0a0a0a;
  }

  .checkbox-box.checked {
    background-color: #646cff;
    border-color: #646cff;
    color: #fff;
  }

  .custom-checkbox:hover .checkbox-box {
    border-color: #4a4a4a;
  }

  .custom-checkbox:hover .checkbox-box.checked {
    background-color: #535bf2;
    border-color: #535bf2;
  }

  .checkbox-text {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #999;
    font-weight: 500;
  }

  .custom-checkbox:hover .checkbox-text {
    color: #aaa;
  }

  .pitch-input {
    width: 100%;
    min-width: 0;
    padding: 0.35rem 0.5rem;
    background-color: #1a1a1a;
    border: 1px solid #3a3a3a;
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
    font-variant-numeric: tabular-nums;
    box-sizing: border-box;
  }

  .pitch-input:focus {
    outline: none;
    border-color: #646cff;
    background-color: #0a0a0a;
  }

  .pitch-input.locked {
    border-color: #646cff;
    background-color: #0a0a0a;
    box-shadow: 0 0 0 1px rgba(100, 108, 255, 0.2);
  }

  .pitch-input.locked:focus {
    box-shadow: 0 0 0 1px rgba(100, 108, 255, 0.4);
  }

  .pitch-input.invalid {
    border-color: #ff4444;
    box-shadow: 0 0 0 1px rgba(255, 68, 68, 0.2);
  }

  .pitch-input::placeholder {
    color: #555;
    font-weight: 400;
  }

  @media (min-width: 640px) {
    .controls-group {
      flex-direction: row;
      flex-wrap: wrap;
    }

    .control-item {
      min-width: 140px;
      flex: 1;
    }

    .pitch-lock-control {
      min-width: 160px;
    }

    .control-item input[type="range"] {
      min-width: 80px;
    }
  }

  @media (min-width: 768px) {
    .top-bar {
      flex-direction: row;
      justify-content: space-between;
      align-items: center;
      gap: 1rem;
    }

    .mode-buttons {
      flex: 1;
      overflow-x: auto;
      padding-bottom: 0;
      max-width: 60%;
    }

    .engine-button {
      font-size: 0.9rem;
      padding: 0.6rem 1rem;
      min-width: auto;
    }

    .engine-button::after {
      display: block;
      width: 250px;
    }

    .engine-button:hover::after {
      opacity: 1;
    }

    .controls-group {
      width: auto;
      flex-shrink: 0;
      gap: 0.5rem;
      flex-wrap: nowrap;
    }

    .control-item {
      min-width: 120px;
      padding: 0.45rem 0.6rem;
    }

    .pitch-lock-control {
      min-width: 140px;
    }

    .control-header label {
      font-size: 0.7rem;
    }

    .control-value-display {
      font-size: 0.75rem;
      min-width: 3rem;
    }

    .checkbox-text {
      font-size: 0.65rem;
    }

    .checkbox-box {
      width: 13px;
      height: 13px;
    }

    .checkbox-box svg {
      width: 9px;
      height: 9px;
    }

    .pitch-input {
      font-size: 0.8rem;
      padding: 0.3rem 0.45rem;
    }

    .control-item input[type="range"] {
      min-width: 70px;
    }
  }

  @media (min-width: 1024px) {
    .mode-buttons {
      max-width: 65%;
    }

    .control-item {
      min-width: 140px;
      padding: 0.5rem 0.65rem;
    }

    .pitch-lock-control {
      min-width: 160px;
    }

    .control-header label {
      font-size: 0.75rem;
    }

    .control-value-display {
      font-size: 0.8rem;
      min-width: 3.5rem;
    }

    .checkbox-text {
      font-size: 0.7rem;
    }

    .checkbox-box {
      width: 14px;
      height: 14px;
    }

    .checkbox-box svg {
      width: 10px;
      height: 10px;
    }

    .pitch-input {
      font-size: 0.85rem;
      padding: 0.35rem 0.5rem;
    }

    .control-item input[type="range"] {
      min-width: 90px;
    }
  }

  @media (min-width: 1280px) {
    .control-item {
      min-width: 160px;
    }

    .pitch-lock-control {
      min-width: 180px;
    }

    .control-item input[type="range"] {
      min-width: 110px;
    }
  }

  .main-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    background-color: #0a0a0a;
    overflow: hidden;
  }

  .waveform-container {
    flex: 1;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    min-height: 200px;
  }

  .vu-meter-container {
    width: 100%;
    height: 60px;
    border-top: 1px solid #333;
  }

  .bottom-controls {
    position: absolute;
    bottom: 1rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    padding: 0 0.5rem;
    max-width: 95%;
  }

  .bottom-controls button {
    font-size: 0.85rem;
    padding: 0.5rem 0.75rem;
    white-space: nowrap;
  }

  .process-button-container {
    position: relative;
  }

  @media (min-width: 768px) {
    .main-area {
      flex-direction: row;
    }

    .waveform-container {
      min-height: auto;
    }

    .vu-meter-container {
      width: 5%;
      min-width: 50px;
      max-width: 80px;
      height: auto;
      border-left: 1px solid #333;
      border-top: none;
    }

    .bottom-controls {
      gap: 0.75rem;
      bottom: 1.5rem;
    }

    .bottom-controls button {
      font-size: 0.9rem;
      padding: 0.6rem 1rem;
    }
  }

  @media (min-width: 1024px) {
    .bottom-controls {
      gap: 1rem;
      bottom: 2rem;
    }

    .bottom-controls button {
      font-size: 1rem;
      padding: 0.75rem 1.25rem;
    }
  }

  input[type="range"] {
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
    height: 20px;
    border-radius: 0;
  }

  input[type="range"]::-webkit-slider-track {
    background: #333;
    height: 4px;
    border: 1px solid #444;
    border-radius: 0;
  }

  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background: #fff;
    border: 1px solid #000;
    border-radius: 0;
    cursor: pointer;
    margin-top: -6px;
  }

  input[type="range"]::-webkit-slider-thumb:hover {
    background: #ddd;
  }

  input[type="range"]::-moz-range-track {
    background: #333;
    height: 4px;
    border: 1px solid #444;
    border-radius: 0;
  }

  input[type="range"]::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: #fff;
    border: 1px solid #000;
    border-radius: 0;
    cursor: pointer;
  }

  input[type="range"]::-moz-range-thumb:hover {
    background: #ddd;
  }

  .file-drop-zone {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px dashed #444;
    background-color: #0a0a0a;
    transition: all 0.2s;
    padding: 1rem;
  }

  .file-drop-zone.drag-over {
    border-color: #646cff;
    background-color: #1a1a1a;
  }

  .drop-zone-content {
    text-align: center;
    color: #ccc;
  }

  .drop-zone-content h2 {
    font-size: 1.2rem;
    margin-bottom: 0.75rem;
    color: #fff;
  }

  .file-input-label {
    display: inline-block;
    padding: 0.65rem 1.25rem;
    background-color: #646cff;
    color: #fff;
    border: 1px solid #646cff;
    cursor: pointer;
    transition: background-color 0.2s;
    font-size: 0.95rem;
  }

  .file-input-label:hover {
    background-color: #535bf2;
  }

  @media (min-width: 768px) {
    .drop-zone-content h2 {
      font-size: 1.5rem;
      margin-bottom: 1rem;
    }

    .file-input-label {
      padding: 0.75rem 1.5rem;
      font-size: 1rem;
    }
  }

  button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
</style>
