# Settings Modal Redesign — Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Redesign the PulseJT settings modal with glassmorphism styling, add Playback and Background tabs, merge Help into Info, and improve responsiveness.

**Architecture:** Extend the existing 4-tab settings modal to 5 tabs by adding Playback (relocated volume + new controls) and Background tabs, merging Help/Contact into Info. All changes are in 3 files: `index.html` (markup), `style.css` (styles), and `JS/bundle.js` (logic). No build system — edit files directly. The `assets/` copies are mirrored at the end.

**Tech Stack:** HTML5, CSS3 (custom properties, backdrop-filter, grid), vanilla ES5 JavaScript (IIFE pattern, no modules), localStorage for persistence.

---

## Important Context

- This is a CEP extension — no test framework, no build system, no npm. Verify changes visually in After Effects or a browser at `localhost:8092`.
- All JS must be ES5 compatible (no `let`, `const`, arrow functions, template literals, etc.).
- The IIFE wraps all code: `(function() { 'use strict'; ... })()`.
- Storage keys use `STORAGE_KEYS` object at `JS/bundle.js:1114-1134`.
- Tab switching logic is in `initSettingsModal()` at `JS/bundle.js:4396-4544`.
- The `#drop` element is the preview area whose background we'll customize.
- Always mirror `index.html` -> `assets/index.html` and `style.css` -> `assets/style.css` at the end.

---

### Task 1: Add New Storage Keys to bundle.js

**Files:**
- Modify: `JS/bundle.js:1114-1134` (STORAGE_KEYS object)

**Step 1: Add new keys to STORAGE_KEYS**

In `JS/bundle.js`, find the `STORAGE_KEYS` object (around line 1114) and add the new keys after `PERFORMANCE_MODE`:

```javascript
  var STORAGE_KEYS = {
    LAST_MEDIA_PATH: 'gifPreview.lastMediaPath',
    LAST_MEDIA_THUMB: 'gifPreview.lastMediaThumb',
    LAST_MEDIA_DATA: 'gifPreview.lastMediaData',
    LAST_MEDIA_TYPE: 'gifPreview.lastMediaType',
    LAST_MEDIA_NAME: 'gifPreview.lastMediaName',
    FIT_MODE: 'gifPreview.fitMode',
    UI_HIDDEN: 'gifPreview.uiHidden',
    PAN_X: 'gifPreview.panX',
    PAN_Y: 'gifPreview.panY',
    SCALE: 'gifPreview.scale',
    THEME: 'gifPreview.theme',
    AUDIO_MUTED: 'gifPreview.audioMuted',
    VOLUME: 'gifPreview.volume',
    LAST_VERSION: 'gifPreview.lastSeenVersion',
    CORNERS_ENABLED: 'gifPreview.cornersEnabled',
    BEVEL_ENABLED: 'gifPreview.bevelEnabled',
    HISTORY_LIMIT: 'gifPreview.historyLimit',
    ERRORS_DISABLED: 'gifPreview.errorsDisabled',
    PERFORMANCE_MODE: 'gifPreview.performanceMode',
    PLAYBACK_SPEED: 'gifPreview.playbackSpeed',
    LOOP_ENABLED: 'gifPreview.loopEnabled',
    AUTOPLAY: 'gifPreview.autoplay',
    BG_TYPE: 'gifPreview.bgType',
    BG_COLOR: 'gifPreview.bgColor',
    BG_CHECKER_SIZE: 'gifPreview.bgCheckerSize',
    BG_CHECKER_VARIANT: 'gifPreview.bgCheckerVariant',
    BG_IMAGE: 'gifPreview.bgImage',
    BG_IMAGE_FIT: 'gifPreview.bgImageFit',
    BG_IMAGE_OPACITY: 'gifPreview.bgImageOpacity'
  };
```

**Step 2: Verify no syntax errors**

Open DevTools at `localhost:8092` and confirm the console shows `Starting PulseJT v3.3` without errors.

**Step 3: Commit**

```bash
git add JS/bundle.js
git commit -m "feat: add storage keys for playback and background settings"
```

---

### Task 2: Restructure HTML — Tab Buttons

**Files:**
- Modify: `index.html:132-150` (settingsTabs section)

**Step 1: Replace the 4-tab bar with 5 tabs**

Find the `settingsTabs` div (line 132-150) and replace it with:

```html
          <!-- Tabs -->
          <div class="settingsTabs">
            <button class="settingsTab active" data-tab="general">
              <span class="tab-icon">&#9881;</span>
              <span class="tab-label">General</span>
            </button>
            <button class="settingsTab" data-tab="playback">
              <span class="tab-icon">&#9654;</span>
              <span class="tab-label">Playback</span>
            </button>
            <button class="settingsTab" data-tab="background">
              <span class="tab-icon">&#9638;</span>
              <span class="tab-label">Backdrop</span>
            </button>
            <button class="settingsTab" data-tab="history">
              <span class="tab-icon">&#128194;</span>
              <span class="tab-label">History</span>
            </button>
            <button class="settingsTab" data-tab="info">
              <span class="tab-icon">&#8505;</span>
              <span class="tab-label">Info</span>
            </button>
          </div>
```

Note: Using HTML entities instead of emoji ensures consistent rendering across CEP versions. `&#9881;` = gear, `&#9654;` = play triangle, `&#9638;` = filled square, `&#128194;` = folder, `&#8505;` = info.

**Step 2: Verify tabs render**

Open the panel settings modal. All 5 tabs should appear. Only General will work (others are not wired yet).

**Step 3: Commit**

