.wrap{position:relative;width:100%;height:100%}
#cv{position:absolute;inset:0;width:100%;height:100%}
.plane{position:absolute;right:10px;bottom:10px;width:96px;height:96px;border:1px solid rgba(255,255,255,0.35);
border-radius:8px;background:rgba(255,255,255,0.06);z-index:2}
.corner{position:absolute;font-size:8.5px;color:rgba(255,255,255,0.8);font-weight:700}
.tl{top:3px;left:4px}
.tr{top:3px;right:4px}
.bl{bottom:3px;left:4px}
.br{bottom:3px;right:4px}
.dot{position:absolute;width:8px;height:8px;border-radius:50%;background:#fff;box-shadow:0 0 8px 2px rgba(255,255,255,0.7);
transform:translate(-50%,-50%);transition:left 1.6s ease,top 1.6s ease}
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const dot = document.getElementById('dot');
function fit() { const dpr = Math.min(devicePixelRatio || 1, 2); cv.width = innerWidth * dpr; cv.height = innerHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); render(currentHue()); }
addEventListener('resize', fit);
const corners = [{ u: 0, v: 0, hue: 20 }, { u: 1, v: 0, hue: 200 }, { u: 0, v: 1, hue: 140 }, { u: 1, v: 1, hue: 35 }];
const waypoints = [[0.08, 0.08], [0.92, 0.08], [0.92, 0.92], [0.08, 0.92]];
let wi = 0, u = 0.08, v = 0.08;
function hueAt(uu, vv) {
const a = (1 - uu) * (1 - vv), b = uu * (1 - vv), c = (1 - uu) * vv, d = uu * vv;
return corners[0].hue * a + corners[1].hue * b + corners[2].hue * c + corners[3].hue * d;
}
function currentHue() { return hueAt(u, v); }
function paintScene(w, h, hue) {
const g = ctx.createLinearGradient(0, 0, 0, h);
g.addColorStop(0, 'hsl(' + hue + ' 55% 60%)'); g.addColorStop(1, 'hsl(' + ((hue + 40) % 360) + ' 45% 28%)');
ctx.fillStyle = g; ctx.fillRect(0, 0, w, h);
ctx.beginPath(); ctx.moveTo(0, h);
for (let i = 0; i <= 7; i++) { const x = w * i / 7; const y = h * 0.6 + Math.sin(i * 1.4 + hue * 0.05) * h * 0.08; ctx.lineTo(x, y); }
ctx.lineTo(w, h); ctx.closePath();
ctx.fillStyle = 'hsl(' + hue + ' 40% 20%)'; ctx.fill();
}
function render(hue) { paintScene(innerWidth, innerHeight, hue); }
function moveTo() {
[u, v] = waypoints[wi];
dot.style.left = (u * 100) + '%'; dot.style.top = (v * 100) + '%';
render(hueAt(u, v));
wi = (wi + 1) % waypoints.length;
setTimeout(moveTo, 1900);
}
fit();
moveTo();