Rio de Janeiro
TOP 3 DO DIA
AGENDA
EM SEGUIDA Ver tudo →
TODAS ABERTAS Ver tudo →
ESCORREGANDO ver →
ROTINAS ver →
RELEMBRAR
REVISAR
ESCORREGANDO ver →
ROTINAS ver →
RELEMBRAR
REVISAR
Ordenar:
Ordenar:
PERFIL
Nome
Cargo
Conta Google
🎤 VOZ E IA
Groq API Key
Whisper (voz) + Llama 3.3 (chat) · console.groq.com
Status
GOOGLE CALENDAR
Sincronizar agenda
Eventos aparecem em "Em Seguida"
Não conectado
VERSÃO
Fast Fluent OS
APARÊNCIA
Tema
Cores de categoria
Aulas
Admin
Cobranças
Pessoal
IDIOMA
Idioma do app
🔔 NOTIFICAÇÕES
Rotinas — Manhã
Lembrete de rotinas matinais
Rotinas — Tarde
Rotinas — Noite
Lembrete de compromissos
15 min antes de cada evento do Calendar
LAYOUT E TEMA
Modo compacto
Menos espaço, mais conteúdo
Cor de destaque
Cor dos botões e destaques
DADOS
Exportar
Backup JSON de todos os dados
Limpar tudo
Remove todos os dados permanentemente
O que deseja criar?
Tarefa
Adicionar uma nova tarefa
Projeto
Criar um novo projeto
Nota
Salvar uma nota ou citação
Rotina
Adicionar uma nova rotina
🔔
Sincronizado
Soltar para atualizar
Fast Fluent OS
T
Grafo de notas
Atividade recente
Nenhuma atividade ainda
📵 Sem conexão — trabalhando offline
Nova tarefa
Nova nota
Assistente de voz
Assistente de voz
Toque no microfone para falar
VOCÊ DISSE
RESPOSTA
in string function exportNotePDF(){ const title=(document.getElementById('editor-title')||{value:'Nota'}).value||'Nota'; const content=document.getElementById('note-editor-content'); if(!content)return; const w=window.open('','_blank'); if(!w){toast('Permita popups para exportar PDF.');return;} const css='body{font-family:Georgia,serif;max-width:700px;margin:40px auto;color:#2a1a16;line-height:1.8;font-size:15px}h1{font-size:28px;font-weight:300;border-bottom:1px solid #ddd;padding-bottom:10px;margin-bottom:24px}h2{font-size:20px;font-weight:600}blockquote{border-left:3px solid #ddd;padding:4px 16px;color:#666;font-style:italic}code{background:#f5f5f5;padding:2px 6px;border-radius:4px}@media print{body{margin:20px}}'; w.document.open(); w.document.write('Fast Fluent OS v2.0618.1830

'); w.document.write(escHtml(title)); w.document.write('

'); w.document.write(content.innerHTML); w.document.write(''); w.document.close(); setTimeout(function(){w.print();},500); } // GRAPH function toggleGraph(){_graphOpen?closeGraph():openGraph();} function openGraph(){_graphOpen=true;document.getElementById('graph-panel').classList.add('open');const btn=document.getElementById('graph-toggle-btn');if(btn)btn.classList.add('active');renderGraph();} function closeGraph(){_graphOpen=false;document.getElementById('graph-panel').classList.remove('open');const btn=document.getElementById('graph-toggle-btn');if(btn)btn.classList.remove('active');if(_graphSim){_graphSim.stop();_graphSim=null;}} function renderGraph(){const svg=document.getElementById('graph-svg');if(!svg)return;if(typeof d3==='undefined'){const s=document.createElement('script');s.src='https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js';s.onload=()=>renderGraph();document.head.appendChild(s);return;}const libs=getLib();const W=svg.clientWidth||340,H=svg.clientHeight||window.innerHeight-60;const nodes=libs.map(l=>({id:l.id,title:l.title||'Sem título',type:l.type||'nota'}));const nodeMap={};libs.forEach(l=>{nodeMap[(l.title||'').toLowerCase()]=l.id;});const links=[];libs.forEach(l=>{[...(l.body||'').matchAll(/\[\[([^\]]+)\]\]/g)].forEach(m=>{const tid=nodeMap[m[1].toLowerCase()];if(tid&&tid!==l.id)links.push({source:l.id,target:tid});});});d3.select(svg).selectAll('*').remove();const svgEl=d3.select(svg).attr('width',W).attr('height',H);const g=svgEl.append('g');svgEl.call(d3.zoom().scaleExtent([.2,4]).on('zoom',e=>g.attr('transform',e.transform)));const typeColor={nota:'var(--accent)',citacao:'var(--blue)',livro:'#0f9d58'};const connCount={};nodes.forEach(n=>connCount[n.id]=0);links.forEach(l=>{connCount[l.source]=(connCount[l.source]||0)+1;connCount[l.target]=(connCount[l.target]||0)+1;});const link=g.append('g').selectAll('line').data(links).join('line').attr('stroke','var(--border2)').attr('stroke-width',1.5).attr('stroke-opacity',.7);const node=g.append('g').selectAll('g').data(nodes).join('g').style('cursor','pointer').call(d3.drag().on('start',(e,d)=>{if(!e.active)_graphSim.alphaTarget(.3).restart();d.fx=d.x;d.fy=d.y;}).on('drag',(e,d)=>{d.fx=e.x;d.fy=e.y;}).on('end',(e,d)=>{if(!e.active)_graphSim.alphaTarget(0);d.fx=null;d.fy=null;})).on('click',(e,d)=>openNoteEditor(d.id)).on('mouseover',(e,d)=>{const tt=document.getElementById('graph-tooltip');if(tt){tt.textContent=d.title;tt.style.display='block';tt.style.left=(e.clientX+12)+'px';tt.style.top=(e.clientY-8)+'px';}}).on('mouseout',()=>{const tt=document.getElementById('graph-tooltip');if(tt)tt.style.display='none';});node.append('circle').attr('r',d=>6+Math.min((connCount[d.id]||0)*2,12)).attr('fill',d=>typeColor[d.type]||'var(--accent)').attr('fill-opacity',.9).attr('stroke','var(--bg)').attr('stroke-width',2.5);node.append('text').text(d=>d.title.length>18?d.title.substring(0,16)+'…':d.title).attr('x',d=>10+Math.min((connCount[d.id]||0)*2,12)).attr('y',4).attr('font-size','10px').attr('fill','var(--text2)').attr('font-family','inherit');_graphSim=d3.forceSimulation(nodes).force('link',d3.forceLink(links).id(d=>d.id).distance(90)).force('charge',d3.forceManyBody().strength(-150)).force('center',d3.forceCenter(W/2,H/2)).force('collision',d3.forceCollide().radius(28)).on('tick',()=>{link.attr('x1',d=>d.source.x).attr('y1',d=>d.source.y).attr('x2',d=>d.target.x).attr('y2',d=>d.target.y);node.attr('transform',d=>'translate('+d.x+','+d.y+')');});const ce=document.getElementById('graph-node-count');if(ce)ce.textContent=nodes.length+' notas · '+links.length+' links';} function toggleActivityPanel(){_activityOpen?closeActivityPanel():openActivityPanel();} function openActivityPanel(){_activityOpen=true;const p=document.getElementById('activity-panel');if(p)p.classList.add('open');const btn=document.getElementById('activity-bell-btn');if(btn)btn.classList.add('active');const dot=document.getElementById('bell-dot');if(dot)dot.classList.remove('show');localStorage.setItem('ffos_activity_seen',Date.now().toString());renderActivityPanel();} function closeActivityPanel(){_activityOpen=false;const p=document.getElementById('activity-panel');if(p)p.classList.remove('open');const btn=document.getElementById('activity-bell-btn');if(btn)btn.classList.remove('active');} function renderActivityPanel(){const body=document.getElementById('activity-panel-body');if(!body)return;const todayStr=dk(today0());const yd=new Date(today0());yd.setDate(yd.getDate()-1);const ydStr=dk(yd);const items=[];getTasks().forEach(t=>{const d=t.updated||t.date||'';if(d>=ydStr)items.push({type:'task',id:t.id,name:t.name,meta:t.done?'Concluída':(t.date?'Vence '+t.date:'Sem data'),badge:t.done?'done':(d===todayStr?'new':'edited'),badgeText:t.done?'✓ Feita':(d===todayStr?'Hoje':'Ontem'),icon:'✓',iconClass:'task',date:d});});getLib().forEach(l=>{const d=l.updated||l.date||'';if(d>=ydStr){const icons={nota:'📝',citacao:'💬',livro:'📚'};const labels={nota:'Nota',citacao:'Citação',livro:'Livro'};items.push({type:'lib',id:l.id,name:l.title||'Sem título',meta:(labels[l.type]||'Nota')+' · '+d,badge:d===todayStr?'new':'edited',badgeText:d===todayStr?'Hoje':'Ontem',icon:icons[l.type]||'📝',iconClass:'note',date:d});}});getRoutines().forEach(r=>{if(localStorage.getItem('routine_'+r.id+'_'+todayStr))items.push({type:'routine',id:r.id,name:r.name,meta:'Rotina · Concluída hoje',badge:'done',badgeText:'✓ Feita',icon:'↻',iconClass:'routine',date:todayStr});});getProjects().forEach(p=>{const d=p.updated||'';if(d>=ydStr)items.push({type:'project',id:p.id,name:p.name,meta:'Projeto · '+p.status,badge:d===todayStr?'new':'edited',badgeText:d===todayStr?'Hoje':'Ontem',icon:'▣',iconClass:'project',date:d});});items.sort((a,b)=>b.date>a.date?1:-1);if(!items.length){body.innerHTML='
Nenhuma atividade recente
';return;}function ri(arr){return arr.map(i=>'
'+i.icon+'
'+escHtml(i.name)+'
'+escHtml(i.meta)+'
'+i.badgeText+'
').join('');}const ti=items.filter(i=>i.date===todayStr),yi=items.filter(i=>i.date===ydStr);let h='';if(ti.length)h+='
HOJE
'+ri(ti);if(yi.length)h+='
ONTEM
'+ri(yi);body.innerHTML=h;} function actItemClick(type,id){closeActivityPanel();setTimeout(()=>{if(type==='task'){goTo('tasks');setTimeout(()=>openEditTask(id),150);}else if(type==='lib'){goTo('library');setTimeout(()=>openEditLib(id),150);}else if(type==='routine'){goTo('routines');}else if(type==='project'){goTo('projects');setTimeout(()=>openEditProject(id),150);}},200);} function checkActivityBell(){const todayStr=dk(today0());const yd=new Date(today0());yd.setDate(yd.getDate()-1);const ydStr=dk(yd);let hasNew=false;getTasks().forEach(t=>{if((t.updated||t.date||'')>=ydStr)hasNew=true;});getLib().forEach(l=>{if((l.updated||l.date||'')>=ydStr)hasNew=true;});const dot=document.getElementById('bell-dot');if(dot&&hasNew)dot.classList.add('show');} function toggleFabMenu(){_fabOpen?closeFabMenu():openFabMenu();} function openFabMenu(){_fabOpen=true;document.getElementById('fab-menu').classList.add('open');document.getElementById('fab-backdrop').classList.add('show');} function closeFabMenu(){_fabOpen=false;const m=document.getElementById('fab-menu');const b=document.getElementById('fab-backdrop');if(m)m.classList.remove('open');if(b)b.classList.remove('show');} function hideSplash(){const s=document.getElementById('splash-screen');if(s){s.style.opacity='0';s.style.transition='opacity .4s';setTimeout(()=>{if(s.parentNode)s.parentNode.removeChild(s);},400);}} function startClock(){function tick(){const el=document.getElementById('today-clock');if(el)el.textContent=new Date().toLocaleTimeString('pt-BR',{hour:'2-digit',minute:'2-digit',second:'2-digit'});}tick();setInterval(tick,1000);} function renderRoutineProgress(){const el=document.getElementById('routine-progress-wrap');if(!el)return;const routines=getRoutines();if(!routines.length){el.style.display='none';return;}const todayStr=dk(today0());const done=routines.filter(r=>localStorage.getItem('routine_'+r.id+'_'+todayStr)).length;const pct=Math.round(done/routines.length*100);el.innerHTML='
Rotinas de hoje'+done+'/'+routines.length+' ('+pct+'%)
';el.style.display='block';} async function fetchWeatherInline(){const el=document.getElementById('today-weather-inline');if(!el||!navigator.geolocation)return;try{navigator.geolocation.getCurrentPosition(async pos=>{const{latitude:lat,longitude:lon}=pos.coords;const r=await fetch('https://api.open-meteo.com/v1/forecast?latitude='+lat+'&longitude='+lon+'¤t_weather=true');const d=await r.json();const w=d.current_weather;const icons={0:'☀️',1:'🌤',2:'⛅',3:'☁️',45:'🌫',51:'🌦',61:'🌧',71:'❄️',80:'🌦',95:'⛈'};el.innerHTML=''+(icons[w.weathercode]||'🌡')+''+Math.round(w.temperature)+'°C';});}catch(e){}} function initOfflineIndicator(){const b=document.getElementById('offline-banner');if(!b)return;function u(){b.classList.toggle('show',!navigator.onLine);}window.addEventListener('online',u);window.addEventListener('offline',u);u();} let _libSort='updated'; function setLibSort(s,btn){_libSort=s;document.querySelectorAll('.lib-sort-btn').forEach(b=>b.classList.remove('active'));if(btn)btn.classList.add('active');renderLibrary();} function applyLibSort(items){const s=items.slice();if(_libSort==='updated')s.sort((a,b)=>(b.updated||b.date||'')>(a.updated||a.date||'')?1:-1);else if(_libSort==='created')s.sort((a,b)=>(b.date||'')>(a.date||'')?1:-1);else if(_libSort==='alpha')s.sort((a,b)=>(a.title||'')>(b.title||'')?1:-1);return s;} function dueDateLabel(dateStr){if(!dateStr)return '';const today=dk(today0());if(dateStr'+days+'d atraso';}if(dateStr===today)return 'Hoje';const days=Math.floor((new Date(dateStr)-new Date(today))/86400000);if(days===1)return 'Amanhã';if(days<=3)return 'em '+days+'d';return ''+dateStr+'';} let _noteSearchMatches=[],_noteSearchIdx=0; function noteSearchOpen(){const bar=document.getElementById('note-search-bar');if(bar){bar.classList.add('open');document.getElementById('note-search-input').focus();}} function noteSearchClose(){const bar=document.getElementById('note-search-bar');if(bar)bar.classList.remove('open');const c=document.getElementById('note-editor-content');if(c)c.innerHTML=c.innerHTML.replace(/(.*?)<\/mark>/g,'$1');const cnt=document.getElementById('note-search-count');if(cnt)cnt.textContent='';_noteSearchMatches=[];} function noteSearchRun(q){const c=document.getElementById('note-editor-content');if(!c)return;c.innerHTML=c.innerHTML.replace(/(.*?)<\/mark>/g,'$1');if(!q||!q.trim())return;c.innerHTML=c.innerHTML.replace(new RegExp('('+q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+')','gi'),'$1');_noteSearchMatches=Array.from(c.querySelectorAll('mark.search-hl'));_noteSearchIdx=0;noteSearchHighlight();const cnt=document.getElementById('note-search-count');if(cnt)cnt.textContent=_noteSearchMatches.length?'1/'+_noteSearchMatches.length:'0';} function noteSearchNav(dir){if(!_noteSearchMatches.length)return;_noteSearchMatches[_noteSearchIdx].classList.remove('current');_noteSearchIdx=(_noteSearchIdx+dir+_noteSearchMatches.length)%_noteSearchMatches.length;noteSearchHighlight();const cnt=document.getElementById('note-search-count');if(cnt)cnt.textContent=(_noteSearchIdx+1)+'/'+_noteSearchMatches.length;} function noteSearchHighlight(){if(!_noteSearchMatches[_noteSearchIdx])return;_noteSearchMatches[_noteSearchIdx].classList.add('current');_noteSearchMatches[_noteSearchIdx].scrollIntoView({block:'center'});} function gcalResync(){const icon=document.getElementById('gcal-resync-icon');const token=localStorage.getItem('ffos_gcal_token');if(!token){toast('Conecte o Google Calendar primeiro.');return;}if(icon){let spin=0;const si=setInterval(()=>{spin+=360;icon.style.transform='rotate('+spin+'deg)';},800);gcalFetch();setTimeout(()=>{clearInterval(si);icon.style.transform='rotate(0deg)';toast('📅 Agenda atualizada!');},1500);}else{gcalFetch();toast('📅 Agenda atualizada!');}} setInterval(()=>{if(localStorage.getItem('ffos_gcal_token'))gcalFetch();},5*60*1000); function gcalSilentRefresh(){if(!window._auth||!window._auth.currentUser){gcalConnect();return;}var provider=new firebase.auth.GoogleAuthProvider();provider.addScope('https://www.googleapis.com/auth/calendar.readonly');window._auth.signInWithPopup(provider).then(function(result){var token=result.credential?result.credential.accessToken:null;if(token){localStorage.setItem('ffos_gcal_token',token);localStorage.setItem('ffos_gcal_expiry',Date.now()+55*60*1000);localStorage.setItem('ffos_gcal_connected','1');setTimeout(gcalFetch,500);}}).catch(function(){localStorage.removeItem('ffos_gcal_token');localStorage.setItem('ffos_gcal_connected','0');gcalUpdateUI();renderGCalPrompt();});} setInterval(function(){var expiry=parseInt(localStorage.getItem('ffos_gcal_expiry')||'0');var token=localStorage.getItem('ffos_gcal_token');if(token&&expiry&&Date.now()>expiry)gcalSilentRefresh();},10*60*1000); function openVoiceAssistant(){const ov=document.getElementById('voice-assistant-overlay');if(ov)ov.classList.add('open');vaClear();} function closeVoiceAssistant(){const ov=document.getElementById('voice-assistant-overlay');if(ov)ov.classList.remove('open');vaStopMic();vaStopSpeaking();} function openVoiceDiary(){openVoiceAssistant();} function vaStatus(text,cls){const el=document.getElementById('va-status');if(!el)return;el.textContent=text;el.className='va-status'+(cls?' '+cls:'');} function vaWave(on){const wf=document.getElementById('va-waveform');if(wf)wf.classList.toggle('listening',on);const btn=document.getElementById('va-mic-btn');if(btn){btn.classList.remove('listening','speaking');if(on)btn.classList.add('listening');}} function vaClear(){const t=document.getElementById('va-transcript');const r=document.getElementById('va-response');const sb=document.getElementById('va-speak-btn');const ab=document.getElementById('va-response-actions');if(t)t.classList.remove('show');if(r)r.classList.remove('show');if(sb)sb.style.display='none';if(ab)ab.innerHTML='';vaStatus('Toque no microfone para falar','');vaStopSpeaking();const btn=document.getElementById('va-mic-btn');if(btn)btn.classList.remove('listening','speaking');vaWave(false);} function vaToggleMic(){_vaRecording?vaStopMic():vaStartMic();} async function vaStartMic(){const key=localStorage.getItem('ffos_groq_key');if(!key){toast('Configure a Groq API Key em Configurações.');return;}try{const stream=await navigator.mediaDevices.getUserMedia({audio:true});_vaChunks=[];_vaMediaRec=new MediaRecorder(stream,{mimeType:'audio/webm'});_vaMediaRec.ondataavailable=e=>{if(e.data.size>0)_vaChunks.push(e.data);};_vaMediaRec.onstop=async()=>{stream.getTracks().forEach(t=>t.stop());await vaProcessAudio(new Blob(_vaChunks,{type:'audio/webm'}));};_vaMediaRec.start();_vaRecording=true;vaWave(true);vaStatus('Ouvindo... toque para parar','listening');setTimeout(()=>{if(_vaRecording)vaStopMic();},30000);}catch(err){toast('Microfone não disponível.');}} function vaStopMic(){if(_vaMediaRec&&_vaRecording){_vaMediaRec.stop();_vaRecording=false;vaWave(false);vaStatus('Processando...','thinking');}} async function vaProcessAudio(blob){const key=localStorage.getItem('ffos_groq_key');vaStatus('Transcrevendo...','thinking');try{const fd=new FormData();fd.append('file',blob,'audio.webm');fd.append('model','whisper-large-v3');fd.append('language','pt');const tr=await fetch('https://api.groq.com/openai/v1/audio/transcriptions',{method:'POST',headers:{'Authorization':'Bearer '+key},body:fd});const td=await tr.json();const text=td.text||'';if(!text.trim()){vaStatus('Não entendi. Tente novamente.','');return;}const tEl=document.getElementById('va-transcript');const tTxt=document.getElementById('va-transcript-text');if(tEl)tEl.classList.add('show');if(tTxt)tTxt.textContent=text;vaStatus('Pensando...','thinking');await vaAskGroq(text,key);}catch(err){vaStatus('Erro ao processar.','');console.error(err);}} async function vaAskGroq(question,key){const todayStr=dk(today0());const cal=(_gcalEvents||[]).filter(ev=>dk(new Date(ev.start.dateTime||ev.start.date))===todayStr).map(ev=>(ev.start.dateTime?new Date(ev.start.dateTime).toLocaleTimeString('pt-BR',{hour:'2-digit',minute:'2-digit'}):'Dia todo')+' - '+(ev.summary||'')).join('; ');const tasks=getTasks().filter(t=>!t.done).slice(0,20).map(t=>t.name+(t.date?' ['+t.date+']':'')).join('; ');const routines=getRoutines().map(r=>r.name).join(', ');const projects=getProjects().filter(p=>p.status==='ativo').map(p=>p.name).join(', ');const sys='Você é o assistente pessoal de voz de Tiago, dono da Fast Fluent Idiomas no Rio de Janeiro. Hoje é '+todayStr+'. Agenda: '+(cal||'nenhum evento')+'. Tarefas: '+(tasks||'nenhuma')+'. Rotinas: '+(routines||'nenhuma')+'. Projetos: '+(projects||'nenhum')+'. Responda em português, de forma natural e concisa. Máximo 2 parágrafos.';try{const res=await fetch('https://api.groq.com/openai/v1/chat/completions',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+key},body:JSON.stringify({model:'llama-3.3-70b-versatile',max_tokens:250,messages:[{role:'system',content:sys},{role:'user',content:question}]})});const data=await res.json();const answer=data.choices&&data.choices[0]?data.choices[0].message.content:'';if(!answer){vaStatus('Sem resposta.','');return;}const rEl=document.getElementById('va-response');const rTxt=document.getElementById('va-response-text');const sb=document.getElementById('va-speak-btn');if(rEl)rEl.classList.add('show');if(rTxt)rTxt.textContent=answer;if(sb)sb.style.display='flex';vaCheckActions(question);vaStatus('Respondendo...','speaking');const btn=document.getElementById('va-mic-btn');if(btn){btn.classList.remove('listening');btn.classList.add('speaking');}await vaSpeak(answer);vaStatus('Toque para continuar','');if(btn)btn.classList.remove('speaking');}catch(err){vaStatus('Erro ao conectar com a IA.','');console.error(err);}} function vaSpeak(text){return new Promise(resolve=>{const synth=window.speechSynthesis;if(!synth||!text){resolve();return;}synth.cancel();const utt=new SpeechSynthesisUtterance(text);utt.lang='pt-BR';utt.rate=1.05;utt.pitch=1;const v=synth.getVoices().find(v=>v.lang.startsWith('pt'))||null;if(v)utt.voice=v;utt.onend=resolve;utt.onerror=resolve;synth.speak(utt);});} function vaStopSpeaking(){if(window.speechSynthesis)window.speechSynthesis.cancel();_vaSpeaking=false;} function vaCheckActions(question){const actEl=document.getElementById('va-response-actions');if(!actEl)return;const q=question.toLowerCase();let btns='';if(/adiciona|cria|criar|lembra|tarefa/i.test(q))btns+='';if(/nota|anota|salva|escreve/i.test(q))btns+='';actEl.innerHTML=btns;} function vaCreateTask(){const tTxt=document.getElementById('va-transcript-text');closeVoiceAssistant();setTimeout(()=>{openAddTask();setTimeout(()=>{const n=document.getElementById('t-name');if(n&&tTxt)n.value=tTxt.textContent;},150);},300);} function vaCreateNote(){const rTxt=document.getElementById('va-response-text');closeVoiceAssistant();setTimeout(()=>{openNoteEditor(null,'nota');setTimeout(()=>{const c=document.getElementById('note-editor-content');if(c&&rTxt)c.innerHTML='

'+escHtml(rTxt.textContent)+'

';},200);},300);} let _dpField=null,_dpYear=0,_dpMonth=0; const _dpMonths=['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro']; function dpOpen(fieldId,triggerEl){_dpField=fieldId;const popup=document.getElementById('dp-popup');const backdrop=document.getElementById('dp-backdrop');if(!popup)return;const input=document.getElementById(fieldId);const val=input?input.value:'';const now=val?new Date(val+'T12:00:00'):new Date();_dpYear=now.getFullYear();_dpMonth=now.getMonth();const rect=triggerEl.getBoundingClientRect();const spaceBelow=window.innerHeight-rect.bottom;popup.style.display='block';popup.style.left=Math.min(rect.left,window.innerWidth-280)+'px';if(spaceBelow>300){popup.style.top=(rect.bottom+6)+'px';popup.style.bottom='auto';}else{popup.style.bottom=(window.innerHeight-rect.top+6)+'px';popup.style.top='auto';}if(backdrop)backdrop.style.display='block';triggerEl.classList.add('open');dpRender();} function dpClose(){const popup=document.getElementById('dp-popup');const backdrop=document.getElementById('dp-backdrop');if(popup)popup.style.display='none';if(backdrop)backdrop.style.display='none';document.querySelectorAll('.dp-input.open').forEach(el=>el.classList.remove('open'));} function dpRender(){const label=document.getElementById('dp-month-label');const daysEl=document.getElementById('dp-days');if(!label||!daysEl)return;label.textContent=_dpMonths[_dpMonth]+' '+_dpYear;const todayStr=dk(today0());const curVal=_dpField?(document.getElementById(_dpField)||{}).value||'':'';const firstDay=new Date(_dpYear,_dpMonth,1).getDay();const daysInMonth=new Date(_dpYear,_dpMonth+1,0).getDate();let h='';for(let i=0;i';for(let d=1;d<=daysInMonth;d++){const ds=_dpYear+'-'+String(_dpMonth+1).padStart(2,'0')+'-'+String(d).padStart(2,'0');let cls='dp-day';if(ds===todayStr)cls+=' dp-day-today';if(ds===curVal)cls+=' dp-day-selected';h+='';}daysEl.innerHTML=h;} function dpPrevMonth(){_dpMonth--;if(_dpMonth<0){_dpMonth=11;_dpYear--;}dpRender();} function dpNextMonth(){_dpMonth++;if(_dpMonth>11){_dpMonth=0;_dpYear++;}dpRender();} function dpSelect(dateStr){if(!_dpField)return;const input=document.getElementById(_dpField);if(input)input.value=dateStr;const display=document.getElementById(_dpField+'-display');if(display){const d=new Date(dateStr+'T12:00:00');display.textContent=d.toLocaleDateString('pt-BR',{day:'2-digit',month:'short',year:'numeric'});display.style.color='var(--text)';}dpClose();} function dpSelectToday(){dpSelect(dk(today0()));} function dpClear(){dpClearField(_dpField);dpClose();} function dpClearField(fieldId){const input=document.getElementById(fieldId);if(input)input.value='';const display=document.getElementById(fieldId+'-display');if(display){display.textContent='Selecionar data';display.style.color='var(--text3)';}}