```bash
git add index.html
git commit -m "feat: add Playback and Background tabs to settings modal"
```

---

### Task 3: Restructure HTML — Move Volume to Playback Tab, Add New Controls

**Files:**
- Modify: `index.html:152-354` (settingsPanel content area)

**Step 1: Remove the volume control from the General tab**

In the General tab page (`data-page="general"`), find and remove the entire volume control section (the `settingRow value-setting` div that contains `volumeControl`, `volumeMuteBtn`, etc. — lines 322-353). Keep the three toggle rows (Rounded Corners, Disable Error Messages, Performance Mode).

**Step 2: Add the Playback tab page after General's closing div**

Insert this new tab page right after the General tab page's closing `</div>` (which is currently around line 354), and before the History tab:

```html
            <!-- PLAYBACK TAB -->
            <div class="settingsTabPage" data-page="playback">

              <!-- Volume Control (moved from General) -->
              <div class="settingRow value-setting">
                <label>Video Volume</label>
                <div class="volume-control-container">
                  <div class="volume-icon-wrapper">
                    <button id="volumeMuteBtn" class="volume-mute-btn" title="Mute/Unmute">
                      <span class="volume-icon">&#128266;</span>
                    </button>
                  </div>
                  <div class="volume-slider-wrapper">
                    <input type="range" id="volumeControl" min="0" max="1" step="0.01" value="1" class="volume-slider">
                    <div class="volume-track">
                      <div class="volume-progress"></div>
                    </div>
                    <div class="volume-ticks">
                      <div class="tick"></div>
                      <div class="tick"></div>
                      <div class="tick"></div>
                      <div class="tick"></div>
                      <div class="tick"></div>
                    </div>
                  </div>
                  <div class="volume-value-wrapper">
                    <span class="volume-percentage">100%</span>
                    <div class="volume-bars">
                      <div class="bar"></div>
                      <div class="bar"></div>
                      <div class="bar"></div>
                    </div>
                  </div>
                </div>
                <div class="volume-feedback" id="volumeFeedback"></div>
              </div>

              <!-- Playback Speed -->
              <div class="settingRow">
                <label>Playback Speed</label>
                <div class="settingHelp">Adjust video and GIF playback rate</div>
                <div class="speed-selector" id="speedSelector">
                  <button class="speed-btn" data-speed="0.25">0.25x</button>
                  <button class="speed-btn" data-speed="0.5">0.5x</button>
                  <button class="speed-btn" data-speed="0.75">0.75x</button>
                  <button class="speed-btn active" data-speed="1">1x</button>
                  <button class="speed-btn" data-speed="1.5">1.5x</button>
                  <button class="speed-btn" data-speed="2">2x</button>
                </div>
              </div>

              <!-- Loop Toggle -->
              <div class="settingRow">
                <label class="toggle-label" style="justify-content: space-between; width: 100%;">
                  <span class="toggle-text">Loop Playback</span>
                  <div class="toggle-container">
                    <input type="checkbox" id="loopToggle" checked>
                    <div class="toggle-slider">
                      <div class="toggle-thumb"></div>
                    </div>
                  </div>
                </label>
                <div class="settingHelp">When off, media plays once and stops on last frame</div>
              </div>

              <!-- Autoplay Toggle -->
              <div class="settingRow">
                <label class="toggle-label" style="justify-content: space-between; width: 100%;">
                  <span class="toggle-text">Autoplay</span>
                  <div class="toggle-container">
                    <input type="checkbox" id="autoplayToggle" checked>
                    <div class="toggle-slider">
                      <div class="toggle-thumb"></div>
                    </div>
                  </div>
                </label>
                <div class="settingHelp">When off, media loads paused until you click to play</div>
              </div>

            </div>
```

**Step 3: Add the Background tab page after Playback**

Insert this right after the Playback tab's closing `</div>` and before the History tab:

```html
            <!-- BACKGROUND TAB -->
            <div class="settingsTabPage" data-page="background">

              <!-- Background Type Selector -->
              <div class="settingRow">
                <label>Background Type</label>
                <div class="settingHelp">Choose what appears behind your media</div>
                <div class="bg-type-selector" id="bgTypeSelector">
                  <button class="bg-type-btn active" data-bg="default">Default</button>
                  <button class="bg-type-btn" data-bg="color">Color</button>
                  <button class="bg-type-btn" data-bg="checker">Checker</button>
                  <button class="bg-type-btn" data-bg="image">Image</button>
                </div>
              </div>

              <!-- Solid Color Options (hidden by default) -->
              <div class="settingRow bg-options" id="bgColorOptions" style="display: none;">
                <label>Background Color</label>
                <div class="color-picker-row">
                  <input type="color" id="bgColorPicker" value="#000000" class="color-input">
                  <input type="text" id="bgColorHex" value="#000000" maxlength="7" class="hex-input" placeholder="#000000">
                </div>
              </div>

              <!-- Checkerboard Options (hidden by default) -->
              <div class="settingRow bg-options" id="bgCheckerOptions" style="display: none;">
                <label>Checkerboard Size</label>
                <div class="bg-type-selector" id="checkerSizeSelector">
                  <button class="bg-type-btn active" data-size="small">Small (8px)</button>
                  <button class="bg-type-btn" data-size="large">Large (16px)</button>
                </div>
                <div style="margin-top: 12px;">
                  <label class="toggle-label" style="justify-content: space-between; width: 100%;">
                    <span class="toggle-text">Dark Variant</span>
                    <div class="toggle-container">
                      <input type="checkbox" id="checkerVariantToggle" checked>
                      <div class="toggle-slider">
                        <div class="toggle-thumb"></div>
                      </div>
                    </div>
                  </label>
                </div>
              </div>

              <!-- Custom Image Options (hidden by default) -->
              <div class="settingRow bg-options" id="bgImageOptions" style="display: none;">
                <label>Background Image</label>
                <div class="settingHelp">Upload an image to use as the preview backdrop</div>
                <div class="bg-image-upload">
                  <button id="bgImageUploadBtn" class="bg-upload-btn">Choose Image</button>
                  <input type="file" id="bgImageFile" accept="image/*" style="display: none;">
                  <span class="bg-image-name" id="bgImageName">No image selected</span>
                  <button id="bgImageClearBtn" class="bg-clear-btn" style="display: none;" title="Remove image">&#10005;</button>
                </div>
                <div style="margin-top: 12px;">
                  <label>Fit Mode</label>
                  <div class="bg-type-selector" id="bgImageFitSelector">
                    <button class="bg-type-btn active" data-fit="cover">Cover</button>
                    <button class="bg-type-btn" data-fit="tile">Tile</button>
                  </div>
                </div>
                <div style="margin-top: 12px;">
                  <label>Opacity</label>
                  <div class="bg-opacity-row">
                    <input type="range" id="bgImageOpacity" min="0" max="1" step="0.01" value="1" class="volume-slider">
                    <span class="bg-opacity-value" id="bgOpacityValue">100%</span>
                  </div>
                </div>
              </div>

            </div>
```

