LeenAlQadi commited on
Commit
3638b8c
·
1 Parent(s): 62947e5

UI polish: sticky avg column at 3rd, global color gradient, podium links, cards pronounced

Browse files
backend/config.py CHANGED
@@ -22,7 +22,7 @@ RESULTS_TASKS: List[Tuple[Any, Any, str]] = [
22
  ("qimma-ArabicMMLU:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "ArabicMMLU"),
23
  ("qimma-ArabCulture:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "ArabCulture"),
24
  ("qimma-PalmX:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "PALMX"),
25
- ("qimma-3lmSTEM:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "3lmSTEM"),
26
  ("qimma-AraTrust|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "AraTrust"),
27
  ("qimma-Mizan|0", "normalized_mc_prob_norm", "MizanQA"),
28
  (
 
22
  ("qimma-ArabicMMLU:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "ArabicMMLU"),
23
  ("qimma-ArabCulture:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "ArabCulture"),
24
  ("qimma-PalmX:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "PALMX"),
25
+ ("qimma-3lmSTEM:_average|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "3LM STEM"),
26
  ("qimma-AraTrust|0", "acc:logprob_normalization=LogProbCharNorm(name='norm', ignore_first_space=False)", "AraTrust"),
27
  ("qimma-Mizan|0", "normalized_mc_prob_norm", "MizanQA"),
28
  (
frontend/about.html CHANGED
@@ -159,21 +159,49 @@
159
  </div>
160
  <h2 class="text-2xl font-bold text-slate-800 dark:text-slate-100">Resources</h2>
161
  </div>
162
- <div class="flex flex-wrap gap-3">
163
- <a href="#" target="_blank"
164
- class="flex items-center gap-2 px-4 py-2.5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30 text-slate-700 dark:text-slate-300 hover:border-indigo-400 dark:hover:border-indigo-500 hover:text-indigo-600 dark:hover:text-indigo-400 transition-all text-sm font-medium">
165
- <i data-lucide="file-text" class="w-4 h-4"></i>
166
- Paper <span class="text-xs text-slate-400 dark:text-slate-500 font-normal ml-1">(coming soon)</span>
167
- </a>
 
 
 
 
 
 
 
 
 
 
168
  <a href="https://huggingface.co/blog/tiiuae/qimma-arabic-leaderboard" target="_blank"
169
- class="flex items-center gap-2 px-4 py-2.5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30 text-slate-700 dark:text-slate-300 hover:border-indigo-400 dark:hover:border-indigo-500 hover:text-indigo-600 dark:hover:text-indigo-400 transition-all text-sm font-medium">
170
- <i data-lucide="newspaper" class="w-4 h-4"></i>
171
- Blog Post
 
 
 
 
 
 
 
 
172
  </a>
 
 
173
  <a href="https://github.com/tiiuae/QIMMA-leaderboard" target="_blank"
174
- class="flex items-center gap-2 px-4 py-2.5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30 text-slate-700 dark:text-slate-300 hover:border-indigo-400 dark:hover:border-indigo-500 hover:text-indigo-600 dark:hover:text-indigo-400 transition-all text-sm font-medium">
175
- <i data-lucide="github" class="w-4 h-4"></i>
176
- GitHub
 
 
 
 
 
 
 
 
177
  </a>
178
  </div>
179
  <p class="mt-5 text-sm text-slate-600 dark:text-slate-400">
 
159
  </div>
160
  <h2 class="text-2xl font-bold text-slate-800 dark:text-slate-100">Resources</h2>
161
  </div>
162
+ <div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
163
+ <!-- Paper -->
164
+ <div class="flex flex-col gap-3 p-5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30">
165
+ <div class="flex items-center gap-2 text-slate-700 dark:text-slate-300">
166
+ <i data-lucide="file-text" class="w-5 h-5 shrink-0"></i>
167
+ <span class="font-semibold">Paper</span>
168
+ </div>
169
+ <p class="text-sm text-slate-500 dark:text-slate-400 leading-relaxed flex-1">
170
+ Describes the full methodology, benchmark design, and analysis behind QIMMA — including task selection, scoring, and model comparisons.
171
+ </p>
172
+ <span class="inline-flex items-center gap-1 text-xs text-slate-400 dark:text-slate-500 font-medium cursor-not-allowed">
173
+ <i data-lucide="clock" class="w-3 h-3"></i> Coming soon
174
+ </span>
175
+ </div>
176
+
177
+ <!-- Blog Post -->
178
  <a href="https://huggingface.co/blog/tiiuae/qimma-arabic-leaderboard" target="_blank"
179
+ class="flex flex-col gap-3 p-5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30 hover:border-indigo-400 dark:hover:border-indigo-500 hover:shadow-md transition-all group">
180
+ <div class="flex items-center gap-2 text-slate-700 dark:text-slate-300 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors">
181
+ <i data-lucide="newspaper" class="w-5 h-5 shrink-0"></i>
182
+ <span class="font-semibold">Blog Post</span>
183
+ </div>
184
+ <p class="text-sm text-slate-500 dark:text-slate-400 leading-relaxed flex-1">
185
+ A high-level overview of QIMMA, its goals, the benchmarks it covers, and key findings from the evaluation of Arabic language models.
186
+ </p>
187
+ <span class="inline-flex items-center gap-1 text-xs text-indigo-500 dark:text-indigo-400 font-medium">
188
+ Read on Hugging Face <i data-lucide="arrow-right" class="w-3 h-3"></i>
189
+ </span>
190
  </a>
191
+
192
+ <!-- GitHub -->
193
  <a href="https://github.com/tiiuae/QIMMA-leaderboard" target="_blank"
194
+ class="flex flex-col gap-3 p-5 rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/30 hover:border-indigo-400 dark:hover:border-indigo-500 hover:shadow-md transition-all group">
195
+ <div class="flex items-center gap-2 text-slate-700 dark:text-slate-300 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors">
196
+ <i data-lucide="github" class="w-5 h-5 shrink-0"></i>
197
+ <span class="font-semibold">GitHub Repository</span>
198
+ </div>
199
+ <p class="text-sm text-slate-500 dark:text-slate-400 leading-relaxed flex-1">
200
+ Contains the full evaluation pipeline used to produce every score on this leaderboard. Use it to reproduce results, run evaluations on your own models, or extend the benchmark suite.
201
+ </p>
202
+ <span class="inline-flex items-center gap-1 text-xs text-indigo-500 dark:text-indigo-400 font-medium">
203
+ View on GitHub <i data-lucide="arrow-right" class="w-3 h-3"></i>
204
+ </span>
205
  </a>
206
  </div>
207
  <p class="mt-5 text-sm text-slate-600 dark:text-slate-400">
frontend/header.html CHANGED
@@ -29,9 +29,9 @@
29
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-12">
30
 
31
  <!-- Podium -->
32
- <div class="rounded-xl p-6 shadow-sm text-white relative overflow-visible group col-span-1 sm:col-span-2 lg:col-span-1 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
33
  style="background: linear-gradient(to bottom, #2d7d65, #1f604f);">
34
- <div class="absolute -right-6 -top-6 w-20 h-20 rounded-full opacity-50 group-hover:scale-[2.5] transition-transform duration-500"
35
  style="background-color: #174d3e;"></div>
36
  <div class="flex justify-between items-start mb-4 relative z-10">
37
  <p class="text-sm font-medium text-white/80 uppercase tracking-wider">Podium</p>
@@ -41,9 +41,9 @@
41
  </div>
42
 
43
  <!-- Total Models -->
44
- <div class="stat-card p-4 rounded-2xl border border-slate-200 dark:border-slate-700 shadow-sm flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
45
  style="background-color: var(--card-bg);">
46
- <div class="p-3 bg-indigo-50 dark:bg-indigo-900/30 rounded-xl">
47
  <i data-lucide="database" class="w-6 h-6 text-indigo-600 dark:text-indigo-400"></i>
48
  </div>
49
  <div>
@@ -53,28 +53,28 @@
53
  </div>
54
 
55
  <!-- Eval Status -->
56
- <div class="stat-card p-4 rounded-2xl border border-slate-200 dark:border-slate-700 shadow-sm flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
57
  style="background-color: var(--card-bg);">
58
- <div class="p-3 bg-emerald-50 dark:bg-emerald-900/30 rounded-xl">
59
  <i data-lucide="activity" class="w-6 h-6 text-emerald-600 dark:text-emerald-400"></i>
60
  </div>
61
  <div class="w-full">
62
  <p class="text-xs font-bold uppercase text-slate-400 tracking-wider mb-2">Eval Status</p>
63
  <div class="grid grid-cols-4 gap-1 text-center mb-2">
64
  <div>
65
- <div class="text-lg font-bold text-emerald-600 dark:text-emerald-400" id="stat-done">--</div>
66
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Done</div>
67
  </div>
68
  <div>
69
- <div class="text-lg font-bold text-rose-600 dark:text-rose-400" id="stat-failed">--</div>
70
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Failed</div>
71
  </div>
72
  <div>
73
- <div class="text-lg font-bold text-blue-600 dark:text-blue-400" id="stat-running">--</div>
74
- <div class="text-[10px] text-slate-500 dark:text-slate-400">Run</div>
75
  </div>
76
  <div>
77
- <div class="text-lg font-bold text-amber-500 dark:text-amber-400" id="stat-queue">--</div>
78
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Queue</div>
79
  </div>
80
  </div>
@@ -88,9 +88,9 @@
88
  </div>
89
 
90
  <!-- Benchmarks -->
91
- <div class="stat-card p-4 rounded-2xl border border-slate-200 dark:border-slate-700 shadow-sm flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
92
  style="background-color: var(--card-bg);">
93
- <div class="p-3 bg-purple-50 dark:bg-purple-900/30 rounded-xl">
94
  <i data-lucide="bar-chart-2" class="w-6 h-6 text-purple-600 dark:text-purple-400"></i>
95
  </div>
96
  <div>
@@ -141,7 +141,7 @@
141
  <div class="group/podium relative py-0.5">
142
  <div class="flex items-center gap-3">
143
  <div class="w-4 h-5 shrink-0 rounded-full ${rankStyles[i] || 'bg-slate-100 text-emerald-900'} flex items-center justify-center text-xs font-bold">${i + 1}</div>
144
- <span class="text-sm font-semibold truncate flex-1 min-w-0 cursor-help">${esc(m["Model Name"])}</span>
145
  <span class="ml-auto text-xs font-mono text-emerald-300">${parseFloat(m[avgK]).toFixed(1)}</span>
146
  </div>
147
  <div class="absolute left-7 top-full mt-1 z-30 pointer-events-none opacity-0 translate-y-1 group-hover/podium:opacity-100 group-hover/podium:translate-y-0 transition-all duration-200 ease-out">
 
29
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-12">
30
 
31
  <!-- Podium -->
32
+ <div class="rounded-xl p-6 shadow-sm text-white relative overflow-hidden group col-span-1 sm:col-span-2 lg:col-span-1 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
33
  style="background: linear-gradient(to bottom, #2d7d65, #1f604f);">
34
+ <div class="absolute -right-6 -top-6 w-[86px] h-[86px] rounded-full opacity-50 group-hover:scale-[2.5] transition-transform duration-500"
35
  style="background-color: #174d3e;"></div>
36
  <div class="flex justify-between items-start mb-4 relative z-10">
37
  <p class="text-sm font-medium text-white/80 uppercase tracking-wider">Podium</p>
 
41
  </div>
42
 
43
  <!-- Total Models -->
44
+ <div class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
45
  style="background-color: var(--card-bg);">
46
+ <div class="p-3 bg-indigo-50 dark:bg-indigo-900/30 rounded-xl border border-indigo-200 dark:border-indigo-700">
47
  <i data-lucide="database" class="w-6 h-6 text-indigo-600 dark:text-indigo-400"></i>
48
  </div>
49
  <div>
 
53
  </div>
54
 
55
  <!-- Eval Status -->
56
+ <div class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
57
  style="background-color: var(--card-bg);">
58
+ <div class="p-3 bg-emerald-50 dark:bg-emerald-900/30 rounded-xl border border-emerald-200 dark:border-emerald-700 shrink-0">
59
  <i data-lucide="activity" class="w-6 h-6 text-emerald-600 dark:text-emerald-400"></i>
60
  </div>
61
  <div class="w-full">
62
  <p class="text-xs font-bold uppercase text-slate-400 tracking-wider mb-2">Eval Status</p>
63
  <div class="grid grid-cols-4 gap-1 text-center mb-2">
64
  <div>
65
+ <div class="text-base font-bold text-emerald-600 dark:text-emerald-400" id="stat-done">--</div>
66
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Done</div>
67
  </div>
68
  <div>
69
+ <div class="text-base font-bold text-rose-600 dark:text-rose-400" id="stat-failed">--</div>
70
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Failed</div>
71
  </div>
72
  <div>
73
+ <div class="text-base font-bold text-blue-600 dark:text-blue-400" id="stat-running">--</div>
74
+ <div class="text-[10px] text-slate-500 dark:text-slate-400">Running</div>
75
  </div>
76
  <div>
77
+ <div class="text-base font-bold text-amber-500 dark:text-amber-400" id="stat-queue">--</div>
78
  <div class="text-[10px] text-slate-500 dark:text-slate-400">Queue</div>
79
  </div>
80
  </div>
 
88
  </div>
89
 
90
  <!-- Benchmarks -->
91
+ <div class="stat-card p-4 rounded-2xl border border-slate-300 dark:border-slate-600 shadow-md flex items-center gap-4 transition-all duration-300 ease-in-out transform hover:-translate-y-1 cursor-default"
92
  style="background-color: var(--card-bg);">
93
+ <div class="p-3 bg-purple-50 dark:bg-purple-900/30 rounded-xl border border-purple-200 dark:border-purple-700">
94
  <i data-lucide="bar-chart-2" class="w-6 h-6 text-purple-600 dark:text-purple-400"></i>
95
  </div>
96
  <div>
 
141
  <div class="group/podium relative py-0.5">
142
  <div class="flex items-center gap-3">
143
  <div class="w-4 h-5 shrink-0 rounded-full ${rankStyles[i] || 'bg-slate-100 text-emerald-900'} flex items-center justify-center text-xs font-bold">${i + 1}</div>
144
+ <span class="text-sm font-semibold truncate flex-1 min-w-0 cursor-pointer hover:underline" onclick="window.openModelDetails && window.openModelDetails(decodeURIComponent('${encodeURIComponent(m["Model Name"])}'))">${esc(m["Model Name"].split('/').pop())}</span>
145
  <span class="ml-auto text-xs font-mono text-emerald-300">${parseFloat(m[avgK]).toFixed(1)}</span>
146
  </div>
147
  <div class="absolute left-7 top-full mt-1 z-30 pointer-events-none opacity-0 translate-y-1 group-hover/podium:opacity-100 group-hover/podium:translate-y-0 transition-all duration-200 ease-out">
frontend/leaderboard.html CHANGED
@@ -17,6 +17,29 @@
17
  <body class="bg-slate-50 text-slate-800 dark:bg-darkbg dark:text-slate-100 relative">
18
 
19
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  #table-wrapper {
21
  max-height: 700px;
22
  overflow-y: auto;
@@ -76,6 +99,19 @@
76
  position: relative;
77
  z-index: 20;
78
  border-top: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
  #table-wrapper .gridjs-th.sticky-rank-col,
@@ -89,7 +125,7 @@
89
  #table-wrapper .gridjs-th.sticky-model-col,
90
  #table-wrapper .gridjs-td.sticky-model-col {
91
  position: sticky !important;
92
- left: var(--sticky-model-left, 110px) !important;
93
  z-index: 31 !important;
94
  box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
95
  }
@@ -133,7 +169,7 @@
133
 
134
  #table-wrapper table.gridjs-table thead th:nth-child(2) {
135
  position: sticky !important;
136
- left: var(--sticky-model-left, 110px) !important;
137
  top: 0 !important;
138
  z-index: 45 !important;
139
  background: #f1f5f9 !important;
@@ -141,15 +177,64 @@
141
 
142
  #table-wrapper table.gridjs-table tbody td:nth-child(2) {
143
  position: sticky !important;
144
- left: var(--sticky-model-left, 110px) !important;
145
  z-index: 29 !important;
146
  }
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  .dark #table-wrapper table.gridjs-table thead th:nth-child(1),
149
- .dark #table-wrapper table.gridjs-table thead th:nth-child(2) {
 
150
  background: #0f172a !important;
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  .dark .gridjs-head,
154
  .dark th.gridjs-th {
155
  background-color: #0f172a !important;
@@ -713,7 +798,7 @@
713
  </div>
714
  </div>
715
 
716
- <div class="w-full sm:w-[95%] mx-auto mb-20">
717
  <div id="table-wrapper" class="bg-white dark:bg-slate-800 shadow-sm transition-colors"></div>
718
  </div>
719
 
@@ -1538,9 +1623,9 @@
1538
  const rankIdx = visibleCols.indexOf("Rank");
1539
  const modelIdx = visibleCols.indexOf("Model Name");
1540
 
1541
- headers.forEach(th => th.classList.remove('sticky-rank-col', 'sticky-model-col'));
1542
  table.querySelectorAll('tbody tr').forEach(tr => {
1543
- [...tr.children].forEach(td => td.classList.remove('sticky-rank-col', 'sticky-model-col'));
1544
  });
1545
 
1546
  if (rankIdx >= 0 && headers[rankIdx]) {
@@ -1559,9 +1644,34 @@
1559
  if (tr.children[modelIdx]) tr.children[modelIdx].classList.add('sticky-model-col');
1560
  });
1561
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1562
  return true;
1563
  }
1564
 
 
 
 
 
 
 
 
 
 
 
 
 
1565
  function scheduleStickyApply(retries = 8) {
1566
  let attempts = 0;
1567
  const run = () => {
@@ -1646,10 +1756,17 @@
1646
  }
1647
  }).render($('#table-wrapper'));
1648
  scheduleStickyApply();
 
1649
  }
1650
 
1651
  function prepareColumns(data) {
1652
  const keys = Object.keys(data[0] || {});
 
 
 
 
 
 
1653
  const typeIdx = keys.findIndex(k => ["T", "Type", "Full Type"].includes(k));
1654
  const modelNameIdx = keys.findIndex(k => k === "Model Name");
1655
  const vis = tableColumns.reduce((acc, c) => ({ ...acc, [c.id]: c.hidden }), {});
@@ -1738,7 +1855,7 @@
1738
  };
1739
 
1740
  } else if (key === "Rank") {
1741
- def.width = '110px';
1742
  def.formatter = (c) => {
1743
  const rank = parseInt(c);
1744
  let badge = `<span class="font-mono font-bold text-slate-700 dark:text-slate-200">#${rank}</span>`;
 
17
  <body class="bg-slate-50 text-slate-800 dark:bg-darkbg dark:text-slate-100 relative">
18
 
19
  <style>
20
+ #table-outer {
21
+ position: relative;
22
+ --green-opacity: 0.07;
23
+ --red-opacity: 0;
24
+ }
25
+
26
+ #table-outer::after {
27
+ content: '';
28
+ position: absolute;
29
+ inset: 0;
30
+ background: linear-gradient(
31
+ to bottom,
32
+ rgba(16, 185, 129, var(--green-opacity)) 0%,
33
+ transparent 30%,
34
+ transparent 70%,
35
+ rgba(239, 68, 68, var(--red-opacity)) 100%
36
+ );
37
+ pointer-events: none;
38
+ z-index: 1;
39
+ border-radius: 1rem;
40
+ transition: background 0.15s ease;
41
+ }
42
+
43
  #table-wrapper {
44
  max-height: 700px;
45
  overflow-y: auto;
 
99
  position: relative;
100
  z-index: 20;
101
  border-top: none !important;
102
+ box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
103
+ }
104
+
105
+ .gridjs-td {
106
+ box-shadow: 1px 0 0 rgba(148, 163, 184, 0.15);
107
+ }
108
+
109
+ .dark .gridjs-th {
110
+ box-shadow: 1px 0 0 rgba(71, 85, 105, 0.4);
111
+ }
112
+
113
+ .dark .gridjs-td {
114
+ box-shadow: 1px 0 0 rgba(71, 85, 105, 0.3);
115
  }
116
 
117
  #table-wrapper .gridjs-th.sticky-rank-col,
 
125
  #table-wrapper .gridjs-th.sticky-model-col,
126
  #table-wrapper .gridjs-td.sticky-model-col {
127
  position: sticky !important;
128
+ left: var(--sticky-model-left, 100px) !important;
129
  z-index: 31 !important;
130
  box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
131
  }
 
169
 
170
  #table-wrapper table.gridjs-table thead th:nth-child(2) {
171
  position: sticky !important;
172
+ left: var(--sticky-model-left, 100px) !important;
173
  top: 0 !important;
174
  z-index: 45 !important;
175
  background: #f1f5f9 !important;
 
177
 
178
  #table-wrapper table.gridjs-table tbody td:nth-child(2) {
179
  position: sticky !important;
180
+ left: var(--sticky-model-left, 100px) !important;
181
  z-index: 29 !important;
182
  }
183
 
184
+ #table-wrapper table.gridjs-table thead th:nth-child(3) {
185
+ position: sticky !important;
186
+ left: var(--sticky-avg-left, 620px) !important;
187
+ top: 0 !important;
188
+ z-index: 44 !important;
189
+ background: #f1f5f9 !important;
190
+ box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
191
+ }
192
+
193
+ #table-wrapper table.gridjs-table tbody td:nth-child(3) {
194
+ position: sticky !important;
195
+ left: var(--sticky-avg-left, 620px) !important;
196
+ z-index: 28 !important;
197
+ box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
198
+ }
199
+
200
  .dark #table-wrapper table.gridjs-table thead th:nth-child(1),
201
+ .dark #table-wrapper table.gridjs-table thead th:nth-child(2),
202
+ .dark #table-wrapper table.gridjs-table thead th:nth-child(3) {
203
  background: #0f172a !important;
204
  }
