File size: 24,617 Bytes
9a06ef9
 
027d464
9a06ef9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
'use strict';
(() => {
  const DATA = JSON.parse(document.getElementById('leaderboard-data').textContent);
  const CITATIONS = JSON.parse(document.getElementById('citation-data').textContent);
  const $ = (selector) => document.querySelector(selector);
  const $$ = (selector) => [...document.querySelectorAll(selector)];
  const esc = (value) => String(value ?? '').replace(/[&<>"']/g, (ch) => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[ch]));
  const groupLabels = {closed:'Closed-source',open:'Open-source',agentic:'Agentic'};
  const colors = ['#3283bf','#2d9a86','#9b75bd'];
  const params = new URLSearchParams(location.search);
  const initialBenchmark = DATA.benchmarks.find(b => b.id === params.get('benchmark')) || DATA.benchmarks[0];
  const state = {benchmark:initialBenchmark.id,language:params.get('language')==='zh'?'zh':'en',view:'accuracy',dimension:'temporal',subcategory:'all',sort:'total',direction:'desc',group:'all',input:'all',query:'',selected:[],visible:[]};
  let toastTimer;
  const benchmarkMetadata = () => DATA.benchmarks.find(b => b.id === state.benchmark);
  const languageCode = () => benchmarkMetadata().results_by_language[state.language] ? state.language : 'en';
  const benchmark = () => ({...benchmarkMetadata(), ...benchmarkMetadata().results_by_language[languageCode()]});
  const resultLanguageLabel = () => state.benchmark==='risebench-plusplus' ? benchmark().language : 'Original';
  const modelById = id => benchmark().models.find(m => m.id === id);
  const score = (model, key = state.sort) => model[state.view]?.[key] ?? null;
  const fmt = value => value == null ? '—' : value.toFixed(1);
  const summaryKeys = ['total','single','multi'];
  const orderedAccuracyColumns = () => {
    const columns=benchmark().accuracy_columns;
    return benchmark().id==='risebench-plusplus'
      ? [...columns.filter(c=>!summaryKeys.includes(c.key)), ...summaryKeys.map(key=>columns.find(c=>c.key===key))]
      : [columns.find(c=>c.key==='total'), ...columns.filter(c=>c.key!=='total')];
  };
  const isBreakdown = () => ['subcategories','task_types'].includes(state.view);
  const viewLabel = () => ({accuracy:'Reasoning accuracy',metrics:'Evaluation scores',subcategories:'Subcategory accuracy',task_types:'Task-type accuracy'}[state.view]);
  const availableColumns = () => {
    const b=benchmark();
    if(state.view==='accuracy')return orderedAccuracyColumns();
    if(state.view==='metrics')return b.metrics;
    return b[state.view==='subcategories'?'subcategory_columns':'task_type_columns'].filter(c=>(state.dimension==='all'||c.dimension===state.dimension)&&(state.view!=='task_types'||state.subcategory==='all'||c.subcategory===state.subcategory));
  };
  const qualifiedLabel = c => isBreakdown()?`${c.dimension[0].toUpperCase()+c.dimension.slice(1)} · ${c.label}`:c.label;
  const scoreLabel = key => availableColumns().find(c=>c.key===key)?.label || key;
  const isPlus = () => state.benchmark === 'risebench-plusplus';
  function toast(message) {
    clearTimeout(toastTimer); $('#toast').textContent = message; $('#toast').hidden = false;
    toastTimer = setTimeout(() => {$('#toast').hidden = true;}, 3000);
  }
  function saveState() {
    try {
      const url = new URL(location.href); url.searchParams.set('benchmark',state.benchmark); url.searchParams.set('language',languageCode());
      history.replaceState(null,'',url);
    } catch (_) { /* Local file previews still work without history updates. */ }
  }
  function filteredModels() {
    const q = state.query.trim().toLowerCase();
    return benchmark().models.filter(m => (!q || m.name.toLowerCase().includes(q)) && (state.group==='all'||m.group===state.group) && (state.input==='all'||m.multi_image===(state.input==='multi'))).sort((a,b) => {
      const av=score(a), bv=score(b);
      if(av===null&&bv===null)return a.source_order-b.source_order;
      if(av===null)return 1;
      if(bv===null)return -1;
      return (state.direction==='desc'?bv-av:av-bv)||a.source_order-b.source_order;
    });
  }
  function rankOf(model) {
    const value = score(model); if(value===null)return null;
    return 1+benchmark().models.filter(m=>score(m)!==null&&score(m)>value).length;
  }
  function renderResources() {
    const b=benchmark();
    $('#hero-links').innerHTML=[['Paper','paper'],['Dataset','data'],['Outputs','outputs'],['Code','github']].map(([label,key])=>`<a href="${esc(b.links[key])}" target="_blank" rel="noopener noreferrer">${label} <span aria-hidden="true">↗</span></a>`).join('');
    $('#board-options').hidden=b.available_result_languages.length<2;
    $$('[data-language]').forEach(button=>button.setAttribute('aria-pressed',button.dataset.language===languageCode()));
    $('#group-filters').innerHTML=isPlus()?['all','closed','open','agentic'].map(g=>`<button data-group="${g}" aria-pressed="${state.group===g}">${g==='all'?'All models':groupLabels[g]}<span>${g==='all'?b.models.length:b.models.filter(m=>m.group===g).length}</span></button>`).join(''):'<span class="caption-text">All models</span>';
    $('.input-filter').hidden=!isPlus();
    $$('[data-plus-only]').forEach(el=>el.hidden=!isPlus());
    $('#page-citation-code').textContent=CITATIONS[state.benchmark];
    $('#citation-benchmark').textContent=b.name;
    $('#page-copy-citation').textContent='Copy BibTeX';
    renderBreakdownControls();
    renderColumns();
  }
  function renderBreakdownControls() {
    $('#breakdown-controls').hidden=!isBreakdown();
    if(!isBreakdown())return;
    const b=benchmark(), dimensions=b.dimensions.filter(d=>b.subcategory_columns.some(c=>c.dimension===d.key));
    $('#dimension-tabs').innerHTML=[{key:'all',label:'All dimensions'},...dimensions].map(d=>`<button data-dimension="${d.key}" aria-pressed="${state.dimension===d.key}">${esc(d.label)}</button>`).join('');
    $('#subcategory-filter').hidden=state.view!=='task_types';
    const subs=b.subcategory_columns.filter(c=>state.dimension==='all'||c.dimension===state.dimension);
    $('#subcategory-select').innerHTML='<option value="all">All subcategories</option>'+subs.map(c=>`<option value="${c.key}">${esc((state.dimension==='all'?c.dimension[0].toUpperCase()+c.dimension.slice(1)+' · ':'')+c.label)}</option>`).join('');
    $('#subcategory-select').value=state.subcategory;
  }
  function resetScoreColumns() {
    state.visible=availableColumns().map(c=>c.key);state.sort=state.visible[0];state.direction='desc';
    renderBreakdownControls();renderColumns();renderTable();$('.table-scroll').scrollLeft=0;
  }
  function renderColumns() {
    $('#column-options').innerHTML='<div class="eyebrow muted" >VISIBLE SCORE COLUMNS</div>'+availableColumns().map(c=>`<label><input type="checkbox" data-column="${c.key}" ${state.visible.includes(c.key)?'checked':''}>${esc(qualifiedLabel(c))}</label>`).join('');
  }
  function renderTable() {
    const b=benchmark(), models=filteredModels(), columns=availableColumns().filter(c=>state.visible.includes(c.key));
    const minimumWidth=370+(isPlus()?86:0)+columns.length*(isBreakdown()?156:96);
    $('#results-table').style.minWidth=minimumWidth+'px';
    $('#results-table').classList.toggle('breakdown-table',isBreakdown());
    $('#table-caption').textContent=b.name+' '+resultLanguageLabel()+' results, '+viewLabel()+(state.view==='metrics'?' (/100)':' (%)')+', sorted by '+scoreLabel(state.sort)+' '+state.direction;
    const summaryClass=key=>isPlus()&&summaryKeys.includes(key)?'summary-result':'';
    const sortableHeader=c=>`<th scope="col" class="${summaryClass(c.key)} ${state.sort===c.key?'active-sort':''}" aria-sort="${state.sort===c.key?(state.direction==='desc'?'descending':'ascending'):'none'}"><button data-sort="${c.key}" title="${esc(c.description)} — sort ${state.sort===c.key&&state.direction==='desc'?'ascending':'descending'}"><span>${c.key==='counterfactual'?'Counter-<br>factual':c.key==='instruction_reasoning'?'Instruction<br>Reasoning':c.key==='appearance_consistency'?'Appearance<br>Consistency':c.key==='visual_plausibility'?'Visual<br>Plausibility':esc(c.label)}</span><span class="sort-icon" aria-hidden="true">${state.sort===c.key?(state.direction==='desc'?'↓':'↑'):'↕'}</span></button></th>`;
    const rowSpan=isBreakdown()?' rowspan="2"':'';
    const modelHeaders=`<th scope="col" class="select-cell"${rowSpan}><span class="sr-only">Compare</span></th><th scope="col" class="rank-cell"${rowSpan} title="Global rank on the currently sorted score">#</th><th scope="col" class="model-cell"${rowSpan}>Model <span class="muted" style="font-weight:400">/ method</span></th>${isPlus()?`<th scope="col" style="width:86px"${rowSpan}>Input</th>`:''}`;
    const groups=[];
    if(isBreakdown())columns.forEach(c=>{
      const dimension=c.dimension[0].toUpperCase()+c.dimension.slice(1);
      const label=state.view==='task_types'?(state.dimension==='all'?dimension+' · ':'')+b.subcategory_columns.find(s=>s.key===c.subcategory).label:dimension;
      const key=state.view==='task_types'?c.subcategory:c.dimension;
      if(groups.at(-1)?.key===key)groups.at(-1).count++;else groups.push({key,label,count:1,dimension:c.dimension});
    });
    $('#table-head').innerHTML=isBreakdown()?`<tr>${modelHeaders}${groups.map(g=>`<th scope="colgroup" colspan="${g.count}" class="dimension-band dim-${g.dimension}">${esc(g.label)}</th>`).join('')}</tr><tr>${columns.map(sortableHeader).join('')}</tr>`:`<tr>${modelHeaders}${columns.map(sortableHeader).join('')}</tr>`;
    $('#table-body').innerHTML=models.map(m=>{
      const rank=rankOf(m), ours=m.id==='rise-agent-ours';
      const cells=columns.map(c=>{const v=score(m,c.key), featured=isPlus()&&summaryKeys.includes(c.key), tint=v==null?0:(featured ? .065+(v/100)*.10 : .02+(v/100)*.055);return `<td class="score-cell ${summaryClass(c.key)} ${c.key==='total'?'overall':''} ${v===null?'missing':''}" style="background-color:rgba(88,118,158,${tint.toFixed(4)})" title="${esc(c.label)}: ${v===null?'Not evaluated':fmt(v)+(state.view==='metrics'?' / 100':'%')}">${fmt(v)}${c.key==='total'&&v!==null?`<span class="score-meter" aria-hidden="true"><i style="width:${v}%"></i></span>`:''}</td>`;}).join('');
      return `<tr class="${ours?'ours ':''}${state.selected.includes(m.id)?'selected':''}"><td class="select-cell"><input type="checkbox" data-select="${esc(m.id)}" aria-label="Compare ${esc(m.name)}" ${state.selected.includes(m.id)?'checked':''}></td><td class="rank-cell">${rank===null?'—':`<span class="${rank<=3?'rank-top rank-'+rank:''}">${rank}</span>`}</td><th scope="row" class="model-cell" style="position:sticky;top:auto"><button class="model-button" data-model="${esc(m.id)}">${esc(m.name)}</button><span class="model-meta">${m.group?`<span class="group-dot ${m.group}"></span>${groupLabels[m.group]}`:''}${ours?'<span class="ours-badge">OURS</span>':''}</span></th>${isPlus()?`<td><span class="input-pill ${m.multi_image?'multi':''}" title="${m.multi_image?'Supports multiple input images':'Single-image only'}">${m.multi_image?'Multi':'Single'}</span></td>`:''}${cells}</tr>`;
    }).join('');
    $('#empty-state').hidden=models.length>0; $('#results-table').hidden=models.length===0;
    $('#result-count').innerHTML=`<strong>${models.length}</strong>${models.length<b.models.length?' / '+b.models.length:''} models`;
    if(isBreakdown())$('#result-count').innerHTML+=`<span class="context-separator">·</span>${columns.length} ${state.view==='subcategories'?'subcategories':'task types'}`;
    $('#reset-filters').hidden=!(state.query||state.group!=='all'||state.input!=='all');
    $$('#group-filters button').forEach(el=>el.setAttribute('aria-pressed',el.dataset.group===state.group));
    renderTray();
  }
  function renderTray() {
    $('#compare-tray').hidden=state.selected.length===0;
    $('#compare-count').textContent=state.selected.length+' / 3 models selected';
    $('#compare-chips').innerHTML=state.selected.map(id=>`<span class="compare-chip">${esc(modelById(id).name)}<button data-remove="${esc(id)}" aria-label="Remove ${esc(modelById(id).name)} from comparison">×</button></span>`).join('');
    $('#compare-open').disabled=state.selected.length<2;
    updateTraySpacing();
  }
  function updateTraySpacing() {
    document.body.style.paddingBottom=state.selected.length?($('#compare-tray').offsetHeight+48)+'px':'';
  }
  if ('ResizeObserver' in window) new ResizeObserver(updateTraySpacing).observe($('#compare-tray'));
  window.addEventListener('resize',updateTraySpacing);
  function toggleSelected(id,checked) {
    if(checked&&state.selected.length>=3){toast('Compare up to 3 models at a time. Remove one to add another.');renderTable();return;}
    state.selected=checked?[...state.selected,id]:state.selected.filter(x=>x!==id);renderTable();
  }
  function resetFilters() {
    state.query='';state.group='all';state.input='all';
    $('#model-search').value='';$('#input-filter').value='all';renderTable();
  }
  function switchBenchmark(id) {
    state.benchmark=id;state.selected=[];state.group='all';state.input='all';state.view='accuracy';state.sort='total';state.direction='desc';
    state.query='';$('#model-search').value='';$('#input-filter').value='all';
    state.visible=availableColumns().map(c=>c.key);
    $$('[data-benchmark]').forEach(btn=>btn.setAttribute('aria-pressed',btn.dataset.benchmark===id));
    $$('[data-view]').forEach(btn=>btn.setAttribute('aria-pressed',btn.dataset.view===state.view));
    renderResources();renderTable();saveState();
  }
  function switchLanguage(language) {
    if(!benchmarkMetadata().results_by_language[language] || language===languageCode())return;
    state.language=language;state.selected=[];
    renderResources();renderTable();saveState();
  }
  function switchView(view) {
    if(!isPlus()&&['subcategories','task_types'].includes(view))return;
    state.view=view;
    if(view==='task_types')state.subcategory=benchmark().subcategory_columns.find(c=>state.dimension==='all'||c.dimension===state.dimension).key;
    state.sort=isBreakdown()?availableColumns()[0].key:view==='accuracy'?'total':'instruction_reasoning';state.direction='desc';state.visible=availableColumns().map(c=>c.key);
    $$('[data-view]').forEach(btn=>btn.setAttribute('aria-pressed',btn.dataset.view===view));
    renderBreakdownControls();renderColumns();renderTable();$('.table-scroll').scrollLeft=0;
  }
  function download(name,content,type) {
    const url=URL.createObjectURL(new Blob([content],{type}));const a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1000);
  }
  function exportCSV(models,name='filtered') {
    const b=benchmark(), mainFields=[...(isPlus()?orderedAccuracyColumns():b.accuracy_columns).map(c=>({type:'accuracy',...c})),...b.metrics.map(c=>({type:'metrics',...c}))];
    const fields=isBreakdown()?[...(name==='comparison'?mainFields:[]),...availableColumns().filter(c=>state.visible.includes(c.key)).map(c=>({type:state.view,...c,label:qualifiedLabel(c)}))]:mainFields;
    const safeCSV=value=>{let t=String(value??'');if(/^\s*[=+@-]|^[\t\r\n]/.test(t))t="'"+t;return '"'+t.replace(/"/g,'""')+'"';};
    const rows=[['Benchmark','Result language','Model','Category','Multi-image support',...fields.map(c=>c.label+(c.type==='metrics'?' (/100)':' (%)'))],...models.map(m=>[b.name,b.language,m.name,groupLabels[m.group]||'Not specified',m.multi_image===null?'Not specified':m.multi_image?'Yes':'No',...fields.map(c=>m[c.type][c.key]===null?'':fmt(m[c.type][c.key]))])];
    download(`${b.id}-${languageCode()}-${state.view}-${name}-results.csv`,'\uFEFF'+rows.map(r=>r.map(safeCSV).join(',')).join('\r\n'),'text/csv;charset=utf-8');toast(`Exported ${models.length} models · ${resultLanguageLabel()} results.`);
  }
  function radar(models) {
    const dims=benchmark().dimensions, cx=205,cy=156,r=98,n=dims.length;
    const point=(i,radius)=>{const a=-Math.PI/2+i*2*Math.PI/n;return [cx+Math.cos(a)*radius,cy+Math.sin(a)*radius];};
    const polygon=radius=>dims.map((_,i)=>point(i,radius).map(x=>x.toFixed(1)).join(',')).join(' ');
    const rings=[20,40,60,80,100].map(v=>`<polygon points="${polygon(r*v/100)}" fill="none" stroke="#dce7ef" stroke-width=".8"/><text class="radar-value" x="${cx+4}" y="${cy-r*v/100-3}">${v}</text>`).join('');
    const lines=dims.map((d,i)=>{const p=point(i,r),l=point(i,r+24);return `<line x1="${cx}" y1="${cy}" x2="${p[0]}" y2="${p[1]}" stroke="#e3ecf3"/><text x="${l[0]}" y="${l[1]+3}" class="radar-label" text-anchor="${Math.abs(l[0]-cx)<1?'middle':l[0]>cx?'start':'end'}">${esc(d.label)}</text>`;}).join('');
    const plots=models.map((m,j)=>{const points=dims.map((d,i)=>point(i,r*(m.accuracy[d.key]??0)/100));return `<polygon points="${points.map(p=>p.join(',')).join(' ')}" fill="${colors[j]}" fill-opacity=".08" stroke="${colors[j]}" stroke-width="2"/>`+points.map(p=>`<circle cx="${p[0]}" cy="${p[1]}" r="2.5" fill="${colors[j]}" stroke="white" stroke-width="1"/>`).join('');}).join('');
    return `<svg class="radar" viewBox="0 0 410 305" role="img" aria-label="Reasoning-dimension accuracy comparison on a shared 0 to 100 percent scale. Exact values are listed in the table below.">${rings}${lines}${plots}</svg>`;
  }
  function showDialog(eyebrow,html) {
    $('#dialog-eyebrow').textContent=eyebrow;$('#dialog-content').innerHTML=html;
    $('#detail-dialog').showModal();$('#detail-dialog').scrollTop=0;
  }
  function showModels(ids) {
    const b=benchmark(), models=ids.map(modelById).filter(Boolean);if(!models.length)return;
    const mixed=isPlus()&&new Set(models.map(m=>m.multi_image)).size>1;
    const tableSection=(title,fields,type)=>`<tr class="comparison-section"><td colspan="${models.length+1}">${title}</td></tr>`+fields.map(c=>{const vals=models.map(m=>m[type]?.[c.key] ?? null);const max=Math.max(...vals.filter(v=>v!==null));return `<tr><td>${esc(c.label)}</td>${vals.map(v=>`<td class="${v!==null&&v===max&&models.length>1?'best-value':''}">${fmt(v)}${v!==null&&type!=='metrics'?'%':''}</td>`).join('')}</tr>`;}).join('');
    showDialog(b.name+' · '+resultLanguageLabel().toUpperCase()+' RESULTS',`<h2 class="dialog-title" id="dialog-title">${models.length===1?esc(models[0].name):'Model comparison'}</h2>${mixed?'<p class="comparison-warning">These models use different evaluation subsets: single-image only and full benchmark.</p>':''}<div class="comparison-layout">${radar(models)}<div class="compare-summaries">${models.map((m,i)=>`<div class="compare-summary"><div><h4><span class="series-dot" style="background:${colors[i]}"></span>${esc(m.name)}</h4><p>${esc(groupLabels[m.group]||b.name)}${isPlus()?' · '+(m.multi_image?'Multi-image supported':'Single-image only'):''}</p></div><strong style="color:${colors[i]}">${fmt(m.accuracy.total)}<small> ${m.accuracy.total!==null?'%':''}<br>${isPlus()?'Total':'Overall'}</small></strong></div>`).join('')}${models.some(m=>m.accuracy.total===null)?'<p class="caption-text">Single-image-only models have no Total score.</p>':''}</div></div><div class="comparison-table-wrap"><table class="comparison-table"><thead><tr><th>Metric</th>${models.map((m,i)=>`<th><span class="series-dot" style="background:${colors[i]}"></span>${esc(m.name)}</th>`).join('')}</tr></thead><tbody>${tableSection('REASONING ACCURACY (%)',isPlus()?orderedAccuracyColumns():b.accuracy_columns,'accuracy')}${tableSection('EVALUATION SCORES (/100)',b.metrics,'metrics')}${isBreakdown()?tableSection(viewLabel().toUpperCase()+' (%)',availableColumns().filter(c=>state.visible.includes(c.key)).map(c=>({...c,label:qualifiedLabel(c)})),state.view):''}</tbody></table></div><div class="dialog-actions"><button class="outline-button" id="dialog-export">Export ${models.length===1?'model':'comparison'} CSV ↓</button></div>`);
    $('#dialog-export').addEventListener('click',()=>exportCSV(models,'comparison'));
  }
  async function copyCitation(text,button) {
    try {await navigator.clipboard.writeText(text);button.textContent='Copied ✓';toast('BibTeX copied.');}
    catch(_){const area=document.createElement('textarea');area.value=text;($('#detail-dialog').open?$('#dialog-content'):document.body).appendChild(area);area.select();const copied=document.execCommand('copy');area.remove();toast(copied?'BibTeX copied.':'Select and copy the citation below.');}
  }
  function showCitation() {
    const citation=CITATIONS[state.benchmark];
    showDialog('CITATION',`<h2 class="dialog-title" id="dialog-title">Cite ${esc(benchmark().name)}</h2><pre class="citation-code"><code>${esc(citation)}</code></pre><div class="dialog-actions"><button class="primary-button" id="copy-citation">Copy BibTeX</button><button class="outline-button" id="save-citation">Download .bib ↓</button></div>`);
    $('#copy-citation').addEventListener('click',e=>copyCitation(citation,e.currentTarget));
    $('#save-citation').addEventListener('click',()=>download(state.benchmark+'.bib',citation+'\n','text/plain;charset=utf-8'));
  }
  document.addEventListener('click',event=>{
    const button=event.target.closest('button');if(!button)return;
    if(button.dataset.benchmark)switchBenchmark(button.dataset.benchmark);
    if(button.dataset.view)switchView(button.dataset.view);
    if(button.dataset.language)switchLanguage(button.dataset.language);
    if(button.dataset.dimension){state.dimension=button.dataset.dimension;state.subcategory='all';resetScoreColumns();}
    if(button.dataset.group){state.group=button.dataset.group;renderTable();}
    if(button.dataset.sort){state.direction=state.sort===button.dataset.sort&&state.direction==='desc'?'asc':'desc';state.sort=button.dataset.sort;renderTable();}
    if(button.dataset.model)showModels([button.dataset.model]);
    if(button.dataset.remove)toggleSelected(button.dataset.remove,false);
  });
  document.addEventListener('change',event=>{
    const input=event.target;
    if(input.dataset.select)toggleSelected(input.dataset.select,input.checked);
    if(input.dataset.column){
      if(!input.checked&&state.visible.length===1){input.checked=true;toast('Keep at least one score column visible.');return;}
      state.visible=input.checked?[...state.visible,input.dataset.column]:state.visible.filter(c=>c!==input.dataset.column);
      if(!state.visible.includes(state.sort)){state.sort=availableColumns().find(c=>state.visible.includes(c.key)).key;state.direction='desc';}
      renderTable();
    }
  });
  $('#model-search').addEventListener('input',e=>{state.query=e.target.value;renderTable();});
  $('#input-filter').addEventListener('change',e=>{state.input=e.target.value;renderTable();});
  $('#subcategory-select').addEventListener('change',e=>{state.subcategory=e.target.value;resetScoreColumns();});
  $('#page-copy-citation').addEventListener('click',e=>copyCitation(CITATIONS[state.benchmark],e.currentTarget));
  $('#page-save-citation').addEventListener('click',()=>download(state.benchmark+'.bib',CITATIONS[state.benchmark]+'\n','text/plain;charset=utf-8'));
  $('#reset-filters').addEventListener('click',resetFilters);$('#empty-reset').addEventListener('click',resetFilters);
  $('#download-csv').addEventListener('click',()=>exportCSV(filteredModels()));
  $('#compare-open').addEventListener('click',()=>showModels(state.selected));
  $('#clear-compare').addEventListener('click',()=>{state.selected=[];renderTable();});
  $('.dialog-close').addEventListener('click',()=>$('#detail-dialog').close());
  $('#detail-dialog').addEventListener('click',e=>{if(e.target===$('#detail-dialog')){const r=e.target.getBoundingClientRect();if(e.clientX<r.left||e.clientX>r.right||e.clientY<r.top||e.clientY>r.bottom)e.target.close();}});
  $('#citation-button').addEventListener('click',showCitation);
  document.addEventListener('click',e=>{if(!$('#column-menu').contains(e.target))$('#column-menu').open=false;});
  document.addEventListener('keydown',e=>{
    if(e.key==='/'&&!['INPUT','TEXTAREA','SELECT'].includes(document.activeElement.tagName)&&!$('#detail-dialog').open){e.preventDefault();$('#model-search').focus();}
    const tab=e.target.closest('[data-benchmark], [data-view], [data-language]');
    if(tab&&['ArrowLeft','ArrowRight','Home','End'].includes(e.key)){
      e.preventDefault();const siblings=[...tab.parentElement.querySelectorAll('[data-benchmark], [data-view], [data-language]')].filter(el=>!el.hidden),i=siblings.indexOf(tab);
      const n=e.key==='Home'?0:e.key==='End'?siblings.length-1:(i+(e.key==='ArrowRight'?1:-1)+siblings.length)%siblings.length;
      siblings[n].click();siblings[n].focus();
    }
  });
  switchBenchmark(state.benchmark);
})();