**Step 4: Merge Help/Contact content into Info tab**

Find the Info tab page (`data-page="info"`, around line 366). After the Terms of Use `infoLicense` div and before the closing `</div>` of the `infoPage`, add the Help content:

```html
                <div class="infoDivider"></div>

                <!-- Discord (merged from Help tab) -->
                <h2 class="infoTitle">Support</h2>
                <p class="contactText" style="margin-bottom: 12px;">
                  Join our Discord for support, bug reports, and updates!
                </p>
                <button id="discordContact" class="discordCard" onclick="openDiscordServer()">
                  <div class="discordIconWrapper">
                    <svg class="discordIcon" viewBox="0 0 24 24" width="48" height="48">
                      <path fill="currentColor" d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/>
                    </svg>
                  </div>
                  <div class="discordInfo">
                    <div class="discordName">Join our Discord</div>
                    <div class="discordStatus">discord.gg/D279vpncWC</div>
                  </div>
                </button>

                <div class="infoDivider"></div>

                <!-- Quick Tips (merged from Help tab) -->
                <div class="contactHelpSection">
                  <h3 class="contactHelpTitle">Quick Tips</h3>
                  <ul class="contactHelpList">
                    <li>Drag & drop any image or video to preview it</li>
                    <li>Use mouse wheel to zoom in/out</li>
                    <li>Click and drag to pan around</li>
                    <li>Press Home button to recenter</li>
                    <li>Press ESC to exit fullscreen mode</li>
                  </ul>
                </div>

                <div class="infoDivider"></div>

                <!-- Debug Logs (merged from Help tab) -->
                <div class="contactHelpSection">
                  <h3 class="contactHelpTitle">Debug Logs</h3>
                  <p class="contactText" style="margin-bottom: 12px;">
                    Export logs to help troubleshoot issues. Include these when reporting bugs.
                  </p>
                  <div class="log-export-buttons">
                    <button id="btnExportLogs" class="log-btn log-btn-primary" title="Download log file">
                      <span class="log-btn-icon">&#128229;</span>
                      <span class="log-btn-text">Download Logs</span>
                    </button>
                    <button id="btnCopyLogs" class="log-btn log-btn-secondary" title="Copy logs to clipboard">
                      <span class="log-btn-icon">&#128203;</span>
                      <span class="log-btn-text">Copy to Clipboard</span>
                    </button>
                    <button id="btnClearLogs" class="log-btn log-btn-danger" title="Clear all logs">
                      <span class="log-btn-icon">&#128465;</span>
                      <span class="log-btn-text">Clear</span>
                    </button>
                  </div>
                  <div class="log-count" id="logCount">0 log entries</div>
                </div>
```

**Step 5: Remove the old Help/Contact tab page entirely**

Delete the entire `<div class="settingsTabPage" data-page="contact">...</div>` block (was lines 431-486).

**Step 6: Verify**

Open settings modal — General should show theme + toggles (no volume). The old Contact tab should be gone. New Playback/Background tabs won't have styling yet but should render content when clicked.

**Step 7: Commit**

```bash
git add index.html
git commit -m "feat: add Playback/Background tab content, merge Help into Info"
```

---

### Task 4: Update Tab Switching Logic in bundle.js

**Files:**
- Modify: `JS/bundle.js:4396-4544` (initSettingsModal function)

**Step 1: Update the Help tab log count listener**

In `initSettingsModal()`, find the section that binds the log count update to the Help tab (around line 4538-4544):

```javascript
    // Update log count when Help tab is opened
    var helpTab = document.querySelector('.settingsTab[data-tab="contact"]');
    if (helpTab) {
      helpTab.addEventListener('click', function() {
        setTimeout(updateLogCount, 50);
      });
    }
```

Replace with:

```javascript
    // Update log count when Info tab is opened (logs merged from Help)
    var infoTab = document.querySelector('.settingsTab[data-tab="info"]');
    if (infoTab) {
      infoTab.addEventListener('click', function() {
        setTimeout(updateLogCount, 50);
      });
    }
```

