<div class="viz">
<div class="tile">
<div class="lbl">주간 방문자</div>
<div class="row">
<div class="num" id="num">1,284</div>
<div class="delta" id="delta">▲ 4.2%</div>
</div>
</div>
<svg id="svg"></svg>
</div>
body{display:block}
.viz{display:grid;grid-template-rows:auto 1fr;width:100%;height:100%;padding:10px 12px;box-sizing:border-box;gap:2px}
.lbl{font:600 10px/1 system-ui,sans-serif;color:var(--muted)}
.row{display:flex;align-items:baseline;gap:8px}
.num{font:700 20px/1 system-ui,sans-serif;color:var(--fg)}
.delta{font:700 11px/1 system-ui,sans-serif}
.delta.up{color:var(--accent-3)}
.delta.down{color:var(--accent-2)}
svg{display:block;width:100%;height:100%;overflow:visible}
.ln{fill:none;stroke:var(--muted);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;opacity:.55}
.dot{fill:var(--accent)}
var svg = document.getElementById('svg');
var numEl = document.getElementById('num');
var deltaEl = document.getElementById('delta');
var NS = 'http://www.w3.org/2000/svg';
function se(t){ return document.createElementNS(NS,t); }
function sa(e,o){ for (var k in o) e.setAttribute(k,o[k]); }
function R(a,b){ return a + Math.random()*(b-a); }
var N = 14;
var series = [];
var v = 50;
for (var i=0;i<N;i++){ v = Math.max(15,Math.min(90, v+R(-14,14))); series.push(v); }
var cur = series.slice();
var W=300, H=200;
function measure(){
var r = svg.getBoundingClientRect();
W = Math.max(r.width,10); H = Math.max(r.height,10);
sa(svg,{ viewBox: '0 0 ' + W + ' ' + H });
}
function draw(){
svg.innerHTML = '';
var padX=4, padY=8;
var pw=W-padX*2, ph=H-padY*2;
var pts = cur.map(function(val,i){ return { x: padX+(pw*i)/(N-1), y: padY+ph-(val/100)*ph }; });
var d = pts.map(function(p,i){ return (i===0?'M':'L')+p.x.toFixed(1)+','+p.y.toFixed(1); }).join(' ');
var path = se('path');
sa(path,{d:d,class:'ln'});
svg.appendChild(path);
var last = pts[pts.length-1];
var dot = se('circle');
sa(dot,{cx:last.x,cy:last.y,r:3,class:'dot'});
svg.appendChild(dot);
}
function updateFacts(){
var val = cur[cur.length-1];
var prev = cur[cur.length-2];
numEl.textContent = Math.round(val*14).toLocaleString();
var pct = ((val-prev)/prev*100);
var up = pct >= 0;
deltaEl.textContent = (up?'▲ ':'▼ ') + Math.abs(pct).toFixed(1) + '%';
deltaEl.className = 'delta ' + (up?'up':'down');
}
function animate(){
var from = cur.slice();
var t0 = performance.now();
function step(t){
var p = Math.min(1,(t-t0)/700);
var e = 1-Math.pow(1-p,3);
cur = from.map(function(vv,i){ return vv+(series[i]-vv)*e; });
draw();
if (p<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
new ResizeObserver(function(){ measure(); draw(); }).observe(svg);
measure();
draw();
updateFacts();
setInterval(function(){
series.shift();
var last = series[series.length-1];
series.push(Math.max(12,Math.min(92, last+R(-16,16))));
cur = [series[0]].concat(cur.slice(1));
animate();
updateFacts();
}, 2600);