ztwang commited on
Commit
a399453
·
verified ·
1 Parent(s): e319cd2

Upload 10 files

Browse files
Files changed (4) hide show
  1. app.py +90 -9
  2. index.html +36 -52
  3. script.js +23 -4
  4. style.css +6 -16
app.py CHANGED
@@ -20,6 +20,53 @@ def encode_image_to_base64(image_path):
20
  return f"data:{mime_type};base64,{encoded}"
21
  return ""
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  def create_gradio_app():
24
  """
25
  Gradio app to serve the static HTML leaderboard with embedded images
@@ -34,10 +81,6 @@ def create_gradio_app():
34
  with open('style.css', 'r', encoding='utf-8') as f:
35
  css_content = f.read()
36
 
37
- # Read the JavaScript content
38
- with open('script.js', 'r', encoding='utf-8') as f:
39
- js_content = f.read()
40
-
41
  # Convert images to base64 for embedding
42
  diagram_b64 = encode_image_to_base64('mcp-bench.png')
43
  ranking_b64 = encode_image_to_base64('ranking.png')
@@ -51,20 +94,58 @@ def create_gradio_app():
51
  f'src="{ranking_b64}"'
52
  )
53
 
54
- # Combine everything into a single HTML page
 
 
 
55
  combined_html = html_content.replace(
 
 
 
56
  '<link rel="stylesheet" href="style.css">',
57
  f'<style>{css_content}</style>'
58
- ).replace(
59
- '<script src="script.js"></script>',
60
- f'<script>if(document.readyState === "loading") {{ document.addEventListener("DOMContentLoaded", () => {{ {js_content} }}); }} else {{ {js_content} }}</script>'
61
  )
62
 
 
 
63
  # Create the Gradio interface
64
  with gr.Blocks(
65
  title="MCP-Bench Leaderboard",
66
  theme=gr.themes.Soft(),
67
- css="body { margin: 0; padding: 0; }"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  ) as demo:
69
  gr.HTML(
70
  combined_html,
 
20
  return f"data:{mime_type};base64,{encoded}"
21
  return ""
22
 
23
+ def generate_table_html():
24
+ """Generate table HTML from data"""
25
+ models = [
26
+ {"name": "gpt-5", "overall_score": 0.749, "valid_tool_name_rate": 100.0, "schema_compliance": 99.3, "execution_success": 99.1, "task_fulfillment": 0.677, "information_grounding": 0.828, "tool_appropriateness": 0.767, "parameter_accuracy": 0.749, "dependency_awareness": 0.649, "parallelism_efficiency": 0.339},
27
+ {"name": "o3", "overall_score": 0.715, "valid_tool_name_rate": 99.3, "schema_compliance": 99.9, "execution_success": 97.1, "task_fulfillment": 0.641, "information_grounding": 0.706, "tool_appropriateness": 0.724, "parameter_accuracy": 0.726, "dependency_awareness": 0.592, "parallelism_efficiency": 0.359},
28
+ {"name": "gpt-oss-120b", "overall_score": 0.692, "valid_tool_name_rate": 97.7, "schema_compliance": 98.8, "execution_success": 94.0, "task_fulfillment": 0.636, "information_grounding": 0.705, "tool_appropriateness": 0.691, "parameter_accuracy": 0.661, "dependency_awareness": 0.576, "parallelism_efficiency": 0.329},
29
+ {"name": "gemini-2.5-pro", "overall_score": 0.690, "valid_tool_name_rate": 99.4, "schema_compliance": 99.6, "execution_success": 96.9, "task_fulfillment": 0.562, "information_grounding": 0.725, "tool_appropriateness": 0.717, "parameter_accuracy": 0.670, "dependency_awareness": 0.541, "parallelism_efficiency": 0.329},
30
+ {"name": "claude-sonnet-4", "overall_score": 0.681, "valid_tool_name_rate": 100.0, "schema_compliance": 99.8, "execution_success": 98.8, "task_fulfillment": 0.554, "information_grounding": 0.676, "tool_appropriateness": 0.689, "parameter_accuracy": 0.671, "dependency_awareness": 0.541, "parallelism_efficiency": 0.328},
31
+ {"name": "qwen3-235b-a22b-2507", "overall_score": 0.678, "valid_tool_name_rate": 99.1, "schema_compliance": 99.3, "execution_success": 94.8, "task_fulfillment": 0.549, "information_grounding": 0.625, "tool_appropriateness": 0.688, "parameter_accuracy": 0.712, "dependency_awareness": 0.542, "parallelism_efficiency": 0.355},
32
+ {"name": "glm-4.5", "overall_score": 0.668, "valid_tool_name_rate": 99.7, "schema_compliance": 99.7, "execution_success": 97.4, "task_fulfillment": 0.525, "information_grounding": 0.682, "tool_appropriateness": 0.680, "parameter_accuracy": 0.661, "dependency_awareness": 0.523, "parallelism_efficiency": 0.297},
33
+ {"name": "gpt-oss-20b", "overall_score": 0.654, "valid_tool_name_rate": 98.8, "schema_compliance": 99.1, "execution_success": 93.6, "task_fulfillment": 0.547, "information_grounding": 0.623, "tool_appropriateness": 0.661, "parameter_accuracy": 0.638, "dependency_awareness": 0.509, "parallelism_efficiency": 0.309},
34
+ {"name": "kimi-k2", "overall_score": 0.629, "valid_tool_name_rate": 98.8, "schema_compliance": 98.1, "execution_success": 94.5, "task_fulfillment": 0.502, "information_grounding": 0.577, "tool_appropriateness": 0.631, "parameter_accuracy": 0.623, "dependency_awareness": 0.448, "parallelism_efficiency": 0.307},
35
+ {"name": "qwen3-30b-a3b-instruct-2507", "overall_score": 0.627, "valid_tool_name_rate": 99.2, "schema_compliance": 95.4, "execution_success": 94.4, "task_fulfillment": 0.459, "information_grounding": 0.536, "tool_appropriateness": 0.658, "parameter_accuracy": 0.646, "dependency_awareness": 0.471, "parallelism_efficiency": 0.318},
36
+ {"name": "gemini-2.5-flash-lite", "overall_score": 0.598, "valid_tool_name_rate": 98.7, "schema_compliance": 98.8, "execution_success": 91.1, "task_fulfillment": 0.446, "information_grounding": 0.569, "tool_appropriateness": 0.629, "parameter_accuracy": 0.564, "dependency_awareness": 0.423, "parallelism_efficiency": 0.262},
37
+ {"name": "gpt-4o", "overall_score": 0.595, "valid_tool_name_rate": 96.7, "schema_compliance": 87.6, "execution_success": 85.3, "task_fulfillment": 0.477, "information_grounding": 0.519, "tool_appropriateness": 0.588, "parameter_accuracy": 0.551, "dependency_awareness": 0.423, "parallelism_efficiency": 0.253},
38
+ {"name": "gemma-3-27b-it", "overall_score": 0.582, "valid_tool_name_rate": 98.4, "schema_compliance": 81.6, "execution_success": 85.5, "task_fulfillment": 0.396, "information_grounding": 0.495, "tool_appropriateness": 0.588, "parameter_accuracy": 0.530, "dependency_awareness": 0.408, "parallelism_efficiency": 0.251},
39
+ {"name": "llama-3-3-70b-instruct", "overall_score": 0.558, "valid_tool_name_rate": 99.5, "schema_compliance": 93.1, "execution_success": 91.5, "task_fulfillment": 0.366, "information_grounding": 0.476, "tool_appropriateness": 0.554, "parameter_accuracy": 0.486, "dependency_awareness": 0.359, "parallelism_efficiency": 0.244},
40
+ {"name": "gpt-4o-mini", "overall_score": 0.557, "valid_tool_name_rate": 95.5, "schema_compliance": 86.5, "execution_success": 84.0, "task_fulfillment": 0.426, "information_grounding": 0.453, "tool_appropriateness": 0.556, "parameter_accuracy": 0.499, "dependency_awareness": 0.359, "parallelism_efficiency": 0.230},
41
+ {"name": "mistral-small-2503", "overall_score": 0.530, "valid_tool_name_rate": 92.0, "schema_compliance": 95.6, "execution_success": 87.2, "task_fulfillment": 0.344, "information_grounding": 0.438, "tool_appropriateness": 0.528, "parameter_accuracy": 0.462, "dependency_awareness": 0.345, "parallelism_efficiency": 0.220},
42
+ {"name": "llama-3-1-70b-instruct", "overall_score": 0.510, "valid_tool_name_rate": 99.2, "schema_compliance": 90.5, "execution_success": 92.5, "task_fulfillment": 0.314, "information_grounding": 0.432, "tool_appropriateness": 0.523, "parameter_accuracy": 0.433, "dependency_awareness": 0.303, "parallelism_efficiency": 0.190},
43
+ {"name": "nova-micro-v1", "overall_score": 0.508, "valid_tool_name_rate": 96.0, "schema_compliance": 93.1, "execution_success": 87.8, "task_fulfillment": 0.339, "information_grounding": 0.419, "tool_appropriateness": 0.504, "parameter_accuracy": 0.428, "dependency_awareness": 0.315, "parallelism_efficiency": 0.212},
44
+ {"name": "llama-3-2-90b-vision-instruct", "overall_score": 0.495, "valid_tool_name_rate": 99.6, "schema_compliance": 85.0, "execution_success": 90.9, "task_fulfillment": 0.293, "information_grounding": 0.444, "tool_appropriateness": 0.515, "parameter_accuracy": 0.427, "dependency_awareness": 0.267, "parallelism_efficiency": 0.173},
45
+ {"name": "llama-3-1-8b-instruct", "overall_score": 0.428, "valid_tool_name_rate": 96.1, "schema_compliance": 89.4, "execution_success": 90.9, "task_fulfillment": 0.261, "information_grounding": 0.295, "tool_appropriateness": 0.352, "parameter_accuracy": 0.310, "dependency_awareness": 0.221, "parallelism_efficiency": 0.141}
46
+ ]
47
+
48
+ # Sort by overall score descending
49
+ models.sort(key=lambda x: x['overall_score'], reverse=True)
50
+
51
+ rows = []
52
+ for model in models:
53
+ row = f'''<tr>
54
+ <td class="model-col"><span class="model-name">{model['name']}</span></td>
55
+ <td class="score-col"><span class="score">{model['overall_score']:.3f}</span></td>
56
+ <td class="metric-col">{model['valid_tool_name_rate']:.1f}%</td>
57
+ <td class="metric-col">{model['schema_compliance']:.1f}%</td>
58
+ <td class="metric-col">{model['execution_success']:.1f}%</td>
59
+ <td class="metric-col">{model['task_fulfillment']:.3f}</td>
60
+ <td class="metric-col">{model['information_grounding']:.3f}</td>
61
+ <td class="metric-col">{model['tool_appropriateness']:.3f}</td>
62
+ <td class="metric-col">{model['parameter_accuracy']:.3f}</td>
63
+ <td class="metric-col">{model['dependency_awareness']:.3f}</td>
64
+ <td class="metric-col">{model['parallelism_efficiency']:.3f}</td>
65
+ </tr>'''
66
+ rows.append(row)
67
+
68
+ return '\n'.join(rows)
69
+
70
  def create_gradio_app():
71
  """