**Step 2: Verify**

Click the Info tab in settings. The log count should update. No errors in console.

**Step 3: Commit**

```bash
git add JS/bundle.js
git commit -m "fix: update log count listener for merged Info tab"
```

---

### Task 5: Add Playback Settings Logic to bundle.js

**Files:**
- Modify: `JS/bundle.js` — add to `initSettingsModal()` function, after the performance mode toggle section (after line ~4498)

**Step 1: Add playback speed, loop, and autoplay initialization**

Insert the following code inside `initSettingsModal()`, after the performance mode toggle block and before the log export buttons section:

```javascript
    // ---- PLAYBACK TAB ----

    // Playback speed selector
    var speedBtns = document.querySelectorAll('#speedSelector .speed-btn');
    var savedSpeed = parseFloat(localStorage.getItem(STORAGE_KEYS.PLAYBACK_SPEED) || '1');

    speedBtns.forEach(function(btn) {
      // Set initial active state
      if (parseFloat(btn.dataset.speed) === savedSpeed) {
        speedBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
      }

      btn.addEventListener('click', function() {
        var speed = parseFloat(btn.dataset.speed);
        speedBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
        localStorage.setItem(STORAGE_KEYS.PLAYBACK_SPEED, speed.toString());

        // Apply to current video if playing
        var video = document.querySelector('video.gif');
        if (video) {
          video.playbackRate = speed;
        }
        showToast('Speed: ' + speed + 'x', 1500, 'info');
      });
    });

    // Loop toggle
    var loopToggle = document.getElementById('loopToggle');
    if (loopToggle) {
      var loopEnabled = localStorage.getItem(STORAGE_KEYS.LOOP_ENABLED) !== 'false';
      loopToggle.checked = loopEnabled;

      loopToggle.addEventListener('change', function(e) {
        var isEnabled = e.target.checked;
        localStorage.setItem(STORAGE_KEYS.LOOP_ENABLED, isEnabled.toString());

        var video = document.querySelector('video.gif');
        if (video) {
          video.loop = isEnabled;
        }
      });
    }

    // Autoplay toggle
    var autoplayToggle = document.getElementById('autoplayToggle');
    if (autoplayToggle) {
      var autoplayEnabled = localStorage.getItem(STORAGE_KEYS.AUTOPLAY) !== 'false';
      autoplayToggle.checked = autoplayEnabled;

      autoplayToggle.addEventListener('change', function(e) {
        var isEnabled = e.target.checked;
        localStorage.setItem(STORAGE_KEYS.AUTOPLAY, isEnabled.toString());
      });
    }
```

**Step 2: Apply saved settings when video loads**

In `loadVideo()` function (around line 2351), find where `video.loop = true;` is set (line 2385) and replace the hardcoded values:

```javascript
    video.loop = localStorage.getItem(STORAGE_KEYS.LOOP_ENABLED) !== 'false';
    video.muted = true; // Start muted for autoplay to work
```

After the video's `canplay` event fires and playback starts, apply the saved speed. Find the section where the video starts playing (look for the `video.play()` call inside the `canplay` or `loadeddata` handler) and add after any `video.play()` call:

```javascript
        // Apply saved playback speed
        var savedSpeed = parseFloat(localStorage.getItem(STORAGE_KEYS.PLAYBACK_SPEED) || '1');
        if (savedSpeed !== 1) {
          video.playbackRate = savedSpeed;
        }
```

For autoplay, find where `video.play()` is called and wrap it:

```javascript
        var autoplayEnabled = localStorage.getItem(STORAGE_KEYS.AUTOPLAY) !== 'false';
        if (autoplayEnabled) {
          video.play().catch(function(e) {
            console.log('Autoplay blocked:', e.message);
          });
        }
```

Replace any existing bare `video.play()` calls in the load flow with this conditional version.

**Step 3: Verify**

1. Set speed to 2x in settings, load a video — it should play at 2x.
2. Disable loop, play a video — it should stop on last frame.
3. Disable autoplay, load a video — it should load paused.

**Step 4: Commit**

```bash
git add JS/bundle.js
git commit -m "feat: add playback speed, loop, and autoplay controls"
```

---

### Task 6: Add Background Settings Logic to bundle.js

**Files:**
- Modify: `JS/bundle.js` — add to `initSettingsModal()` function

**Step 1: Add the background type selector logic**

Insert after the autoplay toggle code:

```javascript
    // ---- BACKGROUND TAB ----

    function applyBackground() {
      var drop = document.getElementById('drop');
      if (!drop) return;

      var bgType = localStorage.getItem(STORAGE_KEYS.BG_TYPE) || 'default';

      // Remove custom background classes/styles
      drop.classList.remove('bg-checker-small-dark', 'bg-checker-small-light',
                            'bg-checker-large-dark', 'bg-checker-large-light',
                            'bg-custom-color', 'bg-custom-image');
      drop.style.removeProperty('--custom-bg-color');
      drop.style.removeProperty('--custom-bg-image');
      drop.style.removeProperty('--custom-bg-opacity');
      drop.style.removeProperty('--custom-bg-fit');

      if (bgType === 'color') {
        var bgColor = localStorage.getItem(STORAGE_KEYS.BG_COLOR) || '#000000';
        drop.classList.add('bg-custom-color');
        drop.style.setProperty('--custom-bg-color', bgColor);
      } else if (bgType === 'checker') {
        var size = localStorage.getItem(STORAGE_KEYS.BG_CHECKER_SIZE) || 'small';
        var variant = localStorage.getItem(STORAGE_KEYS.BG_CHECKER_VARIANT) === 'false' ? 'light' : 'dark';
        drop.classList.add('bg-checker-' + size + '-' + variant);
      } else if (bgType === 'image') {
        var bgImage = localStorage.getItem(STORAGE_KEYS.BG_IMAGE) || '';
        var bgFit = localStorage.getItem(STORAGE_KEYS.BG_IMAGE_FIT) || 'cover';
        var bgOpacity = localStorage.getItem(STORAGE_KEYS.BG_IMAGE_OPACITY) || '1';
        if (bgImage) {
          drop.classList.add('bg-custom-image');
          drop.style.setProperty('--custom-bg-image', 'url(' + bgImage + ')');
          drop.style.setProperty('--custom-bg-opacity', bgOpacity);
          drop.style.setProperty('--custom-bg-fit', bgFit === 'tile' ? 'auto' : 'cover');
        }
      }
      // 'default' = no custom classes, uses theme CSS as-is
    }

    // Make applyBackground available globally for theme changes
    window.applyBackground = applyBackground;

    // Background type selector
    var bgTypeBtns = document.querySelectorAll('#bgTypeSelector .bg-type-btn');
    var savedBgType = localStorage.getItem(STORAGE_KEYS.BG_TYPE) || 'default';

    function showBgOptions(type) {
      var allOptions = document.querySelectorAll('.bg-options');
      allOptions.forEach(function(el) { el.style.display = 'none'; });

      if (type === 'color') {
        var colorOpts = document.getElementById('bgColorOptions');
        if (colorOpts) colorOpts.style.display = '';
      } else if (type === 'checker') {
        var checkerOpts = document.getElementById('bgCheckerOptions');
        if (checkerOpts) checkerOpts.style.display = '';
      } else if (type === 'image') {
        var imageOpts = document.getElementById('bgImageOptions');
        if (imageOpts) imageOpts.style.display = '';
      }
    }

    bgTypeBtns.forEach(function(btn) {
      if (btn.dataset.bg === savedBgType) {
        bgTypeBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
      }
      btn.addEventListener('click', function() {
        bgTypeBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
        localStorage.setItem(STORAGE_KEYS.BG_TYPE, btn.dataset.bg);
        showBgOptions(btn.dataset.bg);
        applyBackground();
      });
    });
    showBgOptions(savedBgType);

    // Color picker
    var bgColorPicker = document.getElementById('bgColorPicker');
    var bgColorHex = document.getElementById('bgColorHex');
    var savedBgColor = localStorage.getItem(STORAGE_KEYS.BG_COLOR) || '#000000';
    if (bgColorPicker) bgColorPicker.value = savedBgColor;
    if (bgColorHex) bgColorHex.value = savedBgColor;

    if (bgColorPicker) {
      bgColorPicker.addEventListener('input', function() {
        var color = bgColorPicker.value;
        if (bgColorHex) bgColorHex.value = color;
        localStorage.setItem(STORAGE_KEYS.BG_COLOR, color);
        applyBackground();
      });
    }
    if (bgColorHex) {
      bgColorHex.addEventListener('change', function() {
        var color = bgColorHex.value;
        if (/^#[0-9a-fA-F]{6}$/.test(color)) {
          if (bgColorPicker) bgColorPicker.value = color;
          localStorage.setItem(STORAGE_KEYS.BG_COLOR, color);
          applyBackground();
        }
      });
    }

    // Checkerboard size selector
    var checkerSizeBtns = document.querySelectorAll('#checkerSizeSelector .bg-type-btn');
    var savedCheckerSize = localStorage.getItem(STORAGE_KEYS.BG_CHECKER_SIZE) || 'small';
    checkerSizeBtns.forEach(function(btn) {
      if (btn.dataset.size === savedCheckerSize) {
        checkerSizeBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
      }
      btn.addEventListener('click', function() {
        checkerSizeBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
        localStorage.setItem(STORAGE_KEYS.BG_CHECKER_SIZE, btn.dataset.size);
        applyBackground();
      });
    });

    // Checkerboard variant toggle
    var checkerVariantToggle = document.getElementById('checkerVariantToggle');
    if (checkerVariantToggle) {
      var isDark = localStorage.getItem(STORAGE_KEYS.BG_CHECKER_VARIANT) !== 'false';
      checkerVariantToggle.checked = isDark;
      checkerVariantToggle.addEventListener('change', function(e) {
        localStorage.setItem(STORAGE_KEYS.BG_CHECKER_VARIANT, e.target.checked.toString());
        applyBackground();
      });
    }

    // Background image upload
    var bgImageUploadBtn = document.getElementById('bgImageUploadBtn');
    var bgImageFile = document.getElementById('bgImageFile');
    var bgImageName = document.getElementById('bgImageName');
    var bgImageClearBtn = document.getElementById('bgImageClearBtn');

    // Show current image name if saved
    var savedBgImage = localStorage.getItem(STORAGE_KEYS.BG_IMAGE) || '';
    if (savedBgImage && bgImageName) {
      bgImageName.textContent = 'Custom image loaded';
      if (bgImageClearBtn) bgImageClearBtn.style.display = '';
    }

    if (bgImageUploadBtn && bgImageFile) {
      bgImageUploadBtn.addEventListener('click', function() {
        bgImageFile.click();
      });

      bgImageFile.addEventListener('change', function(e) {
        var file = e.target.files[0];
        if (!file) return;

        // Size warning
        if (file.size > 1024 * 1024) {
          showToast('Large image (' + Math.round(file.size / 1024 / 1024) + 'MB) may slow down localStorage', 3000, 'warning');
        }

        var reader = new FileReader();
        reader.onload = function(ev) {
          localStorage.setItem(STORAGE_KEYS.BG_IMAGE, ev.target.result);
          if (bgImageName) bgImageName.textContent = file.name;
          if (bgImageClearBtn) bgImageClearBtn.style.display = '';
          applyBackground();
        };
        reader.readAsDataURL(file);
      });
    }

    if (bgImageClearBtn) {
      bgImageClearBtn.addEventListener('click', function() {
        localStorage.removeItem(STORAGE_KEYS.BG_IMAGE);
        if (bgImageName) bgImageName.textContent = 'No image selected';
        bgImageClearBtn.style.display = 'none';
        if (bgImageFile) bgImageFile.value = '';
        applyBackground();
      });
    }

    // Background image fit selector
    var bgFitBtns = document.querySelectorAll('#bgImageFitSelector .bg-type-btn');
    var savedBgFit = localStorage.getItem(STORAGE_KEYS.BG_IMAGE_FIT) || 'cover';
    bgFitBtns.forEach(function(btn) {
      if (btn.dataset.fit === savedBgFit) {
        bgFitBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
      }
      btn.addEventListener('click', function() {
        bgFitBtns.forEach(function(b) { b.classList.remove('active'); });
        btn.classList.add('active');
        localStorage.setItem(STORAGE_KEYS.BG_IMAGE_FIT, btn.dataset.fit);
        applyBackground();
      });
    });

    // Background image opacity
    var bgOpacitySlider = document.getElementById('bgImageOpacity');
    var bgOpacityValue = document.getElementById('bgOpacityValue');
    var savedBgOpacity = localStorage.getItem(STORAGE_KEYS.BG_IMAGE_OPACITY) || '1';
    if (bgOpacitySlider) bgOpacitySlider.value = savedBgOpacity;
    if (bgOpacityValue) bgOpacityValue.textContent = Math.round(parseFloat(savedBgOpacity) * 100) + '%';

    if (bgOpacitySlider) {
      bgOpacitySlider.addEventListener('input', function() {
        var val = parseFloat(bgOpacitySlider.value);
        if (bgOpacityValue) bgOpacityValue.textContent = Math.round(val * 100) + '%';
        localStorage.setItem(STORAGE_KEYS.BG_IMAGE_OPACITY, val.toString());
        applyBackground();
      });
    }

    // Apply background on load
    applyBackground();
```

