diff --git a/app/forms/main/config_logos.py b/app/forms/main/config_logos.py
index 6529907d823a34fa61b37ef2aae243f11d8e515f..31f8bc6ffa5b63c3caf969b66541fbe7e06d04b8 100644
--- a/app/forms/main/config_logos.py
+++ b/app/forms/main/config_logos.py
@@ -46,10 +46,8 @@ from app.scodoc.sco_config_actions import LogoInsert
 from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc.sco_logos import find_logo
 
-
-JAVASCRIPTS = html_sco_header.BOOTSTRAP_JS + []
-
 CSSSTYLES = html_sco_header.BOOTSTRAP_CSS
+JAVASCRIPTS = html_sco_header.BOOTSTRAP_JS
 
 # class ItemForm(FlaskForm):
 #     """Unused Generic class to document common behavior for classes
diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py
index 9c2c2880c48956d3097247d9ee22ca1d40c98e42..f37a55f68fd9ed65522527e9cdb786ca4d6279bd 100644
--- a/app/scodoc/gen_tables.py
+++ b/app/scodoc/gen_tables.py
@@ -57,7 +57,6 @@ from reportlab.lib.units import cm
 
 from flask import render_template
 
-from app.scodoc import html_sco_header
 from app.scodoc import sco_utils as scu
 from app.scodoc import sco_excel
 from app.scodoc import sco_pdf
diff --git a/app/scodoc/sco_archives_etud.py b/app/scodoc/sco_archives_etud.py
index 9b332b030556e8e7633c50bb8f7177ba19bcec8c..b7ff7d32b07b18f30253b6bf1bf73a42fe993a0b 100644
--- a/app/scodoc/sco_archives_etud.py
+++ b/app/scodoc/sco_archives_etud.py
@@ -41,10 +41,8 @@ from app.scodoc import sco_groups
 from app.scodoc import sco_trombino
 from app.scodoc import sco_archives
 from app.scodoc.sco_permissions import Permission
-from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
+from app.scodoc.sco_exceptions import AccessDenied
 from app.scodoc.TrivialFormulator import TrivialFormulator
-from app.scodoc import html_sco_header
-from app.scodoc import sco_etud
 
 
 class EtudsArchiver(sco_archives.BaseArchiver):
