function workMetrics(work,moneyCents=0,distanceMeters=0,now=Date.now()){
  if(!work)return {workedMs:0,pausedMs:0,incomeCents:moneyCents,distanceMeters,averagePerHour:0,averagePerKm:distanceMeters?moneyCents/100/(distanceMeters/1000):0,status:'Pronto para iniciar'};
  const end=work.endedAt??now;
  const pausedMs=work.pauses.reduce((sum,p)=>sum+Math.max(0,Math.min(p.end??end,end)-Math.max(p.start,work.startedAt)),0);
  const workedMs=Math.max(0,end-work.startedAt-pausedMs);
  const incomeCents=work.endedAt!==null?work.finalIncomeCents:moneyCents,meters=work.endedAt!==null?work.finalDistanceMeters:distanceMeters;
  return {workedMs,pausedMs,incomeCents,distanceMeters:meters,averagePerHour:workedMs?incomeCents/100/(workedMs/3600000):0,averagePerKm:meters?incomeCents/100/(meters/1000):0,status:work.endedAt!==null?'Terminado':work.pauses.at(-1)?.end===null?'Em pausa':'A trabalhar'};
}
function lisbonStartTime(arg,work,now){
  const match=arg.match(/^(?:(\d{4}-\d{2}-\d{2})\s+)?([01]?\d|2[0-3]):([0-5]\d)$/);
  if(!match)throw Error('Usa !inicio HH:MM ou !inicio AAAA-MM-DD HH:MM.');
  const parts=new Intl.DateTimeFormat('en-CA',{timeZone:'Europe/Lisbon',year:'numeric',month:'2-digit',day:'2-digit'}).formatToParts(new Date(work.startedAt));
  const get=k=>parts.find(p=>p.type===k).value,day=match[1]||`${get('year')}-${get('month')}-${get('day')}`;
  const hour=match[2].padStart(2,'0');
  const utc=Date.parse(`${day}T${hour}:${match[3]}:00Z`);
  const candidates=[utc,utc-3600000].filter(ts=>{
    if(!Number.isFinite(ts)||ts>(work.endedAt??now))return false;
    const f=new Intl.DateTimeFormat('en-GB',{timeZone:'Europe/Lisbon',year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit',hourCycle:'h23'}).formatToParts(new Date(ts));
    const value=key=>f.find(p=>p.type===key)?.value;
    return `${value('year')}-${value('month')}-${value('day')}`===day&&value('hour')===hour&&value('minute')===match[3];
  });
  if(!candidates.length)throw Error('A hora de início é inválida ou está no futuro.');
  return Math.max(...candidates);
}
function applyWorkCommand(work,raw,moneyCents,distanceMeters,now=Date.now(),id='work-'+now){
  const normalized=String(raw).normalize('NFD').replace(/[\u0300-\u036f]/g,'').trim();
  const m=normalized.match(/^!(trabalho|p|fim|terminar|inicio|incio|km)(?:\s+(.+))?$/i);
  if(!m)return null;
  const command=m[1].toLowerCase()==='incio'?'inicio':m[1].toLowerCase()==='terminar'?'fim':m[1].toLowerCase(),arg=(m[2]||'').trim();
  let next=work?JSON.parse(JSON.stringify(work)):null,meters=distanceMeters;
  if(command==='km'){
    if(!/^[+-]?\d+(?:[.,]\d{1,3})?$/.test(arg))throw Error('Usa !km 150 ou !km +10.');
    const n=Math.round(Number(arg.replace(',','.'))*1000);
    meters=/^[+-]/.test(arg)?meters+n:n;
    if(!Number.isSafeInteger(meters)||meters<0||meters>1000000000)throw Error('Quilómetros inválidos.');
    if(next?.endedAt!==null&&next)throw Error('O dia está terminado. Inicia um novo dia para alterar os quilómetros.');
  }else if(command==='trabalho'){
    if(arg)throw Error('Usa !inicio HH:MM para corrigir o início.');
    if(!next||next.endedAt!==null)next={id,startedAt:now,endedAt:null,pauses:[],finalIncomeCents:null,finalDistanceMeters:null};
    else if(next.pauses.at(-1)?.end===null)next.pauses.at(-1).end=now;
  }else{
    if(!next&&command==='inicio')next={id,startedAt:now,endedAt:null,pauses:[],finalIncomeCents:null,finalDistanceMeters:null};
    if(!next)throw Error('Inicia primeiro com !trabalho.');
    if(command==='inicio')next.startedAt=lisbonStartTime(arg,next,now);
    else if(command==='p'){
      if(next.endedAt!==null)return {work:next,distanceMeters:meters};
      if(next.pauses.at(-1)?.end!==null)next.pauses.push({start:now,end:null});
    }else if(command==='fim'){
      if(next.endedAt===null){if(next.pauses.at(-1)?.end===null)next.pauses.at(-1).end=now;next.endedAt=now;next.finalIncomeCents=moneyCents;next.finalDistanceMeters=meters;}
    }
  }
  return {work:next,distanceMeters:meters};
}
function validateWorkSnapshot(value,now=Date.now()){
  const integer=(v,max=1000000000000)=>Number.isSafeInteger(v)&&v>=0&&v<=max;
  if(!value||!integer(value.revision,Number.MAX_SAFE_INTEGER)||!integer(value.moneyCents)||!integer(value.distanceMeters,1000000000))throw Error('Valores de sincronização inválidos.');
  const work=value.work;
  if(work!==null){
    if(!work||typeof work.id!=='string'||!/^[\w-]{1,100}$/.test(work.id)||!integer(work.startedAt,now+300000)||!Array.isArray(work.pauses)||work.pauses.length>10000)throw Error('Contador inválido.');
    const end=work.endedAt??now;
    if(!integer(end,now+300000)||end<work.startedAt)throw Error('Fim inválido.');
    let previous=0;
    work.pauses.forEach((p,i)=>{if(!integer(p.start,end)||p.start<previous||(p.end===null?(work.endedAt!==null||i!==work.pauses.length-1):(!integer(p.end,end)||p.end<p.start)))throw Error('Pausa inválida.');previous=p.end??end});
    if(work.endedAt!==null&&(!integer(work.finalIncomeCents)||!integer(work.finalDistanceMeters,1000000000)))throw Error('Totais finais inválidos.');
  }
  return {revision:value.revision,moneyCents:value.moneyCents,distanceMeters:value.distanceMeters,work,feedback:String(value.feedback||'').slice(0,240)};
}

const STORE_KEY='lisbonbusdriverwidgetv1';
const MONEY_COOLDOWN_MS=6000;
let carClock=null;
const carMonotonicNow=()=>typeof performance!=='undefined'?performance.now():Date.now();
function carNow(){return Math.floor(carClock?carClock.time+carMonotonicNow()-carClock.receivedAt:Date.now())}
// Repair fractional millisecond anchors produced by the previous widget version.
function repairCarClockPrecision(car){if(!car)return;for(const key of ['elapsedStartedAt','totalStartedAt'])if(Number.isFinite(car[key])&&car[key]>=0)car[key]=Math.floor(car[key]);}
function repairPendingCarClocks(){repairCarClockPrecision(state);for(const pending of Array.isArray(state.workOutbox)?state.workOutbox:[])repairCarClockPrecision(pending.car);}
function syncCarClock(serverNow){if(!Number.isFinite(serverNow))return;const receivedAt=carMonotonicNow(),previous=carClock?carClock.time+receivedAt-carClock.receivedAt:0;carClock={time:Math.max(previous,serverNow),receivedAt}}

let moneyReadyAt=0;
const $=id=>document.getElementById(id);
let fields={},ready=false,currentCarMode=null,tick=null,audioContext=null,limitAlertedFor=0;
let state={status:'LIVRE',elapsedBase:0,elapsedStartedAt:0,totalBase:0,totalStartedAt:0,moneyCents:0,targetCents:10000,limitSeconds:0};
function secondsNow(base,start){return Math.max(0,Math.floor(Number(base||0)+(start?(carNow()-start)/1000:0)))}
function clockText(seconds,alwaysHours=false){seconds=Math.max(0,Math.floor(seconds||0));const h=Math.floor(seconds/3600),m=Math.floor(seconds%3600/60),s=seconds%60,p=n=>String(n).padStart(2,'0');return alwaysHours||h?[p(h),p(m),p(s)].join(':'):[p(m),p(s)].join(':')}
function moneyText(cents){return(cents/100).toLocaleString('pt-PT',{minimumFractionDigits:2,maximumFractionDigits:2})+' €'}
const ALERT_TONES={l:[[660,0,.11],[880,.12,.13]],v:[[494,0,.12],[659,.14,.12],[880,.28,.18]],p:[[587,0,.12],[392,.15,.2]],m:[[440,0,.18]],r:[[523,0,.1],[392,.15,.16]],g:[[784,0,.1],[988,.11,.16]],meta:[[587,0,.1],[784,.12,.15]],goal:[[784,0,.12],[988,.14,.12],[1318,.29,.28]],limit:[[880,0,.12],[659,.15,.13],[440,.31,.24]]};
function playAlert(name){if(fields.soundEnabled===false||String(fields.soundEnabled).toLowerCase()==='false')return;const Ctx=window.AudioContext||window.webkitAudioContext;if(!Ctx)return;try{audioContext=audioContext||new Ctx();if(audioContext.state==='suspended')audioContext.resume().catch(()=>{});const volume=Math.max(0,Math.min(1,Number(fields.soundVolume??40)/100));if(!volume)return;const start=audioContext.currentTime;for(const [frequency,offset,duration] of ALERT_TONES[name]||[]){const oscillator=audioContext.createOscillator(),gain=audioContext.createGain(),when=start+offset;oscillator.type='sine';oscillator.frequency.setValueAtTime(frequency,when);gain.gain.setValueAtTime(.0001,when);gain.gain.exponentialRampToValueAtTime(.16*volume,when+.012);gain.gain.exponentialRampToValueAtTime(.0001,when+duration);oscillator.connect(gain);gain.connect(audioContext.destination);oscillator.start(when);oscillator.stop(when+duration+.02)}}catch(e){}}
function parseMoney(raw){const normalized=String(raw||'').replace(/€/g,'').trim().replace(/\.(?=\d{3}(?:\D|$))/g,'').replace(',','.');const n=Number(normalized);return Number.isFinite(n)&&n>=0&&n<=1000000?Math.round(n*100):null}
function parseDuration(raw){const v=String(raw||'').trim().toLowerCase().replace(/\s+/g,'').replace(',','.');let n=0;let m=v.match(/^(\d+(?:\.\d+)?)(s|sec|seg|m|min|h|hr|hora|horas)$/);if(m){const amount=Number(m[1]),unit=m[2];n=amount*(unit==='s'||unit==='sec'||unit==='seg'?1:unit==='h'||unit==='hr'||unit==='hora'||unit==='horas'?3600:60)}else if((m=v.match(/^(\d+)h(?:(\d+)m)?$/)))n=Number(m[1])*3600+Number(m[2]||0)*60;else if((m=v.match(/^(\d+):(\d{1,2})(?::(\d{1,2}))?$/))){n=m[3]!==undefined?Number(m[1])*3600+Number(m[2])*60+Number(m[3]):Number(m[1])*60+Number(m[2])}return Number.isFinite(n)&&n>0&&n<=86400?Math.floor(n):null}
function parseTotalTime(raw){const match=String(raw||'').trim().match(/^(\d+):([0-5]\d):([0-5]\d)$/);if(!match)return null;const seconds=Number(match[1])*3600+Number(match[2])*60+Number(match[3]);return Number.isSafeInteger(seconds)?seconds:null}
function render(){const root=$('widget'),elapsed=secondsNow(state.elapsedBase,state.elapsedStartedAt),total=secondsNow(state.totalBase,state.totalStartedAt),money=Number(state.moneyCents)||0,target=Math.max(1,Number(state.targetCents)||10000);$('status').textContent=state.status;root.classList.toggle('travel',state.status==='EM VIAGEM');root.classList.toggle('paused',state.status==='PAUSA');root.classList.toggle('muted',state.status==='MUTE');setCar(state.status==='EM VIAGEM'?'on':'off');$('elapsed').textContent=clockText(elapsed);$('total').textContent=clockText(total,true);$('tripLimit').textContent=state.limitSeconds?' / '+clockText(state.limitSeconds):'';const overLimit=Boolean(state.limitSeconds&&elapsed>state.limitSeconds);$('currentStat').classList.toggle('over-limit',overLimit);if(overLimit){if(limitAlertedFor!==state.limitSeconds){playAlert('limit');limitAlertedFor=state.limitSeconds}}else limitAlertedFor=0;$('money').textContent=moneyText(money);$('moneyTargetLabel').textContent=moneyText(target);const complete=money>=target;$('moneyProgress').style.width=Math.max(0,Math.min(100,money/target*100))+'%';$('moneyProgress').parentElement.classList.toggle('complete',complete);document.querySelector('.stat.objective').classList.toggle('goal-met',complete)}
function saveOriginal(){if(ready&&typeof SE_API!=='undefined'&&SE_API.store)try{SE_API.store.set(STORE_KEY,state)}catch(e){}}
function syncTimers(){state.elapsedBase=secondsNow(state.elapsedBase,state.elapsedStartedAt);state.totalBase=secondsNow(state.totalBase,state.totalStartedAt);if(state.elapsedStartedAt)state.elapsedStartedAt=carNow();if(state.totalStartedAt)state.totalStartedAt=carNow()}
function legacyCommand(raw){const text=String(raw||'').trim().replace(/^!g-(?=\s*\d)/i,'!g -'),match=text.match(/^!(l|v|p|m|r|g|meta|total)(?:\s+(.+))?$/i);if(!match)return false;const cmd=match[1].toLowerCase(),arg=(match[2]||'').trim(),now=carNow(),previousStatus=state.status,goalWasReached=Number(state.moneyCents)>=Number(state.targetCents);if(cmd==='l'){syncTimers();state.status='LIVRE';state.elapsedBase=0;state.elapsedStartedAt=0;state.totalStartedAt=0;state.limitSeconds=0}else if(cmd==='v'){const limit=arg?parseDuration(arg):null;if(arg&&!limit)return false;syncTimers();state.status='EM VIAGEM';if(limit)state.limitSeconds=limit;if(!state.elapsedStartedAt)state.elapsedStartedAt=now;if(!state.totalStartedAt)state.totalStartedAt=now}else if(cmd==='p'){syncTimers();state.status='PAUSA';state.elapsedStartedAt=0;state.totalStartedAt=0}else if(cmd==='m'){state.status='MUTE'}else if(cmd==='r'){state.status='LIVRE';state.elapsedBase=0;state.elapsedStartedAt=0;state.totalBase=0;state.totalStartedAt=0;state.moneyCents=0;state.distanceMeters=0;state.limitSeconds=0}else if(cmd==='g'){const subtract=arg.startsWith('-'),amount=parseMoney(subtract?arg.slice(1).trim():arg);if(amount===null)return false;if(now<moneyReadyAt)return false;moneyReadyAt=now+MONEY_COOLDOWN_MS;state.moneyCents=Math.max(0,(Number(state.moneyCents)||0)+(subtract?-amount:amount))}else if(cmd==='total'){const seconds=parseTotalTime(arg);if(seconds===null)return false;state.totalBase=seconds;state.totalStartedAt=state.totalStartedAt?now:0}else if(cmd==='meta'){const amount=parseMoney(arg);if(amount===null||amount===0)return false;state.targetCents=amount}let sound=cmd;if(['l','v','p','m'].includes(cmd)&&previousStatus===state.status)sound='';if(!goalWasReached&&Number(state.moneyCents)>=Number(state.targetCents))sound='goal';if(sound)playAlert(sound);render();save();return true}
function isAllowed(message){const nick=String(message.nick||message.username||message.displayName||'').replace(/^@/,'').toLowerCase(),channel=String(fields.channelName||'').replace(/^#/,'').trim().toLowerCase(),tags=message.tags||{},badgeList=Array.isArray(message.badges)?message.badges.map(b=>String((b&&b.type)||b||'')).join(','):String(tags.badges||'');return nick===channel||String(tags.mod||'')==='1'||/(^|[,/])moderator([,/]|$)|(^|[,/])broadcaster([,/]|$)/i.test(badgeList)}
function applyMessage(data){const message=data&&data.data?data.data:data;if(message&&isAllowed(message))command(message.text||'')}
function imageUrl(value){if(Array.isArray(value))value=value[0];if(value&&typeof value==='object')value=value.url||value.src||'';return typeof value==='string'?value:''}
function setCar(mode){if(currentCarMode===mode)return;currentCarMode=mode;const image=$('carImage'),off=imageUrl(fields.carOffImage),on=imageUrl(fields.carOnImage),src=mode==='on'?(on||off):(off||on);if(src){image.src=src;image.style.visibility='visible'}else image.style.visibility='hidden'}
window.addEventListener('onWidgetLoad',async event=>{let restoredWorkState=false;fields=event.detail.fieldData||{};$('brand1').textContent=String(fields.brand1||'LISBON').toUpperCase();$('brand2').textContent=String(fields.brand2||'BUSDRIVER').toUpperCase();$('subtitle').textContent=String(fields.subtitle||'TELEMETRY SYSTEM //').toUpperCase();const coinSource=imageUrl(fields.coinImage);if(coinSource)$('coinImage').src=coinSource;state.targetCents=parseMoney(fields.moneyTarget||100)||10000;setCar('off');const panel=$('editorTests');if(panel){if(fields.showTestButtons===true||String(fields.showTestButtons).toLowerCase()==='true')panel.classList.add('visible');panel.addEventListener('click',e=>{const b=e.target.closest('[data-command]');if(b)command(b.dataset.command)})}try{if(typeof SE_API!=='undefined'&&SE_API.store){const saved=await SE_API.store.get(STORE_KEY);if(saved&&typeof saved==='object'&&Number.isSafeInteger(saved.moneyCents)){state={...state,...saved};restoredWorkState=true}}}catch(e){}if(!restoredWorkState&&/^[a-f0-9]{64}$/.test(String(fields.workSyncKey||'').trim())){try{const response=await fetch('https://lisbonbusdriver-viagens.pages.dev/api/public-stats?v='+Date.now(),{cache:'no-store'});if(response.ok){const totals=await response.json();if(totals.source==='twitch'&&Number.isSafeInteger(totals.incomeCents)&&totals.incomeCents>=0&&Number.isSafeInteger(totals.distanceMeters)&&totals.distanceMeters>=0){state.moneyCents=totals.incomeCents;state.distanceMeters=totals.distanceMeters}}}catch{}}state.targetCents=Math.max(1,Number(state.targetCents)||10000);state.moneyCents=Math.max(0,Number(state.moneyCents)||0);state.limitSeconds=Math.max(0,Number(state.limitSeconds)||0);repairPendingCarClocks();ready=true;render();resumePendingWorkSync();if(tick)clearInterval(tick);tick=setInterval(render,250)});
window.addEventListener('onEventReceived',event=>{const d=event.detail||{};if(d.listener==='message')applyMessage(d.event);if(d.listener==='widget-button'){const e=d.event||{},map={testLivre:'!l',testViagem:'!v',testPause:'!p',testMute:'!m',testReset:'!r',testMoney:'!g 5',testGoal:'!g 100',testMeta:'!meta 100'};const cmd=map[String(e.field||'')]||String(e.value||'');if(cmd)command(cmd)}});




// Work commands are separate from the existing trip/status commands.
function command(raw){
  if(!ready)return false;
  const text=String(raw||'').normalize('NFD').replace(/[\u0300-\u036f]/g,'').trim();
  if(/^!f\s*$/i.test(text)){state.mediasVisible=state.mediasVisible===false;state.workFeedback=state.mediasVisible?'Médias visíveis.':'Médias ocultas.';render();save();return true;}
  // Livre only resumes the work clock when an unfinished workday is paused.
  if(/^!l\s*$/i.test(text)&&state.workday?.endedAt===null&&state.workday.pauses.at(-1)?.end===null){
    const resumed=applyWorkCommand(state.workday,'!trabalho',Number(state.moneyCents)||0,Number(state.distanceMeters)||0,carNow());
    state.workday=resumed.work;
    state.workFeedback='Pausa terminada. Trabalho retomado com !l.';
    state.workCodeVersion=12;
    return legacyCommand(text);
  }
  if(/^!(fim|terminar)\s*$/i.test(text)&&!state.workday&&state.workLastFinishedId)return true;
  const isWork=/^!(trabalho|fim|terminar|inicio|incio|km|p)(?:\s|$)/i.test(text);
  if(isWork){
    try{
      const result=applyWorkCommand(state.workday||null,text,Number(state.moneyCents)||0,Number(state.distanceMeters)||0,carNow(),'work-'+Date.now());
      if(!result)return false;
      if(/^!p(?:\s|$)/i.test(text))legacyCommand(text);
      state.workday=result.work;state.distanceMeters=result.distanceMeters;
      state.workFeedback=/^!(inicio|incio)\s/i.test(text)?'Início corrigido: '+new Date(state.workday.startedAt).toLocaleString('pt-PT',{timeZone:'Europe/Lisbon'}):'Comando de trabalho recebido.';
      state.workCodeVersion=12;
      if(/^!(fim|terminar)\s*$/i.test(text)&&state.workday?.endedAt!==null&&state.workday){
        state.workResetAfterSave=state.workday.id;
        state.workFeedback='Turno terminado. A guardar antes de repor os valores.';
      }
      render();save();return true;
    }catch(error){state.workFeedback='Erro: '+error.message;state.workCodeVersion=12;save();console.warn('LisbonBusDriver: '+error.message);return false}
  }
  return legacyCommand(text);
}
let syncPending=null,syncBusy=false,syncRetry=null,syncBackoff=5000;
function queueWorkSync(){
  if(!ready)return;
  // Never send money or a private key to an arbitrary URL from field data.
  const token=String(fields.workSyncKey||'').trim();
  if(!/^[a-f0-9]{64}$/.test(token))return;
  state.workRevision=Math.max(Date.now(),Number(state.workRevision||0)+1);
  const snapshot={revision:state.workRevision,moneyCents:Number(state.moneyCents)||0,distanceMeters:Number(state.distanceMeters)||0,work:state.workday?JSON.parse(JSON.stringify(state.workday)):null,feedback:state.workFeedback||'',car:{status:state.status,elapsedBase:Number(state.elapsedBase)||0,elapsedStartedAt:Number(state.elapsedStartedAt)||0,totalBase:Number(state.totalBase)||0,totalStartedAt:Number(state.totalStartedAt)||0,limitSeconds:Number(state.limitSeconds)||0,targetCents:Number(state.targetCents)||10000},...(typeof state.mediasVisible==='boolean'?{widgetVisible:state.mediasVisible}:{})};
  const workId=snapshot.work?.id||'no-work';
  state.workOutbox=(Array.isArray(state.workOutbox)?state.workOutbox:[]).filter(s=>(s.work?.id||'no-work')!==workId);
  state.workOutbox.push(snapshot);
  syncPending=state.workOutbox[0];
  void sendWorkSync();
}
async function sendWorkSync(){
  if(syncBusy||!syncPending||syncRetry)return;
  syncBusy=true;const sending=syncPending;
  try{
    const response=await fetch('https://lisbonbusdriver-viagens.pages.dev/api/widget-sync',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+String(fields.workSyncKey||'').trim()},body:JSON.stringify(sending)});
    if(!response.ok)throw Error('HTTP '+response.status);
    state.workOutbox=(state.workOutbox||[]).filter(s=>s.revision!==sending.revision);
    syncPending=state.workOutbox[0]||null;
    const finishedId=sending.work&&sending.work.endedAt!==null?sending.work.id:null;
    if(finishedId&&state.workResetAfterSave===finishedId){
      state.workResetAfterSave=null;
      if(state.workday?.id===finishedId&&state.workday.endedAt!==null)resetFinishedWorkDisplay(finishedId);
    }
    saveOriginal();
    syncBackoff=5000;
  }catch(error){
    console.warn('LisbonBusDriver: não foi possível sincronizar o widget. Verifica a chave e a ligação.');
    syncRetry=setTimeout(()=>{syncRetry=null;void sendWorkSync()},syncBackoff);syncBackoff=Math.min(60000,syncBackoff*2);
  }finally{syncBusy=false;if(syncPending&&!syncRetry)void sendWorkSync()}
}
function save(){
  queueWorkSync();saveOriginal();
}

function resetFinishedWorkDisplay(finishedId){
  state.workLastFinishedId=finishedId;
  state.workday=null;state.distanceMeters=0;state.moneyCents=0;
  state.status='LIVRE';state.elapsedBase=0;state.elapsedStartedAt=0;
  state.totalBase=0;state.totalStartedAt=0;state.limitSeconds=0;
  moneyReadyAt=0;limitAlertedFor=0;
  state.workFeedback='Turno guardado no histórico. Valores repostos a zero.';
  render();save();
}
function resumePendingWorkSync(){
  if(!/^[a-f0-9]{64}$/.test(String(fields.workSyncKey||'').trim()))return;
  syncPending=(Array.isArray(state.workOutbox)?state.workOutbox:[])[0]||null;
  if(syncPending)void sendWorkSync();
}

const deckClientId='deck-'+Date.now().toString(36)+'-'+Math.random().toString(36).slice(2);
let deckPolling=false,deckRetryAt=0;
async function pollDeckCommands(){
  const token=String(fields.workSyncKey||'').trim();
  if(!ready||deckPolling||Date.now()<deckRetryAt||!/^[a-f0-9]{64}$/.test(token))return;
  deckPolling=true;
  try{
    const response=await fetch('https://lisbonbusdriver-viagens.pages.dev/api/widget-control?client='+encodeURIComponent(deckClientId)+'&version=12',{headers:{Authorization:'Bearer '+token},cache:'no-store'});
    if(!response.ok)throw Error('Sem ligação ao painel');
    const payload=await response.json(),item=payload.command;
    syncCarClock(payload.serverNow);
    const base=payload.snapshot;
    if(base&&Number.isSafeInteger(base.revision)&&base.revision>Number(state.workRevision||0)){
      state.moneyCents=base.moneyCents;state.distanceMeters=base.distanceMeters;state.workday=base.work;state.workRevision=base.revision;
      if(typeof base.widgetVisible==='boolean')state.mediasVisible=base.widgetVisible;
      if(base.car)Object.assign(state,base.car);
      render();saveOriginal();
    }
    if(!item)return;
    state.deckAppliedCommands=Array.isArray(state.deckAppliedCommands)?state.deckAppliedCommands:[];
    let result=state.deckAppliedCommands.find(r=>r.id===item.id);
    if(!result){
      let ok=false,message='';
      try{ok=!!command(item.command);message=ok?'Executado no widget.':(/^!g(?:\s|-)/i.test(item.command)?'Não executado: aguarda 6 segundos entre alterações de ganhos.':state.workFeedback||'Comando não executado.');}catch(e){message=e.message}
      result={id:item.id,ok,message};
      state.deckAppliedCommands.push(result);state.deckAppliedCommands=state.deckAppliedCommands.slice(-100);saveOriginal();
    }
    const ack=await fetch('https://lisbonbusdriver-viagens.pages.dev/api/widget-control',{method:'POST',headers:{'Content-Type':'application/json',Authorization:'Bearer '+token},body:JSON.stringify({...result,client:deckClientId})});
    if(!ack.ok)throw Error('A aguardar confirmação do painel');
  }catch{deckRetryAt=Date.now()+5000}finally{deckPolling=false}
}
setInterval(()=>void pollDeckCommands(),250);
