Índice · ve a donde quierasToca un tema o un número de escena. Lo que ya viste sale en verde.
🔄 Tip: para ver las diapositivas más grandes, gira el teléfono de lado.
🔊 Sube el volumen. La voz sale de tu aparato: en Microsoft Edge o Chrome suena más natural. Usa el botón “Voz” para escoger la que más te guste.
🎙 Escoge la voz
La voz sale de tu navegador y es distinta en cada aparato. Prueba y quédate con la que suene más natural (busca las que dicen Natural, Online, Premium o Google).
';$('#stage').appendChild(el);cEl=el;$('#who').textContent=COACH_NAMES[v]||'';$('#mini').style.backgroundImage='url(data:image/webp;base64,'+d[0]+')';sizeCoach()}
function sizeCoach(){if(!cEl)return;var s=$('#stage'),h=s.clientHeight,w=s.clientWidth,d=CD[cur],ar=d[1]/d[2];if(h<40||w<40)return;var H=Math.min(h-10,(w-10)/ar);if(document.documentElement.classList.contains('port'))H=Math.min(H,380);cEl.style.height=H+'px';cEl.style.width=(H*ar)+'px'}
var talking=false,tick=0;
function mouthAnim(on){talking=on;if(!on){var b=$('#wave').children;for(var k=0;k
'}).join('');
$('#sKick').textContent=CFG.kick;$('#sTitle').innerHTML=CFG.titleHtml;$('#sDesc').textContent=CFG.desc;$('#eTitle').innerHTML=CFG.endHtml;
/* ---------- diapositivas ---------- */
var deck=$('#deck'),deckReady=false;
deck.srcdoc=unesc($('#deckSrc').textContent);
deck.onload=function(){deckReady=true;try{var d=deck.contentDocument,st=d.createElement('style');st.textContent='#nav,.hint{display:none!important}';d.head.appendChild(st)}catch(e){}};
var SMALL=false;
function fit(){var vw=innerWidth,vh=innerHeight,R=document.documentElement,port=vw<=vh,short=!port&&vh<520;SMALL=port||short;
var ap=R.classList.contains('ap');
R.classList.toggle('port',port);R.classList.toggle('short',short);R.classList.toggle('sm',SMALL);
var bh=170,cw=Math.min(vw*.22,Math.max(230,(vh-170)*.36));
if(port){bh=vw<600?196:Math.round(Math.min(250,vw*.3));cw=0}else if(short){bh=70;cw=Math.min(vw*.16,150)}
R.style.setProperty('--bh',bh+'px');R.style.setProperty('--cw',cw+'px');
var T=$('#top'),w=T.clientWidth,h=T.clientHeight,s=Math.min(w/16,h/9);deck.style.width=(16*s)+'px';deck.style.height=(9*s)+'px';deck.style.left=((w-16*s)/2)+'px';deck.style.top=((h-9*s)/2)+'px';fitApps();sizeCoach()}
/* ---------- apps reales ---------- */
var APPF={made:false,p:null,t:null,ready:{p:!CFG.needs.p,t:!CFG.needs.t},pd:null,td:null};
function mkApps(){if(APPF.made)return;APPF.made=true;['p','t'].forEach(function(k){if(!CFG.needs[k])return;var d=document.createElement('div');d.className='dev '+(k==='p'?'ph':'tab');var f=document.createElement('iframe');f.onload=function(){APPF.ready[k]=true};inflB64($('#app_'+k).textContent).then(function(x){f.srcdoc=unesc(x)});d.appendChild(f);$('#appsStage').appendChild(d);APPF[k]=f;APPF[k+'d']=d});
['p','t'].forEach(function(k){if(!APPF[k+'d']){APPF[k+'d']=document.createElement('div');APPF[k+'d'].style.display='none'}})}
function fitApps(){var T=$('#top'),w=T.clientWidth,h=T.clientHeight,st=$('#appsStage');
if(!SMALL){var s=Math.min(w/1600,h/900);st.style.width='1600px';st.style.height='900px';st.style.transform='scale('+s+')';st.style.left=((w-1600*s)/2)+'px';st.style.top=((h-900*s)/2)+'px';if(APPF.made&&APPF.mode)deskPlace();return}
st.style.width=w+'px';st.style.height=h+'px';st.style.transform='none';st.style.left='0px';st.style.top='0px';if(APPF.made&&APPF.mode)smallPlace(w,h)}
function placeDev(d,x,y,sc){d.style.display='block';d.style.left=x+'px';d.style.top=y+'px';d.style.transform='scale('+sc+')'}
function deskPlace(){var m=APPF.mode;APPF.pd.style.display=APPF.td.style.display='none';
if(m==='p')placeDev(APPF.pd,1030,96,.925);else if(m==='t')placeDev(APPF.td,(1600-1452*.86)/2,98,.86);else{placeDev(APPF.td,16,120,.8);placeDev(APPF.pd,1196,96,.925)}}
function smallPlace(w,h){var m=APPF.mode,pd=APPF.pd,td=APPF.td,PW=402,PH=856,TW=1452,TH=924,g=10;pd.style.display=td.style.display='none';
if(m==='p'){var s=Math.min((w-8)/PW,(h-8)/PH);placeDev(pd,(w-PW*s)/2,(h-PH*s)/2,s)}
else if(m==='t'){var s=Math.min((w-8)/TW,(h-8)/TH);placeDev(td,(w-TW*s)/2,(h-TH*s)/2,s)}
else if(w>h){var s=Math.min((w-8-g)/(TW+PW),(h-8)/TH);var x0=(w-(TW+PW)*s-g)/2;placeDev(td,x0,(h-TH*s)/2,s);placeDev(pd,x0+TW*s+g,(h-PH*s)/2,s)}
else{var sT=(w-8)/TW,hT=TH*sT,sP=Math.max(.15,Math.min((h-hT-8-g)/PH,(w-8)/PW)),y0=Math.max(2,(h-hT-PH*sP-g)/2);placeDev(td,(w-TW*sT)/2,y0,sT);placeDev(pd,(w-PW*sP)/2,y0+hT+g,sP)}}
function showApp(a){mkApps();document.documentElement.classList.add('ap');$('#apps').classList.add('on');$('#appKick').textContent=a.kick||'';$('#appTitle').innerHTML=a.title||'';APPF.mode=a.mode||'b';
var sd=$('#appSide');sd.innerHTML='';sd.style.display='none';
if(a.mode==='p'&&a.side){sd.style.display='block';sd.innerHTML=a.side.map(function(x){return '
'+x[0]+''+x[1]+'
'}).join('')}
fit()}
function hl(n){$$('#appSide .sc').forEach(function(e,i){e.classList.toggle('hl',i===n)})}
function hideApp(){if(!$('#apps').classList.contains('on'))return;$('#apps').classList.remove('on');document.documentElement.classList.remove('ap');APPF.mode=null;fit()}
function appRun(k,js){var f=APPF[k];if(!f||!f.contentWindow)return Promise.resolve();try{return Promise.resolve(f.contentWindow.eval(js))}catch(e){console.warn('app',k,e);return Promise.resolve()}}
function wait(ms){return new Promise(function(r){setTimeout(r,ms)})}
async function initScene(e,my){var a=e.app;showApp(a);var t0=Date.now();$('#appLoad').style.display='block';
while(!(APPF.ready.p&&APPF.ready.t)&&Date.now()-t0<40000){await wait(150);if(token!==my)return}
$('#appLoad').style.display='none';
await wait(300);for(var i=0;i<(a.init||[]).length;i++){if(token!==my)return;await appRun(a.init[i][0],a.init[i][1]);await wait(a.init[i][2]||200)}}
/* ---------- voz ---------- */
var FAST=+((location.search.match(/fast=(\d+)/)||[0,1])[1])||1;var hasTTS='speechSynthesis' in window,VOICES=[],picked=ls('fcva_voice'),spd=1,muted=false;
function loadV(){if(!hasTTS)return;VOICES=speechSynthesis.getVoices().filter(function(v){return /^es/i.test(v.lang)||/spanish|español/i.test(v.name)});renderVL()}
if(hasTTS){loadV();speechSynthesis.onvoiceschanged=loadV}
function score(v){var s=0,l=v.lang.replace('_','-'),n=v.name;
if(/es-PR/i.test(l))s+=60;else if(/es-US/i.test(l))s+=48;else if(/es-MX/i.test(l))s+=44;else if(/es-419|es-CO|es-VE|es-CU|es-DO/i.test(l))s+=40;else if(/es-AR|es-CL|es-PE|es-UY|es-EC|es-BO|es-PY|es-GT|es-HN|es-SV|es-NI|es-CR|es-PA/i.test(l))s+=30;else if(/es-ES/i.test(l))s+=12;
if(/natural|neural/i.test(n))s+=120;if(/online/i.test(n))s+=60;if(/premium|enhanced|mejorad/i.test(n))s+=80;if(/siri/i.test(n))s+=70;if(/google/i.test(n))s+=45;
if(/espeak|compact|festival|mbrola/i.test(n))s-=80;if(v.localService===false)s+=10;return s}
function bestVoice(){if(!VOICES.length)return null;if(picked){var p=VOICES.filter(function(v){return v.name===picked})[0];if(p)return p}return VOICES.slice().sort(function(a,b){return score(b)-score(a)})[0]}
function renderVL(){var L=$('#vlist');if(!L)return;if(!VOICES.length){L.innerHTML='
Este aparato no tiene voces en español. Puedes ver la presentación leyendo los subtítulos.
';return}
var b=bestVoice();L.innerHTML=VOICES.slice().sort(function(a,c){return score(c)-score(a)}).map(function(v,i){return '
'+v.name+' ('+v.lang+')
'}).join('');
$$('#vlist [data-t]').forEach(function(x){x.onclick=function(){var v=VOICES.filter(function(q){return q.name===x.getAttribute('data-n')})[0];try{speechSynthesis.cancel()}catch(e){}var u=new SpeechSynthesisUtterance('Hola, familia Fusion Control. Así suena esta voz. ¿Te gusta?');u.voice=v;u.lang=v.lang;speechSynthesis.speak(u)}});
$$('#vlist [data-u]').forEach(function(x){x.onclick=function(){picked=x.getAttribute('data-u');ls('fcva_voice',picked);renderVL()}});
$('#vtip').innerHTML='Voz en uso: '+(b?b.name:'—')+'. Consejo: en Mac, ve a Ajustes → Accesibilidad → Contenido hablado → Voz del sistema → Gestionar voces, y baja una voz en español “Premium”; en Windows, usa Microsoft Edge.'}
function openVB(){renderVL();$('#vbox').classList.add('on')}
$('#bVoice').onclick=openVB;$('#goPick').onclick=openVB;$('#vclose').onclick=function(){$('#vbox').classList.remove('on');try{speechSynthesis.cancel()}catch(e){}};
function chunks(t){var S=t.split(/(?<=[.!?:;])\s+/).filter(Boolean),out=[],c='';S.forEach(function(s){if((c+' '+s).length>200&&c){out.push(c);c=s}else c=c?c+' '+s:s});if(c)out.push(c);return out}
var PRON=[[/\bcoaches\b/gi,'cóuches'],[/\bcoach\b/gi,'cóuch'],[/\bkills\b/gi,'quils'],[/\bkill\b/gi,'quil'],[/\baces\b/gi,'éises'],[/\bace\b/gi,'éis'],[/\btablet\b/gi,'táblet'],[/\bPDF\b/g,'pe de efe'],[/\bFusion\b/g,'Fiúshon'],[/\bset\b/gi,'set']];
function say(t){PRON.forEach(function(r){t=t.replace(r[0],r[1])});return t}
function speak(text,e,done){var v=bestVoice(),C=chunks(text),i=0;function nx(){if(i>=C.length){done();return}var u=new SpeechSynthesisUtterance(say(C[i++]));if(v){u.voice=v;u.lang=v.lang}else u.lang='es-US';u.rate=spd*1.0;u.pitch=1;u.onend=nx;u.onerror=function(){done()};speechSynthesis.speak(u)}nx()}
/* ---------- reproductor ---------- */
var idx=0,playing=false,token=0,timers=[],visited={};
function clearT(){timers.forEach(clearTimeout);timers=[]}
function present(e,my){if(e.app){$('#deck').classList.remove('on');return initScene(e,my)}hideApp();$('#deck').classList.add('on');try{deck.contentWindow.__show(e.s)}catch(x){}return Promise.resolve()}
function clickD(sel){try{var d=deck.contentDocument,m=sel.split(' >> '),els=d.querySelectorAll(m[0]),el=els[m[1]?+m[1]:0];if(el)el.click()}catch(x){}}
function segAct(sg,my){if(!sg)return;if(sg.h!==undefined)hl(sg.h);['P','T'].forEach(function(kk){if(sg[kk]){var js=sg[kk];timers.push(setTimeout(function(){if(token===my)appRun(kk.toLowerCase(),js)},sg.d||0))}});(sg.D||[]).forEach(function(sel,j){timers.push(setTimeout(function(){if(token===my)clickD(sel)},(sg.d||0)+j*1100))})}
function play(i,from){
if(i<0)i=0;if(i>=SCRIPT.length){finish();return}
idx=i;token++;var my=token;clearT();try{speechSynthesis.cancel()}catch(x){}
var e=SCRIPT[i];visited[i]=1;setCoach(e.v);$('#cnt').textContent=(i+1)+' / '+SCRIPT.length;$('#prog i').style.width=((i+1)/SCRIPT.length*100)+'%';playing=true;$('#bPlay').textContent='⏸';
var segs=e.segs,k=from||0;
function after(){if(token!==my)return;mouthAnim(false);timers.push(setTimeout(function(){if(token===my&&playing)play(i+1)},muted||!hasTTS?300:700))}
function next(){
if(token!==my)return;if(k>=segs.length){after();return}
var sg=segs[k],s=sg.t;k++;$('#sub').textContent=s;segAct(sg,my);var w=sg.w||0;
function fin(){if(token!==my)return;mouthAnim(false);if(w)timers.push(setTimeout(next,w));else next()}
if(muted||!hasTTS||!VOICES.length){mouthAnim(true);timers.push(setTimeout(fin,Math.max(1200/FAST,s.length/15*1000/spd/FAST)));return}
mouthAnim(true);speak(s,e,function(){if(token===my)fin()})}
present(e,my).then(function(){if(token===my)next()})}
function finish(){playing=false;mouthAnim(false);if(CFG.sign){openSign()}else $('#end').classList.add('on')}
function closeSignX(){$('#sign').classList.remove('on');$('#end').classList.add('on');$('#reSign').style.display=CFG.sign&&!lastSaved?'inline-block':'none'}
function pause(){playing=false;token++;clearT();try{speechSynthesis.cancel()}catch(x){}mouthAnim(false);$('#bPlay').textContent='▶'}
function peek(){var e=SCRIPT[idx];setCoach(e.v);token++;present(e,token);$('#sub').textContent=e.segs.map(function(x){return x.t}).join(' ');$('#cnt').textContent=(idx+1)+' / '+SCRIPT.length}
$('#bPlay').onclick=function(){playing?pause():play(idx)};
$('#bNext').onclick=function(){var w=playing;pause();idx=Math.min(SCRIPT.length-1,idx+1);if(w)play(idx);else peek()};
$('#bPrev').onclick=function(){var w=playing;pause();idx=Math.max(0,idx-1);if(w)play(idx);else peek()};
$('#bMute').onclick=function(){muted=!muted;this.textContent=muted?'🔇':'🔊';if(playing)play(idx)};
$('#bSpd').onclick=function(){spd=spd===1?1.12:spd===1.12?.9:1;this.textContent='Velocidad '+spd+'×';if(playing)play(idx)};
$('#chap').innerHTML=CFG.chapters.map(function(c,i){return ''}).join('');
$$('[data-c]').forEach(function(b){b.onclick=function(){$('#end').classList.remove('on');$('#sign').classList.remove('on');play(+b.getAttribute('data-c'))}});
/* ---------- índice ---------- */
function buildIdx(){var C=CFG.chapters.slice().sort(function(a,b){return a.i-b.i}),h='';if(!C.length||C[0].i>0)C.unshift({i:0,n:'Inicio'});
C.forEach(function(c,k){var a=c.i,b=(C[k+1]?C[k+1].i:SCRIPT.length),n=b-a,vis=0,cur=idx>=a&&idx'+(j-a+1)+'';
h+='
'});
$('#idxL').innerHTML=h;
$$('#idxL [data-g]').forEach(function(el){el.onclick=function(ev){ev.stopPropagation();var g=+el.getAttribute('data-g');closeIdx();$('#end').classList.remove('on');$('#sign').classList.remove('on');play(g)}})}
function openIdx(){buildIdx();$('#idx').classList.add('on');var c=$('#idxL .cur');if(c&&c.scrollIntoView)try{c.scrollIntoView({block:'nearest'})}catch(e){}}
function closeIdx(){$('#idx').classList.remove('on')}
$('#bIdx').onclick=function(){$('#idx').classList.contains('on')?closeIdx():openIdx()};$('#idxX').onclick=closeIdx;
$('#idx').onclick=function(e){if(e.target===$('#idx'))closeIdx()};
addEventListener('keydown',function(e){if(e.key==='Escape')closeIdx()});
$('#prog').onclick=function(ev){var i=Math.floor(ev.offsetX/this.clientWidth*SCRIPT.length);$('#end').classList.remove('on');play(i)};
function go(sil,pick){$('#start').style.display='none';muted=!!sil;$('#bMute').textContent=muted?'🔇':'🔊';if(hasTTS){try{speechSynthesis.getVoices();var u=new SpeechSynthesisUtterance(' ');u.volume=0;speechSynthesis.speak(u)}catch(x){}}
var t=setInterval(function(){if(deckReady){clearInterval(t);play(0);setTimeout(mkApps,CFG.needsAny?2500:0)}},150)}
$('#goVoice').onclick=function(){go(false)};$('#goSilent').onclick=function(){go(true)};
$('#again').onclick=function(){$('#end').classList.remove('on');visited={};play(0)};
addEventListener('resize',fit);addEventListener('orientationchange',function(){setTimeout(fit,250)});fit();setCoach(0);
/* ---------- firma de asistencia ---------- */
var FBCFG={apiKey:"AIzaSyACOR2Qr9o_V66-JGrOfq-fYVTIJVwwDR4",authDomain:"fusion-control-volleyball.firebaseapp.com",projectId:"fusion-control-volleyball",storageBucket:"fusion-control-volleyball.firebasestorage.app",messagingSenderId:"651688559378",appId:"1:651688559378:web:f92574ff243392bd5129cb"};
var TEAMS=[['u16f','16U Femenino'],['u17m','17U Masculino'],['u17f','17U Femenino'],['u18m','U18 Masculino']],PICK=!!CFG.pick,selAth=null,fdb=null;
function getDb(){if(fdb)return Promise.resolve(fdb);return loadJs('https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js').then(function(){return loadJs('https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore-compat.js')}).then(function(){if(!firebase.apps.length)firebase.initializeApp(FBCFG);fdb=firebase.firestore();return fdb})}
function esc2(t){return String(t||'').replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c]})}
var QA=(location.search.match(/[?&]a=([^&]+)/)||[])[1];QA=QA?decodeURIComponent(QA):'';var TL={u16f:'16U Femenino',u17m:'17U Masculino',u17f:'17U Femenino',u18m:'U18 Masculino'};
function preload(){if(!QA)return;$('#sgWho').innerHTML='
'+(PICK?'FIRMA EL ATLETA':'FIRMA EN NOMBRE DE LA FAMILIA DE')+'
'+esc2(nm)+'
'+esc2(tm)+'
'}).catch(function(e){console.warn('preload',e);$('#sgWho').innerHTML=''})}
function pickTeam(key){selAth=null;var g=$('#sgGrid');if(!key){g.innerHTML='Primero escoge el equipo.';return}g.innerHTML='Cargando atletas…';getDb().then(function(db){return db.collection('athletes').where('team','==',key).get()}).then(function(q){if($('#sgTeam').value!==key)return;var L=q.docs.map(function(d){return d.data()}).filter(function(a){return a.playerName&&!a.notFound}).sort(function(a,b){var x=a.jerseyNumber===undefined||a.jerseyNumber===''||a.jerseyNumber===null?999:+a.jerseyNumber,y=b.jerseyNumber===undefined||b.jerseyNumber===''||b.jerseyNumber===null?999:+b.jerseyNumber;return x-y||String(a.playerName).localeCompare(b.playerName)});
if(!L.length){g.innerHTML='No encontré atletas en este equipo.';$('#sgManual').style.display='block';return}
g.innerHTML=L.map(function(a,i){var ini=String(a.playerName).split(' ').slice(0,2).map(function(w){return w[0]}).join('').toUpperCase();return ''}).join('')+'';
$$('#sgGrid .sga').forEach(function(b){b.onclick=function(){$$('#sgGrid .sga').forEach(function(x){x.classList.remove('on')});b.classList.add('on');var i=+b.getAttribute('data-i');if(i<0){selAth=null;$('#sgManual').style.display='block'}else{selAth={id:L[i].athleteId||'',name:L[i].playerName};$('#sgManual').style.display='none'}}})}).catch(function(e){console.warn('atletas',e);g.innerHTML='No se pudo cargar la lista. Escribe el nombre abajo.';$('#sgManual').style.display='block'})}
var sigDirty=false,lastSaved=null;
function loadJs(u){return new Promise(function(res,rej){var s=document.createElement('script');s.src=u;s.onload=res;s.onerror=function(){rej(new Error('load '+u))};document.head.appendChild(s)})}
function openSign(){var vis=Object.keys(visited).length,pct=Math.round(vis/SCRIPT.length*100);var box=$('#signBox');$('#sign').classList.add('on');if(!$('#signX')){var xb=document.createElement('button');xb.id='signX';xb.className='xbtn';xb.style.zIndex=95;xb.textContent='✕ Cerrar';xb.onclick=function(){if(lastSaved)exitP();else closeSignX()};$('#sign').appendChild(xb)}
if(pct<90){box.innerHTML='
Casi terminas
Para que cuente tu asistencia necesitas ver la presentación completa. Te faltan algunas partes ('+(100-pct)+'%).
';$('#sgBack').onclick=function(){$('#sign').classList.remove('on');var m=0;for(var i=0;i'+CFG.partName+'. Esta firma confirma que viste la presentación completa y cuenta como '+(PICK?'tu asistencia a la reunión de atletas.':'tu asistencia a la reunión.')+''+
(PICK?'':'')+
'
'+''+
'
Primero escoge el equipo.
'+
''+'
'+
''+
''+
''+
'';
initCanvas();$('#sgTeam').onchange=function(){pickTeam(this.value)};$('#sgSend').onclick=submitSign;preload()}
function initCanvas(){var c=$('#sigc'),x=c.getContext('2d');x.fillStyle='#fff';x.fillRect(0,0,c.width,c.height);x.lineWidth=4;x.lineCap='round';x.lineJoin='round';x.strokeStyle='#111';var d=false,lx=0,ly=0;sigDirty=false;
function pos(ev){var r=c.getBoundingClientRect();return [(ev.clientX-r.left)*c.width/r.width,(ev.clientY-r.top)*c.height/r.height]}
c.onpointerdown=function(ev){d=true;var p=pos(ev);lx=p[0];ly=p[1];try{c.setPointerCapture(ev.pointerId)}catch(e){}x.beginPath();x.arc(lx,ly,2,0,7);x.fillStyle='#111';x.fill();sigDirty=true;ev.preventDefault()};
c.onpointermove=function(ev){if(!d)return;var p=pos(ev);x.beginPath();x.moveTo(lx,ly);x.lineTo(p[0],p[1]);x.stroke();lx=p[0];ly=p[1];ev.preventDefault()};
c.onpointerup=c.onpointercancel=function(){d=false};
$('#sgClear').onclick=function(){x.fillStyle='#fff';x.fillRect(0,0,c.width,c.height);sigDirty=false}}
function msg(t,c){var m=$('#sgMsg');m.className='msg '+(c||'');m.innerHTML=t}
function sigPng(){var c=$('#sigc'),o=document.createElement('canvas');o.width=360;o.height=114;var x=o.getContext('2d');x.fillStyle='#fff';x.fillRect(0,0,o.width,o.height);x.drawImage(c,0,0,o.width,o.height);return o.toDataURL('image/png')}
function constancia(rec){var W=1100,H=700,c=document.createElement('canvas');c.width=W;c.height=H;var x=c.getContext('2d');x.fillStyle='#fff';x.fillRect(0,0,W,H);x.fillStyle='#f769a2';x.fillRect(0,0,W,18);x.fillStyle='#00b9f2';x.fillRect(0,18,W,8);x.strokeStyle='#111';x.lineWidth=3;x.strokeRect(24,44,W-48,H-72);
x.fillStyle='#111';x.textAlign='center';x.font='900 30px Arial';x.fillText('FUSION CONTROL VOLLEYBALL ACADEMY',W/2,100);x.font='700 36px Arial';x.fillStyle='#d6407f';x.fillText('Constancia de asistencia',W/2,152);x.fillStyle='#111';x.font='22px Arial';x.fillText((rec.role==='atleta'?'Reunión con atletas':'Reunión de padres')+' · Temporada 2026-2027',W/2,190);
x.textAlign='left';x.font='20px Arial';var L=[[rec.role==='atleta'?'Atleta':'Padre / madre / encargado',rec.parentName],['Atleta',rec.athleteName+' · '+rec.team],['Presentación vista',rec.deckTitle],['Fecha y hora',rec.when]];L.forEach(function(r,i){var y=250+i*66;x.fillStyle='#666';x.font='16px Arial';x.fillText(r[0].toUpperCase(),80,y);x.fillStyle='#111';x.font='700 26px Arial';x.fillText(r[1],80,y+32)});
var im=new Image();im.src=rec.signaturePng;return new Promise(function(res){im.onload=function(){x.drawImage(im,700,470,300,95);x.strokeStyle='#111';x.beginPath();x.moveTo(690,575);x.lineTo(1010,575);x.stroke();x.fillStyle='#666';x.font='15px Arial';x.fillText('Firma',690,598);x.font='700 17px Arial';x.fillStyle='#111';x.fillText('Código: '+rec.code,80,H-50);res(c)};im.onerror=function(){res(c)}})}
function dlConst(rec){constancia(rec).then(function(c){c.toBlob(function(b){var u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download='constancia_FCVA_'+rec.code+'.png';document.body.appendChild(a);a.click();a.remove();setTimeout(function(){URL.revokeObjectURL(u)},3000)})})}
function submitSign(){var n=PICK?'':$('#sgName').value.trim(),a=selAth?selAth.name:$('#sgAth').value.trim(),tk=$('#sgTeam').value,t=selAth&&selAth.teamLabel?selAth.teamLabel:(tk?$('#sgTeam').options[$('#sgTeam').selectedIndex].text:''),ct=$('#sgContact').value.trim();
if(!PICK&&n.length<3)return msg('Escribe tu nombre completo.','er');if(!t)return msg('Escoge el equipo.','er');if(PICK&&!selAth)return msg('Toca tu foto.','er');if(a.length<3)return msg(PICK?'Toca tu foto.':'Toca la foto del atleta.','er');if(PICK)n=a;if(!sigDirty)return msg('Falta tu firma.','er');if(!$('#sgOk').checked)return msg('Marca la casilla de confirmación.','er');
var code=(Math.random().toString(36).slice(2,6)+Date.now().toString(36).slice(-4)).toUpperCase(),now=new Date();
var rec={code:code,reunion:PICK?'atletas-2026-2027':'padres-2026-2027',deck:CFG.deck,deckTitle:CFG.partName,parentName:n,athleteName:a,athleteId:selAth?selAth.id:'',role:PICK?'atleta':'familia',team:t,contact:ct,signaturePng:sigPng(),visitedPct:Math.round(Object.keys(visited).length/SCRIPT.length*100),ua:(navigator.userAgent||'').slice(0,120),when:now.toLocaleString('es-PR',{dateStyle:'long',timeStyle:'short'}),clientTs:now.getTime()};
$('#sgSend').disabled=true;msg('Enviando tu firma…');
loadJs('https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js').then(function(){return loadJs('https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore-compat.js')}).then(function(){
if(!firebase.apps.length)firebase.initializeApp(FBCFG);var db=firebase.firestore();var d=Object.assign({},rec);d.createdAt=firebase.firestore.FieldValue.serverTimestamp();var aid=selAth&&selAth.id?selAth.id:'',b=db.batch();b.set(db.collection('reunion_firmas').doc('d'+CFG.deck+'_'+(aid||code)),d);
if(aid){b.set(db.collection('reunion_asistencia').doc('d'+CFG.deck+'_'+aid),{athleteId:aid,athleteName:a,team:t,deck:CFG.deck,deckTitle:CFG.partName,status:'presente',role:rec.role,signedBy:n,when:rec.when,clientTs:rec.clientTs,reunion:rec.reunion,createdAt:firebase.firestore.FieldValue.serverTimestamp()})}
return b.commit()})
.then(function(){lastSaved=rec;ls('fcva_firma_'+CFG.deck,code);done(rec,true)})
.catch(function(err){console.warn('firma',err);$('#sgSend').disabled=false;fallback(rec,err)})}
function done(rec,ok){$('#signBox').innerHTML='
✅
¡Firma recibida!
Gracias, '+rec.parentName+'. Tu asistencia a esta parte de la reunión quedó registrada. Código de confirmación: '+rec.code+'
'+(CFG.deck===4?'¡Gracias por estar en la reunión de atletas!':CFG.deck<3?'Recuerda ver también las otras presentaciones de la reunión y firmar en cada una.':'Si ya viste las 3 presentaciones y firmaste en cada una, ¡quedaste completo!')+'
';
$('#sgDl').onclick=function(){dlConst(rec)};$('#sgAgain').onclick=function(){$('#sign').classList.remove('on');visited={};play(0)}}
function fallback(rec,err){var sub=encodeURIComponent('Asistencia reunión de padres · '+CFG.partName+' · '+rec.athleteName),body=encodeURIComponent('Vi la presentación completa: '+CFG.partName+'\nPadre/madre/encargado: '+rec.parentName+'\nAtleta: '+rec.athleteName+'\nEquipo: '+rec.team+'\nContacto: '+rec.contact+'\nFecha: '+rec.when+'\nCódigo: '+rec.code);
msg('No se pudo enviar la firma automáticamente (puede ser la conexión). No te preocupes: guarda tu constancia y envíala por correo para que cuente.