@@ -142,9 +140,6 @@ def etud_upload_file_form(etudid):
     etud = Identite.get_etud(etudid)
 
     H = [
-        html_sco_header.sco_header(
-            page_title=f"Chargement d'un document associé à {etud.nomprenom}",
-        ),
         f"""<h2>Chargement d'un document associé à {etud.nomprenom}</h2>
 
         <p>Le fichier ne doit pas dépasser {
@@ -171,8 +166,12 @@ def etud_upload_file_form(etudid):
         cancelbutton="Annuler",
     )
     if tf[0] == 0:
-        return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
-    elif tf[0] == -1:
+        return render_template(
+            "sco_page.j2",
+            title=f"Chargement d'un document associé à {etud.nomprenom}",
+            content="\n".join(H) + tf[1],
+        )
+    if tf[0] == -1:
         return flask.redirect(etud.url_fiche())
     data = tf[2]["datafile"].read()
     descr = tf[2]["description"]
@@ -263,9 +262,6 @@ def etudarchive_generate_excel_sample(group_id=None):
 def etudarchive_import_files_form(group_id):
     """Formulaire pour importation fichiers d'un groupe"""
     H = [
-        html_sco_header.sco_header(
-            page_title="Import de fichiers associés aux étudiants"
-        ),
         """<h2 class="formsemestre">Téléchargement de fichier associés aux étudiants</h2>
         <p>Les fichiers associés (dossiers d'admission, certificats, ...), de
         types quelconques (pdf, doc, images) sont accessibles aux utilisateurs via
@@ -292,7 +288,6 @@ def etudarchive_import_files_form(group_id):
          """
         % group_id,
     ]
-    F = html_sco_header.sco_footer()
     tf = TrivialFormulator(
         request.base_url,
         scu.get_request_args(),
@@ -313,7 +308,11 @@ def etudarchive_import_files_form(group_id):
     )
 
     if tf[0] == 0:
-        return "\n".join(H) + tf[1] + "</li></ol>" + F
+        return render_template(
+            "sco_page.j2",
+            title="Import de fichiers associés aux étudiants",
+            content="\n".join(H) + tf[1] + "</li></ol>",
+        )
     # retrouve le semestre à partir du groupe:
     group = sco_groups.get_group(group_id)
     if tf[0] == -1:
diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py
index eb3fb169c6900f4967e9155c1ed5b435658594a5..d0cd13bb1c14eb85d3ab620dccd66b8f37b60e64 100644
--- a/app/scodoc/sco_find_etud.py
+++ b/app/scodoc/sco_find_etud.py
@@ -309,7 +309,7 @@ def search_etud_by_name(term: str) -> list:
 # ---------- Recherche sur plusieurs département
 
 
-def search_etud_in_accessible_depts(
+def search_etuds_in_accessible_depts(
     expnom=None,
 ) -> tuple[list[list[Identite]], list[str]]:
     """
@@ -330,14 +330,14 @@ def search_etud_in_accessible_depts(
     return result, accessible_depts
 
 
-def table_etud_in_accessible_depts(expnom=None):
+def table_etuds_in_accessible_depts(expnom=None):
     """
     Page avec table étudiants trouvés, dans tous les departements.
     Attention: nous sommes ici au niveau de ScoDoc, pas dans un département
     """
-    result, accessible_depts = search_etud_in_accessible_depts(expnom=expnom)
+    result, accessible_depts = search_etuds_in_accessible_depts(expnom=expnom)
     H = [
-        f"""<div class="table_etud_in_accessible_depts">
+        f"""<div class="table_etuds_in_accessible_depts">
         <h3>Recherche multi-département de "<tt>{expnom}</tt>"</h3>
         """,
     ]
@@ -362,7 +362,7 @@ def table_etud_in_accessible_depts(expnom=None):
                 rows=rows,
                 html_sortable=True,
                 html_class="table_leftalign",
-                # table_id="etud_in_accessible_depts",
+                table_id="etuds_in_accessible_depts",
             )
 
             H.append('<div class="table_etud_in_dept">')
@@ -382,8 +382,10 @@ def table_etud_in_accessible_depts(expnom=None):
         </div>
         """
     )
-    return (
-        html_sco_header.scodoc_top_html_header(page_title="Choix d'un étudiant")
-        + "\n".join(H)
-        + html_sco_header.standard_html_footer()
+    return render_template(
+        "base.j2",
+        title="Choix d'un étudiant",
+        content="\n".join(H),
+        javascripts=["DataTables/datatables.min.js"],
+        cssstyles=["DataTables/datatables.min.css"],
     )
diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py
index 4e2e86741d614b7bcffbd62c6d90dfc9437f8ddf..8ea83d7b0acd0f9445a9a87b99e736c6acff78fb 100644
--- a/app/scodoc/sco_moduleimpl_inscriptions.py
+++ b/app/scodoc/sco_moduleimpl_inscriptions.py
@@ -46,7 +46,6 @@ from app.models import (
     UniteEns,
     Scolog,
 )
-from app.scodoc import html_sco_header
 from app.scodoc import htmlutils
 from app.scodoc import sco_cache
 from app.scodoc import codes_cursus
@@ -82,12 +81,8 @@ def moduleimpl_inscriptions_edit(
     # -- check permission (and lock)
     if not modimpl.can_change_inscriptions():
         return  # can_change_inscriptions raises exception
-    header = html_sco_header.sco_header(
-        page_title="Inscription au module",
-    )
-    footer = html_sco_header.sco_footer()
+
     H = [
-        header,
         f"""<h2>Inscriptions au module <a class="stdlink" href="{
             url_for("notes.moduleimpl_status", scodoc_dept=g.scodoc_dept,
                 moduleimpl_id=moduleimpl_id)
@@ -215,8 +210,9 @@ def moduleimpl_inscriptions_edit(
             )
         )
     #
