// --- Data Init & Colors ---
let projects = JSON.parse(localStorage.getItem('crochetCounters')) || [];
// New Earthy/Woodland Palette extracted from image vibes
const colors = [
    '#a17d63', // Soft oak
    '#7a8c6a', // Moss sage
    '#c7a272', // Warm amber
    '#b88b8a', // Rose clay
    '#7b9189', // Sage teal
    '#aa9a7a', // Wheat linen
    '#5f6d57', // Forest dusk
    '#b07d6f', // Terra blush
    '#6d5947', // Walnut
    '#c4b08a', // Oat
    '#7c7565', // Stone
    '#8ca58c'  // Meadow
];
const oldColors = [
    '#b56b54', // Rust/Mushroom
    '#7a8b4f', // Olive Green
    '#cba052', // Mustard/Daisy center
    '#5f8a8b', // Muted Teal
    '#8c6246', // Warm Wood tone
    '#a87b8c', // Dusty Rose
    '#4a5d43', // Deep Forest
    '#9c7e63'  // Taupe
];

// --- State Variables ---
let modalState = { type: null, projectId: null, partId: null };
const app = document.getElementById('app');
const modal = document.getElementById('modalOverlay');
const modalInput = document.getElementById('modalInput');
const modalTitle = document.getElementById('modalTitle');
const hapticTick = () => { if ('vibrate' in navigator) navigator.vibrate(12); };
const installBtn = document.getElementById('installBtn');
const importInput = document.getElementById('importFile');
const motionBtn = document.getElementById('motionBtn');
const colorOverlay = document.getElementById('colorOverlay');
const colorGrid = document.getElementById('colorGrid');
const customColorInput = document.getElementById('customColorInput');
const saveOverlay = document.getElementById('saveOverlay');
const saveList = document.getElementById('saveList');
let pendingSaveSelection = [];
let lastCountPulse = null;
let lastFinishedId = null;
let fireflyTimer = null;
let fireflyActive = false;
let titleClicks = [];
let easterEggCooling = false;

// --- Service Worker ---
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js').catch(() => {
            // fail silently; optional log
        });
    });
}

// --- Install Prompt ---
let deferredInstallPrompt = null;
const isStandalone = () =>
    window.matchMedia('(display-mode: standalone)').matches ||
    window.navigator.standalone === true;

function hideInstall() {
    if (installBtn) installBtn.classList.add('hidden');
}
function showInstall() {
    if (installBtn) installBtn.classList.remove('hidden');
}

window.addEventListener('beforeinstallprompt', (e) => {
    e.preventDefault();
    deferredInstallPrompt = e;
    if (!isStandalone()) showInstall();
});

window.addEventListener('appinstalled', () => {
    deferredInstallPrompt = null;
    hideInstall();
});

if (installBtn) {
    installBtn.addEventListener('click', async () => {
        if (!deferredInstallPrompt) return;
        deferredInstallPrompt.prompt();
        const choice = await deferredInstallPrompt.userChoice;
        if (choice.outcome === 'accepted') hideInstall();
        deferredInstallPrompt = null;
    });
}

if (isStandalone()) hideInstall();

// --- Sweet-ish Alerts ---
function removeSwal() {
    const existing = document.querySelector('.swal-overlay');
    if (existing) existing.remove();
}

function showConfirm({ title = 'Are you sure?', text = '', confirmText = 'Yes', cancelText = 'Cancel', danger = false } = {}) {
    return new Promise(resolve => {
        removeSwal();
        const overlay = document.createElement('div');
        overlay.className = 'swal-overlay';
        overlay.innerHTML = `
            <div class="swal-dialog">
                <div class="swal-title">${title}</div>
                <div class="swal-text">${text}</div>
                <div class="swal-actions">
                    <button class="swal-btn swal-cancel">${cancelText}</button>
                    <button class="swal-btn ${danger ? 'swal-danger' : 'swal-confirm'}">${confirmText}</button>
                </div>
            </div>
        `;
        const cancelBtn = overlay.querySelector('.swal-cancel');
        const confirmBtn = overlay.querySelector('.swal-confirm, .swal-danger');
        cancelBtn.onclick = () => { removeSwal(); resolve(false); };
        confirmBtn.onclick = () => { removeSwal(); resolve(true); };
        overlay.addEventListener('click', (e) => { if (e.target === overlay) { removeSwal(); resolve(false); } });
        document.addEventListener('keydown', function onKey(e) {
            if (e.key === 'Escape') { removeSwal(); resolve(false); document.removeEventListener('keydown', onKey); }
        });
        document.body.appendChild(overlay);
    });
}

