.wrap{position:relative;width:100%;height:100%}
#cv{position:absolute;inset:0;width:100%;height:100%}
.panel{position:absolute;left:10px;right:10px;bottom:10px;z-index:2;padding:8px 10px;border-radius:10px;
background:rgba(13,13,18,0.55);backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,0.15)}
.row{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:#f1f0ec}
.bar{margin-top:5px;height:5px;border-radius:99px;background:rgba(255,255,255,0.15);overflow:hidden}
.fill{height:100%;width:5%;background:var(--accent);transition:width .08s linear}
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const val = document.getElementById('val'), fill = document.getElementById('fill');
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); }
addEventListener('resize', fit); fit();
function mulberry32(a) { return function () { a |= 0; a = a + 0x6D2B79F5 | 0; let t = Math.imul(a ^ a >>> 15, 1 | a); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }
function render(cfg) {
const w = innerWidth, h = innerHeight;
ctx.clearRect(0, 0, w, h);
ctx.setLineDash([5, 5]); ctx.strokeStyle = 'rgba(255,255,255,0.3)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(w * 0.5, h * 0.55, Math.min(w, h) * 0.22, 0, Math.PI * 2); ctx.stroke();
ctx.setLineDash([]);
const t = cfg / 20, r = mulberry32(7)();
const wob = 1 - t;
const px = w * 0.5 + (r - 0.5) * w * 0.34 * wob, py = h * 0.55 + (r - 0.5) * h * 0.34 * wob;
const rad = Math.min(w, h) * 0.22 * (0.65 + t * 0.35);
ctx.beginPath();
if (cfg > 16) {
const n = 14;
for (let i = 0; i <= n; i++) { const a = i / n * Math.PI * 2; const rr = rad * (i % 2 ? 1.3 : 1); const x = px + Math.cos(a) * rr, y = py + Math.sin(a) * rr; i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); }
} else {
ctx.arc(px, py, rad, 0, Math.PI * 2);
}
ctx.closePath();
ctx.fillStyle = 'hsl(265 ' + (25 + t * 60) + '% ' + (45 + t * 18) + '%)';
ctx.fill();
}
let cfg = 1, dir = 1;
setInterval(() => {
render(cfg); val.textContent = cfg.toFixed(0); fill.style.width = (cfg / 20 * 100) + '%';
cfg += dir * 0.35;
if (cfg >= 20) { cfg = 20; dir = -1; } if (cfg <= 1) { cfg = 1; dir = 1; }
}, 90);
render(1);