// ==UserScript==
// @name TurboLoader
// @namespace https://lstv.ml/
// @version 2.12
// @description An an UI to quickly and automatically manage plugins, addons and themes.
// @author LSTV
// @match *://turbowarp.org/editor*
// @match *://packager.turbowarp.org/*
// @icon https://www.google.com/s2/favicons?domain=turbowarp.org
// @grant none
// @license MIT
// ==/UserScript==
'esversion: 11';
/*
Copyright (c) under www.LSTV.fun || www.LSTV.ml
Update Tuesday 30, August 2022 by LSTV at 11:41PM (Czechia)
Release Saturday 31, December 2022 by LSTV at 0:00PM (Czechia)
(update and release dates vary)
You are free to distribute or modify this code without written permission by the author, but the name ("LSTV") and the website ("lstv.ml") has to be referenced on a visible place.
You are (not) allowed to sell this code or use it for any kind of financial gain.
This product is provided "as is", with no warranty or guarantee.
If you do find any bugs, please report them as soon as possible!
Privacy notice;
May make a request to an API hosted by LSTV APIs, ExtraGon, or Github.
Those are fully anonymous and no logs are kept.
You acknowledge that any of those providers may see your IP adress and collect data like your browser type and OS.
*/
var isPackager=location.host.includes("packager"),
repo='https://raw.githubusercontent.com/lukas-studio-tv/TurboWarpPluginUI/main/',
resourceCDN="https://ugc.lstv.ml/turboloader_resources",
defaultCDN="https://cdn.lstv.ml/tw",
TurboLoader={ //This object may be modified remotely!!
PublicVersion:2.12,serverData:{}//the serverdata object may be changed remotely after load.
};
let Content={
plugins:[
{
name:"Utils V2",
id:10,
description:`Multi-purpose plugin that fills many of the holes that
Scratch has. Adds many new operators, allows selecting
and reading files, fetching sites, executing scripts, adding
styles, changing cursors, rendering text/images and waay
more.`,
color:"#507750",
isRemote:true,
mirror:"/UtilsV2/"
},
{
name:"GameJolt API",
id:11,
description:`GJ API wrapper made for Scratch!
Allows you to get GJ profile details, add trophies,
use scoreboards, cloud storage and more to extend your game.`,
color:"#2F7F6F",
isRemote:true,
mirror:"/GameJoltAPI/",
updated:true
},
{
name:"AudioStream",
id:12,
description:`Ever thought that the default sound blocks in Scratch are
just too weak? Fear no more with theese advanced!
You can now play audio from any sprite/file/URL, skip in time,
play/pause, add effects, and speed/pitch up the song.
It has everything that Scratch has and more.`,
color:"#A832A8",
isRemote:true,
mirror:"/AudioStream/",
updated:true
},
{
name:"JSONUtils",
id:13,
description:`JSON is amazing, simple, and powerfull.
Are you tired of lists in scratch and need something more?
JSONUtils got you covered!
Store better lists with keys, parse or generate JSON code,
and save game data for each user using localstorage.`,
color:"#21C7FF",
isRemote:true,
mirror:""
},
{
name:"ScratchZIP",
id:14,
description:`A plugin that adds full ZIP capability to scratch using
blocks.
Can create, compress & read ZIP archives using
interactive blocks.`,
color:"#FEE75C",
isRemote:true,
mirror:""
},
{
name:"OverlayGL",
id:15,
description:`Plugin for rendering overlays.
For example, play YouTube or local videos, draw HTML,
view some websites, use code editors, unleash your
creativity.`,
color:"#FF6A6A",
isRemote:true,
mirror:""
},
{
name:"SimplyText",
id:16,
description:`Ever tought of the Scratch'es lack of any proper text
rendering? This plugin is for you then!
No more slow text draw engines!
It allows you to instantly render text, in any font and style.
Extended and upgraded version of the text block from
UtilsV2.`,
color:"#161616",
isRemote:true,
mirror:""
},
{
name:"QuickSand",
id:17,
description:`Need precise on-time calculations or graphics?
Or feel like your game is just way too slow?
The QuickSand engine allows you to add components
that run outside of the ScratchVM so they aren’t limited by
it. Perfect for, for example, rythm games, that need precise
movement and images drawing. `,
color:"linear-gradient(158.04deg, #6AC1FF 14.37%, #C349D7 87.19%)",
isRemote:true,
mirror:""
},
{
name:"Turbocord",
id:18,
description:`This plugins allows you to integrate Discord APIs with
your Scratch project. This means webhooks,
OAuth, and with ARC also Rich Presence and bots.
[ preview only at this moment ]`,
color:"linear-gradient(156.38deg, #5865F2 15.21%, #2E38A8 86.57%)",
isRemote:true,
mirror:""
},
{
name:"FetchAPI",
id:19,
description:`Fetch client (like fetchSync, Ajax or xhr), but for Scratch.
Allows you to download/fetch/send data over to any
server or URL of your choice.
COMES WITH A FREE CORS-BYPASS PROXY!
Features: GET, POST, PUT, DELETE etc, custom headers,
ping and more.`,
color:"#D08900",
isRemote:true,
mirror:""
},
],
themes:[
{
name:"AMSTheme",
id:0,
description:`Minimalistic, precise theme inspired by AMS studio.`,
iconTransparency:false,
color:"#151F0D",
source:""
},
],
addons:[
{
name:"Horizontal sprite menu",
description:"Converts your traditional grid menu to a compact horizontal one.",
screenshots:[],
main:()=>{
//:sandbox
}
}
]
}
function TurboWarp(){
if(!O().has('#plui'))O().add(N('div',{id:'plui',className:'plmenu'}));
window.plTab="plugins";
window.setTab=function(t){
S(O(".pltab_"+window.plTab),{display:"none"});
S(O(".pltab_"+t),{display:"block"});
window.plTab=t;
}
O('#plui').set([
N('div',{className:'plheader',innerHTML:'<h4>TurboLoader</h4>'}),
N('div',{className:'plcontent',inner:[
N('div',{className:'pltabs',inner:[
N('div',{className:'pltab active',innerHTML:'Plugins'}),
N('div',{className:'pltab',innerHTML:'Addons'}),
N('div',{className:'pltab',innerHTML:'Themes'})
]}),
N('div',{className:'pltabc pltab_plugins',inner:[
N('div',{className:'plist',inner:[
N('input',{style:S({width:'calc(100% - 72px)',height:"22px","margin-left":"5px"}),attr:{placeholder:"Search...",Array:["ls","fluent"]},oninput:function(){Q(".pltab_plugins .plist>div.plcard").forEach(a=>{a.style.display=(a.get("h4").innerText+a.get("span").innerText).replaceAll(" ","").toLowerCase().includes(this.value.replaceAll(" ","").toLowerCase())?"block":"none"})}}),
]})
]}),
N('div',{className:'pltabc pltab_addons',inner:[
N("div",{inner:[N("div",{inner:[
N("img",{style:"width:140px;margin-bottom:15px",src:"https://ik.imagekit.io/3dicons/tr:w-200,h-200/v1/dynamic/color/tool-dynamic-color.png"}),
/*blur*/N("img",{style:"width:185px;position:absolute;filter:blur(40px);-webkit-filter:blur(40px);z-index:-1;left:50%;transform:translateX(-50%)",src:"https://ik.imagekit.io/3dicons/tr:w-200,h-200/v1/dynamic/color/tool-dynamic-color.png"}),
N("h1",{style:"font-weight:900",innerHTML:"Sorry!"}),
N("span",{style:"color:#868686",innerHTML:"You do not yet have access here.<br>Things need to get a bit more stable first.<br>I’ll let you know when you can enter!"})
]})],style:"display:flex;align-items:center;justify-content:center;text-align:center;height:100%"})
]}),
N('div',{className:'pltabc pltab_themes',inner:[
N('div',{className:'plist',inner:[
//...
]}),
]}),
N('div',{className:'plbuttonbar',inner:[
N('button',{attr:['tw'],onclick:()=>{O(".plmenu").classList.remove("open")},innerHTML:"Close",style:S({background:'#fff',color:'#000'})})
]})
]}),
])
Q('#plui .pltab').forEach(t=>t.onclick=function(){Q('#plui .pltab').map(e=>e.classList[e==this?'add':'remove']('active'));setTab(this.innerText.trim().toLowerCase())})
O(".pltab_themes").innerHTML=O(".pltab_addons").innerHTML//temporary, and i didnt use .set() because it for some reason steals the content instead of copying
//S(O('#plui'),{display:'block'})
try{
(async()=>{
Content.plugins=Content.plugins.map(p=>{p.mirror=p?.mirror?.length?p.mirror.includes("http")?p.mirror:defaultCDN+p.mirror:"";return p});
for(const p of Content.plugins){
O('.pltab_plugins .plist')?.add?.(N('div',{
className:'plcard',
inner:[
N('div',{
className:'plbanner',
style:S({background:p.color}),
inner:[
p.updated?N("span",{style:"position:absolute;top:9px;background:#32323280;color:#fff;padding:5px;border-radius:6px;left:9px",innerText:"Recently updated"}):"",
N('img',{
attr:{
draggable:'false'
},
className:'plicon',
src:await getImage(resourceCDN+'/icons/'+p.id+'.svg?nc')
})
]
}),
N('h4',p.name),
N('span',{innerHTML:p.description,style:S({
"font-size":'10px'
})}),
N('div',{className:'plbuttonbar',attr:["ch"],inner:
(p.mirror.length?[
N('button',{attr:{"ui-tooltip":"Install plugin",Array:['tw','ls','fluent']},innerHTML:"Install",onclick:function(){installPlugin(p,this)}}),
N('button',{style:"width:25px;height:25px;min-width:0;margin:6px 0;padding:4px",attr:{"ui-tooltip":"Force update",Array:['tw','ls','fluent']},innerHTML:'<svg fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" fill-rule="evenodd"/><path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/></svg>',onclick:async function(){if(await _confirm("Force reload? This redownloads the plugin even if you have a offline copy.<br>It may help if the plugin is broken due to the copy being corrupted."))installPlugin(p,this,true)}})
]:[N('span',{className:"bgrad",style:S({color:'gray'}),innerHTML:"Soon"})])
})
]
}))
}
})();
}catch(e){console.error(e)}
async function installPlugin(plugin,ref,forceUpdate=false){
if(typeof plugin=="string")plugin={mirror:plugin};
plugin.updated=false;
let url=plugin.mirror;
var m=modal({loading:!0,title:"Installing plugin",cancelable:!1,content:forceUpdate?"Preparing reload...":"Checking for plugin updates..."}),v,success=null;
//NOTE: some repetative code here, might need cleanup
let _install=async d=>{
let saved="false",outdated=true;
if(!forceUpdate){
saved=JSON.parse(window.localStorage["Plugin_"+btoa(url)]||"false");
outdated=saved?.version<d;
}
if(saved&&(!outdated||d===!1)&&!forceUpdate){
if(d===!1){
if(!await _confirm("Couldn't check for updates of this plugin, but you do have a local copy for offline use.\nDo you want to load the copy (may be outdated)?")){m?.close?.();return};
}
m.element.get("span>span").set("Installing plugin from local storage...");
try{await addPlugin(saved?.code,plugin)}catch(e){console.error("[TurboLoader] Plugin error ("+url.split("/").filter(f=>f).pop()+"): "+e);success=!1}
m.close();
alert(success===!1?"Plugin loaded with errors.\nCheck the console for details and report the issue to the plugin developer.\n<b>Note: If the plugin works without issues, in some cases this might be ignored.</b>":"The plugin was loaded sucessfully (from memory).\nCheck out your block pallete!");
if(success!==!1)success=!0;
}
if(forceUpdate||(((outdated||!saved)&&(d!==!1))||(d===!1&&!saved))){
if(((d===!1)&&!saved)&&!await _confirm("Warning: couldn't check latest version on the server. Do you still wish to proceed?")){m?.close?.();return} //if failed to check updates & no offline version, warn user before downloading
m.element.get("span>span").set("Downloading "+(outdated?"update":"plugin")+"...");
let pl=await fetchAsync(url+"index.js?v="+d+"&cc="+(Math.round(Math.random()*9000)))("text");
if(pl){
localStorage["Plugin_"+btoa(url)]=JSON.stringify({version:d||0,code:pl});
m.element.get("span>span").set("Installing "+(outdated?"update":"plugin")+"...");
if(outdated)plugin.updated=!0;
if(!saved&&!outdated)plugin.firstTime=!0;
try{await addPlugin(pl,plugin)}catch(e){console.error("[TurboLoader] Plugin error ("+url.split("/").filter(f=>f).pop()+"): "+e);success=!1}
alert(success===!1?"Plugin loaded with errors.\nCheck the console for details and report the issue to the plugin developer.\n<b>Note: If the plugin works without issues, in some cases this might be ignored.</b>":"The plugin was loaded sucessfully.\nCheck out your block pallete!");
if(success!==!1)success=!0;
m?.close?.();
}else{
m.close();
m=await modal({content:outdated?"Couldn't update the plugin! Check your internet connection and status of the CDN.\nAn OUTDATED version of the plugin will now be loaded.":"Couldn't download this plugin and there isn't a offline version available.\nPlease check your internet connection or the status of the CDN!",title:"Failed downloading plugin",buttons:[{text:"Close"},{text:"Retry",color:"gray",element:{onclick:()=>{installPlugin(plugin,ref)}}}]})
}
}
if(success!==!1&&success!==null){
ref.onclick=()=>{};
ref.parentElement.innerHTML='<span style="color:#32ee5d" class=bgrad>Plugin installed</span>'
}else{
ref.onclick=()=>{};
ref.parentElement.innerHTML='<span style="color:#ee3232" class=bgrad>Plugin has errors</span>'
}
}
if(!forceUpdate){fetchSync(url+"@version",{bypass_cache:!0})("json")(_install)}else{_install(0)}
}
function addPlugin(c,plugin){
// Actually imports the plugin.
let tl="1F3D180F303344BAA3DEC35D9717812A",id=btoa(Date.now()/(Math.random()*10)).replaceAll('=','');
window[tl]={
extension(fun){
if(typeof fun!="function")return;
fun({
set(_class){
try{_class=(_class)()}catch(e){}//if _class is a function, call it and use the class it returns
//Register extension
let i=new _class(window.vm.extensionManager.runtime,window.vm),sn=window.vm.extensionManager._registerInternalExtension(i);
window.vm.extensionManager._loadedExtensions.set(i.getInfo().id,sn)
},
requires(l){
//TODO: This should be improoved
//addPlugin(window[l].toString())
},
dependency(plugin){
//TODO: This should be improoved
//installPlugin("https://cdn.lstv.ml/tw/"+plugin+"/")//Only allows safe plugins
},
window:window,
blocks(o){
},
async imageAsset(src){
return await getImage(plugin?.mirror+src);
},
details:plugin,
isPackager:isPackager,
vm:vm,
hasUpdates:!!plugin?.hasUpdates,
firstTime:!!plugin?.firstTime,
updated:!!plugin?.updated,
alert:(a)=>{alert(a,{title:plugin?.name+" says:"})},
changelog:(n)=>{if((!isPackager)&&(plugin.updated||plugin.firstTime)){setTimeout(()=>alert(n,{title:plugin?.name+"'s changelog:"}),1500)}},
})
},
emptyMenu:[{text:"empty",value:"empty"}],
blocksPrefix(p,b){
return b.blocks.map(b=>{b.opcode=p+b.opcode;return b})
},
pickFile(accept,callback=()=>{}){
//no frameworks allowed here so going plain JS
return new Promise((r,rj)=>{
let i=document.createElement('input');
i.type='file';
i.accept=accept;
i.onchange=e=>{
if(!i.files.length){callback("empty");rj("Error: The user has cancelled the request")}
let file=i.files[0],
reader = new FileReader();
reader.readAsDataURL(file);
reader.onload=_r=>{callback(_r.target.result);r(_r.target.result)}
}
i.click();
})
}
}
return new Promise((r,e)=>{
O().add(N("script",{innerHTML:`window["${id}"]=((TurboLoader)=>{${c}});`}))
try{window[id](window[tl])}catch(er){e(er)}
setTimeout(r,1500)
});
}
setTimeout(() => {
/*Adds the plugin menu button*/O("div.menu-bar_file-group_1_CHX").add(N("div",{className:"plbutton menu-bar_menu-bar-item_oLDa- menu-bar_hoverable_c6WFB",innerHTML:`<div><span>Plugins<div style=display:none class=plupdateind><h1 style=font-weight:900>NEW UPDATE</h1><span style=color:#868686>Good news! You got the<br>new version of TurboLoader!<br>Check it out!</span><img style=top:-35px;right:-45px;width:100px src="https://ugc.lstv.ml/sparkle_2.png?q2"><img style=bottom:-20px;left:-40px;width:80px src="https://ugc.lstv.ml/sparkle_1.png?q2"></div></span></div>`,onclick:()=>{O(".plmenu").classList.add("open");window.localStorage.updateChecked="true";O(".plupdateind").style.display="none"}}))
if(!window.localStorage.updateChecked){O(".plupdateind").style.display="block"}
setTab("plugins");
}, 700);
let d=()=>{
D().documentElement.style.setProperty('--vw-scale', `${0.002*window.innerWidth}`);
}
d();
window.addEventListener('resize',d);
}
function TurboWarpPackager(){
}
/*
CHECKPOINT: Libraries
*/
/*TinyFramework*/var TinyFramework={Q:(e,q)=>(e?.tagName&&!q?[e]:[...(e?.tagName?e:D()).querySelectorAll(e?.tagName?!q?'*':q:typeof e=='string'?e:'*')])?.map(r=>{Object.assign(r,{isElement:!0,attr(specific=!1){let a=r.attributes,c={};Object.keys(a).map(b=>c[a[b].nodeName]=a[b].nodeValue);return specific?c[specific]:c},get:(t='*')=>O(r,t),getChildern:q=>Q(r.query()+'>'+q||'*'),child:i=>r.children[i||0],getAll:(t='*')=>Q(r,t),add:(a='')=>{if(typeof a=='string'||a?.tagName)a=[a];a.forEach(i=>r[i?.tagName?'appendChild':'append'](i));return r.self},addOnce(a){if(!O('#'+a.id))r.add(a)},setStyle:(...a)=>S(r.self,...a),getStyle:_=>S(r.self),set:(...a)=>{r.innerHTML='';return r.add(...a)},has:(...a)=>{return !!a.find(l=>r.get(l))},watch:c=>E(r,c),parent:(n=0)=>r.tagName=='BODY'?r.parentElement:(n>0?O(r.parentElement).parent(n-1):r.parentElement),self:r,path:()=>{let p=[r],i=0;while(p[p.length-1]?.tagName!='HTML'){p.push(r.parent(i));i++}return p.reverse()},query:()=>r.path().map(r=>r.tagName+(r.className?'.'+r.className.replace(/\s/g,'.'):'')+(r.id?'#'+r.id:'')).join('>'),queryPath:r.query});return r.self}),O:(...e)=>{e=e.length<1?['body']:e;return Q(...e)[0]},D:()=>document,N:(e='div',o={})=>{let n=O(Object.assign(D().createElement(e),(typeof o=='string'?{innerHTML:o}:o)));if(Array.isArray(o?.attr)){o.attr={'Array':o.attr}}if(o?.attr){Object.keys(o.attr).forEach(k=>{if(k=='Array'){o.attr[k].map(_=>n.setAttribute(_,''));return}n.setAttribute(k,o.attr[k]||'')})}if(o?.inner||o?.content){n.add(o?.inner||o?.content)}return n},S:(e,s)=>!s?!e?O():(e.id!==void 0)?getComputedStyle(e):typeof e=='string'?O(e):Object.keys(e).map(f=>f+':'+e[f]).join(';'):(Array.isArray(e)?e:!e?[O()]:[e]).forEach(m=>{m=typeof m=='string'?O(m):m;Object.assign(m.style,s)}),E:(b,c)=>{if(typeof c!='function'){let _c=c,_b=b;c=()=>{try{S(Q(_b),_c)}catch(e){}};b=O()}new (window.MutationObserver||window.WebKitMutationObserver)(r=>{c([...r[0].addedNodes].map(n=>O(n)),[...r[0].removedNodes].map(n=>O(n)))}).observe(b,{childList:!0,subtree:!0});return O(b)}}
var fetchSync=(...a)=>b=>{let d=d=>{a[0]=a[1]?.bypass_cache?(a[0]+(a[0].includes('?')?'&':'?')+'cache='+btoa(Date.now()/(Math.random()*10)).replaceAll('=','')):a[0];a[0]=a[0].includes('://')||a[1].local?a[0]:window.location.protocol+'//'+a[0];let ts=Date.now();try{fetch(...a).then(q=>q).then(async q=>{let _t="string"==typeof b?b:"text";d(_t=='ping'?(q.ok?(a[1]?.ping?(a[1]?.ping==await q.text()?Date.now()-ts:!1):Date.now()-ts):!1):await q[_t](),Date.now()-ts)}).catch(w=>d(!1))}catch(e){d(!1)}};return"string"==typeof b?a=>{d(a)}:void d(b)},fetchAsync=(...c)=>async(a)=>new Promise(b=>{fetchSync(...c)(a)(a=>{b(a)})});
/*Downloads image and forces caching by storing it in localStorage*/function getImage(b,id){return new Promise(async e=>{let f=id||"Cache_"+btoa(b.replaceAll(/[\/\\\:]/gi,"").replace("https","").replace("http","").trim()),a=localStorage[f];if(a){e(a);return};if(b.includes(".svg")){let svg="data:image/svg+xml;base64,"+btoa(await fetchAsync(b,{local:false})("text"));localStorage[f]=svg;e(svg);return};var d=new Image;d.src=b;d.crossOrigin="Anonymous",d.onload=function(){var b=document.createElement("canvas"),a=b.getContext("2d");b.height=this.naturalHeight,b.width=this.naturalWidth,a.drawImage(this,0,0);var c=b.toDataURL("image/png");localStorage[f]=c,e(c)}})}
if(!window?.Globalise){window.Globalise=(...b)=>b.map(a=>typeof(a)=='string'?(()=>window[a]=window?.[a]||null)():Array.isArray(a)?a.map(v=>window[v]=window?.[v]||null):Object.keys(a).map(v=>window[v]=a[v]))};
const {S,Q,O,D,E,N}=TinyFramework;
Globalise(TinyFramework,{modal:modal,fetchSync:fetchSync,fetchAsync:fetchAsync,getImage:getImage});
function modal(opt={}){
opt=Object.assign({
title:"Alert",
content:"",
cancelable:true,
buttons:[
{text:"OK"},
{text:"Cancel",color:"gray"},
],
loading:false,
use:!1
},opt);
let element=N("div",{
attr:{"ls-modal":"true"},
className:"closed",
style:opt.style,
onclick:e=>{if(opt.cancelable&&O(e.target).attr("ls-modal"))close()},
inner:[!opt.use?N('div',{
inner:[
N('span',{
inner:[N("b",opt?.title?opt.title+"<br>":""),N("span",opt.content.trim())]
}),
N('div',{
inner:opt.loading?[N("div",{attr:["ls-load"]})]:opt.buttons?.map?.((b,i)=>N('button',Object.assign({attr:["ls","fluent",b.color?"ls-"+b.color:'ls-blue'],className:"btn-index-"+i,innerHTML:b.text},(b?.element||{})))),
attr:["dialog_bottom"]
})
],
attr:["modal_body","dialog_body"]
}):opt.use]
});
let close=function(ref){element.classList.add('closed');let id=ref?.className.includes("btn-index-")?(+ref?.className.replaceAll(/[a-z-]/g,"")):void 0;opt?.onclose?.(id);return id};
element.getAll("button").forEach(e=>e.addEventListener("click",()=>close(e)))
O().add(element);
setTimeout(()=>{element.classList.remove('closed')},20);
return {
element:element,
close:close,
open:()=>element.classList.remove('closed')
}
}
//comment following if you don't want to override default methods
Globalise({alert:(m,opt={})=>new Promise((r)=>modal(Object.assign({content:m,buttons:[{text:"OK"}],onclose:r},opt))),_confirm:(m,opt={})=>new Promise((r)=>modal(Object.assign({content:m,cancelable:false,buttons:[{text:"OK"},{text:"Cancel",color:"gray"}],onclose:(b)=>r(!b)},opt)))})
if(!O().has('#plugin_loader_styles'))O().add(N('div',{id:'plugin_loader_styles'}));
/*
Following is just CSS for the UI
*/
O('#plugin_loader_styles').set(N('style',`
@import url('https://fonts.googleapis.com/css?family=Rubik:300,400,500,700,900');
/*Copyright (c) LSTV 2022*/
@import url('data:text/css;charset=utf-8;base64,OnJvb3R7LS1hY2NlbnQ6IzAwODVGRjstLWFjY2VudC10cjojMDA4NGZmODA7LS1hY2NlbnQtZGFyazojMDA1ZWI2Oy0tbHN0di15ZWxsb3c6I0ZGRTEwOTstLWxzdHYtcmVkOiNGRjI4Mjg7LS1sc3R2LWJsdWU6IzAwRDFGRn1he2NvbG9yOiMwMDg1RkY7dGV4dC1kZWNvcmF0aW9uOm5vbmV9aDEsaDIsaDMsaDQsaDUsaDYscCxoZWFkZXIsYm9keSxodG1se21hcmdpbjowfWgxLGgyLGgzLGg0LGg1LGg2LGhlYWRlcntmb250LXdlaWdodDo3MDB9W2xzXTpub3QoW2ZsdWVudF0saW5wdXQsdGV4dGFyZWEsc2VsZWN0KXtiYWNrZ3JvdW5kOnZhcigtLWFjY2VudCkhaW1wb3J0YW50O2NvbG9yOnZhcigtLWNvbG9yLWZsaXApfWJ1dHRvbltsc117Y3Vyc29yOnBvaW50ZXJ9W2xzXXtiYWNrZ3JvdW5kOnZhcigtLWJhY2tncm91bmQpO2JvcmRlcjowO2JvcmRlci1yYWRpdXM6OXB4O3BhZGRpbmc6NXB4IDEwcHg7bWFyZ2luOjZweCAwO291dGxpbmU6bm9uZTtwb3NpdGlvbjpyZWxhdGl2ZTtjb2xvcjp2YXIoLS1jb2xvci1mbGlwKX1bbHNdOm5vdChbZmx1ZW50XSl7Ym94LXNoYWRvdzowIDNweCAwIDAgdmFyKC0tYWNjZW50LWRhcmspLGluc2V0IDAgMCAwIDFweCB2YXIoLS1hY2NlbnQpfVtsc11bZmx1ZW50XXtiYWNrZHJvcC1maWx0ZXI6Ymx1cigyNXB4KTtib3JkZXItcmFkaXVzOjdweDtvcGFjaXR5Oi45O2JveC1zaGFkb3c6MCAxNXB4IDI0cHggLTEwcHggIzAwMDAwMDU1LGluc2V0IDAgLjJweCAwIDEuMXB4ICNmZmZmZmYyOX1pbnB1dFtsc106bm90KFtmbHVlbnRdKTpmb2N1cyxbbHNdOmFjdGl2ZTpub3QoW2Rpc2FibGVkXSk6bm90KFtmbHVlbnRdKSx0ZXh0YXJlYVtsc106Zm9jdXN7Ym94LXNoYWRvdzowIDEuNXB4IDAgMCB2YXIoLS1hY2NlbnQtZGFyayksaW5zZXQgMCAwIDAgMXB4IHZhcigtLWFjY2VudCksMCAxNHB4IDIwcHggLTVweCB2YXIoLS1hY2NlbnQtdHIpO3RyYW5zZm9ybTp0cmFuc2xhdGVZKDEuNXB4KX1bbnNdLFtsb2FkXSAqLFtsb2FkXXstd2Via2l0LXVzZXItc2VsZWN0Om5vbmU7dXNlci1zZWxlY3Q6bm9uZTstd2Via2l0LXRvdWNoLWNhbGxvdXQ6bm9uZX1bbnBdLFtsb2FkXSAqLFtsb2FkXXtwb2ludGVyLWV2ZW50czpub25lfVtsc11bc3dpdGNoXT4qe3dpZHRoOjMwcHg7aGVpZ2h0OjMwcHg7ZGlzcGxheTppbmxpbmUtZmxleH1bbHNdW3N3aXRjaF0gaXttYXJnaW46MH1bbHNdW3N3aXRjaF17cGFkZGluZzowO2N1cnNvcjpwb2ludGVyfVtsc11bc3dpdGNoXSBbaGFuZGxlXXtwb2ludGVyLWV2ZW50czpub25lO2JvcmRlci1yYWRpdXM6OXB4O2JhY2tncm91bmQ6I2ZmZjtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6NHB4O2xlZnQ6NHB4O3RyYW5zaXRpb24tZHVyYXRpb246LjJzO3dpZHRoOjMwcHg7aGVpZ2h0OjIycHh9W2xzXVtzd2l0Y2hdLnNlbGVjdGVkIFtoYW5kbGVde2xlZnQ6MzBweH1bdWktdG9vbHRpcF17cG9zaXRpb246cmVsYXRpdmV9W2ZsdWVudF0sW3VpLXRvb2x0aXBdOjphZnRlcntiYWNrZHJvcC1maWx0ZXI6Ymx1cigyMHB4KTtiYWNrZ3JvdW5kOiMwMDAwMDA4YTtjb2xvcjojZmZmO2JveC1zaGFkb3c6MCAxNXB4IDIwcHggMXB4ICMwMDAwMDBhYTt0cmFuc2l0aW9uLWR1cmF0aW9uOi4yc30ubWQtYm94LFtscy1tb2RhbF0gW2RpYWxvZ19ib2R5XSxbbHMtbW9kYWwtbm9maWx0ZXJde3RyYW5zaXRpb24tZHVyYXRpb246LjJzO2JhY2tncm91bmQ6IzJCMkIyQjtib3JkZXI6LjhweCBzb2xpZCAjM0MzQzNDO2JveC1zaGFkb3c6MCA4cHggMjVweCAjMDAwO2JvcmRlci1yYWRpdXM6MTJweDttYXgtd2lkdGg6NTcwcHg7b3ZlcmZsb3c6aGlkZGVufVt1aS10b29sdGlwXTpob3Zlcjo6YWZ0ZXJ7Ym90dG9tOjM1cHg7b3BhY2l0eToxIWltcG9ydGFudH1bdWktdG9vbHRpcF06OmFmdGVye2NvbnRlbnQ6YXR0cih1aS10b29sdGlwKTt6LWluZGV4OjkwMDAwMDtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjUwJTt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtNTAlKTtwb2ludGVyLWV2ZW50czpub25lO29wYWNpdHk6MDtib3R0b206MjNweDtwYWRkaW5nOjRweCA4cHg7Ym9yZGVyLXJhZGl1czo2cHg7d2lkdGg6bWF4LWNvbnRlbnQ7dGV4dC1hbGlnbjpjZW50ZXI7Zm9udC1zaXplOjE2cHg7Zm9udC1mYW1pbHk6dmFyKC0tZm9udCk7bWF4LXdpZHRoOjI1MHB4O3doaXRlLXNwYWNlOnByZS13cmFwfVt1aS10b29sdGlwXTo6YWZ0ZXI6bm90KFtmbHVlbnRdKXtiYWNrZ3JvdW5kOiMwMDB9W3VpLXRvb2x0aXBdOjphZnRlcjpub3QoW2ZsdWVudF0pOmFmdGVye2NvbnRlbnQ6IiI7cG9zaXRpb246YWJzb2x1dGU7dG9wOjEwMCU7bGVmdDo1MCU7bWFyZ2luLWxlZnQ6LTVweDtib3JkZXItd2lkdGg6NXB4O2JvcmRlci1zdHlsZTpzb2xpZDtib3JkZXItY29sb3I6IzAwMCAjMDAwMCAjMDAwMH1bbHNdW2ZsdWVudF06aG92ZXJ7b3BhY2l0eToxfVtsc11bZmx1ZW50XTpub3QoaW5wdXQsdGV4dGFyZWEsc2VsZWN0KXtiYWNrZ3JvdW5kOnZhcigtLWFjY2VudCl9W2xzXVtmbHVlbnRdOmFjdGl2ZTpub3QoaW5wdXQsdGV4dGFyZWEsc2VsZWN0KXtiYWNrZ3JvdW5kOnZhcigtLWFjY2VudC1kYXJrKX1pbWdbbHNde3BhZGRpbmc6MH1bb3ZlcmxheV17cG9zaXRpb246Zml4ZWQ7dG9wOjA7bGVmdDowO3JpZ2h0OjA7Ym90dG9tOjA7ei1pbmRleDo5OTk5O3dpZHRoOjEwMCU7aGVpZ2h0OjEwMCV9Knstd2Via2l0LXRhcC1oaWdobGlnaHQtY29sb3I6IzAwMDA7LXdlYmtpdC1oaWdobGlnaHQ6bm9uZX1ib2R5e2JhY2tncm91bmQ6dmFyKC0tYmFja2dyb3VuZCk7b3ZlcmZsb3cteTpvdmVybGF5O3BhZGRpbmctdG9wOjQ1cHh9Ojotd2Via2l0LXNjcm9sbGJhcnt3aWR0aDozcHg7aGVpZ2h0OjNweH06Oi13ZWJraXQtc2Nyb2xsYmFyLXRyYWNre2JhY2tncm91bmQ6IzAwMDB9Ojotd2Via2l0LXNjcm9sbGJhci10aHVtYntib3JkZXItcmFkaXVzOjVweDtiYWNrZ3JvdW5kOiMyYzJjMmM4MX06Oi13ZWJraXQtc2Nyb2xsYmFyLXRodW1iOmhvdmVye2JhY2tncm91bmQ6IzBmMGYwZjU1fVtsc10sW3RyXXt0cmFuc2l0aW9uLWR1cmF0aW9uOi4yc31pbnB1dFtsc117cG9zaXRpb246cmVsYXRpdmV9Ym9keSxidXR0b24saW5wdXR7Zm9udC1mYW1pbHk6dmFyKC0tZm9udCkhaW1wb3J0YW50O2NvbG9yOnZhcigtLWNvbG9yKX1idXR0b25bZmx1ZW50XTphY3RpdmV7dHJhbnNmb3JtOnNjYWxlKDAuOSl9LmRvdHt3aWR0aDoxMHB4O2hlaWdodDoxMHB4O2JvcmRlci1yYWRpdXM6NTAlO2JhY2tncm91bmQ6Z3JheX0uaGVhZGVye2JhY2tncm91bmQ6IzQxNDE0MTtoZWlnaHQ6NDVweDt3aWR0aDoxMDAlO3Bvc2l0aW9uOmZpeGVkO3otaW5kZXg6NTt0b3A6MDttYXgtaGVpZ2h0OjQ1cHh9W2xzXSBpe2ZvbnQtc2l6ZToxZW07bWFyZ2luOjAgNHB4IDAgMnB4fVtscy1ncmVlbl17LS1hY2NlbnQ6IzRkYWY1MTstLWFjY2VudC10cjojNGRhZjUxODA7LS1hY2NlbnQtZGFyazojMzY3YzM5fVtscy1ncmF5XXstLWFjY2VudDojNDk0OTQ5Oy0tYWNjZW50LXRyOiM0OTQ5NDk4MDstLWFjY2VudC1kYXJrOiMyNzI3Mjd9W2xzLWdyYXktbGlnaHRdey0tYWNjZW50OiM2YjZiNmI7LS1hY2NlbnQtdHI6IzZiNmI2YjgwOy0tYWNjZW50LWRhcms6IzQ5NDk0OX1bbHMtcHVycGxlXXstLWFjY2VudDojOWI0ZGFmOy0tYWNjZW50LXRyOiM5YjRkYWY4MDstLWFjY2VudC1kYXJrOiM3OTJiOGZ9W2xzLWJ1cnBsZV17LS1hY2NlbnQ6IzUxNjVmNjstLWFjY2VudC10cjojNTE2NWY2ODA7LS1hY2NlbnQtZGFyazojM2I0YWJifVtscy1vcmFuZ2Vdey0tYWNjZW50OiNmZjhjMjA7LS1hY2NlbnQtdHI6I2ZmOGMyMDgwOy0tYWNjZW50LWRhcms6I2JhNjcxOH1bbHMtcmVkXXstLWFjY2VudDojZjUyZjJmOy0tYWNjZW50LXRyOiNmNTJmMmY4MDstLWFjY2VudC1kYXJrOiM5NjFiMWJ9W2xzLXdoaXRlXXstLWFjY2VudDojZmZmOy0tYWNjZW50LXRyOiNmZmZmZmY4MDstLWFjY2VudC1kYXJrOiNjY2N9W2xzLWJsYWNrXXstLWFjY2VudDojMDAwOy0tYWNjZW50LXRyOiMwMDAwMDA4MDstLWFjY2VudC1kYXJrOiMxNjE2MTY7LS1jb2xvcjojZmZmfSNsb2Fke2Rpc3BsYXk6bm9uZSFpbXBvcnRhbnR9LmZsLFtmbF17ZGlzcGxheTpmbGV4fWV2YWwsW2V2YWxde2Rpc3BsYXk6bm9uZX0uY2h2LFtjaHZdLC5jdmgsW2N2aF17ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpjZW50ZXI7YWxpZ24taXRlbXM6Y2VudGVyfS5jaCxbY2hde2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyfS5jdixbY3Zde2Rpc3BsYXk6ZmxleDthbGlnbi1pdGVtczpjZW50ZXJ9QGZvbnQtZmFjZXtmb250LWRpc3BsYXk6YmxvY2s7Zm9udC1mYW1pbHk6ImxzdHYtaWNvbnMiO3NyYzp1cmwoL3N0YXRpY192Mi9mb250cy9sc3R2aWNvbnMud29mZjI/dj0wKSBmb3JtYXQoIndvZmYyIiksdXJsKC9zdGF0aWNfdjIvZm9udHMvbHN0dmljb25zLndvZmY/dj0wKSBmb3JtYXQoIndvZmYiKX0ubGk6OmJlZm9yZSxbY2xhc3NePSJsaS0iXTo6YmVmb3JlLFtjbGFzcyo9IiBsaS0iXTo6YmVmb3Jle2Rpc3BsYXk6aW5saW5lLWJsb2NrO2ZvbnQtZmFtaWx5OmxzdHYtaWNvbnMhaW1wb3J0YW50O2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtd2VpZ2h0OjQwMCFpbXBvcnRhbnQ7Zm9udC12YXJpYW50Om5vcm1hbDt0ZXh0LXRyYW5zZm9ybTpub25lO2xpbmUtaGVpZ2h0OjE7dmVydGljYWwtYWxpZ246LS4xMjVlbTstd2Via2l0LWZvbnQtc21vb3RoaW5nOmFudGlhbGlhc2VkOy1tb3otb3N4LWZvbnQtc21vb3RoaW5nOmdyYXlzY2FsZX1Aa2V5ZnJhbWVzIHJvdGF0ZXswJXt0cmFuc2Zvcm06cm90YXRlKDApfTEwMCV7dHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpfX1bbG9hZF06YmVmb3Jle3otaW5kZXg6MTtjb250ZW50OicnO2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO2FsaWduLWl0ZW1zOmNlbnRlcjtiYWNrZ3JvdW5kOnZhcigtLWJhY2tncm91bmQtdHIpO3BvaW50ZXItZXZlbnRzOm5vbmU7cG9zaXRpb246YWJzb2x1dGU7dG9wOjA7bGVmdDowO3JpZ2h0OjA7Ym90dG9tOjA7LXdlYmtpdC1iYWNrZHJvcC1maWx0ZXI6Ymx1cigxOHB4KTtiYWNrZHJvcC1maWx0ZXI6Ymx1cigxOHB4KX1bbG9hZF06YWZ0ZXJ7ei1pbmRleDoyO2NvbnRlbnQ6J2U4MzAnO2ZvbnQtc2l6ZTo0ZW07Y29sb3I6dmFyKC0tYWNjZW50KTtmb250LWZhbWlseTpsc3R2LWljb25zO3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6Y2FsYyg1MCUgLSAzMHB4KTt0b3A6Y2FsYyg1MCUgLSA0NXB4KX1bbHMtbG9hZF17d2lkdGg6NTZweDt3aWR0aDozNnB4O2hlaWdodDozNnB4O2JvcmRlcjo1cHggc29saWQgdmFyKC0tYWNjZW50LXRyKTtib3JkZXItdG9wLWNvbG9yOnZhcigtLWFjY2VudCk7Ym9yZGVyLXJhZGl1czo1MCV9W2xzLXJvdGF0ZV0sW2xzLWxvYWRdLFtsb2FkXTphZnRlcnthbmltYXRpb246cm90YXRlIDJzIGxpbmVhciBpbmZpbml0ZSBib3RofVtscy1tb2RhbF17cG9zaXRpb246Zml4ZWQ7dG9wOjA7bGVmdDowO3JpZ2h0OjA7Ym90dG9tOjA7ei1pbmRleDo1MDAwMDtiYWNrZ3JvdW5kOiMwMDA1O2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6Y2VudGVyO2FsaWduLWl0ZW1zOmNlbnRlcjt0cmFuc2l0aW9uLWR1cmF0aW9uOi4yc31bZGlhbG9nX2JvZHldLFtscy1tb2RhbC1ub2ZpbHRlcl17cGFkZGluZzoyMHB4O3BhZGRpbmctYm90dG9tOjg1cHg7d2lkdGg6MzcwcHg7bWluLWhlaWdodDoxNzBweDtwb3NpdGlvbjpyZWxhdGl2ZTt0ZXh0LWFsaWduOmxlZnQ7dHJhbnNpdGlvbi1kdXJhdGlvbjouMnN9W2RpYWxvZ19ib2R5XSBzcGFuLFtscy1tb2RhbC1ub2ZpbHRlcl0gc3Bhbnt3aGl0ZS1zcGFjZTpwcmUtd3JhcH1bbHMtbW9kYWxdLmNsb3NlZCxbbHMtbW9kYWwtbm9maWx0ZXJdLmNsb3NlZHtvcGFjaXR5OjA7cG9pbnRlci1ldmVudHM6bm9uZX1bbHMtbW9kYWxdLmNsb3NlZCBbbW9kYWxfYm9keV17dHJhbnNmb3JtOnNjYWxlKDEuMil9W2RpYWxvZ19ib3R0b21de3Bvc2l0aW9uOmFic29sdXRlO2JvdHRvbTowO2xlZnQ6MDtyaWdodDowO2JhY2tncm91bmQ6IzIwMjAyMDtib3JkZXItdG9wOi4xcHggc29saWQgIzFDMUMxQztwYWRkaW5nOjEwcHg7aGVpZ2h0OjY1cHg7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpzcGFjZS1hcm91bmQ7YWxpZ24taXRlbXM6Y2VudGVyfVtkaWFsb2dfYm90dG9tXSBidXR0b257d2lkdGg6MTAwJTttYXJnaW46NXB4O2hlaWdodDo4MCV9LmltZ19yb3VuZF9zZWxlY3R7ZGlzcGxheTppbmxpbmUtYmxvY2s7Y3Vyc29yOnBvaW50ZXI7cG9zaXRpb246cmVsYXRpdmU7b3ZlcmZsb3c6aGlkZGVuO3dpZHRoOjkwcHg7aGVpZ2h0OjkwcHg7Ym9yZGVyLXJhZGl1czo1MCV9LmltZ19yb3VuZF9zZWxlY3QgaW1ne29iamVjdC1maXQ6Y292ZXI7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJX0uaW1nX3JvdW5kX3NlbGVjdDpob3ZlcntvdXRsaW5lOjNweCBzb2xpZCB2YXIoLS1hY2NlbnQtdHIpfS5pbWdfcm91bmRfc2VsZWN0OmFmdGVye2NvbnRlbnQ6IkYyMTkiO2JvdHRvbTotNTBweDt0cmFuc2l0aW9uLWR1cmF0aW9uOi4yc30uaW1nX3JvdW5kX3NlbGVjdDpob3ZlcjphZnRlcntmb250LWZhbWlseTpib290c3RyYXAtaWNvbnM7cG9zaXRpb246YWJzb2x1dGU7Ym90dG9tOjAhaW1wb3J0YW50O3BhZGRpbmc6MTBweDtsZWZ0OjA7cmlnaHQ6MDtiYWNrZ3JvdW5kOiMwMDA2fQ==');
[ls],[ls-modal]{font-family:'Rubik',sans-serif}
[dialog_body],[ls-modal-nofilter]{min-height:85px;font-size:16px}
[dialog_body] span{word-break:break-word}
[dialog_body] button{font-size:15px}
:root{
--tw-color:#E44444;
--accent:#E44444;--accent-tr:#E4444480;--accent-dark:#872a2a;--lstv-yellow:#FFE109;--lstv-red:#FF2828;--lstv-blue:#00D1FF
}
.plheader{display:flex;align-items:center;padding:0 12px;background:#fff1;position:absolute;top:0px;left:0px;right:0px;height:35px}
.plmenu{box-shadow:0 0 0 40vw #0006;background:#181818;color:#fff;font-family:'Rubik',sans-serif;width:765px;height:450px;display:none;position:fixed;z-index:10000;top:50%;left:50%;transform:translateX(-50%) translateY(-50%) scale(calc(max(1,min(1.3,var(--vw-scale))) - 0.2));border-radius:12px;border:3px solid #62626231;padding:0;padding-top:40px;overflow:hidden}
.plmenu h4{line-height:16px}
.plcontent{padding:15px;position:absolute;bottom:0;top:35px;right:0;left:0}
button[tw] {
border: none;
outline: none;
border-radius: 7px;
padding: 4px 15px;
box-shadow: inset 0 0 0 2px #0006;
font-size: 12px;
min-width: 72px;
background: var(--tw-color);
color: #fff;
cursor: pointer;
}
.plcard button[tw]{padding:8px 15px;width:calc(90% - 35px);margin-right:7px}
.pl_preset{background:#333333;color:white;padding:10px;border-radius:5px;display:inline-block;cursor:pointer;margin:5px}
.plcspan{margin-right:8px;border-radius:300px;padding:0px;width:10px;height:10px;display:inline-block;}
[theme="light"] .plmenu,[theme="light"] .plcard,[theme="light"] [dialog_body]{background:#fff!important;color:#222}
[theme="light"] .plheader{background:#0001}
[theme="light"] .pltab{background:#e6e6e6}
[theme="light"] .pltab.active{background:#ffe8e8}
[theme="light"] .plupdateind{background:#fff;color:#222;box-shadow:0px 10px 40px 0 #00000042}
[theme="light"] textarea,[theme="light"] input,[theme="light"] .pl_preset{color:#222}
[theme="light"] [dialog_bottom]{background:#e3e3e3;border-top:0.1px solid #a7a7a7}
[theme="light"] input[fluent]{background:#f7f7f7;box-shadow:0 12px 24px -10px #32323255,inset 0px 0.2px 0 1.1px #8c8c8c29}
[dialog_bottom]{height:50px}
[ls-load]{width:27px;height:27px;border:7px solid var(--accent-tr);border-top-color:var(--accent)}
.plcard span{color:#999}
[theme="light"] .plcard span{color:#777}
.plmenu.open{display:block}
h1,h2,h3,h4,h5,h6{margin:0}
.pltabs{display:flex;justify-content:center;margin-bottom:10px}
.pltab{width:120px;padding:7px 0;text-align:center;margin-right:20px;position:relative;background:#151515;border-radius:70px;transition-duration:.2s;overflow:hidden;user-select:none;cursor:pointer}
.pltab:last-child{margin-right:0}
.pltab.active{background:#1F1F1F}
.pltab:after{content:"";transition-duration:.2s;position:absolute;bottom:-5px;left:35%;right:35%;height:3px;border-radius:10px;background:var(--tw-color)}
.pltab.active:after{bottom:1px}
.plcard {
background:#131313;
border-radius: 11px;
width: 213px;
height: 115px;
position: relative;
margin: 5px;
box-shadow: 0 4px 5px #0005;
padding: 9px;
overflow: hidden;
padding-top: 80px;
padding-bottom: 15px;
transition-duration: .2s;
box-shadow: 0 4px 8px #0005, inset 0px -1px 0 0px #ffffff12;
line-height:8.5px;
}
.plbanner {
position: absolute;
top: 1px;
left: 1px;
right: 1px;
height: 70px;
box-shadow: inset 0px -4px 17px 0 #000b, inset 0px 1px 0 0px #ffffff63;
border-radius: 10px 10px 0 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.plbutton{
position:relative;
}
.plupdateind{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 45px;
padding: 20px 65px;
background: #171717;
box-shadow: inset 0 2px 0 0 #ffffff36, 0px 10px 40px 0 #000a;
border-radius: 9px;
font-family: Rubik;
text-align: center;
font-weight: 400;
letter-spacing: 1px;
z-index: 900;
}
.plupdateind:hover{
outline:2px solid var(--tw-color)
}
.plupdateind img{
position:absolute
}
.bgrad:before{content:"";position:absolute;bottom:-18px;left:0;right:0;background:currentColor;height:15px;-webkit-filter:blur(25px);filter:blur(25px)}
.bgrad{
margin-bottom:12px;display:block;font-size:16px
}
.plist{display:flex;align-content:flex-start;width:100%;overflow:overlay;flex-wrap:wrap;bottom:35px;top:60px;position:absolute;padding-bottom:50px}
.plicon {
width: 32px;
height: 32px;
object-fit: contain;
}
/*temporary:*/
.pltab_themes,.pltab_addons{height:100%}
.pltabc{display:none}
.plbuttonbar{position:absolute;bottom:6px;right:6px;left:0;text-align:right}
.plcard .plbuttonbar{bottom:4px;right:0;left:0;text-align:center}
::-webkit-scrollbar{width:3px;height:3px}
::-webkit-scrollbar-track{background:none}
::-webkit-scrollbar-thumb{background:#ffF3;border-radius:10px}
@media(max-width:800px){.plmenu{width:520px;height:85%}}
@media(min-width:1400px){.plmenu{zoom:110%}}
@media(min-width:1600px){.plmenu{zoom:118%}}
`))
/*
CHECKPOINT: Load
*/
setTimeout(()=>{
fetchSync(defaultCDN+"/@version",{bypass_cache:!0})("json")(async(d,p)=>{
if(typeof d=="object"){TurboLoader.serverData=d;d=d.version};
let outdated=TurboLoader.PublicVersion<d;
console.debug("[TurboLoader Debug] Version check took about "+((p)||0)+"ms, server version: "+((d)||"(error)")+", local: "+TurboLoader.PublicVersion);
if(!TurboLoader.serverData?.forcedUpdate){if(!isPackager){TurboWarp()}else{TurboWarpPackager()}}
if(outdated&&!TurboLoader.serverData?.forcedUpdate){
modal({title:"New update found",content:"A new version of TurboLoader is available!\nDo you wish to update now?",onclose:b=>{
if(b==0){open("https://greatest.deepsurf.us/cs/scripts/437432-plugin-loader-ui")}
}})
}else if(TurboLoader.serverData?.forcedUpdate){
modal({title:"Important update found",cancelable:false,content:"A critical update for TurboLoader has been found.\nTo continue using it, please update.\n(This update does some important changes and thus isn't optional, because without it the functionality may be affected or there may be a security risk.)",buttons:[{text:"OK"}],onclose:b=>{
open("https://greatest.deepsurf.us/cs/scripts/437432-plugin-loader-ui")
}})
}
})
},300)