\n
\n
\n
Windows 11 WebOS
\n
\n\n\n\n\n
\n
\n
\n
Recycle Bin
\n
\n
\n
\n
Files
\n
\n
\n
\n
Browser
\n
\n
\n\n
\n
\n\n\x3C!-- Context Menu -->\n
\n
↻ Refresh
\n
\n
📁 New Folder
\n
📋 Paste
\n
\n
🖥 Display settings
\n
🎨 Personalize
\n
\n\n\x3C!-- Weather Panel -->\n
\n
Round Rock, United States
\n
\n
\n
\n
76°F
\n
Sunny
\n
\n
\n
Feels like
76°F
\n
Humidity
38%
\n
Wind
10 mph
\n
\n\n\x3C!-- Quick Settings Panel -->\n
\n
\n
\n
\n
Wi-Fi
\n
High · 46ms
\n
\n
\n
\n
Bluetooth
\n
Not connected
\n
\n
\n
\n
Airplane
\n
Off
\n
\n
\n
\n
Focus assist
\n
Off
\n
\n
\n
\n
Accessibility
\n
Off
\n
\n
\n\n \x3C!-- Brightness -->\n
\n
\n
\n
\n\n \x3C!-- Volume -->\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n \x3C!-- Battery -->\n
\n
\n
\n
\n
\n
\n
\n
100%
\n
\n
\n
\n\n\x3C!-- Calendar / Clock Panel -->\n
\n
2:46 PM
\n
Sunday, May 3, 2026
\n
\n
May 2026
\n
\n
\n
\n
\n
\n
\n
Su
Mo
Tu
\n
We
Th
Fr
Sa
\n
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
\n
\n\n\x3C!-- TASKBAR -->\n
\n
\n
\n
\n
76°F
\n
Sunny
\n
\n
\n
\n
\n
\n \x3C!-- WiFi tray -->\n
\n
\n
\n
\n \x3C!-- Volume tray -->\n
\n
\n
\n
\n
\n \x3C!-- Battery tray -->\n
\n
\n
\n
\n
\n
\n
\n
2:46 PM
\n
5/3/26
\n
\n
\n
\n\n\x3Cscript>\n// ============================================================\n// CLOCK\n// ============================================================\nfunction updateClock(){\n const n=new Date();\n const t=n.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"});\n document.getElementById("clock-time").textContent=t;\n document.getElementById("clock-date").textContent=n.toLocaleDateString([],{month:"numeric",day:"numeric",year:"2-digit"});\n document.getElementById("clock-popup-time").textContent=t;\n document.getElementById("clock-popup-date").textContent=n.toLocaleDateString([],{weekday:"long",month:"long",day:"numeric",year:"numeric"});\n}\nupdateClock(); setInterval(updateClock,1000);\n\n// ============================================================\n// CALENDAR\n// ============================================================\nlet calYear=new Date().getFullYear(), calMonth=new Date().getMonth();\nfunction renderCalendar(){\n const today=new Date();\n document.getElementById("cal-month-label").textContent=\n new Date(calYear,calMonth,1).toLocaleDateString([],{month:"long",year:"numeric"});\n const grid=document.getElementById("cal-grid");\n while(grid.children.length>7) grid.removeChild(grid.lastChild);\n const firstDay=new Date(calYear,calMonth,1).getDay();\n const dim=new Date(calYear,calMonth+1,0).getDate();\n const prevDim=new Date(calYear,calMonth,0).getDate();\n for(let i=firstDay-1;i>=0;i--){ const d=document.createElement("div"); d.className="cal-day other-month"; d.textContent=prevDim-i; grid.appendChild(d); }\n for(let d=1;d<=dim;d++){\n const el=document.createElement("div"); el.className="cal-day";\n if(d===today.getDate()&&calMonth===today.getMonth()&&calYear===today.getFullYear()) el.classList.add("today");\n el.textContent=d; grid.appendChild(el);\n }\n const total=firstDay+dim; const rem=(7-total%7)%7;\n for(let d=1;d<=rem;d++){ const el=document.createElement("div"); el.className="cal-day other-month"; el.textContent=d; grid.appendChild(el); }\n}\nfunction changeCalMonth(dir){ calMonth+=dir; if(calMonth>11){calMonth=0;calYear++;} if(calMonth<0){calMonth=11;calYear--;} renderCalendar(); }\nrenderCalendar();\n\n// ============================================================\n// POPUP SYSTEM\n// ============================================================\nconst popupIds=["weather-popup","quick-popup","clock-popup"];\nfunction closeAllPopups(){ popupIds.forEach(id=>{ const p=document.getElementById(id); p.classList.remove("visible"); p.style.display="none"; }); }\nfunction togglePopup(id){\n const pop=document.getElementById(id);\n const was=pop.classList.contains("visible");\n closeAllPopups();\n if(!was){ pop.style.display="block"; requestAnimationFrame(()=>pop.classList.add("visible")); }\n}\ndocument.addEventListener("click",(e)=>{\n if(!e.target.closest(".tray-popup")&&!e.target.closest("#quick-tray")&&!e.target.closest("#clock-btn")&&!e.target.closest("#taskbar-left")) closeAllPopups();\n});\n\n// ============================================================\n// WEATHER\n// ============================================================\nfunction getWeatherInfo(code,wind){\n if([95,96,99].includes(code)) return {icon:"https://img.icons8.com/?size=96&id=c0Otgmp74zQX&format=png",label:"Thunderstorm"};\n if([51,53,55,56,57,61,63,65,66,67,80,81,82].includes(code)) return {icon:"https://img.icons8.com/?size=96&id=R1kPtXvDMnWj&format=png",label:"Rainy"};\n if([71,73,75,77,85,86].includes(code)) return {icon:"https://img.icons8.com/?size=96&id=W8fUZZSmXssu&format=png",label:"Snow"};\n if([45,48].includes(code)) return {icon:"https://img.icons8.com/?size=96&id=W8fUZZSmXssu&format=png",label:"Foggy"};\n if(code===3) return {icon:"https://img.icons8.com/?size=96&id=W8fUZZSmXssu&format=png",label:"Cloudy"};\n if([1,2].includes(code)) return {icon:"https://img.icons8.com/?size=96&id=zIVmoh4T8wh7&format=png",label:"Partly Cloudy"};\n if(wind>25) return {icon:"https://img.icons8.com/?size=96&id=RtDA8YDN9Mi9&format=png",label:"Windy"};\n return {icon:"https://raw.githubusercontent.com/HaydenReeve/WindowsIcons/refs/heads/main/Icons/applications/weather.ico",label:"Sunny"};\n}\nasync function loadWeather(){\n try{\n const geo=await(await fetch("https://ipapi.co/json/")).json();\n const w=await(await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${geo.latitude}&longitude=${geo.longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,weather_code&temperature_unit=fahrenheit&wind_speed_unit=mph&timezone=auto`)).json();\n const c=w.current; const info=getWeatherInfo(c.weather_code,Math.round(c.wind_speed_10m));\n document.getElementById("weather-icon").src=info.icon;\n document.getElementById("weather-temp").textContent=`${Math.round(c.temperature_2m)}°F`;\n document.getElementById("weather-desc").textContent=info.label;\n document.getElementById("weather-popup-icon").src=info.icon;\n document.getElementById("popup-temp").textContent=`${Math.round(c.temperature_2m)}°F`;\n document.getElementById("popup-desc").textContent=info.label;\n document.getElementById("popup-feels").textContent=`${Math.round(c.apparent_temperature)}°F`;\n document.getElementById("popup-humidity").textContent=`${c.relative_humidity_2m}%`;\n document.getElementById("popup-wind").textContent=`${Math.round(c.wind_speed_10m)} mph`;\n document.getElementById("popup-location").textContent=`${geo.city||geo.region||""}, ${geo.country_name||""}`;\n }catch(e){ document.getElementById("weather-temp").textContent="72°F"; document.getElementById("weather-desc").textContent="Sunny"; }\n}\nloadWeather(); setInterval(loadWeather,600000);\n\n// ============================================================\n// WIFI\n// ============================================================\nasync function measurePing(){\n if(!navigator.onLine){ document.getElementById("qs-wifi-sub").textContent="Offline"; updateWifiTray(0); return; }\n const t0=performance.now();\n try{ await fetch(`https://www.gstatic.com/generate_204?_=${Date.now()}`,{mode:"no-cors",cache:"no-store"}); }catch(_){}\n const ms=Math.round(performance.now()-t0);\n let bars,label;\n if(ms<80){bars=4;label="High";}else if(ms<200){bars=3;label="Medium";}else if(ms<500){bars=2;label="Low";}else{bars=1;label="Poor";}\n document.getElementById("qs-wifi-sub").textContent=`${label} · ${ms}ms`;\n updateWifiTray(bars);\n}\nfunction updateWifiTray(bars){\n const paths=document.getElementById("tray-wifi-svg").querySelectorAll("path");\n const op=bars>=4?[1,1,1]:bars===3?[.2,1,1]:bars===2?[.2,.2,1]:[.2,.2,.2];\n paths.forEach((p,i)=>{ if(i<3) p.style.opacity=op[i]; });\n}\nfunction toggleQsTile(el){ el.classList.toggle("active"); }\nmeasurePing(); setInterval(measurePing,15000);\n\n// ============================================================\n// VOLUME — Web Audio GainNode (routes all page audio)\n// ============================================================\nlet audioCtx=null, gainNode=null;\nlet volValue=75, isMuted=false, prevVol=75;\n\nfunction ensureAudioCtx(){\n if(!audioCtx){\n audioCtx=new (window.AudioContext||window.webkitAudioContext)();\n gainNode=audioCtx.createGain();\n gainNode.connect(audioCtx.destination);\n gainNode.gain.value=volValue/100;\n }\n}\nfunction hookMedia(el){\n if(el._hooked) return; el._hooked=true;\n try{ ensureAudioCtx(); audioCtx.createMediaElementSource(el).connect(gainNode); }catch(_){}\n}\nnew MutationObserver(m=>m.forEach(r=>r.addedNodes.forEach(n=>{ if(n.tagName===\'AUDIO\'||n.tagName===\'VIDEO\') hookMedia(n); }))).observe(document.body,{childList:true,subtree:true});\ndocument.querySelectorAll("audio,video").forEach(hookMedia);\n\nconst volSlider=document.getElementById("vol-slider");\nfunction applyVolume(){\n const eff=isMuted?0:volValue;\n if(gainNode) gainNode.gain.value=eff/100;\n volSlider.value=isMuted?0:volValue;\n volSlider.style.background=`linear-gradient(to right,#0078d4 ${isMuted?0:volValue}%,#ccc ${isMuted?0:volValue}%)`;\n // Icon waves\n const w1=document.getElementById("tray-wave1"),w2=document.getElementById("tray-wave2");\n const q1=document.getElementById("qs-wave1"),q2=document.getElementById("qs-wave2");\n if(isMuted||eff===0){ [w1,w2,q1,q2].forEach(e=>e&&(e.style.display="none")); }\n else if(eff<40){ [w1,q1].forEach(e=>e&&(e.style.display="")); [w2,q2].forEach(e=>e&&(e.style.display="none")); }\n else { [w1,w2,q1,q2].forEach(e=>e&&(e.style.display="")); }\n}\nfunction toggleMute(){ if(isMuted){isMuted=false;volValue=prevVol||60;} else{prevVol=volValue;isMuted=true;} applyVolume(); }\nvolSlider.addEventListener("mousedown",()=>ensureAudioCtx());\nvolSlider.addEventListener("input",()=>{\n volValue=parseInt(volSlider.value);\n if(volValue>0) isMuted=false;\n applyVolume();\n});\n\n// Brightness slider style\nconst brightSlider=document.getElementById("bright-slider");\nfunction updateBrightTrack(){ brightSlider.style.background=`linear-gradient(to right,#0078d4 ${brightSlider.value}%,#ccc ${brightSlider.value}%)`; }\nbrightSlider.addEventListener("input",updateBrightTrack);\nupdateBrightTrack();\napplyVolume();\n\n// ============================================================\n// BATTERY\n// ============================================================\nasync function loadBattery(){\n try{\n if(!navigator.getBattery) throw new Error();\n const bat=await navigator.getBattery();\n function updateBat(){\n const pct=Math.round(bat.level*100);\n const color=pct<=20?"#e74c3c":pct<=50?"#f39c12":"#27ae60";\n const fillW=Math.max(1,Math.round(pct/100*10));\n // Quick panel\n document.getElementById("qs-bat-pct").textContent=`${pct}%`;\n document.getElementById("qs-bat-status").textContent=bat.charging?"":"";\n document.getElementById("qs-bat-bar").style.width=`${pct}%`;\n document.getElementById("qs-bat-bar").style.background=color;\n document.getElementById("qs-bat-rect").setAttribute("width",fillW);\n document.getElementById("qs-bat-rect").setAttribute("fill",color);\n // Tray\n document.getElementById("tray-bat-fill").setAttribute("width",fillW);\n document.getElementById("tray-bat-fill").setAttribute("fill",color);\n }\n updateBat();\n ["levelchange","chargingchange","chargingtimechange","dischargingtimechange"].forEach(ev=>bat.addEventListener(ev,updateBat));\n }catch(e){\n document.getElementById("qs-bat-pct").textContent="N/A";\n document.getElementById("qs-bat-bar").style.width="50%";\n document.getElementById("qs-bat-bar").style.background="#aaa";\n }\n}\nloadBattery();\n\n// ============================================================\n// TASKBAR CENTER\n// ============================================================\nconst LOCKED_COUNT=3;\nlet tbItems=[\n {id:"start",src:"https://cdn.jsdelivr.net/gh/HaydenReeve/WindowsIcons@main/Icons/applications/start.ico",locked:true},\n {id:"search",src:"https://cdn.jsdelivr.net/gh/HaydenReeve/WindowsIcons@main/Icons/applications/search.ico",locked:true},\n {id:"taskview",src:"https://cdn.jsdelivr.net/gh/HaydenReeve/WindowsIcons@main/Icons/applications/taskview.ico",locked:true},\n {id:"folder",src:"https://raw.githubusercontent.com/HaydenReeve/WindowsIcons/refs/heads/main/Icons/folders/filled.ico",locked:false},\n {id:"edge",src:"https://raw.githubusercontent.com/HaydenReeve/WindowsIcons/refs/heads/main/Icons/applications/edge.ico",locked:false},\n {id:"store",src:"https://cdn.jsdelivr.net/gh/HaydenReeve/WindowsIcons@main/Icons/applications/store.ico",locked:false},\n {id:"settings",src:"https://raw.githubusercontent.com/HaydenReeve/WindowsIcons/refs/heads/main/Icons/applications/settings.ico",locked:false},\n];\nconst ICON_STEP=46;\nconst tbCenter=document.getElementById("taskbar-center");\nconst ghost=document.getElementById("tb-ghost");\nconst ghostImg=ghost.querySelector("img");\nlet dragTb={active:false,srcIdx:-1,dropIdx:-1};\nfunction renderTaskbar(){\n tbCenter.innerHTML="";\n tbItems.forEach((item,i)=>{\n const btn=document.createElement("div"); btn.className="taskbar-icon"+(item.locked?" non-draggable":"");\n const img=document.createElement("img"); img.src=item.src; img.draggable=false; btn.appendChild(img);\n if(!item.locked) btn.addEventListener("mousedown",e=>{ if(e.button===0) onTbDown(e,i); });\n tbCenter.appendChild(btn);\n });\n}\nfunction getTbIcons(){ return Array.from(tbCenter.querySelectorAll(".taskbar-icon")); }\nfunction onTbDown(e,idx){ if(tbItems[idx].locked) return; e.preventDefault(); dragTb={active:true,srcIdx:idx,dropIdx:idx}; ghostImg.src=tbItems[idx].src; ghost.style.display="flex"; posGhost(e.clientX); getTbIcons()[idx].classList.add("is-source"); document.addEventListener("mousemove",onTbMove); document.addEventListener("mouseup",onTbUp); }\nfunction posGhost(mx){ const cR=tbCenter.getBoundingClientRect(); ghost.style.left=Math.max(cR.left,Math.min(mx-20,cR.right-40))+"px"; ghost.style.top=(window.innerHeight-48+4)+"px"; }\nfunction onTbMove(e){ if(!dragTb.active) return; posGhost(e.clientX); const cR=tbCenter.getBoundingClientRect(); let di=Math.round((e.clientX-cR.left)/ICON_STEP); di=Math.max(LOCKED_COUNT,Math.min(di,tbItems.length-1)); if(tbItems[di]?.locked) di=dragTb.srcIdx; dragTb.dropIdx=di; getTbIcons().forEach((el,i)=>{ if(i===dragTb.srcIdx||i
=di&&i
dragTb.srcIdx&&i>dragTb.srcIdx&&i<=di) s=-ICON_STEP; el.style.transform=s?`translateX(${s}px)`:""; el.style.transition="transform 0.13s"; }); }\nfunction onTbUp(){ if(!dragTb.active) return; dragTb.active=false; ghost.style.display="none"; const {srcIdx:s,dropIdx:d}=dragTb; getTbIcons().forEach(el=>{el.style.transform="";el.style.transition="";}); if(s!==d&&s>=LOCKED_COUNT&&d>=LOCKED_COUNT){ const [it]=tbItems.splice(s,1); tbItems.splice(d,0,it); } getTbIcons()[s]?.classList.remove("is-source"); document.removeEventListener("mousemove",onTbMove); document.removeEventListener("mouseup",onTbUp); renderTaskbar(); }\nrenderTaskbar();\n\n// ============================================================\n// DESKTOP ICONS — Grid-snap on drop + full collision prevention\n// ============================================================\nconst DESKTOP_ICON_W=80, DESKTOP_ICON_H=92, TASKBAR_H=48;\nconst GRID_COL=92, GRID_ROW=102;\n\nconst allIcons=()=>Array.from(document.querySelectorAll("#desktop .icon"));\nfunction iconRect(ic){ return {left:parseInt(ic.style.left)||0,top:parseInt(ic.style.top)||0,right:(parseInt(ic.style.left)||0)+DESKTOP_ICON_W,bottom:(parseInt(ic.style.top)||0)+DESKTOP_ICON_H}; }\nfunction rectsOverlap(a,b){ return !(a.right<=b.left||a.left>=b.right||a.bottom<=b.top||a.top>=b.bottom); }\nfunction snapToGrid(l,t){ return {left:Math.round(l/GRID_COL)*GRID_COL, top:Math.round(t/GRID_ROW)*GRID_ROW}; }\n\nfunction findFreeCell(prefL,prefT,checkSet){\n const maxX=window.innerWidth-DESKTOP_ICON_W, maxY=window.innerHeight-TASKBAR_H-DESKTOP_ICON_H;\n const sn=snapToGrid(prefL,prefT);\n let bl=Math.max(0,Math.min(sn.left,maxX)), bt=Math.max(0,Math.min(sn.top,maxY));\n const hits=(l,t)=>{ const r={left:l,top:t,right:l+DESKTOP_ICON_W,bottom:t+DESKTOP_ICON_H}; for(const o of checkSet) if(rectsOverlap(r,iconRect(o))) return true; return false; };\n if(!hits(bl,bt)) return {left:bl,top:bt};\n for(let rad=1;rad<80;rad++){\n for(let dx=-rad;dx<=rad;dx++){\n for(let dy=-rad;dy<=rad;dy++){\n if(Math.abs(dx)!==rad&&Math.abs(dy)!==rad) continue;\n const nl=Math.max(0,Math.min(bl+dx*GRID_COL,maxX)), nt=Math.max(0,Math.min(bt+dy*GRID_ROW,maxY));\n if(!hits(nl,nt)) return {left:nl,top:nt};\n }\n }\n }\n return {left:bl,top:bt};\n}\n\nlet selectedIcons=new Set(), selRectActive=false, rectStart={x:0,y:0};\nconst selDiv=document.getElementById("selection-rect");\nfunction updateSelVis(){ allIcons().forEach(ic=>ic.classList.toggle("selected",selectedIcons.has(ic))); }\nfunction clearSel(){ selectedIcons.clear(); updateSelVis(); }\n\ndocument.getElementById("desktop").addEventListener("mousedown",(e)=>{\n if(e.button!==0||e.target!==document.getElementById("desktop")) return;\n clearSel(); selRectActive=true; rectStart={x:e.clientX,y:e.clientY};\n Object.assign(selDiv.style,{display:"block",left:e.clientX+"px",top:e.clientY+"px",width:"0",height:"0"});\n});\ndocument.addEventListener("mousemove",(e)=>{\n if(!selRectActive) return;\n const l=Math.min(rectStart.x,e.clientX), t=Math.min(rectStart.y,e.clientY);\n const w=Math.abs(rectStart.x-e.clientX), h=Math.abs(rectStart.y-e.clientY);\n Object.assign(selDiv.style,{left:l+"px",top:t+"px",width:w+"px",height:h+"px"});\n const r={left:l,top:t,right:l+w,bottom:t+h};\n allIcons().forEach(ic=>{ const o=iconRect(ic); rectsOverlap(r,o)?selectedIcons.add(ic):selectedIcons.delete(ic); });\n updateSelVis();\n});\ndocument.addEventListener("mouseup",()=>{ if(selRectActive){ selRectActive=false; selDiv.style.display="none"; } });\n\n// Drag state\nlet dI={active:false,moving:[],starts:new Map(),ox:0,oy:0};\n\nfunction onIconDown(e){\n const ic=e.target.closest(".icon"); if(!ic||e.button!==0) return; e.preventDefault();\n if(!e.ctrlKey&&!selectedIcons.has(ic)){ clearSel(); selectedIcons.add(ic); updateSelVis(); }\n dI.active=true; dI.moving=Array.from(selectedIcons); dI.starts.clear();\n dI.moving.forEach(i=>dI.starts.set(i,{left:parseInt(i.style.left)||0,top:parseInt(i.style.top)||0}));\n dI.ox=e.clientX-(parseInt(ic.style.left)||0); dI.oy=e.clientY-(parseInt(ic.style.top)||0);\n document.addEventListener("mousemove",onIconMove); document.addEventListener("mouseup",onIconUp);\n}\nfunction onIconMove(e){\n if(!dI.active) return;\n const maxX=window.innerWidth-DESKTOP_ICON_W, maxY=window.innerHeight-TASKBAR_H-DESKTOP_ICON_H;\n const o0=dI.starts.get(dI.moving[0]);\n const dx=e.clientX-dI.ox-o0.left, dy=e.clientY-dI.oy-o0.top;\n // Free visual movement during drag\n for(const ic of dI.moving){\n const o=dI.starts.get(ic);\n ic.style.left=Math.max(0,Math.min(o.left+dx,maxX))+"px";\n ic.style.top=Math.max(0,Math.min(o.top+dy,maxY))+"px";\n }\n}\nfunction onIconUp(){\n if(!dI.active) return; dI.active=false;\n document.removeEventListener("mousemove",onIconMove); document.removeEventListener("mouseup",onIconUp);\n const maxX=window.innerWidth-DESKTOP_ICON_W, maxY=window.innerHeight-TASKBAR_H-DESKTOP_ICON_H;\n const movingSet=new Set(dI.moving);\n const committed=new Set();\n // Non-moved icons are always obstacles\n const staticIcons=allIcons().filter(i=>!movingSet.has(i));\n\n for(const ic of dI.moving){\n // Obstacles = static icons + already-placed moved icons\n const checkSet=new Set([...staticIcons,...committed]);\n const curL=parseInt(ic.style.left)||0, curT=parseInt(ic.style.top)||0;\n const cell=findFreeCell(curL,curT,checkSet);\n ic.style.left=Math.max(0,Math.min(cell.left,maxX))+"px";\n ic.style.top=Math.max(0,Math.min(cell.top,maxY))+"px";\n committed.add(ic);\n }\n}\n\nfunction attachIconEvents(){\n allIcons().forEach(ic=>{ ic.removeEventListener("mousedown",onIconDown); ic.addEventListener("mousedown",onIconDown); });\n}\nattachIconEvents();\nnew MutationObserver(attachIconEvents).observe(document.getElementById("desktop"),{childList:true});\n\n// Snap initial icon positions to grid (no overlaps)\n(function initSnap(){\n const icons=allIcons(); const placed=new Set();\n const maxX=window.innerWidth-DESKTOP_ICON_W, maxY=window.innerHeight-TASKBAR_H-DESKTOP_ICON_H;\n for(const ic of icons){\n const cell=findFreeCell(parseInt(ic.style.left)||0,parseInt(ic.style.top)||0,placed);\n ic.style.left=Math.max(0,Math.min(cell.left,maxX))+"px";\n ic.style.top=Math.max(0,Math.min(cell.top,maxY))+"px";\n placed.add(ic);\n }\n})();\n\n// ============================================================\n// CONTEXT MENU\n// ============================================================\nconst ctxMenu=document.getElementById("context-menu");\nfunction hideCtx(){ ctxMenu.style.display="none"; }\ndocument.addEventListener("contextmenu",(e)=>{\n e.preventDefault();\n const ic=e.target.closest(".icon");\n if(ic){ if(!selectedIcons.has(ic)){ clearSel(); selectedIcons.add(ic); updateSelVis(); } }\n else clearSel();\n let x=e.clientX, y=e.clientY;\n if(x+210>window.innerWidth) x=window.innerWidth-215;\n if(y+220>window.innerHeight-TASKBAR_H) y=e.clientY-225;\n ctxMenu.style.left=x+"px"; ctxMenu.style.top=y+"px"; ctxMenu.style.display="block";\n setTimeout(()=>document.addEventListener("click",hideCtx,{once:true}),0);\n});\ndocument.querySelectorAll(".ctx-item").forEach(item=>{\n item.addEventListener("click",()=>{\n const a=item.dataset.action;\n if(a==="refresh") alert("Refreshed"); if(a==="newfolder") alert("New Folder");\n if(a==="paste") alert("Paste"); if(a==="display") alert("Display settings");\n if(a==="personalize") alert("Personalize");\n hideCtx();\n });\n});\ndocument.body.addEventListener("click",hideCtx);\nwindow.addEventListener("resize",hideCtx);\n\x3C/script>\n\x3Cscript defer="" src="https://static.cloudflareinsights.com/beacon.min.js/v8c78df7c7c0f484497ecbca7046644da1771523124516" integrity="sha512-8DS7rgIrAmghBFwoOTujcf6D9rXvH8xm8JQ1Ja01h9QX8EzXldiszufYa4IFfKdLUKTTrnSFXLDkUEOTrZQ8Qg==" data-cf-beacon="{"version":"2024.11.0","token":"94c79d4d951745d085049dd7f2bbd8f8","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}" crossorigin="anonymous">\x3C/script>\n\n\n\n\x3Cscript defer="" data-domain="html.cafe" src="https://milkymouse.com/js/script.js">\x3C/script>\n\n