diff --git a/app/comp/res_common.py b/app/comp/res_common.py
index bbb14ca342e8511411066642d5a5a18f932a8a92..fbd12ae58756f7b8e363d99b73548241b344b7dd 100644
--- a/app/comp/res_common.py
+++ b/app/comp/res_common.py
@@ -749,13 +749,22 @@ class ResultatsSemestre(ResultatsCache):
                     val = ""
 
             col_id = f"moy_{modimpl.module.type_abbrv()}_{modimpl.id}_{ue.id}"
-            val_fmt = val_fmt_html = table.fmt_note(val)
+
+            val_fmt_html = val_fmt = table.fmt_note(val)
             if modimpl.module.module_type == scu.ModuleType.MALUS:
-                val_fmt_html = (
-                    (scu.EMO_RED_TRIANGLE_DOWN + val_fmt)
-                    if val and not np.isnan(val)
-                    else ""
-                )
+                if val and not isinstance(val, str) and not np.isnan(val):
+                    if val >= 0:
+                        val_fmt_html = f"""<span class="red-arrow-down"></span><span class="sp2l">+{
+                            val_fmt
+                        }</span>"""
+                    else:
+                        # val_fmt_html = (scu.EMO_RED_TRIANGLE_DOWN + val_fmt)
+                        val_fmt_html = f"""<span class="green-arrow-up"></span><span class="sp2l malus_negatif">-{
+                            table.fmt_note(-val)
+                        }</span>"""
+                else:
+                    val_fmt = val_fmt_html = ""  # inscrit à ce malus, mais sans note
+
             cell = row.add_cell(
                 col_id,
                 modimpl.module.code,
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index cb5e0344ef6aa41fd9b1c82e89861bf38836d431..808031f406a04d3e1be60b105132ea626c528ee2 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -4143,6 +4143,15 @@ table.table_recap td.col_ues_validables {
   border-bottom: 8px solid rgb(48, 239, 0);
 }
 
+.red-arrow-down {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  border-left: 8px solid transparent;
+  border-right: 8px solid transparent;
+  border-top: 8px solid red;
+}
+
 table.table_recap td.col_ue_bonus,
 table.table_recap th.col_ue_bonus {
   font-size: 80%;
@@ -4150,10 +4159,14 @@ table.table_recap th.col_ue_bonus {
   color: rgb(0, 128, 11);
 }
 
-table.table_recap td.col_ue_bonus>span.sp2l {
+table.table_recap span.sp2l {
   margin-left: 2px;
 }
 
+table.table_recap .malus_negatif {
+  color: green;
+}
+
 table.table_recap td.col_ue_bonus {
   white-space: nowrap;
 }
diff --git a/app/static/js/table_recap.js b/app/static/js/table_recap.js
index 62080b4b327c8ecd7db304bbf3c606cab0ea37be..4b45961df8b1cabddd54e863ba95de5076fab640 100644
--- a/app/static/js/table_recap.js
+++ b/app/static/js/table_recap.js
@@ -201,10 +201,10 @@ $(function () {
                             }
                         },
                         {
-                            // Elimine les décorations (fleches bonus/malus) pour les exports
+                            // Elimine les "+"" pour les exports
                             targets: ["col_ue_bonus", "col_malus"],
                             render: function (data, type, row) {
-                                return type === 'export' ? data.replace(/.*(\d\d\.\d\d)/, '$1').replace(/0(\d\..*)/, '$1') : data;
+                                return type === 'export' ? data.replace(/.*\+(\d?\d?\.\d\d).*/m, '$1').replace(/0(\d\..*)/, '$1') : data;
                             }
                         },
                         {