**Step 2: Verify**

1. Select "Color" background type, pick a color — the drop area background should change.
2. Select "Checker" — checkerboard pattern should appear.
3. Upload an image — it should appear behind media.
4. Select "Default" — reverts to theme background.

**Step 3: Commit**

```bash
git add JS/bundle.js
git commit -m "feat: add background customization (color, checker, image)"
```

---

### Task 7: Add CSS for New Components (Playback & Background)

**Files:**
- Modify: `style.css` — add after the existing settings content styles (after line ~1682)

**Step 1: Add speed selector styles**

```css
/* ===== SPEED SELECTOR ===== */
.speed-selector {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.speed-btn {
  flex: 1;
  min-width: 48px;
  padding: 8px 4px;
  border: 1px solid var(--theme-border);
  border-radius: 8px;
  background: var(--theme-input-bg);
  color: var(--theme-text-secondary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  text-align: center;
}

.speed-btn:hover {
  background: var(--btn-hover-bg);
  border-color: var(--theme-primary-soft);
  color: var(--theme-text-primary);
}

.speed-btn.active {
  background: var(--btn-active-bg);
  border-color: var(--theme-primary);
  color: var(--theme-primary);
  box-shadow: 0 0 12px var(--theme-glow);
}
```

**Step 2: Add background type selector styles**

```css
/* ===== BACKGROUND TYPE SELECTOR ===== */
.bg-type-selector {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.bg-type-btn {
  flex: 1;
  min-width: 60px;
  padding: 10px 8px;
  border: 1px solid var(--theme-border);
  border-radius: 8px;
  background: var(--theme-input-bg);
  color: var(--theme-text-secondary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  text-align: center;
}

.bg-type-btn:hover {
  background: var(--btn-hover-bg);
  border-color: var(--theme-primary-soft);
  color: var(--theme-text-primary);
}

.bg-type-btn.active {
  background: var(--btn-active-bg);
  border-color: var(--theme-primary);
  color: var(--theme-primary);
  box-shadow: 0 0 12px var(--theme-glow);
}
```

**Step 3: Add color picker styles**

```css
/* ===== COLOR PICKER ===== */
.color-picker-row {
  display: flex;
  gap: 10px;
  align-items: center;
}

.color-input {
  width: 48px;
  height: 48px;
  border: 2px solid var(--theme-border);
  border-radius: 10px;
  cursor: pointer;
  padding: 2px;
  background: var(--theme-input-bg);
  transition: border-color 0.2s ease;
}

.color-input:hover {
  border-color: var(--theme-primary);
}

.hex-input {
  width: 100px;
  padding: 10px 14px;
  border: 1px solid var(--theme-border);
  border-radius: 8px;
  background: var(--theme-input-bg);
  color: var(--theme-text-primary);
  font-size: 14px;
  font-family: monospace;
  transition: all 0.2s ease;
}

.hex-input:focus {
  outline: none;
  border-color: var(--theme-primary);
  box-shadow: 0 0 0 3px var(--theme-glow);
}
```