205
 
206
+ .dark #table-wrapper table.gridjs-table tbody td:nth-child(3) {
207
+ box-shadow: 1px 0 0 rgba(71, 85, 105, 0.6);
208
+ }
209
+
210
+ #table-wrapper .gridjs-th.avg-col-header,
211
+ #table-wrapper .gridjs-td.avg-col-header {
212
+ position: sticky !important;
213
+ left: var(--sticky-avg-left, 620px) !important;
214
+ z-index: 30 !important;
215
+ box-shadow: 1px 0 0 rgba(148, 163, 184, 0.25);
216
+ }
217
+
218
+ #table-wrapper .gridjs-th.avg-col-header {
219
+ background: #f1f5f9 !important;
220
+ z-index: 39 !important;
221
+ top: 0 !important;
222
+ }
223
+
224
+ #table-wrapper .gridjs-td.avg-col-header {
225
+ background: #fff !important;
226
+ }
227
+
228
+ .dark #table-wrapper .gridjs-th.avg-col-header {
229
+ background: #0f172a !important;
230
+ box-shadow: 1px 0 0 rgba(71, 85, 105, 0.6);
231
+ }
232
+
233
+ .dark #table-wrapper .gridjs-td.avg-col-header {
234
+ background: #1e293b !important;
235
+ box-shadow: 1px 0 0 rgba(71, 85, 105, 0.6);
236
+ }
237
+
238
  .dark .gridjs-head,
