diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 9b776eb49b1d889b60ca7476034829a50114ed5e..e2b4f3c81a9ae3f52bf1488c2511d4aad522b5d1 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -56,7 +56,6 @@ from app.models import (
 )
 from app.scodoc.sco_permissions import Permission
 from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoTemporaryError
-from app.scodoc import html_sco_header
 from app.scodoc import htmlutils
 from app.scodoc import sco_assiduites
 from app.scodoc import sco_bulletins_generator
@@ -960,7 +959,21 @@ def formsemestre_bulletinetud(
     elif fmt == "pdfmail":
         return ""
     H = [
-        _formsemestre_bulletinetud_header_html(etud, formsemestre, fmt, version),
+        render_template(
+            "bul_head.j2",
+            etud=etud,
+            fmt=fmt,
+            formsemestre=formsemestre,
+            menu_autres_operations=make_menu_autres_operations(
+                etud=etud,
+                formsemestre=formsemestre,
+                endpoint="notes.formsemestre_bulletinetud",
+                version=version,
+            ),
+            scu=scu,
+            time=time,
+            version=version,
+        ),
         bulletin,
         render_template(
             "bul_foot.j2",
@@ -971,10 +984,18 @@ def formsemestre_bulletinetud(
             inscription_courante=etud.inscription_courante(),
             inscription_str=etud.inscription_descr()["inscription_str"],
         ),
-        html_sco_header.sco_footer(),
     ]
-
-    return "".join(H)
+    return render_template(
+        "sco_page.j2",
+        title=f"Bulletin de {etud.nomprenom}",
+        content="".join(H),
+        javascripts=[
+            "js/bulletin.js",
+            "libjs/d3.v3.min.js",
+            "js/radar_bulletin.js",
+        ],
+        cssstyles=["css/radar_bulletin.css"],
+    )
 
 
 def can_send_bulletin_by_mail(formsemestre_id):
@@ -1312,38 +1333,3 @@ def make_menu_autres_operations(
         },
     ]
     return htmlutils.make_menu("Autres opérations", menu_items, alone=True)
-
-
-def _formsemestre_bulletinetud_header_html(
-    etud,
-    formsemestre: FormSemestre,
-    fmt=None,
-    version=None,
-):
-    H = [
-        html_sco_header.sco_header(
-            page_title=f"Bulletin de {etud.nomprenom}",
-            javascripts=[
-                "js/bulletin.js",
-                "libjs/d3.v3.min.js",
-                "js/radar_bulletin.js",
-            ],
-            cssstyles=["css/radar_bulletin.css"],
-        ),
-        render_template(
-            "bul_head.j2",
-            etud=etud,
-            fmt=fmt,
-            formsemestre=formsemestre,
-            menu_autres_operations=make_menu_autres_operations(
-                etud=etud,
-                formsemestre=formsemestre,
-                endpoint="notes.formsemestre_bulletinetud",
-                version=version,
-            ),
-            scu=scu,
-            time=time,
-            version=version,
-        ),
-    ]
-    return "\n".join(H)
diff --git a/app/scodoc/sco_evaluation_check_abs.py b/app/scodoc/sco_evaluation_check_abs.py
index e8865708a9349e4742bf9f12e90eb37ab796871e..83532b136616add6d5f7cd06e4c0e444db64c1c9 100644
--- a/app/scodoc/sco_evaluation_check_abs.py
+++ b/app/scodoc/sco_evaluation_check_abs.py
@@ -33,7 +33,6 @@ from flask_sqlalchemy.query import Query
 from app import db
 from app.models import Evaluation, FormSemestre, Identite, Assiduite
 import app.scodoc.sco_utils as scu
-from app.scodoc import html_sco_header
 from app.scodoc import sco_evaluations
 from app.scodoc import sco_evaluation_db
 from app.scodoc import sco_groups
diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py
index d0cd13bb1c14eb85d3ab620dccd66b8f37b60e64..07c76cb3ad2a4b76901c12a04d9bdd3bc77d7084 100644
--- a/app/scodoc/sco_find_etud.py
+++ b/app/scodoc/sco_find_etud.py
@@ -36,7 +36,6 @@ from app import db
 from app.models import Departement, Identite
 import app.scodoc.notesdb as ndb
 from app.scodoc.gen_tables import GenTable
-from app.scodoc import html_sco_header
 from app.scodoc import sco_etud
 from app.scodoc import sco_groups
 from app.scodoc.sco_exceptions import ScoException
@@ -52,7 +51,7 @@ def form_search_etud(
     title="Rechercher un étudiant par nom : ",
     add_headers=False,  # complete page
 ):
-    "form recherche par nom"
+    "form recherche par nom: utilisé pour choisir un étudiant à inscrire, par exemple"
     H = []
     H.append(
         f"""<form action="{
@@ -93,10 +92,8 @@ def form_search_etud(
     H.append("</form>")
 
     if add_headers:
-        return (
-            html_sco_header.sco_header(page_title="Choix d'un étudiant")
-            + "\n".join(H)
-            + html_sco_header.sco_footer()
+        return render_template(
+            "sco_page.j2", title="Choix d'un étudiant", content="\n".join(H)
         )
     else:
         return "\n".join(H)
diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py
index 28b65a0a8a08c852982f67bbc4034c7dd587e032..a7564b35d6b0f55c088aaa46b1366c71758ff308 100644
--- a/app/scodoc/sco_inscr_passage.py
+++ b/app/scodoc/sco_inscr_passage.py
@@ -31,14 +31,13 @@
 import datetime
 from operator import itemgetter
 
-from flask import url_for, g, request
+from flask import url_for, g, render_template, request
 
 import app.scodoc.notesdb as ndb
 import app.scodoc.sco_utils as scu
 from app import db, log
 from app.models import Formation, FormSemestre, GroupDescr, Identite
 from app.scodoc.gen_tables import GenTable
-from app.scodoc import html_sco_header
 from app.scodoc import sco_cache
 from app.scodoc import codes_cursus
 from app.scodoc import sco_etud
@@ -310,12 +309,7 @@ def formsemestre_inscr_passage(
     # -- check lock
     if not formsemestre.etat:
         raise ScoValueError("opération impossible: semestre verrouille")
-    H = [
-        html_sco_header.sco_header(
-            page_title="Passage des étudiants",
-        )
-    ]
-    footer = html_sco_header.sco_footer()
+    H = []
     etuds = [] if etuds is None else etuds
     if isinstance(etuds, str):
         # string, vient du form de confirmation
@@ -454,8 +448,9 @@ def formsemestre_inscr_passage(
                 )
 
     #
-    H.append(footer)
-    return "\n".join(H)
+    return render_template(
+        "sco_page.j2", title="Passage des étudiants", content="\n".join(H)
+    )
 
 
 def _build_page(
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index 5250af778c77138f7ce47569419576fb7328d354..43dc699dd2a52db43517355a41c764a6765b534e 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -628,7 +628,7 @@ def fiche_etud(etudid=None):
         """
     )
     return render_template(
-        "sco_page.j2",
+        "sco_page_dept.j2",
         content=tmpl % info,
         title=f"Fiche étudiant {etud.nomprenom}",
         cssstyles=[
diff --git a/app/scodoc/sco_pv_forms.py b/app/scodoc/sco_pv_forms.py
index fa651942bfac36a35128ed80b6e9816d51cd62a8..17808d704531b9ddc92e0cd03bd932b3d3ac99ab 100644
--- a/app/scodoc/sco_pv_forms.py
+++ b/app/scodoc/sco_pv_forms.py
@@ -41,7 +41,6 @@ from app.models import FormSemestre, Identite
 
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
-from app.scodoc import html_sco_header
 from app.scodoc import codes_cursus
 from app.scodoc import sco_pv_dict
 from app.scodoc import sco_etud
diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py
index 33b8bb17da2035522e0a3c652b01ca8427567f7f..1c9bbeef0b79df1db25884bb0ec4187f09f84c49 100644
--- a/app/scodoc/sco_recapcomplet.py
+++ b/app/scodoc/sco_recapcomplet.py
@@ -32,8 +32,7 @@ import datetime
 import time
 from xml.etree import ElementTree
 
-from flask import g, request
-from flask import abort, url_for
+from flask import abort, g, render_template, request, url_for
 
 from app import log
 from app.but import bulletin_but
@@ -44,14 +43,12 @@ from app.models import FormSemestre
 from app.models.etudiants import Identite
 
 import app.scodoc.sco_utils as scu
-from app.scodoc import html_sco_header
 from app.scodoc import sco_bulletins_json
 from app.scodoc import sco_bulletins_xml
 from app.scodoc import sco_cache
 from app.scodoc import sco_evaluations
 from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc import sco_formsemestre
-from app.scodoc import sco_formsemestre_status
 from app.scodoc import sco_preferences
 from app.tables.recap import TableRecap
 from app.tables.jury_recap import TableJury
@@ -119,15 +116,9 @@ def formsemestre_recapcomplet(
     )
 
     H = [
-        html_sco_header.sco_header(
-            page_title=f"{formsemestre.sem_modalite()}: "
-            + ("jury" if mode_jury else "moyennes"),
-            no_sidebar=True,
-            javascripts=["js/table_recap.js"],
-        ),
-        sco_formsemestre_status.formsemestre_status_head(
-            formsemestre_id=formsemestre_id
-        ),
+        # sco_formsemestre_status.formsemestre_status_head(
+        #     formsemestre_id=formsemestre_id
+        # ),
     ]
     if len(formsemestre.inscriptions) > 0:
         H.append(
@@ -273,10 +264,17 @@ def formsemestre_recapcomplet(
     </div>
     """
     )
-    H.append(html_sco_header.sco_footer())
     # HTML or binary data ?
     if len(H) > 1:
-        return "".join(H)
+        return render_template(
+            "sco_page.j2",
+            content="".join(H),
+            title=f"{formsemestre.sem_modalite()}: "
+            + ("jury" if mode_jury else "moyennes"),
+            javascripts=["js/table_recap.js"],
+            formsemestre_id=formsemestre_id,
+            no_sidebar=True,
+        )
     elif len(H) == 1:
         return H[0]
     else:
diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py
index 4d0ea01745a5263fb470a9a43724237d110f01d7..4b14360c70ed1ff69836b5d327216e6ff7cf6171 100644
--- a/app/scodoc/sco_saisie_notes.py
+++ b/app/scodoc/sco_saisie_notes.py
@@ -31,7 +31,7 @@ import time
 
 
 import flask
-from flask import g, url_for
+from flask import g, render_template, url_for
 from flask_login import current_user
 from flask_sqlalchemy.query import Query
 import psycopg2
@@ -57,7 +57,6 @@ from app.scodoc.sco_exceptions import (
     ScoInvalidParamError,
     ScoValueError,
 )
-from app.scodoc import html_sco_header
 from app.scodoc import htmlutils
 from app.scodoc import sco_cache
 from app.scodoc import sco_etud
@@ -247,14 +246,15 @@ def do_evaluation_set_missing(
     if len(invalids) > 0:
         diag = f"Valeur {value} invalide ou hors barème"
     if diag:
-        return f"""
-            {html_sco_header.sco_header()}
+        return render_template(
+            "sco_page.j2",
+            content=f"""
             <h2>{diag}</h2>
             <p><a href="{ dest_url }">
             Recommencer</a>
             </p>
-            {html_sco_header.sco_footer()}
-            """
+            """,
+        )
     # Confirm action
     if not dialog_confirmed:
         plural = len(valid_notes) > 1
@@ -293,23 +293,24 @@ def do_evaluation_set_missing(
         url=url,
         max_frequency=30 * 60,
     )
-    return f"""
-        { html_sco_header.sco_header() }
+    return render_template(
+        "sco_page.j2",
+        content=f"""
         <h2>{len(etudids_changed)} notes changées</h2>
         <ul>
-        <li><a class="stdlink" href="{dest_url}">
-        Revenir au formulaire de saisie des notes</a>
-        </li>
-        <li><a class="stdlink" href="{
-            url_for(
-                "notes.moduleimpl_status",
-                scodoc_dept=g.scodoc_dept,
-                moduleimpl_id=evaluation.moduleimpl_id,
-            )}">Tableau de bord du module</a>
-        </li>
+            <li><a class="stdlink" href="{dest_url}">
+            Revenir au formulaire de saisie des notes</a>
+            </li>
+            <li><a class="stdlink" href="{
+                url_for(
+                    "notes.moduleimpl_status",
+                    scodoc_dept=g.scodoc_dept,
+                    moduleimpl_id=evaluation.moduleimpl_id,
+                )}">Tableau de bord du module</a>
+            </li>
         </ul>
-        { html_sco_header.sco_footer() }
-        """
+        """,
+    )
 
 
 def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
@@ -390,7 +391,7 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
             url=status_url,
         )
 
-    return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
+    return render_template("sco_page.j2", content="\n".join(H))
 
 
 def _check_inscription(
@@ -640,16 +641,17 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
     # Check access
     # (admin, respformation, and responsable_id)
     if not evaluation.moduleimpl.can_edit_notes(current_user):
-        return f"""
-            {html_sco_header.sco_header()}
+        return render_template(
+            "sco_page.j2",
+            content=f"""
             <h2>Modification des notes impossible pour {current_user.user_name}</h2>
 
             <p>(vérifiez que le semestre n'est pas verrouillé et que vous
                avez l'autorisation d'effectuer cette opération)</p>
                <p><a href="{ moduleimpl_status_url }">Continuer</a>
             </p>
-            {html_sco_header.sco_footer()}
-            """
+        """,
+        )
 
     # Informations sur les groupes à afficher:
     groups_infos = sco_groups_view.DisplayedGroupsInfos(
@@ -666,11 +668,6 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
     )
     # HTML page:
     H = [
-        html_sco_header.sco_header(
-            page_title=page_title,
-            javascripts=sco_groups_view.JAVASCRIPTS + ["js/saisie_notes.js"],
-            cssstyles=sco_groups_view.CSSSTYLES,
-        ),
         sco_evaluations.evaluation_describe(
             evaluation_id=evaluation_id, link_saisie=False
         ),
@@ -754,9 +751,13 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
     </ul>
     </div>"""
     )
-
-    H.append(html_sco_header.sco_footer())
-    return "\n".join(H)
+    return render_template(
+        "sco_page.j2",
+        content="\n".join(H),
+        title=page_title,
+        javascripts=sco_groups_view.JAVASCRIPTS + ["js/saisie_notes.js"],
+        cssstyles=sco_groups_view.CSSSTYLES,
+    )
 
 
 def get_sorted_etuds_notes(
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index 869444ef24e9072063eff65eab2591d48ae27d35..41841e943b68bb23c513744043d1916658333571 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -31,7 +31,7 @@
 import time
 from operator import itemgetter
 
-from flask import g, url_for
+from flask import g, render_template, url_for
 from flask_login import current_user
 
 from app import db, log
@@ -39,7 +39,6 @@ from app.models import Admission, Adresse, FormSemestre, Identite, ScolarNews
 
 import app.scodoc.sco_utils as scu
 import app.scodoc.notesdb as ndb
-from app.scodoc import html_sco_header
 from app.scodoc import sco_cache
 from app.scodoc import sco_formsemestre
 from app.scodoc import sco_formsemestre_inscriptions
@@ -118,7 +117,6 @@ def formsemestre_synchro_etuds(
         """,
             safe=True,
         )
-    footer = html_sco_header.sco_footer()
     base_url = url_for(
         "notes.formsemestre_synchro_etuds",
         scodoc_dept=g.scodoc_dept,
@@ -168,7 +166,7 @@ def formsemestre_synchro_etuds(
             suffix=scu.XLSX_SUFFIX,
         )
 
-    H = [html_sco_header.sco_header(page_title="Synchronisation étudiants")]
+    H = []
     if not submitted:
         H += _build_page(
             sem,
@@ -300,8 +298,9 @@ def formsemestre_synchro_etuds(
                     """
                 )
 
-    H.append(footer)
-    return "\n".join(H)
+    return render_template(
+        "sco_page.j2", title="Synchronisation des étudiants", content="\n".join(H)
+    )
 
 
 def _build_page(
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index a51790c793f3da2224b3a0784bb201757e63fd43..d189a0ffd9dc0153f0cd469c2201248851c3fdc8 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -55,7 +55,7 @@ from pytz import timezone
 
 
 import flask
-from flask import g, request, Response
+from flask import g, render_template, request, Response
 from flask import flash, make_response
 from flask_json import json_response
 from werkzeug.http import HTTP_STATUS_CODES
@@ -1527,8 +1527,6 @@ def confirm_dialog(
     target_variable="dialog_confirmed",
 ):
     """HTML confirmation dialog: submit (POST) to same page or dest_url if given."""
-    from app.scodoc import html_sco_header
-
     parameters = parameters or {}
     # dialog de confirmation simple
     parameters[target_variable] = 1
@@ -1567,9 +1565,7 @@ def confirm_dialog(
     if help_msg:
         H.append('<p class="help">' + help_msg + "</p>")
     if add_headers:
-        return (
-            html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
-        )
+        return render_template("sco_page.j2", content="\n".join(H))
     else:
         return "\n".join(H)
 
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 9e3cf526c9e481bcae5ab518880bf146c6fd43dd..927eebd2d47b0aa704932f50ac9e1d25a0549eb5 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -58,6 +58,10 @@ div.sco-app-content {
   margin-right: 8px;
 }
 
+.space-before-18 {
+  margin-top: 18px;
+}
+
 div.scobox {
   flex: 1 0 0;
   /* Equal width for all boxes */
@@ -2363,8 +2367,6 @@ span.eval_coef_ue {
   margin-right: 2em;
 }
 
-span.eval_coef_ue_titre {}
-
 /* Inscriptions modules/UE */
 div.list_but_ue_inscriptions {
   margin-top: 16px;
@@ -4258,6 +4260,7 @@ div.apo_csv_status {
 
 .form_apo_export input[type="submit"] {
   -webkit-appearance: button;
+  appearance: button;
   font-size: 150%;
   font-weight: bold;
   color: green;
diff --git a/app/templates/about.j2 b/app/templates/about.j2
index 4d960b1c821c09854fc274a9635fd7613d826488..bc17c7feda1d28bd25a1d8693e3ce304891b7348 100644
--- a/app/templates/about.j2
+++ b/app/templates/about.j2
@@ -6,7 +6,7 @@
 
 <h2>Système de gestion scolarité</h2>
 
-<p>&copy; Emmanuel Viennet 2023</p>
+<p>&copy; Emmanuel Viennet 2024</p>
 
 <p>Version {{ version }}</p>
 
diff --git a/app/templates/bul_head.j2 b/app/templates/bul_head.j2
index 94e6ada6ec08d2666e1e12674cb3bb1704207ee0..639a72ceb339e7688580e588d1dc539e9a256426 100644
--- a/app/templates/bul_head.j2
+++ b/app/templates/bul_head.j2
@@ -1,6 +1,5 @@
 {# -*- mode: jinja-html -*- #}
 {# L'en-tête des bulletins HTML #}
-{# was _formsemestre_bulletinetud_header_html #}
 
 <div class="bull_head">
     <div class="bull_head_text">
diff --git a/app/views/notes.py b/app/views/notes.py
index e97bfcdf4c48d7b8cc2d4f213639ff9f26c4ec42..194e5092f0baa5e94bdd5f3eaf410e24eaa2448d 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -41,7 +41,7 @@ from flask_login import current_user
 from flask_wtf import FlaskForm
 from flask_wtf.file import FileAllowed
 from wtforms.validators import DataRequired, Length
-from wtforms import FileField, HiddenField, StringField, SubmitField
+from wtforms import FileField, StringField, SubmitField
 
 from app import db, log, send_scodoc_alarm
 from app import models
@@ -944,10 +944,10 @@ def edit_enseignants_form(moduleimpl_id):
     modimpl.can_change_ens(raise_exc=True)
     #
     page_title = f"Enseignants du module {modimpl.module.titre or modimpl.module.code}"
-    title = f"""Enseignants du <a href="{
+    title = f"""<h2>Enseignants du <a class="stdlink" href="{
             url_for("notes.moduleimpl_status",
             scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
-        }">module {modimpl.module.titre or modimpl.module.code}</a>"""
+        }">module {modimpl.module.titre or modimpl.module.code}</a></h2>"""
     # Liste des enseignants avec forme pour affichage / saisie avec suggestion
     userlist = sco_users.get_user_list()
     uid2display = {}  # uid : forme pour affichage = "NOM Prenom (login)"(login)"
@@ -972,7 +972,8 @@ def edit_enseignants_form(moduleimpl_id):
             </li>"""
         )
     H.append("</ul>")
-    F = f"""<p class="help">Les enseignants d'un module ont le droit de
+    F = f"""<div class="help space-before-18">
+    <p>Les enseignants d'un module ont le droit de
     saisir et modifier toutes les notes des évaluations de ce module.
     </p>
     <p class="help">Pour changer le responsable du module, passez par la
@@ -982,6 +983,7 @@ def edit_enseignants_form(moduleimpl_id):
         }">Modification du semestre</a>",
     accessible uniquement au responsable de la formation (chef de département)
     </p>
+    </div>
     """
 
     modform = [
@@ -1018,7 +1020,7 @@ def edit_enseignants_form(moduleimpl_id):
         return render_template(
             "sco_page.j2",
             title=page_title,
-            content=title + "\n".join(H) + tf[1],
+            content=title + "\n".join(H) + tf[1] + F,
             javascripts=["libjs/AutoSuggest.js"],
             cssstyles=["css/autosuggest_inquisitor.css"],
         )
@@ -1061,7 +1063,7 @@ def edit_enseignants_form(moduleimpl_id):
         return render_template(
             "sco_page.j2",
             title=page_title,
-            content=title + "\n".join(H) + tf[1],
+            content=title + "\n".join(H) + tf[1] + F,
             javascripts=["libjs/AutoSuggest.js"],
             cssstyles=["css/autosuggest_inquisitor.css"],
         )
@@ -2567,7 +2569,6 @@ def check_sem_integrity(formsemestre_id, fix=False):
             modimpl["mod"] = mod
 
     H = [
-        html_sco_header.sco_header(),
         "<p>formation_id=%s" % sem["formation_id"],
     ]
     if bad_ue:
@@ -2605,7 +2606,7 @@ def check_sem_integrity(formsemestre_id, fix=False):
         else:
             H.append("""<p class="alert">Problème détecté !</p>""")
 
-    return "\n".join(H) + html_sco_header.sco_footer()
+    return render_template("sco_page.j2", content="\n".join(H))
 
 
 @bp.route("/check_form_integrity")
diff --git a/app/views/scolar.py b/app/views/scolar.py
index 455388aaa26e64ba17f98389b8588636285ac19c..424500d24131f1fad6d34f680e56e5368763fa52 100644
--- a/app/views/scolar.py
+++ b/app/views/scolar.py
@@ -82,7 +82,6 @@ from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
 from app.scodoc.gen_tables import GenTable
 from app.scodoc import (
     codes_cursus,
-    html_sco_header,
     sco_import_etuds,
     sco_archives_etud,
     sco_bug_report,
@@ -827,9 +826,7 @@ def form_change_coordonnees(etudid):
     else:
         adr = {}  # no data for this student
     H = [
-        f"""{html_sco_header.sco_header(
-        page_title=f"Changement coordonnées de {etud.nomprenom}"
-    )}
+        f"""
     <h2>Changement des coordonnées de {etud.nomprenom}</h2>
     <p>"""
     ]
@@ -873,7 +870,11 @@ def form_change_coordonnees(etudid):
     )
     dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
     if tf[0] == 0:
-        return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
+        return render_template(
+            "sco_page_dept.j2",
+            title=f"Changement coordonnées de {etud.nomprenom}",
+            content="\n".join(H) + tf[1],
+        )
     elif tf[0] == -1:
         return flask.redirect(dest_url)
     else:
@@ -1004,17 +1005,14 @@ def students_groups_auto_assignment(formsemestre_id: int):
     """Répartition auto des groupes"""
     formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
     H = [
-        html_sco_header.sco_header(
-            page_title="Répartition des groupes",
-        ),
         render_template(
             "scolar/students_groups_auto_assignment.j2",
             formsemestre=formsemestre,
         ),
-        html_sco_header.sco_footer(),
     ]
-
-    return "\n".join(H)
+    return render_template(
+        "sco_page.j2", title="Répartition des groupes", content="\n".join(H)
+    )
 
 
 @bp.route("/create_partition_parcours", methods=["GET", "POST"])
@@ -1049,15 +1047,17 @@ sco_publish("/etud_photo_html", sco_photos.etud_photo_html, Permission.ScoView)
 def etud_photo_orig_page(etudid):
     "Page with photo in orig. size"
     etud = Identite.get_etud(etudid)
-    return f"""{
-        html_sco_header.sco_header(etudid=etud.id, page_title=etud.nomprenom)
-    }
+    return render_template(
+        "sco_page_dept.j2",
+        title=f"Photo de {etud.nomprenom}",
+        content=f"""
     <h2>{etud.nomprenom}</h2>
     <div>
         <a href="{etud.url_fiche()}">{etud.photo_html(size='orig')}</a>
     </div>
-    {html_sco_header.sco_footer()}
-    """
+    """,
+        sco=ScoData(etud=etud),
+    )
 
 
 @bp.route("/form_change_photo", methods=["GET", "POST"])
@@ -1072,8 +1072,8 @@ def form_change_photo(etudid=None):
     else:
         photo_loc = "externe"
     H = [
-        html_sco_header.sco_header(page_title="Changement de photo"),
         f"""<h2>Changement de la photo de {etud.nomprenom}</h2>
+
         <p>Photo actuelle ({photo_loc}):
         {sco_photos.etud_photo_html(etudid=etud.id, title="photo actuelle")}
         </p>
@@ -1098,16 +1098,17 @@ def form_change_photo(etudid=None):
     )
     dest_url = url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
     if tf[0] == 0:
-        return (
-            "\n".join(H)
+        return render_template(
+            "sco_page_dept.j2",
+            title="Changement de photo",
+            content="\n".join(H)
             + f"""
             {tf[1]}
-            <p><a class="stdlink" href="{
+            <div class=""><a class="stdlink" href="{
                 url_for("scolar.form_suppress_photo",
                         scodoc_dept=g.scodoc_dept, etudid=etud.id)
-            }">Supprimer cette photo</a></p>
-            {html_sco_header.sco_footer()}
-        """
+            }">Supprimer cette photo</a></div>
+        """,
         )
     elif tf[0] == -1:
         return flask.redirect(dest_url)
@@ -1120,7 +1121,9 @@ def form_change_photo(etudid=None):
             return flask.redirect(dest_url)
         else:
             H.append(f"""<p class="warning">Erreur: {err_msg}</p>""")
-    return "\n".join(H) + html_sco_header.sco_footer()
+    return render_template(
+        "sco_page_dept.j2", title="Changement de photo", content="\n".join(H)
+    )
 
 
 @bp.route("/form_suppress_photo", methods=["POST", "GET"])
@@ -1191,12 +1194,11 @@ def _form_dem_of_def(
         raise ScoValueError("Modification impossible: semestre verrouille")
     nowdmy = time.strftime(scu.DATE_FMT)
     #
-    header = html_sco_header.sco_header(
-        page_title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})"""
-    )
     validations_descr = formsemestre.etud_validations_description_html(etudid)
-    return f"""
-    {header}
+    return render_template(
+        "sco_page_dept.j2",
+        title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})""",
+        content=f"""
     <h2><font color="#FF0000">{operation_name} de</font> {etud.nomprenom} ({formsemestre.titre_mois()})</h2>
 
     <form action="{operation_method}" method="get">
@@ -1216,8 +1218,8 @@ def _form_dem_of_def(
                     formsemestre_id=formsemestre_id, etudid=etudid)
         + '">modifier ces décisions</a></p>') if validations_descr else ""}
     </div>
-    {html_sco_header.sco_footer()}
-    """
+    """,
+    )
 
 
 @bp.route("/do_dem_etudiant")
@@ -1405,8 +1407,7 @@ def _validate_date_naissance(val: str, field) -> bool:
 
 def _etudident_create_or_edit_form(edit):
     "Le formulaire HTML"
-    H = [html_sco_header.sco_header()]
-    F = html_sco_header.sco_footer()
+    H = []
     vals = scu.get_request_args()
     etudid = vals.get("etudid", None)
     cnx = ndb.GetDBConnexion()
@@ -1767,11 +1768,12 @@ def _etudident_create_or_edit_form(edit):
         cancelbutton="Re-interroger Apogee",
         initvalues=initvalues,
     )
-    if tf[0] == 0:
-        return "\n".join(H) + tf[1] + "<p>" + A + F
-    elif tf[0] == -1:
-        return "\n".join(H) + tf[1] + "<p>" + A + F
-        # return '\n'.join(H) + '<h4>annulation</h4>' + F
+    if tf[0] in (0, -1):
+        return render_template(
+            "sco_page_dept.j2",
+            content="\n".join(H) + tf[1] + "<p>" + A,
+            title="Création/édition d'étudiant",
+        )
     else:
         # form submission
         if edit:
@@ -1783,13 +1785,14 @@ def _etudident_create_or_edit_form(edit):
         )
         nb_homonyms = len(homonyms)
         if not ok:
-            return (
-                "\n".join(H)
+            return render_template(
+                "sco_page_dept.j2",
+                content="\n".join(H)
                 + tf_error_message("Nom ou prénom invalide")
                 + tf[1]
                 + "<p>"
-                + A
-                + F
+                + A,
+                title="Création/édition d'étudiant",
             )
         if not tf[2]["dont_check_homonyms"] and nb_homonyms > 0:
             homonyms_html = f"""
@@ -1801,20 +1804,23 @@ def _etudident_create_or_edit_form(edit):
                 </ul>
             </div>
             """
-            return (
-                "\n".join(H)
-                + tf_error_message(
-                    """Attention: il y a déjà un étudiant portant des noms et prénoms proches
+            return render_template(
+                "sco_page_dept.j2",
+                title="Création/édition d'étudiant",
+                content=(
+                    "\n".join(H)
+                    + tf_error_message(
+                        """Attention: il y a déjà un étudiant portant des noms et prénoms proches
                     (voir liste en bas de page).
                     Vous pouvez forcer la présence d'un homonyme en cochant
                     "autoriser les homonymes" en bas du formulaire.
                     """
-                )
-                + tf[1]
-                + "<p>"
-                + A
-                + homonyms_html
-                + F
+                    )
+                    + tf[1]
+                    + "<p>"
+                    + A
+                    + homonyms_html
+                ),
             )
         tf[2]["date_naissance"] = (
             scu.convert_fr_date(tf[2]["date_naissance"])
@@ -2173,7 +2179,6 @@ def form_students_import_excel(formsemestre_id=None):
     if sem and not sem["etat"]:
         raise ScoValueError("Modification impossible: semestre verrouille")
     H = [
-        html_sco_header.sco_header(page_title="Import etudiants"),
         """<h2 class="formsemestre">Téléchargement d\'une nouvelle liste d\'etudiants</h2>
             <div style="color: red">
             <p>A utiliser pour importer de <b>nouveaux</b> étudiants (typiquement au
@@ -2229,7 +2234,6 @@ def form_students_import_excel(formsemestre_id=None):
     <li>"""
     )
 
-    F = html_sco_header.sco_footer()
     tf = TrivialFormulator(
         request.base_url,
         scu.get_request_args(),
@@ -2285,7 +2289,11 @@ Les champs avec un astérisque (*) doivent être présents (nulls non autorisés
             % (t[0], t[1], t[4], ast)
         )
     if tf[0] == 0:
-        return "\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S) + F
+        return render_template(
+            "sco_page.j2",
+            title="Import etudiants",
+            content="\n".join(H) + tf[1] + "</li></ol>" + "\n".join(S),
+        )
     elif tf[0] == -1:
         return flask.redirect(dest_url)
     else:
@@ -2345,29 +2353,26 @@ def import_generate_admission_sample(formsemestre_id):
 def form_students_import_infos_admissions(formsemestre_id=None):
     "formulaire import xls"
     authuser = current_user
-    F = html_sco_header.sco_footer()
     if not authuser.has_permission(Permission.EtudInscrit):
         # autorise juste l'export
-        H = [
-            html_sco_header.sco_header(
-                page_title="Export données admissions (Parcoursup ou autre)",
-            ),
-            f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission
-            des étudiants</h2>
-            <p>
-            <a href="{ url_for('scolar.import_generate_admission_sample',
-             scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id )
-            }">Exporter les informations de ScoDoc (classeur Excel)</a> (ce fichier
-            peut être ré-importé après d'éventuelles modifications)
-            </p>
-            <p class="warning">Vous n'avez pas le droit d'importer les données</p>
+        return render_template(
+            "sco_page.j2",
+            title="Export données admissions (Parcoursup ou autre)",
+            content=f"""
+        <h2 class="formsemestre">Téléchargement des informations sur l'admission
+        des étudiants</h2>
+        <p>
+        <a href="{ url_for('scolar.import_generate_admission_sample',
+            scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id )
+        }">Exporter les informations de ScoDoc (classeur Excel)</a> (ce fichier
+        peut être ré-importé après d'éventuelles modifications)
+        </p>
+        <p class="warning">Vous n'avez pas le droit d'importer les données</p>
             """,
-        ]
-        return "\n".join(H) + F
+        )
 
     # On a le droit d'importer:
     H = [
-        html_sco_header.sco_header(page_title="Import données admissions Parcoursup"),
         f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission des étudiants
         depuis feuilles import Parcoursup</h2>
         <div style="color: red">
@@ -2451,7 +2456,11 @@ def form_students_import_infos_admissions(formsemestre_id=None):
     )
 
     if tf[0] == 0:
-        return "\n".join(H) + tf[1] + help_text + F
+        return render_template(
+            "sco_page.j2",
+            title="Import données admissions Parcoursup",
+            content="\n".join(H) + tf[1] + help_text,
+        )
     elif tf[0] == -1:
         return flask.redirect(
             url_for(
@@ -2582,13 +2591,15 @@ def sco_dump_and_send_db(message="", request_url="", traceback_str_base64=""):
         Merci de contacter <a href="mailto:{scu.SCO_DEV_MAIL}">{scu.SCO_DEV_MAIL}</a>
         """
 
-    H = [html_sco_header.sco_header(page_title="Assistance technique")]
+    H = []
     if status_code == requests.codes.OK:  # pylint: disable=no-member
         H.append(f"""<p>Opération effectuée.</p><p>{r_msg}</p>""")
     else:
         H.append(f"""<p class="warning">{r_msg}</p>""")
     flash("Données envoyées au serveur d'assistance")
-    return "\n".join(H) + html_sco_header.sco_footer()
+    return render_template(
+        "sco_page_dept.j2", title="Assistance technique", content="\n".join(H)
+    )
 
 
 # --- Report form (assistance)
@@ -2616,12 +2627,14 @@ def sco_bug_report_form():
                 <a href="mailto:{scu.SCO_DEV_MAIL}">{scu.SCO_DEV_MAIL}</a>
             """
 
-        H = [html_sco_header.sco_header(page_title="Assistance technique")]
+        H = []
         if r.status_code >= 200 and r.status_code < 300:
             H.append(f"""<p>Opération effectuée.</p><p>{r_msg}</p>""")
         else:
             H.append(f"""<p class="warning">{r_msg}</p>""")
-        return "\n".join(H) + html_sco_header.sco_footer()
+        return render_template(
+            "sco_page_dept.j2", title="Assistance technique", content="\n".join(H)
+        )
 
     return render_template(
         "sco_bug_report.j2",