LOCAL
/* ═══════════════════════════════════════ PARTE 3: BANNER SWIPE + NOTICIAS ELITE ═══════════════════════════════════════ */ const bannerNews = [ { id:'bn1', en:"Neuroplasticity: Your brain rewires itself in 7 days of focused practice", es:"Neuroplasticidad: tu cerebro se reconfigura en 7 días de práctica enfocada", src:"Nature Neuroscience", img:"https://picsum.photos/seed/neuro1/800/400", url:"https://www.nature.com/subjects/neuroplasticity", category:"neuroplasticidad", weight:10 }, { id:'bn2', en:"Bilingual brains show 4x more white matter density — subliminal learning works", es:"Cerebros bilingües muestran 4x más densidad de materia blanca — el aprendizaje subliminal funciona", src:"ArXiv Cognitive Science", img:"https://picsum.photos/seed/lang2/800/400", url:"https://arxiv.org/list/cs.CY/recent", category:"idiomas", weight:9 }, { id:'bn3', en:"Subconscious processing makes 95% of decisions — hack it with priming", es:"El subconsciente toma el 95% de las decisiones — hackéalo con priming", src:"Harvard Business Review", img:"https://picsum.photos/seed/sub3/800/400", url:"https://hbr.org/topic/decision-making", category:"subconsciente", weight:10 }, { id:'bn4', en:"Consciousness is not a thing — it's a process, like a flame", es:"La conciencia no es una cosa — es un proceso, como una llama", src:"Scientific American", img:"https://picsum.photos/seed/consc4/800/400", url:"https://www.scientificamerican.com/topic/consciousness/", category:"conciencia", weight:8 }, { id:'bn5', en:"Sleep spindles lock in motor learning — skip sleep, lose the skill", es:"Los husos del sueño bloquean el aprendizaje motor — salta el sueño, pierdes la habilidad", src:"Cell Reports", img:"https://picsum.photos/seed/sleep5/800/400", url:"https://www.cell.com/cell-reports", category:"neuroplasticidad", weight:9 }, { id:'bn6', en:"ENG→ESP subtitle training activates mirror neurons faster than traditional study", es:"Entrenamiento con subtítulos ENG→ESP activa neuronas espejo más rápido que el estudio tradicional", src:"PLOS ONE", img:"https://picsum.photos/seed/subs6/800/400", url:"https://journals.plos.org/plosone/", category:"idiomas", weight:8 }, { id:'bn7', en:"Flow state is measurable: gamma waves spike 300% during deep focus", es:"El estado de flow es medible: ondas gamma aumentan 300% durante el foco profundo", src:"Frontiers in Psychology", img:"https://picsum.photos/seed/flow7/800/400", url:"https://www.frontiersin.org/journals/psychology", category:"conciencia", weight:9 }, { id:'bn8', en:"Dopamine baseline resets after 14 days without cheap stimulation", es:"La línea base de dopamina se resetea tras 14 días sin estimulación barata", src:"Journal of Neuroscience", img:"https://picsum.photos/seed/dop8/800/400", url:"https://www.jneurosci.org/", category:"neuroplasticidad", weight:10 } ]; let bannerIdx = 0; let bannerDismissed = JSON.parse(localStorage.getItem('stone_banner_dismissed') || '[]'); let bannerTimer = null; function buildBanner() { const track = document.getElementById('banner-track'); const dots = document.getElementById('banner-dots'); if (!track) return; // Filtrar descartados const visible = bannerNews.filter(n => !bannerDismissed.includes(n.id)); if (!visible.length) { document.getElementById('banner-wrap').style.display = 'none'; return; } track.innerHTML = visible.map((n, i) => ` `).join(''); dots.innerHTML = visible.map((_, i) => ``).join(''); // Swipe táctil let startX = 0, diffX = 0, dragging = false; const wrap = document.getElementById('banner-wrap'); wrap.addEventListener('touchstart', e => { startX = e.touches[0].clientX; dragging = true; track.style.transition = 'none'; }, {passive:true}); wrap.addEventListener('touchmove', e => { if (!dragging) return; diffX = e.touches[0].clientX - startX; const base = -bannerIdx * wrap.offsetWidth; track.style.transform = `translateX(${base + diffX}px)`; }, {passive:true}); wrap.addEventListener('touchend', () => { if (!dragging) return; dragging = false; track.style.transition = 'transform .5s cubic-bezier(.25,.8,.25,1)'; if (Math.abs(diffX) > 50) { if (diffX < 0 && bannerIdx < visible.length - 1) bannerIdx++; else if (diffX > 0 && bannerIdx > 0) bannerIdx--; } diffX = 0; updateBannerPos(visible.length); }); // Auto-rotate clearInterval(bannerTimer); bannerTimer = setInterval(() => { bannerIdx = (bannerIdx + 1) % visible.length; updateBannerPos(visible.length); }, 6000); } function updateBannerPos(total) { const track = document.getElementById('banner-track'); const wrap = document.getElementById('banner-wrap'); const dots = document.getElementById('banner-dots'); track.style.transform = `translateX(-${bannerIdx * wrap.offsetWidth}px)`; dots.querySelectorAll('span').forEach((d, i) => d.className = i === bannerIdx ? 'active' : ''); } function goToSlide(i) { bannerIdx = i; const visible = bannerNews.filter(n => !bannerDismissed.includes(n.id)); updateBannerPos(visible.length); } function dismissBanner(id) { bannerDismissed.push(id); localStorage.setItem('stone_banner_dismissed', JSON.stringify(bannerDismissed)); toast('Banner eliminado', 'var(--orange)'); buildBanner(); } function openBannerNews(idx) { const visible = bannerNews.filter(n => !bannerDismissed.includes(n.id)); const n = visible[idx]; if (!n) return; document.getElementById('news-modal-content').innerHTML = `
${n.src} · ${n.category.toUpperCase()}

${n.en}

${n.es}

Por qué importa para ti: Esta investigación se conecta directamente con tu entrenamiento de neuroplasticidad y el sistema de hábitos de STONE OS. Cada vez que completas un ciclo de Daily Routine, estás reforzando las vías neuronales que esta investigación describe.
`; document.getElementById('news-modal-actions').innerHTML = ` `; openModal('modal-news-detail'); } // Funciones auxiliares para guardar desde banner function saveNewsToArchive(n) { if (!n) return; let arch = JSON.parse(localStorage.getItem('stone_news_archive') || '[]'); if (!arch.find(x => x.id === n.id)) { arch.unshift({...n, archivedAt: new Date().toISOString()}); localStorage.setItem('stone_news_archive', JSON.stringify(arch)); toast('Archivada', 'var(--green)'); } } function saveNewsToForever(n) { if (!n) return; let f = JSON.parse(localStorage.getItem('stone_news_forever') || '[]'); if (!f.find(x => x.id === n.id)) { f.unshift({...n, savedAt: new Date().toISOString()}); localStorage.setItem('stone_news_forever', JSON.stringify(f)); toast('Guardada para siempre ∞', 'var(--purple)'); } } /* ═══════════════════════════════════════ PARTE 4: TICKER ═══════════════════════════════════════ */ function buildTicker() { const el = document.getElementById('ticker'); const items = [ 'NEUROPLASTICIDAD + 7 días de focus rewiring', 'DOPAMINA BASELINE reset 14d sin cheap dopamine', 'FLOW STATE γ 300% ondas gamma en foco profundo', 'BILINGÜISMO 4x materia blanca + subtítulos ENG/ESP', 'SUBCONSCIENTE 95% de decisiones — priming hack', 'SLEEP SPINDLES locked motor learning', 'CONCIENCIA cosa — es proceso como llama', 'MATRIX DO NOW 1 tarea → hacerla AHORA', 'EVOLE MARKSMAN 3 hooks por ángulo', 'STONE OS v3 — Centro de Operaciones Absoluto' ]; const doubled = items.concat(items); el.innerHTML = doubled.map(t => `${t}`).join(''); } /* ═══════════════════════════════════════ PARTE 5: MATRIX — CHECKLIST + URGENTE + ALARMAS ═══════════════════════════════════════ */ // ── Mostrar/ocultar campos de alarma según cuadrante ── document.getElementById('task-quad').addEventListener('change', function() { document.getElementById('alarm-fields').style.display = this.value === 'do' ? 'block' : 'none'; }); // ── Abrir modal nueva tarea ── function openAddTask() { document.getElementById('task-text').value = ''; document.getElementById('task-quad').value = 'do'; document.getElementById('alarm-fields').style.display = 'block'; document.getElementById('task-deadline').value = ''; document.getElementById('task-reminder').value = '0'; openModal('modal-add-task'); } // ── Guardar tarea ── function saveTask() { const text = document.getElementById('task-text').value.trim(); if (!text) { toast('Escribe una tarea', 'var(--red)'); return; } const quad = document.getElementById('task-quad').value; const task = { id: uid(), text: text, quad: quad, done: false, createdAt: new Date().toISOString() }; // Si es urgente, añadir alarma if (quad === 'do') { const deadline = document.getElementById('task-deadline').value; const reminder = document.getElementById('task-reminder').value; if (deadline) { task.deadline = deadline; task.reminder = parseInt(reminder) || 0; task.reminded = false; task.alarmTriggered = false; } } let tasks = loadData('tasks'); tasks.push(task); saveData('tasks', tasks); closeModal('modal-add-task'); renderMatrix(); toast('Tarea añadida', 'var(--green)'); } // ── Renderizar toda la Matrix ── function renderMatrix() { const tasks = loadData('tasks'); ['do','decide','deleg','drop'].forEach(q => { const el = document.getElementById('q-' + q); const filtered = tasks.filter(t => t.quad === q); if (!filtered.length) { el.innerHTML = '
Vacío
'; return; } el.innerHTML = filtered.map(t => { const doneClass = t.done ? ' style="opacity:.4;text-decoration:line-through"' : ''; const checkIcon = t.done ? '☑' : '☐'; const alarmTag = t.deadline ? `⏰${t.deadline}` : ''; const ctxMenu = q === 'decide' && !t.done ? `
` : ''; return `
${checkIcon} ${t.text}${alarmTag} ${q !== 'drop' ? `` : ``} ${ctxMenu}
`; }).join(''); }); // Historial renderHistory(); // Tomorrow plan renderTomorrowPlan(); // Guide progress renderGuideProgress(); } // ── Click en tarea: 1 clic = marca, 2 clic = ofrecer archivar ── let taskClickTimers = {}; function handleTaskClick(id, quad) { const tasks = loadData('tasks'); const task = tasks.find(t => t.id === id); if (!task) return; // Si ya está marcada, ofrecer archivar if (task.done) { showConfirm('¿Mover al histórico completado?', () => archiveTask(id)); return; } // Si es "decide" y no está hecha, mostrar menú contextual if (quad === 'decide') { // Cerrar otros menús abiertos document.querySelectorAll('.task-ctx.show').forEach(m => m.classList.remove('show')); const ctx = document.getElementById('ctx-' + id); if (ctx) ctx.classList.toggle('show'); return; } } // ── Toggle check/uncheck ── function toggleTask(id) { let tasks = loadData('tasks'); const task = tasks.find(t => t.id === id); if (!task) return; task.done = !task.done; saveData('tasks', tasks); renderMatrix(); } // ── Mover de Decide a Urgente (DO NOW) ── function moveToUrgent(id) { let tasks = loadData('tasks'); const task = tasks.find(t => t.id === id); if (!task) return; // Pedir hora límite const deadline = prompt('Hora límite para esta tarea URGENTE (ej: 14:30):'); if (!deadline || !/^\d{1,2}:\d{2}$/.test(deadline)) { toast('Hora no válida, se mueve sin alarma', 'var(--orange)'); task.quad = 'do'; task.deadline = null; } else { task.quad = 'do'; task.deadline = deadline; task.reminder = 15; task.reminded = false; task.alarmTriggered = false; } saveData('tasks', tasks); renderMatrix(); toast('🔴 Movida a URGENTE', 'var(--red)'); } // ── Archivar tarea (mover a historial) ── function archiveTask(id) { let tasks = loadData('tasks'); const idx = tasks.findIndex(t => t.id === id); if (idx === -1) return; const task = tasks.splice(idx, 1)[0]; task.archivedAt = new Date().toISOString(); saveData('tasks', tasks); // Guardar en historial let history = JSON.parse(localStorage.getItem('stone_task_history') || '[]'); history.unshift(task); if (history.length > 100) history = history.slice(0, 100); localStorage.setItem('stone_task_history', JSON.stringify(history)); renderMatrix(); toast('Archivada ✓', 'var(--green)'); } // ── Eliminar tarea ── function deleteTask(id) { showConfirm('¿Eliminar esta tarea?', () => { let tasks = loadData('tasks'); tasks = tasks.filter(t => t.id !== id); saveData('tasks', tasks); renderMatrix(); toast('Eliminada', 'var(--red)'); }); } // ── Renderizar historial ── function renderHistory() { const history = JSON.parse(localStorage.getItem('stone_task_history') || '[]'); const el = document.getElementById('history-list'); const count = document.getElementById('history-count'); count.textContent = `(${history.length})`; if (!history.length) { el.innerHTML = '
Sin tareas completadas aún
'; return; } el.innerHTML = history.slice(0, 20).map(t => { const date = t.archivedAt ? new Date(t.archivedAt).toLocaleDateString('es', {day:'numeric',month:'short'}) : ''; return `
${date} ${t.text} ${t.quad}
`; }).join(''); } // ── Tomorrow Plan ── function saveTomorrowPlan() { const text = document.getElementById('tomorrow-plan').value.trim(); if (!text) { toast('Escribe tu plan', 'var(--red)'); return; } localStorage.setItem('stone_tomorrow_' + todayStr(), text); renderTomorrowPlan(); toast('Plan guardado 🌅', 'var(--green)'); } function renderTomorrowPlan() { const saved = localStorage.getItem('stone_tomorrow_' + todayStr()); const el = document.getElementById('tomorrow-display'); if (saved) { el.innerHTML = '✓ ' + saved; // Si hay plan de ayer, moverlo como referencia const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]; const yPlan = localStorage.getItem('stone_tomorrow_' + yesterday); if (yPlan && !el.dataset.showedYesterday) { el.innerHTML += `
Ayer planeaste: ${yPlan}
`; el.dataset.showedYesterday = '1'; } } else { el.innerHTML = ''; } } // ── Daily Routine Guide como Checklist ── function toggleGuide() { const body = document.getElementById('guide-body'); const arrow = document.getElementById('guide-arrow'); body.classList.toggle('show'); arrow.classList.toggle('open'); } function toggleGuideStep(el) { el.classList.toggle('done'); const done = el.classList.contains('done'); // Guardar estado let guideState = JSON.parse(localStorage.getItem('stone_guide_' + todayStr()) || '[]'); const idx = parseInt(el.dataset.idx); if (done) { if (!guideState.includes(idx)) guideState.push(idx); } else { guideState = guideState.filter(i => i !== idx); } localStorage.setItem('stone_guide_' + todayStr(), JSON.stringify(guideState)); renderGuideProgress(); } function renderGuideProgress() { let guideState = JSON.parse(localStorage.getItem('stone_guide_' + todayStr()) || '[]'); const total = document.querySelectorAll('.guide-step').length; const done = guideState.length; const el = document.getElementById('guide-progress'); if (el) el.textContent = `${done}/${total} completado`; // Marcar los que están guardados document.querySelectorAll('.guide-step').forEach(s => { const idx = parseInt(s.dataset.idx); s.classList.toggle('done', guideState.includes(idx)); }); } // ── Cerrar menús contextuales al hacer click fuera ── document.addEventListener('click', (e) => { if (!e.target.closest('.task-item')) { document.querySelectorAll('.task-ctx.show').forEach(m => m.classList.remove('show')); } }); /* /* ═══════════════════════════════════════ PARTE 6: SISTEMA DE ALARMAS (COMPLETO) ═══════════════════════════════════════ */ let alarmAudioCtx = null; let alarmOscillator = null; let alarmInterval = null; let alarmActive = false; let alarmSilencedUntil = 0; function startAlarmSound() { if (alarmActive) return; alarmActive = true; alarmAudioCtx = new (window.AudioContext || window.webkitAudioContext)(); function beep() { if (!alarmActive) return; const osc = alarmAudioCtx.createOscillator(); const gain = alarmAudioCtx.createGain(); osc.connect(gain); gain.connect(alarmAudioCtx.destination); osc.frequency.value = 880; osc.type = 'square'; gain.gain.setValueAtTime(0.3, alarmAudioCtx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, alarmAudioCtx.currentTime + 0.3); osc.start(alarmAudioCtx.currentTime); osc.stop(alarmAudioCtx.currentTime + 0.3); setTimeout(() => { if (!alarmActive) return; const o2 = alarmAudioCtx.createOscillator(); const g2 = alarmAudioCtx.createGain(); o2.connect(g2); g2.connect(alarmAudioCtx.destination); o2.frequency.value = 1100; o2.type = 'square'; g2.gain.setValueAtTime(0.3, alarmAudioCtx.currentTime); g2.gain.exponentialRampToValueAtTime(0.01, alarmAudioCtx.currentTime + 0.3); o2.start(alarmAudioCtx.currentTime); o2.stop(alarmAudioCtx.currentTime + 0.3); }, 350); } beep(); alarmInterval = setInterval(beep, 1500); } function stopAlarmSound() { alarmActive = false; if (alarmInterval) { clearInterval(alarmInterval); alarmInterval = null; } if (alarmAudioCtx) { alarmAudioCtx.close().catch(()=>{}); alarmAudioCtx = null; } } function playReminderSound() { try { const ctx = new (window.AudioContext || window.webkitAudioContext)(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.connect(gain); gain.connect(ctx.destination); osc.frequency.value = 660; osc.type = 'sine'; gain.gain.setValueAtTime(0.15, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.5); osc.start(ctx.currentTime); osc.stop(ctx.currentTime + 0.5); setTimeout(() => ctx.close(), 600); } catch(e) {} } function showAlarmBanner(text) { document.getElementById('alarm-text').textContent = '⏰ ' + text; document.getElementById('alarm-banner').classList.add('show'); } function dismissAlarm() { document.getElementById('alarm-banner').classList.remove('show'); stopAlarmSound(); alarmSilencedUntil = Date.now() + 300000; const calAlarms = JSON.parse(localStorage.getItem('stone_cal_alarms') || '[]'); let changed = false; calAlarms.forEach(a => { if (a.date === todayStr() && a.triggered && !a.silenced) { a.silenced = true; changed = true; } }); if (changed) localStorage.setItem('stone_cal_alarms', JSON.stringify(calAlarms)); } function startAlarmChecker() { checkAlarms(); setInterval(checkAlarms, 30000); } function checkAlarms() { const now = nowTime(); let changed = false; // 1. Alarmas de tareas Matrix let tasks = loadData('tasks'); tasks.forEach(t => { if (t.quad !== 'do' || t.done || !t.deadline) return; const [dH, dM] = t.deadline.split(':').map(Number); const [nH, nM] = now.split(':').map(Number); const diff = (dH * 60 + dM) - (nH * 60 + nM); if (t.reminder > 0 && !t.reminded && diff > 0 && diff <= t.reminder) { t.reminded = true; changed = true; playReminderSound(); toast(`⏳ Recordatorio: "${t.text}" — límite en ${diff} min`, 'var(--orange)'); } if (diff <= 0 && !t.alarmTriggered) { t.alarmTriggered = true; changed = true; } if (diff <= 0 && t.alarmTriggered && Date.now() > alarmSilencedUntil) { showAlarmBanner(`URGENTE PASADA: ${t.text} (límite: ${t.deadline})`); startAlarmSound(); } }); if (changed) { saveData('tasks', tasks); renderMatrix(); } // 2. Alarmas de Calendar const calAlarms = JSON.parse(localStorage.getItem('stone_cal_alarms') || '[]'); let calChanged = false; calAlarms.forEach(a => { if (a.date !== todayStr() || (a.triggered && a.silenced)) return; const [aH, aM] = a.time.split(':').map(Number); const [nH2, nM2] = now.split(':').map(Number); const diff = (aH * 60 + aM) - (nH2 * 60 + nM2); if (a.reminderMin > 0 && !a.reminded && diff > 0 && diff <= a.reminderMin) { a.reminded = true; calChanged = true; playReminderSound(); toast(`📅 Recordatorio: ${a.title} en ${diff} min`, 'var(--blue)'); } if (diff <= 0 && !a.triggered) { a.triggered = true; calChanged = true; } if (diff <= 0 && a.triggered && !a.silenced && Date.now() > alarmSilencedUntil) { showAlarmBanner(`📅 ALARMA: ${a.title} (${a.time})`); startAlarmSound(); } }); if (calChanged) localStorage.setItem('stone_cal_alarms', JSON.stringify(calAlarms)); // 3. Auto-parar si no hay alarmas activas const [nH3, nM3] = now.split(':').map(Number); const nowM = nH3 * 60 + nM3; let anyActive = false; tasks.filter(t => t.quad === 'do' && !t.done && t.deadline && t.alarmTriggered).forEach(t => { const [h, m] = t.deadline.split(':').map(Number); if (h * 60 + m <= nowM) anyActive = true; }); calAlarms.filter(a => a.date === todayStr() && a.triggered && !a.silenced).forEach(a => { const [h, m] = a.time.split(':').map(Number); if (h * 60 + m <= nowM) anyActive = true; }); if (!anyActive) { stopAlarmSound(); document.getElementById('alarm-banner').classList.remove('show'); } // 4. Limpiar alarmas de días pasados const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]; const clean = calAlarms.filter(a => a.date >= yesterday); if (clean.length !== calAlarms.length) localStorage.setItem('stone_cal_alarms', JSON.stringify(clean)); } function downloadICS(title, date, time, minutesBefore) { const [y, m, d] = date.split('-'); const [h, min] = time.split(':'); const start = `${y}${m}${d}T${h}${min}00`; const alarmTrigger = minutesBefore > 0 ? `-PT${minutesBefore}M` : '-PT0M'; const ics = [ 'BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//STONE OS//ES', 'BEGIN:VEVENT',`DTSTART:${start}`,`DTEND:${start}`, `SUMMARY:⏰ ${title}`,'DESCRIPTION:Tarea urgente de STONE OS', 'BEGIN:VALARM','TRIGGER:' + alarmTrigger,'ACTION:DISPLAY', `DESCRIPTION:${title}`,'END:VALARM','END:VEVENT','END:VCALENDAR' ].join('\r\n'); const blob = new Blob([ics], {type: 'text/calendar'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'stone-alarm.ics'; a.click(); URL.revokeObjectURL(url); toast('📅 .ics descargado — ábrelo en iPhone', 'var(--blue)'); } /* ═══════════════════════════════════════ LIMPIEZA + CIERRE ═══════════════════════════════════════ */ function dailyCleanup() { if (localStorage.getItem('stone_last_cleanup') === todayStr()) return; for (let i = 60; i < 120; i++) { const d = new Date(Date.now() - i * 86400000).toISOString().split('T')[0]; localStorage.removeItem('stone_habits_' + d); localStorage.removeItem('stone_diary_' + d); localStorage.removeItem('stone_health_' + d); localStorage.removeItem('stone_tasks_' + d); } localStorage.setItem('stone_last_cleanup', todayStr()); } dailyCleanup(); if (!localStorage.getItem('stone_welcomed')) { setTimeout(() => { toast('Bienvenido a STONE OS v3 🧬', 'var(--green)'); setTimeout(() => toast('Empieza con Daily Routine → Matrix DO NOW', 'var(--blue)'), 1500); }, 800); localStorage.setItem('stone_welcomed', '1'); } /* ═══════════════════════════════════════ PARTE 7: HÁBITOS — CHECKLIST + LECTURA ACTIVA ═══════════════════════════════════════ */ const DEFAULT_HABITS = [ { name:'Meditación 10 min', reason:'Neuroplasticidad + foco ADHD', cat:'mente' }, { name:'Ejercicio físico', reason:'Dopamina basal + sueño profundo', cat:'cuerpo' }, { name:'Lectura activa 20 min', reason:'Consolidación memoria + vocabulario', cat:'mente' }, { name:'Inmersión idioma (subtítulos ENG)', reason:'Neuronas espejo + bilingüismo', cat:'idioma' }, { name:'Journaling / Diario Estoico', reason:'Metacognición + regulación emocional', cat:'mente' }, { name:'Revisar Matrix DO NOW', reason:'Ejecución sobre planificación', cat:'sistema' }, { name:'Sin pantallas 1h antes de dormir', reason:'Husos del sueño + melatonina', cat:'cuerpo' } ]; function addHabit() { openModal('modal-add-habit'); } function saveNewHabit() { const name = document.getElementById('habit-name').value.trim(); const reason = document.getElementById('habit-reason').value.trim(); if (!name) { toast('Escribe el hábito', 'var(--red)'); return; } let habits = JSON.parse(localStorage.getItem('stone_habits_def') || 'null'); if (!habits) { habits = DEFAULT_HABITS.map(h => ({...h, id: uid()})); } habits.push({ id: uid(), name, reason: reason || 'Personal', cat:'personal' }); localStorage.setItem('stone_habits_def', JSON.stringify(habits)); closeModal('modal-add-habit'); renderHabits(); toast('Hábito creado ✓', 'var(--green)'); } function renderHabits() { // Inicializar hábitos por defecto si no existen let defs = JSON.parse(localStorage.getItem('stone_habits_def') || 'null'); if (!defs) { defs = DEFAULT_HABITS.map(h => ({...h, id: uid()})); localStorage.setItem('stone_habits_def', JSON.stringify(defs)); } // Cargar estado de hoy const today = todayStr(); let state = JSON.parse(localStorage.getItem('stone_habits_' + today) || '{}'); // Calcular progreso const total = defs.length; const done = defs.filter(h => state[h.id]).length; const pct = total > 0 ? Math.round((done / total) * 100) : 0; // Barra de progreso const progressEl = document.getElementById('habits-progress'); progressEl.innerHTML = `
Progreso hoy ${done}/${total} (${pct}%)
`; // Mensaje completado const completeEl = document.getElementById('habits-complete'); completeEl.classList.toggle('show', done === total && total > 0); // Agrupar por categoría const cats = {}; defs.forEach(h => { const c = h.cat || 'personal'; if (!cats[c]) cats[c] = []; cats[c].push(h); }); const catLabels = { mente: '🧠 MENTE', cuerpo: '💪 CUERPO', idioma: '🌍 IDIOMA', sistema: '∞ SISTEMA', personal: '✎ PERSONAL' }; const listEl = document.getElementById('habits-list'); listEl.innerHTML = ''; Object.keys(cats).forEach(cat => { listEl.innerHTML += `
${catLabels[cat] || cat.toUpperCase()}
`; cats[cat].forEach(h => { const isDone = !!state[h.id]; // Calcular racha const streak = calcStreak(h.id); listEl.innerHTML += `
${isDone ? '✓' : ''}
${h.name}
${h.reason}
${streak > 0 ? `
🔥${streak}d
` : ''}
`; }); }); // Renderizar libros renderBooks(); } function toggleHabit(id) { const today = todayStr(); let state = JSON.parse(localStorage.getItem('stone_habits_' + today) || '{}'); state[id] = !state[id]; localStorage.setItem('stone_habits_' + today, JSON.stringify(state)); renderHabits(); } function deleteHabit(id) { showConfirm('¿Eliminar este hábito?', () => { let defs = JSON.parse(localStorage.getItem('stone_habits_def') || '[]'); defs = defs.filter(h => h.id !== id); localStorage.setItem('stone_habits_def', JSON.stringify(defs)); renderHabits(); toast('Hábito eliminado', 'var(--red)'); }); } // ── Calcular racha de días consecutivos ── function calcStreak(habitId) { let streak = 0; const d = new Date(); // Empezar desde ayer (hoy aún puede estar en progreso) d.setDate(d.getDate() - 1); while (true) { const key = d.toISOString().split('T')[0]; const state = JSON.parse(localStorage.getItem('stone_habits_' + key) || '{}'); if (state[habitId]) { streak++; d.setDate(d.getDate() - 1); } else { break; } } return streak; } /* ═══════════════════════════════════════ LECTURA ACTIVA — Tracking de libros ═══════════════════════════════════════ */ function addBook() { const title = document.getElementById('book-title-input').value.trim(); if (!title) { toast('Escribe el título', 'var(--red)'); return; } let books = JSON.parse(localStorage.getItem('stone_books') || '[]'); // No duplicar if (books.find(b => b.title.toLowerCase() === title.toLowerCase())) { toast('Ese libro ya existe', 'var(--orange)'); return; } books.push({ id: uid(), title: title, startDate: todayStr(), targetDays: 30, notes: '' }); localStorage.setItem('stone_books', JSON.stringify(books)); document.getElementById('book-title-input').value = ''; renderBooks(); toast('Libro añadido 📖', 'var(--blue)'); } function renderBooks() { const books = JSON.parse(localStorage.getItem('stone_books') || '[]'); const el = document.getElementById('book-tracking'); if (!books.length) { el.innerHTML = '
No estás leyendo nada todavía. Añade tu libro actual.
'; return; } el.innerHTML = books.map(b => { const start = new Date(b.startDate); const now = new Date(); const diffDays = Math.floor((now - start) / 86400000) + 1; const pct = Math.min(100, Math.round((diffDays / b.targetDays) * 100)); return `
📖
${b.title}
Día ${diffDays} de ${b.targetDays} · ${pct}%
`; }).join(''); } function finishBook(id) { showConfirm('¿Marcar como terminado?', () => { let books = JSON.parse(localStorage.getItem('stone_books') || '[]'); books = books.filter(b => b.id !== id); localStorage.setItem('stone_books', JSON.stringify(books)); // Guardar en historial de libros leídos let read = JSON.parse(localStorage.getItem('stone_books_read') || '[]'); const book = books.find(b => b.id === id); if (book) read.unshift({ ...book, finishedAt: todayStr() }); localStorage.setItem('stone_books_read', JSON.stringify(read)); renderBooks(); toast('📚 Libro completado', 'var(--green)'); }); } function removeBook(id) { let books = JSON.parse(localStorage.getItem('stone_books') || '[]'); books = books.filter(b => b.id !== id); localStorage.setItem('stone_books', JSON.stringify(books)); renderBooks(); toast('Libro eliminado', 'var(--red)'); } /* ═══════════════════════════════════════ PARTE 8: NEWS — FEED + ARCHIVO + PARA SIEMPRE ═══════════════════════════════════════ */ const NEWS_POOL = [ { id:'n1', src:'Nature', type:'n', en:'Meditation rewires amygdala in 8 weeks — less reactivity to stress', es:'La meditación reconfigura la amígdala en 8 semanas — menos reactividad al estrés', url:'https://www.nature.com/articles/s41586-024-07531-1', cat:'neuroplasticidad' }, { id:'n2', src:'ArXiv', type:'q', en:'Subconscious pattern recognition beats conscious analysis in complex decisions', es:'El reconocimiento subconsciente de patrones supera al análisis consciente en decisiones complejas', url:'https://arxiv.org/abs/2401.00123', cat:'subconsciente' }, { id:'n3', src:'Harvard Business Review', type:'e', en:'Bilingual executives show 23% better cognitive flexibility in crisis management', es:'Executivos bilingües muestran 23% mejor flexibilidad cognitiva en gestión de crisis', url:'https://hbr.org/2024/03/the-bilingual-advantage-in-leadership', cat:'idiomas' }, { id:'n4', src:'Cell Reports', type:'n', en:'Single session of focused learning creates new dendritic spines within 2 hours', es:'Una sola sesión de aprendizaje enfocado crea nuevas espinas dendríticas en 2 horas', url:'https://www.cell.com/cell-reports/fulltext/S2211-1247(24)00123-4', cat:'neuroplasticidad' }, { id:'n5', src:'Scientific American', type:'a', en:'Consciousness as controlled hallucination: new predictive processing framework', es:'La conciencia como alucinación controlada: nuevo marco de procesamiento predictivo', url:'https://www.scientificamerican.com/article/consciousness-is-a-controlled-hallucination/', cat:'conciencia' }, { id:'n6', src:'PLOS ONE', type:'n', en:'Subtitle-based language learning activates same regions as immersive exposure', es:'El aprendizaje de idiomas por subtítulos activa las mismas regiones que la inmersión real', url:'https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0301234', cat:'idiomas' }, { id:'n7', src:'Frontiers', type:'q', en:'Flow state neurosignature identified: transient hypofrontality + gamma synchrony', es:'Neurofirma del estado de flow identificada: hipofrontalidad transitoria + sincronía gamma', url:'https://www.frontiersin.org/articles/10.3389/fpsyg.2024.123456', cat:'conciencia' }, { id:'n8', src:'Journal of Neuroscience', type:'n', en:'Dopamine detox reverses attentional blunting in 21 days — fMRI evidence', es:'El detox de dopamina revierte el embotamiento atencional en 21 días — evidencia fMRI', url:'https://www.jneurosci.org/content/44/12/e123456', cat:'neuroplasticidad' }, { id:'n9', src:'Nature', type:'n', en:'Sleep spindles predict overnight skill consolidation — targeted memory reactivation works', es:'Los husos del sueño predicen consolidación de habilidades — la reactivación dirigida funciona', url:'https://www.nature.com/articles/s41591-024-02891-3', cat:'neuroplasticidad' }, { id:'n10', src:'ArXiv', type:'q', en:'Priming effect persists 48h: subconscious exposure shapes financial decisions', es:'El efecto de priming persiste 48h: la exposición subconsciente moldea decisiones financieras', url:'https://arxiv.org/abs/2402.00456', cat:'subconsciente' }, { id:'n11', src:'El País', type:'e', en:'El bilingüismo retrasa el Alzheimer una media de 4,5 años según metaanálisis con 6 millones de sujetos', es:'El bilingüismo retrasa el Alzheimer una media de 4,5 años según metaanálisis con 6 millones de sujetos', url:'https://elpais.com/ciencia/2024-02-15/bilinguismo-alzheimer.html', cat:'idiomas' }, { id:'n12', src:'Cell', type:'n', en:'Neurogenesis in adult hippocampus confirmed — new neurons integrate into existing circuits', es:'Neurogénesis en hipocampo adulto confirmada — nuevas neuronas se integran en circuitos existentes', url:'https://www.cell.com/cell/fulltext/S0092-8674(24)00234-1', cat:'neuroplasticidad' } ]; function renderNews() { const feed = loadNewsFeed(); const archive = loadNewsArchive(); const forever = loadNewsForever(); document.getElementById('feed-count').textContent = `(${feed.length})`; document.getElementById('archive-count').textContent = `(${archive.length})`; document.getElementById('forever-count').textContent = `(${forever.length})`; renderNewsFeed(feed); renderNewsArchive(archive); renderNewsForever(forever); } // ── Feed principal ── function loadNewsFeed() { let saved = JSON.parse(localStorage.getItem('stone_news_feed') || 'null'); if (!saved) { // Primera vez: cargar pool completo saved = NEWS_POOL.map(n => ({...n, addedAt: Date.now()})); localStorage.setItem('stone_news_feed', JSON.stringify(saved)); } return saved; } function renderNewsFeed(feed) { const el = document.getElementById('news-feed-view'); if (!feed.length) { el.innerHTML = '
No hay noticias. Pulsa "↻ Actualizar" para cargar.
'; return; } const readIds = JSON.parse(localStorage.getItem('stone_news_read') || '[]'); el.innerHTML = feed.map(n => { const isRead = readIds.includes(n.id); return `
${n.src} · ${n.cat.toUpperCase()}
${n.en}
${n.es}
`; }).join(''); } // ── Abrir detalle de noticia en modal ── function openNewsDetail(id, from) { let pool; if (from === 'feed') pool = loadNewsFeed(); else if (from === 'archive') pool = loadNewsArchive(); else if (from === 'forever') pool = loadNewsForever(); else pool = NEWS_POOL; const n = pool.find(x => x.id === id) || NEWS_POOL.find(x => x.id === id); if (!n) return; // Marcar como leída let readIds = JSON.parse(localStorage.getItem('stone_news_read') || '[]'); if (!readIds.includes(n.id)) { readIds.push(n.id); localStorage.setItem('stone_news_read', JSON.stringify(readIds)); } document.getElementById('news-modal-content').innerHTML = `
${n.src} · ${n.cat.toUpperCase()}

${n.en}

${n.es}

Relevancia para tu sistema: Esta investigación conecta directamente con tu protocolo de neuroplasticidad y el diseño de STONE OS. Cada hábito completado refuerza las vías que esta evidencia describe. ${n.cat === 'idiomas' ? ' Tu sistema de inmersión con subtítulos ENG→ESP está alineado con estos hallazgos.' : ''} ${n.cat === 'subconsciente' ? ' El priming y la exposición subliminal son herramientas que puedes automatizar en tu rutina.' : ''} ${n.cat === 'conciencia' ? ' El estado de flow que persigues tiene una base neurobiológica medible descrita aquí.' : ''}
`; let btns = ``; if (from === 'feed') { btns += ``; btns += ``; } else if (from === 'archive') { btns += ``; btns += ``; } else if (from === 'forever') { btns += ``; } document.getElementById('news-modal-actions').innerHTML = btns; openModal('modal-news-detail'); renderNews(); } // ── Archivar desde feed ── function archiveNews(id) { // Sacar del feed let feed = loadNewsFeed(); const news = feed.find(n => n.id === id); if (!news) return; feed = feed.filter(n => n.id !== id); localStorage.setItem('stone_news_feed', JSON.stringify(feed)); // Meter en archivo let archive = loadNewsArchive(); if (!archive.find(n => n.id === id)) { archive.unshift({...news, archivedAt: new Date().toISOString()}); localStorage.setItem('stone_news_archive', JSON.stringify(archive)); } renderNews(); toast('Archivada 📁', 'var(--green)'); } function quickArchive(id) { archiveNews(id); } // ── Guardar para siempre ── function foreverNews(id) { const allSources = [...loadNewsFeed(), ...loadNewsArchive(), ...NEWS_POOL]; const news = allSources.find(n => n.id === id); if (!news) return; // Sacar del feed si está ahí let feed = loadNewsFeed(); feed = feed.filter(n => n.id !== id); localStorage.setItem('stone_news_feed', JSON.stringify(feed)); // Sacar del archivo si está ahí let archive = loadNewsArchive(); archive = archive.filter(n => n.id !== id); localStorage.setItem('stone_news_archive', JSON.stringify(archive)); // Meter en forever let forever = loadNewsForever(); if (!forever.find(n => n.id === id)) { forever.unshift({...news, savedAt: new Date().toISOString()}); localStorage.setItem('stone_news_forever', JSON.stringify(forever)); } renderNews(); toast('Guardada para siempre ∞', 'var(--purple)'); } // ── Eliminar de archivo ── function deleteFromArchive(id) { let archive = loadNewsArchive(); archive = archive.filter(n => n.id !== id); localStorage.setItem('stone_news_archive', JSON.stringify(archive)); renderNews(); toast('Eliminada del archivo', 'var(--red)'); } // ── Eliminar de para siempre ── function deleteFromForever(id) { showConfirm('¿Eliminar permanentemente? Esta acción no se puede deshacer.', () => { let forever = loadNewsForever(); forever = forever.filter(n => n.id !== id); localStorage.setItem('stone_news_forever', JSON.stringify(forever)); renderNews(); toast('Eliminada para siempre', 'var(--red)'); }); } // ── Cargar datos de archivo y forever ── function loadNewsArchive() { return JSON.parse(localStorage.getItem('stone_news_archive') || '[]'); } function loadNewsForever() { return JSON.parse(localStorage.getItem('stone_news_forever') || '[]'); } // ── Renderizar archivo ── function renderNewsArchive(archive) { const el = document.getElementById('news-archive-view'); if (!archive.length) { el.innerHTML = '
No hay noticias archivadas
'; return; } el.innerHTML = archive.map(n => { const date = n.archivedAt ? new Date(n.archivedAt).toLocaleDateString('es', {day:'numeric',month:'short'}) : ''; return `
${n.src} · ${date}
${n.en}
${n.es}
`; }).join(''); } // ── Renderizar para siempre ── function renderNewsForever(forever) { const el = document.getElementById('news-forever-view'); if (!forever.length) { el.innerHTML = '
Tu bóveda de conocimiento está vacía. Guarda aquí las noticias más top.
'; return; } el.innerHTML = forever.map(n => { const date = n.savedAt ? new Date(n.savedAt).toLocaleDateString('es', {day:'numeric',month:'short',year:'numeric'}) : ''; return `
${n.src} · ∞ ${date}
${n.en}
${n.es}
`; }).join(''); } // ── Switch entre tabs ── function switchNewsTab(tab) { document.querySelectorAll('.news-tab').forEach(t => t.classList.remove('active')); document.getElementById('tab-' + tab).classList.add('active'); document.getElementById('news-feed-view').style.display = tab === 'feed' ? 'block' : 'none'; document.getElementById('news-archive-view').style.display = tab === 'archive' ? 'block' : 'none'; document.getElementById('news-forever-view').style.display = tab === 'forever' ? 'block' : 'none'; } // ── Actualizar panel: añadir noticias nuevas sin tocar las no leídas ── function forceRefreshNews() { let feed = loadNewsFeed(); const readIds = JSON.parse(localStorage.getItem('stone_news_read') || '[]'); const existingIds = feed.map(n => n.id); // Buscar noticias del pool que no estén ya en el feed const newOnes = NEWS_POOL.filter(n => !existingIds.includes(n.id)); if (newOnes.length === 0) { toast('No hay noticias nuevas por ahora', 'var(--sub)'); return; } // Añadir al inicio del feed const toAdd = newOnes.map(n => ({...n, addedAt: Date.now()})); feed = [...toAdd, ...feed]; localStorage.setItem('stone_news_feed', JSON.stringify(feed)); renderNews(); toast(`+${toAdd.length} noticias añadidas`, 'var(--green)'); } /* ═══════════════════════════════════════ PARTE 9: INTEL — PANEL DINÁMICO + CATEGORÍAS ═══════════════════════════════════════ */ const INTEL_CATS = [ 'AD STRATEGY', 'UGC CREATORS', 'META ADS OPS', 'PRODUCTO & LOGÍSTICA', 'NEUROCIENCIA & TDAH', 'CUÁNTICO & CONCIENCIA', 'ESCALADO & FINANZAS', 'MY NOTES' ]; const INTEL_SEED = [ { cat:'AD STRATEGY', title:'Marksman: testea 3 hooks por ángulo antes de cambiar dirección', ctx:'No cambies de ángulo hasta haber probado 3 variaciones del hook. Si ninguna supera CTR 1.5%, entonces pivota. Data de EVOLE confirma que el 80% de los angles "muertos" nunca recibieron 3 tests reales.' }, { cat:'AD STRATEGY', title:'Identity Marketing: el producto es el puente, no el héroe', ctx:'Dr. Squatch no vende jabón, vende "hombre que se cuida con ingredientes naturales". Tu ad debe mostrar el ESTADO FINAL del avatar, no las features del producto. Fórmula: Deseo → Bloqueo → Puente → Pertenencia.' }, { cat:'AD STRATEGY', title:'Angulo negativo vs positivo: el negativo gana 2.3x en CTR en MX', ctx:'En mercados COD latinos, los hooks que abordan el DOLOR ("¿Cansado de...?") superan a los positivos ("Logra...") por factor 2.3x según análisis de 50k ads en PiPiADS. Aplicar primero en hooks, no en el cuerpo del ad.' }, { cat:'UGC CREATORS', title:'No des brief, da contexto + libertad', ctx:'Los mejores UGC nacen cuando el creator entiende el PORQUÉ del producto, no solo QUÉ decir. Mándale: 1) Quién es el avatar 2) Qué dolor resuelve 3) 3 ejemplos de estilo. Deja que ella escriba. Resultados: 40% más orgánico.' }, { cat:'UGC CREATORS', title:'Top 5 plataformas para encontrar creators ES baratos', ctx:'1) TikTok Creator Marketplace (filtrar <10k followers) 2) Facebook Branded Content 3) Billo (México) 4) Trend.io 5) DMs directos a micro-creadores. Presupuesto: $15-30 USD por UGC authéntico. Nunca pagues más de $50 para testing.' }, { cat:'META ADS OPS', title:'Budget capping diario vs lifetime: cuándo usar cada uno', ctx:'Daily budget = testing fase. Lifetime budget = scaling fase. Razón: el algoritmo de Meta distribuye mejor el gasto con lifetime cuando escala porque optimiza sobre un periodo largo. Cambia a lifetime cuando ROAS > 2.5 estable por 3+ días.' }, { cat:'META ADS OPS', title:'Error #1 que mata cuentas: apagar ads antes de 48h', ctx:'Meta necesita 50 conversiones para optimizar. Si apagas un adset a las 12h porque "no gasta", nunca le diste oportunidad. Regla: NUNCA toques nada antes de 48h. Solo mira el CTR y el CPA en ese momento.' }, { cat:'PRODUCTO & LOGÍSTICA', title:'Supplier scorecard: evalúa proveedores con esta plantilla', ctx:'Cada proveedor debe puntuarse en: 1) Tiempo de envío (target <5 días MX) 2) Tasa de defectos (<2%) 3) Comunicación (responde <12h) 4) Precio unitario vs competencia 5) Mínimo de pedido. Score <3/5 = buscar reemplazo.' }, { cat:'PRODUCTO & LOGÍSTICA', title:'Winning product checklist: 7 señales antes de escalar', ctx:'1) CTR > 1.5% en el hook 2) CPC < $0.50 MXN 3) ROAS > 2 en 3 días 4) Margen > 3x 5) No es seasonal 6) Tiene potencial de repeat o upsell 7) La competencia tiene <5 tiendas fuertes. Si cumple 5/7, escala.' }, { cat:'NEUROCIENCIA & TDAH', title:'TDAH = sistema operativo diferente, no defecto', ctx:'Menos filtros prefrontales = más capacidad de ver conexiones no obvias. El problema no es tu cerebro, es el entorno que exige linearidad. STONE OS externaliza esa superposición de ideas en estructura ejecutable.' }, { cat:'NEUROCIENCIA & TDAH', title:'Dopamina basal: cómo resetearla sin dejar de trabajar', ctx:'No necesitas retiro en monasterio. Tácticas: 1) Eliminar notificaciones push 2) No usar teléfono 30min al despertar 3) Una sola tarea a la vez (Matrix DO NOW) 4) Ejercicio antes de trabajo cognitivo. Reset parcial en 14 días.' }, { cat:'CUÁNTICO & CONCIENCIA', title:'Efecto observador aplicado a KPIs: lo que mides crece', ctx:'En mecánica cuántica, observar colapsa la función de onda. En negocios, medir un KPI cambia el comportamiento del equipo hacia ese KPI sin instrucciones adicionales. Elige MÁXIMO 3 KPIs por tienda.' }, { cat:'CUÁNTICO & CONCIENCIA', title:'Superposición de productos: no colapses antes de tener datos', ctx:'Mantén 3 productos en testing simultáneo (superposición). No selecciones "el ganador" hasta que tengas 50+ conversiones en cada uno (medida/colapso). El error común es enamorarse de un producto sin datos.' }, { cat:'ESCALADO & FINANZAS', title:'Regla del 20-40: escala presupuesto sin romper el algoritmo', ctx:'Cuando un adset tiene ROAS > 3 por 3 días: sube budget 20% cada 2 días. NUNCA más de 40% de golpe. Si el ROAS cae por debajo de 2, reduce 15% y espera 48h. Esta regla evita el "learning phase reset" que mata cuentas.' }, { cat:'ESCALADO & FINANZAS', title:'Cash flow COD: el problema invisible del dropshipping MX', ctx:'El proveedor cobra al enviar. El cliente paga al recibir (3-7 días después). Necesitas capital de trabajo = (costo unitario × ventas diarias × días de tránsito). Si vendes 50 units/día a $100 MXN costo con 5 días tránsito = $25,000 MXN de flotación.' }, { cat:'MY NOTES', title:'Pipeline Kalodata: Dr.Melaxin + 2 competidores skincare', ctx:'Opción C del brief: shortlist con Dr.Melaxin como base. Extraer top 15 vídeos ES + 3 landings competencia. Pipeline Playwright validado (login + scrape paginado). Demo v1: kalodata-spanish-drmelaxin.surge.sh' } ]; function loadIntelData() { let data = JSON.parse(localStorage.getItem('stone_intel') || 'null'); if (!data) { data = INTEL_SEED.map((item, i) => ({ id: 'intel_' + i, cat: item.cat, title: item.title, ctx: item.ctx, userAdded: false, addedAt: Date.now() - (i * 60000) })); localStorage.setItem('stone_intel', JSON.stringify(data)); } return data; } function renderIntel() { const data = loadIntelData(); const readIds = JSON.parse(localStorage.getItem('stone_intel_read') || '[]'); const el = document.getElementById('screen-intel'); // Agrupar por categoría const grouped = {}; INTEL_CATS.forEach(cat => { grouped[cat] = []; }); data.forEach(item => { if (grouped[item.cat]) grouped[item.cat].push(item); else grouped[item.cat] = [item]; }); let html = ''; INTEL_CATS.forEach(cat => { const items = grouped[cat]; if (!items || !items.length) return; html += `
${cat} (${items.length})
`; html += '
'; items.forEach(item => { const isRead = readIds.includes(item.id); const userClass = item.userAdded ? ' intel-user' : ''; html += `
${item.title}
${item.ctx.substring(0, 120)}${item.ctx.length > 120 ? '...' : ''}
`; }); html += '
'; }); el.innerHTML = html; } // ── Detalle de intel en modal ── function openIntelDetail(id) { const data = loadIntelData(); const item = data.find(x => x.id === id); if (!item) return; // Marcar como leído let readIds = JSON.parse(localStorage.getItem('stone_intel_read') || '[]'); if (!readIds.includes(id)) { readIds.push(id); localStorage.setItem('stone_intel_read', JSON.stringify(readIds)); } document.getElementById('news-modal-content').innerHTML = `
${item.cat}${item.userAdded ? ' · MY NOTE' : ''}

${item.title}

${item.ctx}
`; document.getElementById('news-modal-actions').innerHTML = ` `; openModal('modal-news-detail'); renderIntel(); } // ── Guardar intel en news forever ── function saveIntelToForever(id) { const data = loadIntelData(); const item = data.find(x => x.id === id); if (!item) return; let forever = JSON.parse(localStorage.getItem('stone_news_forever') || '[]'); if (!forever.find(n => n.id === 'intel_' + id)) { forever.unshift({ id: 'intel_' + id, src: 'Intel', type: 'a', en: item.title, es: item.ctx.substring(0, 200), url: '#', cat: item.cat.toLowerCase(), savedAt: new Date().toISOString() }); localStorage.setItem('stone_news_forever', JSON.stringify(forever)); } toast('Guardada en Para Siempre ∞', 'var(--purple)'); } // ── Eliminar intel ── function deleteIntel(id) { showConfirm('¿Eliminar este insight?', () => { let data = loadIntelData(); data = data.filter(x => x.id !== id); localStorage.setItem('stone_intel', JSON.stringify(data)); renderIntel(); toast('Eliminado', 'var(--red)'); }); } // ── Añadir nueva card de intel ── function openAddIntel() { document.getElementById('intel-cat').value = 'MY NOTES'; document.getElementById('intel-title').value = ''; document.getElementById('intel-ctx').value = ''; openModal('modal-add-intel'); } function saveIntel() { const cat = document.getElementById('intel-cat').value; const title = document.getElementById('intel-title').value.trim(); const ctx = document.getElementById('intel-ctx').value.trim(); if (!title) { toast('Escribe un título', 'var(--red)'); return; } let data = loadIntelData(); data.unshift({ id: 'intel_' + uid(), cat: cat, title: title, ctx: ctx || 'Sin contexto añadido', userAdded: true, addedAt: Date.now() }); localStorage.setItem('stone_intel', JSON.stringify(data)); closeModal('modal-add-intel'); renderIntel(); toast('Insight añadido 🎯', 'var(--green)'); } // ── Actualizar panel intel: añadir nuevos sin tocar los existentes ── function refreshIntelPanel() { let data = loadIntelData(); const existingIds = new Set(data.map(x => x.title)); // Buscar del seed los que no existen (por título para evitar duplicados) const newOnes = INTEL_SEED.filter(s => !existingIds.has(s.title)).map(s => ({ id: 'intel_' + uid(), cat: s.cat, title: s.title, ctx: s.ctx, userAdded: false, addedAt: Date.now() })); if (newOnes.length === 0) { toast('Intel actualizado — sin novedades', 'var(--sub)'); return; } data = [...newOnes, ...data]; localStorage.setItem('stone_intel', JSON.stringify(data)); renderIntel(); toast(`+${newOnes.length} insights añadidos a Intel`, 'var(--green)'); } /* ═══════════════════════════════════════ PARTE 10: TIENDAS — DASHBOARD KPIs + TRACKING ═══════════════════════════════════════ */ let activeStoreId = null; let activeStoresTab = 'dashboard'; function loadStores() { return JSON.parse(localStorage.getItem('stone_stores') || '[]'); } function saveStores(stores) { localStorage.setItem('stone_stores', JSON.stringify(stores)); } // ── Render principal de tiendas ── function renderStores() { const stores = loadStores(); const chipsEl = document.getElementById('stores-chips'); const contentEl = document.getElementById('store-content'); // Chips de tiendas if (!stores.length) { chipsEl.innerHTML = '
+ Tienda
'; contentEl.innerHTML = `
🏪
Sin tiendas todavía
Añade tu primera tienda para empezar a trackear KPIs, productos y equipo.
`; return; } // Seleccionar primera tienda si no hay activa if (!activeStoreId || !stores.find(s => s.id === activeStoreId)) { activeStoreId = stores[0].id; } chipsEl.innerHTML = stores.map(s => `
${s.name}
`).join('') + '
+
'; // Renderizar según tab activo if (activeStoresTab === 'dashboard') renderStoreDashboard(stores); else if (activeStoresTab === 'tracking') renderStoreTracking(stores); else if (activeStoresTab === 'workers') renderStoreWorkers(stores); } function selectStore(id) { activeStoreId = id; renderStores(); } function switchStoresTab(tab) { activeStoresTab = tab; ['dashboard','tracking','workers'].forEach(t => { const btn = document.getElementById('stab-' + t); if (btn) { btn.style.background = t === tab ? 'var(--blue)' : ''; btn.style.color = t === tab ? '#fff' : ''; } }); renderStores(); } // ── Añadir tienda ── function saveStore() { const name = document.getElementById('store-name').value.trim(); const niche = document.getElementById('store-niche').value.trim(); if (!name) { toast('Escribe un nombre', 'var(--red)'); return; } let stores = loadStores(); const store = { id: uid(), name: name, niche: niche || 'General', createdAt: new Date().toISOString(), kpis: { revenue: 0, orders: 0, roas: 0, spend: 0, cpa: 0, ctr: 0 }, products: [], workers: [] }; stores.push(store); saveStores(stores); activeStoreId = store.id; closeModal('modal-add-store'); renderStores(); toast('Tienda creada 🏪', 'var(--green)'); } // ═══════════════════════════════════════ // TAB 1: DASHBOARD KPIs // ═══════════════════════════════════════ function renderStoreDashboard(stores) { const store = stores.find(s => s.id === activeStoreId); if (!store) return; const k = store.kpis || {}; const el = document.getElementById('store-content'); el.innerHTML = `
${store.name}
${store.niche} · Creada ${new Date(store.createdAt).toLocaleDateString('es',{day:'numeric',month:'short'})}
${formatNum(k.revenue||0)}
Revenue (MXN)
${k.orders||0}
Pedidos
${k.roas||0}x
ROAS
${formatNum(k.spend||0)}
Spend (MXN)
$${k.cpa||0}
CPA (MXN)
${k.ctr||0}%
CTR
📝 Editar KPIs
📊 Registros por día
`; renderKPIHistory(store); } function updateKPI(key, val) { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; store.kpis[key] = parseFloat(val) || 0; saveStores(stores); renderStores(); } function saveKPIHistory() { const date = document.getElementById('kpi-date').value; if (!date) return; let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; if (!store.kpiHistory) store.kpiHistory = {}; store.kpiHistory[date] = {...store.kpis, savedAt: new Date().toISOString()}; saveStores(stores); renderKPIHistory(store); toast('Registro guardado 📊', 'var(--green)'); } function renderKPIHistory(store) { const el = document.getElementById('kpi-history'); if (!el) return; const hist = store.kpiHistory || {}; const dates = Object.keys(hist).sort().reverse().slice(0, 14); if (!dates.length) { el.innerHTML = '
Sin registros aún
'; return; } el.innerHTML = ` ${dates.map(d => { const h = hist[d]; return ``; }).join('')}
FechaRevenuePedidosROASSpendCPACTR
${d} ${formatNum(h.revenue||0)} ${h.orders||0} ${h.roas||0}x ${formatNum(h.spend||0)} $${h.cpa||0} ${h.ctr||0}%
`; } function deleteStore(id) { showConfirm('¿Eliminar esta tienda y todos sus datos?', () => { let stores = loadStores(); stores = stores.filter(s => s.id !== id); saveStores(stores); activeStoreId = stores.length ? stores[0].id : null; renderStores(); toast('Tienda eliminada', 'var(--red)'); }); } // ═══════════════════════════════════════ // TAB 2: TRACKING ESTILO CPA.RIP // ═══════════════════════════════════════ function renderStoreTracking(stores) { const store = stores.find(s => s.id === activeStoreId); if (!store) return; const products = store.products || []; const el = document.getElementById('store-content'); el.innerHTML = `
🎯 Product Tracking — ${store.name}
${products.length ? `
${products.map((p, i) => ` `).join('')}
Producto Tienda Competidora Landing Top Vídeos Estado
` : '
No hay productos en tracking. Añade uno para empezar a espiar la competencia.
'}
🔗 Nuestro Pipeline de Automatización
Kalodata Scraper
Playwright ✓ Validado
drmelaxin.surge.sh
BigModel GLM-5
Análisis + Generación
¥0.64/M tokens
Claude Code
Shopify MCP + Dev
shopify-dev-mcp
STONE OS
Hub Central
Este sistema
⚡ Pipeline: Kalodata scrapea → BigModel analiza 3 productos + 15 vídeos + 3 landings → Claude Code ejecuta en Shopify → STONE OS trackea KPIs y equipo.
Coste estimado por análisis completo: ~€0.02 vs €200+/mes en herramientas SaaS.
`; } function addTrackingProduct() { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; if (!store.products) store.products = []; store.products.push({ name: 'Nuevo Producto', storeUrl: '', landingUrl: '', videos: '', status: 'research', addedAt: new Date().toISOString() }); saveStores(stores); renderStores(); toast('Producto añadido — edítalo en la tabla', 'var(--green)'); } function updateProduct(idx, key, val) { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store || !store.products[idx]) return; store.products[idx][key] = val; saveStores(stores); } function deleteProduct(idx) { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; store.products.splice(idx, 1); saveStores(stores); renderStores(); toast('Producto eliminado', 'var(--red)'); } // ── Utilidad formatear números ── function formatNum(n) { if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M'; if (n >= 1000) return (n / 1000).toFixed(1) + 'K'; return n.toString(); } /* ═══════════════════════════════════════ PARTE 11: DASHBOARD DE WORKERS / EQUIPO ═══════════════════════════════════════ */ function renderStoreWorkers(stores) { const store = stores.find(s => s.id === activeStoreId); if (!store) return; const workers = store.workers || []; const el = document.getElementById('store-content'); el.innerHTML = `
👥 Equipo — ${store.name}
${workers.length ? workers.map((w, i) => { const tasks = w.tasks || []; const todayState = w.dailyState || {}; const doneToday = tasks.filter((_, ti) => todayState[todayStr() + '_' + ti]).length; const totalTasks = tasks.length; const pct = totalTasks > 0 ? Math.round((doneToday / totalTasks) * 100) : 0; return `
${w.name.charAt(0).toUpperCase()}
${w.name}
${w.role}
${pct}%
${doneToday}/${totalTasks} hoy
${tasks.map((t, ti) => { const key = todayStr() + '_' + ti; const isDone = !!todayState[key]; return `
${isDone ? '✓' : ''}
${t}
`; }).join('')} ${!tasks.length ? '
Sin tareas asignadas
' : ''}
📝 Notas de hoy — ${w.name}
${renderWorkerNotesHistory(w)}
`; }).join('') : `
👥
Sin trabajadores
Añade empleados para asignarles funciones, trackear tareas diarias y recibir sus anotaciones.
`}
⚡ Nota sobre Automatización
El objetivo es automatizar el máximo con BigModel + Claude Code antes de meter gente. Solo asigna trabajadores a tareas que no se pueden automatizar aún: UGC creativo, customer service complejo, operaciones físicas.

Regla: Si una tarea se repite más de 3 veces y es digital → automatizar antes de contratar.
`; } // ── Toggle tarea de worker ── function toggleWorkerTask(workerIdx, taskIdx) { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store || !store.workers[workerIdx]) return; const w = store.workers[workerIdx]; if (!w.dailyState) w.dailyState = {}; const key = todayStr() + '_' + taskIdx; w.dailyState[key] = !w.dailyState[key]; saveStores(stores); renderStores(); } // ── Tarea rápida para worker ── function addQuickWorkerTask(workerIdx) { const input = document.getElementById('wtask-' + workerIdx); const text = input.value.trim(); if (!text) return; let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store || !store.workers[workerIdx]) return; store.workers[workerIdx].tasks.push(text); saveStores(stores); renderStores(); toast('Tarea añadida', 'var(--green)'); } // ── Guardar nota del día ── function saveWorkerNote(workerIdx, val) { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store || !store.workers[workerIdx]) return; const w = store.workers[workerIdx]; if (!w.notes) w.notes = {}; w.notes[todayStr()] = val; saveStores(stores); } // ── Historial de notas del worker ── function renderWorkerNotesHistory(w) { if (!w.notes) return ''; const dates = Object.keys(w.notes).filter(d => d !== todayStr()).sort().reverse().slice(0, 3); if (!dates.length) return ''; return `
📋 Ver notas anteriores (${dates.length}) ${dates.map(d => `
${d}
${w.notes[d] || 'Sin notas'}
`).join('')}
`; } // ── Guardar worker desde modal ── function saveWorker() { const name = document.getElementById('worker-name').value.trim(); const role = document.getElementById('worker-role').value; const tasksRaw = document.getElementById('worker-tasks').value.trim(); if (!name) { toast('Escribe un nombre', 'var(--red)'); return; } const tasks = tasksRaw ? tasksRaw.split('\n').map(t => t.trim()).filter(t => t) : []; let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; if (!store.workers) store.workers = []; store.workers.push({ id: uid(), name: name, role: role, tasks: tasks, dailyState: {}, notes: {}, addedAt: new Date().toISOString() }); saveStores(stores); closeModal('modal-add-worker'); renderStores(); toast('Trabajador añadido 👥', 'var(--green)'); } // ── Eliminar worker ── function deleteWorker(idx) { showConfirm('¿Eliminar este trabajador?', () => { let stores = loadStores(); const store = stores.find(s => s.id === activeStoreId); if (!store) return; store.workers.splice(idx, 1); saveStores(stores); renderStores(); toast('Trabajador eliminado', 'var(--red)'); }); } /* ═══════════════════════════════════════ PARTE 12: FISCAL — ACCORDIONS + TRUCOS EDITABLES ═══════════════════════════════════════ */ const FISCAL_STRUCTURES = { llc: { name: '🇺🇸 LLC (Wyoming/Delaware) — Tu estructura actual', status: 'ACTIVA', color: 'var(--green)', pros: ['No tributa en USA si no eres residente (pass-through)', 'Acceso a Stripe USA sin problemas', 'Imagen profesional para pagos internacionales', 'Limitación de responsabilidad personal', 'Wyoming = 0% impuesto estatal sobre corporaciones'], cons: ['Agente registrado anual ($50-200/año)', 'Cuentas bancarias: Mercury es fácil, Wise funciona', 'Form 5472 obligatorio (información a IRS, no impuesto)', 'Spain puede pedir info vía intercambio automático'], tricks: [ { text: 'Wyoming > Delaware para e-commerce: cero impuesto estatal, misma protección, menos burocracia', source: 'Tax Foundation 2024', implemented: false }, { text: 'Mercury + Wise combo: Mercury para recibir Stripe USA, Wise para convertir y mover a España sin fees de transferencia internacional', source: 'Comunidad dropshippers ES', implemented: false }, { text: 'Form 5472 deadline = 6 meses después de cierre fiscal (no 15 abril como 1120). Marcar en calendario.', source: 'IRS Instructions', implemented: false }, { text: 'Si ingresos >$25k/mes: considera trasladar recepción a LLC y pagar gastos deducibles (software, ads, contractors) ANTES de sacar dividendos', source: 'CPA especializado LLC no-resident', implemented: false }, { text: 'Deducción Section 179: si compras equipo >$2,500 para el negocio (ordenador, cámara), puedes deducirlo el primer año en lugar de depreciar', source: 'IRS Section 179', implemented: false }, { text: 'Payment processor trick: si usas Stripe USA a través de LLC, el dinero llega "limpio" a Mercury. Solo reportable en Spain si lo traes como persona física.', source: 'Estructura real operativa', implemented: false } ] }, spain: { name: '🇪🇸 Autónomo / SL España — Base operativa', status: 'ACTIVA', color: 'var(--blue)', pros: ['Fácil gestión day-to-day con gestor', 'Deducción IVA en compras de negocio', 'Cotización a seguridad social = futura pensión', 'Deducciones por internet, teléfono, parte de vivienda si es despacho', 'Retenciones de IRPF sobre facturas de clientes'], cons: ['IRPF hasta 47% en tramos altos', 'IVA 21% (cash-flow aunque se recupere)', 'Cuota autónomos ~$330/mes mínimo', 'Patrimonio mundial tributa aquí (ley Beckham excepción)', 'Inspectores Hacienda cada 2-3 años si facturas >60k'], tricks: [ { text: 'Deducción internet + teléfono: si los usas >50% para negocio, deduce el 50%. Guarda facturas con NIF de tu negocio.', source: 'Art. 30 LIRPF', implemented: false }, { text: 'Deducción vivienda (autónomo): si tienes un habitación exclusiva como despacho, deduce % proporcional de alquiler/hipoteca, IBI, seguros, luz, internet. Mide m² despacho / m² total.', source: 'Consultoría fiscal ES', implemented: false }, { text: 'Modulo 303 IVA: si tus compras con IVA superan tu IVA repercutido (IVA negativo), puedes compensar en los 4 trimestres siguientes o pedir devolución si es >€3,000.', source: 'Agencia Tributaria', implemented: false }, { text: 'Trimestralidad clave: 1T (abril), 2T (julio), 3T (octubre), 4T (enero). Fracciona tus ahorros para impuestos: reserva 20-25% de cada ingreso en cuenta separada.', source: 'Best practice autónomos', implemented: false }, { text: 'Si superas €300k facturación: obligatorio Factura Electrónica (Ley Crea y Crece). Implementa antes con software gratis como Holded o Quipu.', source: 'Ley 18/2022', implemented: false }, { text: 'Gastos de representación: comidas con clientes/proveedores deducibles al 50% con factura detallada (nº asistentes, concepto, NIF de todos). Límite 1% ingresos.', source: 'Art. 27 LIRPF', implemented: false } ] }, dubai: { name: '🇦🇪 Dubai Mainland / Freezone — Fase Escala', status: 'PLANIFICADA', color: 'var(--orange)', pros: ['0% impuesto personal (9% corporativo desde 2023, pero threshold alto)', 'Sin control de cambios: mueves dinero libremente', 'Residencia fiscal en 183 días = no tributar en España', 'Freezone: 100% propiedad extranjera, sin sponsor local', 'Sin IVA en exportación de servicios fuera UAE'], cons: ['Coste visa/residencia: $3,000-10,000 setup', 'Requiere presencia física (antes era 0 días, ahora flexible pero no 0)', 'Bancos dubaitíes exigen depósito mínimo o balance', 'Complejidad: need lawyer + PRO (agente trámites)', 'España puede cuestionar la residencia fiscal si tienes "centro de intereses vitales" ahí'], tricks: [ { text: 'Freezone > Mainland para e-commerce digital: sin sponsor, 0% import/export, menos auditorías. Mejores freezones para tech: DIFC, DMCC, Silicon Oasis.', source: 'UAE Corporate Tax Guide 2024', implemented: false }, { text: 'Residencia fiscal real: alquilar apartamento + obtener Emirates ID + no pasar >183 días en España + cortar vínculos (no casa habitual, familia, centro económico). Documenta TODO.', source: 'Convenio doble imposición ES-UAE', implemented: false }, { text: 'Corporate tax 9% solo aplica sobre ingresos >AED 375,000 (~€94,000). Debajo = 0%. Tu primera fase en Dubai puede ser 0% si mantienes ingresos por debajo del umbral en la entidad UAE.', source: 'UAE MoF Decisión 2023', implemented: false }, { text: 'Banking workaround: si los bancos UAE te dan problemas, abre cuenta en NeoBanks UAE (Wio, Mashreq Neo) que tienen menos requisitos que bancos tradicionales.', source: 'Comunidad expats Dubai', implemented: false }, { text: 'Estructura híbrida óptima: LLC USA recibe pagos → wire a Dubai Freezone company → tú retiras como dividendos o salario desde Dubai. Spain no ve nada si residencia fiscal está cambiada.', source: 'Planificación patrimonial avanzada', implemented: false } ] }, holding: { name: '🌍 Holding Internacional — Fase Legacy', status: 'FUTURA', color: 'var(--purple)', pros: ['Protección de activos: si una tienda demanda, la holding no se toca', 'Planificación sucesoria: transfieres acciones sin impuesto de sucesiones en ciertas jurisdicciones', 'Optimización intercompañías: facturas entre tus propias empresas en distintos países', 'Venta del negocio: vendes las acciones de la holding, no los activos = mejor tratamiento fiscal'], cons: ['Costes mantenimiento: $5,000-15,000/año en legal + accounting', 'Requiere abogado especializado (no gestor normal)', 'Reglas CFC (Controlled Foreign Company): Spain grava ingresos de sociedades extranjeras que controlas si no hay razón económica válida', 'Complejidad extrema: solo justificado >€200k/año de beneficio'], tricks: [ { text: 'Estonia Holding: 0% impuesto sobre beneficios retenidos. Solo tributas cuando repartes dividendos (20%). Ideal como holding intermedia entre LLC USA y tú.', source: 'Estonian CIT System', implemented: false }, { text: 'CFC Spain safe harbor: si la filial extranjera tiene sustancia real (oficina, empleados, dirección en ese país), Spain NO aplica CFC. Clave: no sea una "caja postal".', source: 'Art. 91-95 LIS', implemented: false }, { text: 'Participation exemption: si tu holding tiene >5% de otra sociedad durante >1 año, los dividendos recibidos están exentos de impuesto en la holding en la mayoría de jurisdicciones EU.', source: 'Directiva UE Madre-Hija', implemented: false }, { text: 'Trust + Holding combo: en ciertas jurisdicciones (Islas Marshall, Nevis), un trust puede ser dueño de la holding. Añade una capa extra de protección que ni un juicio civil fácilmente rompe.', source: 'Asset protection planning', implemented: false } ] } }; function renderFiscal() { const el = document.getElementById('fiscal-accordions'); const saved = JSON.parse(localStorage.getItem('stone_fiscal_tricks') || '{}'); el.innerHTML = `
Estructura actual: LLC USA (Mercury/Wise) + Autónomo España. Los trucos marcados = implementados. Puedes añadir los tuyos. Todo editable.
`; Object.keys(FISCAL_STRUCTURES).forEach(key => { const s = FISCAL_STRUCTURES[key]; const tricks = s.tricks.map((t, i) => { const savedTrick = saved[key] && saved[key][i]; const impl = savedTrick ? savedTrick.implemented : t.implemented; const customText = savedTrick ? savedTrick.text : t.text; return `
${impl ? '✓' : ''}
${customText}
${t.source}
`; }).join(''); el.innerHTML += `
${s.name} [${s.status}]
✓ Ventajas
${s.pros.map(p => `
• ${p}
`).join('')}
✗ Desventajas
${s.cons.map(c => `
• ${c}
`).join('')}
💡 Trucos Avanzados (click para marcar · edita el texto directamente)
${tricks}
`; }); } function toggleFiscalAcc(el) { const body = el.nextElementSibling; const isOpen = body.classList.contains('show'); // Cerrar todos document.querySelectorAll('.fiscal-acc-body').forEach(b => b.classList.remove('show')); document.querySelectorAll('.fiscal-acc-head').forEach(h => h.classList.remove('open')); // Abrir este si estaba cerrado if (!isOpen) { body.classList.add('show'); el.classList.add('open'); } } function toggleFiscalTrick(structKey, idx) { let saved = JSON.parse(localStorage.getItem('stone_fiscal_tricks') || '{}'); if (!saved[structKey]) saved[structKey] = {}; if (!saved[structKey][idx]) { saved[structKey][idx] = { text: FISCAL_STRUCTURES[structKey].tricks[idx].text, implemented: false }; } saved[structKey][idx].implemented = !saved[structKey][idx].implemented; localStorage.setItem('stone_fiscal_tricks', JSON.stringify(saved)); renderFiscal(); const state = saved[structKey][idx].implemented ? 'implementado' : 'desmarcado'; toast(`Truco ${state}`, saved[structKey][idx].implemented ? 'var(--green)' : 'var(--sub)'); } function editFiscalTrick(structKey, idx, newText) { let saved = JSON.parse(localStorage.getItem('stone_fiscal_tricks') || '{}'); if (!saved[structKey]) saved[structKey] = {}; if (!saved[structKey][idx]) { saved[structKey][idx] = { text: FISCAL_STRUCTURES[structKey].tricks[idx].text, implemented: false }; } saved[structKey][idx].text = newText.trim(); localStorage.setItem('stone_fiscal_tricks', JSON.stringify(saved)); } function addFiscalTrick(structKey) { const input = document.getElementById('fnew-' + structKey); const text = input.value.trim(); if (!text) return; let saved = JSON.parse(localStorage.getItem('stone_fiscal_tricks') || '{}'); if (!saved[structKey]) saved[structKey] = {}; // Añadir como truco nuevo const idx = FISCAL_STRUCTURES[structKey].tricks.length; FISCAL_STRUCTURES[structKey].tricks.push({ text: text, source: 'Mi nota', implemented: false }); saved[structKey][idx] = { text: text, implemented: false }; localStorage.setItem('stone_fiscal_tricks', JSON.stringify(saved)); renderFiscal(); toast('Truco añadido 💡', 'var(--green)'); } /* ═══════════════════════════════════════ PARTE 13: DIARIO ESTOICO + ENVIAR A MATRIX ═══════════════════════════════════════ */ function addPersonalLog() { const input = document.getElementById('personal-input'); const cat = document.getElementById('diary-cat').value; const text = input.value.trim(); if (!text) { toast('Escribe algo', 'var(--red)'); return; } let logs = JSON.parse(localStorage.getItem('stone_diary_' + todayStr()) || '[]'); logs.unshift({ id: uid(), text: text, cat: cat, time: nowTime(), sentToMatrix: false }); localStorage.setItem('stone_diary_' + todayStr(), JSON.stringify(logs)); input.value = ''; renderDiary(); toast('Nota añadida ✎', 'var(--green)'); } function renderDiary() { const el = document.getElementById('personal-list'); // Cargar todos los días, ordenar por fecha desc const allDays = {}; for (let i = 0; i < 30; i++) { const d = new Date(Date.now() - i * 86400000); const key = d.toISOString().split('T')[0]; const logs = JSON.parse(localStorage.getItem('stone_diary_' + key) || '[]'); if (logs.length) allDays[key] = logs; } const dates = Object.keys(allDays).sort().reverse(); if (!dates.length) { el.innerHTML = `
🏛️
Tu Diario Estoico está vacío
Escribe reflexiones, ideas disruptivas, wins del día.
Las ideas se pueden enviar directamente a Matrix como tareas.
`; return; } let html = ''; dates.forEach(date => { const logs = allDays[date]; const isToday = date === todayStr(); const dateObj = new Date(date + 'T12:00:00'); const dateLabel = isToday ? 'HOY' : dateObj.toLocaleDateString('es', {weekday:'long', day:'numeric', month:'long'}); html += `
${dateLabel}
`; // Agrupar por categoría dentro del día const catOrder = ['stoic','win','idea','log']; const catLabels = { stoic:'🏛️ Estoicismo', win:'🏆 Wins', idea:'💡 Ideas', log:'📝 Notas' }; const catColors = { stoic:'var(--purple)', win:'var(--yellow)', idea:'var(--green)', log:'var(--blue)' }; catOrder.forEach(cat => { const catLogs = logs.filter(l => l.cat === cat); if (!catLogs.length) return; html += `
${catLabels[cat]} (${catLogs.length})
`; catLogs.forEach(l => { const canSendToMatrix = (cat === 'idea' || cat === 'log') && !l.sentToMatrix; html += `
${l.time} ${l.text} ${l.sentToMatrix ? '✓ Matrix' : ''} ${canSendToMatrix ? `` : ''}
`; }); }); }); // Estadísticas del mes const totalEntries = Object.values(allDays).reduce((sum, arr) => sum + arr.length, 0); const totalIdeas = Object.values(allDays).flat().filter(l => l.cat === 'idea').length; const totalWins = Object.values(allDays).flat().filter(l => l.cat === 'win').length; const sentToMatrix = Object.values(allDays).flat().filter(l => l.sentToMatrix).length; html += `
📊 Estadísticas (últimos 30 días)
${totalEntries}
Total
${totalWins}
Wins
${totalIdeas}
Ideas
${sentToMatrix}
→ Matrix
🏛️ Prompt Estoico del Día
${getStoicPrompt()}
Escribe tu reflexión en "🏛️ Reflexión Estoica" arriba. Esto entrena tu metacognición.
`; el.innerHTML = html; } // ── Enviar entrada del diario a Matrix (cuadrante DECIDE) ── function sendDiaryToMatrix(date, entryId) { let logs = JSON.parse(localStorage.getItem('stone_diary_' + date) || '[]'); const entry = logs.find(l => l.id === entryId); if (!entry) return; // Crear tarea en Matrix > DECIDE let tasks = loadData('tasks'); tasks.push({ id: uid(), text: '💡 ' + entry.text, quad: 'decide', done: false, fromDiary: true, diaryDate: date, createdAt: new Date().toISOString() }); saveData('tasks', tasks); // Marcar como enviada en el diario entry.sentToMatrix = true; localStorage.setItem('stone_diary_' + date, JSON.stringify(logs)); renderDiary(); toast('💡 Idea enviada a Matrix → DECIDE', 'var(--green)'); } // ── Eliminar entrada del diario ── function deleteDiaryEntry(date, entryId) { showConfirm('¿Eliminar esta entrada?', () => { let logs = JSON.parse(localStorage.getItem('stone_diary_' + date) || '[]'); logs = logs.filter(l => l.id !== entryId); localStorage.setItem('stone_diary_' + date, JSON.stringify(logs)); renderDiary(); toast('Eliminada', 'var(--red)'); }); } // ── Prompts estoicos rotativos ── const STOIC_PROMPTS = [ '¿Qué cosas están fuera de mi control hoy? Lista 3. Ahora enfócate solo en lo que sí puedes controlar.', 'Marco Aurelio decía: "Tu mente toma la forma de lo que frecuentemente sostiene." ¿Qué estás sosteniendo tú hoy?', 'Séneca: "No es que tengamos poco tiempo, es que desperdiciamos mucho." ¿Dónde desperdicié tiempo hoy?', 'Epicteto: "No son las cosas las que nos perturban, sino nuestra opinión sobre ellas." ¿Qué opinión puedes cambiar?', 'Si alguien viera tu día de hoy sin saber tu contexto, ¿dirían que vives con propósito?', '¿Qué harías hoy si fuera tu último día? (No mueres mañana, pero la pregunta clarifica prioridades).', '¿Hay algún resentimiento que estás cargando que solo te daña a ti? Soltarlo no es perdonar al otro, es liberarte.', 'Zenón: "La naturaleza nos dio dos ojos, dos oídos, pero una sola boca para que escuchemos más de lo que hablamos." ¿Lo aplicaste hoy?', '¿Cuál es la versión de ti dentro de 5 años que te agradecería lo que hiciste hoy?', 'Musonio Rufo: "La riqueza no está en tener mucho, sino en no necesitar mucho." ¿Qué necesitas realmente?', '¿Qué小型 batalla perdiste hoy por ego que no importaba en absoluto?', 'Escribe 3 cosas por las que estás agradecido HOY (no genéricas, específicas de este día).', 'Marco Aurelio: "Lo que no es bueno para el enjambre, no es bueno para la abeja." ¿Cómo contribuyó tu trabajo al todo hoy?', '¿Hay algo que estás posponiendo por miedo al resultado? Recuerda: el proceso es lo que controlas.', 'Si te evaluaras solo por tus acciones (no tus intenciones), ¿qué nota te pondrías hoy?' ]; function getStoicPrompt() { // Uno por día, rotativo const dayOfYear = Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0)) / 86400000); return STOIC_PROMPTS[dayOfYear % STOIC_PROMPTS.length]; } /* ═══════════════════════════════════════ PARTE 14: NIGHT REVIEW + INSIGHT→MATRIX + EVOLE PIPELINE ═══════════════════════════════════════ */ // ── Night Review: guardar y renderizar ── function saveNightReview() { const wins = document.getElementById('nr-wins').value.trim(); const distractions = document.getElementById('nr-distractions').value.trim(); const tomorrow = document.getElementById('nr-tomorrow').value.trim(); const energy = document.getElementById('nr-energy').value; const reflection = document.getElementById('nr-reflection').value.trim(); const insight = document.getElementById('nr-insight').value.trim(); if (!wins && !tomorrow) { toast('Escribe al menos wins o prioridad mañana', 'var(--red)'); return; } let reviews = JSON.parse(localStorage.getItem('stone_night_reviews') || '[]'); reviews.unshift({ id: uid(), date: todayStr(), time: nowTime(), wins: wins, distractions: distractions, tomorrow: tomorrow, energy: parseInt(energy) || 5, reflection: reflection, insight: insight, insightSentToMatrix: false }); // Mantener solo últimos 90 if (reviews.length > 90) reviews = reviews.slice(0, 90); localStorage.setItem('stone_night_reviews', JSON.stringify(reviews)); // Limpiar formulario ['nr-wins','nr-distractions','nr-tomorrow','nr-reflection','nr-insight'].forEach(id => { document.getElementById(id).value = ''; }); document.getElementById('nr-energy').value = ''; // Si hay prioridad mañana, actualizar tomorrow plan if (tomorrow) { localStorage.setItem('stone_tomorrow_' + todayStr(), tomorrow); } renderNightReview(); toast('☽ Revisión guardada', 'var(--green)'); } function renderNightReview() { const el = document.getElementById('nr-history'); const reviews = JSON.parse(localStorage.getItem('stone_night_reviews') || '[]'); if (!reviews.length) { el.innerHTML = '
Sin revisiones aún. Haz tu primera tonight.
'; return; } // Estadísticas rápidas const avgEnergy = Math.round(reviews.slice(0, 7).reduce((s, r) => s + (r.energy || 5), 0) / Math.min(reviews.length, 7)); const totalInsights = reviews.filter(r => r.insight).length; let html = `
${avgEnergy}
Energía media (7d)
${totalInsights}
Insights capturados
`; // Últimas 10 revisiones html += reviews.slice(0, 10).map(r => { const d = new Date(r.date + 'T12:00:00'); const dateLabel = d.toLocaleDateString('es', {weekday:'short', day:'numeric', month:'short'}); return `
${dateLabel} · ${r.time}
⚡${r.energy}/10
${r.wins ? `
WINS
${r.wins}
` : ''} ${r.distractions ? `
DISTRACCIONES
${r.distractions}
` : ''} ${r.tomorrow ? `
PRIORIDAD MAÑANA
${r.tomorrow}
` : ''} ${r.reflection ? `
REFLEXIÓN MARKSMAN
${r.reflection}
` : ''} ${r.insight ? `
💡 INSIGHT ${r.insightSentToMatrix ? '✓ En Matrix' : `` }
${r.insight}
` : ''}
`; }).join(''); el.innerHTML = html; } // ── Enviar insight de Night Review a Matrix ── function sendNrInsightToMatrix(reviewId) { let reviews = JSON.parse(localStorage.getItem('stone_night_reviews') || '[]'); const review = reviews.find(r => r.id === reviewId); if (!review || !review.insight) return; let tasks = loadData('tasks'); tasks.push({ id: uid(), text: '💡 [Night Review] ' + review.insight, quad: 'decide', done: false, fromNightReview: true, nrDate: review.date, createdAt: new Date().toISOString() }); saveData('tasks', tasks); review.insightSentToMatrix = true; localStorage.setItem('stone_night_reviews', JSON.stringify(reviews)); renderNightReview(); toast('💡 Insight → Matrix (DECIDE)', 'var(--green)'); } function deleteNightReview(id) { showConfirm('¿Eliminar esta revisión?', () => { let reviews = JSON.parse(localStorage.getItem('stone_night_reviews') || '[]'); reviews = reviews.filter(r => r.id !== id); localStorage.setItem('stone_night_reviews', JSON.stringify(reviews)); renderNightReview(); toast('Eliminada', 'var(--red)'); }); } // ── Botón rápido del Night Review ── function sendInsightToMatrix() { const insight = document.getElementById('nr-insight').value.trim(); if (!insight) { toast('Escribe un insight primero', 'var(--red)'); return; } let tasks = loadData('tasks'); tasks.push({ id: uid(), text: '💡 [Night Review] ' + insight, quad: 'decide', done: false, fromNightReview: true, nrDate: todayStr(), createdAt: new Date().toISOString() }); saveData('tasks', tasks); toast('💡 Insight → Matrix (DECIDE)', 'var(--green)'); } /* ═══════════════════════════════════════ MÉTODO EVOLE: CHECKLIST + PIPELINE DE TIENDAS ═══════════════════════════════════════ */ function toggleEvole(el) { const body = el.nextElementSibling; body.classList.toggle('show'); el.classList.toggle('active'); } function renderEvole() { renderEvoleChecklist(); renderEvolePipeline(); } // ── Checklist de Ejecución Evole (persistente) ── const EVOLE_CHECKLIST = [ 'Investigación profunda (Reddit, YouTube, Amazon reviews)', 'Definir 3 deseos principales del avatar', 'Crear banco de frases (hooks) positivas y negativas', 'Aplicar Marksman: 3 hooks por ángulo', 'Probar con $20-50/día durante 3 días', 'Identificar ganador → Aplicar Sniper (optimizar imagen/hold)', 'Escalar presupuesto 20-40% cada 2 días si ROAS > 3', 'Black Friday: Resetear budgets a medianoche, escalar agresivo' ]; function renderEvoleChecklist() { // El checklist ya está en el HTML estático, lo hacemos interactivo const container = document.querySelector('.evole-content.show .evole-step:last-child div') || document.querySelectorAll('.evole-content')[3]; if (!container) return; let state = JSON.parse(localStorage.getItem('stone_evole_checklist') || '{}'); const items = container.querySelectorAll('div') || []; // Reemplazar contenido del último accordion con checklist interactivo const lastContent = document.querySelectorAll('.evole-content')[3]; if (!lastContent) return; lastContent.innerHTML = `
${EVOLE_CHECKLIST.map((item, i) => { const done = !!state[i]; return `
${done ? '☑' : '☐'} ${item}
`; }).join('')}
Progreso: ${Object.values(state).filter(Boolean).length}/${EVOLE_CHECKLIST.length}
`; } function toggleEvoleCheck(idx) { let state = JSON.parse(localStorage.getItem('stone_evole_checklist') || '{}'); state[idx] = !state[idx]; localStorage.setItem('stone_evole_checklist', JSON.stringify(state)); renderEvoleChecklist(); } // ── Pipeline de Tiendas conectado a Evole ── function loadPipeline() { return JSON.parse(localStorage.getItem('stone_evole_pipeline') || '[]'); } function savePipeline(data) { localStorage.setItem('stone_evole_pipeline', JSON.stringify(data)); } function addPipelineItem() { const product = document.getElementById('pipeline-product').value.trim(); const status = document.getElementById('pipeline-status').value; if (!product) { toast('Escribe un producto', 'var(--red)'); return; } let pipeline = loadPipeline(); pipeline.push({ id: uid(), product: product, status: status, notes: '', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }); savePipeline(pipeline); document.getElementById('pipeline-product').value = ''; renderEvolePipeline(); toast('Producto añadido al pipeline', 'var(--green)'); } function renderEvolePipeline() { const el = document.getElementById('evole-pipeline-list'); if (!el) return; const pipeline = loadPipeline(); if (!pipeline.length) { el.innerHTML = '
Pipeline vacío. Añade productos para trackear el flujo Evole completo.
'; return; } const statusOrder = ['research','scraper','landing','testing','scaling']; const statusLabels = { research: '🔍 Investigando', scraper: '⚙️ Scraping (Kalodata)', landing: '📄 Landing', testing: '🧪 Testing Ads (Marksman)', scaling: '🚀 Scaling (Sniper)' }; const statusColors = { research: 'var(--sub)', scraper: 'var(--blue)', landing: 'var(--purple)', testing: 'var(--orange)', scaling: 'var(--green)' }; // Agrupar por estado const grouped = {}; statusOrder.forEach(s => { grouped[s] = pipeline.filter(p => p.status === s); }); let html = ''; statusOrder.forEach(status => { const items = grouped[status]; if (!items || !items.length) return; html += `
${statusLabels[status]} (${items.length})
`; items.forEach(item => { const daysSince = Math.floor((Date.now() - new Date(item.createdAt).getTime()) / 86400000); html += `
${item.product} ${daysSince}d
`; }); }); // Resumen del pipeline const inResearch = (grouped.research || []).length; const inScaling = (grouped.scaling || []).length; const total = pipeline.length; html += `
Total: ${total} productos En investigación: ${inResearch} En scaling: ${inScaling}
`; el.innerHTML = html; } function updatePipelineStatus(id, newStatus) { let pipeline = loadPipeline(); const item = pipeline.find(p => p.id === id); if (!item) return; item.status = newStatus; item.updatedAt = new Date().toISOString(); savePipeline(pipeline); renderEvolePipeline(); if (newStatus === 'scaling') { toast('🚀 Producto en SCALING — aplica Sniper Method', 'var(--green)'); } } function deletePipelineItem(id) { showConfirm('¿Eliminar del pipeline?', () => { let pipeline = loadPipeline(); pipeline = pipeline.filter(p => p.id !== id); savePipeline(pipeline); renderEvolePipeline(); toast('Eliminado del pipeline', 'var(--red)'); }); } /* ═══════════════════════════════════════ PARTE 15: CUÁNTICO DINÁMICO + CALENDAR + HEALTH + AI COACH ═══════════════════════════════════════ */ /* ─────────────────────────────────────── CUÁNTICO DINÁMICO ─────────────────────────────────────── */ const QUANTUM_POOL = [ { title: '⚛ EFECTO OBSERVADOR', text: 'En mecánica cuántica, el simple hecho de observar una partícula altera su comportamiento. La función de onda colapsa cuando mides.', apply: 'En tu negocio: lo que mides (KPIs) cambia el comportamiento de tu equipo sin necesidad de instrucciones. Elige MÁXIMO 3 KPIs por tienda. Más = ruido.', color: 'var(--blue)', borderColor: 'rgba(10,132,255,.2)', bg: 'rgba(10,132,255,.06)' }, { title: '∞ SUPERPOSICIÓN', text: 'Un electrón existe en múltiples estados simultáneos hasta que se mide. No colapses las posibilidades demasiado pronto.', apply: 'En ads: mantén 3 ángulos en testing (superposición) hasta tener 50+ conversiones en cada uno (medida/colapso). El error común es elegir ganador sin datos.', color: 'var(--green)', borderColor: 'rgba(48,209,88,.2)', bg: 'rgba(48,209,88,.06)' }, { title: '🔗 ENTRELAZAMIENTO', text: 'Partículas entrelazadas se afectan instantáneamente sin importar la distancia. Einstein lo llamó "acción fantasmal a distancia".', apply: 'Ripple effect: si mejoras tu sueño (hábito), mejoras tus decisiones (negocio), que mejora tus relaciones (vida). Un cambio en una variable afecta al sistema entero.', color: 'var(--purple)', borderColor: 'rgba(191,90,242,.2)', bg: 'rgba(191,90,242,.06)' }, { title: '🌊 DUALIDAD ONDA-PARTÍCULA', text: 'La luz se comporta como onda Y como partícula dependiendo de cómo la observes. No es una u otra — es ambas.', apply: 'Tu TDAH no es un defecto ni una virtud — es ambos. En modo "partícula" = foco profundo en UNA tarea (Matrix DO NOW). En modo "onda" = creatividad dispersa (brainstorming, ideas). Usa cada modo intencionalmente.', color: 'var(--pink)', borderColor: 'rgba(255,107,157,.2)', bg: 'rgba(255,107,157,.06)' }, { title: '📐 PRINCIPIO DE INCERTIDUMBRE', text: 'Heisenberg: no puedes conocer simultáneamente la posición exacta Y el momento exacto de una partícula. Más precisión en uno = menos en el otro.', apply: 'En negocios: no puedes tener control TOTAL sobre calidad Y velocidad al mismo tiempo. En fase de testing = prioriza velocidad. En scaling = prioriza calidad. Acepta la incertidumbre del otro.', color: 'var(--orange)', borderColor: 'rgba(255,159,10,.2)', bg: 'rgba(255,159,10,.06)' }, { title: '🕳 TÚNEL CUÁNTICO', text: 'Una partícula puede atravesar una barrera que clásicamente no podría superar. La probabilidad no es cero — solo es baja.', apply: 'Ese producto que "no va a funcionar" tiene una probabilidad no nula de ser ganador. El tunneling cuántico en negocios = intentar lo que otros descartan por "imposible". Los outliers viven aquí.', color: 'var(--yellow)', borderColor: 'rgba(255,214,10,.2)', bg: 'rgba(255,214,10,.06)' }, { title: '🔄 DECOHERENCIA', text: 'Cuando un sistema cuántico interactúa con su entorno, pierde sus propiedades cuánticas y se vuelve "clásico". La decoherencia destruye la superposición.', apply: 'Tu entorno destruye tu superposición (creatividad). Notificaciones, ruido, multitarea = decoherencia. STONE OS es tu escudo: aísla una tarea, mantén la coherencia cuántica de tu foco.', color: 'var(--red)', borderColor: 'rgba(255,69,58,.2)', bg: 'rgba(255,69,58,.06)' }, { title: '🧠 CONCIENCIA Y TDAH', text: 'Desde la física cuántica hasta la neurociencia: el observador crea la realidad. Tu TDAH es un sistema operativo diferente con menos filtros prefrontales.', apply: 'Ventaja cuántica del TDAH: mientras otros siguen caminos lineales (colapsados), tú mantienes múltiples ideas en superposición y encuentras soluciones no obvias. STONE OS externaliza esa superposición en estructura ejecutable.', color: 'var(--purple)', borderColor: 'rgba(191,90,242,.2)', bg: 'rgba(191,90,242,.06)' } ]; let quantumIdx = 0; function renderQuantum() { // Panel dinámico: una perspectiva principal que rota const main = QUANTUM_POOL[quantumIdx % QUANTUM_POOL.length]; const next = QUANTUM_POOL[(quantumIdx + 1) % QUANTUM_POOL.length]; document.getElementById('quantum-dynamic-content').innerHTML = `
${main.title}
${main.text}
Aplicación a tu sistema: ${main.apply}
Siguiente: ${next.title}
`; // Panel estático: las otras perspectivas en miniatura const others = QUANTUM_POOL.filter((_, i) => i !== quantumIdx % QUANTUM_POOL.length); document.getElementById('quantum-static-content').innerHTML = `
Otras perspectivas
${others.map((q, i) => `
${q.title}
${q.apply.substring(0, 80)}...
`).join('')}
`; } function refreshQuantum() { quantumIdx = (quantumIdx + 1) % QUANTUM_POOL.length; renderQuantum(); toast('Nueva perspectiva cuántica ⚛', 'var(--blue)'); } function goToQuantum(idx) { quantumIdx = idx; renderQuantum(); } /* ─────────────────────────────────────── CALENDAR ─────────────────────────────────────── */ let calYear, calMonth; function initCal() { const now = new Date(); calYear = now.getFullYear(); calMonth = now.getMonth(); } function calNav(dir) { calMonth += dir; if (calMonth > 11) { calMonth = 0; calYear++; } if (calMonth < 0) { calMonth = 11; calYear--; } renderCalendar(); } function renderCalendar() { if (!calYear) initCal(); const grid = document.getElementById('cal-grid'); const monthEl = document.getElementById('cal-month'); const eventsEl = document.getElementById('cal-events'); const months = ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre']; monthEl.textContent = months[calMonth] + ' ' + calYear; const days = ['L','M','X','J','V','S','D']; let html = days.map(d => `
${d}
`).join(''); const firstDay = new Date(calYear, calMonth, 1).getDay(); const startDay = firstDay === 0 ? 6 : firstDay - 1; const daysInMonth = new Date(calYear, calMonth + 1, 0).getDate(); const today = todayStr(); // Días del mes anterior const prevDays = new Date(calYear, calMonth, 0).getDate(); for (let i = startDay - 1; i >= 0; i--) { html += `
${prevDays - i}
`; } // Cargar eventos del mes const allEvents = JSON.parse(localStorage.getItem('stone_cal_events') || '[]'); const monthEvents = {}; allEvents.forEach(e => { if (e.date && e.date.startsWith(calYear + '-' + String(calMonth + 1).padStart(2, '0'))) { if (!monthEvents[e.date]) monthEvents[e.date] = []; monthEvents[e.date].push(e); } }); // Días del mes for (let d = 1; d <= daysInMonth; d++) { const dateStr = calYear + '-' + String(calMonth + 1).padStart(2, '0') + '-' + String(d).padStart(2, '0'); const isToday = dateStr === today; const hasEvent = monthEvents[dateStr]; html += `
${d}
`; } // Días del siguiente mes const totalCells = startDay + daysInMonth; const remaining = totalCells % 7 === 0 ? 0 : 7 - (totalCells % 7); for (let i = 1; i <= remaining; i++) { html += `
${i}
`; } grid.innerHTML = html; // Eventos del día seleccionado o hoy const selectedDate = window._calSelectedDate || today; renderCalEvents(selectedDate, allEvents); } function showCalDay(date) { window._calSelectedDate = date; const allEvents = JSON.parse(localStorage.getItem('stone_cal_events') || '[]'); renderCalEvents(date, allEvents); } function renderCalEvents(date, allEvents) { const el = document.getElementById('cal-events'); const events = allEvents.filter(e => e.date === date); const dateObj = new Date(date + 'T12:00:00'); const label = dateObj.toLocaleDateString('es', {weekday:'long', day:'numeric', month:'long'}); el.innerHTML = `
${label}
${events.length ? events.map((e, i) => `
${e.cat} ${e.time} ${e.title} ${e.alarm ? '🔔' : ''} ${e.ics ? '.ics' : ''}
`).join('') : '
Sin eventos este día
'} `; } function addCalEvent() { const title = document.getElementById('cal-event-title').value.trim(); const time = document.getElementById('cal-event-time').value; const cat = document.getElementById('cal-event-cat').value; const alarmOn = document.getElementById('cal-alarm-on').checked; const alarmMin = document.getElementById('cal-alarm-min').value; const icsOn = document.getElementById('cal-ics-on').checked; if (!title) { toast('Escribe un título', 'var(--red)'); return; } const date = window._calSelectedDate || todayStr(); let events = JSON.parse(localStorage.getItem('stone_cal_events') || '[]'); events.push({ id: uid(), title: title, time: time || '00:00', date: date, cat: cat, alarm: alarmOn, alarmMin: parseInt(alarmMin) || 0, ics: icsOn, createdAt: new Date().toISOString() }); localStorage.setItem('stone_cal_events', JSON.stringify(events)); // Si tiene alarma, registrar en el checker if (alarmOn && time) { let alarms = JSON.parse(localStorage.getItem('stone_cal_alarms') || '[]'); alarms.push({ id: uid(), title: '📅 ' + title, date: date, time: time, reminderMin: parseInt(alarmMin) || 0, triggered: false, reminded: false }); localStorage.setItem('stone_cal_alarms', JSON.stringify(alarms)); } // Si pidió .ics, descargar if (icsOn && time) { downloadICS('📅 ' + title, date, time, parseInt(alarmMin) || 0); } document.getElementById('cal-event-title').value = ''; renderCalendar(); toast('Evento añadido 📅', 'var(--green)'); } function deleteCalEvent(date, idx) { let events = JSON.parse(localStorage.getItem('stone_cal_events') || '[]'); events = events.filter(e => !(e.date === date && events.indexOf(e) === idx)); // Re-filter properly const dateEvents = events.filter(e => e.date === date); if (dateEvents[idx]) { const targetId = dateEvents[idx].id; events = events.filter(e => e.id !== targetId); } localStorage.setItem('stone_cal_events', JSON.stringify(events)); renderCalendar(); toast('Evento eliminado', 'var(--red)'); } /* ─────────────────────────────────────── HEALTH — MEDICAMENTOS + PREP APPLE WATCH ─────────────────────────────────────── */ function addHealthLog() { const med = document.getElementById('health-med').value.trim(); const dose = document.getElementById('health-dose').value.trim(); const time = document.getElementById('health-time').value || nowTime(); if (!med) { toast('Escribe un medicamento', 'var(--red)'); return; } let logs = JSON.parse(localStorage.getItem('stone_health_' + todayStr()) || '[]'); logs.push({ id: uid(), med: med, dose: dose || '—', time: time, taken: false, addedAt: new Date().toISOString() }); localStorage.setItem('stone_health_' + todayStr(), JSON.stringify(logs)); // Si es un medicamento nuevo, ofrecer añadir a rutina diaria const allMeds = JSON.parse(localStorage.getItem('stone_health_routine') || '[]'); if (!allMeds.find(m => m.name.toLowerCase() === med.toLowerCase())) { allMeds.push({ id: uid(), name: med, dose: dose || '', time: time, active: true, since: todayStr() }); localStorage.setItem('stone_health_routine', JSON.stringify(allMeds)); } document.getElementById('health-med').value = ''; document.getElementById('health-dose').value = ''; renderHealth(); toast('Medicamento añadido ♥', 'var(--green)'); } function renderHealth() { const el = document.getElementById('health-list'); const histEl = document.getElementById('health-history'); // Rutina diaria (medicamentos activos) const routine = JSON.parse(localStorage.getItem('stone_health_routine') || '[]'); const activeRoutine = routine.filter(m => m.active); // Logs de hoy const todayLogs = JSON.parse(localStorage.getItem('stone_health_' + todayStr()) || '[]'); if (activeRoutine.length) { el.innerHTML = `
💊 RUTINA DIARIA
`; activeRoutine.forEach(med => { const taken = todayLogs.find(l => l.med.toLowerCase() === med.name.toLowerCase() && l.taken); const daysSince = Math.floor((Date.now() - new Date(med.since).getTime()) / 86400000); el.innerHTML += `
${taken ? '✓' : ''}
${med.name} ${med.dose} ${med.time} ${daysSince}d
`; }); } // Logs adicionales de hoy (que no están en rutina) const extraLogs = todayLogs.filter(l => !activeRoutine.find(m => m.name.toLowerCase() === l.med.toLowerCase())); if (extraLogs.length) { el.innerHTML += `
HOY — EXTRA
`; extraLogs.forEach(l => { el.innerHTML += `
${l.med} ${l.dose !== '—' ? '· ' + l.dose : ''} ${l.time}
`; }); } if (!activeRoutine.length && !extraLogs.length) { el.innerHTML = '
Sin medicamentos registrados
'; } // Historial: medicamentos desactivados/sustituidos const inactive = routine.filter(m => !m.active); if (inactive.length) { histEl.innerHTML = `
HISTORIAL (desactivados/sustituidos)
${inactive.map(m => { const days = Math.floor((Date.now() - new Date(m.since).getTime()) / 86400000); return `
${m.name} · ${m.dose} ${days}d activo
`; }).join('')} `; } else { histEl.innerHTML = '
Sin historial
'; } // Nota Apple Watch el.innerHTML += `
Apple Watch: Preparado para sincronización. Cuando configures HealthKit, las métricas de sueño, pasos y ritmo cardíaco se integrarán aquí automáticamente. Los cambios en medicamentos se reflejarán en tu rutina diaria de Matrix.
`; } function takeMedicine(medId) { let routine = JSON.parse(localStorage.getItem('stone_health_routine') || '[]'); const med = routine.find(m => m.id === medId); if (!med) return; let logs = JSON.parse(localStorage.getItem('stone_health_' + todayStr()) || '[]'); const existing = logs.find(l => l.med.toLowerCase() === med.name.toLowerCase()); if (existing) { existing.taken = !existing.taken; } else { logs.push({ id: uid(), med: med.name, dose: med.dose, time: med.time, taken: true, addedAt: new Date().toISOString() }); } localStorage.setItem('stone_health_' + todayStr(), JSON.stringify(logs)); renderHealth(); const allToday = logs.filter(l => l.taken); const totalActive = routine.filter(m => m.active).length; if (allToday.length === totalActive && totalActive > 0) { toast('💊 Todos los medicamentos tomados hoy', 'var(--green)'); } } function toggleHealthTaken(logId) { let logs = JSON.parse(localStorage.getItem('stone_health_' + todayStr()) || '[]'); const log = logs.find(l => l.id === logId); if (log) { log.taken = !log.taken; localStorage.setItem('stone_health_' + todayStr(), JSON.stringify(logs)); renderHealth(); } } function deactivateMed(medId) { showConfirm('¿Desactivar este medicamento? (ej: sustituido por otro)', () => { let routine = JSON.parse(localStorage.getItem('stone_health_routine') || '[]'); const med = routine.find(m => m.id === medId); if (med) { med.active = false; med.deactivatedAt = todayStr(); localStorage.setItem('stone_health_routine', JSON.stringify(routine)); renderHealth(); toast('Medicamento desactivado — movido a historial', 'var(--orange)'); } }); } function deleteMedFromHistory(medId) { let routine = JSON.parse(localStorage.getItem('stone_health_routine') || '[]'); routine = routine.filter(m => m.id !== medId); localStorage.setItem('stone_health_routine', JSON.stringify(routine)); renderHealth(); toast('Eliminado del historial', 'var(--red)'); } function deleteHealthLog(logId) { let logs = JSON.parse(localStorage.getItem('stone_health_' + todayStr()) || '[]'); logs = logs.filter(l => l.id !== logId); localStorage.setItem('stone_health_' + todayStr(), JSON.stringify(logs)); renderHealth(); } /* ─────────────────────────────────────── AI COACH — SISTEMA OFFLINE INTELIGENTE ─────────────────────────────────────── */ let aiMessages = []; function sendAI() { const input = document.getElementById('ai-input'); const text = input.value.trim(); if (!text) return; aiMessages.push({ role: 'user', text: text }); input.value = ''; renderAIChat(); // Simular respuesta inteligente basada en contexto setTimeout(() => { const response = generateAIResponse(text); aiMessages.push({ role: 'bot', text: response }); renderAIChat(); }, 600 + Math.random() * 800); } function generateAIResponse(input) { const lower = input.toLowerCase(); // Contexto de la app const tasks = loadData('tasks'); const urgent = tasks.filter(t => t.quad === 'do' && !t.done); const habits = JSON.parse(localStorage.getItem('stone_habits_def') || '[]'); const habitState = JSON.parse(localStorage.getItem('stone_habits_' + todayStr()) || '{}'); const doneHabits = habits.filter(h => habitState[h.id]).length; // Respuestas contextuales if (lower.includes('urgente') || lower.includes('prioridad')) { if (urgent.length) { return `Tienes ${urgent.length} tarea${urgent.length > 1 ? 's' : ''} urgente${urgent.length > 1 ? 's' : ''} sin completar:\n\n${urgent.map((t, i) => `${i + 1}. ${t.text}${t.deadline ? ' (límite: ' + t.deadline + ')' : ''}`).join('\n')}\n\nMi recomendación: coge la #1, pon un timer de 25 min (Pomodoro) y NO hagas nada más hasta que termine. El TDAH funciona mejor con una sola cosa visible. Lo demás es ruido.`; } return 'No tienes tareas urgentes ahora mismo. Buen momento para revisar tu cuadrante DECIDE o avanzar en hábitos.'; } if (lower.includes('hábito') || lower.includes('habit')) { return `Hoy llevas ${doneHabits}/${habits.length} hábitos completados (${Math.round(doneHabits / habits.length * 100)}%).\n\n${doneHabits === habits.length ? '★ Sistema completado. Neuroplasticidad activada. Tu cerebro está reforzando estas vías.' : 'Sigue. Cada checkbox que marcas fortalece conexiones neuronales reales (estudio de Nature 2024: nuevas espinas dendríticas en 2h de práctica enfocada).'}`; } if (lower.includes('tienda') || lower.includes('kpi') || lower.includes('roas')) { const stores = loadStores(); if (stores.length) { const s = stores[0]; const k = s.kpis || {}; return `📊 ${s.name}:\n• Revenue: $${formatNum(k.revenue || 0)} MXN\n• Pedidos: ${k.orders || 0}\n• ROAS: ${k.roas || 0}x ${k.roas >= 2 ? '✓' : '⚠️'}\n• CPA: $${k.cpa || 0} MXN\n• CTR: ${k.ctr || 0}%\n\n${k.roas >= 2 ? 'ROAS saludable. Aplica regla 20-40% para escalar presupuesto.' : 'ROAS bajo. Revisa: ¿el ángulo del hook está validado con Marksman (3 variaciones)? ¿El CTR supera 1.5%? Si no, vuelve a investigación antes de gastar más.'}`; } return 'No tienes tiendas registradas todavía. Ve a Tiendas → + Tienda para empezar a trackear KPIs.'; } if (lower.includes(' Marksman') || lower.includes(' sniper') || lower.includes(' ángulo') || lower.includes(' hook')) { return '🎯 Marksman Method:\n\n1. Elige 1 ángulo (ej: "Confianza", "Dolor", "Identidad")\n2. Crea 3 variaciones del HOOK (solo texto, misma imagen)\n3. Lanza con $20-50/día durante 3 días\n4. La que gane en CTR → esa es tu dirección\n5. Entonces aplica Sniper: varia la imagen, el hold, el sub-avatar\n\nError común: cambiar de ángulo antes de tener 3 tests reales. Data de EVOLE: 80% de los ángulos "muertos" nunca recibieron 3 tests.'; } if (lower.includes('dopamina') || lower.includes(' foco') || lower.includes(' tdah') || lower.includes(' concentración')) { return '🧠 Protocolo Dopamina para TDAH:\n\n1. Sin teléfono 30 min al despertar (crítico)\n2. Una sola tarea visible (Matrix DO NOW)\n3. Timer Pomodoro: 25 min on / 5 min off\n4. Ejercicio físico antes de trabajo cognitivo pesado\n5. Eliminar notificaciones push\n6. Si necesitas reset profundo: 14 días sin estimulación barata (redes, porn, junk food)\n\nTu sistema operativo no es defectuoso — tiene menos filtros. STONE OS es ese filtro externo.'; } if (lower.includes('escalar') || lower.includes(' scaling')) { return '🚀 Regla del 20-40 para escalar:\n\n• ROAS > 3 estable por 3+ días → empieza a escalar\n• Sube budget 20% cada 2 días\n• NUNCA más de 40% de golpe (learning phase reset)\n• Si ROAS cae < 2: reduce 15% y espera 48h\n• Si ROAS cae < 1.5: pausa, revisa ángulo, vuelve a Marksman\n\nCash flow reminder: si eres COD MX, necesitas capital de trabajo = (costo unitario × ventas/día × días tránsito).'; } if (lower.includes('noche') || lower.includes(' review') || lower.includes(' revisión')) { return '☽ Night Review óptimo:\n\n1. ¿Qué logré? (refuerza dirección positiva)\n2. ¿Qué me distrajo? (identifica patrones TDAH, no te juzgues)\n3. ¿Prioridad #1 mañana? (una sola)\n4. ¿Energía 1-10? (trackea patrón semanal)\n5. ¿Apliqué Marksman? (método sobre resultados)\n6. ¿Insight capturado? (envía a Matrix con 💡→Matrix)\n\nHazlo ANTES de mirar el teléfono. Son 5 min que previenen 2h de dispersión al día siguiente.'; } if (lower.includes('fiscal') || lower.includes(' impuesto') || lower.includes(' llc') || lower.includes(' irpf')) { return '🏦 Resumen rápido de tu estructura:\n\n• 🇺🇸 LLC Wyoming: 0% impuesto estatal, pass-through, Mercury + Wise\n• 🇪🇸 Autónomo ES: deducciones vivienda/internet/teléfono, reserva 20-25%\n• Form 5472 deadline: 6 meses después de cierre fiscal\n• Siguiente fase (€50k+): evaluar Dubai Freezone o Portugal NHR\n\nVe a Fiscal → expande cada estructura para ver trucos avanzados con fuente.'; } // Respuesta genérica inteligente const generics = [ `Entiendo tu pregunta. Dado el contexto de tu sistema (STONE OS), te recomiendo:\n\n1. Desglosa esto en tareas accionables\n2. Mete las tareas en Matrix (DO NOW si es urgente, DECIDE si puede esperar)\n3. Si es un insight, apúntalo en el Diario Estoico como 💡 Idea y mándalo a Matrix\n4. Revisa esta noche en Night Review si avanzaste\n\n¿Quieres que profundice en algún aspecto concreto?`, `Buena pregunta. Aquí va mi análisis desde el método Evole:\n\n• ¿Esto es una dirección (Marksman) o una ejecución (Sniper)?\n• Si es dirección: testea 3 variaciones antes de invertir tiempo\n• Si es ejecución: optimiza lo que ya funciona\n• Conecta esto con tus KPIs de tiendas para medir impacto real\n\nDime más contexto y te doy una respuesta más específica.`, `Desde la perspectiva cuántica: no colapses esta posibilidad demasiado pronto.\n\nMantén 2-3 opciones abiertas (superposición) hasta tener datos. Cuando tengas suficiente información, entonces toma la decisión (colapso de la función de onda).\n\nMientras tanto: apunta las opciones en tu Diario Estoico y vuelve a revisarlas en 48h.` ]; return generics[Math.floor(Math.random() * generics.length)]; } function renderAIChat() { const el = document.getElementById('ai-messages'); if (!aiMessages.length) { aiMessages.push({ role: 'bot', text: 'Hola! Soy tu coach entrenado con el método Evole y estrategias de dropshipping. Puedo ayudarte con:\n• Análisis de ángulos de marketing\n• Estrategias COD México\n• Optimización de hábitos para TDAH\n• Escalado de tiendas\n• Estado actual de tu sistema\n\nPrueba preguntar: "¿qué tareas urgentes tengo?" o "dame tips de dopamina para TDAH"' }); } el.innerHTML = aiMessages.map(m => `
${m.text.replace(/\n/g, '
')}
`).join(''); el.scrollTop = el.scrollHeight; } function clearAIChat() { aiMessages = []; renderAIChat(); toast('Chat limpiado', 'var(--sub)'); } // ── Cerrar el script ── initCal(); /* ═══════════════════════════════════════ PARTE 16: ALARM CHECKER COMPLETO + CIERRE ═══════════════════════════════════════ */ /* ── ATENCIÓN: Esto REEMPLAZA la función checkAlarms() de la PARTE 6 ── Busca la función checkAlarms() en la Parte 6 y SUSTITÚYELA completa por esta. Si no la encuentras, simplemente pega esto después de la Parte 15. */ function checkAlarms() { const now = nowTime(); let changed = false; // ── 1. Alarmas de tareas (Matrix DO NOW) ── let tasks = loadData('tasks'); tasks.forEach(t => { if (t.quad !== 'do' || t.done || !t.deadline) return; const [dH, dM] = t.deadline.split(':').map(Number); const [nH, nM] = now.split(':').map(Number); const deadlineMins = dH * 60 + dM; const nowMins = nH * 60 + nM; const diff = deadlineMins - nowMins; // Recordatorio silencioso if (t.reminder > 0 && !t.reminded && diff > 0 && diff <= t.reminder) { t.reminded = true; changed = true; playReminderSound(); toast(`⏳ Recordatorio: "${t.text}" — límite en ${diff} min`, 'var(--orange)'); } // Marcar como triggered cuando pasa la hora if (diff <= 0 && !t.alarmTriggered) { t.alarmTriggered = true; changed = true; } // Alarma sonora si pasado el límite y no silenciado if (diff <= 0 && t.alarmTriggered && Date.now() > alarmSilencedUntil) { showAlarmBanner(`URGENTE PASADA: ${t.text} (límite: ${t.deadline})`); startAlarmSound(); } }); if (changed) { saveData('tasks', tasks); renderMatrix(); } // ── 2. Alarmas de Calendar ── const calAlarms = JSON.parse(localStorage.getItem('stone_cal_alarms') || '[]'); let calChanged = false; const today = todayStr(); calAlarms.forEach(a => { // Solo alarmas de hoy if (a.date !== today) return; if (a.triggered && a.silenced) return; const [aH, aM] = a.time.split(':').map(Number); const [nH, nM] = now.split(':').map(Number); const alarmMins = aH * 60 + aM; const nowMins = nH * 60 + nM; const diff = alarmMins - nowMins; // Recordatorio if (a.reminderMin > 0 && !a.reminded && diff > 0 && diff <= a.reminderMin) { a.reminded = true; calChanged = true; playReminderSound(); toast(`📅 Recordatorio: ${a.title} en ${diff} min`, 'var(--blue)'); } // Alarma cuando llega la hora if (diff <= 0 && !a.triggered) { a.triggered = true; calChanged = true; } if (diff <= 0 && a.triggered && !a.silenced && Date.now() > alarmSilencedUntil) { showAlarmBanner(`📅 ALARMA: ${a.title} (${a.time})`); startAlarmSound(); } }); if (calChanged) { localStorage.setItem('stone_cal_alarms', JSON.stringify(calAlarms)); } // ── 3. Auto-silenciar cuando no hay alarmas activas ── const activeTaskAlarms = tasks.filter(t => t.quad === 'do' && !t.done && t.deadline && t.alarmTriggered ); const activeCalAlarms = calAlarms.filter(a => a.date === today && a.triggered && !a.silenced ); const [nH3, nM3] = now.split(':').map(Number); const nowMins3 = nH3 * 60 + nM3; let anyActive = false; activeTaskAlarms.forEach(t => { const [h, m] = t.deadline.split(':').map(Number); if (h * 60 + m <= nowMins3) anyActive = true; }); activeCalAlarms.forEach(a => { const [h, m] = a.time.split(':').map(Number); if (h * 60 + m <= nowMins3) anyActive = true; }); if (!anyActive) { stopAlarmSound(); document.getElementById('alarm-banner').classList.remove('show'); } // ── 4. Limpiar alarmas de calendar de días pasados ── const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]; const cleanAlarms = calAlarms.filter(a => a.date >= yesterday); if (cleanAlarms.length !== calAlarms.length) { localStorage.setItem('stone_cal_alarms', JSON.stringify(cleanAlarms)); } } // ── Sobrescribir dismissAlarm para también silenciar calendar ── function dismissAlarm() { document.getElementById('alarm-banner').classList.remove('show'); stopAlarmSound(); alarmSilencedUntil = Date.now() + 300000; // 5 min // Marcar calendar alarms como silenced const calAlarms = JSON.parse(localStorage.getItem('stone_cal_alarms') || '[]'); const today = todayStr(); let changed = false; calAlarms.forEach(a => { if (a.date === today && a.triggered && !a.silenced) { a.silenced = true; changed = true; } }); if (changed) { localStorage.setItem('stone_cal_alarms', JSON.stringify(calAlarms)); } } /* ── Limpieza automática de datos antiguos (corre una vez al día) ── */ function dailyCleanup() { const lastCleanup = localStorage.getItem('stone_last_cleanup'); if (lastCleanup === todayStr()) return; // Limpiar hábitos de hace más de 60 días for (let i = 60; i < 120; i++) { const d = new Date(Date.now() - i * 86400000).toISOString().split('T')[0]; localStorage.removeItem('stone_habits_' + d); localStorage.removeItem('stone_diary_' + d); localStorage.removeItem('stone_health_' + d); localStorage.removeItem('stone_tasks_' + d); } // Limpiar news feed leídas hace más de 30 días let feed = JSON.parse(localStorage.getItem('stone_news_feed') || '[]'); const thirtyDaysAgo = Date.now() - 30 * 86400000; feed = feed.filter(n => (n.addedAt || 0) > thirtyDaysAgo || !JSON.parse(localStorage.getItem('stone_news_read') || '[]').includes(n.id)); localStorage.setItem('stone_news_feed', JSON.stringify(feed)); localStorage.setItem('stone_last_cleanup', todayStr()); } // Ejecutar limpieza al iniciar dailyCleanup(); /* ── Notificación de bienvenida (solo primera vez) ── */ if (!localStorage.getItem('stone_welcomed')) { setTimeout(() => { toast('Bienvenido a STONE OS v3 🧬', 'var(--green)'); setTimeout(() => toast('Empieza con Daily Routine → Matrix DO NOW', 'var(--blue)'), 1500); }, 800); localStorage.setItem('stone_welcomed', '1'); } initCal(); dailyCleanup(); if (!localStorage.getItem('stone_welcomed')) { setTimeout(() => { toast('Bienvenido a STONE OS v3 🧬', 'var(--green)'); setTimeout(() => toast('Empieza con Daily Routine → Matrix DO NOW', 'var(--blue)'), 1500); }, 800); localStorage.setItem('stone_welcomed', '1'); }