**Step 4: Add background image upload styles**

```css
/* ===== BACKGROUND IMAGE UPLOAD ===== */
.bg-image-upload {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

.bg-upload-btn {
  padding: 10px 16px;
  border: 1px solid var(--theme-primary-soft);
  border-radius: 8px;
  background: var(--btn-bg);
  color: var(--theme-primary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.bg-upload-btn:hover {
  background: var(--btn-hover-bg);
  box-shadow: 0 0 12px var(--theme-glow);
}

.bg-image-name {
  font-size: 12px;
  color: var(--theme-text-tertiary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bg-clear-btn {
  width: 32px;
  height: 32px;
  border: 1px solid rgba(239, 68, 68, 0.3);
  border-radius: 8px;
  background: rgba(239, 68, 68, 0.1);
  color: #ef4444;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.bg-clear-btn:hover {
  background: rgba(239, 68, 68, 0.2);
  border-color: rgba(239, 68, 68, 0.5);
}

.bg-opacity-row {
  display: flex;
  gap: 12px;
  align-items: center;
}

.bg-opacity-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--theme-primary);
  min-width: 40px;
  text-align: right;
}
```

**Step 5: Add checkerboard background pattern styles**

```css
/* ===== CHECKERBOARD BACKGROUNDS ===== */
.drop.bg-custom-color {
  background: var(--custom-bg-color) !important;
}

.drop.bg-checker-small-dark {
  background: repeating-conic-gradient(#1a1a1a 0% 25%, #2a2a2a 0% 50%) 0 0 / 16px 16px !important;
}

.drop.bg-checker-small-light {
  background: repeating-conic-gradient(#cccccc 0% 25%, #ffffff 0% 50%) 0 0 / 16px 16px !important;
}

.drop.bg-checker-large-dark {
  background: repeating-conic-gradient(#1a1a1a 0% 25%, #2a2a2a 0% 50%) 0 0 / 32px 32px !important;
}

.drop.bg-checker-large-light {
  background: repeating-conic-gradient(#cccccc 0% 25%, #ffffff 0% 50%) 0 0 / 32px 32px !important;
}

.drop.bg-custom-image {
  position: relative;
}

.drop.bg-custom-image::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--custom-bg-image);
  background-size: var(--custom-bg-fit, cover);
  background-position: center;
  background-repeat: repeat;
  opacity: var(--custom-bg-opacity, 1);
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
}

.drop.bg-custom-image .gif,
.drop.bg-custom-image video.gif,
.drop.bg-custom-image .placeholder {
  position: relative;
  z-index: 1;
}
```

**Step 6: Verify**

Each background type should render correctly in the drop area.

**Step 7: Commit**

```bash
git add style.css
git commit -m "feat: add CSS for playback and background settings components"
```

---

### Task 8: Glassmorphism Visual Redesign

**Files:**
- Modify: `style.css` — update existing modal and settings styles

**Step 1: Update modal card for glassmorphism**

Find `.modalCard` (line 1148) and update:

```css
.modalCard {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  min-width: min(600px, 100vw - 20px);
  min-height: min(400px, 100vh - 20px);
  border-radius: 16px;
  overflow: hidden;
  background: rgba(15, 15, 18, 0.85);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  margin: 0;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    0 0 0 1px var(--theme-primary-soft),
    0 0 40px var(--theme-glow),
    0 20px 60px var(--theme-shadow);
}
```

**Step 2: Update tab bar for frosted glass**

Find `#settingsModal .settingsTabs` (line 1419) and update:

```css
#settingsModal .settingsTabs {
  display: flex;
  gap: 4px;
  margin-bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  justify-content: center;
  padding: 12px 16px;
  flex-shrink: 0;
}
```

**Step 3: Update individual tabs for compact 5-tab layout**

Find `#settingsModal .settingsTab` (line 1430) and update:

```css
#settingsModal .settingsTab {
  background: transparent;
  border: 1px solid transparent;
  color: var(--theme-text-secondary);
  font-size: 11px;
  font-weight: 600;
  padding: 8px 12px;
  cursor: pointer;
  position: relative;
  transition: all 0.2s ease;
  text-align: center;
  border-radius: 8px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 56px;
  flex: 1;
}
```

**Step 4: Update active tab glow**

Find `#settingsModal .settingsTab.active` (line 1475) and update:

```css
#settingsModal .settingsTab.active {
  color: var(--theme-text-primary);
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--theme-primary-soft);
  box-shadow: 0 0 16px var(--theme-glow);
}
```

**Step 5: Update setting row cards for glass effect**

Find `.settingRow` (line 1560) and update:

```css
.settingRow {
  margin-bottom: 12px;
  width: 100%;
  box-sizing: border-box;
  background: rgba(255, 255, 255, 0.04);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 10px;
  padding: 16px 20px;
  transition: all 0.2s ease;
  position: relative;
}

.settingRow:hover {
  background: rgba(255, 255, 255, 0.07);
  border-color: var(--theme-primary-soft);
  box-shadow: 0 0 12px var(--theme-glow);
}
```

**Step 6: Update theme grid cards for glow selection**

Find `.theme-card` styles and add a glow ring for the active state. Add this CSS:

```css
.theme-card.active {
  box-shadow: 0 0 0 2px var(--theme-primary), 0 0 16px var(--theme-glow);
}
```

**Step 7: Update settings body background**

Find `#settingsModal .settingsBody` (line 1377) and update the background to be more transparent:

```css
#settingsModal .settingsBody {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0;
  background: rgba(15, 15, 18, 0.6);
  position: relative;
  overflow: hidden;
}
```