function showAlert({ title = 'Notice', text = '' } = {}) {
    return new Promise(resolve => {
        removeSwal();
        const overlay = document.createElement('div');
        overlay.className = 'swal-overlay';
        overlay.innerHTML = `
            <div class="swal-dialog">
                <div class="swal-title">${title}</div>
                <div class="swal-text">${text}</div>
                <div class="swal-actions">
                    <button class="swal-btn swal-confirm">OK</button>
                </div>
            </div>
        `;
        const okBtn = overlay.querySelector('.swal-confirm');
        okBtn.onclick = () => { removeSwal(); resolve(); };
        overlay.addEventListener('click', (e) => { if (e.target === overlay) { removeSwal(); resolve(); } });
        document.addEventListener('keydown', function onKey(e) {
            if (e.key === 'Escape') { removeSwal(); resolve(); document.removeEventListener('keydown', onKey); }
        });
        document.body.appendChild(overlay);
    });
}

// --- Theme Logic ---
let isDarkMode = JSON.parse(localStorage.getItem('crochetDarkMode'));
if (isDarkMode === null) {
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        isDarkMode = true;
    } else {
        isDarkMode = false;
    }
}
let animationsEnabled = JSON.parse(localStorage.getItem('crochetAnimations'));
if (animationsEnabled === null) animationsEnabled = true;

function applyTheme() {
    if (isDarkMode) {
        document.body.classList.add('dark-mode');
        document.getElementById('themeBtn').innerHTML = '<i class="fa-solid fa-moon"></i>';
    } else {
        document.body.classList.remove('dark-mode');
        document.getElementById('themeBtn').innerHTML = '<i class="fa-solid fa-sun"></i>';
    }
    handleAmbientDrift();
    updateMotionBtn();
}

function toggleTheme() {
    isDarkMode = !isDarkMode;
    localStorage.setItem('crochetDarkMode', isDarkMode);
    applyTheme();
    if (animationsEnabled) {
        document.body.classList.add('theme-animating');
        setTimeout(() => document.body.classList.remove('theme-animating'), 750);
    }
}
applyTheme();

function updateMotionBtn() {
    if (!motionBtn) return;
    motionBtn.innerHTML = animationsEnabled ? '<i class="fa-solid fa-wand-magic-sparkles"></i>' : '<i class="fa-solid fa-ban"></i>';
    motionBtn.title = animationsEnabled ? 'Toggle Animations' : 'Animations disabled';
}

function toggleAnimations() {
    animationsEnabled = !animationsEnabled;
    localStorage.setItem('crochetAnimations', animationsEnabled);
    updateMotionBtn();
    if (!animationsEnabled) {
        stopAmbientDrift();
        document.body.classList.remove('theme-animating');
    } else {
        handleAmbientDrift();
    }
}

function openColorPicker(pId, partId) {
    if (!colorOverlay || !colorGrid) return;
    const project = projects.find(p => p.id === pId);
    const part = project.parts.find(pt => pt.id === partId);
    colorGrid.innerHTML = colors.map(c => `
        <button class="color-swatch" style="background:${c}" onclick="setPartColor(${pId}, ${partId}, '${c}'); closeColorPicker();"></button>
    `).join('');
    if (customColorInput) {
        customColorInput.value = part.color || project.color || colors[0];
        customColorInput.oninput = (e) => {
            setPartColor(pId, partId, e.target.value);
        };
    }
    colorOverlay.classList.add('active');
    colorOverlay.dataset.projectId = pId;
    colorOverlay.dataset.partId = partId;
}

