diff --git a/scipost_django/forums/forms.py b/scipost_django/forums/forms.py
index 5ee198234354b7a9a61ae5be624fde5e836d03db..b732ca425c36dbfc32533d056134511de244b417 100644
--- a/scipost_django/forums/forms.py
+++ b/scipost_django/forums/forms.py
@@ -61,6 +61,8 @@ class MeetingForm(ForumForm):
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
+        self.fields["preamble"].widget = TextareaWithPreview()
+        self.fields["minutes"].widget = TextareaWithPreview()
         if self.instance:
             self.fields["parent"].initial = self.instance.parent
 
diff --git a/scipost_django/markup/constants.py b/scipost_django/markup/constants.py
index 4be31e14be8369eacc24bda12b5c1ac5c294cb67..ad4fa9761445c8e57deea447ef731acc937bf791 100644
--- a/scipost_django/markup/constants.py
+++ b/scipost_django/markup/constants.py
@@ -2,6 +2,13 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+recognized_markup_languages = {
+    "plain": "plain",
+    "md": "Markdown",
+    "reST": "reStructuredText",
+}
+
+
 # Dictionary for regex expressions to recognize reStructuredText headers.
 # This follows the Python conventions: order is #, *, =, -, ", ^ and
 # for the first two levels (# and *), over- and underlining are necessary, while
diff --git a/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html b/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
index 4f55342302bc4a619c3486d7ccd9c9cb676fe9c6..7c3d2cc4304d307761770dc96eae415d5d754abc 100644
--- a/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
+++ b/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
@@ -1,12 +1,12 @@
 <div style="border: 2px solid orange; padding: 0.5rem;">
   <span style="padding: 0.5rem; background-color: #f3f6ff; color: #004057;">
-    <em><strong>Preview</strong>&emsp;(detected language: <strong>{{ markup.language }}</strong></em>)
+    <em><strong>Preview</strong>&emsp;(markup language: <strong>{{ markup.language }}</strong></em>)
   </span>
   {% if markup.errors %}
-    <span style="text-color: red;">Errors: {{ markup.errors }}</span>
+    &emsp;<span style="color: red;">Errors: {{ markup.errors }}</span>
   {% endif %}
   {% if markup.warnings %}
-    <span style="text-color: orange;">Errors: {{ markup.warnings }}</span>
+    &emsp;<span style="color: orange;">Warnings: {{ markup.warnings }}</span>
   {% endif %}
   <div style="margin: 1rem;">{{ markup.processed|safe }}</div>
 </div>
diff --git a/scipost_django/markup/utils.py b/scipost_django/markup/utils.py
index d40017faae6d14ea02a423f1fa4f60db94343a05..4db7bb0088b6ce39a3350448320796d4de86e1d9 100644
--- a/scipost_django/markup/utils.py
+++ b/scipost_django/markup/utils.py
@@ -13,6 +13,7 @@ from django.utils.encoding import force_text
 from django.utils.safestring import mark_safe
 
 from .constants import (
+    recognized_markup_languages,
     ReST_HEADER_REGEX_DICT,
     ReST_ROLES,
     ReST_DIRECTIVES,
@@ -375,7 +376,7 @@ def apply_markdown_preserving_displayed_maths(text):
     )
 
 
-def process_markup(text, language_forced=None, include_errors=False):
+def process_markup(text_given, language_forced=None, include_errors=False):
     """
     Process a text in a markup language into HTML.
 
@@ -385,16 +386,40 @@ def process_markup(text, language_forced=None, include_errors=False):
     Parameters:
     * `language_forced=None`: override language auto-detection
     """
-    markup_detector = detect_markup_language(text)
 
     markup = {"language": "plain", "errors": None, "warnings": None, "processed": ""}
 
-    if language_forced and language_forced != markup_detector["language"]:
+    if not text_given:
+        return markup
+
+    # See if text_given contains a language coerce
+    coerced = False
+    if text_given.partition("\n")[0].startswith("#coerce:"):
+        language_requested_code = text_given.partition("\n")[0].partition("#coerce:")[2]
+        coerced = True
+        text = text_given.partition("\n")[2]
+        if language_requested_code not in recognized_markup_languages:
+            markup["errors"] = (
+                f"Unknown language ({language_requested_code}) requested for coerce.\n"
+                "Your options are: "
+                f"{recognized_markup_languages}\n"
+                "To coerce, at the start of the first line, write #coerce:[code] "
+                "with the language code, e.g. #coerce:reST"
+            )
+            return markup
+        language_requested = recognized_markup_languages[language_requested_code]
+        markup["warnings"] = f"Coercing language: {language_requested}"
+    else:
+        text = text_given
+
+    markup_detector = detect_markup_language(text)
+
+    if coerced and language_requested != markup_detector["language"]:
         markup["warnings"] = (
-            "Warning: markup language was forced to %s, while the detected one was %s."
-        ) % (language_forced, markup_detector["language"])
+            "markup language was coerced to %s, while the detected one was %s."
+        ) % (language_requested, markup_detector["language"])
 
-    language = language_forced if language_forced else markup_detector["language"]
+    language = language_requested if coerced else markup_detector["language"]
     markup["language"] = language
     markup["errors"] = markup_detector["errors"]
 
@@ -409,7 +434,8 @@ def process_markup(text, language_forced=None, include_errors=False):
                 "%s</span><br><br>"
             ) % linebreaksbr(markup["errors"])
         markup["processed"] = mark_safe(error_msg + linebreaksbr(text))
-        return markup
+        if not coerced:
+            return markup
 
     if language == "reStructuredText":
         warnStream = StringIO()
diff --git a/scipost_django/profiles/views.py b/scipost_django/profiles/views.py
index b82026056913a7de13e84f4c89161b6060874118..113a72382d0caff1d76b33d96fee4ff5c547d403 100644
--- a/scipost_django/profiles/views.py
+++ b/scipost_django/profiles/views.py
@@ -358,7 +358,7 @@ def _hx_profile_dynsel_list(request):
 @permission_required("scipost.can_create_profiles")
 def _hx_profile_specialties(request, profile_id):
     """
-Returns a snippet with current and possible specialties, with one-click actions.
+    Returns a snippet with current and possible specialties, with one-click actions.
     """
     profile = get_object_or_404(Profile, pk=profile_id)
     if request.method == "POST":