239
  .dark th.gridjs-th {
240
  background-color: #0f172a !important;
 
798
  </div>
799
  </div>
800
 
801
+ <div id="table-outer" class="w-full sm:w-[99%] mx-auto mb-20">
802
  <div id="table-wrapper" class="bg-white dark:bg-slate-800 shadow-sm transition-colors"></div>
803
  </div>
804
 
 
1623
  const rankIdx = visibleCols.indexOf("Rank");
1624
  const modelIdx = visibleCols.indexOf("Model Name");
1625
 
1626
+ headers.forEach(th => th.classList.remove('sticky-rank-col', 'sticky-model-col', 'avg-col-header'));
1627
  table.querySelectorAll('tbody tr').forEach(tr => {
1628
+ [...tr.children].forEach(td => td.classList.remove('sticky-rank-col', 'sticky-model-col', 'avg-col-header'));
1629
  });
1630
 
1631
  if (rankIdx >= 0 && headers[rankIdx]) {
 
1644
  if (tr.children[modelIdx]) tr.children[modelIdx].classList.add('sticky-model-col');
1645
  });
1646
  }
1647
+
1648
+ const modelWidth = (modelIdx >= 0 && headers[modelIdx]) ? headers[modelIdx].getBoundingClientRect().width : 0;
1649
+ const avgLeft = Math.max(0, Math.round(rankWidth + modelWidth));
1650
+ wrapper.style.setProperty('--sticky-avg-left', `${avgLeft}px`);
1651
+
1652
+ const avgIdx = visibleCols.findIndex(k => k.includes("Average"));
1653
+ if (avgIdx >= 0 && headers[avgIdx]) {
1654
+ headers[avgIdx].classList.add('avg-col-header');
1655
+ table.querySelectorAll('tbody tr').forEach(tr => {
1656
+ if (tr.children[avgIdx]) tr.children[avgIdx].classList.add('avg-col-header');
1657
+ });
1658
+ }
1659
+
1660
  return true;
