diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index 9b1c5e8c9d68031d13f5896f6a802a5e3c018977..429f96a736be579f7b98f864a2775c9663fb3216 100644
--- a/app/but/jury_but.py
+++ b/app/but/jury_but.py
@@ -207,6 +207,19 @@ class DecisionsProposeesAnnee(DecisionsProposees):
             self.code_valide = self.validation.code
         self.parcour = None
         "Le parcours considéré (celui du semestre pair, ou à défaut impair)"
+        if self.formsemestre_pair is not None:
+            self.res_pair: ResultatsSemestreBUT = res_sem.load_formsemestre_results(
+                self.formsemestre_pair
+            )
+        else:
+            self.res_pair = None
+        if self.formsemestre_impair is not None:
+            self.res_impair: ResultatsSemestreBUT = res_sem.load_formsemestre_results(
+                self.formsemestre_impair
+            )
+        else:
+            self.res_impair = None
+
         self.ues_impair, self.ues_pair = self.compute_ues_annee()  # pylint: disable=all
         self.decisions_ues = {
             ue.id: DecisionsProposeesUE(etud, formsemestre_impair, ue)
@@ -332,14 +345,14 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         """
         etudid = self.etud.id
         ues_sems = []
-        for formsemestre in self.formsemestre_impair, self.formsemestre_pair:
+        for (formsemestre, res) in (
+            (self.formsemestre_impair, self.res_impair),
+            (self.formsemestre_pair, self.res_pair),
+        ):
             if formsemestre is None:
                 ues = []
             else:
                 formation: Formation = formsemestre.formation
-                res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(
-                    formsemestre
-                )
                 # Parcour dans lequel l'étudiant est inscrit, et liste des UEs
                 if res.etuds_parcour_id[etudid] is None:
                     # pas de parcour: prend toutes les UEs (non bonus)
diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py
index e19d5fc3fe595b38086f20ccd7b55599cf5985b3..346b89e5ee662419921e8c3b96c562d8a0c025f3 100644
--- a/app/but/jury_but_recap.py
+++ b/app/but/jury_but_recap.py
@@ -11,6 +11,7 @@ import time
 from flask import g, url_for
 
 from app.but import jury_but
+from app.but.jury_but import DecisionsProposeesAnnee
 from app.comp.res_but import ResultatsSemestreBUT
 from app.comp import res_sem
 from app.models.but_validations import RegroupementCoherentUE
@@ -65,7 +66,7 @@ def formsemestre_saisie_jury_but(
     )
     H = [
         html_sco_header.sco_header(
-            page_title=f"{formsemestre2.sem_modalite()}: moyennes",
+            page_title=f"{formsemestre2.sem_modalite()}: jury BUT annuel",
             no_side_bar=True,
             init_qtip=True,
             javascripts=["js/etud_info.js", "js/table_recap.js"],
@@ -123,6 +124,7 @@ class RowCollector:
         self.titles = titles
         self.row = cells or {}  # col_id : str
         self.idx = 0
+        self.last_etud_cell_idx = 0
         if convert_values:
             self.fmt_note = scu.fmt_note
         else:
@@ -175,6 +177,7 @@ class RowCollector:
         self["_nom_short_target_attrs"] = f'class="etudinfo" id="{etud.id}"'
         self["_nom_disp_target"] = self["_nom_short_target"]
         self["_nom_disp_target_attrs"] = self["_nom_short_target_attrs"]
+        self.last_etud_cell_idx = self.idx
 
     def add_ue_cell(self, ue: UniteEns, val):
         "cell de moyenne d'UE"
@@ -196,18 +199,48 @@ class RowCollector:
         val = rcue.moy_rcue
         if isinstance(val, float):
             if val < BUT_BARRE_RCUE:
-                note_class = " moy_inf"
+                note_class = " moy_ue_inf"
             elif val >= BUT_BARRE_RCUE:
                 note_class = " moy_ue_valid"
             if val < BUT_RCUE_SUFFISANT:
                 note_class = " moy_ue_warning"  # notes très basses
         self.add_cell(
             col_id,
-            f"{rcue.ue_1.acronyme}-{rcue.ue_2.acronyme}",
+            f"<div>{rcue.ue_1.acronyme}</div><div>{rcue.ue_2.acronyme}</div>",
             self.fmt_note(val),
-            "col_ue" + note_class,
+            "col_rcue" + note_class,
         )
 
+    def add_nb_rcues_cell(self, deca: DecisionsProposeesAnnee):
+        "cell avec nb niveaux validables / total"
+        klass = " "
+        if deca.nb_rcues_under_8 > 0:
+            klass += "moy_ue_warning"
+        elif deca.nb_validables < deca.nb_competences:
+            klass += "moy_ue_inf"
+        else:
+            klass += "moy_ue_valid"
+        self.add_cell(
+            "rcues_validables",
+            "RCUEs",
+            f"""{deca.nb_validables}/{deca.nb_competences}"""
+            + ((" " + scu.EMO_WARNING) if deca.nb_rcues_under_8 > 0 else ""),
+            "col_rcue col_rcues_validables" + klass,
+        )
+        if len(deca.rcues_annee) > 0:
+            # permet un tri par nb de niveaux validables + moyenne gen indicative S_pair
+            if deca.res_pair and deca.etud.id in deca.res_pair.etud_moy_gen:
+                moy_gen_d = f"{int(deca.res_pair.etud_moy_gen[deca.etud.id]*1000):05}"
+            else:
+                moy_gen_d = "x"
+            self["_rcues_validables_order"] = f"{deca.nb_validables:04d}-{moy_gen_d}"
+        else:
+            # etudiants sans RCUE: pas de semestre impair, ...
+            # les classe à la fin
+            self[
+                "_rcues_validables_order"
+            ] = f"{deca.nb_validables:04d}-00000-{deca.etud.sort_key}"
+
 
 def get_table_jury_but(
     formsemestre2: FormSemestre, readonly: bool = False
@@ -221,7 +254,9 @@ def get_table_jury_but(
         deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre2)
         row = RowCollector(titles=titles)
         row.add_etud_cells(etud, formsemestre2)
-
+        row.idx = 100  # laisse place pour les colonnes de groupes
+        # --- Nombre de niveaux
+        row.add_nb_rcues_cell(deca)
         # --- Les RCUEs
         for rcue in deca.rcues_annee:
             row.add_ue_cell(rcue.ue_1, rcue.moy_ue_1)
@@ -251,7 +286,8 @@ def get_table_jury_but(
                 """,
             )
         rows.append(row.row)