-    H.append(footer)
-    return "\n".join(H)
+    return render_template(
+        "sco_page.j2", title="Inscriptions au module", content="\n".join(H)
+    )
 
 
 def _make_menu(partitions: list[dict], title="", check="true") -> str:
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index 162c0af892b5a186458e415b6e9bf85aa8f9f30d..c2f604c359aa266371654f8ca1e5562ae2156424 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -47,7 +47,6 @@ from app.models import (
 )
 from app.scodoc import (
     codes_cursus,
-    html_sco_header,
     htmlutils,
     sco_archives_etud,
     sco_bac,
@@ -628,8 +627,10 @@ def fiche_etud(etudid=None):
 </div>
         """
     )
-    header = html_sco_header.sco_header(
-        page_title=f"Fiche étudiant {etud.nomprenom}",
+    return render_template(
+        "sco_page.j2",
+        content=tmpl % info,
+        title=f"Fiche étudiant {etud.nomprenom}",
         cssstyles=[
             "libjs/jQuery-tagEditor/jquery.tag-editor.css",
             "css/jury_but.css",
@@ -644,7 +645,6 @@ def fiche_etud(etudid=None):
             "js/etud_debouche.js",
         ],
     )
-    return header + tmpl % info + html_sco_header.sco_footer()
 
 
 def _format_adresse(adresse: Adresse | None) -> dict:
@@ -874,10 +874,6 @@ def etud_info_html(etudid, with_photo="1", debug=False):
 
     H += "</div>"
     if debug:
-        return (
-            html_sco_header.standard_html_header()
-            + H
-            + html_sco_header.standard_html_footer()
-        )
-    else:
-        return H
+        return render_template("sco_page.j2", title="debug", content=H)
+
+    return H
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index e147f51eaee1242f833199535da66f204e768c8a..3f5f923b1eb31f38b0fb6b0ec771e24c6f53a9de 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -483,7 +483,7 @@ span.dept_cache {
   color: rgb(194, 5, 5);
 }
 
-div.table_etud_in_accessible_depts {
+div.table_etuds_in_accessible_depts {
   margin-left: 3em;
   margin-bottom: 2em;
 }
diff --git a/app/templates/babase.j2 b/app/templates/babase.j2
index 00a1a6dab330b2560908c22e7f9ed3e155dc1bdf..544d3f4e03927c39ac2ad41718f58dce6b0a7cd3 100644
--- a/app/templates/babase.j2
+++ b/app/templates/babase.j2
@@ -10,6 +10,10 @@
     {%- endblock metas %}
 
     {%- block styles %}
+    <link type="text/css" rel="stylesheet"
+      href="{{scu.STATIC_DIR}}/libjs/jquery-ui-1.10.4.custom/css/smoothness/jquery-ui-1.10.4.custom.min.css" />
+    <link type="text/css" rel="stylesheet"
+      href="{{scu.STATIC_DIR}}/libjs/timepicker-1.3.5/jquery.timepicker.min.css" />
     <!-- Bootstrap -->
     <link href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap.css" rel="stylesheet">
     <link type="text/css" rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.css">
diff --git a/app/templates/base.j2 b/app/templates/base.j2
index 24341c4d2287839abfe5f5e96095270f366f202a..fd22d3ea1069d613212c43e0ff9f8e3ee668ce8b 100644
--- a/app/templates/base.j2
+++ b/app/templates/base.j2
@@ -57,7 +57,7 @@
             </ul>
         </div>
     </div>
-    
+
 </nav>
 {% endblock %}
 
@@ -67,7 +67,7 @@
 
 {# application content needs to be provided in the app_content block #}
 <div class="container">
-    {% block app_content %}{% endblock %}
+    {% block app_content %}{{ content | safe }}{% endblock %}
 </div>
 
 <script>
diff --git a/app/templates/sco_page.j2 b/app/templates/sco_page.j2
index 792042003830faa8fd061747bb328b306cbb8b1c..b28df527d7785f94d0e9060bbc0d70545b8c728b 100644
--- a/app/templates/sco_page.j2
+++ b/app/templates/sco_page.j2
@@ -3,10 +3,6 @@
 
 {% block styles %}
 {{super()}}
-<link type="text/css" rel="stylesheet"
-    href="{{scu.STATIC_DIR}}/libjs/jquery-ui-1.10.4.custom/css/smoothness/jquery-ui-1.10.4.custom.min.css" />
-<link type="text/css" rel="stylesheet"
-            href="{{scu.STATIC_DIR}}/libjs/timepicker-1.3.5/jquery.timepicker.min.css" />
 <link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/scodoc.css">
 <link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/scodoc97.css">
 <link href="{{scu.STATIC_DIR}}/css/menu.css" rel="stylesheet" type="text/css" />
diff --git a/app/templates/scodoc.j2 b/app/templates/scodoc.j2
index 235835d230bd7bba387cfb082eff65aa634d30eb..2ff0dbcd24954a145bf8c3ff0c81fbab0ae18de8 100644
--- a/app/templates/scodoc.j2
+++ b/app/templates/scodoc.j2
@@ -45,8 +45,8 @@
 
 
 {% if current_user.is_authenticated %}
-<form action="{{url_for('scodoc.table_etud_in_accessible_depts')}}" method="POST">
-    <b>Chercher étudiant:</b>
+<form action="{{url_for('scodoc.table_etuds_in_accessible_depts')}}">
+    <b>Chercher étudiant&nbsp;:</b>
     <input type="text" name="expnom" width="12" spellcheck="false" value="">
     <input type="submit" value="Chercher">
     <br />(entrer une partie du nom ou le code NIP, cherche dans tous les départements autorisés)
diff --git a/app/views/scodoc.py b/app/views/scodoc.py
index f789313208bc7477391d7e76512733a62d973f12..8096e927a9efaf634b4b074bbd5df25ad0f1065e 100644
--- a/app/views/scodoc.py
+++ b/app/views/scodoc.py
@@ -45,7 +45,6 @@ from flask import (
     url_for,
 )
 from flask import request
-import flask_login
 from flask_login.utils import login_required, current_user
 from PIL import Image as PILImage
 
@@ -54,13 +53,9 @@ from werkzeug.exceptions import BadRequest, NotFound
 
 from app import db, log
 from app import entreprises
-from app.auth.models import User, Role
+from app.auth.models import Role
 from app.auth.cas import set_cas_configuration
-from app.decorators import (
-    admin_required,
-    scodoc7func,
-    scodoc,
-)
+from app.decorators import admin_required
 from app.forms.generic import SimpleConfirmationForm
 from app.forms.main import config_logos, config_main
 from app.forms.main.activate_entreprises import ActivateEntreprisesForm
@@ -112,9 +107,9 @@ def index():
     )
 
 
-# Renvoie les url /ScoDoc/RT/ vers /ScoDoc/RT/Scolarite
-@bp.route("/ScoDoc/<scodoc_dept>/")
-def index_dept(scodoc_dept):
+@bp.route("/ScoDoc/<string:scodoc_dept>/")
+def index_dept(scodoc_dept: str):
+    "Renvoie les url /ScoDoc/RT/ vers /ScoDoc/RT/Scolarite"
     return redirect(url_for("scolar.index_html", scodoc_dept=scodoc_dept))
 
 
@@ -518,11 +513,14 @@ def activate_entreprises():
     )
 
 
-@bp.route("/ScoDoc/table_etud_in_accessible_depts", methods=["POST"])
+@bp.route("/ScoDoc/table_etuds_in_accessible_depts")
 @login_required
-def table_etud_in_accessible_depts():
+def table_etuds_in_accessible_depts():
     """recherche étudiants sur plusieurs départements"""
-    return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"])
+    expnom = request.args.get("expnom")
+    if not expnom:
+        raise ScoValueError("paramètre manquant: expnom")
+    return sco_find_etud.table_etuds_in_accessible_depts(expnom=expnom)
 
 
 # Fonction d'API accessible sans aucun authentification
diff --git a/app/views/users.py b/app/views/users.py
index 48d76a86489c11315283524050bc06c70ad9a24b..0ed67057f9c44f461988d21a58d167acb4517927 100644
--- a/app/views/users.py
+++ b/app/views/users.py
@@ -221,12 +221,7 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
     initvalues = {}
     edit = int(edit)
     all_roles = int(all_roles)
-    H = [
-        html_sco_header.sco_header(
-            javascripts=["js/user_form.js"],
-        )
-    ]
-    F = html_sco_header.sco_footer()
+    H = []
     the_user: User = None
     if edit:
         if not user_name:
@@ -603,7 +598,11 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
         cancelbutton="Annuler",
     )
     if tf[0] == 0:
-        return "\n".join(H) + "\n" + tf[1] + F
+        return render_template(
+            "base.j2",
+            content="\n".join(H) + "\n" + tf[1],
+            javascripts=["js/user_form.js"],
+        )
     elif tf[0] == -1:
         return flask.redirect(url_for("users.index_html", scodoc_dept=g.scodoc_dept))
     else:
@@ -645,7 +644,12 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
             err_msg = f"identifiant {user_name} déjà utilisé"
         if err_msg:
             H.append(tf_error_message(f"""Erreur: {err_msg}"""))
-            return "\n".join(H) + "\n" + tf[1] + F
+            return render_template(
+                "base.j2",
+                content="\n".join(H) + "\n" + tf[1],
+                javascripts=["js/user_form.js"],
+            )
+
         if not edit_only_roles:
             ok_modif, msg = sco_users.check_modif_user(
                 edit,
@@ -660,8 +664,11 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
             )
             if not ok_modif:
                 H.append(tf_error_message(msg))
-                return "\n".join(H) + "\n" + tf[1] + F
-
+                return render_template(
+                    "base.j2",
+                    content="\n".join(H) + "\n" + tf[1],
+                    javascripts=["js/user_form.js"],
+                )
             if "date_expiration" in vals:
                 try:
                     if vals["date_expiration"]:
@@ -670,12 +677,20 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
                         )
                         if vals["date_expiration"] < datetime.datetime.now():
                             H.append(tf_error_message("date expiration passée"))
-                            return "\n".join(H) + "\n" + tf[1] + F
+                            return render_template(
+                                "base.j2",
+                                content="\n".join(H) + "\n" + tf[1],
+                                javascripts=["js/user_form.js"],
+                            )
                     else:
                         vals["date_expiration"] = None
                 except ValueError:
                     H.append(tf_error_message("date expiration invalide"))
-                    return "\n".join(H) + "\n" + tf[1] + F
+                    return render_template(
+                        "base.j2",
+                        content="\n".join(H) + "\n" + tf[1],
+                        javascripts=["js/user_form.js"],
+                    )
 
         if edit:  # modif utilisateur (mais pas password ni user_name !)
             if (not can_choose_dept) and "dept" in vals:
@@ -727,7 +742,11 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
                 msg = tf_error_message(
                     "identifiant invalide (pas d'accents ni de caractères spéciaux)"
                 )
-                return "\n".join(H) + msg + "\n" + tf[1] + F
+                return render_template(
+                    "base.j2",
+                    content="\n".join(H) + msg + "\n" + tf[1],
+                    javascripts=["js/user_form.js"],
+                )
             # Traitement initial (mode) : 3 cas
             # cf énumération Mode
             # A: envoi de welcome + procedure de reset
@@ -754,12 +773,20 @@ def create_user_form(user_name=None, edit=0, all_roles=True):
                         msg = tf_error_message(
                             """Les deux mots de passes ne correspondent pas !"""
                         )
-                        return "\n".join(H) + msg + "\n" + tf[1] + F
+                        return render_template(
+                            "base.j2",
+                            content="\n".join(H) + msg + "\n" + tf[1],
+                            javascripts=["js/user_form.js"],
+                        )
                     if not is_valid_password(vals["password"]):
                         msg = tf_error_message(
                             """Mot de passe trop simple, recommencez !"""
                         )
-                        return "\n".join(H) + msg + "\n" + tf[1] + F
+                        return render_template(
+                            "base.j2",
+                            content="\n".join(H) + msg + "\n" + tf[1],
+                            javascripts=["js/user_form.js"],
+                        )
             # Département:
             if not can_choose_dept:
                 vals["dept"] = auth_dept
@@ -1000,13 +1027,12 @@ def form_change_password(user_name=None):
 
     # check access
     if not can_handle_passwd(user):
-        return "\n".join(
-            [
-                html_sco_header.sco_header(),
-                "<p>Vous n'avez pas la permission de changer ce mot de passe</p>",
-                html_sco_header.sco_footer(),
-            ]
+        return render_template(
+            "base.j2",
+            content="<p>Vous n'avez pas la permission de changer ce mot de passe</p>",
+            title="Accès refusé",
         )
+
     form = ChangePasswordForm(user_name=user.user_name, email=user.email)
     destination = url_for(
         "users.user_info_page",