1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4163],{26544:(e,t,i)=>{i.r(t),i.d(t,{meta:()=>o,mount:()=>E});var n=i(41635),a=i(39803);let o={id:"media-tasks",label:"Media Tasks",icon:"\uD83C\uDFAC"},r={high:0,medium:1,low:2},s={red:{e:"\uD83D\uDD34",c:"#e5484d",r:0},amber:{e:"\uD83D\uDFE1",c:"#e5a23c",r:1},green:{e:"\uD83D\uDFE2",c:"#138c60",r:2}},d={running:{e:"\uD83D\uDFE2",label:"Running",c:"#138c60",cd:"#3ecf8e",r:0},probable:{e:"\uD83D\uDFE2",label:"Probably running (matched by name)",c:"#2f8f68",cd:"#6fdcaa",r:0},fatigued:{e:"\uD83D\uDFE0",label:"Running â frequency too high",c:"#e0632f",cd:"#ff9a5c",r:1},used:{e:"\uD83D\uDFE1",label:"Used before â not running",c:"#b7791f",cd:"#ffc357",r:2},unused:{e:"âª",label:"Unused â needs \uD83D\uDE80 Push",c:"#8b8595",cd:"#cfd3dc",r:3},silent:{e:"â«",label:"Silent cut â never attach",c:"#6b6675",cd:"#8b8595",r:4}},l=["unused","used","fatigued","running","probable","silent"],p={ok:{c:"#138c60",cd:"#3ecf8e",t:""},tired:{c:"#b7791f",cd:"#ffc357",t:"getting tired"},high:{c:"#e5484d",cd:"#ff6b6f",t:"frequency too high"}},u="These count THIS COMPETITION'S OWN VIDEO FILES in the Drive â not its adverts. \uD83D\uDFE2 in a running advert \xb7 \uD83D\uDFE0 running but shown too often \xb7 \uD83D\uDFE1 used before, not running now \xb7 ⪠sitting unused, nothing uses it until someone presses \uD83D\uDE80 Push \xb7 â« silent cut (never attach) \xb7 â next to the green number means that many files are almost certainly in a running advert but were matched by name only, so they cannot be confirmed â e.g. \uD83D\uDFE20â12 means twelve are running. If the green and â are both 0 while LIVE ADS shows a number, its adverts were built from winner videos rather than this competition's own files.",c=[{k:"today",label:"Today so far",short:"today"},{k:"d3",label:"Last 3 days",short:"last 3 days"},{k:"d7",label:"Last 7 days",short:"last 7 days"},{k:"d30",label:"Last 30 days",short:"last 30 days"},{k:"life",label:"All time",short:"all time"}],m=e=>c.find(t=>t.k===e)||c[2];function f(e,t){let i=e&&e.win||null;return i&&i[t]?i[t]:"d7"===t?{roas:e&&e.roas,purchases:e&&e.purchases}:"today"===t?{roas:e&&e.roasToday,purchases:e&&e.purchasesToday}:null}let g=(e,t)=>{let i=f(e,t);return i&&null!=i.roas?Number(i.roas):null},h=(e,t)=>{let i=f(e,t);return i&&null!=i.purchases?Number(i.purchases):null},y={big:{label:"BIG SPENDER",c:"#e5484d",order:0,hint:"most of the money goes here â these are the ones that matter"},medium:{label:"MEDIUM",c:"#e5a23c",order:1,hint:"spending a fair bit"},tiny:{label:"TINY TEST",c:"#8b8595",order:2,hint:"spends almost nothing â a long list of these is normal"}},b=e=>y[String(e&&e.size||"")]?String(e.size):"medium";function x(e){let t=y[b(e)];return'<span title="'+t.hint+'" style="display:inline-block;background:'+t.c+"18;color:"+t.c+";border:1px solid "+t.c+'55;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:800;white-space:nowrap">'+t.label+"</span>"}function v(e){return(e=Number(e||0))>=3.5?"high":e>=2.5?"tired":"ok"}function w(e,t){if(!(e=Number(e||0)))return'<span style="font-size:11px;color:#8b8595">freq â</span>';let i=p[v(e)],n=t?i.cd:i.c;return'<span title="How many times the average person has seen it: under 2.5 fine \xb7 2.5â3.5 getting tired \xb7 3.5+ frequency too high" style="display:inline-block;background:'+n+"22;color:"+n+";border:1px solid "+n+'55;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:800;white-space:nowrap">freq '+e.toFixed(1)+"\xd7"+(i.t?" \xb7 "+i.t:"")+"</span>"}function k(e,t){let i=e&&e.usage;if(!i||"object"!=typeof i)return null;let n="fuzzy"===i.confidence,a=eV(e,t),o=a.filter(e=>e&&(null!=e.status||null!=e.roas)),r=o.filter(e=>/ACTIVE/i.test(e.status||"")),s=e=>e.map(e=>Number(e.roas||0)).filter(e=>e>0),d=Math.max(0,...s(o)),l=Math.max(0,...s(r)),p=r.reduce((e,t)=>Math.max(e,Number(t.frequency||0)),0),u=Math.max((i.adIds||[]).length,a.length),c={fuzzy:n,linked:a,live:r,known:o,bestRoas:d,liveRoas:l,maxFreq:p,adCount:u,tired:!1,proven:!1,engineOk:!1,note:i.note||""};if(!u&&"in_use"!==i.state&&"used"!==i.state){let t;return(t=e.name,/no[\s_-]?music|silent/i.test(String(t||""))||/silent|never attach/i.test(String(i.note||"")))?{...c,key:"silent",text:"Silent export (no audio) â never attached to a paid ad; the media team must export it again with audio"}:{...c,key:"unused",text:i.note?"Never used in an ad â "+String(i.note):"Never used in an ad. AdPilotX will NOT pick this up by itself â press \uD83D\uDE80 Push to put it live"}}
1if(!n&&(r.length>0||"in_use"===i.state&&!o.length)){let e=v(p),t=l?l.toFixed(2):"â";return"high"===e?{...c,key:"fatigued",text:"Running but the audience has seen it "+p.toFixed(1)+" times â AdPilotX will rotate it out; a fresh cut is needed"}:"tired"===e?{...c,key:"running",tired:!0,text:"Running \xb7 ROAS "+t+" \xb7 freq "+p.toFixed(1)+" â getting tired, line up a fresh cut"}:{...c,key:"running",text:"Running \xb7 ROAS "+t+" \xb7 freq "+(p?p.toFixed(1):"â")}}let m=n&&r.length>0,f=!m&&d>=1.5,g=f&&o.some(e=>Number(e.roas||0)>=2&&Number(e.purchases||0)>=5),h="Ran before in "+u+" ad"+(1===u?"":"s")+(d?", best ROAS "+d.toFixed(2):", no ROAS on record")+". ",y=m?"Open the ad below to confirm it is this file":d?f?"Proven â AdPilotX can re-add it":"Under-performed â do not re-add without a new hook":"Unproven â no result on record";return{...c,key:m?"probable":"used",proven:f,engineOk:g,probablyLive:m,text:(m?"â Probably running â matched by name only, so it can't be counted as the live one. ":"Not running now. ")+h+y}}function S(e,t){let i={running:0,probable:0,probablyRunning:0,tired:0,fatigued:0,used:0,proven:0,engineOk:0,unused:0,silent:0,total:0,withUsage:0,maxFreq:0};return(e||[]).forEach(e=>{i.total++;let n=e&&(e._st||k(e,t));n&&(i.withUsage++,i[n.key]++,n.probablyLive&&i.probablyRunning++,n.tired&&i.tired++,n.proven&&i.proven++,n.engineOk&&i.engineOk++,i.maxFreq=Math.max(i.maxFreq,n.maxFreq||0))}),i.withUsage?i:null}function A(e){if(!e||"object"!=typeof e)return null;if("running"in e)return e;let t=Number(e.in_use||0)+Number(e.used||0)+Number(e.unused||0);return{running:Number(e.in_use||0),tired:0,fatigued:0,used:Number(e.used||0),proven:0,engineOk:0,unused:Number(e.unused||0),silent:0,total:t,withUsage:t,maxFreq:0}}function D(e,t){if(!e)return"";let i=Number(e.probablyRunning||0),n=["\uD83D\uDFE2"+Number(e.running||0)+(i?"â"+i:""),"\uD83D\uDFE0"+Number(e.fatigued||0),"\uD83D\uDFE1"+Number(e.used||0),"âª"+Number(e.unused||0)];return e.silent&&n.push("â«"+Number(e.silent)),'<span title="'+(0,a.ZD)(u)+'" style="display:inline-block;background:'+(t?"rgba(255,255,255,.06)":"#f4f4f8")+";border:1px solid "+(t?"rgba(255,255,255,.12)":"#e3e3ea")+";color:"+(t?"#eef0f5":"#17141f")+';border-radius:999px;padding:3px 9px;font-size:12px;font-weight:700;white-space:nowrap">'+n.join(" \xb7 ")+"</span>"}function N(e){let t=Number(e.roas||0),i=Number(e.frequency||0),n=Number(e.purchases||0);if(!/ACTIVE/i.test(e.status||"")){if(t>=1.5){let e=t>=2&&n>=5;return{key:"readd",auto:e,c:"#138c60",t:e?"proven â eligible for re-add (meets the automatic bar)":"proven â eligible for re-add (under the automatic bar; ask AdPilotX)"}}return{key:"leave",auto:!1,c:"#8b8595",t:t?"paused â under-performed, not for re-add":"paused â no result on record"}}return i>=3.5&&t<1.2?{key:"rotate",auto:!0,c:"#e5484d",t:"AdPilotX will swap this for a fresh video"}:i>=3.5?{key:"hold",auto:!1,c:"#e0632f",t:"Still making money, but people have seen it too often â please film a new one"}:t<.5&&n>0?{key:"kill",auto:!0,c:"#e5484d",t:"Losing money â AdPilotX will switch it off"}:t||n?i>=2.5?{key:"keep",auto:!1,c:"#b7791f",t:"Leave it running â but it is getting tired, line up a new video"}:{key:"keep",auto:!1,c:"#138c60",t:"Leave it running"}:{key:"watch",auto:!1,c:"#8b8595",t:"No sales yet â AdPilotX switches it off if that carries on"}}async function z(){try{let{data:e}=await n.ND.auth.getSession();return e?.session?.access_token||""}catch{return""}}async function _(e,t={}){let i=await z(),n=await fetch(e,{...t,cache:"no-store",headers:{...t.headers||{},authorization:"Bearer "+i,...t.body?{"content-type":"application/json"}:{}}});try{return await n.json()}catch{return{ok:!1}}}let T=["\xa32,?500[\\s-]*.*draw","f1[\\s-]*legends","boxing[\\s-]*legends"];function P(e,t){let i=t&&t.exclusions||{},n=T.concat(Array.isArray(i.titlePatterns)?i.titlePatterns:[]),a=(Array.isArray(i.slugs)?i.slugs:[]).map(e=>String(e).toLowerCase()),o=String(e&&e.title||""),r=String(e&&e.slug||"").toLowerCase();return!!(r&&a.includes(r))||n.some(e=>{try{return RegExp(e,"i").test(o)}catch{return!1}})}function q(e,t){let i=t&&Array.isArray(t.smallPrizeSkipped)?t.smallPrizeSkipped:[],n=String(e&&e.slug||"").toLowerCase();return!!n&&i.some(e=>e&&String(e.slug||"").toLowerCase()===n)}async function I(){try{let{data:e}=await n.ND.from("competitions").select("id,slug,title,status,draw_at").eq("status","live");return Array.isArray(e)?e:[]}catch{return[]}}function L(e){if(!e)return"";let t=Math.max(0,Math.round((Date.now()-new Date(e).getTime())/6e4));if(t<1)return"just now";if(t<60)return t+" min ago";let i=Math.round(t/60);return i+(1===i?" hour ago":" hours ago")}async function E(e){e.innerHTML='<div style="max-width:1150px"><h1 style="margin:0 0 4px">Media Team Tasks</h1><p class="muted" style="margin:0 0 14px;font-size:13px">Live board + ad health from the hourly AdPilotX snapshot. Health is ROAS only; no spend or revenue figures here.</p><div id="mt-tabs" style="display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap"><button data-mt-tab="board">\uD83D\uDEA6 Health Board</button><button data-mt-tab="tasks">Tasks</button><button data-mt-tab="active">Active Ads & ROAS</button><button data-mt-tab="drive">\uD83D\uDCC1 Drive</button><button data-mt-tab="msg">
1\uD83D\uDCAC Message AdPilotX</button><button data-mt-tab="insights">\uD83E\uDDE0 Insights</button><button data-mt-tab="audiences">\uD83D\uDC65 Who sees our ads</button><button data-mt-tab="campaigns">\uD83D\uDDC2 Campaigns</button><button data-mt-tab="platforms">\uD83C\uDF10 Platforms</button><button data-mt-tab="rejected">\uD83D\uDEAB Rejected ads <span id="mt-rej-count" style="display:none;margin-left:4px;padding:1px 7px;border-radius:999px;background:#d64545;color:#fff;font-size:11px;font-weight:800"></span></button><button data-mt-tab="review">â
Ad review <span id="mt-review-count" style="display:none;margin-left:4px;padding:1px 7px;border-radius:999px;background:#d64545;color:#fff;font-size:11px;font-weight:800"></span></button></div><div id="mt-ask" style="display:flex;gap:10px;align-items:center;margin-bottom:14px;flex-wrap:wrap"><button id="mt-ask-btn" class="btn btn-primary btn-sm">\uD83D\uDD04 Ask AdPilotX for a fresh update</button><span id="mt-ask-status" class="muted" style="font-size:12px"></span><span style="flex:1"></span><span id="mt-ap-state" style="font-size:12px;font-weight:700"></span><button id="mt-ap-btn" class="btn btn-sm" style="font-weight:800"></button></div><div id="mt-controls" style="margin-bottom:12px"></div><div id="mt-summary" style="margin-bottom:14px"></div><div id="mt-body">Loading live dataâ¦</div><div id="mt-modal"></div></div>';let[t,i,n]=await Promise.all([_("/api/admin/media-needs"),_("/api/admin/media-tasks"),I()]),o=e=>P(e,t)||q(e,t);t&&Array.isArray(t.awaitingMedia)&&(t.awaitingMedia=t.awaitingMedia.filter(e=>!o(e))),t&&Array.isArray(t.mediaTeamActions)&&(t.mediaTeamActions=t.mediaTeamActions.filter(e=>!(e&&/^smallprize:/.test(String(e.key||""))))),e._mt={needs:t,states:i,comps:(n||[]).filter(e=>!o(e)),view:"board",sort:"important",filter:"all"},e._mtRefresh&&clearInterval(e._mtRefresh),e._mtRefresh=setInterval(async()=>{if(!document.body.contains(e))return void clearInterval(e._mtRefresh);if("hidden"===document.visibilityState||!e._mt)return;let t=await _("/api/admin/media-needs");if(!t||!1===t.ok)return;Array.isArray(t.awaitingMedia)&&(t.awaitingMedia=t.awaitingMedia.filter(e=>!o(e))),Array.isArray(t.mediaTeamActions)&&(t.mediaTeamActions=t.mediaTeamActions.filter(e=>!(e&&/^smallprize:/.test(String(e.key||""))))),e._mt.needs=t;let i=document.activeElement;i&&e.contains(i)&&/^(INPUT|TEXTAREA|SELECT)$/.test(i.tagName)||("active"===e._mt.view||"board"===e._mt.view)&&Z(e)},6e5),e.querySelectorAll("[data-mt-tab]").forEach(t=>t.addEventListener("click",()=>{e._mt.view=t.getAttribute("data-mt-tab"),M(e),Z(e)})),M(e),ej(e).catch(()=>{}),Z(e),function(e,t,i){let n=e.querySelector("#mt-ask-btn"),a=e.querySelector("#mt-ask-status");if(!n||!a)return;let o=t&&t._updatedAt,r=i&&i.signal;a.textContent=o?"Ads / Drive last updated "+L(o)+("snapshot"===t._source?" (via AdPilotX â Supabase)":""):"No AdPilotX snapshot yet.",r&&"pending"===r.status&&(n.disabled=!0,a.textContent="AdPilotX is checking⦠(usually under a minute)",G(e)),n.addEventListener("click",async()=>{n.disabled=!0,a.textContent="Asking AdPilotXâ¦";let t=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"ask"})});if(!t||!t.ok){a.textContent="Couldn't reach the signal channel.",n.disabled=!1;return}a.textContent="AdPilotX is checking⦠(usually under a minute)",G(e)})}(e,t,i),function(e,t){try{!function(e,t){let i=t&&t.autopilot||null,n=i&&i.health,o=e.querySelector("#mt-ap-state");if(!o||!o.parentElement)return;let r=e.querySelector("#mt-ap-health");if(r||((r=document.createElement("div")).id="mt-ap-health",r.style.cssText="margin:6px 0 12px;padding:10px 14px;border:1px solid #e3e3ea;border-radius:12px;font-size:12.5px;background:#fff;color:#17141f;line-height:1.55",o.parentElement.insertAdjacentElement("afterend",r)),!n){r.innerHTML="<b>\uD83E\uDE7A Autopilot health</b> â arrives with the next AdPilotX update.";return}let s=function(e,t){if(!1===t)return{dot:"\uD83D\uDD34",word:"Stopped â press â¶ Start to run again",color:"#c0392b"};let i=e&&e.lastRun?Date.parse(e.lastRun.at||""):NaN;if(!Number.isFinite(i))return{dot:"âª",word:"Waiting for the first run report",color:"#666"};let n=(Date.now()-i)/6e4,a=Object.values(e&&e.steps||{}).some(e=>e&&!1===e.ok);return n>150||!1===e.lastRun.ok?{dot:"\uD83D\uDD34",word:"Not running â last run "+L(e.lastRun.at),color:"#c0392b"}:n>75||a?{dot:"\uD83D\uDFE0",word:n>75?"Late â last run "+L(e.lastRun.at):"Running â one step reported a problem",color:"#8a5a00"}:{dot:"\uD83D\uDFE2",word:"Healthy â last run "+L(e.lastRun.at),color:"#0e7a52"}}(n,i.on),d=n.lastRun||{},l={meta:"Facebook / Instagram",snap:"Snapchat",tiktok:"TikTok",reddit:"Reddit",mission:"Agents"},p=Object.assign({meta:d.at?{ok:!1!==d.ok,at:d.at}:null},n.steps||{}),u=Object.keys(l).filter(e=>p[e]).map(e=>{let t=p[e];return'<span title="'+(0,a.ZD)(B(t.text||""))+'" style="display:inline-block;margin:2px 4px 2px 0;padding:2px 8px;border-radius:10px;font-weight:700;background:'+(!1===t.ok?"#fdecea;color:#9b1c1c":"#dff3e8;color:#0b5d3b")+'">'+(!1===t.ok?"â ï¸ ":"â
")+(0,a.ZD)(l[e])+"</span>"}).join(""),c=n.growth||null,m=c?"climbing"===c.state?"\uD83D\uDCC8 Growing spend â up to +15% a day while ROAS holds":"capped"===c.state?"Spend at the owner's ceiling":"⸠Holding spend for now â "+(0,a.ZD)(B(c.why||"ROAS under the floor;
1 cutting losers first")):"",f=n.nextRunAt?" \xb7 next run "+new Date(n.nextRunAt).toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",timeZone:"Europe/London"}):"",g=n.doctor?"Delivery doctor: "+(n.doctor.findings||0)+" issue(s) found, "+(n.doctor.fixed||0)+" fixed \xb7 ":"",h=n.memory&&n.memory.at?"Memory learned "+L(n.memory.at):"",y=(d.items||[]).map(e=>"<li><b>"+(0,a.ZD)(e.kind||"")+"</b> "+(0,a.ZD)(e.name||"")+(e.why?" â "+(0,a.ZD)(B(e.why)):"")+"</li>").join("");r.innerHTML='<div style="font-weight:800;color:'+s.color+'">'+s.dot+" \uD83E\uDE7A Autopilot "+(0,a.ZD)(s.word)+(0,a.ZD)(f)+"</div><div>"+u+"</div><div>"+(d.changes||0)+" change(s) last run: "+(d.cuts||0)+" cut \xb7 "+(d.raises||0)+" raised \xb7 "+(d.pauses||0)+" paused</div>"+(m?"<div>"+m+"</div>":"")+(g||h?'<div style="color:#44404f">'+(0,a.ZD)(g+h)+"</div>":"")+(y?'<details style="margin-top:4px"><summary style="cursor:pointer;font-weight:700;color:#17141f">What it did last run</summary><ul style="margin:4px 0 0 18px;padding:0">'+y+"</ul></details>":"")+'<div style="color:#5b5766;margin-top:4px">Nothing here needs you â the autopilot does it all. Ask AdPilotX if something is missing or not live.</div>'}(e,t)}catch(e){}try{!function(e,t){let i=e.querySelector("#mt-rej-count");if(!i)return;let n=(O(t)||[]).filter(e=>e&&!1!==e.still).length;i.textContent=String(n),i.style.display=n?"inline-block":"none"}(e,t)}catch(e){}let i=t&&t.autopilot||null;W(e,i?i.on:null,i&&i.by,i?null:"Autopilot status arrives with the next update");let n=e.querySelector("#mt-ap-btn");n&&n.addEventListener("click",async()=>{let t="0"!==n.dataset.on;if(t&&!n.dataset.armed){n.dataset.armed="1",n.textContent="Press again to STOP everything",setTimeout(()=>{n.dataset.armed&&(n.dataset.armed="",n.textContent="â¹ Stop autopilot")},5e3);return}n.disabled=!0;let i=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"autopilot",on:!t})});(n.disabled=!1,i&&i.ok)?(W(e,!t,null,t?"Stopping⦠(within a minute)":"Starting⦠(within a minute)"),n.dataset.on=t?"0":"1"):W(e,t,null,"Couldn't reach AdPilotX â try again")})}(e,t)}function M(e){e.querySelectorAll("[data-mt-tab]").forEach(t=>{let i=t.getAttribute("data-mt-tab")===e._mt.view;t.className="btn btn-sm "+(i?"btn-primary":"btn-ghost")})}function Z(e){var t;let i,n,o,d,l,p=e._mt.view;e.querySelector("#mt-controls").innerHTML="","board"===p?function(e){let{needs:t,comps:i,sort:n,filter:o}=e._mt,d=e.querySelector("#mt-body"),l=e.querySelector("#mt-summary");if(!t||!t.ok)return Y(e,t);let p=Q(i,t),c={red:0,amber:0,green:0};p.forEach(e=>{c[e.light]++}),e.querySelector("#mt-controls").innerHTML='<div style="display:flex;gap:14px;flex-wrap:wrap;align-items:center;font-size:13px"><label>Sort: <select id="mt-sort" class="btn btn-ghost btn-sm" style="padding:4px 8px">'+es("important",n,"Most important")+es("missing",n,"Least / missing media")+es("mediacount",n,"Fewest media files")+es("freq",n,"Highest frequency")+es("roas",n,"Lowest ROAS")+es("name",n,"Name")+'</select></label><label>Show: <select id="mt-filter" class="btn btn-ghost btn-sm" style="padding:4px 8px">'+es("all",o,"All")+es("red",o,"\uD83D\uDD34 Red only")+es("amber",o,"\uD83D\uDFE1 Amber only")+es("green",o,"\uD83D\uDFE2 Green only")+'</select></label><button id="mt-plan-btn" class="btn btn-sm btn-primary">\uD83E\uDDED What\'s the plan?</button><span class="muted" style="font-size:12px">Date range & per-comp file counts need an AdPilotX update.</span></div>',e.querySelector("#mt-sort").addEventListener("change",t=>{e._mt.sort=t.target.value,Z(e)}),e.querySelector("#mt-filter").addEventListener("change",t=>{e._mt.filter=t.target.value,Z(e)}),e.querySelector("#mt-plan-btn").addEventListener("click",()=>{var n,o,r;let d,l,p,u,c,m,f,g,h,y,b;return n=e,o=Q(i,t),r=t,l=(d=o.map(e=>{var t,i;let n,a,o,s,d;return{r:e,p:(t=e,i=r,n=t.comp,o=Number((a=t.stateSummary||{}).unused||0),s=Number(a.proven||0),d=(e,t)=>
1e+" "+t+(1===e?"":"s"),P(n,i)?{group:"keep",why:"Owner rule â no adverts for this competition.",auto:"AdPilotX will not advertise it or ask for media.",who:null,when:"Stays as it is on purpose."}:q(n,i)?{group:"keep",why:"Small prize â under AdPilotX's prize floor.",auto:"Not advertised on its own; covered by the general Always-On adverts.",who:null,when:"Stays as it is on purpose."}:"green"===t.light?{group:"green",why:t.needsText,auto:"Keeps it running, scales it while it pays, rotates tired adverts.",who:null,when:"â"}:t.noMedia?{group:"media",why:"No video for it anywhere yet.",auto:"Won't advertise it until a video exists, and keeps the media-team task open.",who:"Media team: upload finished cuts (9:16 + 4:5, with audio) to its Drive folder.",when:"Green within about an hour of the video being pushed live from Media Tasks."}:a&&a.silent&&a.silent===a.withUsage?{group:"media",why:"Only silent cuts in the Drive.",auto:"Will not use silent videos.",who:"Media team: re-export the videos with audio.",when:"Green once a cut with audio is pushed live."}:0===t.liveAds&&Number(t.pendingAds||0)>0?{group:"auto",why:d(Number(t.pendingAds),"advert")+" already placed, waiting for Meta to approve "+(1===Number(t.pendingAds)?"it":"them")+".",auto:"Nothing needed â Meta checks every new advert before it can show, usually within the hour. AdPilotX will pick it up as live on its next hourly check.",who:null,when:"Usually under an hour. If it is still not showing tomorrow, say so in Messages."}:0===t.liveAds?s?{group:"auto",why:"Nothing live right now, but "+d(s,"proven video")+" are in the Drive.",auto:"AdPilotX switches a proven advert back on in an empty ad set by itself (hourly check); a \uD83D\uDE80 Push from Media Tasks is faster.",who:null,when:"Next hourly check once an ad set exists for it."}:o?{group:"auto",why:"Nothing live, "+d(o,"unused video")+" ready in the Drive.",auto:"AdPilotX queues an unused video for an empty ad set of this competition (hourly check); a \uD83D\uDE80 Push from Media Tasks goes live straight away.",who:null,when:"Next hourly check, or straight away with \uD83D\uDE80 Push."}:{group:"media",why:"Nothing live and nothing usable in the Drive.",auto:"Keeps the media-team task open.",who:"Media team: new cuts for this competition.",when:"Green once new cuts are pushed."}:t.maxFreq>=3.5?o||s?{group:"auto",why:"People have seen the adverts too often ("+t.maxFreq.toFixed(1)+"\xd7).",auto:"Rotates in "+(o?d(o,"fresh video"):d(s,"proven video"))+" and pauses the tired ones (hourly rotation).",who:null,when:"Within the next few hourly checks; turns green as frequency drops."}:{group:"media",why:"People have seen the adverts too often ("+t.maxFreq.toFixed(1)+"\xd7) and nothing fresh is in the Drive.",auto:"Keeps paying adverts running; pauses any that stop paying.",who:"Media team: a fresh cut (new hook) for this competition.",when:"Green once the fresh cut is live and frequency falls."}:t.avgRoas>0&&t.avgRoas<1.5?{group:"auto",why:"Low return ("+t.avgRoas.toFixed(2)+"\xd7).",auto:"Pauses adverts that don't pay and moves budget to the winners (hourly).",who:o?null:"Media team (helps): a new angle for this competition.",when:"Improves over the next day or two as losers pause and winners get the budget."}:{group:"media",why:t.needsText,auto:"Keeps the best adverts running.",who:"Media team: more variants (different hooks).",when:"Green once more variants are live."})}})).filter(e=>"green"!==e.r.light||"keep"===e.p.group),p=d.filter(e=>"green"===e.r.light&&"keep"!==e.p.group).length,u=e=>'<div style="border:1px solid #e3e3ea;border-radius:10px;padding:10px 12px;margin:6px 0;background:#fff;color:#17141f"><div style="font-weight:800">'+s[e.r.light].e+" "+(0,a.ZD)(e.r.comp.title||e.r.comp.slug)+'</div><div style="font-size:12.5px;margin-top:4px"><b>Why:</b> '+(0,a.ZD)(e.p.why||"")+'</div><div style="font-size:12.5px"><b>AdPilotX:</b> '+(0,a.ZD)(e.p.auto||"")+"</div>"+(e.p.who?'<div style="font-size:12.5px"><b>Needs:</b> '+(0,a.ZD)(e.p.who)+"</div>":"")+'<div class="muted" style="font-size:12px"><b>When green:</b> '+(0,a.ZD)(e.p.when||"")+"</div></div>",c=en.map(([e,t])=>{let i=l.filter(t=>t.p.group===e);return i.length?'<div style="margin-top:12px"><div style="font-weight:800;margin-bottom:4px">'+(0,a.ZD)(t)+" ("+i.length+")</div>"+i.map(u).join("")+"</div>":""}).join(""),f=(m=function(e){let t=e&&e.libraryMedia;if(!t||"object"!=typeof t)return[];let i=e&&e.ads||[],n=t.summary||{}
1,a=[],o=Array.isArray(t.winners)?t.winners:[];if(o.length){let e=S(o,i)||A(n.winners)||{},t=Number(e.unused||0),r=Number(e.running||0),s=Number(e.proven||0),d=ee(i,/winner/i);a.push({icon:"\uD83C\uDFC6",title:"Winner videos",light:ei(d,t>0||s>0),line:o.length+" in the Drive â "+r+" running, "+t+" never used, "+s+" proven and paused. "+et(d),auto:"The hourly rotation switches proven winner adverts back on when an ad set needs one, and a winner video pushed from Media Tasks without a competition goes to the best live competition with room.",who:t?null:"Media team: new winner-reveal videos keep this fresh."})}let r=er(e,t);if(r.length){let e=r.filter(e=>e.live).length,t=r.filter(e=>e.paused).length,n=r.filter(e=>!1===e.paused&&!e.live).length,o=ee(i,/generic|always.?on/i),s=o.live&&o.avg&&o.avg<1.5;a.push({icon:"\uD83C\uDF9E",title:"Always-On (generic)",light:ei(o,n>0),line:r.length+" videos â "+e+" running now, "+n+" waiting in the rotation, "+t+" stopped by staff. "+et(o),auto:"AdPilotX rotates the least-recently-used Always-On videos in and out by itself and pauses any that stop paying."+(s?" Right now these bring back less than they cost, so AdPilotX is trimming the worst â a fresh hook is what turns this green.":""),who:s?"Media team: a new generic hook â the current ones have stopped paying.":r.length-t<4?"Media team: more generic cuts keep the rotation fresh.":null})}return a}(r)).length?'<div style="margin-top:12px"><div style="font-weight:800;margin-bottom:4px">\uD83D\uDCDA Winner videos & Always-On</div>'+m.map(e=>'<div style="border:1px solid #e3e3ea;border-radius:10px;padding:10px 12px;margin:6px 0;background:#fff;color:#17141f"><div style="font-weight:800">'+(({green:"\uD83D\uDFE2",amber:"\uD83D\uDFE0",red:"\uD83D\uDD34"})[e.light]||"")+" "+e.icon+" "+(0,a.ZD)(e.title)+'</div><div style="font-size:12.5px;margin-top:4px">'+(0,a.ZD)(e.line)+'</div><div style="font-size:12.5px"><b>AdPilotX:</b> '+(0,a.ZD)(e.auto)+"</div>"+(e.who?'<div style="font-size:12.5px"><b>Needs:</b> '+(0,a.ZD)(e.who)+"</div>":"")+"</div>").join("")+"</div>":"",h=(g=r&&r.platforms||null)?Object.entries(g).filter(([,e])=>e&&Array.isArray(e.needs)&&e.needs.length).map(([e,t])=>"<li>"+(0,a.ZD)(e)+": "+t.needs.length+" thing"+(1===t.needs.length?"":"s")+" to sort â see \uD83C\uDF10 Platforms (AdPilotX fixes the Meta ones itself).</li>").join(""):"",(y=n.querySelector("#mt-plan-modal"))||((y=document.createElement("div")).id="mt-plan-modal",n.appendChild(y)),y.innerHTML='<div style="position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:60;display:flex;align-items:flex-start;justify-content:center;overflow:auto;padding:24px 12px" data-mt-plan-bg><div style="background:#f6f6f9;color:#17141f;border-radius:14px;max-width:760px;width:100%;padding:16px 18px;box-shadow:0 12px 40px rgba(0,0,0,.35)"><div style="display:flex;justify-content:space-between;align-items:center;gap:10px"><div style="font-size:18px;font-weight:900">\uD83E\uDDED The plan to get everything green</div><button class="btn btn-sm btn-ghost" data-mt-plan-close>Close</button></div><div style="font-size:13px;margin-top:6px">'+p+" of "+d.length+" live competitions are \uD83D\uDFE2 green. Here is what happens to the rest:</div>"+(c||'<div class="notice" style="margin-top:10px">Everything is green â AdPilotX keeps it that way: scaling winners, rotating tired adverts and pausing anything that stops paying.</div>')+f+(h?'<div style="margin-top:12px;font-size:12.5px"><b>Other platforms</b><ul style="margin:4px 0 0;padding-left:18px">'+h+"</ul></div>":"")+'<div class="muted" style="font-size:11.5px;margin-top:12px">\uD83E\uDD16 Everything under "AdPilotX is sorting it" happens by itself in the hourly checks â nobody needs to press anything. AdPilotX changes adverts only; it never edits competitions, tickets, prizes or the site.</div></div></div>',b=()=>{y.innerHTML=""},void(y.querySelector("[data-mt-plan-close]").addEventListener("click",b),y.querySelector("[data-mt-plan-bg]").addEventListener("click",e=>{e.target===e.currentTarget&&b()}))}),"all"!==o&&(p=p.filter(e=>e.light===o)),p.sort((e,t)=>
1"freq"===n?t.maxFreq-e.maxFreq:"roas"===n?(e.avgRoas||99)-(t.avgRoas||99):"mediacount"===n?(e.media&&e.media.length||0)-(t.media&&t.media.length||0):"missing"===n?s[e.light].r-s[t.light].r||e.liveAds-t.liveAds:"name"===n?(e.comp.title||"").localeCompare(t.comp.title||""):s[e.light].r-s[t.light].r||(r[e.priority]??3)-(r[t.priority]??3)),l.innerHTML=V("\uD83D\uDD34 need media",c.red,"#e5484d")+V("\uD83D\uDFE1 watch",c.amber,"#e5a23c")+V("\uD83D\uDFE2 good",c.green,"#138c60")+'<span class="muted" style="font-size:12px">'+i.length+' live competitions</span><div style="font-size:12.5px;margin-top:10px;line-height:1.6;color:#cfd3dc;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:10px 12px"><b style="color:#fff">How to read this</b><br>\uD83D\uDD34 <b>needs media now</b> â nothing in the Drive, or nothing live \xb7 \uD83D\uDFE1 <b>watch</b> â running but low on fresh media or being seen too often \xb7 \uD83D\uDFE2 <b>good</b> â enough fresh creative.<br><b style="color:#fff">Media</b> = the files in the Drive for that competition, one colour each (click for the list):<br>\uD83D\uDFE2 <b>Running</b> â in a live ad and people haven\'t seen it too often yet.<br>\uD83D\uDFE0 <b>Running â frequency too high</b> â still live but the audience has seen it 3.5+ times; AdPilotX rotates it out and a fresh cut is needed.<br>\uD83D\uDFE1 <b>Used before â not running</b> â its ads are paused or ended; if it made 1.5\xd7+ it is proven and can be re-added, otherwise it needs a new hook first.<br>⪠<b>Never used</b> â sitting in the Drive, available to add to an ad.<br>â« <b>Silent</b> â exported without audio, so never attached; re-export it with sound.<br><b style="color:#fff">Freq</b> pill = how many times the average person has seen the ad: green under 2.5 \xb7 amber 2.5â3.5 getting tired \xb7 red 3.5+ <b>frequency too high</b>. <b style="color:#fff">ROAS</b> = how well the ad pays back (higher is better).</div>',d.innerHTML=p.length?"<div style=\"overflow-x:auto\"><table style=\"width:100%;border-collapse:collapse;font-size:13px\"><thead><tr style=\"text-align:left;color:#8b8595;font-size:11px;text-transform:uppercase\"><th style='padding:6px 8px'>#</th><th style='padding:6px 8px'></th><th style='padding:6px 8px'>Competition</th><th style='padding:6px 8px'>Media</th><th style='padding:6px 8px'>Live ads</th><th style='padding:6px 8px'>Freq</th><th style='padding:6px 8px'>ROAS</th><th style='padding:6px 8px'>What it needs</th></tr></thead><tbody>"+p.map((e,t)=>{var i,n;let o,r,d,l,p,c,m,f,g;return i=e,n=t+1,o=s[i.light],r=i.maxFreq?w(i.maxFreq,!0):"<span class='muted'>â</span>",d=i.avgRoas?i.avgRoas.toFixed(2)+"\xd7":"â",p=(l=i.media?i.media.length:0)&&!i.mediaExact?"â":"",c=i.stateSummary,m=(0,a.ZD)(i.comp.slug||""),f=c?"<button class='btn btn-ghost btn-sm' data-mt-media='"+m+"' style='padding:2px 8px;white-space:nowrap' title='"+(0,a.ZD)(u)+" â click for the files'>\uD83D\uDFE2"+Number(c.running||0)+(Number(c.probablyRunning||0)?"â"+Number(c.probablyRunning):"")+" \xb7 \uD83D\uDFE0"+Number(c.fatigued||0)+" \xb7 \uD83D\uDFE1"+Number(c.used||0)+" \xb7 âª"+Number(c.unused||0)+(c.silent?" \xb7 â«"+Number(c.silent):"")+" â¸</button>":l?"<button class='btn btn-ghost btn-sm' data-mt-media='"+m+"' style='padding:2px 8px' title='"+(i.mediaExact?"Exact â from AdPilotX per-comp scan":"Approximate keyword match â awaiting AdPilotX per-comp scan")+"'>"+p+l+" file"+(1===l?"":"s")+" â¸</button>":"red"===i.light?"<span style='color:#e5484d;font-weight:700'>none</span>":"<span class='muted'>â</span>",g=(i.media||[]).some(e=>e&&e.id),"<tr style='border-top:1px solid #eee'><td style='padding:8px;color:#aeb2bd;font-weight:700'>"+(n||"")+"</td><td style='padding:8px;font-size:16px'>"+o.e+"</td><td style='padding:8px;font-weight:700;color:#ffffff'>"+(0,a.ZD)(i.comp.title||i.comp.slug||"")+"</td><td style='padding:8px;white-space:nowrap'>"+f+(g?" <button class='btn btn-ghost btn-sm' data-mt-folder='"+m+"' style='padding:2px 7px;white-space:nowrap' title='Open this competition's folder in the Drive tab'>\uD83D\uDCC1</button>":"")+"</td><td style='padding:8px;white-space:nowrap'>"+(i.liveAds||0)+function(e){if(!e||!e.total)return"";let t="These "+e.total+" advert"+(1===e.total?"":"s")+" run on "+e.phrase+", so none of this competition's own Drive files are lit. That is a choice AdPilotX made for coverage and return, not a fault. Press \uD83D\uDE80 Push on one of its own files if you want it in the rotation.";return' <span title="'+(0,a.ZD)(t)+'" style="display:inline-block;margin-left:6px;background:rgba(255,195,87,.16);border:1px solid rgba(255,195,87,.45);color:#ffc357;border-radius:999px;padding:2px 8px;font-size:11px;font-weight:800;letter-spacing:.04em;white-space:nowrap;vertical-align:middle">'+(0,a.ZD)(e.label)+"</span>"}(i.backedBy)+"</td><td style='padding:8px;white-space:nowrap'>"+r+"</td><td style='padding:8px;color:"+K(i.avgRoas)+";font-weight:700'>"+d+"</td><td style='padding:8px;color:#eef0f5'>
1"+(0,a.ZD)(i.needsText||"")+"</td></tr>"}).join("")+"</tbody></table></div>":'<div class="notice">No competitions match this filter.</div>';let m={};p.forEach(e=>{m[e.comp.slug]=e}),d.querySelectorAll("[data-mt-media]").forEach(t=>t.addEventListener("click",()=>{var i,n;let a,o=m[t.getAttribute("data-mt-media")];o&&(i=e,n=o,a=i._mt&&i._mt.needs||{},eJ(i,{title:n.comp.title||n.comp.slug||"",subtitle:"in the Drive for this competition"+(n.mediaExact?"":" (approximate keyword match)")+(n.mediaCount>(n.media||[]).length?" \xb7 showing the first "+(n.media||[]).length+" of "+n.mediaCount:""),files:n.media||[],usage:n.mediaUsage||null,ads:a.ads||[],empty:"No media matched this competition in the current snapshot. A full per-competition list needs AdPilotX to add mediaByComp to the snapshot."}))})),d.querySelectorAll("[data-mt-folder]").forEach(t=>t.addEventListener("click",()=>{let i=m[t.getAttribute("data-mt-folder")];i&&ea(e,i,t)})),function(e,t){let i=e._mt&&e._mt.needs,n=i&&i.libraryMedia;if(!n||"object"!=typeof n)return;let o=i&&i.ads||[],r=n.summary||{},s=e=>({id:e.id||"",name:e.name||"(file)",link:e.link||"",path:e.path||"",size:e.size||null,modifiedTime:e.modifiedTime||null,usage:e.usage||null}),d=eo.map(e=>{let t=Array.isArray(n[e.key])?n[e.key].map(s):[];if(!t.length)return"";let i=S(t,o)||A(r[e.key]),d=i&&i.fatigued?" \xb7 "+i.fatigued+" running with frequency too high":i&&i.proven?" \xb7 "+i.proven+" proven, not running":"",l='<div style="display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap"><div><b style="color:#fff;font-size:14px">'+e.icon+" "+(0,a.ZD)(e.label)+'</b> <span class="muted" style="font-size:12px">'+t.length+" file"+(1===t.length?"":"s")+" \xb7 "+(0,a.ZD)(e.hint)+(0,a.ZD)(d)+'</span></div><div style="display:flex;gap:8px;align-items:center">'+D(i,!0)+'<button class="btn btn-ghost btn-sm" data-mt-lib="'+(0,a.ZD)(e.key)+'">View files â¸</button></div></div>',p="border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:10px 12px;margin-top:10px;background:rgba(255,255,255,.03)";return e.collapsed?'<details style="'+p+'"><summary style="cursor:pointer;color:#cfd3dc;font-size:13px">'+e.icon+" "+(0,a.ZD)(e.label)+" <span class='muted'>("+t.length+", collapsed)</span></summary><div style='margin-top:8px'>"+l+"</div></details>":'<div style="'+p+'">'+l+"</div>"}).join("");if(!d)return;let l=er(i,n),p=document.createElement("div");p.innerHTML='<div style="margin-top:18px"><div style="font-size:11px;text-transform:uppercase;color:#8b8595;letter-spacing:.04em;margin-bottom:2px">Library (not tied to one competition)</div>'+d+function(e){if(!e.length)return"";let t=e.map((e,t)=>{let i=e.paused?"⸠stopped"+(e.pausedBy?" by "+(0,a.ZD)(String(e.pausedBy)):""):e.live?"\uD83D\uDFE2 running now":!1===e.paused?"⪠in rotation":"",n=(e,i)=>'<button class="btn btn-ghost btn-sm" data-mt-ao="'+e+'" data-mt-ao-i="'+t+'" style="padding:2px 8px;white-space:nowrap">'+i+"</button>",o=!0===e.paused?n("resume","â¶ Use again"):!1===e.paused?n("pause","⸠Stop using"):n("pause","⸠Stop using")+" "+n("resume","â¶ Use again");return'<div style="display:flex;justify-content:space-between;gap:10px;align-items:center;padding:6px 0;border-top:1px solid rgba(255,255,255,.08)"><div style="min-width:0;flex:1"><div style="color:#e8e6ef;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="'+(0,a.ZD)(e.name)+'">'+(0,a.ZD)(e.name)+"</div>"+(i?'<div style="font-size:11.5px;color:#a9a3b5">'+i+"</div>":"")+'</div><div style="flex:none;display:flex;gap:6px">'+o+"</div></div>"}).join("");return'<details style="border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:10px 12px;margin-top:10px;background:rgba(255,255,255,.03)"><summary style="cursor:pointer;color:#fff;font-size:14px;font-weight:700">⯠Always-On files â stop or use again, one by one <span class="muted" style="font-weight:500;font-size:12px">('+e.length+')</span></summary><div style="font-size:12px;color:#a9a3b5;margin:6px 0 4px">Stopping a file only stops AdPilotX picking it; the video in the Drive is never changed or deleted. The button fills in a message â press Send.</
1div>'+t+"</details>"}(l)+"</div>",t.appendChild(p),p.addEventListener("click",t=>{let i=t.target.closest("[data-mt-ao]");if(!i)return;t.preventDefault();let n=l[Number(i.getAttribute("data-mt-ao-i"))];n&&n.driveId&&(e._mt.msgDraft=("pause"===i.getAttribute("data-mt-ao")?"STOP USING: ":"USE AGAIN: ")+n.driveId+" â "+n.name,e._mt.view="msg",M(e),Z(e))}),p.querySelectorAll("[data-mt-lib]").forEach(t=>t.addEventListener("click",i=>{i.preventDefault();let a=t.getAttribute("data-mt-lib"),d=eo.find(e=>e.key===a);if(!d)return;let l=(Array.isArray(n[a])?n[a]:[]).map(s);eJ(e,{title:d.icon+" "+d.label,subtitle:d.hint,files:l,usage:S(l,o)||A(r[a]),ads:o,noPush:"wip"===a})}))}(e,d)}(e):"active"===p?function(e){!function(e){try{let t=e.ownerDocument||document;if(t.getElementById("mt-wide-css"))return;let i=t.createElement("style");i.id="mt-wide-css",i.textContent=ef,(t.head||t.body||e).appendChild(i)}catch(e){}}(e);let{needs:t}=e._mt,i=e.querySelector("#mt-body"),n=e.querySelector("#mt-summary"),o=e._mt.adsView||(e._mt.adsView={sort:"roas",dir:"desc",show:"live",tiny:!1,win:"d7"}),r=new Set((t&&t.adsets||[]).filter(e=>e&&e.learning).map(e=>String(e.id))),s=(t&&t.ads||[]).filter(Boolean).map(e=>r.has(String(e.adsetId))?Object.assign({},e,{learning:!0}):e),d=s.filter(e=>/ACTIVE/i.test(e.status||""));if(!s.length){n.innerHTML=ec(t),i.innerHTML='<div class="notice">No ad data yet â waiting for the next AdPilotX snapshot (hourly).</div>';return}e.querySelector("#mt-controls").innerHTML='<div style="display:flex;gap:14px;flex-wrap:wrap;align-items:center;font-size:13px"><label><b>Period:</b> <select id="mt-ads-window" class="btn btn-ghost btn-sm" style="padding:4px 8px">'+c.map(e=>es(e.k,o.win,e.label)).join("")+'</select></label><label>Show: <select id="mt-ads-show" class="btn btn-ghost btn-sm" style="padding:4px 8px">'+es("live",o.show,"Live ads only")+es("all",o.show,"All ads in the snapshot (incl. paused ones linked to a Drive file)")+'</select></label><label style="display:inline-flex;align-items:center;gap:6px;font-size:13px"><input type="checkbox" id="mt-ads-tiny"'+(o.tiny?" checked":"")+'> Also show the tiny tests (they spend almost nothing)</label><span class="muted" style="font-size:12px">Click a column heading to sort \xb7 click a row for the ad detail \xb7 click a thumbnail to preview.</span></div>',e.querySelector("#mt-ads-show").addEventListener("change",t=>{o.show=t.target.value,Z(e)});let l=e.querySelector("#mt-ads-window");l&&l.addEventListener("change",t=>{o.win=t.target.value,Z(e)});let p=e.querySelector("#mt-ads-tiny");p&&p.addEventListener("change",t=>{o.tiny=!!t.target.checked,Z(e)});let u="all"===o.show?s:d,f=o.tiny?0:u.filter(e=>"tiny"===b(e)).length,k=(o.tiny?u:u.filter(e=>"tiny"!==b(e))).slice(),S=em[o.sort]?o.sort:"roas",A=em[S],D="asc"===o.dir?1:-1;k.sort((e,t)=>{let i,n;return y[b(e)].order-y[b(t)].order||(i=A(e,o.win),(i<(n=A(t,o.win))?-1:+(i>n))*D)||String(e.name||"").localeCompare(String(t.name||""))});let z=k.map(N),_=d.filter(e=>"high"===v(e.frequency)).length,T=d.filter(e=>"tired"===v(e.frequency)).length,P=d.filter(e=>2>Number(e.roas||0)).length,q=s.filter(e=>!/ACTIVE/i.test(e.status||"")&&Number(e.roas||0)>=1.5).length;n.innerHTML=V("live",d.length,"#138c60")+V("frequency too high",_,"#e5484d")+V("getting tired",T,"#e5a23c")+V("under 2\xd7",P,"#e5484d")+(q?V("proven paused â eligible for re-add",q,"#3987e5"):"")+'<div style="margin-top:8px;padding:10px 12px;border:1px solid #e3e3ea;border-radius:10px;background:#fbfaff;font-size:13px;color:#17141f;line-height:1.55"><b>Read this first.</b> '+(0,a.ZD)(t.adsMoney&&t.adsMoney.line||"Biggest spenders first. AdPilotX is still working out which adverts are the big ones â that lands on its next hourly check.")+(f?" <b>"+f+"</b> tiny test"+(1===f?" is":"s are")+" hidden â tick the box above to see them.":"")+'<br><span class="muted">Showing <b>'+(0,a.ZD)(m(o.win).label)+"</b> â change it with the Period box above. âSales â today onlyâ is always just today, which is why an advert can show a good figure for the week and still say 0 today. A dash means AdPilotX has not collected that period yet. BIG SPENDER / TINY TEST is always judged on the last 7 days.</span></div>"+ec(t);let I=(e,t)=>"<th data-mt-sort='"+e+"' style='padding:8px;
1cursor:pointer;white-space:nowrap;user-select:none' title='Sort by "+(0,a.ZD)(t)+"'>"+(0,a.ZD)(t)+(S===e?D>0?" â²":" â¼":" <span style='color:#c9c9d3'>â</span>")+"</th>",L=document.createElement("div");L.innerHTML="<div class=\"mt-wide\" style=\"overflow-x:auto;border:1px solid #e3e3ea;border-radius:12px;background:#fff;color:#17141f\"><table style=\"width:100%;border-collapse:collapse;font-size:13px\"><thead><tr style='text-align:left;color:#8b8595;font-size:11px;text-transform:uppercase;background:#fafafc'><th style='padding:8px'></th><th style='padding:8px'>How big</th>"+I("name","Advert")+I("status","Status")+I("roas","Money back â "+m(o.win).short)+I("freq","How often people see it")+I("purchases","Sales â "+m(o.win).short)+I("today","Sales â today only")+I("file","Video file")+I("plan","What happens next")+"</tr></thead><tbody>"+k.map((e,t)=>{var i,n,r,s;let d,l,p,u,c;return i=e,n=t,r=z[t],d=Number(g(i,s=(s=o.win)||"d7")||0),l=Number(i.frequency||0),p=/ACTIVE/i.test(i.status||""),u=i.image?'<img data-mt-preview="'+n+'" src="'+(0,a.ZD)(i.image)+'" alt="" style="width:44px;height:44px;object-fit:cover;border-radius:8px;cursor:zoom-in;display:block" loading="lazy" />':'<div style="width:44px;height:44px;border-radius:8px;background:#f0f0f4"></div>',c=i.source?'<span title="'+(0,a.ZD)(("fuzzy"===i.source.confidence?"â probable â ":"exact â ")+(eF[i.source.via]||i.source.via||""))+'" style="font-size:12px;display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle">'+("fuzzy"===i.source.confidence?"â ":"")+(0,a.ZD)(i.source.driveName||i.source.slug||"")+"</span>":'<span class="muted" style="font-size:12px">â</span>',"<tr data-mt-adrow='"+n+"' style='border-top:1px solid #eee;cursor:pointer'><td style='padding:6px 8px'>"+u+"</td><td style='padding:6px 8px'>"+x(i)+"</td><td style='padding:6px 8px;min-width:180px'><div style='font-weight:800;color:#17141f;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap' title='"+(0,a.ZD)(i.name||"")+"'>"+(0,a.ZD)(i.name||"(unnamed ad)")+"</div><div class='muted' style='font-size:11px;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap'>"+(0,a.ZD)(i.adset||i.campaign||"")+"</div></td><td style='padding:6px 8px;white-space:nowrap;font-weight:700;color:"+(p?"#138c60":"#8b8595")+"'>"+(i.learning?F(!0)+"<br>":"")+(p?"\uD83D\uDFE2 live":"⸠"+(0,a.ZD)(String(i.status||"paused").toLowerCase().replace(/_/g," "))+(i.source&&i.source.driveId&&!/tiktok|no[\s_-]?music/i.test(i.source.driveName||"")?"<br><button class='btn btn-primary btn-sm' data-mt-pushad='"+n+"' title='AdPilotX puts this video live again in the best ad set right now' style='padding:2px 8px;margin-top:4px;white-space:nowrap'>\uD83D\uDE80 Push live</button>":""))+"</td><td style='padding:6px 8px;font-weight:800;color:"+K(d)+"'>"+(d?d.toFixed(2)+"\xd7":'<span class="muted">â</span>')+"</td><td style='padding:6px 8px'>"+w(l)+"</td><td style='padding:6px 8px'>"+(null!=h(i,s)?(0,a.ZD)(String(h(i,s))):'<span class="muted">â</span>')+"</td><td style='padding:6px 8px;white-space:nowrap'>"+function(e){if(null==e.purchasesToday&&null==e.roasToday)return'<span class="muted">â</span>';let t=Number(e.purchasesToday||0),i=Number(e.roasToday||0);return(0,a.ZD)(String(t))+(1===t?" sale":" sales")+(i?' \xb7 <b style="color:'+K(i)+'">'+i.toFixed(2)+"\xd7</b>":"")}(i)+"</td><td style='padding:6px 8px'>"+c+"</td><td style='padding:6px 8px;font-weight:700;color:"+r.c+"'>"+(r.auto?"\uD83E\uDD16 ":"")+(0,a.ZD)(r.t)+"</td></tr>"}).join("")+'</tbody></table></div><div class="muted" style="font-size:11.5px;margin-top:8px">\uD83E\uDD16 means AdPilotX does it on its own â you do not need to do anything. It switches off adverts that lose money, swaps in a fresh video when people have seen one too many times, and puts more money behind the ones that are working. When it needs a new video from you, it shows up as a job on the \uD83D\uDCCB Tasks tab.</div>',i.innerHTML="",i.appendChild(L),L.addEventListener("click",i=>{let n=i.target.closest("[data-mt-sort]");if(n){let t=n.getAttribute("data-mt-sort");o.sort===t?o.dir="asc"===o.dir?"desc":"asc":(o.sort=t,o.dir="name"===t||"file"===t||"plan"===t||"status"===t?"asc":"desc"),Z(e);return}let r=i.target.closest("[data-mt-preview]");if(r){var s,d;let t;i.stopPropagation();let n=k[Number(r.getAttribute("data-mt-preview"))];n&&(s=e,d={image:n.image,title:n.name},(t=s.querySelector("#mt-modal"))&&(t.innerHTML='<div id="mt-modal-bg" style="position:fixed;inset:0;background:rgba(0,0,0,.72);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px"><div style="max-width:90vw;max-height:90vh;text-align:center">
1'+(d.image?'<img src="'+(0,a.ZD)(d.image)+'" alt="" style="max-width:90vw;max-height:80vh;border-radius:12px;box-shadow:0 10px 40px rgba(0,0,0,.5)" />':"")+'<div style="color:#fff;margin-top:10px;font-size:13px">'+(0,a.ZD)(d.title||"")+'</div><div style="color:#bbb;margin-top:6px;font-size:12px">Click anywhere to close</div></div></div>',t.querySelector("#mt-modal-bg").addEventListener("click",()=>{t.innerHTML=""})));return}let l=i.target.closest("[data-mt-pushad]");if(l){i.stopPropagation();let n=k[Number(l.getAttribute("data-mt-pushad"))];if(n){let i=eQ(e,n,eg(t,n));i&&e0(i,n)}return}let p=i.target.closest("[data-mt-adrow]");if(p){let i=k[Number(p.getAttribute("data-mt-adrow"))];i&&eQ(e,i,eg(t,i))}})}(e):"drive"===p?function(e){var t;let i,n,o,r,{needs:s}=e._mt,d=e.querySelector("#mt-body"),l=e.querySelector("#mt-summary"),p=s&&s.drive||{},u=(s&&s.newDriveMedia||[]).length;l.innerHTML=s&&s.ok?(p.ok?V("files in Drive",p.count||0,"#138c60"):'<span style="color:#c77;font-size:12px">AdPilotX Drive scan not connected</span>')+V("recently created",u,"#3987e5")+ec(s):'<span class="muted" style="font-size:12px">AdPilotX snapshot not ready â the file manager below still works.</span>',d.innerHTML='<details style="border:1px solid #e3e3ea;border-radius:12px;padding:10px 14px;margin-bottom:14px;background:#fff"><summary style="cursor:pointer;font-weight:800;color:#17141f;font-size:14px">\uD83D\uDDC2 Drive rundown from AdPilotX <span class="muted" style="font-weight:500;font-size:12px">('+u+' recently created \xb7 click to expand)</span></summary><div style="margin-top:10px">'+(s&&s.ok?function(e){let t=(e&&e.newDriveMedia||[]).slice().sort((e,t)=>new Date(t.modifiedTime||0)-new Date(e.modifiedTime||0));if(!t.length)return'<div class="notice">No recently-created media in the snapshot yet.</div>';let i={};return t.forEach(e=>{let t=(e.path||"").split("/")[0]||"Drive";(i[t]=i[t]||[]).push(e)}),Object.keys(i).map(e=>'<div style="margin-bottom:14px"><div style="font-weight:800;color:#17141f;font-size:14px;margin-bottom:6px">\uD83D\uDCC1 '+(0,a.ZD)(e)+" <span class='muted' style='font-weight:500;font-size:12px'>("+i[e].length+")</span></div>"+i[e].map(e=>'<div style="display:flex;justify-content:space-between;gap:10px;align-items:center;border:1px solid #eee;border-radius:9px;padding:8px 11px;margin-bottom:6px;background:#fff"><div style="min-width:0"><div style="font-size:13px;font-weight:600;color:#17141f;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(0,a.ZD)(e.name||"")+'</div><div class="muted" style="font-size:11px">'+(0,a.ZD)(L(e.modifiedTime))+"</div></div>"+(e.link?'<a class="btn btn-ghost btn-sm" href="'+(0,a.ZD)(e.link)+'" target="_blank" rel="noopener" style="flex:none">Open â¸</a>':"")+"</div>").join("")+"</div>").join("")}(s):'<div class="notice">Waiting for the first AdPilotX snapshot.</div>')+'</div></details><div id="mt-fm" style="border:1px solid #e3e3ea;border-radius:12px;background:#fff;color:#17141f;overflow:hidden"><div id="mt-fm-bar" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:10px 12px;border-bottom:1px solid #eee;background:#fafafc"></div><div id="mt-fm-list" style="min-height:160px;position:relative"></div><div id="mt-fm-queue"></div><input id="mt-fm-file" type="file" multiple accept="video/*,image/*" style="display:none" /></div><div class="muted" style="font-size:11.5px;margin-top:8px">Drop videos / images onto the list to upload them into the open folder (max 2 GB each). âTrashâ moves to the Drive bin â nothing is deleted permanently from here.</div>',i=(t=e).querySelector("#mt-fm"),n=t.querySelector("#mt-fm-list"),o=t.querySelector("#mt-fm-file"),r=ey(t),i.addEventListener("click",e=>{let n=e.target.closest("[data-fm]");n&&i.contains(n)&&(e.preventDefault(),eS(t,n.getAttribute("data-fm"),n.getAttribute("data-id")||"",n))}),i.addEventListener("keydown",e=>{let i=e.target;i instanceof HTMLInputElement&&("Enter"===e.key&&i.hasAttribute("data-fm-enter")&&(e.preventDefault(),eS(t,i.getAttribute("data-fm-enter"),i.getAttribute("data-id")||"",i)),"Escape"===e.key&&(r.editingId=null,r.creating=!1,ek(t)))}),o.addEventListener("change",()=>{eA(t,Array.from(o.files||[])),o.value=""}
1),["dragenter","dragover"].forEach(e=>n.addEventListener(e,e=>{ev(e)&&(e.preventDefault(),e.dataTransfer.dropEffect="copy",r.dragging||(r.dragging=!0,n.style.outline="3px dashed #3987e5",n.style.outlineOffset="-6px",n.style.background="#eef4ff"))})),["dragleave","dragend"].forEach(e=>n.addEventListener(e,e=>{"dragleave"===e.type&&n.contains(e.relatedTarget)||(r.dragging=!1,n.style.outline="",n.style.background="")})),n.addEventListener("drop",e=>{ev(e)&&(e.preventDefault(),r.dragging=!1,n.style.outline="",n.style.background="",eA(t,Array.from(e.dataTransfer.files||[])))}),n.addEventListener("error",e=>{e.target&&"IMG"===e.target.tagName&&(e.target.style.display="none")},!0);let c=ey(e);ew(e,c.folderId||null)}(e):"msg"===p?(i=(t=e).querySelector("#mt-body"),t.querySelector("#mt-summary").innerHTML='<span class="muted" style="font-size:12.5px">Type what you need and press Send. AdPilotX checks every 30 seconds and replies right here â usually within a minute. Every staff member sees this same conversation.</span>',n=t._mt&&t._mt.msgDraft||"",t._mt&&(t._mt.msgDraft=""),i.innerHTML='<div style="border:1px solid #e3e3ea;border-radius:12px;background:#fbfaff;padding:12px 14px;margin-bottom:12px;font-size:13px;line-height:1.6;color:#17141f"><b>How this works</b><br>1. Want an answer? Tap a purple question button. You get a reply in plain English.<br>2. Want something changed? Tap a grey button, type the name of the advert or competition, press <b>Send</b>. You can also just type it in your own words.<br>3. <b>Nothing changes straight away.</b> AdPilotX tells you what it is about to do and waits. Reply <b>YES</b> to go ahead or <b>NO</b> to leave it.<br>4. Money, new campaigns and who sees the adverts are the owner\'s decisions â those get passed to him.</div><div style="font-size:12px;font-weight:800;color:#7256ec;margin:2px 0 6px">One-tap questions â AdPilotX answers in plain English</div><div id="mt-simple" style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px">'+eP.map(e=>'<button class="btn btn-primary btn-sm" data-mt-simple="'+e.k+'" style="padding:5px 10px">'+e.label+"</button>").join("")+'</div><div style="font-size:12px;font-weight:800;color:#77708a;margin:2px 0 6px">Change something â tap one, type the name, press Send (AdPilotX asks you first)</div><div id="mt-quick" style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px">'+eT.map(e=>'<button class="btn btn-ghost btn-sm" data-mt-quick="'+e.k+'" style="padding:5px 10px">'+e.label+"</button>").join("")+'</div><div style="display:flex;gap:8px;margin-bottom:14px"><textarea id="mt-msg-input" rows="2" placeholder="Type here â e.g. pause the kawasaki advert, or ask a question." style="flex:1;min-width:0;padding:10px;border:1px solid #d7d7e0;border-radius:10px;font:inherit;font-size:14px;resize:vertical">'+(0,a.ZD)(n)+'</textarea><button id="mt-msg-send" class="btn btn-primary" style="flex:none">Send â¸</button></div><div id="mt-filter" style="display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-bottom:8px"><button class="btn btn-sm" data-mt-filter="all" style="padding:4px 10px">All</button><button class="btn btn-sm" data-mt-filter="staff" style="padding:4px 10px">\uD83D\uDCAC Staff chat</button><button class="btn btn-sm" data-mt-filter="reports" style="padding:4px 10px">\uD83D\uDCCB Reports & alerts</button><button class="btn btn-sm" data-mt-filter="actions" style="padding:4px 10px" title="Pause / push-live requests sent from an ad or a Drive file, with AdPilotX\'s result. Kept out of the chat on purpose.">⸠Actions</button><button class="btn btn-sm btn-ghost" data-mt-clear="1" style="padding:4px 10px" title="Tidy your own view. Nothing is deleted â everyone else still sees the full conversation.">\uD83E\uDDF9 Clear chat</button><button class="btn btn-sm btn-ghost" data-mt-history="1" style="padding:4px 10px;display:none" title="Show the messages you cleared">\uD83D\uDD58 Show history</button><span id="mt-new" style="display:none;margin-left:auto;font-size:12px;font-weight:800;color:#7256ec">â New activity</span></div><div id="mt-thread"></div>',o=t.querySelector("#mt-msg-send"),d=t.querySelector("#mt-msg-input"),l=()=>{let e=d.value,t=e.indexOf("<"),i=t>=0?e.indexOf(">",t):-1;d.focus(),t>=0&&i>t?d.setSelectionRange(t,i+1):d.setSelectionRange(e.length,e.length)},t.querySelector("#mt-quick").addEventListener("click",e=>{let t=e.target.closest("[data-mt-quick]");if(!t)return;let i=eT.find(e=>e.k===t.getAttribute("data-mt-quick"));i&&(d.value=i.text,l())}),t.querySelector("#mt-simple").addEventListener("click",async e=>{let i=e.target.closest("[data-mt-simple]");if(!i||i.disabled)return;let n=eP.find(e=>e.k===i.getAttribute("data-mt-simple"));if(!n)return;i.disabled=!0;let o=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"message",text:n.text})});o&&o.ok?((0,a.oR)("Asked â â AdPilotX answers here within a minute"),await eM(t),eq(t)):(0,a.oR)("Couldn't send: "+(o&&(o.detail||o.error)||"")),i.disabled=!1}),n&&l(),t.querySelector("#mt-filter").addEventListener("click",e=>{if(e.target.closest("[data-mt-clear]")){try{localStorage.setItem(e_,String(Date.now()))}catch(e){}t._mt.showHistory=!1,eE(t,!1),(0,a.oR)("Chat cleared for you â nothing was deleted");return}if(e.target.closest("[data-mt-history]")){t._mt.showHistory=!t._mt.showHistory,eE(t,!1),(0,a.oR)(t._mt.showHistory?"Showing the full history":"Hiding cleared messages");return}let i=e.target.closest("[data-mt-filter]");i&&(t._mt.threadFilter=i.getAttribute("data-mt-filter"),eE(t,!1))}),o.addEventListener("click",async()=>{let e=(d.value||"").trim();if(!e)return;if(/<[^<>]*>/.test(e)){(0,a.oR)("Fill in the <â¦> parts first"),l();return}o.disabled=!0;let i=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"message",text:e})});i&&i.ok?(d.value="",(0,a.oR)("Sent â â AdPilotX replies here within a minute"),await eM(t),eq(t)):(0,a.oR)("Couldn't send: "+(i&&(i.detail||i.error)||"")),o.disabled=!1}),eM(t).then(()=>eq(t))):"review"===p?function e(t){let i=t.querySelector("#mt-body");t.querySelector("#mt-summary").innerHTML='<span class="muted" style="font-size:12.5px">Every Meta advert is checked against our advertising rules each hour. Running adverts that need fixing also alert staff. Fix one below, or tell AdPilotX in the chat: <b>what needs sorting</b>, <b>sort them</b>, or <b>EDIT: <ad> â <new text></b>.</span>';let n=t._mt.reviewFilter||"needs";return i.innerHTML='<div id="mt-rf" style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px">'+eZ.map(([e,t])=>'<button class="btn btn-sm '+(e===n?"btn-primary":"btn-ghost")+'" data-mt-rf="'+e+'" style="padding:4px 10px">'+t+"</button>
1").join("")+'</div><div id="mt-rlist"><div class="muted">Loadingâ¦</div></div>',i.querySelector("#mt-rf").addEventListener("click",i=>{let n=i.target.closest("[data-mt-rf]");n&&(t._mt.reviewFilter=n.getAttribute("data-mt-rf"),e(t))}),eH(t,n)}(e):"platforms"===p?function(e){let t,{needs:i}=e._mt,n=e.querySelector("#mt-body"),o=e.querySelector("#mt-summary"),r=i&&i.platforms||null,s=e._mt.platView||(e._mt.platView={tab:"facebook"});if(!r){o.innerHTML=ec(i),n.innerHTML='<div class="notice">No platform data yet â it arrives with the next hourly AdPilotX snapshot.</div>';return}let d=X.find(e=>e.key===s.tab)||X[0],l=r[d.src]||null;if(e.querySelector("#mt-controls").innerHTML='<div style="display:flex;gap:6px;flex-wrap:wrap">'+X.map(e=>{let t=r[e.src]||{},i=Array.isArray(t.needs)?t.needs.length:0;return'<button data-mt-plat="'+e.key+'" class="btn btn-sm '+(e.key===d.key?"btn-primary":"btn-ghost")+'">'+(0,a.ZD)(e.label)+(i?' <span style="margin-left:4px;padding:1px 7px;border-radius:999px;background:#d64545;color:#fff;font-size:11px;font-weight:800">'+i+"</span>":"")+"</button>"}).join("")+"</div>",e.querySelector("#mt-controls").onclick=t=>{let i=t.target.closest("[data-mt-plat]");i&&(s.tab=i.getAttribute("data-mt-plat"),Z(e))},!l||!1===l.ok){o.innerHTML=ec(i),n.innerHTML='<div class="notice">'+(0,a.ZD)(d.label)+" â "+(0,a.ZD)(l&&l.note||"not connected to AdPilotX yet.")+"</div>";return}let p=(t=Array.isArray(l&&l.ads)?l.ads:[],d.place?t.filter(e=>e.placements&&e.placements[d.place]).map(e=>Object.assign({},e,{purchases:e.placements[d.place].purchases,roas:e.placements[d.place].roas})):t);o.innerHTML=V("live",p.filter(e=>/ACTIVE|ENABLED|DELIVERING/i.test(String(e.status||""))).length,"#138c60")+V("needs sorting",(l.needs||[]).length,"#e5484d")+'<span class="muted" style="font-size:12px">'+(0,a.ZD)(H[l.mode]||l.mode||"")+(l.policy?" \xb7 "+(0,a.ZD)(l.policy):"")+(d.place?" \xb7 sales and ROAS on "+(0,a.ZD)(d.label)+" only, last 7 full days":"")+"</span>"+ec(i);let u=(l.needs||[]).length?'<div style="border:1px solid #f1c4c4;background:#fff6f6;color:#17141f;border-radius:12px;padding:10px 12px;margin-bottom:12px"><b>Needs sorting</b><ul style="margin:6px 0 0;padding-left:18px">'+l.needs.slice(0,30).map(e=>"<li style='margin:3px 0'><b>"+(0,a.ZD)(e.title||"")+"</b>"+(e.name?" â "+(0,a.ZD)(e.name):"")+(e.detail?'<div class="muted" style="font-size:12px">'+(0,a.ZD)(e.detail)+"</div>":"")+"</li>").join("")+"</ul></div>":'<div class="muted" style="font-size:12.5px;margin-bottom:10px">â
Nothing needs sorting on '+(0,a.ZD)(d.label)+" right now.</div>",c=p.slice(0,200).map(e=>"<tr style='border-top:1px solid #eee'><td style='padding:6px 8px'>"+(0,a.ZD)(e.name||"")+'<div class="muted" style="font-size:11.5px">'+(0,a.ZD)([e.campaign,e.adset].filter(Boolean).join(" ⺠"))+"</div></td><td style='padding:6px 8px;white-space:nowrap'>"+(0,a.ZD)(e.statusLabel||e.status||"")+"</td><td style='padding:6px 8px'>"+(null!=e.roas&&""!==e.roas&&Number(e.roas)>0?'<b style="color:'+K(Number(e.roas))+'">'+Number(e.roas).toFixed(2)+"\xd7</b>":'<span class="muted">â</span>')+"</td><td style='padding:6px 8px'>"+(null!=e.purchases&&""!==e.purchases?(0,a.ZD)(String(e.purchases)):"â")+"</td></tr>").join("");n.innerHTML=u+(p.length?'<div style="overflow-x:auto;border:1px solid #e3e3ea;border-radius:12px;background:#fff;color:#17141f"><table style="width:100%;border-collapse:collapse;font-size:13px"><thead><tr style="text-align:left;color:#8b8595;font-size:11px;text-transform:uppercase;background:#fafafc"><th style="padding:8px">'+("google"===d.src?"Campaign":"Advert")+'</th><th style="padding:8px">Status</th><th style="padding:8px">ROAS</th><th style="padding:8px">'+("google"===d.src?"Conversions":"Bookings")+"</th></tr></thead><tbody>"+c+"</tbody></table></div>":'<div class="notice">No adverts on '+(0,a.ZD)(d.label)+" in the snapshot.</div>")}(e):"insights"===p?function(e){let{needs:t}=e._mt,i=e.querySelector("#mt-body"),n=e.querySelector("#mt-summary"),o=t&&t.insights||null;if(!o){n.innerHTML=ec(t),i.innerHTML='<div class="notice">AdPilotX is still building its memory â the first insights arrive after its next nightly learning run.</div>';return}let r=(Array.isArray(o.comps)?o.comps:[]).filter(e=>!q(e,t)&&!P({slug:e.slug,title:e.title||e.line||""},t)),s=e=>r.filter(t=>t.verdict===e).length;n.innerHTML=V("ahead of history",s("ahead")+s("best_ever"),"#138c60")+V("behind history",s("behind"),"#e5484d")+'<span class="muted" style="font-size:12px">Learned from '+(0,a.ZD)(String(o.learnedFrom&&o.learnedFrom.competitions||0))+" competitions and "+(0,a.ZD)(String(o.learnedFrom&&o.learnedFrom.adverts||0))+" adverts \xb7 updated "+(0,a.ZD)(o.generatedAt?L(o.generatedAt):"â")+"</span>"+ec(t);let d=(e,t)=>e&&e.length?"<ul style='margin:6px 0 0;padding-left:18px'>"+e.slice(0,20).map(e=>"<li style='margin:4px 0'>"+(0,a.ZD)(e.text||"")+"</li>").join("")+"</ul>":'<div class="muted" style="font-size:12.5px;margin-top:4px">'+(0,a.ZD)(t)+"</div>",l=(e,t)=>
1'<div style="border:1px solid #e3e3ea;border-radius:12px;background:#fff;color:#17141f;padding:12px 14px;margin-bottom:12px"><b>'+(0,a.ZD)(e)+"</b>"+t+"</div>",p=r.map(e=>{let t=R[e.verdict]||R.new;return"<li style='margin:6px 0;list-style:none'><span style='display:inline-block;min-width:92px;font-weight:800;color:"+t[1]+"'>"+t[0]+" "+(0,a.ZD)(t[2])+"</span>"+(0,a.ZD)(e.line||e.title||"")+"</li>"}).join("");i.innerHTML=l("How each live competition compares with similar past ones",r.length?"<ul style='margin:6px 0 0;padding:0'>"+p+"</ul>":d([],"No live competitions right now."))+l("â
What's working",d(o.working,"Not enough history yet to say â AdPilotX keeps learning from every advert."))+l("â ï¸ What isn't working",d(o.notWorking,"Nothing is consistently failing right now."))+'<div class="muted" style="font-size:11.5px">\uD83E\uDD16 AdPilotX uses all of this itself â which videos, audiences and wording it tries first, and how hard it pushes each competition. Nothing here needs you to act.</div>'}(e):"rejected"===p?function(e){let t=e._mt.needs,i=e.querySelector("#mt-body"),n=e.querySelector("#mt-summary"),o=O(t),r='<div style="border:2px solid #d64545;border-radius:12px;background:#fdecea;color:#5c1111;padding:12px 14px;margin-bottom:12px;font-size:13px"><b>â Never switch these back on or resubmit them.</b> Sending a rejected advert back for review again and again can get the whole ad account banned. Make a <b>new</b> advert with the wording or video fixed and upload it to Drive â AdPilotX checks it and does the rest. AdPilotX will never switch a rejected advert back on.</div>';if(!o){n.innerHTML=ec(t),i.innerHTML=r+'<div class="notice">AdPilotX lists rejected adverts from every social after its next run.</div>';return}let s=o.filter(e=>e&&!1!==e.still),d=o.filter(e=>e&&!1===e.still);if(n.innerHTML=V("rejected now",s.length,"#e5484d")+V("earlier (still never switched back on)",d.length,"#666")+ec(t),!o.length){i.innerHTML=r+'<div class="notice">â
No rejected adverts on any social right now.</div>';return}let l={};for(let e of o)(l[e.platform]=l[e.platform]||[]).push(e);i.innerHTML=r+Object.keys(l).map(e=>'<div style="border:1px solid #e3e3ea;border-radius:12px;background:#fff;color:#17141f;padding:12px 14px;margin-bottom:12px"><b>'+(0,a.ZD)(C[e]||e)+"</b> â "+l[e].length+" advert"+(1===l[e].length?"":"s")+(j[e]?'<div style="margin:6px 0 2px;padding:8px 10px;border-radius:8px;background:#eef6ff;color:#12324d;font-size:12.5px"><b>\uD83C\uDFAC How to fix it (make a new advert):</b> '+(0,a.ZD)(j[e])+"</div>":"")+"<ul style='margin:6px 0 0;padding-left:18px'>"+l[e].map(e=>"<li style='margin:6px 0'><b>"+(0,a.ZD)(e.name||e.id)+"</b>"+(e.where?' <span class="muted" style="font-size:12px">('+(0,a.ZD)(e.where)+")</span>":"")+'<div style="font-size:12.5px;margin-top:2px"><b>Why:</b> '+(0,a.ZD)(e.reason||"the platform gave no reason â check its ads manager")+'</div><div class="muted" style="font-size:12px">'+(!1===e.still?"No longer showing as rejected â still never switched back on. ":"Rejected ")+"since "+(0,a.ZD)(e.firstSeen?L(e.firstSeen):"â")+" \xb7 fix: make a new advert, don't resubmit this one</div></li>").join("")+"</ul></div>").join("")+'<div class="muted" style="font-size:11.5px">\uD83E\uDD16 AdPilotX checks every social for rejections every run and keeps this list; it never resubmits or re-enables any of them.</div>'}(e):"audiences"===p?function(e){let{needs:t}=e._mt,i=e.querySelector("#mt-body"),n=e.querySelector("#mt-summary"),o=t&&t.audiences||null;if(!o){n.innerHTML=ec(t),i.innerHTML='<div class="notice">No audience data yet â it arrives with the next hourly AdPilotX check.</div>';return}let r=o.saturated;n.innerHTML=V("audiences in use",(o.list||[]).length,"#3987e5")+V("warm-pool ad sets",o.warmPoolSets||0,"#7256ec")+(r?V("worn out","yes","#e5484d"):V("worn out","no","#138c60"))+'<div style="margin-top:8px;padding:10px 12px;border:1px solid '+(r?"#e5484d55":"#e3e3ea")+";border-radius:10px;background:"+(r?"#fff6f6":"#fbfaff")+';font-size:13px;line-height:1.55;color:#17141f"><b>'+(r?"â ï¸ The same people are seeing our adverts too often.":"â
People are not being over-shown our adverts.")+"</b><br>"+(0,a.ZD)(String(o.plain||""))+(null!=o.seenALot?'<br><span class="muted">
1Out of '+(o.peopleReached?Number(o.peopleReached).toLocaleString("en-GB"):"everyone")+" people reached in the last 7 days, <b>"+U(o.seenALot)+"</b> saw 11 or more of our adverts (healthy is under "+U(o.limitSeenALot)+")"+(null!=o.seenFarTooMuch?", and <b>"+U(o.seenFarTooMuch)+"</b> saw 31 or more":"")+".</span>":"")+"</div>"+ec(t),i.innerHTML="<div class=\"mt-wide\" style=\"overflow-x:auto;border:1px solid #e3e3ea;border-radius:12px;background:#fff\"><table style=\"width:100%;border-collapse:collapse;font-size:13px\"><thead><tr style='text-align:left;color:#8b8595;font-size:11px;text-transform:uppercase;background:#fafafc'><th style='padding:8px'>Who we are showing ads to</th><th style='padding:8px'>Ad sets</th><th style='padding:8px'>Money back â last 7 days</th><th style='padding:8px'>Sales</th><th style='padding:8px'>How often they see it</th><th style='padding:8px'>Examples</th></tr></thead><tbody>"+((o.list||[]).map(e=>"<tr style='border-top:1px solid #eee'><td style='padding:7px 8px;font-weight:700;color:#17141f;
1min-width:200px'>"+(0,a.ZD)(String(e.audience||""))+(e.advantage?' <span class="muted" style="font-size:11px">\xb7 Advantage+</span>':"")+"</td><td style='padding:7px 8px'>"+(0,a.ZD)(String(e.sets||0))+(e.learning?" "+F(!0):"")+"</td><td style='padding:7px 8px;font-weight:800;color:"+K(Number(e.roas||0))+"'>"+(e.roas?Number(e.roas).toFixed(2)+"\xd7":'<span class="muted">â</span>')+"</td><td style='padding:7px 8px'>"+(0,a.ZD)(String(e.purchases||0))+"</td><td style='padding:7px 8px'>"+(e.frequency?w(e.frequency):'<span class="muted">â</span>')+"</td><td style='padding:7px 8px;font-size:12px;color:#8b8595'>"+(0,a.ZD)((e.names||[]).slice(0,3).join(", "))+"</td></tr>").join("")||"<tr><td colspan='6' style='padding:12px'>No audiences running.</td></tr>")+'</tbody></table></div><div class="muted" style="font-size:11.5px;margin-top:8px">An âaudienceâ is the group of people Facebook shows an advert to. When a group has seen everything we have, the answer is a NEW video or a NEW audience â switching adverts off does not help.</div>'}(e):"campaigns"===p?function(e){let{needs:t}=e._mt,i=e.querySelector("#mt-body"),n=e.querySelector("#mt-summary"),o=t&&t.campaigns||[],r=t&&t.adsets||[],s=t&&t.ads||[];if(!o.length){n.innerHTML=ec(t),i.innerHTML='<div class="notice">No campaign data yet â it arrives with the next hourly AdPilotX check.</div>';return}let d=e._mt.campView||(e._mt.campView={open:null});n.innerHTML=V("campaigns",o.length,"#7256ec")+V("ad sets",r.length,"#3987e5")+V("still learning",r.filter(e=>e.learning).length,"#e5a23c")+'<span class="muted" style="font-size:12px">Tap a campaign to see its ad sets, then an ad set to see its adverts.</span>'+ec(t),i.innerHTML='<div class="mt-wide">'+o.map((e,t)=>{let i,n=d.open===t;return'<div style="border:1px solid #e3e3ea;border-radius:12px;background:#fff;margin-bottom:10px;padding:12px 16px"><div data-mt-camp="'+t+'" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;cursor:pointer">'+x({size:e.size})+"<b style='font-size:14px;color:#17141f;flex:1;
1min-width:200px'>"+(0,a.ZD)(String(e.name||""))+"</b>"+(e.roas?"<span style='font-weight:800;color:"+K(Number(e.roas))+"'>"+Number(e.roas).toFixed(2)+"\xd7</span>":"")+'<span class="muted" style="font-size:12px">'+e.live+" of "+e.sets+" ad sets live"+(e.learning?" \xb7 "+e.learning+" still learning":"")+" \xb7 "+(e.purchases||0)+' sales</span><span style="font-size:11.5px;color:#7256ec;font-weight:700">'+(n?"â¾ hide":"⸠open")+"</span></div>"+(n?(i=e.id,r.filter(e=>String(e.campaignId)===String(i)).map(e=>{let t=s.filter(t=>String(t.adsetId)===String(e.id));return'<div style="border-top:1px dashed #e3e3ea;padding:7px 0 7px 18px"><div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap"><b style=\'color:#17141f\'>'+(0,a.ZD)(String(e.name||""))+"</b>"+F(e.learning)+(e.roas?"<span style='font-weight:800;color:"+K(Number(e.roas))+"'>"+Number(e.roas).toFixed(2)+"\xd7</span>":"")+(e.frequency?w(e.frequency):"")+'</div><div class="muted" style="font-size:12px;margin-top:2px">Shown to: '+(0,a.ZD)(String(e.audience||"â"))+" \xb7 "+t.length+" advert"+(1===t.length?"":"s")+"</div>"+(t.length?'<div style="margin-top:4px;font-size:12px;color:#3a3442">'+t.slice(0,6).map(e=>"⢠"+(0,a.ZD)(String(e.name||""))+(e.roas?" â "+Number(e.roas).toFixed(2)+"\xd7":"")).join("<br>")+"</div>":"")+"</div>"}).join("")||'<div class="muted" style="padding:8px 0 8px 18px;font-size:12px">No ad sets in this campaign.</div>'):"")+"</div>"}).join("")+"</div>",i.querySelectorAll("[data-mt-camp]").forEach(t=>{t.addEventListener("click",()=>{let i=Number(t.getAttribute("data-mt-camp"));d.open=d.open===i?null:i,Z(e)})})}(e):function(e){var t;let i,{needs:n,states:o}=e._mt,s=e.querySelector("#mt-body"),d=e.querySelector("#mt-summary");if(!n||!n.ok)return Y(e,n);let l={};for(let e of o&&o.tasks||[])l[e.task_key]=e.status;let p=["done","not_needed","snoozed","removed"],u=function(e,t,i){let n=Number(i||Date.now()),a=t||{},o=[],s=[],d=new Set,l=e=>{let t=e?Date.parse(e):NaN;return Number.isNaN(t)?999:Math.max(0,(t-n)/864e5)},p={};for(let t of e||[])t.comp&&t.comp.slug&&(p[t.comp.slug]=t.comp.draw_at);for(let t of function(e,t){let i=Number(t||Date.now()),n=[];for(let t of e||[]){let e=t.comp||{},a=String(e.title||e.slug||"this competition").split(" â ")[0].split(" - ")[0].trim(),o=J(e.draw_at,i),r=e.draw_at?(Date.parse(e.draw_at)-i)/864e5:null;if(null==r||!(r<1)){if(t.noMedia){n.push({icon:"\uD83C\uDFA5",slug:e.slug,order:0+(null==o?99:o)/1e3,text:"Film a video for "+a+". Put it in its Drive folder."+$(o)});continue}if(t.liveAds>0&&Number(t.maxFreq||0)>=3.5){n.push({icon:"\uD83D\uDD01",slug:e.slug,order:1+(null==o?99:o)/1e3,text:"Make a NEW video for "+a+". People have seen the old one too many times."+$(o)});continue}t.liveAds>0&&t.judged&&Number(t.avgRoas||0)>0&&1>Number(t.avgRoas)&&n.push({icon:"\uD83D\uDD01",slug:e.slug,order:2+(null==o?99:o)/1e3,text:"Make a NEW video for "+a+". The one running now is not selling."+$(o)})}}return n.sort((e,t)=>e.order-t.order)}(e,n)){let i="\uD83C\uDFA5"===t.icon?"film":/too many times/.test(t.text)?"too_often":"new",a=(e||[]).find(e=>e.comp&&e.comp.slug===t.slug)||{comp:{}},r=el(a.comp.title||t.slug),s=l(a.comp.draw_at),p=$(J(a.comp.draw_at,n)).trim(),u="film"===i?"Film a video for "+r:"Make a NEW video for "+r,c="film"===i?"There is no video for it at all.":"too_often"===i?"People have seen the old one too many times.":"The video running now is not selling.";o.push({key:"job:"+t.slug+":"+i,p:ed[i],days:s,icon:t.icon,title:u,why:(c+" "+p).trim(),compName:r,how:"Film it with the sound on (one tall 9:16 and one 4:5) and put it in its Drive folder. AdPilotX does the rest."}),d.add(t.slug+":"+("film"===i?"film":"video"))}let u="Film them with the sound on (tall 9:16 and 4:5) and put them in the Drive. AdPilotX does the rest.",c=e=>o.some(t=>t.compName&&e&&t.compName.toLowerCase()===el(e).toLowerCase()),m=0,f=4,g=[];for(let t of a.mediaTeamActions||[]){var h;if(!t||"scoreboard"===t.type)continue;if(/^nothing for you/i.test(String(t.what||""))){s.push(String(t.title||t.text||"")+" â AdPilotX is doing this itself.");continue}let i=Number(((h=String((h=t.priority)||"").toUpperCase(),/^P[0-4]$/.test(h))?h:"HIGH"===h?"P1":"MEDIUM"===h?"P2":"LOW"===h?"P3":"P4").slice(1)),n=String(t.title||t.text||""),a=Number((n.match(/(\d+)\s+(?:NEW\s+VIDEOS|DIFFERENT)/i)||[])[1]||0),r=(n.match(/for (?:the competition )?[â"](.+?)[â"]/)||[])[1];if(!r&&"rotation_gap"===t.type){m+=a||1,f=Math.min(f,i),g.push(String(t.key));continue}if(r&&c(r))continue;let d=r?el(r):"",y=n,b=String(t.why||"").split(". ")[0];"thin_set"===t.type&&d?(y="Make "+(a||"some")+" different videos for "+d,b="People keep seeing the same few videos."):"supply_exhausted"===t.type&&d?(y="Film "+(a||"some")+" new videos for "+d,b="We have used every video we had for it."):"rotation_gap"===t.type&&d&&(y="Make "+(a||"some")+" new videos for "+d,b="Its old video stopped working and there is nothing left to swap in.");let x=Object.keys(p).find(t=>d&&el((e.find(e=>e.comp&&e.comp.slug===t)||{comp:{}}).comp.title).toLowerCase()===d.toLowerCase());o.push({key:String(t.key||n),p:i,days:l(x?p[x]:null),icon:"\uD83C\uDFAC",title:y,why:b?b.replace(/\.?$/,"."):"",how:u,compName:d,action:t})}for(let t of(m&&o.push({key:"general:"+g.join(","),keys:g,p:f,days:998,icon:"\uD83C\uDFAC",title:"Make "+m+" new general videos (winners, prizes, happy winners
1)",why:"Our adverts to past buyers and to new people have run out of fresh videos.",how:u}),function(e){let t=[],i=new Set((e.driveHasMedia||[]).map(e=>e.slug));for(let i of e.driveHasMedia||[])t.push({key:"attach:"+i.slug,type:"attach_media",priority:"medium",title:i.title,what:"Attach existing Drive creative to the competition (set its video).",detail:"Already in Drive: "+(i.files||[]).map(e=>e.name).join(", "),links:(i.files||[]).map(e=>e.link).filter(Boolean)});for(let n of e.awaitingMedia||[])i.has(n.slug)||t.push({key:"missing:"+n.slug,type:"missing_media",priority:"high",title:n.title,what:"Create + upload new creative to the Drive folder for this competition.",detail:"No creative anywhere yet (nothing matching in the Drive folder)."});for(let i of e.fatigue||[])t.push({key:"fatigue:"+(i.id||i.name),type:"fatigue",priority:"high"===i.severity?"high":"medium",title:i.name,what:"This competition's ad needs FRESH / more media - add new variants to the Drive folder.",detail:"ROAS "+Number(i.roas||0).toFixed(2)+(i.roasBefore?" (was "+Number(i.roasBefore).toFixed(2)+")":"")+" - audience seeing it too often.",roas:i.roas});for(let i of e.hygiene||[])t.push({key:i.key,type:"hygiene",priority:"low",title:i.title,what:i.detail,detail:""});return t.sort((e,t)=>(r[e.priority]??3)-(r[t.priority]??3)),t}(a))){let i=String(t.key||"").split(":")[1]||"",n=(e||[]).find(e=>e.comp&&e.comp.slug===i),a=l(n?n.comp.draw_at:null);if(a<1||"missing_media"===t.type&&(d.has(i+":film")||c(t.title))||"fatigue"===t.type&&(d.has(i+":video")||c(t.title)))continue;if("attach_media"===t.type){s.push(el(t.title)+" â its video is already in the Drive; AdPilotX will use it by itself.");continue}if("hygiene"===t.type)continue;let r=el(t.title);o.push({key:t.key,p:+("missing_media"!==t.type),days:a,icon:"missing_media"===t.type?"\uD83C\uDFA5":"\uD83D\uDD01",title:("missing_media"===t.type?"Film a video for ":"Make a NEW video for ")+r,why:"missing_media"===t.type?"There is no video for it at all.":"People have seen the old one too many times.",how:u,compName:r})}return o.sort((e,t)=>e.p-t.p||e.days-t.days),{jobs:o,auto:s}}(Q(e._mt.comps||[],n),n,Date.now()),c=u.jobs.filter(e=>!p.includes(l[e.key])),m=u.jobs.filter(e=>p.includes(l[e.key])),f=c.filter(e=>0===e.p).length;d.innerHTML=V("jobs to do",c.length,"#17141f")+(f?V("do first",f,"#e5484d"):"")+(m.length?V("done",m.length,"#138c60"):"");let g=c.length?'<div style="font-size:20px;font-weight:800;color:#17141f;margin:4px 0 10px">\uD83D\uDCCB Your jobs â start at JOB 1</div>'+c.slice(0,8).map((e,t)=>eu(e,t+1)).join("")+(c.length>8?'<details style="margin-top:6px"><summary style="cursor:pointer;font-size:14px;font-weight:700;color:#5b5566">â '+(c.length-8)+" more jobs for later â tap to see</summary>"+c.slice(8).map((e,t)=>eu(e,t+9)).join("")+"</details>":""):'<div style="padding:18px;border:2px solid #138c60;border-radius:14px;background:#eafaf3;color:#138c60"><div style="font-size:20px;font-weight:800">â
Nothing to do today.</div><div style="font-size:15px;margin-top:4px;color:#17141f">AdPilotX is running all the adverts by itself. Well done.</div></div>',h='<details style="margin-top:18px"><summary style="cursor:pointer;font-size:14px;font-weight:700;color:#5b5566">\uD83E\uDD16 What AdPilotX is doing by itself â nothing for you to do (tap to see)</summary>'+(u.auto.length?'<ul style="margin:8px 0;padding-left:20px;font-size:13px;color:#17141f">'+u.auto.map(e=>"<li>"+(0,a.ZD)(e)+"</li>").join("")+"</ul>":"")+function(e){let{needs:t,comps:i}=e._mt||{};if(!t||!t.ok)return"";let n=t.ads||[],o=[],r=[],s=(e,t)=>e+" "+t+(1===e?"":"s");Q(i||[],t).forEach(e=>{let t=e.stateSummary,i=e.comp.title||e.comp.slug||"";if(e.noMedia)return void r.push("â"+i+"â: no creative anywhere â new footage");if(t){if(t.silent&&t.silent===t.withUsage)return void r.push("â"+i+"â: only silent cuts â export with audio");t.fatigued&&t.unused&&o.push("rotate fatigued ads out of â"+i+"â â "+s(t.unused,"fresh file")+" ready to go in"),t.engineOk&&!t.running&&o.push("turn proven creative back on for â"+i+"â â "+s(t.engineOk,"file")+(1===t.engineOk?" meets":" meet")+" the automatic bar"),t.proven>t.engineOk&&!t.running&&r.push("â"+i+"â: "+s(t.proven-t.engineOk,"proven file")+" under the automatic re-add bar (2\xd7+ on 5+ bookings) â ask AdPilotX to re-add"),!t.fatigued||t.unused||t.proven||r.push("â"+i+"â: fresh cut needed â ads fatigued, nothing fresh or proven to swap in"),e.liveAds||t.proven||t.unused||!t.used||r.push("â"+i+"â: nothing live and only under-performing files â new hook needed")}});let d=n.filter(e=>/ACTIVE/i.test(e.status||"")).map(N),l=e=>d.filter(t=>t.key===e).length;if(l("kill")&&o.push(s(l("kill"),"live ad")+" that are losing money â AdPilotX switches them off"),l("rotate")&&o.push(s(l("rotate"),"live ad")+" that people have seen too often and are not paying â AdPilotX swaps in a fresh video"),l("hold")&&r.push(s(l("hold"),"live ad")+" fatigued but still paying â held; fresh cuts requested from the media team"),!o.length&&!r.length)return"";let p=(e,t)=>e.map(e=>'<span style="display:inline-block;border:1px solid '+t+"44;background:"+t+'11;color:#17141f;border-radius:8px;padding:3px 8px;font-size:12px;margin:4px 6px 0 0">'+(0,a.ZD)(e)+"</span>").join("");return'<div style="border:1px solid #e3e3ea;border-radius:12px;padding:12px 16px;margin-bottom:12px;background:#fff"><div style="font-weight:800;color:#17141f;font-size:14px">\uD83E\uDD16 Auto-handled <span class="muted" style="font-weight:500;font-size:12px">â worked out from the same file colours as the board</span></div><div style="margin-top:6px;font-size:11px;font-weight:800;color:#138c60;text-transform:uppercase;letter-spacing:.04em">AdPilotX does these itself</div>'+(o.length?p(o,"#138c60"):'<div class="muted" style="font-size:12px;margin-top:3px">Nothing to auto-handle right now.</div>')+'<div style="margin-top:8px;font-size:11px;font-weight:800;color:#e5484d;text-transform:uppercase;letter-spacing:.04em">Needs a person</div>'+(r.length?p(r,"#e5484d"):'<div class="muted" style="font-size:12px;margin-top:3px">Nothing waiting on a person.</div>')+"</div>"}(e)+"</details>";s.innerHTML='<div data-mt-askwrap="1">'+g+(m.length?'<details style="margin-top:14px"><summary class="muted" style="cursor:pointer;font-size:13px">
1'+m.length+" finished or put aside â tap to see</summary>"+m.map((e,t)=>eu(e,t+1,l[e.key])).join("")+"</details>":"")+h+"</div>",(i=(t=s).querySelector("[data-mt-askwrap]")||t).__mtAskWired||(i.__mtAskWired=!0,i.addEventListener("click",async e=>{let i=e.target.closest("[data-mt-asktoggle]");if(i){let e=i.getAttribute("data-mt-asktoggle"),n=t.querySelector('[data-mt-askbody="'+e+'"]');n&&(n.style.display="none"===n.style.display?"block":"none");return}let n=e.target.closest("[data-mt-asksend]");if(!n||n.disabled)return;let a=n.getAttribute("data-mt-asksend"),o=t.querySelector('[data-mt-askinput="'+a+'"]'),r=t.querySelector('[data-mt-askstatus="'+a+'"]'),s=t.querySelector('[data-mt-askreply="'+a+'"]'),d=(o&&o.value||"").trim();if(!d){r&&(r.textContent="Type your question first.");return}let l=n.getAttribute("data-mt-askabout")||"";n.disabled=!0,r&&(r.textContent="Sendingâ¦");let p=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"ask_about",about:l,text:d})});if(!p||!p.ok||!p.signal_id){r&&(r.textContent="Couldn't send: "+(p&&(p.detail||p.error)||"try again")),n.disabled=!1;return}o&&(o.value=""),r&&(r.textContent="Sent â â AdPilotX usually answers within a minuteâ¦");for(let e=0;e<24;e++){if(await new Promise(e=>setTimeout(e,5e3)),!document.body.contains(t))return;let e=await _("/api/admin/media-tasks?signal="+encodeURIComponent(p.signal_id)),i=e&&e.signal,a=i&&i.response&&i.response.text;if(a&&s&&(s.style.display="block",s.textContent="\uD83E\uDD16 "+a),i&&i.status&&"pending"!==i.status){r&&(r.textContent="Answered â â ask another if you need to."),n.disabled=!1;return}}r&&(r.textContent="Still thinking â the answer will appear in the \uD83D\uDCAC Message AdPilotX tab."),n.disabled=!1})),s.querySelectorAll("[data-mt-act]").forEach(t=>{t.addEventListener("click",async()=>{let i=t.getAttribute("data-mt-key"),n=t.getAttribute("data-mt-act");t.disabled=!0;let o=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({task_key:i,status:n})});o&&o.ok?((0,a.oR)("open"===n?"Reopened":"done"===n?"Marked done":"not_needed"===n?"Marked not needed":"removed"===n?"Removed":"Snoozed"),E(e)):((0,a.oR)("Could not save"),t.disabled=!1)})})}(e)}let R={not_advertising:["â","#8b8595","Not advertising"],best_ever:["\uD83C\uDFC6","#138c60","Best ever"],ahead:["â²","#138c60","Ahead"],on_track:["â","#3987e5","On track"],behind:["â¼","#d64545","Behind"],new:["â¦","#8b8595","New ground"]},C={meta:"Facebook / Instagram",snapchat:"Snapchat",tiktok:"TikTok",reddit:"Reddit",google:"Google"},j={meta:'Keep wording skill-based and 18+ UK: e.g. "answer a skill question to enter, free postal route, 18+ UK". Never start with "Win"; no gambling, lottery, jackpot, raffle, "chance to win" or "live draws".',snapchat:'Snap rejects anything it reads as gambling unless we are pre-approved. Use the wording that has passed Snap before: "[Prize] Prizes 18+ UK", the full name "Nitrous Competitions", the Shop Now button â no "Win" and no "draw".',tiktok:'TikTok rejects cash-prize videos as "money-making opportunities". Show the prize itself (car, bike, tech) and how to take part â answer a skill question or free postal entry, 18+ UK. Don\'t lead with a cash amount. AdPilotX no longer builds TikTok ads for cash-prize competitions.',reddit:"Keep wording skill-based and 18+ UK; no gambling words.",google:"Google Ads is brand-search only while the gambling review is open â no prize adverts."};function O(e){return e&&Array.isArray(e.rejectedAds)?e.rejectedAds:null}let X=[{key:"facebook",label:"Facebook",src:"meta",place:"facebook"},{key:"instagram",label:"Instagram",src:"meta",place:"instagram"},{key:"tiktok",label:"TikTok",src:"tiktok"},{key:"snapchat",label:"Snapchat",src:"snapchat"},{key:"reddit",label:"Reddit",src:"reddit"},{key:"google",label:"Google",src:"google"}],H={LIVE:"AdPilotX runs it",APPROVAL_REQUIRED:"AdPilotX asks before changing it",DRY_RUN:"view only â AdPilotX reports, never changes it",READ_ONLY:"view only",DISABLED:"switched off"};function F(e){return e?'<span title="Facebook is still working out who to show this to. Numbers look worse than they are, and AdPilotX never switches these off." style="display:inline-block;background:#3987e518;color:#3987e5;border:1px solid #3987e555;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:800;white-space:nowrap">STILL LEARNING</span>':""}let U=e=>null==e?"â":String(e)+"%";function W(e,t,i,n){let a=e.querySelector("#mt-ap-btn"),o=e.querySelector("#mt-ap-state");a&&o&&(o.textContent=n||(!1===t?"â Autopilot STOPPED"+(i?" by "+String(i).replace(/^staff:/,""):""):"\uD83D\uDFE2 Autopilot running"),o.style.color=!1===t?"#c0392b":"#138c60",a.textContent=!1===t?"â¶ Start autopilot":"â¹ Stop autopilot",a.style.background=!1===t?"#138c60":"#c0392b",a.style.color="#fff",a.dataset.on=!1===t?"0":"1",a.dataset.armed="")}function B(e){return String(e||"").replace(/£\s?-?[\d,]+(\.\d+)?k?(\s?\/\s?(day|d))?/gi,"").replace(/\s{2,}/g," ").trim()}async function G(e){let t=e.querySelector("#mt-ask-status"),i=0,n=setInterval(async()=>{i++;let o=await _("/api/admin/media-tasks"),r=o&&o.signal;if(r&&"done"===r.status){clearInterval(n);let t=r.response||{};(0,a.oR)("AdPilotX updated"+(t.roas_summary?" â "+t.roas_summary:"")+" â"),E(e)}else if(r&&"error"===r.status||i>25){clearInterval(n),t&&(t.textContent=i>25?"AdPilotX didn't respond â it may be offline. The hourly snapshot still updates.":"AdPilotX reported an error.");let a=e.querySelector("#mt-ask-btn");a&&(a.disabled=!1)}},4e3)}let V=(e,t,i)=>'<span style="display:inline-block;background:'+i+"22;color:"+i+';border-radius:999px;padding:4px 11px;font-size:12px;font-weight:700;margin-right:8px">'+t+" "+e+"</span>";function K(e){return(e=Number(e||0))>=2.5?"#138c60":e>=1.5?"#e5a23c":"#e5484d"}function Y(e,t){e.querySelector("#mt-body").innerHTML='<div class="notice err">Live media data unavailable (AdPilotX snapshot not ready). '+(0,a.ZD)(t&&t.error||"")+"</div>"}function J(e,t){let i=e?Date.parse(e):NaN;return Number.isNaN(i)?null:Math.max(0,Math.ceil((i-t)/864e5))}function $(e){return null==e?"":e<=0?" The draw is today.":1===e?" The draw is tomorrow.":" The draw is in "+e+" days."}function Q(e,t){let i=new Set((t.awaitingMedia||[]).map(e=>e.slug)),n=t.ads||[],a=t.hygiene||[],o=t.fatigue||[],r=t.mediaTeamActions||[],s=(e,t)=>e+" "+t+(1===e?"":"s");return e.map(e=>{let d,l,p,u,c,m,f,g,h,y,b,x,v,w,k,D,N,z,_=(e.title||"").toLowerCase(),T=(p=(e.slug||"").toLowerCase(),u=(e.title||"").toLowerCase(),(n||[]).filter(t=>{if(t.source&&t.source.slug&&e.slug&&t.source.slug===e.slug)return!0;let i=(t.name||"").toLowerCase(),n=(t.adset||"").toLowerCase(),a=(t.campaign||"").toLowerCase();return p&&i.includes(p)||u&&(n.includes(u)||a.includes(u)||i.includes(u))})),P=T.filter(e=>/ACTIVE/i.test(e.status||"")),q=T.filter(e=>/IN_PROCESS|PENDING_REVIEW|PENDING_BILLING|PREAPPROVED/i.test(e.status||"")),I=P.reduce((e,t)=>
1Math.max(e,Number(t.frequency||0)),0),L=(P.length?P:T).map(e=>Number(e.roas||0)).filter(e=>e>0),E=L.length?L.reduce((e,t)=>e+t,0)/L.length:0,M=!!_&&a.some(e=>(e.title||"").toLowerCase().includes(_)),Z=!!_&&o.some(e=>(e.name||"").toLowerCase().includes(_)),R=r.find(t=>t.slug&&t.slug===e.slug||!!_&&((t.text||"")+" "+(t.what||"")).toLowerCase().includes(_)),C=i.has(e.slug)||R&&"missing_media"===R.type,j=function(e,t){let i=(e.slug||"").toLowerCase(),n=(e.title||"").toLowerCase(),a=[],o=new Set,r=e=>{if(!e)return;let t=(e.id||e.link||e.name||"").toLowerCase();!t||o.has(t)||(o.add(t),a.push({id:e.id||"",name:e.name||"(file)",link:e.link||"",path:e.path||"",size:e.size||null,modifiedTime:e.modifiedTime||null,usage:e.usage||null}))},s=t.mediaByComp||t.driveByComp||null,d=s&&(s[e.slug]||s[i]);if(d)return(Array.isArray(d)?d:d.files||[]).forEach(r),{files:a,exact:!0,usage:!Array.isArray(d)&&d.usage&&"object"==typeof d.usage?d.usage:null,count:Number(d.count)||a.length};(t.driveHasMedia||[]).forEach(e=>{(e.slug||"").toLowerCase()===i&&(e.files||[]).forEach(r)});let l=n.replace(/[^a-z0-9 ]/g," ").split(/\s+/).filter(e=>e.length>=4&&!["prize","instant","competition","draw","cash","with","from","your","only","live"].includes(e));return(t.newDriveMedia||[]).forEach(e=>{let t=((e.path||"")+" "+(e.name||"")).toLowerCase(),n=l.filter(e=>t.includes(e)).length;(i&&t.includes(i)||n>=2)&&r(e)}),{files:a,exact:!1,usage:null,count:a.length}}(e,t),O=S(j.files,n)||A(j.usage),X=!!(O&&O.silent&&O.silent===O.withUsage),H=O?Number(O.unused||0):0,F=O?Number(O.proven||0):0;if(C)d="red",l=R?function(e){if(!e)return"";let t=[e.what,null!=e.howMany&&""!==e.howMany?"\xd7 "+e.howMany:"",e.style,e.where].filter(Boolean).map(String);return t.length?t.join(" \xb7 "):String(e.text||"")}(R):"No creative anywhere â create + upload (9:16 + 4:5, with audio).";else if(X)d=P.length?"amber":"red",l="Only silent cuts â media team must export with audio.";else if(0===P.length&&q.length)d="amber",l=s(q.length,"advert")+" placed and waiting for Meta to approve "+(1===q.length?"it":"them")+" â usually under an hour. Nothing to do; do not build another.";else if(0===P.length)d="red",l=F?"Re-add proven creative ("+s(F,"file")+") â ran before at 1.5\xd7+ ROAS; no new footage needed.":H?"No live ads â "+s(H,"unused file")+" in the Drive ready to push live; no new footage needed.":"No live ads running for this competition â needs creative pushed live.";else if(M||Z||I>=3.5||E>0&&E<1.5){d="amber";let e=I>=3.5;if(e||Z){let t=e?" (seen "+I.toFixed(1)+"\xd7)":"";l=H?"Frequency too high"+t+" â AdPilotX will rotate in the "+s(H,"fresh file")+" it already has.":F?"Frequency too high"+t+" â AdPilotX can rotate proven creative back in ("+s(F,"file")+").":"Fresh cut needed â current ads fatigued"+t+"."}else l=M?"Too few distinct concepts (thin) â add more variants.":"Low ROAS ("+E.toFixed(2)+"\xd7) â refresh the angle."}else d="green",l=O&&O.tired&&!H&&!F?"Healthy, but the running creative is getting tired and nothing fresh is in the Drive â line up a new cut.":"Healthy â enough fresh creative running.";let U=O?Number(O.running||0)+Number(O.probablyRunning||0):0,W=(g=t&&t.libraryMedia||{},h=e=>new Set((e||[]).map(e=>String(e&&(e.name||e.driveName)||"").toLowerCase()).filter(Boolean)),y=e=>new Set((e||[]).map(e=>String(e&&(e.id||e.driveId)||"")).filter(Boolean)),b=h(g.winners),x=y(g.winners
1),v=h(g.generic),w=y(g.generic),k=0,D=0,N=0,(P||[]).forEach(e=>{let t=e&&e.source||{},i=String(t.driveName||"").toLowerCase(),n=String(t.driveId||"");n&&x.has(n)||i&&b.has(i)||/winner/i.test(i)||/winner/i.test(String(e.name||"")+" "+String(e.adset||""))?k++:n&&w.has(n)||i&&v.has(i)||"generic_ledger"===t.via||/generic|always.?on/i.test(i+" "+String(e.adset||""))?D++:N++}),(z=(P||[]).length)&&k===z?(c="winners",m="\uD83C\uDFC6 RUNNING ON WINNER VIDEOS",f="winner videos"):z&&D===z?(c="generic",m="\uD83D\uDCDA RUNNING ON ALWAYS-ON VIDEOS",f="the generic / always-on videos"):z&&k+D===z?(c="library",m="\uD83D\uDCDA RUNNING ON LIBRARY VIDEOS",f="winner and always-on videos"):z&&k+D>0?(c="mixed",m="\uD83D\uDCDA RUNNING ON LIBRARY + OTHER VIDEOS",f="library videos and files not tied to this competition"):(c="other",m="\uD83C\uDF9E RUNNING ON OTHER VIDEOS",f="videos the engine could not tie to this competition's folder"),{key:c,label:m,phrase:f,winners:k,generic:D,other:N,total:z}),B=P.length>0&&0===U&&(!O||Number(O.total||0)>0||H>0)?W:null;return P.length>0&&0===U&&H>0?l+=" â note: none of its OWN "+s(H,"video")+" "+(1===H?"is":"are")+" in use, because the "+s(P.length,"advert")+" running for it "+(1===P.length?"was":"were")+" built from "+W.phrase+". Nothing for the media team to do â AdPilotX decides which video runs where.":P.length>0&&0===U&&O&&(l+=" â the "+s(P.length,"advert")+" running for it "+(1===P.length?"was":"were")+" built from "+W.phrase+", not from this competition's own files."),{comp:e,light:d,liveAds:P.length,judged:P.some(e=>e.size&&"tiny"!==e.size),pendingAds:q.length,adCount:T.length,maxFreq:I,avgRoas:E,needsText:l,noMedia:!!C,backedBy:B,media:j.files,mediaExact:j.exact,mediaUsage:j.usage,mediaCount:j.count,stateSummary:O,priority:R?R.priority:"red"===d?"high":"amber"===d?"medium":"low"}})}function ee(e,t){let i=(e||[]).filter(e=>t.test((e.name||"")+" "+(e.adset||"")+" "+(e.campaign||""))),n=i.filter(e=>/ACTIVE/i.test(e.status||"")),a=n.map(e=>Number(e.roas||0)).filter(e=>e>0);return{total:i.length,live:n.length,avg:a.length?a.reduce((e,t)=>e+t,0)/a.length:0,best:a.length?Math.max(...a):0}}function et(e){return e.live?e.avg?e.live+" running, bringing back "+e.avg.toFixed(2)+"\xd7 what they cost"+(e.best>e.avg?" (best one "+e.best.toFixed(2)+"\xd7)":"")+".":e.live+" running â no return figures yet, still too new to judge.":"Nothing running right now."}function ei(e,t){return e.live&&e.avg>=1.5?"green":e.live||t?"amber":"red"}let en=[["auto","\uD83E\uDD16 AdPilotX is sorting it â nobody needs to act"],["media","\uD83C\uDFAC Needs the media team"],["owner","\uD83D\uDC64 Needs the owner"],["keep","⸠Kept as it is on purpose"]];async function ea(e,t,i){let n=(t.media||[]).find(e=>e&&e.id);if(!n)return void(0,a.oR)("No Drive file id for this competition yet â ask AdPilotX for an update.");i&&(i.disabled=!0);let o=await _("/api/admin/drive?action=parentOf&fileId="+encodeURIComponent(n.id));(i&&(i.disabled=!1),o&&o.ok&&o.parentId)?(e._mt.view="drive",ey(e).folderId=o.parentId,M(e),Z(e)):(0,a.oR)("Couldn't find that folder: "+eb(o))}let eo=[{key:"winners",icon:"\uD83C\uDFC6",label:"Winner videos",hint:"past-winner reels â proof creative for any comp",collapsed:!1},{key:"generic",icon:"\uD83C\uDF9E",label:"Generic / always-on",hint:"brand & reach creatives not tied to one comp",collapsed:!1},{key:"wip",icon:"\uD83D\uDEE0",label:"Work in progress",hint:"On Going Projects â not finished, not for ads yet",collapsed:!0}];function er(e,t){return e&&Array.isArray(e.alwaysOnPool)?e.alwaysOnPool.filter(e=>e&&e.driveId):(t&&Array.isArray(t.generic)?t.generic:[]).filter(e=>e&&e.id&&!/tiktok|no[\s_-]?music/i.test(e.name||"")).map(e=>({driveId:e.id,name:e.name||"(file)",paused:null,live:null}))}function es(e,t,i){return'<option value="'+e+'"'+(e===t?" selected":"")+">"+i+"</option>"}let ed={film:0,too_often:1,new:1};function el(e){return String(e||"").split(" â ")[0].split(" - ")[0].trim()}let ep=["DO THIS FIRST","TODAY","THIS WEEK","WHEN YOU CAN","ONLY IF YOU HAVE TIME"];function eu(e,t,i){var n,o,r;let s,d,l,p,u=eB["P"+Math.min(4,e.p)],c='<div style="display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;align-items:center"><div><span style="display:inline-block;background:#17141f;color:#fff;border-radius:8px;padding:3px 10px;font-size:13px;font-weight:800;margin-right:8px">JOB '+t+'</span><span style="font-size:12px;font-weight:800;color:'+u+';letter-spacing:.04em">'+ep[Math.min(4,e.p)]+(i?" \xb7 "+(0,a.ZD)(String(i)).toUpperCase():"")+"</span></div><div>
1"+(n=e.key,p=(0,a.ZD)(n),i?'<button class="btn btn-ghost btn-sm" data-mt-act="open" data-mt-key="'+p+'">Put it back</button>':'<button class="btn btn-primary btn-sm" data-mt-act="done" data-mt-key="'+p+'">â
Done</button> <button class="btn btn-ghost btn-sm" data-mt-act="not_needed" data-mt-key="'+p+'">Not needed</button> <button class="btn btn-ghost btn-sm" data-mt-act="snoozed" data-mt-key="'+p+'">Later</button>')+"</div></div>",m='<div style="font-size:17px;font-weight:800;color:#17141f;margin-top:8px">'+(e.icon?e.icon+" ":"")+(0,a.ZD)(e.title)+"</div>"+(e.why?'<div style="font-size:14px;color:#17141f;margin-top:4px"><b>Why:</b> '+(0,a.ZD)(e.why)+"</div>":"")+(e.how?'<div style="font-size:14px;color:#17141f;margin-top:4px"><b>How:</b> '+(0,a.ZD)(e.how)+"</div>":""),f=(i?"done":"job")+t,g=e.action||{};return'<div style="border:1px solid #e3e3ea;border-left:6px solid '+u+";border-radius:12px;padding:14px 16px;margin-bottom:10px;background:#fff"+(i?";opacity:.6":"")+'">'+c+m+('<div data-mt-asktoggle="'+f+'" style="margin-top:8px;font-size:13px;font-weight:700;color:#7256ec;cursor:pointer">\uD83D\uDCAC Ask AdPilotX about this job â¸</div>')+(o={title:e.title,explain:Object.assign({means:e.why,doThis:e.how,askHint:e.title},g.explain||{},{askHint:e.title})},r=f,s=o.explain||{},d=(e,t,i)=>t?'<div style="margin-top:7px"><span style="font-size:11px;font-weight:800;color:'+(i||"#8b8595")+';text-transform:uppercase;letter-spacing:.04em">'+e+'</span><div style="font-size:13px;color:#17141f;margin-top:1px">'+(0,a.ZD)(String(t))+"</div></div>":"",l=s.wornOut?d("Has this audience seen it all?",s.wornOut,/^Yes/.test(s.wornOut)?"#e5484d":/^Nearly/.test(s.wornOut)?"#e5a23c":"#138c60"):"",'<div data-mt-askbody="'+r+'" style="display:none;margin:8px 0 2px 36px;padding:12px 14px;border-left:3px solid #7256ec;background:#fbfaff;border-radius:0 10px 10px 0">'+d("What this means",s.means)+d("Why it matters",s.why)+(s.audience?d("Who sees these adverts",s.audience,"#3987e5")+'<div class="muted" style="font-size:11.5px;margin-top:2px">'+(0,a.ZD)(String(s.audienceNote||""))+"</div>":"")+l+d("What to do",s.doThis,"#138c60")+'<div style="margin-top:10px;border-top:1px dashed #d9d4f0;padding-top:9px"><div style="font-size:12px;font-weight:800;color:#7256ec;margin-bottom:5px">\uD83D\uDCAC Ask AdPilotX about this â it answers in plain English, and can do it for you</div><div style="display:flex;gap:6px;flex-wrap:wrap"><input data-mt-askinput="'+r+'" type="text" maxlength="300" placeholder="e.g. what video should we make for this?" style="flex:1;
1min-width:200px;padding:8px 10px;border:1px solid #d7d7e0;border-radius:8px;font-size:13px"><button class="btn btn-primary btn-sm" data-mt-asksend="'+r+'" data-mt-askabout="'+(0,a.ZD)(String(s.askHint||o.title||""))+'" style="flex:none">Ask â¸</button></div><div data-mt-askstatus="'+r+'" class="muted" style="font-size:12px;margin-top:6px"></div><div data-mt-askreply="'+r+'" style="display:none;margin-top:7px;padding:9px 11px;background:#fff;border:1px solid #e3e3ea;border-radius:8px;font-size:13px;white-space:pre-wrap;color:#17141f"></div></div></div>')+"</div>"}function ec(e){let t=e&&e._updatedAt;if(!t)return'<div class="muted" style="font-size:12px;margin-top:8px">â± Ads last checked: waiting for the first AdPilotX snapshot.</div>';let i=new Date(t).toLocaleString("en-GB",{weekday:"short",day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"});return'<div class="muted" style="font-size:12px;margin-top:8px">â± Ads last checked: <b>'+(0,a.ZD)(i)+"</b> ("+L(t)+") â use âAsk AdPilotXâ to refresh now.</div>"}let em={roas:(e,t)=>Number(g(e,t)||0),freq:e=>Number(e.frequency||0),purchases:(e,t)=>Number(h(e,t)||0),today:e=>Number(e.purchasesToday||0),name:e=>String(e.name||"").toLowerCase(),status:e=>+!/ACTIVE/i.test(e.status||""),plan:e=>({rotate:0,kill:1,hold:2,readd:3,watch:4,keep:5,leave:6})[N(e).key]??9,file:e=>String(e.source&&e.source.driveName||"").toLowerCase()},ef=`@media (min-width:1280px){ 2 #media-tasks .mt-wide{ 3 width:calc(100vw - 340px); 4 max-width:calc(100vw - 340px); 5 margin-left:calc((100% - (100vw - 340px)) / 2); 6 margin-right:calc((100% - (100vw - 340px)) / 2); 7 } 8}`;function eg(e,t){let i=t&&t.source;if(!i)return null;let n=[],a=e&&e.mediaByComp||{};i.slug&&a[i.slug]&&n.push(Array.isArray(a[i.slug])?a[i.slug]:a[i.slug].files||[]);let o=e&&e.libraryMedia||{};for(let e of(["winners","generic","wip"].forEach(e=>{Array.isArray(o[e])&&n.push(o[e])}),n)){let t=e.find(e=>e&&(i.driveId&&e.id===i.driveId||i.driveName&&e.name===i.driveName));if(t)return t}return i.driveName?{id:i.driveId||"",name:i.driveName,link:""}:null}let eh="/api/admin/drive";function ey(e){return e._mt.drive||(e._mt.drive={folderId:null,rootId:null,crumbs:[],items:[],loading:!1,error:"",editingId:null,creating:!1,menuId:null,confirmTrashId:null,uploads:[],running:!1,dragging:!1}),e._mt.drive}function eb(e){return e?"drive_scope_readonly"===e.error?"the Drive connection is read-only â an owner needs to re-authorise it with full Drive access":"drive_not_configured"===e.error?"Drive isn't connected on the server yet":String(e.detail||e.error||"unknown error"):"no response"}async function ex(e){return _(eh,{method:"POST",body:JSON.stringify(e)})}function ev(e){let t=e.dataTransfer&&e.dataTransfer.types;return!!t&&Array.from(t).includes("Files")}async function ew(e,t){let i=ey(e);i.loading=!0,i.error="",i.menuId=null,i.confirmTrashId=null,i.editingId=null,i.creating=!1,ek(e);let n=await _(eh+"?action=list"+(t?"&folderId="+encodeURIComponent(t):""));if("drive"===e._mt.view){if(i.loading=!1,!n||!n.ok)return(i.error=eb(n),n&&("outside_root"===n.error||"not_found"===n.error)&&t)?(i.folderId=null,ew(e,null)):void ek(e);i.folderId=n.folderId,i.rootId=n.rootId,i.crumbs=n.breadcrumb||[],i.items=n.items||[],ek(e)}}function ek(e){let t=ey(e),i=e.querySelector("#mt-fm-bar"),n=e.querySelector("#mt-fm-list");if(!i||!n)return;let o=t.crumbs.length?t.crumbs:[{id:t.folderId||"",name:"Ads Drive"}];if(i.innerHTML='<div style="display:flex;gap:4px;align-items:center;flex-wrap:wrap;flex:1;
8min-width:200px;font-size:13px">'+o.map((e,t)=>{let i=t===o.length-1;return(t?'<span style="color:#aeb2bd">âº</span>':"")+(i?'<b style="color:#17141f;padding:2px 4px">'+(t?"":"\uD83D\uDCC1 ")+(0,a.ZD)(e.name||"")+"</b>":'<button class="btn btn-ghost btn-sm" data-fm="open" data-id="'+(0,a.ZD)(e.id)+'" style="padding:2px 6px">'+(t?"":"\uD83D\uDCC1 ")+(0,a.ZD)(e.name||"")+"</button>")}).join("")+'</div><button class="btn btn-ghost btn-sm" data-fm="refresh" title="Refresh">â»</button><button class="btn btn-ghost btn-sm" data-fm="newfolder">ï¼ New folder</button><button class="btn btn-primary btn-sm" data-fm="upload">⬠Upload files</button>',t.loading){n.innerHTML='<div class="muted" style="padding:28px;text-align:center;font-size:13px">Loading folderâ¦</div>';return}let r="";t.error&&(r+='<div class="notice err" style="margin:10px">'+(0,a.ZD)(t.error)+"</div>"),t.creating&&(r+='<div style="display:flex;gap:8px;align-items:center;padding:8px 12px;border-bottom:1px solid #eee;background:#f6f9ff">\uD83D\uDCC1 <input id="mt-fm-newname" data-fm-enter="mkdir-save" placeholder="New folder name" maxlength="120" style="flex:1;padding:6px 9px;border:1px solid #c9d2ee;border-radius:8px;font:inherit;font-size:13px" /><button class="btn btn-primary btn-sm" data-fm="mkdir-save">Create</button><button class="btn btn-ghost btn-sm" data-fm="cancel">Cancel</button></div>'),t.items.length||t.creating||t.error||(r+='<div class="muted" style="padding:28px;text-align:center;font-size:13px">This folder is empty â drop files here or make a folder.</div>'),n.innerHTML=r+=t.items.map(e=>{var i,n;let o,r,s,d,l,p,u,c,m;return i=e,n=t,o=(0,a.ZD)(i.id),r=n.editingId===i.id,s=n.menuId===i.id,d=n.confirmTrashId===i.id,l=i.isFolder?"\uD83D\uDCC1":/^video\//.test(i.mimeType)?"\uD83C\uDFAC":/^image\//.test(i.mimeType)?"\uD83D\uDDBC":"\uD83D\uDCC4",p=!i.isFolder&&i.thumbnailLink?'<img src="'+(0,a.ZD)(i.thumbnailLink)+'" alt="" loading="lazy" referrerpolicy="no-referrer" style="width:40px;height:40px;object-fit:cover;border-radius:6px;flex:none;background:#f0f0f4" />':'<div style="width:40px;height:40px;border-radius:6px;background:#f4f4f8;display:flex;align-items:center;justify-content:center;font-size:20px;flex:none">'+l+"</div>",u=[i.isFolder?"Folder":(i.mimeType||"").split("/")[1]||"",eU(i.size),i.modifiedTime?L(i.modifiedTime):""].filter(Boolean).join(" \xb7 "),c=r?'<div style="display:flex;gap:6px;align-items:center"><input id="mt-fm-rename" data-fm-enter="rename-save" data-id="'+o+'" value="'+(0,a.ZD)(i.name)+'" maxlength="120" style="flex:1;padding:5px 8px;border:1px solid #c9d2ee;border-radius:8px;font:inherit;font-size:13px" /><button class="btn btn-primary btn-sm" data-fm="rename-save" data-id="'+o+'">Save</button><button class="btn btn-ghost btn-sm" data-fm="cancel">Cancel</button></div>':i.isFolder?'<button data-fm="open" data-id="'+o+'" style="all:unset;cursor:pointer;font-size:13.5px;font-weight:700;color:#17141f;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;display:block" title="'+(0,a.ZD)(i.name)+'">'+(0,a.ZD)(i.name)+"</button>":'<div style="font-size:13.5px;font-weight:600;color:#17141f;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="'+(0,a.ZD)(i.name)+'">'+(0,a.ZD)(i.name)+"</div>",m=d?'<span style="font-size:12px;color:#e5484d;font-weight:700;margin-right:6px">Move to Drive bin?</span><button class="btn btn-sm" data-fm="trash-confirm" data-id="'+o+'" style="background:#e5484d;color:#fff;border-color:#e5484d">Really trash</button> <button class="btn btn-ghost btn-sm" data-fm="cancel">Keep</button>':s?'<button class="btn btn-ghost btn-sm" data-fm="rename" data-id="'+o+'">âï¸ Rename</button> <button class="btn btn-ghost btn-sm" data-fm="move" data-id="'+o+'">\uD83D\uDCC2 Move toâ¦</button> <button class="btn btn-ghost btn-sm" data-fm="trash" data-id="'+o+'" style="color:#e5484d">\uD83D\uDDD1 Trash</button> <button class="btn btn-ghost btn-sm" data-fm="cancel" title="Close">â</button>':(i.webViewLink?'<a class="btn btn-ghost btn-sm" href="'+(0,a.ZD)(i.webViewLink)+'" target="_blank" rel="noopener" style="white-space:nowrap">Open in Drive â¸</a> ':"")+'<button class="btn btn-ghost btn-sm" data-fm="menu" data-id="'+o+'" title="More" style="font-weight:800">â¯</button>','<div style="display:flex;gap:10px;align-items:center;padding:8px 12px;
8border-bottom:1px solid #f0f0f4'+(s||d?";background:#fbfbfd":"")+'">'+p+'<div style="min-width:0;flex:1">'+c+(u?'<div class="muted" style="font-size:11px;margin-top:1px">'+(0,a.ZD)(u)+"</div>":"")+'</div><div style="flex:none;display:flex;gap:4px;align-items:center;flex-wrap:wrap;justify-content:flex-end">'+m+"</div></div>"}).join("");let s=n.querySelector("#mt-fm-newname");s&&s.focus();let d=n.querySelector("#mt-fm-rename");d&&(d.focus(),d.select())}async function eS(e,t,i,n){let o=ey(e),r=o.items.find(e=>e.id===i)||null;switch(t){case"open":return o.menuId=null,o.folderId=i||o.rootId,ew(e,o.folderId);case"refresh":return ew(e,o.folderId);case"upload":{let t=e.querySelector("#mt-fm-file");t&&t.click();return}case"newfolder":return o.creating=!0,o.editingId=null,o.menuId=null,o.confirmTrashId=null,ek(e);case"cancel":return o.creating=!1,o.editingId=null,o.menuId=null,o.confirmTrashId=null,ek(e);case"menu":return o.menuId=o.menuId===i?null:i,o.confirmTrashId=null,o.editingId=null,ek(e);case"rename":return o.editingId=i,o.menuId=null,ek(e);case"trash":return o.confirmTrashId=i,o.menuId=null,ek(e);case"move":return o.menuId=null,ek(e),function(e,t){if(!t)return;let i=ey(e),n={folderId:i.folderId,crumbs:[],folders:[],loading:!0,error:""},o=()=>{let o=n.crumbs.length?n.crumbs:[{id:n.folderId,name:"Ads Drive"}],s=o[o.length-1],d=t.isFolder&&o.some(e=>e.id===t.id),l=eK(e,'<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px"><b style="font-size:15px">Move â'+(0,a.ZD)(t.name)+'â toâ¦</b><button class="btn btn-ghost btn-sm" id="mt-modal-x">Close â</button></div><div style="display:flex;gap:4px;align-items:center;flex-wrap:wrap;font-size:13px;margin-bottom:8px">'+o.map((e,t)=>(t?'<span style="color:#aeb2bd">âº</span>':"")+'<button class="btn btn-ghost btn-sm" data-pk="go" data-id="'+(0,a.ZD)(e.id)+'" style="padding:2px 6px">'+(t?"":"\uD83D\uDCC1 ")+(0,a.ZD)(e.name||"")+"</button>").join("")+'</div><div style="border:1px solid #eee;border-radius:10px;max-height:40vh;overflow:auto">'+(n.loading?'<div class="muted" style="padding:18px;text-align:center">Loadingâ¦</div>':n.error?'<div class="notice err" style="margin:8px">'+(0,a.ZD)(n.error)+"</div>":n.folders.length?n.folders.map(e=>'<button data-pk="go" data-id="'+(0,a.ZD)(e.id)+'" style="all:unset;display:block;width:100%;box-sizing:border-box;cursor:pointer;padding:8px 12px;border-bottom:1px solid #f0f0f4;font-size:13px;color:#17141f'+(e.id===t.id?";opacity:.4;pointer-events:none":"")+'">\uD83D\uDCC1 '+(0,a.ZD)(e.name)+(e.id===t.id?' <span class="muted">(this folder)</span>':"")+"</button>").join(""):'<div class="muted" style="padding:14px;text-align:center;font-size:13px">No sub-folders here.</div>')+'</div><div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px;align-items:center">'+(d?'<span class="muted" style="font-size:12px">A folder can\'t be moved inside itself.</span>':"")+'<button class="btn btn-primary btn-sm" data-pk="here"'+(d||n.loading?" disabled":"")+">Move here ("+(0,a.ZD)(s.name||"")+")</button></div>");l&&l.querySelectorAll("[data-pk]").forEach(o=>o.addEventListener("click",async()=>{let s=o.getAttribute("data-pk");if("go"===s)return n.folderId=o.getAttribute("data-id"),r();if("here"===s){o.disabled=!0;let r=await ex({action:"move",id:t.id,fromParentId:i.folderId,toParentId:n.folderId});if(r&&r.ok){(0,a.oR)(r.unchanged?"Already there":"Moved â");let t=e.querySelector("#mt-modal");return t&&(t.innerHTML=""),ew(e,i.folderId)}(0,a.oR)("Couldn't move: "+eb(r)),o.disabled=!1}}))},r=async()=>{n.loading=!0,n.error="",o();let e=await _(eh+"?action=list"+(n.folderId?"&folderId="+encodeURIComponent(n.folderId):""));n.loading=!1,e&&e.ok?(n.folderId=e.folderId,n.crumbs=e.breadcrumb||[],n.folders=(e.items||[]).filter(e=>e.isFolder)):n.error=eb(e),o()};r()}(e,r);case"mkdir-save":{let t=e.querySelector("#mt-fm-newname"),i=(t&&t.value||"").trim();if(!i)return void(0,a.oR)("Type a folder name");n&&(n.disabled=!0);let r=await ex({action:"mkdir",parentId:o.folderId,name:i});if(r&&r.ok)return(0,a.oR)("Folder created â"),o.creating=!1,ew(e,o.folderId);(0,a.oR)("Couldn't create folder: "+eb(r)),n&&(n.disabled=!1);return}case"rename-save":{let t=e.querySelector("#mt-fm-rename"),s=(t&&t.value||"").trim();if(!s)return void(0,a.oR)("Name can't be empty");if(r&&s===r.name)return o.editingId=null,ek(e);n&&(n.disabled=!0);let d=await ex({action:"rename",id:i,name:s});if(d&&d.ok)return(0,a.oR)("Renamed â"),o.editingId=null,ew(e,o.folderId);(0,a.oR)("Couldn't rename: "+eb(d)),n&&(n.disabled=!1);return}case"trash-confirm":{n&&(n.disabled=!0);let t=await ex({action:"trash",id:i});if(t&&t.ok)return(0,a.oR)("Moved to the Drive bin"),o.confirmTrashId=null,ew(e,o.folderId);(0,a.oR)("Couldn't trash: "+eb(t)),n&&(n.disabled=!1);return}
8case"retry":{let t=o.uploads[Number(i)];t&&"failed"===t.status&&(t.status="queued",t.pct=0,t.error="",eD(e),eN(e));return}case"clear-done":return o.uploads=o.uploads.filter(e=>"done"!==e.status),eD(e);default:return}}function eA(e,t){let i=ey(e);if(!t.length)return;let n=i.folderId,o=(i.crumbs[i.crumbs.length-1]||{}).name||"this folder",r=0;t.forEach(e=>{let t=/^(video|image)\//i.test(e.type||"");if(!t||e.size<=0||e.size>0x80000000){r++,i.uploads.push({file:e,name:e.name,size:e.size,pct:0,status:"failed",error:t?e.size>0x80000000?"over 2 GB":"empty file":"only video / image files",folderId:n,folderName:o});return}i.uploads.push({file:e,name:e.name,size:e.size,pct:0,status:"queued",error:"",folderId:n,folderName:o})}),r&&(0,a.oR)(r+" file"+(1===r?"":"s")+" skipped (video/image only, ⤠2 GB)"),eD(e),eN(e)}function eD(e){let t=ey(e),i=e.querySelector("#mt-fm-queue");if(!i)return;if(!t.uploads.length){i.innerHTML="";return}let n=t.uploads.filter(e=>"done"===e.status).length;i.innerHTML='<div style="border-top:1px solid #eee;padding:8px 12px;background:#fafafc"><div style="display:flex;justify-content:space-between;align-items:center;font-size:12px;margin-bottom:6px"><b>Uploads</b><span>'+n+"/"+t.uploads.length+" done"+(n?' \xb7 <button class="btn btn-ghost btn-sm" data-fm="clear-done" style="padding:1px 6px">clear done</button>':"")+"</span></div>"+t.uploads.map((e,t)=>{let i="done"===e.status?"#138c60":"failed"===e.status?"#e5484d":"#3987e5",n="done"===e.status?"done â":"failed"===e.status?"failed â "+(e.error||""):"queued"===e.status?"queued":(e.pct||0)+"%";return'<div style="margin:4px 0"><div style="display:flex;justify-content:space-between;gap:8px;font-size:12px"><span style="min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(0,a.ZD)(e.name)+' <span class="muted">â '+(0,a.ZD)(e.folderName||"")+" \xb7 "+(0,a.ZD)(eU(e.size))+'</span></span><span style="flex:none;color:'+i+';font-weight:700">'+(0,a.ZD)(n)+("failed"===e.status?' <button class="btn btn-ghost btn-sm" data-fm="retry" data-id="'+t+'" style="padding:1px 6px">retry</button>':"")+'</span></div><div style="height:4px;background:#e9e9f0;border-radius:2px;overflow:hidden;margin-top:3px"><div style="height:100%;width:'+("done"===e.status?100:Number(e.pct||0))+"%;background:"+i+';transition:width .2s"></div></div></div>'}).join("")+"</div>"}async function eN(e){let t=ey(e);if(!t.running){t.running=!0;try{for(;;){let i=t.uploads.find(e=>"queued"===e.status);if(!i)break;i.status="uploading",i.pct=0,eD(e);try{await ez(i,t=>{i.pct=t,eD(e)}),i.status="done",i.pct=100,(0,a.oR)("Uploaded "+i.name+" â"),ey(e).folderId===i.folderId&&"drive"===e._mt.view&&ew(e,i.folderId)}catch(e){i.status="failed",i.error=String(e&&e.message||e||"upload failed")}eD(e)}}finally{t.running=!1}}}async function ez(e,t){let i=e.file,n=await ex({action:"upload-session",parentId:e.folderId,name:i.name,mimeType:i.type,size:i.size});if(!n||!n.ok||!n.sessionUri)throw Error(eb(n));let a=n.sessionUri,o=i.size,r=Number(n.chunkSize)||8388608,s=0,d=0;for(;s<o;){let e=Math.min(s+r,o)-1,n=await function(e,t,i,n,a,o,r){return new Promise(s=>{let d=new XMLHttpRequest;d.open("PUT",e,!0),d.setRequestHeader("Content-Range","bytes "+i+"-"+n+"/"+a),o&&d.setRequestHeader("Content-Type",o),d.upload.onprogress=e=>{e.lengthComputable&&r(e.loaded)},d.onload=()=>s({status:d.status,range:d.getResponseHeader("Range")||""}),d.onerror=()=>s({status:0,range:""}),d.onabort=()=>s({status:0,range:""}),d.send(t)})}(a,i.slice(s,e+1),s,e,o,i.type,e=>t(Math.min(99,Math.floor((s+e)/o*100))));if(200===n.status||201===n.status)return void t(100);if(308===n.status){let t=/bytes=\d+-(\d+)/.exec(n.range||""),i=t?Number(t[1])+1:e+1;if(i<=s){if(++d>3)throw Error("upload stalled")}else d=0;s=i;continue}if(0===n.status||n.status>=500){let e=await function(e,t){return new Promise(i=>{let n=new XMLHttpRequest;n.open("PUT",e,!0),n.setRequestHeader("Content-Range","bytes */"+t),n.onload=()=>{if(200===n.status||201===n.status)return i({done:!0});if(308===n.status){let e=/bytes=\d+-(\d+)/.exec(n.getResponseHeader("Range")||"");return i({next:e?Number(e[1])+1:0})}i({next:null})},n.onerror=()=>i({next:null}),n.send()})}(a,o);if(e.done)return void t(100);if(null!=e.next){if(++d>5)throw Error("upload keeps failing ("+n.status+")");s=e.next,await new Promise(e=>setTimeout(e,1200*d));continue}throw Error("upload interrupted ("+n.status+")")}throw Error(404===n.status?"upload session expired â retry":"Google rejected the upload ("+n.status+")")}}let e_="nc_mt_chat_cleared_at",eT=[{k:"pause",label:"⸠Switch an advert off",text:"PAUSE: "},{k:"resume",label:"â¶ Switch one back on",text:"RESUME: "},{k:"swap",label:"\uD83C\uDFAC Put a different video on",text:"SWAP: "},{k:"fix",label:"âï¸ The words are wrong",text:"FIX: "},{k:"where",label:"\uD83D\uDCC1 Where do the videos go?",text:"WHERE: "},{k:"rescan",label:"\uD83D\uDD04 I have uploaded new videos",text:"RESCAN"},{k:"noads",label:"\uD83D\uDEAB Do not advertise this one",text:"NO ADS: "},{k:"problem",label:"â ï¸ Something is wrong",text:"There is a problem with "},{k:"ask",label:"â Ask anything",text:""}],eP=[{k:"brief",label:"\uD83D\uDCD6 Today's briefing",text:"\uD83D\uDCD6 Show me today's briefing"},{k:"needs",label:"\uD83D\uDCCB What do you need from us?",text:"\uD83D\uDCCB What do you need from us today?"},{k:"first",label:"\uD83C\uDFAC What should we film first?",text:"\uD83C\uDFAC Which videos should we make first?"},{k:"hooks",label:"\uD83D\uDCA1 Hook ideas",text:"\uD83D\uDCA1 Give me hook ideas"},{k:"soon",label:"\uD83D\uDDD3 Ending soon",text:"\uD83D\uDDD3 What is ending soon that needs videos?"}];function eq(e){if(!e._mt)return;clearTimeout(e._mt.msgTimer);let t=e._mt.msgGen=(e._mt.msgGen||0)+1,i=()=>t===e._mt.msgGen&&"msg"===e._mt.view&&!!e.querySelector("#mt-thread"),n=async()=>
8{if(i()){if("hidden"!==document.visibilityState)try{await eM(e)}catch(e){}i()&&(e._mt.msgTimer=setTimeout(n,1e4))}};e._mt.msgTimer=setTimeout(n,1e4),e._mt.visHooked||(e._mt.visHooked=!0,document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&e._mt&&"msg"===e._mt.view&&e.querySelector("#mt-thread")&&eM(e)}))}function eI(e){let t=String(e||"").trim();if(!t)return"Admin";let i=t.includes("@")?t.split("@")[0]:t,n=i.split(/[._-]/)[0]||i;return n.charAt(0).toUpperCase()+n.slice(1)}function eL(e){var t,i,n,o,r;let s=function(e){let t=e.response;if(!t)return"";if("string"==typeof t)return t;if(t.text||t.message)return String(t.text||t.message);if("media_refresh"===e.kind){let i=[];return t.roas_summary&&i.push(String(t.roas_summary)),"string"==typeof t.social?i.push(t.social):t.social&&"object"==typeof t.social&&(t.social.summary||t.social.text)&&i.push(String(t.social.summary||t.social.text)),t.error&&i.push("Problem: "+String(t.error)),("done"===e.status?"Ads & Drive snapshot updated â":"")+(i.length?("done"===e.status?"\n":"")+i.join("\n"):"")}return""}(e);if("adpilotx"===e.requested_by){let t,i;return t=String(e.message||"AdPilotX update"),'<div style="margin:10px 0;border:1px solid #e3e3ea;border-left:4px solid '+((i=/alert · critical/i.test(t))?"#d64545":"#7256ec")+';border-radius:12px;background:#fff;padding:10px 12px"><div style="font-size:11px;font-weight:800;color:'+(i?"#d64545":"#7256ec")+'">\uD83E\uDD16 AdPilotX \xb7 '+(i?"Alert":"Report")+'</div><div style="font-weight:800;font-size:13.5px;color:#17141f;margin:2px 0 4px;overflow-wrap:anywhere">'+(0,a.ZD)(t)+"</div>"+(s?'<div style="font-size:13px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere">'+(0,a.ZD)(s)+"</div>":"")+'<div class="muted" style="font-size:10.5px;margin-top:4px">'+(0,a.ZD)(L(e.responded_at||e.requested_at))+"</div></div>"}let d=s?(t=s+("pending"===e.status?"\nâ¦still working on it":""),i=e.responded_at||e.requested_at,'<div style="display:flex;justify-content:flex-start;margin:8px 0"><div style="max-width:80%;background:'+("error"===e.status?"#fdeeee":"#f2f0fb")+';border-radius:12px 12px 12px 2px;padding:9px 12px"><div style="font-size:11px;font-weight:800;color:#7256ec;margin-bottom:2px">\uD83E\uDD16 AdPilotX</div><div style="font-size:13.5px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere">'+(0,a.ZD)(t)+'</div><div class="muted" style="font-size:10.5px;margin-top:3px">'+(0,a.ZD)(L(i))+"</div></div></div>"):"pending"===e.status?'<div style="display:flex;justify-content:flex-start;margin:8px 0"><div style="background:#f6f6f9;border-radius:12px;padding:7px 11px;font-size:12px;color:#8b8595">\uD83E\uDD16 AdPilotX is on it â replies within a minuteâ¦</div></div>':"";return n=function(e){if("media_refresh"===e.kind)return"â Ask AdPilotX â refresh the ads & Drive check";let t=String(e.message||"");return"staff_action"===e.kind?(/^PAUSE:/i.test(t)?"⸠":/^PUSH/i.test(t)?"\uD83D\uDE80 ":"")+t:t}(e),o=e.requested_by,r=e.requested_at,'<div style="display:flex;justify-content:flex-end;margin:8px 0"><div style="max-width:80%;background:#e9f0ff;border-radius:12px 12px 2px 12px;padding:9px 12px"><div style="font-size:13.5px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere">'+(0,a.ZD)(n)+'</div><div class="muted" style="font-size:10.5px;margin-top:3px;text-align:right">'+(0,a.ZD)(eI(o))+" \xb7 "+(0,a.ZD)(L(r))+"</div></div></div>"+d}function eE(e,t){let i=e.querySelector("#mt-thread");if(!i||!e._mt)return;let n=e._mt.threadFilter||"all",a=e.querySelector("#mt-filter");a&&a.querySelectorAll("[data-mt-filter]").forEach(e=>{let t=e.getAttribute("data-mt-filter")===n;e.classList.toggle("btn-primary",t),e.classList.toggle("btn-ghost",!t)});let o={all:e=>"staff_action"!==e.kind,staff:e=>"staff_action"!==e.kind&&"adpilotx"!==e.requested_by,reports:e=>"adpilotx"===e.requested_by,actions:e=>"staff_action"===e.kind}[n]||(e=>"staff_action"!==e.kind),r=e._mt.showHistory?0:function(){try{return Number(localStorage.getItem(e_)||0)||0}catch(e){return 0}}(),s=(e._mt.lastMsgs||[]).filter(o),d=r?s.filter(e=>Date.parse(e.requested_at||0)>r):s,l=s.length-d.length,p=e.querySelector("[data-mt-history]");p&&(p.style.display=l>0||e._mt.showHistory?"inline-block":"none"),i.innerHTML=d.length?(l>0?'<div class="muted" style="font-size:12px;margin:2px 0 8px">'+l+" earlier message"+(1===l?"":"s")+" hidden â tap \uD83D\uDD58 Show history.</div>":"")+d.map(eL).join(""):'<div class="notice">'+("reports"===n?"No reports or alerts yet.":"actions"===n?"No pause or push-live requests yet.":"No messages yet. Tap a button above or type a question.")+"</div>";let u=e.querySelector("#mt-new");u&&t&&(u.style.display="inline",clearTimeout(e._mt.newTimer),e._mt.newTimer=setTimeout(()=>{u.style.display="none"},12e3))}async function eM(e){let t=e.querySelector("#mt-thread");if(!t||!e._mt)return!1;let i=await _("/api/admin/media-tasks");
8if(!i||!Array.isArray(i.messages))return e._mt.lastMsgs||(t.innerHTML='<div class="notice">Couldn\'t load the conversation â it will retry in a few seconds.</div>'),!1;let n=i.messages.slice().sort((e,t)=>String(t.requested_at||"").localeCompare(String(e.requested_at||""))),a=n.map(e=>e.id+":"+e.status+":"+(e.responded_at||"")).join("|"),o="string"==typeof e._mt.threadSig,r=a!==e._mt.threadSig;e._mt.threadSig=a,e._mt.lastMsgs=n;let s=n.filter(e=>"staff_action"!==e.kind).map(e=>e.id+":"+e.status).join("|"),d=s!==e._mt.chatSig;return e._mt.chatSig=s,(r||!t.innerHTML)&&eE(e,o&&d),n.some(e=>"pending"===e.status&&"adpilotx"!==e.requested_by)}let eZ=[["needs","â ï¸ Needs fixing"],["changes_required","Changes required"],["review_failed","Review failed"],["approved","Approved"],["not_reviewed","Not reviewed"],["all","All"]],eR={changes_required:["#d64545","Changes required"],review_failed:["#c77700","Review failed"],approved:["#1f8a4c","Approved"],not_reviewed:["#77708a","Not reviewed"],in_review:["#7256ec","In review"]};function eC(e,t){let i=e.querySelector("#mt-review-count");if(!i||!t)return;let n=Number(t.needsAction||0);i.textContent=n>0?String(n):"",i.style.display=n>0?"inline-block":"none"}async function ej(e){let t=await _("/api/admin/media-tasks?reviews=1&status=changes_required");return t&&t.ok&&eC(e,t.summary),t}function eO(e,t){let[i,n]=eR[e.status]||["#77708a",String(e.status||"")],o=Array.isArray(e.reasons)?e.reasons:[],r=Array.isArray(e.advice)?e.advice:[],s=[e.headline,e.body].filter(Boolean).join("\n");return'<div class="mt-rcard" data-i="'+t+'" style="border:1px solid #e3e3ea;border-left:4px solid '+i+';border-radius:12px;background:#fff;padding:10px 12px;margin-bottom:10px"><div style="display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between"><b style="font-size:13.5px;color:#17141f;overflow-wrap:anywhere">'+(0,a.ZD)(e.ad_name||e.ad_id)+'</b><span style="font-size:11px;font-weight:800;color:#fff;background:'+i+';border-radius:999px;padding:2px 9px">'+(0,a.ZD)(n)+'</span></div><div class="muted" style="font-size:11.5px;margin:3px 0 6px">'+(0,a.ZD)("running"===e.delivery?"â¶ Running":"⸠Paused")+(e.campaign_name?" \xb7 "+(0,a.ZD)(e.campaign_name):"")+(e.reviewed_at?" \xb7 checked "+(0,a.ZD)(L(e.reviewed_at)):"")+"</div>"+(o.length?'<ul style="margin:4px 0 6px 18px;padding:0;font-size:13px;color:#8a1c1c">'+o.map(e=>"<li>"+(0,a.ZD)(e)+"</li>").join("")+"</ul>":"")+(r.length?'<div style="font-size:12px;color:#5b5670;margin-bottom:6px">\uD83D\uDCA1 '+r.map(a.ZD).join(" \xb7 ")+"</div>":"")+(e.text_optimisation?'<div style="font-size:12px;color:#8a5a00;margin-bottom:6px">â Meta may rewrite this text â spot-check what it shows in Ads Manager.</div>':"")+(s?'<details style="margin-bottom:6px"><summary style="cursor:pointer;font-size:12px;color:#7256ec">Current text</summary><div style="white-space:pre-wrap;font-size:12.5px;color:#17141f;margin-top:4px">'+(0,a.ZD)(s)+"</div></details>":"")+'<div style="display:flex;flex-wrap:wrap;gap:6px"><button class="btn btn-sm btn-primary" data-mt-rfix="'+t+'">âï¸ Fix text</button><button class="btn btn-sm btn-ghost" data-mt-rcheck="'+t+'">\uD83D\uDD01 Re-check</button><button class="btn btn-sm btn-ghost" data-mt-rhist="'+t+'">\uD83D\uDD58 History</button>'+("changes_required"===e.status||"review_failed"===e.status?'<button class="btn btn-sm" data-mt-rover="'+t+'" style="background:#1f8a4c;color:#fff">â
I\'ve checked it â push anyway</button>':"")+'</div><div data-mt-rpanel="'+t+'"></div><div data-mt-rout="'+t+'" style="display:none;margin-top:6px;font-size:12.5px;white-space:pre-wrap;color:#17141f"></div></div>'}async function eX(e,t,i){let n=e.querySelector('[data-mt-rout="'+t+'"]'),a=e=>{n&&(n.style.display="block",n.textContent=e)};for(let t=0;t<36;t++){if(await new Promise(e=>setTimeout(e,5e3)),!document.body.contains(n))return;let t=await _("/api/admin/media-tasks?signal="+encodeURIComponent(i)),o=t&&t.signal,r=o&&o.response&&o.response.text;if(r&&a("\uD83E\uDD16 "+r),o&&o.status&&"pending"!==o.status){r||a("done"===o.status?"Done â":"AdPilotX reported a problem."),ej(e).catch(()=>{});return}}a("\uD83E\uDD16 Still working â AdPilotX will finish it; check this advert again in a few minutes.")}async function eH(e,t){let i=e.querySelector("#mt-rlist");if(!i)return;let n="all"===t||"needs"===t?"":"&status="+encodeURIComponent(t),o=await _("/api/admin/media-tasks?reviews=1"+n);if(!o||!o.ok){i.innerHTML='<div class="notice">Couldn\'t load the review list â try again shortly.</div>';return}eC(e,o.summary);let r=o.items||[];if("needs"===t&&(r=r.filter(e=>"running"===e.delivery&&("changes_required"===e.status||"review_failed"===e.status))),e._mt.reviewItems=r,!r.length){i.innerHTML='<div class="notice">'+("needs"===t?"â
No running advert needs fixing right now.":o.summary&&o.summary.total?"Nothing in this filter.":"Nothing here yet â the first hourly check fills this in.")+"</div>";return}i.innerHTML=r.map(eO).join(""),i.onclick=async t=>{let n=t.target.closest("[data-mt-rfix],[data-mt-rcheck],[data-mt-rhist],[data-mt-rapply],[data-mt-rover],[data-mt-rovgo]");if(!n)return;let o=Number(n.getAttribute("data-mt-rfix")??n.getAttribute("data-mt-rcheck")??n.getAttribute("data-mt-rhist")??n.getAttribute("data-mt-rapply")??n.getAttribute("data-mt-rover")??n.getAttribute("data-mt-rovgo")),r=(e._mt.reviewItems||[])[o];if(!r)return;let s=i.querySelector('[data-mt-rpanel="'+o+'"]'),d=i.querySelector('[data-mt-rout="'+o+'"]'),l=e=>{d.style.display="block",d.textContent=e};if(n.hasAttribute("data-mt-rfix")){s.innerHTML='<textarea data-mt-rtext="'+o+'" rows="3" maxlength="500" style="width:100%;box-sizing:border-box;margin-top:8px;padding:8px;border:1px solid #d7d7e0;border-radius:10px;font:inherit;font-size:13.5px">'+(0,a.ZD)(r.body||"")+'</textarea><div style="display:flex;gap:6px;align-items:center;margin-top:6px"><button class="btn btn-sm btn-primary" data-mt-rapply="'+o+'">Apply</button><span class="muted" style="font-size:11.5px">AdPilotX checks it against our rules first and only applies it if it passes.</span></div>';return}if(n.hasAttribute("data-mt-rapply")){let t=s.querySelector('[data-mt-rtext="'+o+'"]'),i=(t&&t.value||"").trim();if(!i)return void l("Type the new text first.");n.disabled=!0,l("Sendingâ¦");let a=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"apply_edit",ad_id:String(r.ad_id),ad_name:r.ad_name||"",text:i})});if(!a||!a.ok||!a.signal_id){n.disabled=!1,l("Couldn't send: "+(a&&(a.detail||a.error)||"try again"));return}return l("Sent â â AdPilotX is checking the new text (usually under a minute)â¦"),eX(e,o,a.signal_id)}if(n.hasAttribute("data-mt-rover")){s.innerHTML='<textarea data-mt-rreason="'+o+'" rows="2" maxlength="300" placeholder="Why is it OK? e.g. checked with Vic â the wording is fine for Meta" style="width:100%;box-sizing:border-box;margin-top:8px;padding:8px;border:1px solid #d7d7e0;border-radius:10px;font:inherit;font-size:13.5px"></textarea><div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:6px"><button class="btn btn-sm" data-mt-rovgo="'+o+'" style="background:#1f8a4c;color:#fff">Confirm â push anyway</button><span class="muted" style="font-size:11.5px">Marks the wording as checked by you (logged). It does not switch a paused advert on â use RESUME for that. Meta still reviews it; protected adverts are never changed.</span></div>';return}if(n.hasAttribute("data-mt-rovgo")){let t=s.querySelector('[data-mt-rreason="'+o+'"]'),i=(t&&t.value||"").trim();if(!i)return void l("Say why it is OK first.");n.disabled=!0,l("Sendingâ¦");let a=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"override",ad_id:String(r.ad_id),ad_name:r.ad_name||"",reason:i})});if(!a||!a.ok||!a.signal_id){n.disabled=!1,l("Couldn't send: "+(a&&(a.detail||a.error)||"try again"));return}
8return l("Sent â â AdPilotX is approving it (usually under a minute)â¦"),eX(e,o,a.signal_id)}if(n.hasAttribute("data-mt-rcheck")){n.disabled=!0,l("Asking AdPilotX to re-checkâ¦");let t=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"recheck",ad_id:String(r.ad_id),ad_name:r.ad_name||""})});if(!t||!t.ok||!t.signal_id){n.disabled=!1,l("Couldn't send: "+(t&&(t.detail||t.error)||"try again"));return}return eX(e,o,t.signal_id)}if(n.hasAttribute("data-mt-rhist")){let e=await _("/api/admin/media-tasks?review_history="+encodeURIComponent(String(r.ad_id))),t=e&&e.history||[];s.innerHTML=t.length?'<ul style="margin:8px 0 0 18px;padding:0;font-size:12px;color:#17141f">'+t.map(e=>"<li>"+(0,a.ZD)(L(e.at))+" â "+(0,a.ZD)(e.kind)+(e.actor?" by "+(0,a.ZD)(eI(e.actor)):"")+(Array.isArray(e.reasons)&&e.reasons.length?": "+(0,a.ZD)(e.reasons.join("; ")):"")+"</li>").join("")+"</ul>":'<div class="muted" style="font-size:12px;margin-top:6px">No history yet.</div>'}}}let eF={ledger:"matched by rotation log (exact filename)",generic_ledger:"matched by Drive file id (generic reach)",video_title:"matched by the Meta video title (exact)",video_url:"matched as the competition's Spotlight video",concept:"â probable â name similarity only"};function eU(e){return(e=Number(e||0))?e<1048576?Math.round(e/1024)+" KB":e<0x40000000?(e/1048576).toFixed(1)+" MB":(e/0x40000000).toFixed(2)+" GB":""}function eW(e){if(!e)return"";let t=new Date(e);return Number.isNaN(t.getTime())?"":t.toLocaleDateString("en-GB",{day:"numeric",month:"short"})}let eB={P0:"#e5484d",P1:"#f06a3f",P2:"#e5a23c",P3:"#3987e5",P4:"#8b8595"};function eG(e,t){if(!t)return null;let i=String(t);return(e||[]).find(e=>e&&null!=e.id&&String(e.id)===i)||(e||[]).find(e=>e&&e.name===i)||null}function eV(e,t){let i=e&&e.usage||{},n=[],a=new Set;for(let e of i.adIds||[]){let i=eG(t,e),o=i?String(i.id||i.name):String(e);a.has(o)||(a.add(o),n.push(i||{id:String(e),name:null}))}for(let e of i.adNames||[]){if(n.some(t=>t.name===e))continue;let i=eG(t,e),o=i?String(i.id||i.name):e;a.has(o)||(a.add(o),n.push(i||{name:e}))}return n}function eK(e,t,i){let n=e.querySelector("#mt-modal");if(!n)return null;n.innerHTML='<div id="mt-modal-bg" style="position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px"><div style="background:#fff;border-radius:14px;max-width:640px;width:100%;max-height:85vh;overflow:auto;padding:18px 20px;color:#17141f" id="mt-modal-card">'+t+"</div></div>";let a=()=>{n.innerHTML="",i&&i()};n.querySelector("#mt-modal-bg").addEventListener("click",e=>{"mt-modal-bg"===e.target.id&&a()});let o=n.querySelector("#mt-modal-x");return o&&o.addEventListener("click",a),n}function eY(e,t,i){let n=e.usage||null,o=void 0!==e._st?e._st:k(e,i),r=!!(n&&"fuzzy"===n.confidence),s=n&&n.via?eF[n.via]||n.via:"",l=[eU(e.size),s,n&&n.firstUsedAt?"first used "+eW(n.firstUsedAt):"",n&&n.lastUsedAt&&n.lastUsedAt!==n.firstUsedAt?"last "+eW(n.lastUsedAt):""].filter(Boolean).join(" \xb7 "),p=o?o.linked:eV(e,i),u=p.length?'<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:5px;align-items:center">'+p.map((e,i)=>{let n=/ACTIVE/i.test(e.status||""),o=e.name||"ad â¦"+String(e.id||"").slice(-6);return'<button class="btn btn-ghost btn-sm" data-mt-ad="'+t+":"+i+'" style="padding:2px 8px;font-size:11.5px;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-color:'+(n?"#138c60":"#ccc")+'" title="Click for ROAS, frequency, ad set, campaign and what AdPilotX will do">'+(n?"\uD83D\uDFE2 ":"⸠")+(0,a.ZD)(o)+(e.roas?" \xb7 "+Number(e.roas).toFixed(2)+"\xd7":"")+(n&&e.frequency?" "+w(e.frequency):"")+"</button>"}).join("")+"</div>":"",c=o&&d[o.key],m=c?'<div style="margin-top:3px;font-size:12px;font-weight:800;color:'+c.c+'">'+c.e+" "+(0,a.ZD)(c.label.toUpperCase())+(o.tired?' <span style="color:#b7791f">\xb7 GETTING TIRED</span>':"")+("used"===o.key&&o.proven?' <span style="color:#138c60">\xb7 PROVEN</span>':"")+'</div><div style="font-size:12px;color:#3a3442;margin-top:1px">'+(0,a.ZD)(o.text)+"</div>":"",f=n&&n.note&&!(o&&("silent"===o.key||"unused"===o.key))?'<div style="font-size:11.5px;color:#8b8595;margin-top:2px">'+(0,a.ZD)(String(n.note))+"</div>":"",g=o&&"silent"===o.key?";opacity:.55":"",h=/tiktok|no[\s_-]?music/i.test(e.name||"")?'<div style="margin-top:3px;font-size:11.5px;font-weight:800;color:#0f766e">\uD83C\uDFB5 TikTok only â never used for Facebook / Instagram ads</div>':"";return'<div style="border-bottom:1px solid #eee;padding:9px 0'+g+'"><div style="display:flex;justify-content:space-between;gap:10px;align-items:flex-start;flex-wrap:wrap"><div style="min-width:0;flex:1"><div style="font-size:13px;color:#17141f;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="'+(0,a.ZD)(e.path||e.name||"")+'">'+(r?'<span style="color:#b7791f;font-weight:800" title="Probable match by name only â not verified">â probably</span> ':"")+(0,a.ZD)(e.name||"(file)")+"</div>"+(l?'<div style="font-size:11.5px;color:#8b8595;margin-top:1px">'+(0,a.ZD)(l)+"</div>":"")+h+m+f+u+'</div><div style="flex:none;display:flex;flex-direction:column;gap:4px;align-items:flex-end">'+(e.link?'<a class="btn btn-ghost btn-sm" href="'+(0,a.ZD)(e.link)+'" target="_blank" rel="noopener">Open â¸</a>':"")+(!e.id||h||o&&("running"===o.key||"fatigued"===o.key||"probable"===o.key)?"":'<button class="btn btn-primary btn-sm" data-mt-push="'+t+'" title="AdPilotX puts this video live in the best place (compet
8ition ad set, warm or new audience, or Always-On)">\uD83D\uDE80 Push live</button>')+'</div><div data-mt-push-out="'+t+'" style="display:none;flex-basis:100%;margin-top:6px;font-size:12.5px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere;background:#f2f0fb;border-radius:10px;padding:7px 10px"></div></div></div>'}function eJ(e,t){let i,n=t.ads||[],o=(t.files||[]).map((e,t)=>({...e,_i:t,_st:k(e,n)})),r=o.some(e=>e._st);if(o.length)if(r){i=l.map(e=>{let t=o.filter(t=>t._st&&t._st.key===e);if(!t.length)return"";let i=d[e],r=t.filter(e=>e.usage&&"fuzzy"===e.usage.confidence).length,s="";if("used"===e){let e=t.filter(e=>e._st.proven).length;e&&(s=" \xb7 "+e+" proven (1.5\xd7+)")}if("running"===e){let e=t.filter(e=>e._st.tired).length;e&&(s=" \xb7 "+e+" getting tired")}let l="unused"===e?" â tap \uD83D\uDE80 Push live and AdPilotX puts it in the ads, or tells you why it can't":"used"===e?" â \uD83D\uDE80 Push live to bring one back":"fatigued"===e?" â AdPilotX rotates these out; fresh cuts needed":"silent"===e?" â never attached (audio gate)":"";return'<div style="margin-top:12px"><div style="font-size:12px;font-weight:800;color:'+i.c+';text-transform:uppercase;letter-spacing:.04em">'+i.e+" "+(0,a.ZD)(i.label)+" ("+t.length+")"+(0,a.ZD)(s)+(r?' <span style="font-weight:500;color:#b7791f;text-transform:none">\xb7 '+r+" â probable</span>":"")+(l?'<span style="font-weight:500;text-transform:none;color:#8b8595">'+(0,a.ZD)(l)+"</span>":"")+"</div>"+t.map(e=>eY(e,e._i,n)).join("")+"</div>"}).join("");let e=o.filter(e=>!e._st);e.length&&(i+='<div style="margin-top:12px"><div style="font-size:12px;font-weight:800;color:#8b8595;text-transform:uppercase;letter-spacing:.04em">No usage data ('+e.length+")</div>"+e.map(e=>eY(e,e._i,n)).join("")+"</div>")}else i=o.map(e=>eY(e,e._i,n)).join("");else i='<div class="muted" style="font-size:13px">'+(0,a.ZD)(t.empty||"No media matched in the current snapshot.")+"</div>";let s=S(o,n)||A(t.usage),p=eK(e,'<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:4px"><b style="font-size:15px">'+(0,a.ZD)(t.title||"")+'</b><div style="display:flex;gap:8px;align-items:center">'+D(s,!1)+'<button class="btn btn-ghost btn-sm" id="mt-modal-x">Close â</button></div></div><div class="muted" style="font-size:12px;margin-bottom:6px">'+o.length+" media file"+(1===o.length?"":"s")+(t.subtitle?" \xb7 "+(0,a.ZD)(t.subtitle):"")+"</div>"+(r?'<div style="font-size:11.5px;color:#8b8595;margin-bottom:4px">'+(0,a.ZD)(u)+" \xb7 freq pill: green under 2.5, amber getting tired, red 3.5+ frequency too high</div>":"")+i);p&&(p.querySelectorAll("[data-mt-push]").forEach(e=>{t.noPush?e.remove():e.addEventListener("click",()=>{let t=o[Number(e.getAttribute("data-mt-push"))];t&&e1(p,t,e)})}),p.querySelectorAll("[data-mt-ad]").forEach(i=>i.addEventListener("click",()=>{let[a,r]=i.getAttribute("data-mt-ad").split(":").map(Number),s=o[a];if(!s)return;let d=(s._st?s._st.linked:eV(s,n))[r];d&&eQ(e,d,s,()=>eJ(e,t))})))}function e$(e,t){return null==t||""===t?"":'<div style="display:flex;gap:10px;font-size:13px;padding:4px 0;border-bottom:1px solid #f0f0f4"><div style="width:110px;flex:none;color:#8b8595">'+(0,a.ZD)(e)+'</div><div style="min-width:0;color:#17141f;word-break:break-word">'+t+"</div></div>"}function eQ(e,t,i,n){let o=e._mt&&e._mt.needs||{},r=Number(t.roas||0),s=Number(t.frequency||0),l=/ACTIVE/i.test(t.status||""),u=t.source||null,c=N(t),m=p[v(s)],f=i&&i.usage?k(i,o.ads||[]):null,g=i&&i.name?(0,a.ZD)(i.name)+(i.link?' <a href="'+(0,a.ZD)(i.link)+'" target="_blank" rel="noopener">Open â¸</a>':"")+(f?'<div style="font-size:12px;margin-top:2px;color:'+d[f.key].c+';font-weight:700">'+d[f.key].e+" "+(0,a.ZD)(d[f.key].label)+'</div><div style="font-size:12px;color:#3a3442">'+(0,a.ZD)(f.text)+"</div>":""):"",h=eK(e,'<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px"><div style="display:flex;gap:8px;align-items:center">'+(n?'<button class="btn btn-ghost btn-sm" id="mt-modal-back">â¹ Back</button>':"")+'<b style="font-size:15px">Ad</b></div><button class="btn btn-ghost btn-sm" id="mt-modal-x">Close â</button></div><div style="display:flex;gap:14px;align-items:flex-start">'+(t.image?'<img src="'+(0,a.ZD)(t.image)+'" alt="" style="width:96px;height:96px;object-fit:cover;border-radius:10px;flex:none;background:#f0f0f4" loading="lazy" />':'<div style="width:96px;height:96px;border-radius:10px;background:#f0f0f4;flex:none"></div>')+'<div style="min-width:0;flex:1"><div style="font-size:15px;font-weight:800;color:#17141f;word-break:break-word">'+(0,a.ZD)(t.name||"ad â¦"+String(t.id||"").slice(-6))+'</div><div style="margin-top:4px;font-size:13px;font-weight:700;color:'+(l?"#138c60":"#8b8595")+'">'+(l?"\uD83D\uDFE2 Live now":"⸠"+(0,a.ZD)(t.status||"not running"))+'</div><div style="margin-top:6px;display:flex;gap:14px;flex-wrap:wrap"><div><div class="muted" style="font-size:10.5px;text-transform:uppercase">ROAS</div><div style="font-size:18px;font-weight:800;color:'+K(r)+'">'+(r?r.toFixed(2)+"\xd7":"â")+'</div></div><div><div class="muted" style="font-size:10.5px;text-transform:uppercase">Frequency</div><div style="font-size:18px;font-weight:800;color:'+(s?m.c:"#17141f")+'">'+(s?s.toFixed(1)+"\xd7":"â")+"</div>"+(s?'<div style="margin-top:2px">
8'+w(s)+"</div>":"")+'</div><div><div class="muted" style="font-size:10.5px;text-transform:uppercase">Bookings</div><div style="font-size:18px;font-weight:800;color:#17141f">'+(null!=t.purchases&&""!==t.purchases?(0,a.ZD)(String(t.purchases)):"â")+'</div></div></div></div></div><div style="margin-top:10px;padding:8px 10px;border-radius:10px;background:'+c.c+"11;border:1px solid "+c.c+'44;font-size:13px;color:#17141f"><b style="color:'+c.c+'">What AdPilotX will do:</b> '+(c.auto?"\uD83E\uDD16 ":"")+(0,a.ZD)(c.t)+(c.auto?' <span class="muted" style="font-size:11.5px">(unattended)</span>':"")+'</div><div style="margin-top:12px">'+e$("Ad set",t.adset?(0,a.ZD)(t.adset):"")+e$("Campaign",t.campaign?(0,a.ZD)(t.campaign):"")+e$("Drive file",g)+e$("Match",u?(0,a.ZD)(("fuzzy"===u.confidence?"â probable â ":"exact â ")+(eF[u.via]||u.via||"")):i&&i.usage&&i.usage.via?(0,a.ZD)(("fuzzy"===i.usage.confidence?"â probable â ":"exact â ")+(eF[i.usage.via]||i.usage.via)):"")+e$("Ad id",t.id?'<code style="font-size:12px">'+(0,a.ZD)(String(t.id))+"</code>":"")+e$("Video id",t.videoId?'<code style="font-size:12px">'+(0,a.ZD)(String(t.videoId))+"</code>":"")+"</div>"+(l&&t.id?'<div style="margin-top:14px;padding:10px 12px;border:1px solid #e3e3ea;border-radius:12px;background:#fbfaff"><div style="font-weight:800;font-size:13.5px;color:#17141f;margin-bottom:6px">⸠Pause this ad</div><input id="mt-pause-reason" type="text" maxlength="300" placeholder="Why? e.g. wrong video, prize has changed, competition sold out" style="width:100%;box-sizing:border-box;padding:9px 10px;border:1px solid #d7d7e0;border-radius:10px;font:inherit;font-size:13.5px" /><div style="display:flex;gap:10px;align-items:center;margin-top:8px;flex-wrap:wrap"><button id="mt-pause-go" class="btn btn-primary btn-sm">⸠Pause this ad</button><span id="mt-pause-status" class="muted" style="font-size:12.5px">AdPilotX pauses it within a minute and says what happens next.</span></div><div id="mt-pause-reply" style="display:none;margin-top:8px;font-size:13px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere;background:#f2f0fb;border-radius:10px;padding:8px 10px"></div></div>':"")+(l?"":t.source&&t.source.driveId&&!/tiktok|no[\s_-]?music/i.test(t.source.driveName||"")?'<div style="margin-top:14px;padding:10px 12px;border:1px solid #e3e3ea;border-radius:12px;background:#f5fbf8"><div style="font-weight:800;font-size:13.5px;color:#17141f;margin-bottom:4px">\uD83D\uDE80 Push this video live</div><div class="muted" style="font-size:12px;margin-bottom:8px">AdPilotX puts the video back in the ads in the best place right now â its competition's ad set (warm if it has worked before, new audience if not) or the Always-On set for a generic video.</div><div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap"><button id="mt-push-go" class="btn btn-primary btn-sm">\uD83D\uDE80 Push live</button><span id="mt-push-status" class="muted" style="font-size:12.5px"></span></div><div id="mt-push-reply" style="display:none;margin-top:8px;font-size:13px;color:#17141f;white-space:pre-wrap;overflow-wrap:anywhere;background:#f2f0fb;border-radius:10px;padding:8px 10px"></div></div>':'<div class="muted" style="font-size:12px;margin-top:12px">No Drive video is linked to this ad, so it can't be pushed from here â push the video from its competition's media list on the Health Board.</div>')+'<div class="muted" style="font-size:11px;margin-top:10px">Health only â ROAS, frequency and bookings. No spend or revenue is shown here.</div>');if(!h)return;let y=h.querySelector("#mt-modal-back");y&&n&&y.addEventListener("click",n);let b=h.querySelector("#mt-pause-go");b&&b.addEventListener("click",()=>e8(h,t));let x=h.querySelector("#mt-push-go");return x&&x.addEventListener("click",()=>e0(h,t)),h}async function e0(e,t){let i=e.querySelector("#mt-push-go"),n=e.querySelector("#mt-push-status"),a=e.querySelector("#mt-push-reply");if(!i||i.disabled||!(t.source&&t.source.driveId))return;i.disabled=!0,n.textContent="Sendingâ¦";let o=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"push_file",drive_id:String(t.source.driveId),file_name:t.source.driveName||t.name||""})});if(!o||!o.ok||!o.signal_id){n.textContent="Couldn't send: "+(o&&(o.detail||o.error)||"try again"),i.disabled=!1;return}n.textContent="Sent â â AdPilotX is placing it (usually under a minute)â¦";for(let t=0;t<36;t++){if(await new Promise(e=>setTimeout(e,5e3)),!document.body.contains(e)||!e.querySelector("#mt-push-status"))return;let t=await _("/api/admin/media-tasks?signal="+encodeURIComponent(o.signal_id)),i=t&&t.signal,r=i&&i.response&&i.response.text;if(r&&(a.style.display="block",a.textContent="\uD83E\uDD16 "+r),i&&i.status&&"pending"!==i.status){n.textContent="done"===i.status?"Done â":"AdPilotX reported a problem â the owner has been told.";return}}n.textContent="Still working â AdPilotX will finish it; check this ad again in a few minutes."}async function e1(e,t,i){let n=e.querySelector('[data-mt-push-out="'+t._i+'"]'),a=e=>{n&&(n.style.display="block",n.textContent=e)};i.disabled=!0,i.textContent="Sendingâ¦";let o=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"push_file",drive_id:String(t.id),file_name:t.name||""})});if(!o||!o.ok||!o.signal_id){i.disabled=!1,i.textContent="\uD83D\uDE80 Push live",a("Couldn't send: "+(o&&(o.detail||o.error)||"try again"));return}i.textContent="Sent â",a("\uD83E\uDD16 AdPilotX is placing it â usually under a minuteâ¦");for(let t=0;t<36;t++){if(await new Promise(e=>setTimeout(e,5e3)),!document.body.contains(e))return;let t=await _("/api/admin/media-tasks?signal="+encodeURIComponent(o.signal_id)),n=t&&t.signal,r=n&&n.response&&n.response.text;if(r&&a("\uD83E\uDD16 "+r),n&&n.status&&"pending"!==n.status){i.textContent="done"===n.status?"Done â":"Problem";return}}a("\uD83E\uDD16 Still working â AdPilotX will finish it; check this competition again in a few minutes.")}async function e8(e,t){let i=e.querySelector("#mt-pause-go"),n=e.querySelector("#mt-pause-reason"),a=e.querySelector("#mt-pause-status"),o=e.querySelector("#mt-pause-reply"),r=(n&&n.value||"").trim();if(!r){a.textContent="Say why first â AdPilotX uses the reason to decide what to fix.",n&&n.focus();return}i.disabled=!0,n&&(n.disabled=!0),a.textContent="Sendingâ¦";let s=await _("/api/admin/media-tasks",{method:"POST",body:JSON.stringify({action:"pause_ad",ad_id:String(t.id),ad_name:t.name||"",reason:r})});if(!s||!s.ok||!s.signal_id){a.textContent="Couldn't send: "+(s&&(s.detail||s.error)||"try again"),i.disabled=!1,n&&(n.disabled=!1);return}a.textContent="Sent â â waiting for AdPilotX (usually under a minute)â¦";for(let t=0;t<36;t++){if(await new Promise(e=>setTimeout(e,5e3)),!document.body.contains(e)||!e.querySelector("#mt-pause-status"))return;let t=await _("/api/admin/media-tasks?signal="+encodeURIComponent(s.signal_id)),i=t&&t.signal,n=i&&i.response&&(i.response.text||"");if(n&&(o.style.display="block",o.textContent="\uD83E\uDD16 "+n),i&&i.status&&"pending"!==i.status){a.textContent="done"===i.status?"Done â":"AdPilotX reported a problem â the owner has been told.";return}}a.textContent="Still waiting â AdPilotX may be busy. It will still act on it; check this ad again in a few minutes."}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.