-    res2.recap_add_partitions(rows, titles)
+    if len(rows) > 0:
+        res2.recap_add_partitions(rows, titles, col_idx=row.last_etud_cell_idx + 1)
     column_ids = [title for title in titles if not title.startswith("_")]
     column_ids.sort(key=lambda col_id: titles.get("_" + col_id + "_col_order", 1000))
     rows.sort(key=lambda row: row["_nom_disp_order"])
diff --git a/app/comp/res_common.py b/app/comp/res_common.py
index 722d4ecb260a2670a5075abb00b8e9e268135b6e..3b5f08964c9570a5be1cc65a61b8e5432c926a5c 100644
--- a/app/comp/res_common.py
+++ b/app/comp/res_common.py
@@ -829,7 +829,7 @@ class ResultatsSemestre(ResultatsCache):
                 else:
                     row[f"_{cid}_class"] = "admission"
 
-    def recap_add_partitions(self, rows: list[dict], titles: dict):
+    def recap_add_partitions(self, rows: list[dict], titles: dict, col_idx: int = None):
         """Ajoute les colonnes indiquant les groupes
         rows est une liste de dict avec une clé "etudid"
         Les colonnes ont la classe css "partition"
@@ -838,7 +838,7 @@ class ResultatsSemestre(ResultatsCache):
             self.formsemestre.id
         )
         first_partition = True
-        col_order = 10
+        col_order = 10 if col_idx is None else col_idx
         for partition in partitions:
             cid = f"part_{partition['partition_id']}"
             rg_cid = cid + "_rg"  # rang dans la partition
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 95e76fb2b038fcae4d00ce793a768d1285ae51cd..6b41b761b1d9518e6d3ed127473c5162821da179 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -2371,7 +2371,6 @@ td.recap_col_ue_inf {
   padding-right: 1.2em;
   padding-left: 4px;
   text-align: left;
-  font-weight: bold;
   color: rgb(255, 0, 0);
   border-left: 1px solid blue;
 }
@@ -2380,7 +2379,6 @@ td.recap_col_ue_val {
   padding-right: 1.2em;
   padding-left: 4px;
   text-align: left;
-  font-weight: bold;
   color: rgb(0, 140, 0);
   border-left: 1px solid blue;
 }
@@ -3773,6 +3771,19 @@ table.table_recap .group {
   border-left: 1px solid blue;
 }
 
+table.table_recap .col_ue {
+  font-weight: bold;
+}
+
+table.table_recap.jury .col_ue {
+  font-weight: normal;
+}
+
+table.table_recap.jury .col_rcue {
+  font-weight: bold;
+}
+
+
 table.table_recap .group {
   border-left: 1px dashed rgb(160, 160, 160);
   white-space: nowrap;
@@ -3817,18 +3828,15 @@ table.table_recap td.moy_inf {
 }
 
 table.table_recap td.moy_ue_valid {
-  font-weight: bold;
   color: rgb(0, 140, 0);
 }
 
 table.table_recap td.moy_ue_warning {
-  font-weight: bold;
   color: rgb(255, 0, 0);
 }
 
 table.table_recap td.col_ues_validables {
   white-space: nowrap;
-  font-weight: bold;
   font-style: normal !important;
 }