function closeColorPicker() {
    if (!colorOverlay) return;
    colorOverlay.classList.remove('active');
    colorGrid.innerHTML = '';
    colorOverlay.dataset.projectId = '';
    colorOverlay.dataset.partId = '';
}

function exportData(selectedProjects = projects) {
    const payload = {
        projects: selectedProjects,
        isDarkMode,
        animationsEnabled
    };
    const names = selectedProjects.map(p => p.name || 'Project').join('_').replace(/\s+/g, '-').slice(0, 50) || 'projects';
    const filename = `toadstool_${names}.json`;
    const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
}

function triggerImport() {
    if (!importInput) return;
    importInput.value = '';
    importInput.click();
}

async function handleImport(event) {
    const file = event.target.files[0];
    if (!file) return;
    try {
        const text = await file.text();
        const data = JSON.parse(text);
        if (!data.projects || !Array.isArray(data.projects)) throw new Error('Invalid file');
        projects = data.projects;
        if (typeof data.isDarkMode === 'boolean') {
            isDarkMode = data.isDarkMode;
            localStorage.setItem('crochetDarkMode', isDarkMode);
        }
        if (typeof data.animationsEnabled === 'boolean') {
            animationsEnabled = data.animationsEnabled;
            localStorage.setItem('crochetAnimations', animationsEnabled);
        }
        localStorage.setItem('crochetCounters', JSON.stringify(projects));
        applyTheme();
        render();
    } catch (err) {
        showAlert({ title: 'Import failed', text: err.message });
    }
    event.target.value = '';
}

if (importInput) {
    importInput.addEventListener('change', handleImport);
}

function openSaveModal() {
    if (!saveOverlay || !saveList) return;
    saveList.innerHTML = '';
    pendingSaveSelection = projects.map(p => p.id);
    projects.forEach(p => {
        const item = document.createElement('label');
        item.className = 'save-item';
        item.innerHTML = `
            <input type="checkbox" checked data-id="${p.id}">
            <span>${p.name}</span>
        `;
        saveList.appendChild(item);
    });
    saveOverlay.classList.add('active');
}

function closeSaveModal() {
    if (!saveOverlay) return;
    saveOverlay.classList.remove('active');
    saveList.innerHTML = '';
}

function exportSelected() {
    if (!saveOverlay) return;
    const inputs = saveList.querySelectorAll('input[type="checkbox"]');
    const selectedIds = Array.from(inputs).filter(i => i.checked).map(i => Number(i.dataset.id));
    if (selectedIds.length === 0) { closeSaveModal(); return; }
    const selectedProjects = projects.filter(p => selectedIds.includes(p.id));
    exportData(selectedProjects);
    closeSaveModal();
}

// --- Firefly Animation ---
function spawnFirefly({ markActive = false, source = 'ambient', side = 'left' } = {}) {
    const wrap = document.createElement('div');
    wrap.className = 'firefly-wrap';
    const el = document.createElement('div');
    el.className = 'firefly';
    const top = Math.random() * 55 + 5; // 5vh–60vh
    const scale = 0.9 + Math.random() * 0.4;
    const duration = 12 + Math.random() * 8; // 12–20s
    const chosenSide = side === 'any' ? ['left','right','top','bottom'][Math.floor(Math.random()*4)] : side;
    let startX = '-10vw', endX = '110vw', startY = `${top}vh`, endY = `${top + (Math.random()*12 - 6)}vh`;
    let midX = '25vw', midY = `${top - 6}vh`, mid2X = '65vw', mid2Y = `${top + 6}vh`;
    if (chosenSide === 'right') {
        startX = '110vw'; endX = '-10vw';
        midX = '-25vw'; mid2X = '-65vw';
    } else if (chosenSide === 'top') {
        const x = Math.random()*80 + 10;
        startX = `${x}vw`; endX = `${x + (Math.random()*20 - 10)}vw`;
        startY = '-12vh'; endY = '110vh';
        midX = `${x + 8}vw`; mid2X = `${x - 8}vw`;
        midY = '25vh'; mid2Y = '65vh';
    } else if (chosenSide === 'bottom') {
        const x = Math.random()*80 + 10;
        startX = `${x}vw`; endX = `${x + (Math.random()*20 - 10)}vw`;
        startY = '110vh'; endY = '-12vh';
        midX = `${x - 8}vw`; mid2X = `${x + 8}vw`;
        midY = '75vh'; mid2Y = '35vh';
    }
    wrap.style.setProperty('--fly-scale', scale);
    wrap.style.setProperty('--fly-duration', `${duration}s`);
    wrap.style.setProperty('--fly-start-x', startX);
    wrap.style.setProperty('--fly-start-y', startY);
    wrap.style.setProperty('--fly-mid-x', midX);
    wrap.style.setProperty('--fly-mid-y', midY);
    wrap.style.setProperty('--fly-mid2-x', mid2X);
    wrap.style.setProperty('--fly-mid2-y', mid2Y);
    wrap.style.setProperty('--fly-end-x', endX);
    wrap.style.setProperty('--fly-end-y', endY);
    if (markActive) fireflyActive = true;
    wrap.addEventListener('animationend', (e) => {
        if (e.animationName !== 'fireflyGlide') return;
        wrap.remove();
        if (markActive) fireflyActive = false;
    });
    wrap.appendChild(el);
    document.body.appendChild(wrap);
}

