Aced Helper v1.3

Score spoofer

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Aced Helper v1.3
// @namespace    https://omoggle.com/
// @version      1.3.0
// @description  Score spoofer
// @match        https://omoggle.com/*
// @match        https://*.omoggle.com/*
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';
  const W = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
  const LS_KEY = 'aced_cfg_v1';

  const FileStore = {
    DB: 'aced_files', STORE: 'media', KEY: 'afk', _db: null,
    _open() {
      if (this._db) return Promise.resolve(this._db);
      return new Promise((res, rej) => {
        const req = indexedDB.open(this.DB, 1);
        req.onupgradeneeded = () => { const db = req.result; if (!db.objectStoreNames.contains(this.STORE)) db.createObjectStore(this.STORE); };
        req.onsuccess = () => { this._db = req.result; res(this._db); };
        req.onerror = () => rej(req.error);
      });
    },
    async save(blob, meta) {
      try { const db = await this._open(); return await new Promise((res, rej) => { const tx = db.transaction(this.STORE, 'readwrite'); tx.objectStore(this.STORE).put({ blob, meta }, this.KEY); tx.oncomplete = () => res(true); tx.onerror = () => rej(tx.error); }); } catch (e) { return false; }
    },
    async load() {
      try { const db = await this._open(); return await new Promise((res) => { const tx = db.transaction(this.STORE, 'readonly'); const rq = tx.objectStore(this.STORE).get(this.KEY); rq.onsuccess = () => res(rq.result || null); rq.onerror = () => res(null); }); } catch (e) { return null; }
    },
    async clear() {
      try { const db = await this._open(); return await new Promise((res) => { const tx = db.transaction(this.STORE, 'readwrite'); tx.objectStore(this.STORE).delete(this.KEY); tx.oncomplete = () => res(true); tx.onerror = () => res(false); }); } catch (e) { return false; }
    },
  };

  const THEMES = {
    red:    { bg:'#0a0709', surf:'#110d0f', surf2:'#181215', border:'rgba(180,30,50,0.18)', border2:'rgba(180,30,50,0.32)', accent:'#c0192c', accent2:'#e02240', accent3:'#ff3355', accentDim:'rgba(192,25,44,0.12)', accentGlow:'rgba(224,34,64,0.22)', green:'#22a84a', green2:'#2fd65e', muted:'#5a4a50', muted2:'#8a7078', text:'#e8dde0', text2:'#c0aab0' },
    blue:   { bg:'#07090a', surf:'#0d1011', surf2:'#121518', border:'rgba(30,100,180,0.18)', border2:'rgba(30,100,180,0.32)', accent:'#1964c0', accent2:'#2278e0', accent3:'#3399ff', accentDim:'rgba(25,100,192,0.12)', accentGlow:'rgba(34,120,224,0.22)', green:'#22a84a', green2:'#2fd65e', muted:'#4a5060', muted2:'#7080a0', text:'#dde2e8', text2:'#aab8c0' },
    green:  { bg:'#07090a', surf:'#0d1110', surf2:'#121815', border:'rgba(30,160,80,0.18)', border2:'rgba(30,160,80,0.32)', accent:'#19a050', accent2:'#22c060', accent3:'#33ff99', accentDim:'rgba(25,160,80,0.12)', accentGlow:'rgba(34,192,96,0.22)', green:'#22a84a', green2:'#2fd65e', muted:'#4a6050', muted2:'#708070', text:'#dde8e0', text2:'#aac0b0' },
    purple: { bg:'#09070a', surf:'#110d11', surf2:'#181218', border:'rgba(120,30,180,0.18)', border2:'rgba(120,30,180,0.32)', accent:'#7819c0', accent2:'#9022e0', accent3:'#cc33ff', accentDim:'rgba(120,25,192,0.12)', accentGlow:'rgba(144,34,224,0.22)', green:'#22a84a', green2:'#2fd65e', muted:'#584a60', muted2:'#887090', text:'#e4dde8', text2:'#b8aac0' },
    gold:   { bg:'#0a0900', surf:'#110f00', surf2:'#181500', border:'rgba(180,140,0,0.18)', border2:'rgba(180,140,0,0.32)', accent:'#b08800', accent2:'#d4a800', accent3:'#ffd700', accentDim:'rgba(180,140,0,0.12)', accentGlow:'rgba(212,168,0,0.22)', green:'#22a84a', green2:'#2fd65e', muted:'#605040', muted2:'#908060', text:'#e8e0cc', text2:'#c0b080' },
    cyan:   { bg:'#06090a', surf:'#0b1012', surf2:'#101619', border:'rgba(0,180,200,0.18)', border2:'rgba(0,180,200,0.34)', accent:'#0098b0', accent2:'#00c0d8', accent3:'#22e5ff', accentDim:'rgba(0,180,200,0.12)', accentGlow:'rgba(0,200,224,0.25)', green:'#22a84a', green2:'#2fd65e', muted:'#3a5560', muted2:'#5a8590', text:'#d8eef2', text2:'#a0c8d0' },
    pink:   { bg:'#0a060a', surf:'#120b12', surf2:'#191019', border:'rgba(220,40,140,0.18)', border2:'rgba(220,40,140,0.34)', accent:'#c01880', accent2:'#e022a0', accent3:'#ff44cc', accentDim:'rgba(220,40,140,0.12)', accentGlow:'rgba(224,34,160,0.25)', green:'#22a84a', green2:'#2fd65e', muted:'#603a55', muted2:'#905a85', text:'#f2d8ec', text2:'#d0a0c8' },
    mono:   { bg:'#08080a', surf:'#101012', surf2:'#161618', border:'rgba(200,200,210,0.14)', border2:'rgba(200,200,210,0.28)', accent:'#888890', accent2:'#b0b0b8', accent3:'#e8e8f0', accentDim:'rgba(200,200,210,0.10)', accentGlow:'rgba(220,220,230,0.20)', green:'#22a84a', green2:'#2fd65e', muted:'#55555c', muted2:'#85858c', text:'#e8e8ec', text2:'#b0b0b8' },
  };

  // Animated themes: a base palette + an animation class applied to #ac-root
  const ANIM_THEMES = {
    rainbow:  { base:'red',  anim:'ac-anim-rainbow',  label:'Rainbow' },
    aurora:   { base:'cyan', anim:'ac-anim-aurora',   label:'Aurora' },
    sunset:   { base:'pink', anim:'ac-anim-sunset',   label:'Sunset' },
    matrix:   { base:'green',anim:'ac-anim-matrix',   label:'Matrix' },
  };

  const DEFAULTS = {
    enabled:true, liveSpoof:true, liveMode:'fluctuate', liveMin:9.1, liveMax:9.3,
    finalMin:9.3, finalMax:9.6, realisticScoring:false, autoRequeue:false, autoStart:false,
    afkCam:false, autofarmDelay:3500, mirrorOpponent:false, invertCam:false, loopVideo:true,
    afkSource:'Video', zoomFit:false, guiHideKey:'h', liveSpoofKey:'1', finalScoreKey:'f',
    profiles:{}, theme:'red',
    // New tweaks
    panicKey:'`', clickAnim:true, scoreDrift:0.05, opacity:100, compactMode:false, randomizeStart:false,
    panelFX:true,
  };

  let CFG;
  try { CFG = Object.assign({}, DEFAULTS, JSON.parse(W.localStorage.getItem(LS_KEY) || '{}')); }
  catch (e) { CFG = Object.assign({}, DEFAULTS); }
  if (typeof CFG.profiles !== 'object' || Array.isArray(CFG.profiles)) CFG.profiles = {};
  if (!THEMES[CFG.theme] && !ANIM_THEMES[CFG.theme]) CFG.theme = 'red';

  function saveCfg() { try { W.localStorage.setItem(LS_KEY, JSON.stringify(CFG)); } catch (e) {} }

  let framesSent = 0;
  let currentScore = (DEFAULTS.finalMin + DEFAULTS.finalMax) / 2;

  const PARAMS = { FH:0.62,FW:0.394,JW:0.3597,JY:0.26,EY:0.058,IH:0.05,EW:0.0969,EH:0.029,T:0.0005,MOUTH:0.2103 };
  function genNorm(P) {
    const lm=Array.from({length:478},()=>({x:0.5,y:0.5,z:0}));
    const cx=0.5,cy=0.5;
    const set=(li,ri,hw,yy)=>{lm[li]={x:cx-hw,y:yy,z:0};lm[ri]={x:cx+hw,y:yy,z:0};};
    lm[10]={x:cx,y:cy-P.FH/2,z:0};lm[152]={x:cx,y:cy+P.FH/2,z:0};
    lm[234]={x:cx-P.FW/2,y:cy,z:0};lm[454]={x:cx+P.FW/2,y:cy,z:0};
    set(172,397,P.JW/2,cy+P.JY);set(150,379,P.JW/2,cy+P.JY*0.9);set(171,396,P.JW/2,cy+P.JY*1.1);
    const eyeY=cy-P.EY;
    lm[133]={x:cx-P.IH,y:eyeY,z:0};lm[33]={x:cx-P.IH-P.EW,y:eyeY-P.T,z:0};
    lm[362]={x:cx+P.IH,y:eyeY,z:0};lm[263]={x:cx+P.IH+P.EW,y:eyeY-P.T,z:0};
    const lcx=cx-P.IH-P.EW/2,rcx=cx+P.IH+P.EW/2;
    lm[159]={x:lcx,y:eyeY-P.EH/2,z:0};lm[145]={x:lcx,y:eyeY+P.EH/2,z:0};
    lm[386]={x:rcx,y:eyeY-P.EH/2,z:0};lm[374]={x:rcx,y:eyeY+P.EH/2,z:0};
    lm[1]={x:cx,y:cy,z:0};lm[0]={x:cx,y:eyeY+P.MOUTH,z:0};
    const fill=[[70,300,.18,-.12],[63,293,.14,-.14],[105,334,.10,-.16],[46,276,.20,-.10],[116,345,.22,.02],[123,352,.20,.06],[50,280,.18,.10],[187,411,.16,.16],[132,361,.24,0],[174,399,.06,.20],[136,365,.12,.20],[148,377,.08,.24],[176,401,.10,.22],[58,288,.22,-.04]];
    for(const f of fill){lm[f[0]]={x:cx-f[2],y:cy+f[3],z:0};lm[f[1]]={x:cx+f[2],y:cy+f[3],z:0};}
    return lm;
  }
  const _NORM=genNorm(PARAMS);
  const PEAK_DELTAS={0:[.00246,-.00153],133:[-.00555,-.00524],159:[.00505,.00195],176:[.00405,-.00590],187:[.00447,.00585],293:[.00173,-.00283],352:[-.00054,.00220],362:[.00590,.00180],386:[.00415,.00390]};
  const LOW_DELTAS={0:[-.00589,.00354],33:[.00240,-.00215],50:[-.00312,-.00189],58:[-.00750,-.00572],105:[-.00128,.00165],116:[-.00368,.00270],123:[.00578,.00299],145:[.00243,.00522],159:[.00304,-.00501],171:[.00375,-.00190],263:[-.00048,.00605],300:[-.00572,.00073],334:[.00191,-.00197],352:[.00010,.00005],365:[.00352,-.00450],374:[.00455,-.00071],377:[.00595,.00473],379:[-.00028,.00566],386:[-.00028,-.01653],399:[-.00495,-.00209],401:[.00373,-.00379]};
  function applyD(d){const a=_NORM.map(p=>({x:p.x,y:p.y,z:0}));for(const k in d)a[+k]={x:_NORM[+k].x+d[k][0],y:_NORM[+k].y+d[k][1],z:0};return a;}
  const _LOW=applyD(LOW_DELTAS),_PEAK=applyD(PEAK_DELTAS);
  function faceL(L){return _LOW.map((p,i)=>({x:p.x+(_PEAK[i].x-p.x)*L,y:p.y+(_PEAK[i].y-p.y)*L,z:0}));}
  const _WP=[[33,263],[133,362],[70,300],[63,293],[105,334],[46,276],[116,345],[123,352],[50,280],[187,411],[132,361],[174,399],[150,379],[172,397],[136,365],[171,396],[148,377],[176,401],[58,288]];
  const _F=(a,b)=>Math.hypot(a.x-b.x,a.y-b.y);
  const _L=(a,b)=>Math.atan2(b.y-a.y,b.x-a.x)*57.29578;
  const _O=(e,t,r)=>Math.max(t,Math.min(r,e));
  const _B=(e,t,r,a,n)=>e>=t&&e<=r?10:e<t?_O((e-a)/(t-a)*10,0,10):_O((n-e)/(n-r)*10,0,10);
  function simpleScore(p){
    const m=-((_L(p[33],p[133])+_L(p[362],p[263]))/2);
    let jx=0;for(const pr of[[172,397],[150,379],[171,396]]){const r=_F(p[pr[0]],p[pr[1]]);if(r>jx)jx=r;}
    const h=_F(p[234],p[454]),f=_F(p[10],p[152]),g=jx,b=f>0?g/f:0;
    const v=(p[133].x+p[362].x)/2,w=(p[10].y+p[152].y)/2;
    let _=0;for(const pr of _WP){const rr=p[pr[0]],q=p[pr[1]];_+=(h>0?Math.abs(Math.abs(rr.x-v)-Math.abs(q.x-v))/h:0)+(f>0?Math.abs(Math.abs(rr.y-w)-Math.abs(q.y-w))/f:0);}
    const y=Math.round((1-_O(_/(2*_WP.length)/.09,0,1))*100);
    const k=(p[133].y+p[33].y)/2,j=(p[362].y+p[263].y)/2,Nl=(k+j)/2;
    const C=Math.abs(p[0].y-Nl),S=f>0?C/f:0,E=g>0?_F(p[234],p[454])/g:0;
    const R=_F(p[33],p[133]),Ih=_F(p[159],p[145]),Mw=_F(p[263],p[362]),Uh=_F(p[386],p[374]);
    const z=Math.max(.2,((R>0?Ih/R:0)+(Mw>0?Uh/Mw:0))/2);
    const H=h>0?_F(p[133],p[362])/h:0;
    const G=_B(m,2,6.5,-2,11),Y=_B(b,.58,.78,.42,.96),q2=_B(S,.27,.34,.2,.43);
    const V=_B(E,1.04,1.24,.86,1.48),K=_B(z,.22,.3,.18,.43);
    const J=Math.round((.18*Y+.24*q2+.18*V+.16*K+.24*_B(H,.22,.31,.15,.42))*10)/10;
    return _O(.12*G+.14*Y+y/10*.24+.14*q2+.1*V+.08*K+.18*J,1.1,10);
  }
  const _TBL=[];for(let L=0;L<=1.0001;L+=0.02)_TBL.push([L,simpleScore(faceL(L))]);
  const SCORE_MIN=_TBL[0][1],SCORE_MAX=_TBL[_TBL.length-1][1];
  function solveL(score){
    score=Math.max(SCORE_MIN,Math.min(SCORE_MAX,score));
    for(let i=0;i<_TBL.length-1;i++){const a=_TBL[i],b=_TBL[i+1];if(score>=a[1]&&score<=b[1]){const f=(score-a[1])/((b[1]-a[1])||1);return a[0]+(b[0]-a[0])*f;}}
    return 1;
  }
  function getAspect(){try{const v=document.querySelector('video');if(v&&v.videoWidth&&v.videoHeight)return v.videoWidth/v.videoHeight;}catch(e){}return 4/3;}
  const SCORE_IDX=new Set([0,1,10,152,234,454,33,133,263,362,159,145,386,374,172,397,150,379,171,396]);
  for(const pr of _WP){SCORE_IDX.add(pr[0]);SCORE_IDX.add(pr[1]);}
  // Pre-allocated reusable buffer — avoids creating ~956 objects on every crypto.sign call.
  const _idealBuf=Array.from({length:478},()=>({x:0,y:0,z:0}));
  let _idealLastScore=NaN,_idealLastAspect=NaN;
  function idealObjects(aspect){
    const a=aspect||getAspect();
    // Only recompute when the score or aspect actually changed (sign fires many times/sec)
    if(currentScore===_idealLastScore&&a===_idealLastAspect)return _idealBuf;
    _idealLastScore=currentScore;_idealLastAspect=a;
    const cx=0.5,L=solveL(currentScore),base=faceL(L);
    for(let i=0;i<base.length;i++){_idealBuf[i].x=cx+(base[i].x-cx)/a;_idealBuf[i].y=base[i].y;_idealBuf[i].z=0;}
    return _idealBuf;
  }

  // ── Global match-state detection ──
  // Live Spoof only injects while an actual match is in progress. The most reliable signal:
  // omoggle only signs landmark frames (header byte 4) DURING a match. We timestamp each such
  // frame; IN_MATCH is true while those frames are still arriving (within the last 1.5s).
  let IN_MATCH = false;
  let _lastFrameTs = 0;
  setInterval(()=>{ IN_MATCH = (Date.now() - _lastFrameTs) < 1500; }, 300);

  (function setup_sign_rewrite(){
    if(!W.crypto?.subtle?.sign)return;
    const _sign=W.crypto.subtle.sign;
    W.crypto.subtle.sign=function(alg,key,data){
      try{
        let dv;
        if(data instanceof ArrayBuffer)dv=new DataView(data);
        else if(ArrayBuffer.isView(data))dv=new DataView(data.buffer,data.byteOffset,data.byteLength);
        // A landmark frame (header byte 4) means we're actively in a match — timestamp it
        // regardless of whether we spoof, so IN_MATCH tracks correctly.
        if(dv&&dv.getUint8(0)===4&&dv.byteLength>=17){
          _lastFrameTs=Date.now();
          if(CFG.enabled&&CFG.liveSpoof&&!CFG.realisticScoring){
            const s=dv.getUint16(13,true);
            const aspect=dv.getFloat32(9,true)||getAspect();
            const ideal=idealObjects(aspect);
            const n=Math.min(s,ideal.length);
            dv.setUint8(15,255);dv.setUint8(16,2);
            let c=17;
            for(let i=0;i<n;i++){dv.setFloat32(c,ideal[i].x,true);dv.setFloat32(c+4,ideal[i].y,true);c+=8;}
            framesSent++;
          }
        }
      }catch(e){}
      return _sign.call(this,alg,key,data);
    };
  })();

  const AFK={
    mediaEl:null,mediaType:null,remoteVideo:null,canvas:null,ctx:null,
    drawTimer:null,realSenders:[],afkTracks:[],W:640,H:480,
    attachRemote(track){try{
      if(!this.remoteVideo){const v=document.createElement('video');v.muted=true;v.playsInline=true;v.autoplay=true;v.style.cssText='position:fixed;left:-9999px;width:2px;height:2px;';document.body.appendChild(v);this.remoteVideo=v;}
      // Release the PREVIOUS incoming stream/tracks before attaching the new one,
      // otherwise each match leaves a dead decoded-video pipeline in memory.
      const prev=this.remoteVideo.srcObject;
      if(prev&&prev.getTracks){try{prev.getTracks().forEach(t=>{if(t!==track)t.stop();});}catch(e){}}
      this.remoteVideo.srcObject=new MediaStream([track]);
      this.remoteVideo.play().catch(()=>{});
    }catch(e){}},
    // Fully release the hidden opponent-mirror video element + its tracks
    releaseRemote(){try{
      if(this.remoteVideo){
        const s=this.remoteVideo.srcObject;
        if(s&&s.getTracks)s.getTracks().forEach(t=>{try{t.stop();}catch(e){}});
        this.remoteVideo.srcObject=null;
        this.remoteVideo.pause();
      }
    }catch(e){}},
    draw(){const ctx=this.ctx;if(!ctx)return;let src,isVideo;if(CFG.mirrorOpponent&&this.remoteVideo&&this.remoteVideo.readyState>=2){src=this.remoteVideo;isVideo=true;}else{src=this.mediaEl;isVideo=this.mediaType==='video';}if(!src){ctx.fillStyle='#000';ctx.fillRect(0,0,this.W,this.H);return;}if(isVideo&&src===this.mediaEl){if(src.paused&&!src.ended)src.play().catch(()=>{});if(src.ended&&CFG.loopVideo){src.currentTime=0;src.play().catch(()=>{});}}const ready=isVideo?src.readyState>=2:(src.complete&&src.naturalWidth>0);if(!ready){ctx.fillStyle='#000';ctx.fillRect(0,0,this.W,this.H);return;}const sw=src.videoWidth||src.naturalWidth||this.W,sh=src.videoHeight||src.naturalHeight||this.H;ctx.save();if(CFG.invertCam){ctx.translate(this.W,0);ctx.scale(-1,1);}const scale=CFG.zoomFit?Math.max(this.W/sw,this.H/sh):Math.min(this.W/sw,this.H/sh);const dw=sw*scale,dh=sh*scale,dx=(this.W-dw)/2,dy=(this.H-dh)/2;ctx.fillStyle='#000';ctx.fillRect(0,0,this.W,this.H);try{ctx.drawImage(src,dx,dy,dw,dh);}catch(e){}ctx.restore();},
    initCanvas(){if(this.canvas)return;this.canvas=document.createElement('canvas');this.canvas.width=this.W;this.canvas.height=this.H;this.ctx=this.canvas.getContext('2d',{alpha:false});this.ctx.fillStyle='#000';this.ctx.fillRect(0,0,this.W,this.H);this.drawTimer=setInterval(()=>{
        if(this.mediaEl||this.remoteVideo)this.draw();
      },1000/30);},
    _captureStream:null,
    freshVideoTrack(){
      this.initCanvas();
      // Reuse ONE capture stream for the canvas instead of making a new one each call.
      // Each captureStream() allocates a new pipeline that never gets freed otherwise.
      if(!this._captureStream||!this._captureStream.active){
        this._captureStream=this.canvas.captureStream(30);
      }
      let t=this._captureStream.getVideoTracks()[0];
      // If the site stopped our track, the stream is dead — rebuild it once.
      if(!t||t.readyState!=='live'){
        try{this._captureStream.getTracks().forEach(tr=>tr.stop());}catch(e){}
        this._captureStream=this.canvas.captureStream(30);
        t=this._captureStream.getVideoTracks()[0]||null;
      }
      // Track the single live track (no unbounded array growth)
      this.afkTracks=t?[t]:[];
      return t;
    },
    loadFile(file){const kind=CFG.afkSource==='Picture'?'image':'video';FileStore.save(file,{kind,name:file.name});this.loadBlob(file,kind);},
    loadBlob(blob,kind){const url=URL.createObjectURL(blob);this._lastBlobUrl&&URL.revokeObjectURL(this._lastBlobUrl);this._lastBlobUrl=url;this.initCanvas();if(this.mediaEl){try{if(this.mediaType==='video'){this.mediaEl.pause();this.mediaEl.remove();}}catch(e){}this.mediaEl=null;this.mediaType=null;}if(kind==='image'){const img=new Image();img.style.cssText='position:fixed;left:-9999px;width:2px;height:2px;opacity:0;pointer-events:none;';document.body.appendChild(img);img.onload=()=>{
          const nw=img.naturalWidth||640,nh=img.naturalHeight||480;
          if(this.W!==nw||this.H!==nh){this.W=nw;this.H=nh;this.canvas.width=nw;this.canvas.height=nh;}
          this.mediaType='image';this.mediaEl=img;
          try{this.ctx.drawImage(img,0,0,this.W,this.H);}catch(e){}
        };img.onerror=()=>{this.mediaEl=null;img.remove();};img.src=url;}else{const vid=document.createElement('video');vid.src=url;vid.muted=true;vid.playsInline=true;vid.autoplay=true;vid.loop=CFG.loopVideo;vid.setAttribute('playsinline','');vid.style.cssText='position:fixed;left:-9999px;width:2px;height:2px;';document.body.appendChild(vid);vid.addEventListener('loadeddata',()=>{
          const nw=vid.videoWidth||640,nh=vid.videoHeight||480;
          if(this.W!==nw||this.H!==nh){this.W=nw;this.H=nh;this.canvas.width=nw;this.canvas.height=nh;}
          this.mediaType='video';this.mediaEl=vid;vid.play().catch(()=>{});
        });vid.addEventListener('ended',()=>{if(CFG.loopVideo){vid.currentTime=0;vid.play().catch(()=>{});}});vid.load();}},
    hasMedia(){return!!this.mediaEl||(CFG.mirrorOpponent&&!!this.remoteVideo);},
    swapSendersToAfk(){if(!this.hasMedia())return;for(const pc of this.peerConns){try{for(const sender of pc.getSenders()){if(sender.track&&sender.track.kind==='video'){if(!this.realSenders.find(r=>r.sender===sender))this.realSenders.push({sender,realTrack:sender.track});const fresh=this.freshVideoTrack();if(fresh)sender.replaceTrack(fresh).catch(()=>{});}}}catch(e){}}},
    restoreSenders(){
      for(const{sender,realTrack}of this.realSenders){
        try{if(realTrack&&realTrack.readyState==='live')sender.replaceTrack(realTrack).catch(()=>{});}catch(e){}
      }
      this.realSenders=[];
      // Stop and discard all AFK tracks we handed out
      this.afkTracks.forEach(t=>{try{t.stop();}catch(e){}});
      this.afkTracks=[];
      if(this._captureStream){try{this._captureStream.getTracks().forEach(t=>t.stop());}catch(e){}this._captureStream=null;}
    },
    peerConns:[],
    pruneConns(){
      // Drop references to dead peer connections so their senders/receivers/tracks can be GC'd
      const before=this.peerConns.length;
      this.peerConns=this.peerConns.filter(pc=>{
        const dead=pc.connectionState==='closed'||pc.connectionState==='failed'||pc.iceConnectionState==='closed';
        return !dead;
      });
      // If every connection is gone, the opponent feed is over — release the mirror video too
      if(this.peerConns.length===0&&before>0)this.releaseRemote();
    },
  };

  if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){const _gum=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=async function(constraints){const wantsVideo=!!(constraints&&constraints.video),wantsAudio=!!(constraints&&constraints.audio);if(!CFG.afkCam||!AFK.hasMedia()||!wantsVideo)return _gum(constraints);const composed=new MediaStream(),vt=AFK.freshVideoTrack();if(vt)composed.addTrack(vt);if(wantsAudio){try{const real=await _gum({audio:true});real.getAudioTracks().forEach(t=>composed.addTrack(t));real.getVideoTracks().forEach(t=>t.stop());}catch(e){}}return composed;};}
  if(W.RTCPeerConnection){const _PC=W.RTCPeerConnection;const wrapped=function(...args){
    const pc=new _PC(...args);
    AFK.peerConns.push(pc);
    pc.addEventListener('track',(ev)=>{try{if(ev.track&&ev.track.kind==='video')AFK.attachRemote(ev.track);}catch(e){}});
    // Prune as soon as THIS connection dies (don't wait for the timer)
    pc.addEventListener('connectionstatechange',()=>{
      if(pc.connectionState==='closed'||pc.connectionState==='failed'||pc.connectionState==='disconnected'){
        AFK.peerConns=AFK.peerConns.filter(c=>c!==pc);
        if(AFK.peerConns.length===0)AFK.releaseRemote();
      }
    });
    return pc;
  };wrapped.prototype=_PC.prototype;try{W.RTCPeerConnection=wrapped;}catch(e){}try{W.webkitRTCPeerConnection=wrapped;}catch(e){}}
  setInterval(()=>AFK.pruneConns(),3000); // always-on cleanup of dead peer connections
  setInterval(()=>{if(!CFG.afkCam||!CFG.enabled||!AFK.hasMedia())return;for(const pc of AFK.peerConns){try{for(const sender of pc.getSenders()){const tr=sender.track;if(tr&&tr.kind==='video'&&!AFK.afkTracks.includes(tr)){if(!AFK.realSenders.find(r=>r.sender===sender))AFK.realSenders.push({sender,realTrack:tr});const fresh=AFK.freshVideoTrack();if(fresh)sender.replaceTrack(fresh).catch(()=>{});}}}catch(e){}}},1500);
  FileStore.load().then(saved=>{if(saved&&saved.blob&&!AFK.hasMedia()){const kind=saved.meta?.kind||'video';CFG.afkSource=kind==='image'?'Picture':'Video';AFK.loadBlob(saved.blob,kind);}}).catch(()=>{});

  let arenaSeenAt=0,autoStartLast=0;
  function tryAutoStart(){if(!CFG.autoStart||!CFG.enabled){arenaSeenAt=0;return;}const h=[...document.querySelectorAll('h3')].find(x=>x.textContent.trim().toLowerCase()==='arena');if(!h){arenaSeenAt=0;return;}const r=h.getBoundingClientRect();if(r.width===0||r.height===0){arenaSeenAt=0;return;}const now=Date.now();if(arenaSeenAt===0){arenaSeenAt=now;return;}const delay=Math.max(1,CFG.autofarmDelay||1);if(now-arenaSeenAt<delay)return;if(now-autoStartLast<delay)return;const el=document.elementFromPoint(r.left+r.width/2,r.top+100);if(!el)return;autoStartLast=now;arenaSeenAt=0;el.click();}
  setInterval(tryAutoStart,500);
  let searchingSince=0;
  setInterval(()=>{if(!CFG.autoStart||!CFG.enabled){searchingSince=0;return;}const now=Date.now(),text=(document.body?.innerText||'').toLowerCase();const searching=/awaiting challenger|connecting opponent|searching|finding|in queue|looking for/.test(text);const inMatchOrResult=/find new match|rematch|edged|victory|you win|you lose|overall score/.test(text);if(inMatchOrResult||!searching){searchingSince=0;return;}if(searchingSince===0){searchingSince=now;return;}if(now-searchingSince>=30000){searchingSince=0;const ABORT=['cancel','cancel search','stop','stop searching','return to menu','back','leave','leave queue'];const all=Array.from(document.querySelectorAll('button, a, [role="button"]'));let abortBtn=null;for(const label of ABORT){abortBtn=all.find(el=>(el.textContent||'').trim().toLowerCase()===label);if(abortBtn)break;}if(abortBtn){const br=abortBtn.getBoundingClientRect();(document.elementFromPoint(br.left+br.width/2,br.top+br.height/2)||abortBtn).click();}else document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',code:'Escape',keyCode:27,bubbles:true}));}},1000);
  let buttonSeenAt=0,lastClickAt=0;
  setInterval(()=>{if(!CFG.autoRequeue||!CFG.enabled){buttonSeenAt=0;return;}const TARGETS=['find new match','find new','rematch & chat','rematch'];const all=Array.from(document.querySelectorAll('button, a, [role="button"]'));let best=null;for(const label of TARGETS){best=all.find(el=>{const t=(el.textContent||'').trim().toLowerCase();if(t!==label)return false;const r=el.getBoundingClientRect();return r.width>10&&r.height>10&&!el.disabled&&el.getAttribute('aria-disabled')!=='true';});if(best)break;}if(!best){buttonSeenAt=0;return;}const now=Date.now();if(buttonSeenAt===0){buttonSeenAt=now;return;}const delay=Math.max(1,CFG.autofarmDelay||1);if(now-buttonSeenAt<delay)return;if(now-lastClickAt<delay)return;const r=best.getBoundingClientRect();(document.elementFromPoint(r.left+r.width/2,r.top+r.height/2)||best).click();lastClickAt=now;buttonSeenAt=0;},500);
  let scoreVel=0;
  setInterval(()=>{if(!CFG.enabled||!CFG.liveSpoof||CFG.realisticScoring)return;if(CFG.liveMode==='fixed'){currentScore=CFG.liveMin;scoreVel=0;return;}const lo=Math.min(CFG.liveMin,CFG.liveMax),hi=Math.max(CFG.liveMin,CFG.liveMax);if(lo===hi){currentScore=lo;scoreVel=0;return;}scoreVel+=(Math.random()-0.5)*(CFG.scoreDrift||0.05);scoreVel*=0.82;scoreVel=Math.max(-0.12,Math.min(0.12,scoreVel));currentScore+=scoreVel;if(currentScore<lo){currentScore=lo;scoreVel=Math.abs(scoreVel)*0.5;}if(currentScore>hi){currentScore=hi;scoreVel=-Math.abs(scoreVel)*0.5;}},200);

  function applyTheme(t){
    // Animated themes resolve to a base palette + a CSS animation class on #ac-root
    let animClass='';
    if(ANIM_THEMES[t]){animClass=ANIM_THEMES[t].anim;t=ANIM_THEMES[t].base;}
    const rootEl=document.getElementById('ac-root');
    if(rootEl){
      ['ac-anim-rainbow','ac-anim-aurora','ac-anim-sunset','ac-anim-matrix'].forEach(c=>rootEl.classList.remove(c));
      if(animClass)rootEl.classList.add(animClass);
    }
    const T=THEMES[t]||THEMES.red;
    const r=document.documentElement;
    r.style.setProperty('--ac-bg',T.bg);r.style.setProperty('--ac-surf',T.surf);r.style.setProperty('--ac-surf2',T.surf2);
    r.style.setProperty('--ac-border',T.border);r.style.setProperty('--ac-border2',T.border2);
    r.style.setProperty('--ac-red',T.accent);r.style.setProperty('--ac-red2',T.accent2);r.style.setProperty('--ac-red3',T.accent3);
    r.style.setProperty('--ac-red-dim',T.accentDim);r.style.setProperty('--ac-red-glow',T.accentGlow);
    r.style.setProperty('--ac-green',T.green);r.style.setProperty('--ac-green2',T.green2);
    r.style.setProperty('--ac-muted',T.muted);r.style.setProperty('--ac-muted2',T.muted2);
    r.style.setProperty('--ac-text',T.text);r.style.setProperty('--ac-text2',T.text2);
    r.style.setProperty('--ac-shadow','0 24px 60px rgba(0,0,0,0.8),0 0 0 1px '+T.border2+',inset 0 1px 0 rgba(255,255,255,0.04)');
  }

  function buildUI(){
    if(document.getElementById('ac-root'))return;
    const style=document.createElement('style');
    style.id='ac-style';
    style.textContent=`
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
:root{
  --ac-bg:#0a0709;--ac-surf:#110d0f;--ac-surf2:#181215;
  --ac-border:rgba(180,30,50,0.18);--ac-border2:rgba(180,30,50,0.32);
  --ac-red:#c0192c;--ac-red2:#e02240;--ac-red3:#ff3355;
  --ac-red-dim:rgba(192,25,44,0.12);--ac-red-glow:rgba(224,34,64,0.22);
  --ac-green:#22a84a;--ac-green2:#2fd65e;
  --ac-muted:#5a4a50;--ac-muted2:#8a7078;--ac-text:#e8dde0;--ac-text2:#c0aab0;
  --ac-mono:'JetBrains Mono',monospace;--ac-font:'Outfit',system-ui,sans-serif;
  --ac-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(180,30,50,0.15),inset 0 1px 0 rgba(255,255,255,0.04);
}
#ac-root{position:fixed;bottom:22px;right:22px;z-index:2147483647;width:310px;max-height:calc(100vh - 44px);display:flex;flex-direction:column;background:var(--ac-bg);border:1px solid var(--ac-border2);border-radius:20px;box-shadow:var(--ac-shadow);font-family:var(--ac-font);color:var(--ac-text);overflow:hidden;transition:transform 0.45s cubic-bezier(0.34,1.4,0.64,1),opacity 0.3s ease,box-shadow 0.3s ease;user-select:none;animation:ac-in 0.55s cubic-bezier(0.34,1.4,0.64,1) both;}
#ac-root.ac-hidden{transform:translateY(130%)!important;opacity:0!important;pointer-events:none!important;}
#ac-root.ac-panic{display:none!important;}
body.ac-panic-active .ac-ripple{display:none!important;}
#ac-root:hover{box-shadow:0 28px 70px rgba(0,0,0,0.85),0 0 0 1px var(--ac-red2),inset 0 1px 0 rgba(255,255,255,0.05);}
@keyframes ac-in{from{transform:translateY(60px);opacity:0;}to{transform:translateY(0);opacity:1;}}

/* ── MINIMIZED STATE ── */
#ac-root.ac-minimized{width:auto!important;min-width:0;border-radius:50px;}
#ac-root.ac-minimized>*:not(#ac-header){display:none!important;}
#ac-root.ac-minimized #ac-header{border-bottom:none;padding:10px 14px;}
#ac-root.ac-minimized #ac-logo-row{gap:7px;}
#ac-root.ac-minimized #ac-title{font-size:13px;}
#ac-root.ac-minimized #ac-badge{display:none;}
#ac-root.ac-minimized #ac-minimize-btn{transform:rotate(180deg);}
#ac-root.ac-minimized #ac-master{display:none;}
#ac-root.ac-minimized #ac-tabs{display:none;}

#ac-header{flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:13px 16px 11px;cursor:move;background:linear-gradient(135deg,var(--ac-red-dim) 0%,transparent 65%);border-bottom:1px solid var(--ac-border);position:relative;overflow:hidden;}
#ac-header::before{content:'';position:absolute;top:-20px;left:-20px;width:80px;height:80px;background:radial-gradient(circle,var(--ac-red-dim) 0%,transparent 70%);border-radius:50%;pointer-events:none;}
#ac-logo-row{position:relative;z-index:2;display:flex;align-items:center;gap:9px;}
#ac-pulse{width:7px;height:7px;border-radius:50%;background:var(--ac-green2);box-shadow:0 0 8px var(--ac-green2);animation:ac-pulse 2.2s ease-in-out infinite;flex-shrink:0;}
@keyframes ac-pulse{0%,100%{box-shadow:0 0 5px var(--ac-green2);opacity:1;}50%{box-shadow:0 0 14px var(--ac-green2),0 0 4px var(--ac-green);opacity:0.75;}}
#ac-title{font-size:15px;font-weight:800;color:var(--ac-text);letter-spacing:-0.2px;}
#ac-title span{color:var(--ac-red3);}
#ac-ver{font-family:var(--ac-mono);font-size:9px;color:var(--ac-muted2);margin-left:1px;}
#ac-header-right{position:relative;z-index:2;display:flex;align-items:center;gap:6px;}
#ac-badge{display:flex;align-items:center;gap:4px;padding:4px 9px;border-radius:20px;font-size:10px;font-weight:700;letter-spacing:0.6px;transition:all 0.3s;font-family:var(--ac-mono);}
#ac-badge.on{background:rgba(34,168,74,0.14);border:1px solid rgba(34,168,74,0.35);color:var(--ac-green2);}
#ac-badge.off{background:rgba(192,25,44,0.14);border:1px solid rgba(192,25,44,0.35);color:var(--ac-red3);}
#ac-minimize-btn{background:none;border:none;cursor:pointer;color:var(--ac-muted2);font-size:14px;padding:2px 4px;border-radius:4px;transition:all 0.2s;line-height:1;display:flex;align-items:center;justify-content:center;}
#ac-minimize-btn:hover{color:var(--ac-text);background:rgba(255,255,255,0.08);}

#ac-master{position:relative;z-index:2;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:11px 16px;border-bottom:1px solid var(--ac-border);}
.ac-master-lbl{font-size:14px;font-weight:700;color:var(--ac-text);letter-spacing:-0.1px;}
.ac-tog{position:relative;width:40px;height:22px;cursor:pointer;flex-shrink:0;}
.ac-tog input{position:absolute;opacity:0;width:0;height:0;}
.ac-trk{position:absolute;inset:0;border-radius:11px;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.1);transition:background 0.25s,border-color 0.25s,box-shadow 0.25s;}
.ac-tog input:checked+.ac-trk{background:var(--ac-red2);border-color:var(--ac-red2);box-shadow:0 0 10px var(--ac-red-glow);}
.ac-thb{position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 4px rgba(0,0,0,0.5);transition:left 0.25s cubic-bezier(0.34,1.4,0.64,1);}
.ac-tog input:checked~.ac-thb{left:21px;}
.ac-tog-lg{width:48px;height:26px;}.ac-tog-lg .ac-trk{border-radius:13px;}.ac-tog-lg .ac-thb{width:20px;height:20px;}.ac-tog-lg input:checked~.ac-thb{left:24px;}
#ac-tabs{position:relative;z-index:10;flex-shrink:0;display:flex;padding:8px 10px 0;gap:2px;border-bottom:1px solid var(--ac-border);background:var(--ac-surf);pointer-events:auto;}
.ac-tab{position:relative;z-index:11;pointer-events:auto!important;flex:1;padding:7px 2px;background:transparent;border:none;color:var(--ac-muted2);font-family:var(--ac-font);font-size:12px;font-weight:600;cursor:pointer;border-radius:7px 7px 0 0;border-bottom:2px solid transparent;transition:color 0.2s,background 0.2s,border-color 0.2s;letter-spacing:0.1px;}
.ac-tab:hover{color:var(--ac-text2);background:rgba(255,255,255,0.03);}
.ac-tab.on{color:var(--ac-text);border-bottom-color:var(--ac-red2);background:var(--ac-red-dim);}
.ac-panel{position:relative;z-index:2;display:none;flex:1 1 auto;min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--ac-red2) transparent;padding-bottom:4px;animation:ac-panel-in 0.2s ease;}
.ac-panel::-webkit-scrollbar{width:3px;}.ac-panel::-webkit-scrollbar-thumb{background:var(--ac-red2);border-radius:2px;}
.ac-panel.on{display:block;}
@keyframes ac-panel-in{from{opacity:0;transform:translateY(5px);}to{opacity:1;transform:translateY(0);}}
.ac-row{display:flex;align-items:center;justify-content:space-between;padding:9px 16px;transition:background 0.15s;}
.ac-row:hover{background:rgba(255,255,255,0.02);}
.ac-lbl{font-size:13px;font-weight:500;color:var(--ac-text);}
.ac-sub{font-size:10px;color:var(--ac-muted2);font-family:var(--ac-mono);margin-top:2px;}
.ac-sect{display:flex;align-items:center;justify-content:space-between;padding:7px 16px 3px;margin-top:2px;}
.ac-sect-lbl{font-size:9px;font-weight:700;color:var(--ac-muted);letter-spacing:1.2px;text-transform:uppercase;}
.ac-sect-arr{font-size:9px;color:var(--ac-muted);}
.ac-input{background:var(--ac-surf2);color:var(--ac-text);border:1px solid var(--ac-border);border-radius:8px;padding:6px 9px;font-family:var(--ac-mono);font-size:12px;font-weight:500;outline:none;text-align:center;transition:border-color 0.2s,box-shadow 0.2s;width:64px;}
.ac-input:focus{border-color:var(--ac-red2);box-shadow:0 0 0 3px var(--ac-red-dim);}
.ac-input-sm{width:50px;}.ac-input-md{width:80px;}.ac-input-full{width:100%;box-sizing:border-box;}.ac-input-text{text-align:left;font-family:var(--ac-font);font-size:12px;}
.ac-keybadge{background:var(--ac-surf2);border:1px solid var(--ac-border2);border-radius:5px;padding:3px 10px;font-family:var(--ac-mono);font-size:11px;font-weight:600;color:var(--ac-text2);}
.ac-select{background:var(--ac-surf2);color:var(--ac-text);border:1px solid var(--ac-border);border-radius:8px;padding:6px 22px 6px 9px;font-family:var(--ac-font);font-size:12px;font-weight:500;cursor:pointer;outline:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='5'%3E%3Cpath d='M0 0l4.5 5L9 0z' fill='%238a7078'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 7px center;transition:border-color 0.2s;}
.ac-select:focus,.ac-select:hover{border-color:var(--ac-red2);}
.ac-incr{display:flex;align-items:center;gap:6px;flex:1;}
.ac-incr-inp{flex:1;background:var(--ac-surf2);color:var(--ac-text);border:1px solid var(--ac-border);border-radius:8px;padding:6px 9px;font-family:var(--ac-mono);font-size:12px;font-weight:500;outline:none;transition:border-color 0.2s;}
.ac-incr-inp:focus{border-color:var(--ac-red2);}
.ac-incr-btns{display:flex;flex-direction:column;gap:2px;}
.ac-incr-btn{width:20px;height:15px;border-radius:4px;border:1px solid;font-size:10px;font-weight:800;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.15s;line-height:1;font-family:var(--ac-mono);}
.ac-incr-btn.p{background:rgba(34,168,74,0.13);border-color:rgba(34,168,74,0.38);color:var(--ac-green2);}.ac-incr-btn.p:hover{background:rgba(34,168,74,0.28);}
.ac-incr-btn.m{background:var(--ac-red-dim);border-color:var(--ac-border2);color:var(--ac-red3);}.ac-incr-btn.m:hover{background:var(--ac-red2);color:#fff;}
.ac-notice{margin:6px 12px 2px;padding:8px 11px;border-radius:9px;font-size:11px;line-height:1.45;font-weight:500;}
.ac-notice-warn{background:var(--ac-red-dim);border:1px solid var(--ac-border2);color:var(--ac-red3);}
.ac-notice strong{font-weight:700;}
.ac-btn{display:flex;align-items:center;justify-content:center;gap:5px;width:calc(100% - 24px);margin:4px 12px;padding:9px 14px;border-radius:9px;border:1px solid;font-family:var(--ac-font);font-size:12px;font-weight:700;cursor:pointer;transition:all 0.2s;letter-spacing:0.2px;}
.ac-btn-default{background:var(--ac-red-dim);border-color:var(--ac-border2);color:var(--ac-red3);}.ac-btn-default:hover{background:var(--ac-red2);border-color:var(--ac-red2);color:#fff;}
.ac-btn-red{background:var(--ac-red-dim);border-color:var(--ac-border2);color:var(--ac-red3);}.ac-btn-red:hover{background:var(--ac-red2);border-color:var(--ac-red2);color:#fff;}
.ac-btn-green{background:rgba(34,168,74,0.1);border-color:rgba(34,168,74,0.3);color:var(--ac-green2);}.ac-btn-green:hover{background:rgba(34,168,74,0.22);}
.ac-upload-row{display:flex;align-items:center;gap:8px;padding:6px 16px;}
.ac-upload-btn{flex:1;padding:7px 10px;border-radius:8px;background:rgba(192,25,44,0.1);border:1px solid rgba(192,25,44,0.28);color:var(--ac-red3);font-family:var(--ac-font);font-size:12px;font-weight:600;cursor:pointer;transition:all 0.2s;}
.ac-upload-btn:hover{background:rgba(192,25,44,0.2);}
.ac-prow{display:flex;gap:5px;align-items:center;padding:4px 12px;}
.ac-prow .ac-input-full{flex:1;text-align:left;width:auto;font-size:12px;}
#ac-footer{position:relative;z-index:2;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:7px 16px 11px;border-top:1px solid var(--ac-border);margin-top:4px;}
#ac-footer-l{font-size:11px;color:var(--ac-muted);}
#ac-footer-r{font-size:11px;color:var(--ac-muted2);}
#ac-footer-r span{color:var(--ac-red3);font-weight:600;}
#ac-root.ac-drag{transition:none!important;opacity:0.88;}
#ac-live-readout{display:flex;align-items:center;justify-content:space-between;margin:2px 12px 8px;padding:10px 14px;background:linear-gradient(135deg,var(--ac-red-dim),transparent);border:1px solid var(--ac-border2);border-radius:10px;}
.ac-live-label{font-family:var(--ac-mono);font-size:9px;letter-spacing:1.5px;color:var(--ac-muted2);font-weight:600;}
.ac-live-val{font-family:var(--ac-mono);font-size:22px;font-weight:700;color:var(--ac-red3);line-height:1;text-shadow:0 0 12px var(--ac-red-glow);transition:color 0.15s,transform 0.15s;min-width:54px;text-align:right;}
.ac-live-val.ac-pulse{transform:scale(1.06);}.ac-live-val.ac-off{color:var(--ac-muted2);text-shadow:none;}

/* ── THEME SWATCHES ── */
.ac-theme-row{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;}
.ac-swatches{display:flex;gap:6px;}
.ac-swatch{width:20px;height:20px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:all 0.2s;position:relative;}
.ac-swatch:hover{transform:scale(1.15);}
.ac-swatch.active{border-color:#fff;box-shadow:0 0 8px rgba(255,255,255,0.3);}
.ac-swatch[data-t="red"]{background:#c0192c;}
.ac-swatch[data-t="blue"]{background:#1964c0;}
.ac-swatch[data-t="green"]{background:#19a050;}
.ac-swatch[data-t="purple"]{background:#7819c0;}
.ac-swatch[data-t="gold"]{background:#b08800;}
.ac-swatch[data-t="cyan"]{background:#0098b0;}
.ac-swatch[data-t="pink"]{background:#c01880;}
.ac-swatch[data-t="mono"]{background:#888890;}
.ac-swatch.anim{position:relative;overflow:hidden;}
.ac-swatch[data-t="rainbow"]{background:linear-gradient(90deg,#ff3355,#ffd700,#33ff99,#3399ff,#cc33ff,#ff3355);background-size:300% 100%;animation:ac-rainbow-sw 3s linear infinite;}
.ac-swatch[data-t="aurora"]{background:linear-gradient(120deg,#22e5ff,#33ff99,#3399ff);background-size:200% 200%;animation:ac-aurora-sw 4s ease infinite;}
.ac-swatch[data-t="sunset"]{background:linear-gradient(120deg,#ff44cc,#ffd700,#ff3355);background-size:200% 200%;animation:ac-aurora-sw 4s ease infinite;}
.ac-swatch[data-t="matrix"]{background:linear-gradient(180deg,#0a0,#3f9,#0a0);background-size:100% 200%;animation:ac-matrix-sw 2s linear infinite;}
@keyframes ac-rainbow-sw{0%{background-position:0% 50%;}100%{background-position:300% 50%;}}
@keyframes ac-aurora-sw{0%,100%{background-position:0% 50%;}50%{background-position:100% 50%;}}
@keyframes ac-matrix-sw{0%{background-position:0% 0%;}100%{background-position:0% 200%;}}

/* ── ANIMATED THEME EFFECTS on the whole widget ── */
#ac-root.ac-anim-rainbow{animation:ac-in 0.55s cubic-bezier(0.34,1.4,0.64,1) both, ac-rainbow-border 6s linear infinite;}
@keyframes ac-rainbow-border{0%{border-color:#ff3355;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #ff3355,0 0 18px rgba(255,51,85,0.4);}20%{border-color:#ffd700;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #ffd700,0 0 18px rgba(255,215,0,0.4);}40%{border-color:#33ff99;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #33ff99,0 0 18px rgba(51,255,153,0.4);}60%{border-color:#3399ff;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #3399ff,0 0 18px rgba(51,153,255,0.4);}80%{border-color:#cc33ff;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #cc33ff,0 0 18px rgba(204,51,255,0.4);}100%{border-color:#ff3355;box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px #ff3355,0 0 18px rgba(255,51,85,0.4);}}
#ac-root.ac-anim-rainbow #ac-header{background:linear-gradient(135deg,rgba(255,51,85,0.12),rgba(204,51,255,0.06) 50%,transparent 80%);background-size:200% 200%;animation:ac-aurora-sw 6s ease infinite;}
#ac-root.ac-anim-aurora{animation:ac-in 0.55s cubic-bezier(0.34,1.4,0.64,1) both, ac-aurora-glow 5s ease-in-out infinite;}
@keyframes ac-aurora-glow{0%,100%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(34,229,255,0.5),0 0 22px rgba(34,229,255,0.3);}50%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(51,255,153,0.5),0 0 22px rgba(51,255,153,0.3);}}
#ac-root.ac-anim-aurora #ac-header{background:linear-gradient(120deg,rgba(34,229,255,0.12),rgba(51,255,153,0.06) 50%,transparent 80%);background-size:200% 200%;animation:ac-aurora-sw 5s ease infinite;}
#ac-root.ac-anim-sunset{animation:ac-in 0.55s cubic-bezier(0.34,1.4,0.64,1) both, ac-sunset-glow 5s ease-in-out infinite;}
@keyframes ac-sunset-glow{0%,100%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(255,68,204,0.5),0 0 22px rgba(255,68,204,0.3);}50%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(255,215,0,0.5),0 0 22px rgba(255,215,0,0.3);}}
#ac-root.ac-anim-sunset #ac-header{background:linear-gradient(120deg,rgba(255,68,204,0.12),rgba(255,215,0,0.06) 50%,transparent 80%);background-size:200% 200%;animation:ac-aurora-sw 5s ease infinite;}
#ac-root.ac-anim-matrix{animation:ac-in 0.55s cubic-bezier(0.34,1.4,0.64,1) both, ac-matrix-glow 3s linear infinite;}
@keyframes ac-matrix-glow{0%,100%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(51,255,153,0.4),0 0 16px rgba(51,255,153,0.25);}50%{box-shadow:0 24px 60px rgba(0,0,0,0.8),0 0 0 1px rgba(0,255,80,0.6),0 0 24px rgba(0,255,80,0.4);}}
#ac-root.ac-anim-matrix #ac-pulse{animation:ac-pulse 1s ease-in-out infinite;}


/* ── PANEL VISUAL FX ── */
/* Animated gradient mesh behind header */
#ac-header{position:relative;}
#ac-fx-mesh{position:absolute;inset:0;pointer-events:none!important;z-index:0;opacity:0.5;background:radial-gradient(circle at 20% 30%,var(--ac-red-glow),transparent 45%),radial-gradient(circle at 80% 70%,var(--ac-red-dim),transparent 50%),radial-gradient(circle at 50% 50%,var(--ac-red-glow),transparent 60%);background-size:200% 200%;animation:ac-mesh 8s ease-in-out infinite;}
@keyframes ac-mesh{0%,100%{background-position:0% 0%,100% 100%,50% 50%;}33%{background-position:100% 0%,0% 100%,30% 70%;}66%{background-position:50% 100%,50% 0%,70% 30%;}}
#ac-root.ac-no-fx #ac-fx-mesh{display:none;}

/* Floating particle canvas in header */
#ac-fx-particles{position:absolute;inset:0;pointer-events:none!important;z-index:0;width:100%;height:100%;}
#ac-root.ac-no-fx #ac-fx-particles{display:none;}

/* CRT scanline shimmer overlay on whole panel */
#ac-fx-scan{position:absolute;inset:0;pointer-events:none!important;z-index:1;opacity:0.04;background:repeating-linear-gradient(0deg,transparent 0px,transparent 2px,#fff 3px,transparent 4px);animation:ac-scan 8s linear infinite;border-radius:inherit;}
@keyframes ac-scan{0%{background-position-y:0;}100%{background-position-y:100px;}}
#ac-root.ac-no-fx #ac-fx-scan{display:none;}

/* Drag glow trail */
#ac-root.ac-drag{box-shadow:0 0 0 1px var(--ac-red2),0 0 30px var(--ac-red-glow),0 24px 60px rgba(0,0,0,0.85)!important;}

/* Active tab glow pulse */
.ac-tab.on{position:relative;}
.ac-tab.on::after{content:'';position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:60%;height:2px;background:var(--ac-red2);box-shadow:0 0 8px var(--ac-red2);animation:ac-tab-glow 2s ease-in-out infinite;}
@keyframes ac-tab-glow{0%,100%{opacity:0.6;box-shadow:0 0 6px var(--ac-red2);}50%{opacity:1;box-shadow:0 0 14px var(--ac-red2),0 0 4px var(--ac-red3);}}
#ac-root.ac-no-fx .ac-tab.on::after{animation:none;box-shadow:none;}

/* Staggered row entrance when switching tabs */
.ac-panel.on .ac-row,.ac-panel.on .ac-sect,.ac-panel.on .ac-theme-row,.ac-panel.on #ac-live-readout,.ac-panel.on .ac-upload-row,.ac-panel.on .ac-prow{animation:ac-row-in 0.35s cubic-bezier(0.34,1.4,0.64,1) both;}
.ac-panel.on>*:nth-child(1){animation-delay:0.02s;}
.ac-panel.on>*:nth-child(2){animation-delay:0.05s;}
.ac-panel.on>*:nth-child(3){animation-delay:0.08s;}
.ac-panel.on>*:nth-child(4){animation-delay:0.11s;}
.ac-panel.on>*:nth-child(5){animation-delay:0.14s;}
.ac-panel.on>*:nth-child(6){animation-delay:0.17s;}
.ac-panel.on>*:nth-child(7){animation-delay:0.20s;}
.ac-panel.on>*:nth-child(8){animation-delay:0.23s;}
@keyframes ac-row-in{from{opacity:0;transform:translateX(-8px);}to{opacity:1;transform:translateX(0);}}
#ac-root.ac-no-fx .ac-panel.on>*{animation:none!important;}

/* Title shimmer */
#ac-title span{background:linear-gradient(90deg,var(--ac-red3),var(--ac-red2),var(--ac-red3));background-size:200% 100%;-webkit-background-clip:text;background-clip:text;animation:ac-title-shimmer 4s linear infinite;}
@keyframes ac-title-shimmer{0%{background-position:0% 50%;}100%{background-position:200% 50%;}}
#ac-root.ac-no-fx #ac-title span{animation:none;background:var(--ac-red3);-webkit-background-clip:text;background-clip:text;}

/* Toggle switch glow when on */
.ac-tog input:checked+.ac-trk{box-shadow:0 0 10px var(--ac-red-glow),0 0 4px var(--ac-red2);}

/* COMPACT MODE */
/* ── COMPACT MODE ── */
#ac-root.ac-compact .ac-row{padding:5px 16px;}
#ac-root.ac-compact .ac-sect{padding:4px 16px 2px;}
#ac-root.ac-compact #ac-live-readout{padding:6px 14px;margin:2px 12px 5px;}
#ac-root.ac-compact .ac-live-val{font-size:18px;}
#ac-root.ac-compact .ac-lbl{font-size:12px;}
#ac-root.ac-compact #ac-master{padding:7px 16px;}


/* ── CLICK RIPPLE FX ── */
.ac-ripple{position:fixed;border-radius:50%;background:var(--ac-red3);opacity:0.5;transform:translate(-50%,-50%) scale(0);pointer-events:none;z-index:2147483646;animation:ac-ripple-go 0.55s ease-out forwards;}
@keyframes ac-ripple-go{to{transform:translate(-50%,-50%) scale(14);opacity:0;}}

@media(max-width:600px),(pointer:coarse){#ac-root{width:calc(100vw - 20px);max-width:360px;bottom:10px;right:10px;left:auto;border-radius:16px;}.ac-tog{width:46px;height:26px;}.ac-tog .ac-thb{width:20px;height:20px;}.ac-tog input:checked~.ac-thb{left:23px;}.ac-tab{padding:10px 2px;font-size:13px;}.ac-row{padding:12px 16px;}.ac-lbl{font-size:14px;}.ac-incr-btn{width:26px;height:20px;font-size:13px;}.ac-input,.ac-incr-inp,.ac-select{font-size:15px;padding:8px 10px;}.ac-btn{padding:11px 14px;font-size:13px;}.ac-upload-btn{padding:10px;font-size:13px;}.ac-panel{max-height:60vh;}}
    `;
    document.head.appendChild(style);

    const fileInput=document.createElement('input');
    fileInput.type='file';fileInput.style.display='none';
    document.body.appendChild(fileInput);

    const root=document.createElement('div');
    root.id='ac-root';
    root.innerHTML=`
<div id="ac-header">
  <div id="ac-fx-mesh"></div>
  <canvas id="ac-fx-particles"></canvas>
  <div id="ac-logo-row">
    <div id="ac-pulse"></div>
    <div><div id="ac-title"><span>Aced</span> Helper <span id="ac-ver">v1.3</span></div></div>
  </div>
  <div id="ac-header-right">
    <div id="ac-badge" class="${CFG.enabled?'on':'off'}">${CFG.enabled?'● ACTIVE':'○ OFF'}</div>
    <button id="ac-minimize-btn" title="Minimize">▼</button>
  </div>
</div>
<div id="ac-master">
  <span class="ac-master-lbl">Master Enable</span>
  <label class="ac-tog ac-tog-lg"><input type="checkbox" id="ac-en" ${CFG.enabled?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label>
</div>
<div id="ac-tabs">
  <button class="ac-tab on" data-tab="ctrl">Control</button>
  <button class="ac-tab" data-tab="score">Scoring</button>
  <button class="ac-tab" data-tab="media">Media</button>
  <button class="ac-tab" data-tab="cfg">Config</button>
</div>

<!-- CONTROL -->
<div class="ac-panel on" id="ac-p-ctrl">
  <div class="ac-row"><span class="ac-lbl">Auto Requeue</span><label class="ac-tog"><input type="checkbox" id="ac-autoRequeue" ${CFG.autoRequeue?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Auto Start</span><label class="ac-tog"><input type="checkbox" id="ac-autoStart" ${CFG.autoStart?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">AFK Cam</span><label class="ac-tog"><input type="checkbox" id="ac-afkCam" ${CFG.afkCam?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Autoqueue Delay</span><span style="display:flex;align-items:center;gap:5px;"><input class="ac-input ac-input-md" type="number" id="ac-farmDelay" value="${CFG.autofarmDelay}" min="1" max="9000" step="50"><span style="font-size:10px;color:var(--ac-muted2)">ms</span></span></div>
</div>

<!-- SCORING -->
<div class="ac-panel" id="ac-p-score">
  <div class="ac-row" style="padding-bottom:4px;"><div><div class="ac-lbl" style="color:var(--ac-red3)">Realistic Scoring</div><div class="ac-sub">tracks real face movement</div></div><label class="ac-tog"><input type="checkbox" id="ac-realScore" ${CFG.realisticScoring?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-sect"><span class="ac-sect-lbl">Live Spoof</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-row"><span class="ac-lbl">Live Spoof</span><label class="ac-tog"><input type="checkbox" id="ac-liveSpoof" ${CFG.liveSpoof?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div id="ac-live-readout"><span class="ac-live-label">CURRENT SCORE</span><span class="ac-live-val" id="ac-live-val">—</span></div>
  <div class="ac-row"><span class="ac-lbl">Mode</span><select class="ac-select" id="ac-liveMode"><option value="fluctuate" ${CFG.liveMode==='fluctuate'?'selected':''}>Fluctuate</option><option value="fixed" ${CFG.liveMode==='fixed'?'selected':''}>Fixed</option></select></div>
  <div class="ac-row" id="ac-row-liveMin"><span class="ac-lbl" id="ac-lbl-liveMin">Min</span><div class="ac-incr"><input class="ac-incr-inp" type="number" id="ac-liveMin" value="${CFG.liveMin}" step="0.1" min="1" max="10"><div class="ac-incr-btns"><button class="ac-incr-btn p" data-t="ac-liveMin" data-s="0.1">+</button><button class="ac-incr-btn m" data-t="ac-liveMin" data-s="-0.1">−</button></div></div></div>
  <div class="ac-row" id="ac-row-liveMax"><span class="ac-lbl">Max</span><div class="ac-incr"><input class="ac-incr-inp" type="number" id="ac-liveMax" value="${CFG.liveMax}" step="0.1" min="1" max="10"><div class="ac-incr-btns"><button class="ac-incr-btn p" data-t="ac-liveMax" data-s="0.1">+</button><button class="ac-incr-btn m" data-t="ac-liveMax" data-s="-0.1">−</button></div></div></div>
  <div class="ac-sect"><span class="ac-sect-lbl">Final Score</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-row"><span class="ac-lbl">Min</span><div class="ac-incr"><input class="ac-incr-inp" type="number" id="ac-finalMin" value="${CFG.finalMin}" step="0.1" min="1" max="10"><div class="ac-incr-btns"><button class="ac-incr-btn p" data-t="ac-finalMin" data-s="0.1">+</button><button class="ac-incr-btn m" data-t="ac-finalMin" data-s="-0.1">−</button></div></div></div>
  <div class="ac-row"><span class="ac-lbl">Max</span><div class="ac-incr"><input class="ac-incr-inp" type="number" id="ac-finalMax" value="${CFG.finalMax}" step="0.1" min="1" max="10"><div class="ac-incr-btns"><button class="ac-incr-btn p" data-t="ac-finalMax" data-s="0.1">+</button><button class="ac-incr-btn m" data-t="ac-finalMax" data-s="-0.1">−</button></div></div></div>
</div>

<!-- MEDIA -->
<div class="ac-panel" id="ac-p-media">
  <div class="ac-notice ac-notice-warn">⚠ Upload a video/picture below, then turn on <strong>AFK Cam</strong> (Control tab).</div>
  <div class="ac-row"><span class="ac-lbl">Mirror Opponent (Send Back)</span><label class="ac-tog"><input type="checkbox" id="ac-mirror" ${CFG.mirrorOpponent?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Invert Cam</span><label class="ac-tog"><input type="checkbox" id="ac-invert" ${CFG.invertCam?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Loop Video</span><label class="ac-tog"><input type="checkbox" id="ac-loop" ${CFG.loopVideo?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-sect"><span class="ac-sect-lbl">AFK Source</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-row"><span class="ac-lbl">Source</span><select class="ac-select" id="ac-afkSrc"><option value="Video" ${CFG.afkSource==='Video'?'selected':''}>Video</option><option value="Picture" ${CFG.afkSource==='Picture'?'selected':''}>Picture</option></select></div>
  <div class="ac-upload-row"><button class="ac-upload-btn" id="ac-upload-btn">📁 <span id="ac-upload-lbl">${CFG.afkSource==='Picture'?'Upload Picture':'Upload Video'}</span></button><span class="ac-lbl" style="flex-shrink:0">Zoom Fit</span><label class="ac-tog" style="margin-left:4px;"><input type="checkbox" id="ac-zoomFit" ${CFG.zoomFit?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div style="padding:2px 16px 6px;font-size:10px;color:var(--ac-muted2);font-family:var(--ac-mono);" id="ac-file-name">No file selected</div>
</div>

<!-- CONFIG -->
<div class="ac-panel" id="ac-p-cfg">
  <div class="ac-row"><div><span class="ac-lbl">GUI Hide Key</span><div class="ac-sub">slide away / back</div></div><span class="ac-keybadge">h</span></div>
  <div class="ac-row"><span class="ac-lbl">Live Spoof Key</span><span class="ac-keybadge">1</span></div>
  <div class="ac-row"><span class="ac-lbl">Final Score Key</span><span class="ac-keybadge">f</span></div>
  <div class="ac-row"><div><span class="ac-lbl">Panic Hide Key</span><div class="ac-sub">instant blackout</div></div><span class="ac-keybadge">${CFG.panicKey==='`'?'~':CFG.panicKey}</span></div>

  <div class="ac-sect"><span class="ac-sect-lbl">Tweaks</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-row"><span class="ac-lbl">Click Ripple FX</span><label class="ac-tog"><input type="checkbox" id="ac-clickAnim" ${CFG.clickAnim?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Compact Mode</span><label class="ac-tog"><input type="checkbox" id="ac-compact" ${CFG.compactMode?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row"><span class="ac-lbl">Panel Effects</span><label class="ac-tog"><input type="checkbox" id="ac-panelFX" ${CFG.panelFX?'checked':''}><span class="ac-trk"></span><span class="ac-thb"></span></label></div>
  <div class="ac-row">
    <span class="ac-lbl">Drift Speed</span>
    <div class="ac-incr">
      <input class="ac-incr-inp" type="number" id="ac-drift" value="${CFG.scoreDrift}" step="0.01" min="0.01" max="0.2">
      <div class="ac-incr-btns"><button class="ac-incr-btn p" data-t="ac-drift" data-s="0.01">+</button><button class="ac-incr-btn m" data-t="ac-drift" data-s="-0.01">−</button></div>
    </div>
  </div>
  <div class="ac-row">
    <span class="ac-lbl">Panel Opacity</span>
    <span style="display:flex;align-items:center;gap:8px;flex:1;justify-content:flex-end;">
      <input type="range" id="ac-opacity" min="40" max="100" value="${CFG.opacity}" style="width:90px;accent-color:var(--ac-red2);cursor:pointer;">
      <span id="ac-opacity-val" style="font-family:var(--ac-mono);font-size:11px;color:var(--ac-muted2);min-width:32px;text-align:right;">${CFG.opacity}%</span>
    </span>
  </div>

  <div class="ac-sect"><span class="ac-sect-lbl">Theme</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-theme-row">
    <span class="ac-lbl">Color</span>
    <div class="ac-swatches">
      <div class="ac-swatch ${CFG.theme==='red'?'active':''}" data-t="red" title="Red"></div>
      <div class="ac-swatch ${CFG.theme==='blue'?'active':''}" data-t="blue" title="Blue"></div>
      <div class="ac-swatch ${CFG.theme==='green'?'active':''}" data-t="green" title="Green"></div>
      <div class="ac-swatch ${CFG.theme==='purple'?'active':''}" data-t="purple" title="Purple"></div>
      <div class="ac-swatch ${CFG.theme==='gold'?'active':''}" data-t="gold" title="Gold"></div>
    </div>
  </div>
  <div class="ac-theme-row" style="padding-top:0;">
    <span class="ac-lbl" style="opacity:0;">.</span>
    <div class="ac-swatches">
      <div class="ac-swatch ${CFG.theme==='cyan'?'active':''}" data-t="cyan" title="Cyan"></div>
      <div class="ac-swatch ${CFG.theme==='pink'?'active':''}" data-t="pink" title="Pink"></div>
      <div class="ac-swatch ${CFG.theme==='mono'?'active':''}" data-t="mono" title="Mono"></div>
      <div class="ac-swatch ${CFG.theme==='gold'?'':''}" style="opacity:0;pointer-events:none;"></div>
      <div class="ac-swatch ${CFG.theme==='gold'?'':''}" style="opacity:0;pointer-events:none;"></div>
    </div>
  </div>
  <div class="ac-theme-row" style="padding-top:2px;">
    <span class="ac-lbl" style="font-size:11px;color:var(--ac-muted2);">Animated</span>
    <div class="ac-swatches">
      <div class="ac-swatch anim ${CFG.theme==='rainbow'?'active':''}" data-t="rainbow" title="Rainbow"></div>
      <div class="ac-swatch anim ${CFG.theme==='aurora'?'active':''}" data-t="aurora" title="Aurora"></div>
      <div class="ac-swatch anim ${CFG.theme==='sunset'?'active':''}" data-t="sunset" title="Sunset"></div>
      <div class="ac-swatch anim ${CFG.theme==='matrix'?'active':''}" data-t="matrix" title="Matrix"></div>
    </div>
  </div>
  <div class="ac-sect"><span class="ac-sect-lbl">Profiles</span><span class="ac-sect-arr">▼</span></div>
  <div class="ac-prow"><input class="ac-input ac-input-full ac-input-text" type="text" id="ac-profName" placeholder="Profile name"><button class="ac-btn ac-btn-green" id="ac-prof-save" style="width:auto;margin:0;padding:6px 12px;">Save</button></div>
  <div class="ac-prow" style="margin-top:4px;"><select class="ac-select" id="ac-prof-list" style="flex:1;"></select><button class="ac-btn ac-btn-default" id="ac-prof-load" style="width:auto;margin:0;padding:6px 10px;">Load</button><button class="ac-btn ac-btn-red" id="ac-prof-del" style="width:auto;margin:0;padding:6px 10px;">Del</button></div>
  <button class="ac-btn ac-btn-red" id="ac-clear-cookies" style="margin-top:8px;">🍪 Clear Cookies</button>
</div>

<div id="ac-fx-scan"></div>
<div id="ac-footer">
  <span id="ac-footer-l">Discord</span>
  <span id="ac-footer-r">by <span>@celler1321</span></span>
</div>
    `;
    document.body.appendChild(root);

    // Apply saved theme
    applyTheme(CFG.theme);

    // ── Apply persisted opacity + compact mode on load ──
    function applyOpacity(){const r=document.getElementById('ac-root');if(r)r.style.opacity=(CFG.opacity/100);}
    function applyCompact(){const r=document.getElementById('ac-root');if(r)r.classList.toggle('ac-compact',!!CFG.compactMode);}
    applyOpacity(); applyCompact();

    // ── Panel FX master toggle ──
    function applyFX(){const r=document.getElementById('ac-root');if(r)r.classList.toggle('ac-no-fx',!CFG.panelFX);if(CFG.panelFX)startParticles();else stopParticles();}

    // ── Header particle system (floating embers in theme color) ──
    let _particleRAF=null, _particles=[];
    function startParticles(){
      const cv=$('ac-fx-particles'); if(!cv)return;
      const ctx=cv.getContext('2d');
      function resize(){const h=$('ac-header');if(h){cv.width=h.offsetWidth;cv.height=h.offsetHeight;}}
      resize();
      if(!_particles.length){
        for(let i=0;i<14;i++)_particles.push({x:Math.random()*cv.width,y:Math.random()*cv.height,vx:(Math.random()-0.5)*0.3,vy:(Math.random()-0.5)*0.3,r:Math.random()*1.8+0.4,a:Math.random()*0.5+0.2});
      }
      function getAccent(){return getComputedStyle(document.documentElement).getPropertyValue('--ac-red3').trim()||'#ff3355';}
      function tick(){
        if(!CFG.panelFX||document.hidden){_particleRAF=null;return;}
        ctx.clearRect(0,0,cv.width,cv.height);
        const col=getAccent();
        for(const p of _particles){
          p.x+=p.vx; p.y+=p.vy;
          if(p.x<0)p.x=cv.width; if(p.x>cv.width)p.x=0;
          if(p.y<0)p.y=cv.height; if(p.y>cv.height)p.y=0;
          ctx.beginPath();
          ctx.arc(p.x,p.y,p.r,0,Math.PI*2);
          ctx.fillStyle=col; ctx.globalAlpha=p.a;
          ctx.fill();
        }
        ctx.globalAlpha=1;
        _particleRAF=requestAnimationFrame(tick);
      }
      if(!_particleRAF)tick();
    }
    function stopParticles(){if(_particleRAF){cancelAnimationFrame(_particleRAF);_particleRAF=null;}const cv=$('ac-fx-particles');if(cv){const c=cv.getContext('2d');c.clearRect(0,0,cv.width,cv.height);}}

    const $=id=>document.getElementById(id);

    // FX must start AFTER $ is defined (these use $ internally)
    applyFX();
    document.addEventListener('visibilitychange',()=>{if(!document.hidden&&CFG.panelFX&&!_particleRAF)startParticles();});

    // Minimize button
    $('ac-minimize-btn').addEventListener('click', e => {
      e.stopPropagation();
      root.classList.toggle('ac-minimized');
    });

    // Theme swatches
    root.querySelectorAll('.ac-swatch').forEach(sw => {
      sw.addEventListener('click', () => {
        const t = sw.dataset.t;
        CFG.theme = t; saveCfg();
        applyTheme(t);
        root.querySelectorAll('.ac-swatch').forEach(s => s.classList.toggle('active', s.dataset.t === t));
      });
    });

    function syncBadge(){const b=$('ac-badge');b.className=CFG.enabled?'on':'off';b.textContent=CFG.enabled?'● ACTIVE':'○ OFF';}
    root.querySelectorAll('.ac-tab').forEach(tab=>{tab.onclick=()=>{root.querySelectorAll('.ac-tab').forEach(t=>t.classList.remove('on'));root.querySelectorAll('.ac-panel').forEach(p=>p.classList.remove('on'));tab.classList.add('on');$('ac-p-'+tab.dataset.tab)?.classList.add('on');};});
    function bind(id,key,type,cb){const el=$(id);if(!el)return;el.addEventListener(type==='input'?'input':'change',function(){const val=this.type==='checkbox'?this.checked:this.type==='number'?+this.value:this.value;CFG[key]=val;saveCfg();if(cb)cb(val,this);});}
    bind('ac-en','enabled','change',()=>syncBadge());
    bind('ac-autoRequeue','autoRequeue','change');
    bind('ac-autoStart','autoStart','change');
    bind('ac-afkCam','afkCam','change',val=>{const n=$('ac-file-name');if(val){if(!AFK.hasMedia()){if(n)n.textContent='⚠ Upload a video/picture in Media tab';return;}AFK.swapSendersToAfk();}else{AFK.restoreSenders();}});
    bind('ac-farmDelay','autofarmDelay','input',val=>{CFG.autofarmDelay=Math.max(1,Math.min(9000,val||1));saveCfg();});
    bind('ac-realScore','realisticScoring','change');
    bind('ac-liveSpoof','liveSpoof','change');
    bind('ac-liveMin','liveMin','input',v=>{CFG.liveMin=Math.max(1,Math.min(10,v||1));saveCfg();});
    bind('ac-liveMax','liveMax','input',v=>{CFG.liveMax=Math.max(1,Math.min(10,v||1));saveCfg();});
    function syncLiveMode(){const fixed=CFG.liveMode==='fixed';const mr=$('ac-row-liveMax'),ml=$('ac-lbl-liveMin');if(mr)mr.style.display=fixed?'none':'';if(ml)ml.textContent=fixed?'Score':'Min';}
    $('ac-liveMode')?.addEventListener('change',function(){CFG.liveMode=this.value;saveCfg();syncLiveMode();});
    syncLiveMode();
    setInterval(()=>{const el=$('ac-live-val');if(!el)return;const active=CFG.enabled&&CFG.liveSpoof&&!CFG.realisticScoring;if(!active){el.textContent='OFF';el.classList.add('ac-off');return;}if(!IN_MATCH){el.textContent='IDLE';el.classList.add('ac-off');return;}el.classList.remove('ac-off');const v=currentScore.toFixed(1);if(el.textContent!==v){el.textContent=v;el.classList.add('ac-pulse');setTimeout(()=>el.classList.remove('ac-pulse'),150);}},200);
    bind('ac-finalMin','finalMin','input',v=>{CFG.finalMin=Math.max(1,Math.min(10,v||1));saveCfg();});
    bind('ac-finalMax','finalMax','input',v=>{CFG.finalMax=Math.max(1,Math.min(10,v||1));saveCfg();});
    bind('ac-mirror','mirrorOpponent','change',val=>{if(val){if(!AFK.remoteVideo){const n=$('ac-file-name');if(n)n.textContent='⚠ Mirror works only during a live match';}AFK.swapSendersToAfk();}else if(!CFG.afkCam){AFK.restoreSenders();}});
    bind('ac-invert','invertCam','change');
    bind('ac-loop','loopVideo','change');
    bind('ac-zoomFit','zoomFit','change');

    // ── New tweak binds ──
    bind('ac-clickAnim','clickAnim','change');
    bind('ac-compact','compactMode','change',()=>applyCompact());
    bind('ac-panelFX','panelFX','change',()=>applyFX());
    bind('ac-drift','scoreDrift','input',v=>{CFG.scoreDrift=Math.max(0.01,Math.min(0.2,v||0.05));saveCfg();});
    const opSlider=$('ac-opacity');
    if(opSlider)opSlider.addEventListener('input',function(){CFG.opacity=+this.value;const ov=$('ac-opacity-val');if(ov)ov.textContent=this.value+'%';applyOpacity();saveCfg();});
    $('ac-afkSrc')?.addEventListener('change',function(){CFG.afkSource=this.value;saveCfg();const lbl=$('ac-upload-lbl');if(lbl)lbl.textContent=this.value==='Picture'?'Upload Picture':'Upload Video';fileInput.accept=this.value==='Picture'?'image/*':'video/*';});
    $('ac-upload-btn')?.addEventListener('click',()=>{fileInput.accept=CFG.afkSource==='Picture'?'image/*':'video/*';fileInput.value='';fileInput.click();});
    fileInput.addEventListener('change',()=>{const file=fileInput.files?.[0];if(!file)return;const n=$('ac-file-name');if(n)n.textContent=file.name+' ✓';AFK.loadFile(file);setTimeout(()=>{if(CFG.afkCam)AFK.swapSendersToAfk();},400);});
    FileStore.load().then(saved=>{if(saved&&saved.blob){const kind=saved.meta?.kind||'video';CFG.afkSource=kind==='image'?'Picture':'Video';const sel=$('ac-afkSrc');if(sel)sel.value=CFG.afkSource;const lbl=$('ac-upload-lbl');if(lbl)lbl.textContent=CFG.afkSource==='Picture'?'Upload Picture':'Upload Video';const n=$('ac-file-name');if(n)n.textContent=(saved.meta?.name||'saved file')+' ✓ (restored)';if(!AFK.hasMedia())AFK.loadBlob(saved.blob,kind);setTimeout(()=>{if(CFG.afkCam)AFK.swapSendersToAfk();},800);}});
    $('ac-loop')?.addEventListener('change',function(){if(AFK.mediaType==='video'&&AFK.mediaEl)AFK.mediaEl.loop=this.checked;});

    root.querySelectorAll('.ac-incr-btn').forEach(btn=>{btn.onclick=()=>{const inp=$(btn.dataset.t);if(!inp)return;let nv=parseFloat(inp.value||0)+parseFloat(btn.dataset.s);const mn=parseFloat(inp.min)||1,mx=parseFloat(inp.max)||10;nv=Math.max(mn,Math.min(mx,nv));inp.value=nv.toFixed(1);inp.dispatchEvent(new Event('input'));};});
    document.addEventListener('keydown',e=>{if(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'||e.target.tagName==='SELECT')return;if(e.key==='h')root.classList.toggle('ac-hidden');if(e.key==='1'){CFG.liveSpoof=!CFG.liveSpoof;const el=$('ac-liveSpoof');if(el)el.checked=CFG.liveSpoof;saveCfg();}if(e.key==='f'){CFG.realisticScoring=!CFG.realisticScoring;const el=$('ac-realScore');if(el)el.checked=CFG.realisticScoring;saveCfg();}if(e.key==='m')root.classList.toggle('ac-minimized');if(e.key===(CFG.panicKey||'`')){const hidden=root.classList.toggle('ac-panic');document.body.classList.toggle('ac-panic-active',hidden);}});
    function refreshProfiles(){const keys=Object.keys(CFG.profiles);const sel=$('ac-prof-list');if(!sel)return;sel.innerHTML=keys.length?keys.map(k=>`<option value="${k}">${k}</option>`).join(''):'<option value="">No profiles</option>';}
    refreshProfiles();
    $('ac-prof-save')?.addEventListener('click',()=>{const n=$('ac-profName')?.value?.trim();if(!n)return;const snap=JSON.parse(JSON.stringify(CFG));delete snap.profiles;delete snap.sounds;CFG.profiles[n]=snap;saveCfg();refreshProfiles();$('ac-profName').value='';const btn=$('ac-prof-save');if(btn){btn.textContent='✓ Saved';setTimeout(()=>{btn.textContent='Save';},1500);}});
    $('ac-prof-load')?.addEventListener('click',()=>{const n=$('ac-prof-list')?.value;if(!n||!CFG.profiles[n])return;const loaded=JSON.parse(JSON.stringify(CFG.profiles[n]));const profiles=CFG.profiles,sounds=CFG.sounds;Object.assign(CFG,loaded);CFG.profiles=profiles;CFG.sounds=sounds;saveCfg();location.reload();});
    $('ac-prof-del')?.addEventListener('click',()=>{const n=$('ac-prof-list')?.value;if(!n)return;delete CFG.profiles[n];saveCfg();refreshProfiles();});
    $('ac-clear-cookies')?.addEventListener('click',async function(){if(this.dataset.confirm!=='1'){this.dataset.confirm='1';this.textContent='⚠ Click again to confirm';setTimeout(()=>{this.dataset.confirm='0';this.textContent='🍪 Clear Cookies';},3000);return;}this.dataset.confirm='0';this.textContent='⏳ Wiping…';const keepCfg=(()=>{try{return localStorage.getItem(LS_KEY);}catch(e){return null;}})();const host=location.hostname,labels=host.split('.');const domains=[host,'.'+host,''];for(let i=0;i<labels.length-1;i++){const d=labels.slice(i).join('.');domains.push(d,'.'+d);}const paths=['/',location.pathname,''];const expire='Thu, 01 Jan 1970 00:00:00 GMT';document.cookie.split(';').forEach(c=>{const name=c.split('=')[0].trim();if(!name)return;domains.forEach(d=>paths.forEach(p=>{let s=name+'=; expires='+expire;if(p)s+='; path='+p;if(d)s+='; domain='+d;document.cookie=s;document.cookie=s+'; SameSite=Lax';document.cookie=s+'; SameSite=None; Secure';}));});try{localStorage.clear();if(keepCfg)localStorage.setItem(LS_KEY,keepCfg);}catch(e){}try{sessionStorage.clear();}catch(e){}try{if(indexedDB.databases){const dbs=await indexedDB.databases();for(const db of dbs){if(db.name&&db.name!==FileStore.DB){try{indexedDB.deleteDatabase(db.name);}catch(e){}}}}}catch(e){}try{if(W.caches&&caches.keys){const keys=await caches.keys();for(const k of keys){try{await caches.delete(k);}catch(e){}}}}catch(e){}try{if(navigator.serviceWorker&&navigator.serviceWorker.getRegistrations){const regs=await navigator.serviceWorker.getRegistrations();for(const r of regs){try{await r.unregister();}catch(e){}}}}catch(e){}this.textContent='✓ Cleared — reloading';setTimeout(()=>location.reload(),700);});

    // ── Click ripple FX ──
    document.addEventListener('click', e => {
      if(!CFG.clickAnim)return;
      if(e.target.closest('#ac-root'))return; // don't ripple on our own UI
      const rip=document.createElement('div');
      rip.className='ac-ripple';
      rip.style.left=e.clientX+'px'; rip.style.top=e.clientY+'px';
      rip.style.width='8px'; rip.style.height='8px';
      document.body.appendChild(rip);
      setTimeout(()=>rip.remove(),600);
    }, true);

    let drag=false,ox=0,oy=0;
    function resetPosition(){
      // Snap back to default bottom-right corner
      root.style.left='auto'; root.style.top='auto';
      root.style.right='22px'; root.style.bottom='22px';
    }
    function clampIntoView(){
      // If the panel is positioned via left/top, make sure it's still on-screen
      if(root.style.left&&root.style.left!=='auto'){
        const w=root.offsetWidth,h=root.offsetHeight;
        let nx=parseFloat(root.style.left)||0, ny=parseFloat(root.style.top)||0;
        nx=Math.max(0,Math.min(window.innerWidth-w,nx));
        ny=Math.max(0,Math.min(window.innerHeight-h,ny));
        root.style.left=nx+'px'; root.style.top=ny+'px';
      }
    }
    window.addEventListener('resize',clampIntoView);
    // Drag only engages after the pointer moves past a small threshold — a plain
    // click never enters drag mode (which previously could get stuck and block the UI).
    let pendingDrag=false, startX=0, startY=0;
    const DRAG_THRESHOLD=5;
    function pointerDown(cx,cy){pendingDrag=true;drag=false;startX=cx;startY=cy;const r=root.getBoundingClientRect();ox=cx-r.left;oy=cy-r.top;}
    function pointerMove(cx,cy){
      if(!pendingDrag&&!drag)return;
      if(!drag){
        if(Math.abs(cx-startX)<DRAG_THRESHOLD&&Math.abs(cy-startY)<DRAG_THRESHOLD)return;
        // Crossed threshold — begin actual drag
        drag=true;root.classList.add('ac-drag');root.style.bottom='auto';root.style.right='auto';
      }
      const w=root.offsetWidth,h=root.offsetHeight;
      let nx=cx-ox,ny=cy-oy;
      nx=Math.max(0,Math.min(window.innerWidth-w,nx));
      ny=Math.max(0,Math.min(window.innerHeight-h,ny));
      root.style.left=nx+'px';root.style.top=ny+'px';
    }
    function pointerUp(){pendingDrag=false;drag=false;root.classList.remove('ac-drag');}
    const hdr=$('ac-header');
    hdr.addEventListener('mousedown',e=>{if(e.target.closest('#ac-minimize-btn'))return;pointerDown(e.clientX,e.clientY);});
    hdr.addEventListener('dblclick',e=>{if(e.target.closest('#ac-minimize-btn'))return;resetPosition();});
    document.addEventListener('mousemove',e=>pointerMove(e.clientX,e.clientY));
    document.addEventListener('mouseup',pointerUp);
    // Safety: if the window loses focus or the mouse leaves the document, cancel any drag
    window.addEventListener('blur',pointerUp);
    document.addEventListener('mouseleave',pointerUp);
    hdr.addEventListener('touchstart',e=>{if(e.target.closest('#ac-minimize-btn'))return;const t=e.touches[0];if(t)pointerDown(t.clientX,t.clientY);},{passive:true});
    document.addEventListener('touchmove',e=>{const t=e.touches[0];if(t&&(pendingDrag||drag)){pointerMove(t.clientX,t.clientY);if(drag)e.preventDefault();}},{passive:false});
    document.addEventListener('touchend',pointerUp);
    document.addEventListener('touchcancel',pointerUp);
  }

  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',buildUI);
  else if(document.body)buildUI();
  else document.addEventListener('DOMContentLoaded',buildUI);
})();