/* Research Labs charts: dependency-free SVG line charts.
Rules applied: single axis, 2px lines, recessive grid, legend for >=2 series,
crosshair + tooltip, text in ink tokens, fixed series colours. */
const SERIES=['#3987e5','#d95926','#199e70','#c98500','#d55181','#008300','#9085e9','#e66767'];
const tip=(()=>{const d=document.createElement('div');d.className='tip';document.body.appendChild(d);return d;})();
function drawChart(el){
const cfg=JSON.parse(el.dataset.chart); // {series:[{label,slot,data:[[ts,v],...]}], unit, normalize}
const W=el.clientWidth||800, H=el.clientHeight||220, P={l:46,r:12,t:10,b:22};
const all=cfg.series.flatMap(s=>s.data);
if(!all.length){el.innerHTML='
No data in range.
';return;}
const ts=all.map(d=>+new Date(d[0].replace(' ','T')+':00Z'));
const t0=Math.min(...ts), t1=Math.max(...ts);
const norm=cfg.normalize&&cfg.series.length>1;
const yFor=s=>{const vs=s.data.map(d=>d[1]);const mn=Math.min(...vs),mx=Math.max(...vs);return v=> norm? (mx===mn?50:(v-mn)/(mx-mn)*100) : v;};
let vmin=Infinity,vmax=-Infinity;
cfg.series.forEach(s=>{const f=yFor(s);s.data.forEach(d=>{const v=f(d[1]);if(vvmax)vmax=v;});});
if(vmin===vmax){vmin-=1;vmax+=1;}
const X=t=>P.l+( (t-t0)/(t1-t0||1) )*(W-P.l-P.r);
const Y=v=>H-P.b-((v-vmin)/(vmax-vmin))*(H-P.t-P.b);
let g='';
const steps=4;
for(let i=0;i<=steps;i++){const v=vmin+(vmax-vmin)*i/steps,y=Y(v);
g+=``;
g+=`${norm?Math.round(v)+'%':fmt(v)}`;}
const days=(t1-t0)/86400000;
const nlab=Math.min(6,Math.max(2,Math.round(days/10)+2));
for(let i=0;i${new Date(t).toISOString().slice(5,10)}`;}
cfg.series.forEach((s,si)=>{
const f=yFor(s); const col=SERIES[(s.slot??si)%SERIES.length];
const pts=s.data.map(d=>`${X(+new Date(d[0].replace(' ','T')+':00Z')).toFixed(1)},${Y(f(d[1])).toFixed(1)}`).join(' ');
g+=``;
});
g+=``;
el.innerHTML=``;
if(cfg.series.length>1){
el.insertAdjacentHTML('afterend',''+cfg.series.map((s,si)=>`${s.label}${norm?' (indexed)':''}`).join('')+'
');
}
el.onmousemove=e=>{
const r=el.getBoundingClientRect(), fx=e.clientX-r.left;
const t=t0+((fx-P.l)/(W-P.l-P.r))*(t1-t0);
let rows='';
cfg.series.forEach((s,si)=>{
let best=null,bd=1e18;
s.data.forEach(d=>{const dt=Math.abs(+new Date(d[0].replace(' ','T')+':00Z')-t);if(dt${s.label}: ${fmt(best[1])}${cfg.unit?' '+cfg.unit:''} ${best[0]}`;
});
tip.innerHTML=rows; tip.style.display='block';
tip.style.left=Math.min(e.clientX+14,innerWidth-260)+'px'; tip.style.top=(e.clientY+12)+'px';
};
el.onmouseleave=()=>tip.style.display='none';
}
function fmt(v){return Math.abs(v)>=100?v.toFixed(0):Math.abs(v)>=10?v.toFixed(1):v.toFixed(2);}
function spark(el){
const d=JSON.parse(el.dataset.spark); if(!d.length){el.textContent='';return;}
const W=el.clientWidth||140,H=26,vs=d.map(x=>x[1]),mn=Math.min(...vs),mx=Math.max(...vs);
const pts=d.map((x,i)=>`${(i/(d.length-1))*(W-2)+1},${H-2-((x[1]-mn)/(mx-mn||1))*(H-4)}`).join(' ');
el.innerHTML=``;
}
addEventListener('DOMContentLoaded',()=>{
document.querySelectorAll('[data-chart]').forEach(drawChart);
document.querySelectorAll('[data-spark]').forEach(spark);
});