function spawnSeed({ markActive = false, source = 'ambient' } = {}) {
    const wrap = document.createElement('div');
    wrap.className = 'seed-wrap';
    const el = document.createElement('div');
    el.className = 'seed';
    const top = Math.random() * 55 + 5; // 5vh–60vh
    const scale = 0.85 + Math.random() * 0.4;
    const duration = 14 + Math.random() * 8; // 14–22s
    const tilt = (Math.random() * 16 + 8) * (Math.random() < 0.5 ? -1 : 1); // +/-8–24deg
    const sway = 4 + Math.random() * 6; // px
    const fromLeft = Math.random() < 0.5;
    const start = fromLeft ? '-12vw' : '112vw';
    const mid = fromLeft ? '30vw' : '-30vw';
    const end = fromLeft ? '112vw' : '-12vw';
    wrap.style.top = `${top}vh`;
    wrap.style.setProperty('--seed-scale', scale);
    wrap.style.setProperty('--seed-duration', `${duration}s`);
    wrap.style.setProperty('--seed-tilt', `${tilt}deg`);
    wrap.style.setProperty('--seed-sway', `${sway}px`);
    wrap.style.setProperty('--seed-start', start);
    wrap.style.setProperty('--seed-mid', mid);
    wrap.style.setProperty('--seed-end', end);
    if (markActive) fireflyActive = true;
    wrap.addEventListener('animationend', (e) => {
        if (e.animationName !== 'seedGlide') return;
        wrap.remove();
        if (markActive) fireflyActive = false;
    });
    wrap.appendChild(el);
    document.body.appendChild(wrap);
}

function stopAmbientDrift() {
    if (fireflyTimer) {
        clearTimeout(fireflyTimer);
        fireflyTimer = null;
    }
    document.querySelectorAll('.firefly-wrap').forEach(el => el.remove());
    document.querySelectorAll('.seed-wrap').forEach(el => el.remove());
    fireflyActive = false;
}

function scheduleAmbientDrift() {
    const delay = 26000 + Math.random() * 18000; // 26–44s
    fireflyTimer = setTimeout(() => {
        if (!animationsEnabled) { stopAmbientDrift(); return; }
        if (isDarkMode) {
            spawnFirefly();
        } else {
            spawnSeed();
        }
        scheduleAmbientDrift();
    }, delay);
}

function handleAmbientDrift() {
    stopAmbientDrift();
    if (!animationsEnabled) return;
    if (isDarkMode) {
        spawnFirefly();
    } else {
        spawnSeed();
    }
    scheduleAmbientDrift();
}
handleAmbientDrift();

