// script.js - shared tab/UI logic
(() => {
  'use strict';

  document.addEventListener('DOMContentLoaded', () => {
    const ACTIVE_TAB_KEY = 'balloonDesigner:activeTab:v1';

    // Ensure shared helpers are ready
    if (!window.shared) return;
    const { clamp, clamp01, SWATCH_TEXTURE_ZOOM } = window.shared;
    const { FLAT_COLORS } = window.shared;

    // Modal helpers
    const messageModal = document.getElementById('message-modal');
    const modalText = document.getElementById('modal-text');
    const modalCloseBtn = document.getElementById('modal-close-btn');
    function showModal(msg) {
      if (!messageModal || !modalText) return;
      modalText.textContent = msg;
      messageModal.classList.remove('hidden');
    }
    function hideModal() {
      messageModal?.classList.add('hidden');
    }
    modalCloseBtn?.addEventListener('click', hideModal);

    // Tab elements
    const orgSheet = document.getElementById('controls-panel');
    const claSheet = document.getElementById('classic-controls-panel');
    const wallSheet = document.getElementById('wall-controls-panel');
    const orgSection = document.getElementById('tab-organic');
    const claSection = document.getElementById('tab-classic');
    const wallSection = document.getElementById('tab-wall');
    const tabBtns = Array.from(document.querySelectorAll('#mode-tabs .tab-btn'));
    const mobileActionBar = document.getElementById('mobile-action-bar');

    // Export buttons
    const exportPngBtn = document.querySelector('[data-export="png"]');
    const exportSvgBtn = document.querySelector('[data-export="svg"]');
    const { XLINK_NS } = window.shared || {};
    const MOBILE_TAB_DEFAULT = 'controls';
    const MOBILE_TAB_PREFIX = 'designer:mobileTab:';
    const exportModal = document.getElementById('export-modal');
    const exportModalClose = document.getElementById('export-modal-close');

    // Generic color picker modal (used by replace chips)
    (function initColorPickerModal() {
      const modal = document.getElementById('color-picker-modal');
      const grid = document.getElementById('color-picker-grid');
      const titleEl = document.getElementById('color-picker-title');
      const subtitleEl = document.getElementById('color-picker-subtitle');
      const closeBtn = document.getElementById('color-picker-close');
      if (!modal || !grid || !titleEl || !subtitleEl) return;
      const close = () => modal.classList.add('hidden');
      closeBtn?.addEventListener('click', close);
      modal.addEventListener('click', (e) => { if (e.target === modal) close(); });

      const setChipStyle = (el, meta) => {
        if (!el || !meta) return;
        if (meta.image) {
          const zoom = Math.max(1, meta.imageZoom ?? SWATCH_TEXTURE_ZOOM ?? 2.5);
          el.style.backgroundImage = `url("${meta.image}")`;
          el.style.backgroundColor = meta.hex || '#fff';
          el.style.backgroundSize = `${100 * zoom}%`;
          el.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
        } else {
          el.style.backgroundImage = 'none';
          el.style.backgroundColor = meta.hex || '#fff';
        }
      };

      window.openColorPicker = ({ title = 'Choose a color', subtitle = '', items = [], onSelect }) => {
        titleEl.textContent = title;
        subtitleEl.textContent = subtitle;
        grid.innerHTML = '';
        items.forEach(item => {
          const meta = item.meta || (Number.isInteger(item.idx) ? FLAT_COLORS?.[item.idx] : null) || {};
          const sw = document.createElement('button');
          sw.type = 'button';
          sw.className = 'color-option';
          sw.setAttribute('aria-label', item.label || meta.name || meta.hex || 'Color');
          const swatch = document.createElement('div');
          swatch.className = 'swatch';
          setChipStyle(swatch, meta.hex ? meta : { hex: item.hex });
          const label = document.createElement('div');
          label.className = 'label';
          label.textContent = item.label || meta.name || meta.hex || 'Color';
          const metaLine = document.createElement('div');
          metaLine.className = 'meta';
          metaLine.textContent = item.metaText || meta.hex || '';
          sw.appendChild(swatch);
          sw.appendChild(label);
          sw.appendChild(metaLine);
          sw.addEventListener('click', () => {
            close();
            onSelect?.(item);
          });
          grid.appendChild(sw);
        });
        modal.classList.remove('hidden');
      };
    })();

    function getImageHref(el) {
      return el.getAttribute('href') || (XLINK_NS ? el.getAttributeNS(XLINK_NS, 'href') : null);
    }
    function setImageHref(el, val) {
      el.setAttribute('href', val);
      if (XLINK_NS) el.setAttributeNS(XLINK_NS, 'xlink:href', val);
    }

    // Update export buttons visibility depending on tab/design
    window.updateExportButtonVisibility = () => {
      const tab = detectCurrentTab();
      const isWall = tab === '#tab-wall';
      const isClassic = tab === '#tab-classic';
      const hasClassic = !!document.querySelector('#classic-display svg');
      const hasWall = !!document.querySelector('#wall-display svg');
      const enable = (btn, on) => { if (btn) btn.disabled = !on; };
      if (isClassic) enable(exportPngBtn, hasClassic); else enable(exportPngBtn, true);
      if (isClassic) enable(exportSvgBtn, hasClassic); else if (isWall) enable(exportSvgBtn, hasWall); else enable(exportSvgBtn, true);
    };

    async function buildClassicSvgExportFromDom() {
      const svgElement = document.querySelector('#classic-display svg');
      if (!svgElement) throw new Error('Classic design not found. Please create a design first.');
      const clonedSvg = svgElement.cloneNode(true);
      const allImages = Array.from(clonedSvg.querySelectorAll('image'));
      await Promise.all(allImages.map(async img => {
        const href = getImageHref(img);
        if (!href || href.startsWith('data:')) return;
        const dataUrl = await window.shared.imageUrlToDataUrl(href);
        if (dataUrl) setImageHref(img, dataUrl);
      }));
      if (!clonedSvg.getAttribute('xmlns')) clonedSvg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
      if (!clonedSvg.getAttribute('xmlns:xlink') && XLINK_NS) clonedSvg.setAttribute('xmlns:xlink', XLINK_NS);

      let width = Number(clonedSvg.getAttribute('width')) || null;
      let height = Number(clonedSvg.getAttribute('height')) || null;
      const viewBox = (clonedSvg.getAttribute('viewBox') || '').split(/\s+/).map(Number);
      if ((!width || !height) && viewBox.length === 4 && viewBox.every(v => Number.isFinite(v))) {
        width = width || viewBox[2];
        height = height || viewBox[3];
      }
      if (!width || !height) {
        const vbW = svgElement.clientWidth || 1000;
        const vbH = svgElement.clientHeight || 1000;
        width = width || vbW;
        height = height || vbH;
      }
      clonedSvg.setAttribute('width', width);
      clonedSvg.setAttribute('height', height);

      return { svgString: new XMLSerializer().serializeToString(clonedSvg), width, height };
    }

    async function buildWallSvgExportFromDom() {
      const svgElement = document.querySelector('#wall-display svg');
      if (!svgElement) throw new Error('Wall design not found. Please create a design first.');
      const clonedSvg = svgElement.cloneNode(true);

      const allImages = Array.from(clonedSvg.querySelectorAll('image'));
      await Promise.all(allImages.map(async img => {
        const href = getImageHref(img);
        if (!href || href.startsWith('data:')) return;
        const dataUrl = await window.shared.imageUrlToDataUrl(href);
        if (dataUrl) setImageHref(img, dataUrl);
      }));

      if (!clonedSvg.getAttribute('xmlns')) clonedSvg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
      if (!clonedSvg.getAttribute('xmlns:xlink') && XLINK_NS) clonedSvg.setAttribute('xmlns:xlink', XLINK_NS);

      let width = Number(clonedSvg.getAttribute('width')) || null;
      let height = Number(clonedSvg.getAttribute('height')) || null;
      const viewBox = (clonedSvg.getAttribute('viewBox') || '').split(/\s+/).map(Number);
      if ((!width || !height) && viewBox.length === 4 && viewBox.every(v => Number.isFinite(v))) {
        width = width || viewBox[2];
        height = height || viewBox[3];
      }
      if (!width || !height) {
        const vbW = svgElement.clientWidth || 1000;
        const vbH = svgElement.clientHeight || 1000;
        width = width || vbW;
        height = height || vbH;
      }
      clonedSvg.setAttribute('width', width);
      clonedSvg.setAttribute('height', height);

      return { svgString: new XMLSerializer().serializeToString(clonedSvg), width, height };
    }

    // Export routing
    async function buildWallSvgExportFromDom() {
      const svgElement = document.querySelector('#wall-display svg');
      if (!svgElement) throw new Error('Wall design not found. Please create a design first.');
      const clonedSvg = svgElement.cloneNode(true);

      const allImages = Array.from(clonedSvg.querySelectorAll('image'));
      await Promise.all(allImages.map(async img => {
        const href = getImageHref(img);
        if (!href || href.startsWith('data:')) return;
        const dataUrl = await window.shared.imageUrlToDataUrl(href);
        if (dataUrl) setImageHref(img, dataUrl);
      }));

      if (!clonedSvg.getAttribute('xmlns')) clonedSvg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
      if (!clonedSvg.getAttribute('xmlns:xlink') && XLINK_NS) clonedSvg.setAttribute('xmlns:xlink', XLINK_NS);

      let width = Number(clonedSvg.getAttribute('width')) || null;
      let height = Number(clonedSvg.getAttribute('height')) || null;
      const viewBox = (clonedSvg.getAttribute('viewBox') || '').split(/\s+/).map(Number);
      if ((!width || !height) && viewBox.length === 4 && viewBox.every(v => Number.isFinite(v))) {
        width = width || viewBox[2];
        height = height || viewBox[3];
      }
      if (!width || !height) {
        const vbW = svgElement.clientWidth || 1000;
        const vbH = svgElement.clientHeight || 1000;
        width = width || vbW;
        height = height || vbH;
      }
      clonedSvg.setAttribute('width', width);
      clonedSvg.setAttribute('height', height);

      const svgString = new XMLSerializer().serializeToString(clonedSvg);
      return { svgString, width, height };
    }
    async function inlineSvgImages(svgString) {
      try {
        const parser = new DOMParser();
        const doc = parser.parseFromString(svgString, 'image/svg+xml');
        if (doc.querySelector('parsererror')) return svgString;
        const imgs = Array.from(doc.querySelectorAll('image'));
        await Promise.all(imgs.map(async img => {
          const href = img.getAttribute('href') || img.getAttribute('xlink:href');
          if (!href || href.startsWith('data:')) return;
          const dataUrl = await window.shared.imageUrlToDataUrl(href);
          if (dataUrl) {
            img.setAttribute('href', dataUrl);
            img.removeAttribute('xlink:href');
          }
        }));
        return new XMLSerializer().serializeToString(doc.documentElement);
      } catch (err) {
        console.warn('[Export] inlineSvgImages failed', err);
        return svgString;
      }
    }

    async function svgStringToPng(svgString, width, height) {
      const { PNG_EXPORT_SCALE } = window.shared;
      if (!/xmlns=/.test(svgString)) {
        svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');
      }
      // Inline any external images to avoid CORS/fetch issues.
      svgString = await inlineSvgImages(svgString);
      const img = new Image();
      img.crossOrigin = 'anonymous';
      const scale = PNG_EXPORT_SCALE;
      const canvasEl = document.createElement('canvas');
      canvasEl.width = Math.max(1, Math.round(width * scale));
      canvasEl.height = Math.max(1, Math.round(height * scale));
      const ctx2 = canvasEl.getContext('2d');
      if (ctx2) {
        ctx2.imageSmoothingEnabled = true;
        ctx2.imageSmoothingQuality = 'high';
      }
      const loadSrc = (src) => new Promise((resolve, reject) => {
        img.onload = resolve;
        img.onerror = () => reject(new Error('Could not rasterize SVG.'));
        img.src = src;
      });

      // Prefer base64 data URL to avoid parser issues with raw text.
      const svg64 = btoa(unescape(encodeURIComponent(svgString)));
      const dataUrl = `data:image/svg+xml;base64,${svg64}`;
      try {
        await loadSrc(dataUrl);
      } catch (e) {
        // Fallback to blob if base64 path fails.
        let blobUrl = null;
        try {
          const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
          blobUrl = URL.createObjectURL(blob);
          await loadSrc(blobUrl);
        } finally {
          if (blobUrl) URL.revokeObjectURL(blobUrl);
        }
      }
      ctx2.drawImage(img, 0, 0, canvasEl.width, canvasEl.height);
      return canvasEl.toDataURL('image/png');
    }

    function downloadSvg(svgString, filename) {
      const { download } = window.shared;
      const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      download(url, filename);
      setTimeout(() => URL.revokeObjectURL(url), 20000);
    }

    async function exportPng() {
      try {
        const tab = detectCurrentTab();
        if (tab === '#tab-classic') {
          const { svgString, width, height } = window.ClassicExport?.buildClassicSvgPayload
            ? await window.ClassicExport.buildClassicSvgPayload()
            : await buildClassicSvgExportFromDom();
          const pngUrl = await svgStringToPng(svgString, width, height);
          window.shared.download(pngUrl, 'classic_design.png');
          return;
        }
        if (tab === '#tab-wall') {
          const { svgString, width, height } = await buildWallSvgExportFromDom();
          const pngUrl = await svgStringToPng(svgString, width, height);
          window.shared.download(pngUrl, 'wall_design.png');
          return;
        }
        const { svgString, width, height } = await window.organic.buildOrganicSvgPayload();
        const pngUrl = await svgStringToPng(svgString, width, height);
        window.shared.download(pngUrl, 'balloon_design.png');
      } catch (err) {
        console.error('[Export PNG] Failed:', err);
        showModal(err.message || 'Could not export PNG. Check console for details.');
      }
    }

    async function exportSvg() {
      try {
        const tab = detectCurrentTab();
        if (tab === '#tab-classic') {
          const { svgString, width, height } = window.ClassicExport?.buildClassicSvgPayload
            ? await window.ClassicExport.buildClassicSvgPayload()
            : await buildClassicSvgExportFromDom();
          try {
            const pngUrl = await svgStringToPng(svgString, width, height);
            const cleanSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
              <image href="${pngUrl}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet" />
            </svg>`;
            downloadSvg(cleanSvg, 'classic_design.svg');
          } catch (pngErr) {
            console.warn('[Export SVG] PNG embed failed, falling back to vector-only SVG', pngErr);
            downloadSvg(svgString, 'classic_design.svg');
          }
          return;
        }
        if (tab === '#tab-wall') {
          const { svgString, width, height } = await buildWallSvgExportFromDom();
          downloadSvg(svgString, 'wall_design.svg');
          return;
        }
        const { svgString } = await window.organic.buildOrganicSvgPayload();
        downloadSvg(svgString, 'organic_design.svg');
      } catch (err) {
        console.error('[Export] Failed:', err);
        showModal(err.message || 'Could not export. Check console for details.');
      }
    }

    const openExportModal = () => { exportModal?.classList.remove('hidden'); };
    const closeExportModal = () => { exportModal?.classList.add('hidden'); };
    exportModalClose?.addEventListener('click', closeExportModal);
    exportModal?.addEventListener('click', (e) => { if (e.target === exportModal) closeExportModal(); });
    document.body.addEventListener('click', e => {
      const choice = e.target.closest('[data-export-choice]');
      if (choice) {
        const type = choice.dataset.exportChoice;
        closeExportModal();
        if (type === 'png') exportPng();
        else if (type === 'svg') exportSvg();
        return;
      }
      const btn = e.target.closest('[data-export]');
      if (!btn) return;
      e.preventDefault();
      openExportModal();
    });

    // Tab logic
    function detectCurrentTab() {
      const bodyActive = document.body?.dataset?.activeTab;
      const activeBtn = document.querySelector('#mode-tabs .tab-btn.tab-active');
      const classicVisible = !document.getElementById('tab-classic')?.classList.contains('hidden');
      const organicVisible = !document.getElementById('tab-organic')?.classList.contains('hidden');
      const wallVisible = !document.getElementById('tab-wall')?.classList.contains('hidden');

      let id = bodyActive || activeBtn?.dataset?.target;
      if (!id) {
        if (classicVisible && !organicVisible && !wallVisible) id = '#tab-classic';
        else if (organicVisible && !classicVisible && !wallVisible) id = '#tab-organic';
        else if (wallVisible && !classicVisible && !organicVisible) id = '#tab-wall';
      }
      if (!id) id = '#tab-organic';
      if (document.body) document.body.dataset.activeTab = id;
      return id;
    }
    window.detectCurrentTab = detectCurrentTab;

    function updateSheets() {
      const tab = detectCurrentTab();
      const hide = !window.matchMedia('(min-width: 1024px)').matches && document.body?.dataset?.controlsHidden === '1';
      if (orgSheet) orgSheet.classList.toggle('hidden', hide || tab !== '#tab-organic');
      if (claSheet) claSheet.classList.toggle('hidden', hide || tab !== '#tab-classic');
      if (wallSheet) wallSheet.classList.toggle('hidden', hide || tab !== '#tab-wall');
    }

    function updateMobileStacks(tabName) {
      const orgPanel = document.getElementById('controls-panel');
      const claPanel = document.getElementById('classic-controls-panel');
      const wallPanel = document.getElementById('wall-controls-panel');
      const currentTab = detectCurrentTab();
      const panel = currentTab === '#tab-classic' ? claPanel : (currentTab === '#tab-wall' ? wallPanel : orgPanel);
      const target = tabName || document.body?.dataset?.mobileTab || MOBILE_TAB_DEFAULT;
      const isHidden = document.body?.dataset?.controlsHidden === '1';
      const isDesktop = window.matchMedia('(min-width: 1024px)').matches;
      if (!panel) return;
      const stacks = Array.from(panel.querySelectorAll('.control-stack'));
      if (!stacks.length) return;
      stacks.forEach(stack => {
        if (isHidden) {
          stack.style.display = 'none';
        } else if (isDesktop) {
          stack.style.display = '';
        } else {
          const show = stack.dataset.mobileTab === target;
          stack.style.display = show ? 'block' : 'none';
        }
      });
    }

    function setMobileTab(tab, mainTabId, skipPersist = false) {
      const name = tab || MOBILE_TAB_DEFAULT;
      const activeMainTab = mainTabId || detectCurrentTab();
      if (!skipPersist && activeMainTab) {
        try { localStorage.setItem(`${MOBILE_TAB_PREFIX}${activeMainTab}`, name); } catch {}
      }
      const isDesktop = window.matchMedia('(min-width: 1024px)').matches;
      if (document.body) {
        document.body.dataset.mobileTab = name;
        delete document.body.dataset.controlsHidden;
      }
      // Ensure the current panel is not minimized/hidden when we select a tab.
      const panel = activeMainTab === '#tab-classic'
        ? document.getElementById('classic-controls-panel')
        : (activeMainTab === '#tab-wall'
          ? document.getElementById('wall-controls-panel')
          : document.getElementById('controls-panel'));
      panel?.classList.remove('minimized');
      if (panel) panel.style.display = '';
      updateSheets();
      updateMobileStacks(name);
      const buttons = document.querySelectorAll('#mobile-tabbar .mobile-tab-btn');
      buttons.forEach(btn => btn.setAttribute('aria-pressed', String(btn.dataset.mobileTab === name)));
    }
    window.__setMobileTab = setMobileTab;

    const NUDGE_POS_KEY = 'classic:nudgePos:v1';
    const NUDGE_MARGIN = 12;
    const NUDGE_SIZE_HINT = { w: 180, h: 200 };
    let floatingNudgeCollapsed = false;
    function clampNudgePos(pos, el) {
      const vw = window.innerWidth || 1024;
      const vh = window.innerHeight || 768;
      const rect = el?.getBoundingClientRect();
      const w = rect?.width || NUDGE_SIZE_HINT.w;
      const h = rect?.height || NUDGE_SIZE_HINT.h;
      return {
        x: Math.min(Math.max(pos.x, NUDGE_MARGIN), Math.max(NUDGE_MARGIN, vw - w - NUDGE_MARGIN)),
        y: Math.min(Math.max(pos.y, NUDGE_MARGIN), Math.max(NUDGE_MARGIN, vh - h - NUDGE_MARGIN))
      };
    }
    let nudgePos = null;
    let nudgePosInitialized = false;
    function loadNudgePos(el) {
      try {
        const saved = JSON.parse(localStorage.getItem(NUDGE_POS_KEY));
        if (saved && typeof saved.x === 'number' && typeof saved.y === 'number') return clampNudgePos(saved, el);
      } catch {}
      return clampNudgePos({ x: (window.innerWidth || 1024) - 240, y: 120 }, el);
    }
    function ensureNudgePos(el) {
      if (!nudgePos) nudgePos = loadNudgePos(el);
      return clampNudgePos(nudgePos, el);
    }
    function saveNudgePos(pos, el) {
      nudgePos = clampNudgePos(pos, el);
      try { localStorage.setItem(NUDGE_POS_KEY, JSON.stringify(nudgePos)); } catch {}
      return nudgePos;
    }
    function applyNudgePos(el, pos) {
      const p = clampNudgePos(pos || ensureNudgePos(el), el);
      el.style.left = `${p.x}px`;
      el.style.top = `${p.y}px`;
      el.style.right = 'auto';
      el.style.bottom = 'auto';
      nudgePos = p;
      nudgePosInitialized = true;
    }
    function updateFloatingNudge() {
      const el = document.getElementById('floating-topper-nudge');
      if (!el) return;
      const classicActive = document.body?.dataset.activeTab === '#tab-classic';
      const topperActive = document.body?.dataset.topperOverlay === '1';
      const shouldShow = classicActive && topperActive;
      const shouldShowPanel = shouldShow && !floatingNudgeCollapsed;
      el.classList.toggle('hidden', !shouldShowPanel);
      el.classList.toggle('collapsed', floatingNudgeCollapsed);
      el.style.display = shouldShowPanel ? 'block' : 'none';
      if (shouldShowPanel && !nudgePosInitialized) applyNudgePos(el, ensureNudgePos(el));
    }
    function showFloatingNudge() { floatingNudgeCollapsed = false; updateFloatingNudge(); }
    function hideFloatingNudge() {
      floatingNudgeCollapsed = true;
      const nudge = document.getElementById('floating-topper-nudge');
      if (nudge) { nudge.classList.add('hidden'); nudge.style.display = 'none'; }
      const tab = document.getElementById('floating-nudge-tab');
      if (tab) tab.classList.remove('hidden');
      updateFloatingNudge();
    }
    window.__updateFloatingNudge = updateFloatingNudge;
    window.__showFloatingNudge = showFloatingNudge;
    window.__hideFloatingNudge = hideFloatingNudge;

    // Tab switching
    if (orgSection && claSection && tabBtns.length > 0) {
      let current = '#tab-organic';
      const isMobileView = () => window.matchMedia('(max-width: 1023px)').matches;
      const updateMobileActionBarVisibility = () => {
        if (!mobileActionBar) return;
        const modalOpen = !!document.querySelector('.color-modal:not(.hidden)');
        const shouldShow = current === '#tab-organic' && isMobileView() && !modalOpen;
        mobileActionBar.classList.toggle('hidden', !shouldShow);
      };
      const wireMobileActionButtons = () => {
        const guardOrganic = () => current === '#tab-organic';
        const clickBtn = (sel) => { if (!guardOrganic()) return; document.querySelector(sel)?.click(); };
        const on = (id, fn) => document.getElementById(id)?.addEventListener('click', fn);
        on('mobile-act-undo', () => clickBtn('#tool-undo'));
        on('mobile-act-redo', () => clickBtn('#tool-redo'));
        on('mobile-act-eyedrop', () => clickBtn('#tool-eyedropper'));
        on('mobile-act-erase', () => {
          if (!guardOrganic()) return;
          const erase = document.getElementById('tool-erase');
          const draw = document.getElementById('tool-draw');
          const active = erase?.getAttribute('aria-pressed') === 'true';
          (active ? draw : erase)?.click();
        });
        on('mobile-act-clear', () => clickBtn('#clear-canvas-btn-top'));
        on('mobile-act-export', () => clickBtn('[data-export="png"]'));
      };
      wireMobileActionButtons();
      window.addEventListener('resize', updateMobileActionBarVisibility);
      function setTab(id, isInitial = false) {
        if (!id || !document.querySelector(id)) id = '#tab-organic';
        current = id;
        if (document.body) document.body.dataset.activeTab = id;
        orgSheet?.classList.remove('minimized');
        claSheet?.classList.remove('minimized');
        wallSheet?.classList.remove('minimized');
        orgSection.classList.toggle('hidden', id !== '#tab-organic');
        claSection.classList.toggle('hidden', id !== '#tab-classic');
        wallSection?.classList.toggle('hidden', id !== '#tab-wall');
        updateSheets();
        updateFloatingNudge();
        tabBtns.forEach(btn => {
          const active = btn.dataset.target === id;
          btn.classList.toggle('tab-active', active);
          btn.classList.toggle('tab-idle', !active);
          btn.setAttribute('aria-pressed', String(active));
        });
        if (!isInitial) {
          try { localStorage.setItem(ACTIVE_TAB_KEY, id); } catch {}
        }
        if (document.body) delete document.body.dataset.controlsHidden;
        const isOrganic = id === '#tab-organic';
        const showHeaderColor = id !== '#tab-classic';
        const clearTop = document.getElementById('clear-canvas-btn-top');
        if (clearTop) {
          clearTop.classList.toggle('hidden', !isOrganic);
          clearTop.style.display = isOrganic ? '' : 'none';
        }
        const headerActiveSwatch = document.getElementById('current-color-chip-global')?.closest('.flex');
        headerActiveSwatch?.classList.toggle('hidden', !showHeaderColor);
        const savedMobile = (() => {
          try { return localStorage.getItem(`${MOBILE_TAB_PREFIX}${id}`) || MOBILE_TAB_DEFAULT; } catch {}
          return MOBILE_TAB_DEFAULT;
        })();
        if (document.body) document.body.dataset.mobileTab = savedMobile;
        setMobileTab(savedMobile, id, true);
        orgSheet?.classList.toggle('hidden', id !== '#tab-organic');
        claSheet?.classList.toggle('hidden', id !== '#tab-classic');
        wallSheet?.classList.toggle('hidden', id !== '#tab-wall');
        window.updateExportButtonVisibility();
        updateMobileActionBarVisibility();
      }
      tabBtns.forEach(btn => {
        btn.addEventListener('click', (e) => {
          const button = e.target.closest('button[data-target]');
          if (button) setTab(button.dataset.target);
        });
      });
      let savedTab = null;
      try { savedTab = localStorage.getItem(ACTIVE_TAB_KEY); } catch {}
      setTab(savedTab || '#tab-organic', true);
      window.__whichTab = () => current;
      if (!document.body?.dataset?.mobileTab) {
        const initialMobile = (() => {
          try { return localStorage.getItem(`${MOBILE_TAB_PREFIX}${current}`) || MOBILE_TAB_DEFAULT; } catch {}
          return MOBILE_TAB_DEFAULT;
        })();
        document.body.dataset.mobileTab = initialMobile;
      }
      setMobileTab(document.body.dataset.mobileTab, current, true);
      updateSheets();
      updateMobileStacks(document.body.dataset.mobileTab);
      updateMobileActionBarVisibility();
    }

    // Mobile tabbar
    (function initMobileTabs() {
      const buttons = Array.from(document.querySelectorAll('#mobile-tabbar .mobile-tab-btn'));
      if (!buttons.length) return;
      buttons.forEach(btn => {
        btn.addEventListener('click', () => {
          const tab = btn.dataset.mobileTab || 'controls';
          const activeTabId = detectCurrentTab();
          const panel = activeTabId === '#tab-classic'
            ? document.getElementById('classic-controls-panel')
            : (activeTabId === '#tab-wall'
              ? document.getElementById('wall-controls-panel')
              : document.getElementById('controls-panel'));
          const currentTab = document.body.dataset.mobileTab;
          if (tab === currentTab) {
            panel.classList.toggle('minimized');
          } else {
            panel.classList.remove('minimized');
            setMobileTab(tab);
            panel.scrollTop = 0;
          }
        });
      });
      const mq = window.matchMedia('(min-width: 1024px)');
      const sync = () => {
        const current = document.body?.dataset?.mobileTab || MOBILE_TAB_DEFAULT;
        setMobileTab(current, detectCurrentTab(), true);
        updateFloatingNudge();
      };
      mq.addEventListener('change', sync);
      setMobileTab(document.body?.dataset?.mobileTab || MOBILE_TAB_DEFAULT, detectCurrentTab(), true);
      sync();
      const nudgeToggle = document.getElementById('floating-nudge-toggle');
      nudgeToggle?.addEventListener('click', () => {
        hideFloatingNudge();
      });
      const nudge = document.getElementById('floating-topper-nudge');
      const nudgeHeader = document.querySelector('#floating-topper-nudge .floating-nudge-header');
      if (nudge && nudgeHeader) {
        let dragId = null;
        let start = null;
        nudgeHeader.addEventListener('pointerdown', (e) => {
          if (e.target.closest('#floating-nudge-toggle')) return;
          dragId = e.pointerId;
          start = { x: e.clientX, y: e.clientY, pos: loadNudgePos(nudge) };
          nudge.classList.add('dragging');
          nudgeHeader.setPointerCapture(dragId);
        });
        nudgeHeader.addEventListener('pointermove', (e) => {
          if (dragId === null || e.pointerId !== dragId) return;
          if (!start) return;
          const dx = e.clientX - start.x;
          const dy = e.clientY - start.y;
          const next = clampNudgePos({ x: start.pos.x + dx, y: start.pos.y + dy });
          applyNudgePos(nudge, next);
        });
        const endDrag = (e) => {
          if (dragId === null || e.pointerId !== dragId) return;
          const rect = nudge.getBoundingClientRect();
          const next = clampNudgePos({ x: rect.left, y: rect.top }, nudge);
          saveNudgePos(next, nudge);
          nudge.classList.remove('dragging');
          dragId = null;
          start = null;
          try { nudgeHeader.releasePointerCapture(e.pointerId); } catch {}
        };
        nudgeHeader.addEventListener('pointerup', endDrag);
        nudgeHeader.addEventListener('pointercancel', endDrag);
        window.addEventListener('resize', () => {
          const pos = clampNudgePos(loadNudgePos(nudge), nudge);
          saveNudgePos(pos, nudge);
          nudgePosInitialized = false;
          applyNudgePos(nudge, pos);
        });
      }
    })();
  });
})();