**Step 8: Update footer for glass effect**

Find `#settingsModal .settingsFooter` (line 1663) and update:

```css
#settingsModal .settingsFooter {
  flex-shrink: 0;
  padding: 10px 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  font-size: 11px;
  color: var(--theme-text-tertiary);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
```

**Step 9: Verify**

Open the settings modal. The entire modal should have a frosted glass appearance with semi-transparent backgrounds. Theme accent colors should glow through the glass.

**Step 10: Commit**

```bash
git add style.css
git commit -m "feat: apply glassmorphism redesign to settings modal"
```

---

### Task 9: Update Responsive Breakpoints

**Files:**
- Modify: `style.css` — update existing media queries and add new ones

**Step 1: Add responsive breakpoints for settings tabs**

Find the existing responsive media queries (around line 2183) and update the settings-specific rules. Add or replace:

```css
/* ===== SETTINGS RESPONSIVE - 5-tab layout ===== */
@media (max-width: 399px) {
  #settingsModal .settingsTabs {
    padding: 8px 8px;
    gap: 2px;
  }

  #settingsModal .settingsTab {
    padding: 6px 4px;
    min-width: 40px;
  }

  #settingsModal .settingsTab .tab-label {
    display: none;
  }

  #settingsModal .settingsTab .tab-icon {
    font-size: 16px;
  }

  #settingsModal .settingsTabPage {
    padding: 16px 12px;
  }

  .theme-grid {
    grid-template-columns: repeat(3, 1fr) !important;
  }

  .speed-selector {
    gap: 4px;
  }

  .speed-btn {
    min-width: 40px;
    padding: 6px 2px;
    font-size: 11px;
  }

  .bg-type-selector {
    gap: 4px;
  }

  .bg-type-btn {
    min-width: 48px;
    padding: 8px 4px;
    font-size: 11px;
  }
}

@media (max-width: 299px) {
  .theme-grid {
    grid-template-columns: repeat(2, 1fr) !important;
  }

  .volume-control-container {
    flex-direction: column;
    align-items: stretch;
  }

  .speed-selector {
    flex-wrap: wrap;
  }

  .speed-btn {
    flex: 0 0 calc(33% - 4px);
  }

  .bg-type-selector {
    flex-wrap: wrap;
  }

  .bg-type-btn {
    flex: 0 0 calc(50% - 3px);
  }
}
```

**Step 2: Verify**

Resize the panel to various widths. At <400px, tabs should show icons only. At <300px, theme grid should be 2 columns.

**Step 3: Commit**

```bash
git add style.css
git commit -m "feat: add responsive breakpoints for 5-tab settings layout"
```

---

### Task 10: Mirror Changes to Assets Directory

**Files:**
- Copy: `index.html` -> `assets/index.html`
- Copy: `style.css` -> `assets/style.css`

**Step 1: Copy files**

```bash
cp index.html assets/index.html
cp style.css assets/style.css
```

**Step 2: Verify assets match**

```bash
diff index.html assets/index.html
diff style.css assets/style.css
```

Both should show no differences.

**Step 3: Commit**

```bash
git add assets/index.html assets/style.css
git commit -m "chore: mirror settings redesign to assets directory"
```

---

### Task 11: Update Version and Final Verification

**Files:**
- Modify: `JS/bundle.js:30` (CURRENT_VERSION)
- Modify: `JS/bundle.js:2` (comment header)

**Step 1: Update version**

Change `CURRENT_VERSION` from `'3.3.0'` to `'3.4.0'` and update the header comment.

**Step 2: Full verification checklist**

Open the panel and verify each item:

1. **General tab**: Theme grid, rounded corners, error suppression, performance mode (no volume — it moved).
2. **Playback tab**: Volume control works, speed buttons work (apply to playing video), loop toggle works, autoplay toggle works.
3. **Background tab**: Default/Color/Checker/Image all work. Color picker updates live. Checkerboard renders both sizes and variants. Image upload works with cover/tile and opacity.
4. **History tab**: Unchanged, still loads lazily.
5. **Info tab**: Version/author info, license status, Discord link works, quick tips, debug log buttons all work.
6. **Responsiveness**: Resize panel to various widths — tabs go icon-only at <400px, theme grid adjusts.
7. **Glassmorphism**: Modal has frosted glass effect, setting cards have subtle glass borders, tabs glow on active state.
8. **Persistence**: Change settings, close/reopen panel — all settings should restore.

**Step 3: Commit**

```bash
git add JS/bundle.js
git commit -m "chore: bump version to 3.4.0 for settings modal redesign"
```

---

## Summary of All Tasks

| # | Task | Files | Estimated Steps |
|---|------|-------|-----------------|
| 1 | Add storage keys | `JS/bundle.js` | 3 |
| 2 | Restructure tab buttons HTML | `index.html` | 3 |
| 3 | Add Playback/Background tab HTML, merge Help into Info | `index.html` | 7 |
| 4 | Update tab switching logic | `JS/bundle.js` | 3 |
| 5 | Add playback settings JS logic | `JS/bundle.js` | 4 |
| 6 | Add background settings JS logic | `JS/bundle.js` | 3 |
| 7 | Add CSS for new components | `style.css` | 7 |
| 8 | Glassmorphism visual redesign | `style.css` | 10 |
| 9 | Responsive breakpoints | `style.css` | 3 |
| 10 | Mirror to assets | `assets/*` | 3 |
| 11 | Version bump & final verify | `JS/bundle.js` | 3 |