72
  Gradio app to serve the static HTML leaderboard with embedded images
 
81
  with open('style.css', 'r', encoding='utf-8') as f:
82
  css_content = f.read()
83
 
 
 
 
 
84
  # Convert images to base64 for embedding
85
  diagram_b64 = encode_image_to_base64('mcp-bench.png')
86
  ranking_b64 = encode_image_to_base64('ranking.png')
 
94
  f'src="{ranking_b64}"'
95
  )
96
 
97
+ # Generate static table HTML
98
+ table_html = generate_table_html()
99
+
100
+ # Replace the empty tbody with pre-generated content
101
  combined_html = html_content.replace(
102
+ '<tbody id="tableBody">\n <!-- Table rows will be generated by JavaScript -->\n </tbody>',
103
+ f'<tbody id="tableBody">{table_html}</tbody>'
104
+ ).replace(
105
  '<link rel="stylesheet" href="style.css">',
106
  f'<style>{css_content}</style>'
 
 
 
107
  )
108
 
109
+ # The HTML already has the minimal JavaScript for citation copy and date update
110
+
111
  # Create the Gradio interface
112
  with gr.Blocks(
113
  title="MCP-Bench Leaderboard",
114
  theme=gr.themes.Soft(),
115
+ css="""
116
+ .gradio-container { padding: 0 !important; }
117
+ #leaderboard-container {
118
+ width: 100% !important;
119
+ max-width: none !important;
120
+ margin: 0 !important;
121
+ padding: 0 !important;
122
+ }
123
+ #leaderboard-container * {
124
+ box-sizing: border-box;
125
+ }
126
+ /* Force button text to be white and remove underlines */
127
+ #leaderboard-container .paper-link {
128
+ color: white !important;
129
+ background-color: #4285F4 !important;
130
+ text-decoration: none !important;
131
+ }
132
+ #leaderboard-container .paper-link:hover,
133
+ #leaderboard-container .paper-link:focus,
134
+ #leaderboard-container .paper-link:visited,
135
+ #leaderboard-container .paper-link:active {
136
+ color: white !important;
137
+ background-color: #3367D6 !important;
138
+ text-decoration: none !important;
139
+ }
140
+ /* Fix font issues for authors */
141
+ #leaderboard-container .paper-authors {
142
+ font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
143
+ }
144
+ /* Remove any underlines from links globally */
145
+ #leaderboard-container a {
146
+ text-decoration: none !important;
147
+ }
148
+ """
149
  ) as demo:
150
  gr.HTML(
151
  combined_html,
index.html CHANGED
@@ -48,78 +48,42 @@
48
  <section class="leaderboard-section" id="leaderboard">
49
  <h2 class="section-title">Detailed Results</h2>
50
 
51
- <div class="controls">
52
- <div class="search-container">
53
- <i class="fas fa-search"></i>
54
- <input type="text" id="searchInput" placeholder="Search models..." class="search-input">
55
- </div>
56
-
57
- <div class="filter-container">
58
- <label for="sortSelect">Sort by:</label>
59
- <select id="sortSelect" class="sort-select">
60
- <option value="overall_score">Overall Score</option>
61
- <option value="valid_tool_schema">Valid Tool Schema</option>
62
- <option value="compliance">Compliance</option>
63
- <option value="task_success">Task Success</option>
64
- <option value="schema_understanding">Schema Understanding</option>
65
- <option value="task_completion">Task Completion</option>
66
- <option value="tool_usage">Tool Usage</option>
67
- <option value="planning_effectiveness">Planning Effectiveness</option>
68
- </select>
69
-
70
- <button id="sortOrder" class="sort-btn" title="Toggle sort order">
71
- <i class="fas fa-sort-amount-down"></i>
72
- </button>
73
- </div>
74
- </div>
75
-
76
  <div class="table-container">
77
  <table class="leaderboard-table" id="leaderboardTable">
78
  <thead>
79
  <tr>
80
- <th class="model-col sortable" data-column="name">
81
  <strong>Model</strong>
82
- <i class="fas fa-sort sort-icon"></i>
83
  </th>
84
- <th class="score-col sortable" data-column="overall_score">
85
  <strong>Overall Score</strong>
86
- <i class="fas fa-sort sort-icon"></i>
87
  </th>
88
- <th class="metric-col sortable" data-column="valid_tool_name_rate">
89
  Valid Tool<br>Name Rate
90
- <i class="fas fa-sort sort-icon"></i>
91
  </th>
92
- <th class="metric-col sortable" data-column="schema_compliance">
93
  Schema<br>Compliance
94
- <i class="fas fa-sort sort-icon"></i>
95
  </th>
96
- <th class="metric-col sortable" data-column="execution_success">
97
  Execution<br>Success
98
- <i class="fas fa-sort sort-icon"></i>
99
  </th>
100
- <th class="metric-col sortable" data-column="task_fulfillment">
101
  Task<br>Fulfillment
102
- <i class="fas fa-sort sort-icon"></i>
103
  </th>
104
- <th class="metric-col sortable" data-column="information_grounding">
105
  Information<br>Grounding
106
- <i class="fas fa-sort sort-icon"></i>
107
  </th>
108
- <th class="metric-col sortable" data-column="tool_appropriateness">
109
  Tool<br>Appropriateness
110
- <i class="fas fa-sort sort-icon"></i>
111
  </th>
112
- <th class="metric-col sortable" data-column="parameter_accuracy">
113
  Parameter<br>Accuracy
114
- <i class="fas fa-sort sort-icon"></i>
115
  </th>
116
- <th class="metric-col sortable" data-column="dependency_awareness">
117
  Dependency<br>Awareness
118
- <i class="fas fa-sort sort-icon"></i>
119
  </th>
120
- <th class="metric-col sortable" data-column="parallelism_efficiency">
121
  Parallelism<br>and Efficiency
122
- <i class="fas fa-sort sort-icon"></i>
123
  </th>
124
  </tr>
125
  </thead>
@@ -129,10 +93,6 @@
129
  </table>
130
  </div>
131
 
132
- <div class="loading" id="loading">
133
- <i class="fas fa-spinner fa-spin"></i>
134
- Loading leaderboard data...
135
- </div>
136
 
137
  </section>
138
 
@@ -158,6 +118,30 @@
158
  </footer>
159
  </div>
160
 
161
- <script src="script.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  </body>
163
  </html>
 
48
  <section class="leaderboard-section" id="leaderboard">
49
  <h2 class="section-title">Detailed Results</h2>
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  <div class="table-container">
52
  <table class="leaderboard-table" id="leaderboardTable">
53
  <thead>
54
  <tr>
55
+ <th class="model-col">
56
  <strong>Model</strong>
 
57
  </th>
58
+ <th class="score-col">
59
  <strong>Overall Score</strong>
 
60
  </th>
61
+ <th class="metric-col">
62
  Valid Tool<br>Name Rate
 
63
  </th>
64
+ <th class="metric-col">
65
  Schema<br>Compliance
 
66
  </th>
67
+ <th class="metric-col">
68
  Execution<br>Success
 
69
  </th>
70
+ <th class="metric-col">
71
  Task<br>Fulfillment
 
72
  </th>
73
+ <th class="metric-col">
74
  Information<br>Grounding
 
75
  </th>
76
+ <th class="metric-col">
77
  Tool<br>Appropriateness
 
78
  </th>
79
+ <th class="metric-col">
80
  Parameter<br>Accuracy
 
81
  </th>
82
+ <th class="metric-col">
83
  Dependency<br>Awareness
 
84
  </th>
85
+ <th class="metric-col">
86
  Parallelism<br>and Efficiency
 
87
  </th>
88
  </tr>
89
  </thead>
 
93
  </table>
94
  </div>
95
 
 
 
 
 
96
 
97
  </section>
98
 
 
118
  </footer>
119
  </div>
120
 
121
+ <script>
122
+ // Copy citation function
123
+ function copyCitation() {
124
+ const citationText = document.querySelector('.citation-text').textContent;
125
+ navigator.clipboard.writeText(citationText).then(() => {
126
+ const button = document.querySelector('.copy-citation-btn');
127
+ const originalText = button.innerHTML;
128
+ button.innerHTML = '<i class="fas fa-check"></i> Copied!';
129
+ button.style.backgroundColor = '#4caf50';
130
+
131
+ setTimeout(() => {
132
+ button.innerHTML = originalText;
133
+ button.style.backgroundColor = '';
134
+ }, 2000);
135
+ });
136
+ }
137
+
138
+ // Update last updated date
139
+ document.addEventListener('DOMContentLoaded', function() {
140
+ const lastUpdated = document.getElementById('lastUpdated');
141
+ if (lastUpdated) {
142
+ lastUpdated.textContent = 'December 2024';
143
+ }
144
+ });
145
+ </script>
146
  </body>
147
  </html>
script.js CHANGED
@@ -275,10 +275,12 @@ class LeaderboardApp {
275
 
276
  async init() {
277
  try {
 
278
  this.loadData();
279
  this.setupEventListeners();
280
  this.renderTable();
281
  this.updateLastUpdated();
 
282
  } catch (error) {
283
  console.error('Failed to initialize app:', error);
284
  this.showError('Failed to load leaderboard data');
@@ -287,14 +289,24 @@ class LeaderboardApp {
287
 
288
  loadData() {
289
  const loading = document.getElementById('loading');
290
- loading.classList.add('active');
 
 
291
 
292
  try {
 
293
  this.data = LEADERBOARD_DATA;
 
294
  this.filteredData = [...this.data.models];
 
295
  this.sortData();
 
 
 
296
  } finally {
297
- loading.classList.remove('active');
 
 
298
  }
299
  }
300
 
@@ -383,10 +395,16 @@ class LeaderboardApp {
383
  renderTable() {
384
  const tableBody = document.getElementById('tableBody');
385
 
386
- if (this.filteredData.length === 0) {
 
 
 
 
 
 
387
  tableBody.innerHTML = `
388
  <tr>
389
- <td colspan="9" class="no-results">
390
  <i class="fas fa-search"></i>
391
  No models found matching your search criteria
392
  </td>
@@ -395,6 +413,7 @@ class LeaderboardApp {
395
  return;
396
  }
397
 
 
398
  tableBody.innerHTML = this.filteredData
399
  .map((model) => this.createTableRow(model))
400
  .join('');
 
275
 
276
  async init() {
277
  try {
278
+ console.log('Starting LeaderboardApp initialization...');
279
  this.loadData();
280
  this.setupEventListeners();
281
  this.renderTable();
282
  this.updateLastUpdated();
283
+ console.log('LeaderboardApp initialization complete');
284
  } catch (error) {
285
  console.error('Failed to initialize app:', error);
286
  this.showError('Failed to load leaderboard data');
 
289
 
290
  loadData() {
291
  const loading = document.getElementById('loading');
292
+ if (loading) {
293
+ loading.classList.add('active');
294
+ }
295
 
296
  try {
297
+ console.log('Loading LEADERBOARD_DATA...');
298
  this.data = LEADERBOARD_DATA;
299
+ console.log('Data loaded, models count:', this.data.models ? this.data.models.length : 0);
300
  this.filteredData = [...this.data.models];
301
+ console.log('Filtered data initialized with', this.filteredData.length, 'models');
302
  this.sortData();
303
+ console.log('Data sorted');
304
+ } catch (error) {
305
+ console.error('Error loading data:', error);
306
  } finally {
307
+ if (loading) {
308
+ loading.classList.remove('active');
309
+ }
310
  }
311
  }
312
 
 
395
  renderTable() {
396
  const tableBody = document.getElementById('tableBody');
397
 
398
+ if (!tableBody) {
399
+ console.error('tableBody element not found!');
400
+ return;
401
+ }
402
+
403
+ if (!this.filteredData || this.filteredData.length === 0) {
404
+ console.log('No filtered data to display');
405
  tableBody.innerHTML = `
406
  <tr>
407
+ <td colspan="11" class="no-results">
408
  <i class="fas fa-search"></i>
409
  No models found matching your search criteria
410
  </td>
 
413
  return;
414
  }
415
 
416
+ console.log(`Rendering ${this.filteredData.length} models`);
417
  tableBody.innerHTML = this.filteredData
418
  .map((model) => this.createTableRow(model))
419
  .join('');
style.css CHANGED
@@ -100,7 +100,7 @@ body {
100
  padding: 10px 20px;
101
  background-color: var(--primary-color);
102
  color: white;
103
- text-decoration: none;
104
  border-radius: var(--border-radius);
105
  font-weight: 500;
106
  transition: all 0.3s ease;
@@ -112,25 +112,15 @@ body {
112
  transform: translateY(-2px);
113
  box-shadow: var(--shadow-md);
114
  color: white;
115
- text-decoration: none;
116
  }
117
 
118
- /* Specific colors for different links */
119
- .paper-link[href*="github"] {
120
- background-color: #333333;
 
121
  }
122
 
123
- .paper-link[href*="github"]:hover {
124
- background-color: #555555;
125
- }
126
-
127
- .paper-link[href*="arxiv"] {
128
- background-color: #b31b1b;
129
- }
130
-
131
- .paper-link[href*="arxiv"]:hover {
132
- background-color: #d41e1e;
133
- }
134
 
135
  .diagram-section {
136
  text-align: center;
 
100
  padding: 10px 20px;
101
  background-color: var(--primary-color);
102
  color: white;
103
+ text-decoration: none !important;
104
  border-radius: var(--border-radius);
105
  font-weight: 500;
106
  transition: all 0.3s ease;
 
112
  transform: translateY(-2px);
113
  box-shadow: var(--shadow-md);
114
  color: white;
115
+ text-decoration: none !important;
116
  }
117
 
118
+ .paper-link:focus,
119
+ .paper-link:visited,
120
+ .paper-link:active {
121
+ text-decoration: none !important;
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
  .diagram-section {
126
  text-align: center;