const logoIcon = document.querySelector('.brand-icon');
if (logoIcon) {
    logoIcon.addEventListener('click', () => {
        if (!animationsEnabled || fireflyActive) return;
        if (isDarkMode) {
            spawnFirefly({ markActive: true, source: 'logo', side: 'any' });
        } else {
            spawnSeed({ markActive: true, source: 'logo' });
        }
    });
}
if (colorOverlay) {
    colorOverlay.addEventListener('click', (e) => {
        if (e.target === colorOverlay) closeColorPicker();
    });
}
document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && colorOverlay && colorOverlay.classList.contains('active')) {
        closeColorPicker();
    }
});
const importBtn = document.getElementById('importBtn');
if (importBtn) {
    importBtn.addEventListener('click', triggerImport);
}

const titleEl = document.getElementById('appTitle');
if (titleEl) {
    titleEl.addEventListener('click', () => {
        const now = Date.now();
        titleClicks = titleClicks.filter(ts => now - ts < 7000);
        titleClicks.push(now);
        if (titleClicks.length >= 5 && !easterEggCooling) {
            easterEggCooling = true;
            triggerBurst();
            setTimeout(() => {
                easterEggCooling = false;
                titleClicks = [];
            }, 8000);
        }
    });
}

function triggerBurst() {
    if (!animationsEnabled) return;
    const burstCount = isDarkMode ? 24 : 18;
    const spawner = isDarkMode ? (opts) => spawnFirefly({ ...opts, side: 'any' }) : spawnSeed;
    for (let i = 0; i < burstCount; i++) {
        const jitter = Math.random() * 200;
        setTimeout(() => spawner({ source: 'burst' }), i * 140 + jitter);
    }
}

// --- Focus Mode Logic ---
let wakeLock = null;
let isFocusMode = false;
const focusBtn = document.getElementById('focusBtn');

// --- Migration Check ---
if (projects.length > 0) {
    let changed = false;
    projects.forEach((p, index) => {
        if (!p.parts) { p.parts = []; changed = true; }
        if (!p.color) { p.color = colors[index % colors.length]; changed = true; }
        const oldIdx = oldColors.indexOf(p.color);
        if (oldIdx !== -1) { p.color = colors[oldIdx % colors.length]; changed = true; }
        if (p.note === undefined) { p.note = ''; changed = true; }
        p.parts.forEach(pt => {
            if (pt.max === undefined) { pt.max = null; changed = true; }
            if (pt.note === undefined) { pt.note = ''; changed = true; }
            if (!pt.color) { pt.color = p.color; changed = true; }
            const oldPartIdx = oldColors.indexOf(pt.color);
            if (oldPartIdx !== -1) { pt.color = colors[oldPartIdx % colors.length]; changed = true; }
        });
    });
    if (changed) { localStorage.setItem('crochetCounters', JSON.stringify(projects)); }
}

// --- Core Functions ---
function save() {
    localStorage.setItem('crochetCounters', JSON.stringify(projects));
    render();
}

    async function toggleFocusMode() {
        if (!isFocusMode) {
            try {
                if (document.documentElement.requestFullscreen) await document.documentElement.requestFullscreen();
                if ('wakeLock' in navigator) {
                    wakeLock = await navigator.wakeLock.request('screen');
                }
                isFocusMode = true;
                focusBtn.classList.add('is-active');
            } catch (err) { showAlert({ title: 'Focus Mode failed', text: err.message }); }
        } else {
            if (document.fullscreenElement) document.exitFullscreen();
            if (wakeLock !== null) { wakeLock.release(); wakeLock = null; }
            isFocusMode = false;
            focusBtn.classList.remove('is-active');
        }
    }
document.addEventListener('visibilitychange', async () => {
    if (wakeLock !== null && document.visibilityState === 'visible') {
        wakeLock = await navigator.wakeLock.request('screen');
    }
});