1661
  }
1662
 
1663
+ function initGradientScroll() {
1664
+ const wrapper = $('#table-wrapper');
1665
+ const outer = $('#table-outer');
1666
+ if (!wrapper || !outer) return;
1667
+ wrapper.addEventListener('scroll', () => {
1668
+ const max = wrapper.scrollHeight - wrapper.clientHeight;
1669
+ const ratio = max > 0 ? wrapper.scrollTop / max : 0;
1670
+ outer.style.setProperty('--green-opacity', (0.07 * (1 - ratio)).toFixed(3));
1671
+ outer.style.setProperty('--red-opacity', (0.07 * ratio).toFixed(3));
1672
+ }, { passive: true });
1673
+ }
1674
+
1675
  function scheduleStickyApply(retries = 8) {
1676
  let attempts = 0;
1677
  const run = () => {
 
1756
  }
1757
  }).render($('#table-wrapper'));
1758
  scheduleStickyApply();
1759
+ initGradientScroll();
1760
  }
1761
 
1762
  function prepareColumns(data) {
1763
  const keys = Object.keys(data[0] || {});
1764
+ const avgKey = keys.find(k => k.includes("Average"));
1765
+ if (avgKey) {
1766
+ keys.splice(keys.indexOf(avgKey), 1);
1767
+ const insertAt = Math.min(2, keys.length);
1768
+ keys.splice(insertAt, 0, avgKey);
1769
+ }
1770
  const typeIdx = keys.findIndex(k => ["T", "Type", "Full Type"].includes(k));
1771
  const modelNameIdx = keys.findIndex(k => k === "Model Name");
1772
  const vis = tableColumns.reduce((acc, c) => ({ ...acc, [c.id]: c.hidden }), {});
 
1855
  };
1856
 
1857
  } else if (key === "Rank") {
1858
+ def.width = '100px';
1859
  def.formatter = (c) => {
1860
  const rank = parseInt(c);
1861
  let badge = `<span class="font-mono font-bold text-slate-700 dark:text-slate-200">#${rank}</span>`;