// --- Interaction Logic ---
    async function deleteProject(pId) {
        const ok = await showConfirm({ title: 'Delete project?', text: 'This will remove the entire project.', confirmText: 'Delete', danger: true });
        if (ok) { projects = projects.filter(p => p.id !== pId); save(); }
    }
    function toggleProjectCollapse(pId) {
        const project = projects.find(p => p.id === pId);
        project.collapsed = !project.collapsed;
        save();
    }
    function renameProject(pId) {
        modalState = { type: 'renameProject', pId, partId: null };
        const project = projects.find(p => p.id === pId);
        modalTitle.innerText = "Rename Project";
        modalInput.value = project.name;
        modalInput.type = "text";
        modalInput.placeholder = "Project name";
        modal.classList.add('active');
        setTimeout(() => modalInput.focus(), 100);
    }
    async function deletePart(pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        if (part.locked) return;
        const ok = await showConfirm({ title: 'Delete part?', text: 'This part will be removed.', confirmText: 'Delete', danger: true });
        if (ok) {
            project.parts = project.parts.filter(pt => pt.id !== partId);
            save();
        }
    }
    function togglePartMinimize(pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        part.minimized = !part.minimized;
        save();
    }
    function togglePartLock(pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        part.locked = !part.locked;
        save();
    }
    function setPartColor(pId, partId, color) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        part.color = color;
        save();
    }
    function togglePartFinish(pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        part.finished = !part.finished;
        if(part.finished) { part.locked = false; lastFinishedId = part.id; } else { lastFinishedId = null; }
        save();
    }
    function updateCount(pId, partId, change) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        if (part.locked || part.finished) return;
        part.count += change;
        if (part.max !== null && part.count > part.max) part.count = part.max;
        if (part.count < 0) part.count = 0;
        hapticTick();
        lastCountPulse = { partId, dir: change > 0 ? 'up' : 'down' };
        save();
    }
    async function resetCount(pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        if (part.locked || part.finished) return;
        const ok = await showConfirm({ title: 'Reset count?', text: 'Set this count back to zero.', confirmText: 'Reset', danger: true });
        if(ok) {
            part.count = 0;
            save();
        }
    }

// --- Modal Logic ---
function openModal(type, pId = null, partId = null) {
    modalState = { type, pId, partId };
    modalInput.value = "";
    
        if (type === 'addProject') {
            modalTitle.innerText = "New Project Name";
            modalInput.type = "text"; modalInput.placeholder = "e.g., Amigurumi Bear";
        } else if (type === 'addPart') {
            modalTitle.innerText = "New Part Name";
            modalInput.type = "text"; modalInput.placeholder = "e.g., Head";
        } else if (type === 'setMax') {
            const part = projects.find(p => p.id === pId).parts.find(pt => pt.id === partId);
            modalTitle.innerText = "Set Max Stitches";
            modalInput.value = part.max ?? '';
            modalInput.type = "number";
            modalInput.placeholder = "Leave blank to clear";
        } else if (type === 'renamePart') {
            const part = projects.find(p => p.id === pId).parts.find(pt => pt.id === partId);
            if(part.locked || part.finished) return;
            modalTitle.innerText = "Rename Part";
            modalInput.value = part.name; modalInput.type = "text";
        } else if (type === 'manualCount') {
            const part = projects.find(p => p.id === pId).parts.find(pt => pt.id === partId);
            if(part.locked || part.finished) return;
            modalTitle.innerText = "Set Row Count";
            modalInput.value = part.count; modalInput.type = "number";
    }
    else if (type === 'setMax') {
        const part = projects.find(p => p.id === pId).parts.find(pt => pt.id === partId);
        if (part.locked) return;
    }
    modal.classList.add('active');
    setTimeout(() => modalInput.focus(), 100);
}
function closeModal() {
    modal.classList.remove('active');
    modalInput.blur();
}
    function saveModal() {
        const val = modalInput.value.trim();
        if (!val && modalState.type !== 'manualCount' && modalState.type !== 'setMax') return closeModal();

        if (modalState.type === 'addProject') {
            const nextColor = colors[projects.length % colors.length];
            projects.push({ id: Date.now(), name: val, color: nextColor, collapsed: false, parts: [] });
            projects[projects.length-1].parts.push({ id: Date.now() + 1, name: 'Part 1', count: 0, locked: false, finished: false, minimized: false, max: null, color: nextColor });
        } 
        else if (modalState.type === 'addPart') {
            const project = projects.find(p => p.id === modalState.pId);
            project.parts.push({ id: Date.now(), name: val, count: 0, locked: false, finished: false, minimized: false, max: null, color: project.color });
            project.collapsed = false;
        }
        else if (modalState.type === 'renamePart') {
            const part = projects.find(p => p.id === modalState.pId).parts.find(pt => pt.id === modalState.partId);
            part.name = val;
        }
        else if (modalState.type === 'renameProject') {
        const project = projects.find(p => p.id === modalState.pId);
        project.name = val;
    }
        else if (modalState.type === 'manualCount') {
            const num = parseInt(val);
            if (!isNaN(num) && num >= 0) {
                const part = projects.find(p => p.id === modalState.pId).parts.find(pt => pt.id === modalState.partId);
                part.count = num;
                if (part.max !== null && part.count > part.max) part.count = part.max;
            }
        }
        else if (modalState.type === 'setMax') {
            const part = projects.find(p => p.id === modalState.pId).parts.find(pt => pt.id === modalState.partId);
            if (val === '') {
                part.max = null;
            } else {
                const num = parseInt(val);
                if (!isNaN(num) && num > 0) {
                    part.max = num;
                    if (part.count > part.max) part.count = part.max;
                }
            }
        }
    save();
    closeModal();
}
    modalInput.addEventListener("keyup", (e) => { if (e.key === "Enter") saveModal(); });

    function toggleNote(id) {
        const el = document.getElementById(id);
        if (!el) return;
        el.classList.toggle('show');
    }

    function updateProjectNote(e, pId) {
        const project = projects.find(p => p.id === pId);
        project.note = e.target.value;
        localStorage.setItem('crochetCounters', JSON.stringify(projects));
    }

    function updatePartNote(e, pId, partId) {
        const project = projects.find(p => p.id === pId);
        const part = project.parts.find(pt => pt.id === partId);
        part.note = e.target.value;
        localStorage.setItem('crochetCounters', JSON.stringify(projects));
    }

// --- Render Logic ---
function render() {
    app.innerHTML = '';
    if (projects.length === 0) {
        app.innerHTML = '<div class="empty-state">Toadstools & twine await...<br>Tap + to begin a new project.</div>';
        return;
    }

    const grid = document.createElement('div');
    grid.className = 'projects-grid';

    projects.forEach(project => {
        const sortedParts = [...project.parts].sort((a, b) => a.finished - b.finished);
        const projectCollapsedClass = project.collapsed ? 'project-collapsed' : '';
        
        let partsHtml = '';
        sortedParts.forEach(part => {
            const accent = part.color || project.color;
            const isLocked = part.locked ? 'is-locked' : '';
            const isFinished = part.finished ? 'is-finished' : '';
            const isMinimized = part.minimized ? 'is-minimized' : '';
            const lockIcon = part.locked ? '<i class="fa-solid fa-lock"></i>' : '<i class="fa-solid fa-lock-open"></i>';
            const lockBtnClass = part.locked ? 'btn-lock locked-active' : 'btn-lock';
            const controlsDimmed = (part.locked || part.finished) ? 'dimmed' : '';
            const hideControls = (part.finished || part.minimized) ? 'hidden-controls' : '';
            const showSetMax = part.minimized ? 'hidden' : '';
            const partNoteId = `part-note-${project.id}-${part.id}`;
            const countId = `count-${part.id}`;
            const pulseClass = lastCountPulse && lastCountPulse.partId === part.id
                ? (lastCountPulse.dir === 'up' ? 'count-bump-up' : 'count-bump-down')
                : '';
            const finishPulseClass = part.finished && lastFinishedId === part.id ? 'finish-shimmer' : '';
            const partCardId = `part-${part.id}`;
            const partCardFullClass = `${isLocked} ${isFinished} ${isMinimized} ${finishPulseClass}`;
            const lockDisabled = part.locked ? 'disabled' : '';
            const actionsHtml = part.minimized
                ? `<div class="part-actions"><button class="icon-btn btn-toggle-part" onclick="togglePartMinimize(${project.id}, ${part.id})" title="Expand"><i class="fa-solid fa-chevron-down"></i></button></div>`
                : `<div class="part-actions">
                        <button class="btn-color" style="--project-color: ${accent}" onclick="openColorPicker(${project.id}, ${part.id})" title="Set color"></button>
                        <button class="icon-btn btn-reset-part" onclick="resetCount(${project.id}, ${part.id})" ${isFinished || part.locked ? 'disabled' : ''}><i class="fa-solid fa-rotate-left"></i></button>
                        <button class="icon-btn btn-delete-part" onclick="deletePart(${project.id}, ${part.id})" ${lockDisabled}><i class="fa-solid fa-trash"></i></button>
                        <button class="icon-btn btn-toggle-part" onclick="togglePartMinimize(${project.id}, ${part.id})" title="Minimize"><i class="fa-solid fa-chevron-down"></i></button>
                    </div>`;
            const countSubtext = part.minimized ? '' : `
                <div class="count-subtext">
                    ${part.max !== null ? `<strong>${part.count}</strong> / ${part.max}` : 'No max set'}
                    <button class="icon-btn ${showSetMax}" onclick="openModal('setMax', ${project.id}, ${part.id})" title="Set max" ${lockDisabled}><i class="fa-solid fa-gear"></i></button>
                </div>
            `;
            
            partsHtml += `
            <div class="part-card ${partCardFullClass}" id="${partCardId}" style="--project-color: ${accent}">
                <div class="part-header">
                    <div class="part-name-group">
                        <label class="check-container">
                            <input type="checkbox" ${part.finished ? 'checked' : ''} onchange="togglePartFinish(${project.id}, ${part.id})">
                            <span class="checkmark"></span>
                        </label>
                        <span class="part-name" onclick="openModal('renamePart', ${project.id}, ${part.id})">${part.name}</span>
                        <span class="part-mini-count">${part.count}</span>
                    </div>
                    ${actionsHtml}
                </div>
                <div class="count-display ${pulseClass}" id="${countId}" ondblclick="openModal('manualCount', ${project.id}, ${part.id})">${part.count}</div>
                ${countSubtext}
                <div class="controls ${hideControls}">
                    <button class="action-btn btn-minus ${controlsDimmed}" onclick="updateCount(${project.id}, ${part.id}, -1)">-</button>
                    <button class="action-btn ${lockBtnClass}" onclick="togglePartLock(${project.id}, ${part.id})">${lockIcon}</button>
                    <button class="action-btn btn-plus ${controlsDimmed}" onclick="updateCount(${project.id}, ${part.id}, 1)">+</button>
                </div>
                <div class="note-area" id="${partNoteId}">
                    <textarea placeholder="Notes for this part..." oninput="updatePartNote(event, ${project.id}, ${part.id})">${part.note || ''}</textarea>
                </div>
                <button class="note-toggle" onclick="toggleNote('${partNoteId}')">Notes</button>
            </div>`;
        });

        const projectContainer = document.createElement('div');
        projectContainer.className = `project-container ${projectCollapsedClass}`;
        projectContainer.style = `--project-color: ${project.color}`;
        const projectNoteId = `project-note-${project.id}`;
        projectContainer.innerHTML = `
            <div class="project-header">
                <div class="project-title-group">
                    <button class="btn-toggle-project" onclick="toggleProjectCollapse(${project.id})">▼</button>
                    <span class="project-title">${project.name}</span>
                    <button class="btn-rename-project" onclick="renameProject(${project.id})" title="Rename project"><span class="icon-pencil">✎</span></button>
                </div>
                <div class="project-actions">
                    <button class="btn-add-part" onclick="openModal('addPart', ${project.id})">+ Part</button>
                    <button class="btn-delete-project" onclick="deleteProject(${project.id})">×</button>
                </div>
            </div>
            <div class="note-area" id="${projectNoteId}">
                <textarea placeholder="Notes for this project..." oninput="updateProjectNote(event, ${project.id})">${project.note || ''}</textarea>
            </div>
            <button class="note-toggle" onclick="toggleNote('${projectNoteId}')">Notes</button>
            <div class="part-list">${partsHtml}</div>
        `;
        grid.appendChild(projectContainer);
    });

    lastCountPulse = null;
    lastFinishedId = null;
    app.appendChild(grid);
}

render();
