diff --git a/scipost_django/SciPost_v1/urls.py b/scipost_django/SciPost_v1/urls.py
index 098312d1ae5c0dfd131355ba868fae1c93483c34..4a9672067d7f59c6549156d239555052594c8ce5 100644
--- a/scipost_django/SciPost_v1/urls.py
+++ b/scipost_django/SciPost_v1/urls.py
@@ -93,6 +93,7 @@ urlpatterns = [
     path("commentaries/", include("commentaries.urls", namespace="commentaries")),
     path("commentary/", include("commentaries.urls", namespace="_commentaries")),
     path("comments/", include("comments.urls", namespace="comments")),
+    path("common/", include("common.urls", namespace="common")),
     path("edadmin/", include("edadmin.urls", namespace="edadmin")),
     path("ethics/", include("ethics.urls", namespace="ethics")),
     path("forums/", include("forums.urls", namespace="forums")),
diff --git a/scipost_django/colleges/admin.py b/scipost_django/colleges/admin.py
index bb36f032bfad8c11d499e87a33ec86e6798af193..26fb0ab1b581a4849be097575fa9d1b5061fbc33 100644
--- a/scipost_django/colleges/admin.py
+++ b/scipost_django/colleges/admin.py
@@ -101,11 +101,11 @@ class FellowshipNominationAdmin(admin.ModelAdmin):
         FellowshipNominationEventInline,
         FellowshipNominationCommentInline,
         FellowshipNominationVotingRoundInline,
-        FellowshipNominationDecisionInline,
         FellowshipInvitationInline,
     ]
-    list_display = ["college", "profile", "nominated_on"]
-    search_fields = ["college", "profile"]
+    list_filter = ["college__name"]
+    list_display = ["profile", "college", "nominated_on"]
+    search_fields = ["college__name", "profile__last_name", "profile__first_name"]
     autocomplete_fields = ["profile", "nominated_by", "fellowship"]
 
 
@@ -116,16 +116,48 @@ class FellowshipNominationVoteInline(admin.TabularInline):
     model = FellowshipNominationVote
     extra = 0
 
+    # Filter "fellow" field to only those who are eligible to vote
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == "fellow":
+            kwargs["queryset"] = FellowshipNominationVotingRound.objects.get(
+                pk=request.resolver_match.kwargs["object_id"]
+            ).eligible_to_vote.all()
+        return super().formfield_for_foreignkey(db_field, request, **kwargs)
+
 
 class FellowshipNominationVotingRoundAdmin(admin.ModelAdmin):
     model = FellowshipNominationVotingRound
     inlines = [
         FellowshipNominationVoteInline,
+        FellowshipNominationDecisionInline,
+    ]
+    search_fields = [
+        "nomination__profile__last_name",
+        "nomination__profile__first_name",
+        "nomination__college__name",
+    ]
+    list_display = [
+        "nomination",
+        "voting_opens",
+        "voting_deadline",
+        "is_open_checkmark",
+        "decision__outcome",
     ]
     autocomplete_fields = [
         "nomination",
         "eligible_to_vote",
     ]
+    list_filter = ("decision__outcome",)
+
+    def decision__outcome(self, obj):
+        return obj.decision.get_outcome_display()
+
+    @admin.display(
+        boolean=True,
+        description="Open",
+    )
+    def is_open_checkmark(self, obj):
+        return obj.is_open
 
 
 admin.site.register(
diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py
index 38e304c7182b9a8adfb2cd9b247f30e06792d466..e076868a1237e88b5377bac6744f555bd0556103 100644
--- a/scipost_django/colleges/forms.py
+++ b/scipost_django/colleges/forms.py
@@ -3,14 +3,19 @@ __license__ = "AGPL v3"
 
 
 import datetime
+from typing import Any, Dict
 
 from django import forms
-from django.db.models import Q
+from django.contrib.sessions.backends.db import SessionStore
+from django.db.models import Q, Max, OuterRef, Subquery
 
 from crispy_forms.helper import FormHelper
 from crispy_forms.layout import Layout, Div, Field, ButtonHolder, Submit
 from crispy_bootstrap5.bootstrap5 import FloatingField
 from dal import autocomplete
+from django.urls import reverse
+from django.utils import timezone
+from django.utils.timezone import timedelta
 
 from ontology.models import Specialty
 from proceedings.models import Proceedings
@@ -19,6 +24,8 @@ from submissions.models import Submission
 from scipost.forms import RequestFormMixin
 from scipost.models import Contributor
 
+from colleges.permissions import is_edadmin
+
 from .models import (
     College,
     Fellowship,
@@ -27,6 +34,7 @@ from .models import (
     FellowshipNomination,
     FellowshipNominationComment,
     FellowshipNominationDecision,
+    FellowshipNominationVotingRound,
     FellowshipInvitation,
 )
 from .constants import (
@@ -411,7 +419,10 @@ class FellowshipNominationForm(forms.ModelForm):
         self.profile = kwargs.pop("profile")
         super().__init__(*args, **kwargs)
         self.fields["college"].queryset = College.objects.filter(
-            acad_field=self.profile.acad_field
+            acad_field=self.profile.acad_field,
+            # id__in=Fellowship.objects.active()
+            # .filter(contributor=self.fields["nominated_by"].initial)
+            # .values_list("college", flat=True),
         )
         self.fields["college"].empty_label = None
         self.fields["nominator_comments"].label = False
@@ -450,6 +461,16 @@ class FellowshipNominationForm(forms.ModelForm):
             self.add_error(
                 "college", "Mismatch between college.acad_field and profile.acad_field."
             )
+        if (not is_edadmin(data["nominated_by"].user)) and (
+            data["college"].id
+            not in Fellowship.objects.active()
+            .filter(contributor=data["nominated_by"])
+            .values_list("college", flat=True)
+        ):
+            self.add_error(
+                "college",
+                "You do not have an active Fellowship in the selected College.",
+            )
         return data
 
     def save(self):
@@ -459,52 +480,246 @@ class FellowshipNominationForm(forms.ModelForm):
         return nomination
 
 
+# class FellowshipNominationSearchForm(forms.Form):
+#     """Filter a FellowshipNomination queryset using basic search fields."""
+
+#     college = forms.ModelChoiceField(queryset=College.objects.all(), required=False)
+#     specialty = forms.ModelChoiceField(
+#         queryset=Specialty.objects.all(),
+#         label="Specialty",
+#         required=False,
+#     )
+#     name = forms.CharField(max_length=128, required=False)
+
+#     def __init__(self, *args, **kwargs):
+#         super().__init__(*args, **kwargs)
+#         self.helper = FormHelper()
+#         self.helper.layout = Layout(
+#             Div(
+#                 FloatingField("category"),
+#                 css_class="row",
+#             ),
+#             Div(
+#                 Div(FloatingField("college"), css_class="col-lg-6"),
+#                 Div(FloatingField("specialty"), css_class="col-lg-6"),
+#                 css_class="row",
+#             ),
+#             Div(
+#                 Div(FloatingField("name", autocomplete="off"), css_class="col-lg-6"),
+#                 css_class="row",
+#             ),
+#         )
+
+#     def search_results(self):
+#         if self.cleaned_data.get("name"):
+#             nominations = FellowshipNomination.objects.filter(
+#                 Q(profile__last_name__icontains=self.cleaned_data.get("name"))
+#                 | Q(profile__first_name__icontains=self.cleaned_data.get("name"))
+#             )
+#         else:
+#             nominations = FellowshipNomination.objects.all()
+#         if self.cleaned_data.get("college"):
+#             nominations = nominations.filter(college=self.cleaned_data.get("college"))
+#         if self.cleaned_data.get("specialty"):
+#             nominations = nominations.filter(
+#                 profile__specialties__in=[
+#                     self.cleaned_data.get("specialty"),
+#                 ]
+#             )
+#         return nominations
+
+
 class FellowshipNominationSearchForm(forms.Form):
-    """Filter a FellowshipNomination queryset using basic search fields."""
+    all_nominations = FellowshipNomination.objects.all()
+    nomination_colleges = all_nominations.values_list("college", flat=True).distinct()
 
-    college = forms.ModelChoiceField(queryset=College.objects.all(), required=False)
-    specialty = forms.ModelChoiceField(
-        queryset=Specialty.objects.all(),
-        label="Specialty",
+    nominee = forms.CharField(max_length=100, required=False, label="Nominee")
+
+    college = forms.MultipleChoiceField(
+        choices=College.objects.filter(id__in=nomination_colleges)
+        .order_by("name")
+        .values_list("id", "name"),
+        required=False,
+    )
+
+    decision = forms.ChoiceField(
+        choices=[("", "Any"), ("pending", "Pending")]
+        + FellowshipNominationDecision.OUTCOME_CHOICES,
+        required=False,
+    )
+
+    can_vote = forms.BooleanField(
+        label="I can vote",
+        required=False,
+        initial=True,
+    )
+    voting_open = forms.BooleanField(
+        label="Voting open now",
+        required=False,
+        initial=True,
+    )
+    has_rounds = forms.BooleanField(
+        label="Has voting rounds",
+        required=False,
+        initial=True,
+    )
+
+    orderby = forms.ChoiceField(
+        label="Order by",
+        choices=(
+            ("latest_round_deadline", "Deadline"),
+            ("latest_round_open", "Voting start"),
+            ("latest_round_decision_outcome", "Decision"),
+            ("profile__last_name", "Nominee"),
+            ("nominated_on", "Nominated date"),
+        ),
+        required=False,
+    )
+    ordering = forms.ChoiceField(
+        label="Ordering",
+        choices=(
+            # FIXME: Emperically, the ordering appers to be reversed for dates?
+            ("-", "Ascending"),
+            ("+", "Descending"),
+        ),
         required=False,
     )
-    name = forms.CharField(max_length=128, required=False)
 
     def __init__(self, *args, **kwargs):
+        self.user = kwargs.pop("user")
+        self.session_key = kwargs.pop("session_key", None)
         super().__init__(*args, **kwargs)
+
+        # Set the initial values of the form fields from the session data
+        if self.session_key:
+            session = SessionStore(session_key=self.session_key)
+
+            for field in self.fields:
+                if field in session:
+                    self.fields[field].initial = session[field]
+
         self.helper = FormHelper()
+
+        div_block_ordering = Div(
+            Div(FloatingField("orderby"), css_class="col-6 col-md-12 col-xl-6"),
+            Div(FloatingField("ordering"), css_class="col-6 col-md-12 col-xl-6"),
+            css_class="row mb-0",
+        )
+        div_block_checkbox = Div(
+            Div(Field("can_vote"), css_class="col-auto col-lg-12 col-xl-auto"),
+            Div(Field("voting_open"), css_class="col-auto col-lg-12 col-xl-auto"),
+            Div(Field("has_rounds"), css_class="col-auto col-lg-12 col-xl-auto"),
+            css_class="row mb-0",
+        )
+
         self.helper.layout = Layout(
             Div(
-                FloatingField("category"),
-                css_class="row",
-            ),
-            Div(
-                Div(FloatingField("college"), css_class="col-lg-6"),
-                Div(FloatingField("specialty"), css_class="col-lg-6"),
-                css_class="row",
-            ),
-            Div(
-                Div(FloatingField("name", autocomplete="off"), css_class="col-lg-6"),
-                css_class="row",
+                Div(
+                    Div(
+                        Div(FloatingField("nominee"), css_class="col-8"),
+                        Div(FloatingField("decision"), css_class="col-4"),
+                        Div(div_block_ordering, css_class="col-12 col-md-6 col-xl-12"),
+                        Div(div_block_checkbox, css_class="col-12 col-md-6 col-xl-12"),
+                        css_class="row mb-0",
+                    ),
+                    css_class="col",
+                ),
+                Div(
+                    Field("college", size=6),
+                    css_class="col-12 col-md-6 col-lg-4",
+                ),
+                css_class="row mb-0",
             ),
         )
 
+    def apply_filter_set(self, filters: Dict, none_on_empty: bool = False):
+        # Apply the filter set to the form
+        for key in self.fields:
+            if key in filters:
+                self.fields[key].initial = filters[key]
+            elif none_on_empty:
+                if isinstance(self.fields[key], forms.MultipleChoiceField):
+                    self.fields[key].initial = []
+                else:
+                    self.fields[key].initial = None
+
     def search_results(self):
-        if self.cleaned_data.get("name"):
-            nominations = FellowshipNomination.objects.filter(
-                Q(profile__last_name__icontains=self.cleaned_data.get("name"))
-                | Q(profile__first_name__icontains=self.cleaned_data.get("name"))
+        # Save the form data to the session
+        if self.session_key is not None:
+            session = SessionStore(session_key=self.session_key)
+
+            for key in self.cleaned_data:
+                session[key] = self.cleaned_data.get(key)
+
+            session.save()
+
+        def latest_round_subquery(key):
+            return Subquery(
+                FellowshipNominationVotingRound.objects.filter(
+                    nomination=OuterRef("pk")
+                )
+                .order_by("-voting_deadline")
+                .values(key)[:1]
             )
-        else:
-            nominations = FellowshipNomination.objects.all()
-        if self.cleaned_data.get("college"):
-            nominations = nominations.filter(college=self.cleaned_data.get("college"))
-        if self.cleaned_data.get("specialty"):
+
+        nominations = (
+            FellowshipNomination.objects.all()
+            .annotate(
+                latest_round_deadline=latest_round_subquery("voting_deadline"),
+                latest_round_open=latest_round_subquery("voting_opens"),
+                latest_round_decision_outcome=latest_round_subquery(
+                    "decision__outcome"
+                ),
+            )
+            .distinct()
+        )
+
+        if self.cleaned_data.get("can_vote"):
+            # or not self.user.has_perm("scipost.can_view_all_nomination_voting_rounds"):
+            # Restrict rounds to those the user can vote on
+            nominations = nominations.with_user_votable_rounds(self.user).distinct()
+
+        if nominee := self.cleaned_data.get("nominee"):
+            nominations = nominations.filter(
+                Q(profile__first_name__icontains=nominee)
+                | Q(profile__last_name__icontains=nominee)
+            )
+        if college := self.cleaned_data.get("college"):
+            nominations = nominations.filter(college__id__in=college)
+        if decision := self.cleaned_data.get("decision"):
+            if decision == "pending":
+                nominations = nominations.filter(
+                    voting_rounds__decision__isnull=True,
+                )
+            else:
+                nominations = nominations.filter(
+                    voting_rounds__decision__outcome=decision,
+                )
+        if self.cleaned_data.get("voting_open"):
             nominations = nominations.filter(
-                profile__specialties__in=[
-                    self.cleaned_data.get("specialty"),
+                Q(voting_rounds__voting_opens__lte=timezone.now())
+                & Q(voting_rounds__voting_deadline__gte=timezone.now())
+            )
+        if self.cleaned_data.get("has_rounds"):
+            nominations = nominations.filter(voting_rounds__isnull=False)
+
+        # Ordering of nominations
+        # Only order if both fields are set
+        if (orderby_value := self.cleaned_data.get("orderby")) and (
+            ordering_value := self.cleaned_data.get("ordering")
+        ):
+            # Remove the + from the ordering value, causes a Django error
+            ordering_value = ordering_value.replace("+", "")
+
+            # Ordering string is built by the ordering (+/-), and the field name
+            # from the orderby field split by "," and joined together
+            nominations = nominations.order_by(
+                *[
+                    ordering_value + order_part
+                    for order_part in orderby_value.split(",")
                 ]
             )
+
         return nominations
 
 
@@ -534,11 +749,8 @@ class FellowshipNominationCommentForm(forms.ModelForm):
                         placeholder="Add a comment (visible to EdAdmin and all Fellows)",
                         rows=2,
                     ),
-                    css_class="col-lg-10",
-                ),
-                Div(
-                    ButtonHolder(Submit("submit", "Add comment")), css_class="col-lg-2"
                 ),
+                Div(ButtonHolder(Submit("submit", "Add comment"))),
                 css_class="row",
             ),
         )
@@ -547,31 +759,289 @@ class FellowshipNominationCommentForm(forms.ModelForm):
 class FellowshipNominationDecisionForm(forms.ModelForm):
     class Meta:
         model = FellowshipNominationDecision
-        fields = [
-            "nomination",
+        fields: list[str] = [
+            "voting_round",
             "outcome",
             "fixed_on",
             "comments",
         ]
 
+        widgets = {
+            "comments": forms.Textarea(attrs={"rows": 4}),
+        }
+
     def __init__(self, *args, **kwargs):
+        voting_round = kwargs.pop("voting_round", None)
         super().__init__(*args, **kwargs)
         self.helper = FormHelper()
         self.helper.layout = Layout(
-            Field("nomination", type="hidden"),
+            Field("voting_round", type="hidden"),
             Field("fixed_on", type="hidden"),
             Div(
-                Div(Field("comments"), css_class="col-8"),
+                Div(Field("comments"), css_class="col-12 col-lg-8"),
                 Div(
                     Field("outcome"),
                     ButtonHolder(Submit("submit", "Submit")),
-                    css_class="col-4",
+                    css_class="col-12 col-lg-4",
                 ),
                 css_class="row",
             ),
         )
+        if voting_round:
+            self.fields["voting_round"].initial = voting_round
+            self.fields["outcome"].initial = voting_round.vote_outcome
+
+
+#################
+# Voting Rounds #
+#################
+
 
+class FellowshipNominationVotingRoundSearchForm(forms.Form):
+    all_rounds = FellowshipNominationVotingRound.objects.all()
 
+    nominee = forms.CharField(max_length=100, required=False, label="Nominee")
+
+    college = forms.MultipleChoiceField(
+        choices=College.objects.all().order_by("name").values_list("id", "name"),
+        required=False,
+    )
+
+    decision = forms.ChoiceField(
+        choices=[("", "Any"), ("pending", "Pending")]
+        + FellowshipNominationDecision.OUTCOME_CHOICES,
+        required=False,
+    )
+
+    can_vote = forms.BooleanField(
+        label="I can vote",
+        required=False,
+        initial=True,
+    )
+    voting_open = forms.BooleanField(
+        label="Voting open",
+        required=False,
+        initial=True,
+    )
+
+    orderby = forms.ChoiceField(
+        label="Order by",
+        choices=(
+            ("voting_deadline", "Deadline"),
+            ("voting_opens", "Voting start"),
+            ("decision__outcome", "Decision"),
+            ("nomination__profile__last_name", "Nominee"),
+        ),
+        required=False,
+    )
+    ordering = forms.ChoiceField(
+        label="Ordering",
+        choices=(
+            # FIXME: Emperically, the ordering appers to be reversed for dates?
+            ("-", "Ascending"),
+            ("+", "Descending"),
+        ),
+        required=False,
+    )
+
+    def __init__(self, *args, **kwargs):
+        self.user = kwargs.pop("user")
+        self.session_key = kwargs.pop("session_key", None)
+        super().__init__(*args, **kwargs)
+
+        # Set the initial values of the form fields from the session data
+        if self.session_key:
+            session = SessionStore(session_key=self.session_key)
+
+            for field in self.fields:
+                if field in session:
+                    self.fields[field].initial = session[field]
+
+        self.helper = FormHelper()
+        self.helper.layout = Layout(
+            Div(
+                Div(
+                    Div(
+                        Div(FloatingField("nominee"), css_class="col-6 col-lg-6"),
+                        Div(FloatingField("decision"), css_class="col-3 col-lg-4"),
+                        Div(
+                            Div(
+                                Div(Field("can_vote"), css_class="col-12"),
+                                Div(Field("voting_open"), css_class="col-12"),
+                                css_class="row mb-0",
+                            ),
+                            css_class="col-3 col-lg-2",
+                        ),
+                        Div(FloatingField("orderby"), css_class="col-6"),
+                        Div(FloatingField("ordering"), css_class="col-6"),
+                        css_class="row mb-0",
+                    ),
+                    css_class="col",
+                ),
+                Div(
+                    Field("college", size=5),
+                    css_class="col-12 col-md-6 col-lg-4",
+                ),
+                css_class="row mb-0",
+            ),
+        )
+
+    def apply_filter_set(self, filters: Dict, none_on_empty: bool = False):
+        # Apply the filter set to the form
+        for key in self.fields:
+            if key in filters:
+                self.fields[key].initial = filters[key]
+            elif none_on_empty:
+                if isinstance(self.fields[key], forms.MultipleChoiceField):
+                    self.fields[key].initial = []
+                else:
+                    self.fields[key].initial = None
+
+    def search_results(self):
+        # Save the form data to the session
+        if self.session_key is not None:
+            session = SessionStore(session_key=self.session_key)
+
+            for key in self.cleaned_data:
+                session[key] = self.cleaned_data.get(key)
+
+            session.save()
+
+        rounds = FellowshipNominationVotingRound.objects.all()
+
+        if self.cleaned_data.get("can_vote"):
+            # or not self.user.has_perm("scipost.can_view_all_nomination_voting_rounds"):
+            # Restrict rounds to those the user can vote on
+            rounds = rounds.where_user_can_vote(self.user)
+
+        if nominee := self.cleaned_data.get("nominee"):
+            rounds = rounds.filter(
+                Q(nomination__profile__first_name__icontains=nominee)
+                | Q(nomination__profile__last_name__icontains=nominee)
+            )
+        if college := self.cleaned_data.get("college"):
+            rounds = rounds.filter(nomination__college__id__in=college)
+        if decision := self.cleaned_data.get("decision"):
+            if decision == "pending":
+                rounds = rounds.filter(decision__isnull=True)
+            else:
+                rounds = rounds.filter(decision__outcome=decision)
+        if self.cleaned_data.get("voting_open"):
+            rounds = rounds.filter(
+                Q(voting_opens__lte=timezone.now())
+                & Q(voting_deadline__gte=timezone.now())
+            )
+
+        # Ordering of voting rounds
+        # Only order if both fields are set
+        if (orderby_value := self.cleaned_data.get("orderby")) and (
+            ordering_value := self.cleaned_data.get("ordering")
+        ):
+            # Remove the + from the ordering value, causes a Django error
+            ordering_value = ordering_value.replace("+", "")
+
+            # Ordering string is built by the ordering (+/-), and the field name
+            # from the orderby field split by "," and joined together
+            rounds = rounds.order_by(
+                *[
+                    ordering_value + order_part
+                    for order_part in orderby_value.split(",")
+                ]
+            )
+
+        return rounds
+
+
+from datetime import date
+
+
+class FellowshipNominationVotingRoundStartForm(forms.ModelForm):
+    class Meta:
+        model = FellowshipNominationVotingRound
+        fields = ["voting_opens", "voting_deadline"]
+
+        widgets = {
+            "voting_opens": forms.DateInput(attrs={"type": "date"}),
+            "voting_deadline": forms.DateInput(attrs={"type": "date"}),
+        }
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        today = date.today()
+        self.fields["voting_opens"].widget.attrs.update(
+            {
+                "min": today.strftime("%Y-%m-%d"),
+                "value": today.strftime("%Y-%m-%d"),
+            }
+        )
+
+        in_two_weeks = today + timedelta(days=14)
+        self.fields["voting_deadline"].widget.attrs.update(
+            {
+                "min": today.strftime("%Y-%m-%d"),
+                "value": in_two_weeks.strftime("%Y-%m-%d"),
+            }
+        )
+
+        self.helper = FormHelper()
+        self.helper.attrs = {
+            "hx-target": f"#nomination-{self.instance.nomination.id}-round-tab-holder",
+            "hx-swap": "outerHTML",
+            "hx-post": reverse(
+                "colleges:_hx_nomination_voting_rounds_tab",
+                kwargs={
+                    "nomination_id": self.instance.nomination.id,
+                    "round_id": self.instance.id,
+                },
+            ),
+        }
+        self.helper.layout = Layout(
+            Div(
+                Div(Field("voting_opens"), css_class="col"),
+                Div(Field("voting_deadline"), css_class="col"),
+                Div(
+                    ButtonHolder(Submit("submit", "Start")),
+                    css_class="col-auto align-self-end mb-3",
+                ),
+                css_class="row mb-0",
+            )
+        )
+
+    def clean(self):
+        open_date = self.cleaned_data.get("voting_opens", None)
+        deadline_date = self.cleaned_data.get("voting_deadline", None)
+
+        if open_date is None or deadline_date is None:
+            self.add_error(
+                None,
+                "Both the voting opens and voting deadline must be set.",
+            )
+
+        # Check that the voting deadline is after the voting opens
+        if deadline_date <= open_date:
+            self.add_error(
+                "voting_deadline",
+                "The voting deadline must be after the voting opens.",
+            )
+
+        # Check that the voting opens after today
+        if open_date.date() < date.today():
+            self.add_error(
+                "voting_opens", "The voting opening date may not be in the past."
+            )
+
+        if self.instance.eligible_to_vote.count() == 0:
+            self.add_error(
+                None,
+                "There must be at least one eligible voter to start the round. "
+                "Please add voters to the round before setting the dates.",
+            )
+
+
+###############
+# Invitations #
+###############
 class FellowshipInvitationResponseForm(forms.ModelForm):
     class Meta:
         model = FellowshipInvitation
@@ -592,20 +1062,63 @@ class FellowshipInvitationResponseForm(forms.ModelForm):
         self.helper.layout = Layout(
             Field("nomination", type="hidden"),
             Div(
-                Div(Field("response"), css_class="col-lg-5"),
-                Div(Field("postpone_start_to"), css_class="col-lg-5"),
-                css_class="row",
-            ),
-            Div(
+                Div(
+                    Div(
+                        Div(Field("response"), css_class="col-12"),
+                        Div(Field("postpone_start_to"), css_class="col-12"),
+                        css_class="row mb-0",
+                    ),
+                    css_class="col-12 col-md-5",
+                ),
                 Div(
                     Field(
                         "comments",
                         placeholder="Add a comment (visible to EdAdmin)",
-                        rows=2,
+                        rows=4,
                     ),
-                    css_class="col-lg-10",
+                    css_class="col-12 col-md-7",
                 ),
-                Div(ButtonHolder(Submit("submit", "Submit")), css_class="col-lg-2"),
-                css_class="row mt-0",
+                Div(ButtonHolder(Submit("submit", "Update")), css_class="col-auto"),
+                css_class="row mb-0",
             ),
         )
+
+    def clean(self):
+        has_contributor = hasattr(
+            self.cleaned_data["nomination"].profile, "contributor"
+        )
+        invitation_accepted = self.cleaned_data["response"] == (
+            FellowshipInvitation.RESPONSE_ACCEPTED
+        )
+        invitation_postponed = self.cleaned_data["response"] == (
+            FellowshipInvitation.RESPONSE_POSTPONED
+        )
+        postponed_date = self.cleaned_data["postpone_start_to"]
+
+        if (invitation_accepted or invitation_postponed) and not has_contributor:
+            self.add_error(
+                "response",
+                "This profile does not have a Contributor account to create a Fellowship with. Please create one before updating the invitation response to a positive answer.",
+            )
+
+        if postponed_date and (timezone.now().date() > postponed_date):
+            self.add_error(
+                "postpone_start_to",
+                "You cannot set a postponed start date in the past.",
+            )
+
+        if (
+            invitation_accepted
+            and (postponed_date is not None)
+            and (postponed_date != timezone.now().date())
+        ):
+            self.add_error(
+                "postpone_start_to",
+                "If the invitation is accepted for immediate start, you cannot postpone its start date.",
+            )
+
+        if invitation_postponed and not postponed_date:
+            self.add_error(
+                "postpone_start_to",
+                "If the invitation is postponed, you must set a start date in the future.",
+            )
diff --git a/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py b/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py
index 1021ad0c02850e1cad013964c79deca1ae367ecb..04b93e92a903f2b6c954dbda4aac8d4716ca3856 100644
--- a/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py
+++ b/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py
@@ -43,3 +43,31 @@ class Command(BaseCommand):
                     .senior()
                     .filter(college=nomination.college)
                 )
+            voting_round.save()
+
+            if voting_round.eligible_to_vote.count() <= 5:
+                self.stdout.write(
+                    self.style.ERROR(
+                        "Only {nr_eligible_voters} eligible voters for {first_name} {last_name}, cannot create round.".format(
+                            first_name=nomination.profile.first_name,
+                            last_name=nomination.profile.last_name,
+                            nr_eligible_voters=voting_round.eligible_to_vote.count(),
+                        )
+                    )
+                )
+                voting_round.delete()
+            else:
+                self.stdout.write(
+                    self.style.SUCCESS(
+                        "Created voting round for {first_name} {last_name} with {nr_eligible_voters} eligible voters.".format(
+                            first_name=nomination.profile.first_name,
+                            last_name=nomination.profile.last_name,
+                            nr_eligible_voters=voting_round.eligible_to_vote.count(),
+                        )
+                    )
+                )
+
+        if len(nominations) == 0:
+            self.stdout.write(
+                self.style.ERROR(f"No nominations found needing handling.")
+            )
diff --git a/scipost_django/colleges/managers.py b/scipost_django/colleges/managers.py
index a7f0ef26c79c536883fc3fb6062109afafb82e2e..6bf0611656c7f027007ceac6f6a74cd694e8804a 100644
--- a/scipost_django/colleges/managers.py
+++ b/scipost_django/colleges/managers.py
@@ -3,7 +3,7 @@ __license__ = "AGPL v3"
 
 
 from django.db import models
-from django.db.models import Q
+from django.db.models import Q, Prefetch
 from django.utils import timezone
 
 from .constants import POTENTIAL_FELLOWSHIP_ELECTION_VOTE_ONGOING
@@ -95,6 +95,20 @@ class FellowQuerySet(models.QuerySet):
         except AttributeError:
             return []
 
+    def no_competing_interests_with(self, profile):
+        """
+        Returns all Fellowships whose profiles have no competing interests with the specified profile.
+        """
+        from ethics.models import CompetingInterest
+
+        profile_CI, related_CI = CompetingInterest.objects.filter(
+            Q(profile=profile) | Q(related_profile=profile)
+        ).values_list("profile", "related_profile")
+
+        return self.exclude(
+            contributor__profile__pk__in=profile_CI + related_CI,
+        )
+
 
 class PotentialFellowshipQuerySet(models.QuerySet):
     def vote_needed(self, contributor):
@@ -127,7 +141,15 @@ class PotentialFellowshipQuerySet(models.QuerySet):
 
 class FellowshipNominationQuerySet(models.QuerySet):
     def needing_handling(self):
-        return self.exclude(decision__isnull=False).exclude(voting_rounds__isnull=False)
+        return self.exclude(voting_rounds__isnull=False).exclude(
+            voting_rounds__decision__isnull=False
+        )
+
+    def with_user_votable_rounds(self, user):
+        # votable_rounds = self.voting_rounds.where_user_can_vote(user)
+        return self.filter(
+            Q(voting_rounds__eligible_to_vote__in=user.contributor.fellowships.active())
+        )
 
 
 class FellowshipNominationVotingRoundQuerySet(models.QuerySet):
@@ -139,6 +161,10 @@ class FellowshipNominationVotingRoundQuerySet(models.QuerySet):
         now = timezone.now()
         return self.filter(voting_deadline__lte=now)
 
+    def where_user_can_vote(self, user):
+        user_fellowships = user.contributor.fellowships.active()
+        return self.filter(eligible_to_vote__in=user_fellowships)
+
 
 class FellowshipNominationVoteQuerySet(models.QuerySet):
     def agree(self):
@@ -149,3 +175,6 @@ class FellowshipNominationVoteQuerySet(models.QuerySet):
 
     def disagree(self):
         return self.filter(vote=self.model.VOTE_DISAGREE)
+
+    def veto(self):
+        return self.filter(vote=self.model.VOTE_VETO)
diff --git a/scipost_django/colleges/migrations/0040_auto_20230719_2108.py b/scipost_django/colleges/migrations/0040_auto_20230719_2108.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffa1982e87caadc7d5b161bac4178124dc981432
--- /dev/null
+++ b/scipost_django/colleges/migrations/0040_auto_20230719_2108.py
@@ -0,0 +1,56 @@
+# Generated by Django 3.2.18 on 2023-07-19 19:08
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+def copy_decision_from_nomination_to_voting_round(apps, schema_editor):
+    FellowshipNominationDecision = apps.get_model(
+        "colleges", "FellowshipNominationDecision"
+    )
+    for decision in FellowshipNominationDecision.objects.all():
+        decision.voting_round = decision.nomination.voting_rounds.first()
+        decision.save()
+
+
+def copy_decision_from_voting_round_to_nomination(apps, schema_editor):
+    FellowshipNominationDecision = apps.get_model(
+        "colleges", "FellowshipNominationDecision"
+    )
+    for decision in FellowshipNominationDecision.objects.all():
+        decision.nomination = decision.voting_round.nomination
+        decision.save()
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("colleges", "0039_nomination_add_events"),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name="fellowshipnominationdecision",
+            options={
+                "ordering": ["voting_round"],
+                "verbose_name_plural": "Fellowship Nomination Decisions",
+            },
+        ),
+        migrations.AddField(
+            model_name="fellowshipnominationdecision",
+            name="voting_round",
+            field=models.OneToOneField(
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="decision",
+                to="colleges.fellowshipnominationvotinground",
+            ),
+        ),
+        migrations.RunPython(
+            copy_decision_from_nomination_to_voting_round,
+            copy_decision_from_voting_round_to_nomination,
+        ),
+        migrations.RemoveField(
+            model_name="fellowshipnominationdecision",
+            name="nomination",
+        ),
+    ]
diff --git a/scipost_django/colleges/migrations/0041_auto_20230720_1608.py b/scipost_django/colleges/migrations/0041_auto_20230720_1608.py
new file mode 100644
index 0000000000000000000000000000000000000000..408b17115b3745f399be850eb626ce29a36ab6c7
--- /dev/null
+++ b/scipost_django/colleges/migrations/0041_auto_20230720_1608.py
@@ -0,0 +1,37 @@
+# Generated by Django 3.2.18 on 2023-07-20 14:08
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("colleges", "0040_auto_20230719_2108"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="fellowshipnominationdecision",
+            name="voting_round",
+            field=models.OneToOneField(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="decision",
+                to="colleges.fellowshipnominationvotinground",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="fellowshipnominationvote",
+            name="vote",
+            field=models.CharField(
+                choices=[
+                    ("agree", "Agree"),
+                    ("abstain", "Abstain"),
+                    ("disagree", "Disagree"),
+                    ("veto", "Veto"),
+                ],
+                max_length=16,
+            ),
+        ),
+    ]
diff --git a/scipost_django/colleges/migrations/0042_auto_20230914_1057.py b/scipost_django/colleges/migrations/0042_auto_20230914_1057.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d541a2576032e89376c65fd43bfa3ffe535317b
--- /dev/null
+++ b/scipost_django/colleges/migrations/0042_auto_20230914_1057.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.18 on 2023-09-14 08:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('colleges', '0041_auto_20230720_1608'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='fellowshipnominationvotinground',
+            name='voting_deadline',
+            field=models.DateTimeField(blank=True, null=True),
+        ),
+        migrations.AlterField(
+            model_name='fellowshipnominationvotinground',
+            name='voting_opens',
+            field=models.DateTimeField(blank=True, null=True),
+        ),
+    ]
diff --git a/scipost_django/colleges/migrations/0043_alter_fellowshipnominationevent_options.py b/scipost_django/colleges/migrations/0043_alter_fellowshipnominationevent_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d5b931b52308ffc4f77a0d26ea3d7a8bc2d0728
--- /dev/null
+++ b/scipost_django/colleges/migrations/0043_alter_fellowshipnominationevent_options.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.18 on 2023-10-02 15:35
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('colleges', '0042_auto_20230914_1057'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='fellowshipnominationevent',
+            options={'get_latest_by': 'on', 'ordering': ['nomination', '-on'], 'verbose_name_plural': 'Fellowhip Nomination Events'},
+        ),
+    ]
diff --git a/scipost_django/colleges/models/nomination.py b/scipost_django/colleges/models/nomination.py
index d908ea8f785e7165b5d06024527275af79b5dce0..95482e2251ab9b14afa55f61d0805ad91a32fe7b 100644
--- a/scipost_django/colleges/models/nomination.py
+++ b/scipost_django/colleges/models/nomination.py
@@ -4,6 +4,9 @@ __license__ = "AGPL v3"
 
 from django.db import models
 from django.utils import timezone
+from django.utils.functional import cached_property
+
+from colleges.permissions import is_edadmin
 
 from ..managers import (
     FellowshipNominationQuerySet,
@@ -11,6 +14,8 @@ from ..managers import (
     FellowshipNominationVoteQuerySet,
 )
 
+from colleges.models import Fellowship
+
 from scipost.models import get_sentinel_user
 
 
@@ -81,13 +86,17 @@ class FellowshipNomination(models.Model):
     def latest_voting_round(self):
         return self.voting_rounds.first()
 
+    @property
+    def decision(self):
+        """The singular non-deprecated decision for this nomination."""
+        return self.latest_voting_round.decision
+
     @property
     def decision_blocks(self):
         """
         List of blocking facts (if any) preventing fixing a decision.
         """
-        latest_round = self.voting_rounds.first()
-        if latest_round:
+        if latest_round := self.latest_voting_round:
             eligible_count = latest_round.eligible_to_vote.count()
             if eligible_count < 3:
                 return "Fewer than 3 eligible voters (insufficient)."
@@ -100,6 +109,20 @@ class FellowshipNomination(models.Model):
             return "Latest voting round is ongoing, and not everybody has voted."
         return "No voting round found."
 
+    # FIX: This is wrong semantically...
+    @property
+    def get_eligible_voters(self):
+        specialties_slug_list = [s.slug for s in self.profile.specialties.all()]
+
+        eligible_voters = (
+            Fellowship.objects.active()
+            .senior()
+            .specialties_overlap(specialties_slug_list)
+            .distinct()
+        )
+
+        return eligible_voters
+
 
 class FellowshipNominationEvent(models.Model):
     nomination = models.ForeignKey(
@@ -117,6 +140,7 @@ class FellowshipNominationEvent(models.Model):
     class Meta:
         ordering = ["nomination", "-on"]
         verbose_name_plural = "Fellowhip Nomination Events"
+        get_latest_by = "on"
 
     def __str__(self):
         return (
@@ -167,9 +191,9 @@ class FellowshipNominationVotingRound(models.Model):
         blank=True,
     )
 
-    voting_opens = models.DateTimeField()
+    voting_opens = models.DateTimeField(blank=True, null=True)
 
-    voting_deadline = models.DateTimeField()
+    voting_deadline = models.DateTimeField(blank=True, null=True)
 
     objects = FellowshipNominationVotingRoundQuerySet.as_manager()
 
@@ -181,6 +205,8 @@ class FellowshipNominationVotingRound(models.Model):
         verbose_name_plural = "Fellowship Nomination Voting Rounds"
 
     def __str__(self):
+        if self.voting_deadline is None or self.voting_opens is None:
+            return f"Unscheduled voting round for {self.nomination}"
         return (
             f'Voting round ({self.voting_opens.strftime("%Y-%m-%d")} -'
             f' {self.voting_deadline.strftime("%Y-%m-%d")}) for {self.nomination}'
@@ -192,16 +218,82 @@ class FellowshipNominationVotingRound(models.Model):
             return vote.vote
         return None
 
+    def add_voter(self, fellow):
+        self.eligible_to_vote.add(fellow)
+        self.save()
+
+    @property
+    def is_open(self):
+        if (self.voting_deadline is None) or (self.voting_opens is None):
+            return False
+        return self.voting_opens <= timezone.now() <= self.voting_deadline
+
+    @property
+    def is_scheduled(self):
+        return (self.voting_opens is not None) and (self.voting_opens > timezone.now())
+
+    @property
+    def is_unscheduled(self):
+        return (self.voting_opens is None) or (self.voting_deadline is None)
+
+    @property
+    def is_closed(self):
+        return (self.voting_deadline is not None) and (
+            self.voting_deadline < timezone.now()
+        )
+
+    @property
+    def vote_outcome(self):
+        """The outcome as determined by the votes."""
+        if self.votes.veto():
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
+        nr_votes_agree = self.votes.agree().count()
+        nr_votes_disagree = self.votes.disagree().count()
+        nr_non_abstaining_votes = nr_votes_agree + nr_votes_disagree
+
+        # Guard division by zero
+        if nr_non_abstaining_votes == 0:
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
+        # By-laws 1.3.4 grand fellowship if there is a majority of non-abstaining votes.
+        # Agree is counted as +1, disagree as -1
+        agree_ratio = (nr_votes_agree - nr_votes_disagree) / nr_non_abstaining_votes
+        if agree_ratio >= 0.5:
+            return FellowshipNominationDecision.OUTCOME_ELECTED
+        else:
+            return FellowshipNominationDecision.OUTCOME_NOT_ELECTED
+
+    def can_view(self, user) -> bool:
+        """Return whether the user can view this voting round.
+        They must be authenticated and have voting eligibility or be edadmin."""
+
+        eligibility_per_fellowship = [
+            fellowship in self.eligible_to_vote.all()
+            for fellowship in user.contributor.fellowships.all()
+        ]
+        eligible_to_vote = any(eligibility_per_fellowship)
+
+        return user.is_authenticated and (eligible_to_vote or is_edadmin(user))
+
 
 class FellowshipNominationVote(models.Model):
     VOTE_AGREE = "agree"
     VOTE_ABSTAIN = "abstain"
     VOTE_DISAGREE = "disagree"
+    VOTE_VETO = "veto"
     VOTE_CHOICES = (
         (VOTE_AGREE, "Agree"),
         (VOTE_ABSTAIN, "Abstain"),
         (VOTE_DISAGREE, "Disagree"),
+        (VOTE_VETO, "Veto"),
     )
+    VOTE_BS_CLASSES = {
+        VOTE_AGREE: "success",
+        VOTE_ABSTAIN: "warning",
+        VOTE_DISAGREE: "danger",
+        VOTE_VETO: "black",
+    }
 
     voting_round = models.ForeignKey(
         "colleges.FellowshipNominationVotingRound",
@@ -221,6 +313,10 @@ class FellowshipNominationVote(models.Model):
 
     objects = FellowshipNominationVoteQuerySet.as_manager()
 
+    @property
+    def get_vote_bs_class(self):
+        return self.VOTE_BS_CLASSES[self.vote]
+
     class Meta:
         constraints = [
             models.UniqueConstraint(
@@ -235,18 +331,20 @@ class FellowshipNominationVote(models.Model):
 
 
 class FellowshipNominationDecision(models.Model):
-    nomination = models.OneToOneField(
-        "colleges.FellowshipNomination",
+    voting_round = models.OneToOneField(
+        "colleges.FellowshipNominationVotingRound",
         on_delete=models.CASCADE,
         related_name="decision",
+        null=True,
+        blank=True,
     )
 
     OUTCOME_ELECTED = "elected"
     OUTCOME_NOT_ELECTED = "notelected"
-    OUTCOME_CHOICES = (
+    OUTCOME_CHOICES = [
         (OUTCOME_ELECTED, "Elected"),
         (OUTCOME_NOT_ELECTED, "Not elected"),
-    )
+    ]
     outcome = models.CharField(max_length=16, choices=OUTCOME_CHOICES)
 
     fixed_on = models.DateTimeField(default=timezone.now)
@@ -261,12 +359,12 @@ class FellowshipNominationDecision(models.Model):
 
     class Meta:
         ordering = [
-            "nomination",
+            "voting_round",
         ]
         verbose_name_plural = "Fellowship Nomination Decisions"
 
     def __str__(self):
-        return f"Decision for {self.nomination}: {self.get_outcome_display()}"
+        return f"Decision for {self.voting_round}: {self.get_outcome_display()}"
 
     @property
     def elected(self):
@@ -324,3 +422,14 @@ class FellowshipInvitation(models.Model):
     @property
     def declined(self):
         return self.response == self.RESPONSE_DECLINED
+
+    @property
+    def get_response_color(self):
+        if self.response in [self.RESPONSE_ACCEPTED, self.RESPONSE_POSTPONED]:
+            return "success"
+        elif self.response in [self.RESPONSE_DECLINED, self.RESPONSE_NOT_YET_INVITED]:
+            return "danger"
+        elif self.response in [self.RESPONSE_UNRESPONSIVE]:
+            return "warning"
+        else:
+            return "primary"
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html b/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html
index 4534351a8f395c00177f9297a9fe34bba552517d..010888e146f9839c0c870a05a095c35b0629a363 100644
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html
@@ -1,20 +1,18 @@
 {% load crispy_forms_tags %}
 {% load automarkup %}
+
 {% for comment in nomination.comments.all %}
   <details class="m-2 border" open>
     <summary class="bg-light p-2">{{ comment.by }} on {{ comment.on }}</summary>
-    <div class="m-2">
-      {% automarkup comment.text %}
-    </div>
+    <div class="m-2">{% automarkup comment.text %}</div>
   </details>
 {% empty %}
-  <p>No comments have been received</p>
+  <p class="m-2">No comments have been received.</p>
 {% endfor %}
 
 <div class="m-2 mt-4">
   <form hx-post="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}"
-	hx-target="#nomination-{{ nomination.id }}-comments"
-  >
+        hx-target="#nomination-{{ nomination.id }}-comments">
     {% crispy form %}
   </form>
 </div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_decision.html b/scipost_django/colleges/templates/colleges/_hx_nomination_decision.html
deleted file mode 100644
index 8444d39ab90954534d8af36e5958e0bf801ba3e0..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_decision.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% load crispy_forms_tags %}
-{% load automarkup %}
-{% if nomination.decision %}
-  {{ nomination.decision }}
-  <p>Fixed on: {{ nomination.decision.fixed_on }}</p>
-  {% if nomination.decision.comments %}
-    <p>Comments:</p>
-    {% automarkup nomination.decision.comments %}
-  {% endif %}
-{% else %}
-  {% with blocks=nomination.decision_blocks %}
-    {% if blocks %}
-      <p>The decision cannot be fixed at this moment: {{ blocks }}</p>
-    {% else %}
-      <form hx-post="{% url 'colleges:_hx_nomination_decision' nomination_id=nomination.id %}"
-	    hx-target="#nomination-{{ nomination.id }}-decision"
-      >
-	{% crispy decision_form %}
-      </form>
-    {% endif %}
-  {% endwith %}
-{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_decision_form.html b/scipost_django/colleges/templates/colleges/_hx_nomination_decision_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..4435e60cace56a8f110945b8044a8e08aa6e022d
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_decision_form.html
@@ -0,0 +1,17 @@
+{% load crispy_forms_tags %}
+{% load automarkup %}
+
+<div id="nomination-{{ voting_round.id }}-decision">
+  {% with blocks=voting_round.decision_blocks %}
+
+    {% if blocks %}
+      <p>The decision cannot be fixed at this moment: {{ blocks }}</p>
+    {% else %}
+      <form hx-post="{% url 'colleges:_hx_nomination_decision_form' round_id=voting_round.id %}"
+            hx-target="#nomination-{{ voting_round.id }}-decision">
+        {% crispy decision_form %}
+      </form>
+    {% endif %}
+
+  {% endwith %}
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_details.html b/scipost_django/colleges/templates/colleges/_hx_nomination_details.html
new file mode 100644
index 0000000000000000000000000000000000000000..fa25047e52674eea60def9fdd4b2b296d9f303d1
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_details.html
@@ -0,0 +1,10 @@
+<details id="nomination-{{ nomination.id }}-details"
+         class="border border-2 mx-3 p-2 bg-primary bg-opacity-10">
+  <summary class="list-none">{% include "colleges/_hx_nomination_summary.html" with nomination=nomination %}</summary>
+
+  <div id="nomination-{{ nomination.id }}-details-contents"
+       class="p-2 mt-2 bg-white"
+       hx-get="{% url 'colleges:_hx_nomination_details_contents' nomination_id=nomination.id %}"
+       hx-trigger="toggle once from:#nomination-{{ nomination.id }}-details"></div>
+
+</details>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_details_contents.html b/scipost_django/colleges/templates/colleges/_hx_nomination_details_contents.html
new file mode 100644
index 0000000000000000000000000000000000000000..27a967d38b5f08b246d935d98bea4feb95b3e87e
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_details_contents.html
@@ -0,0 +1,183 @@
+{% load user_groups %}
+{% is_ed_admin request.user as is_ed_admin %}
+
+<div class="p-2">
+  <div class="row mb-0">
+ 
+    <div id="profile-{{ nomination.profile.id }}-specialties"
+         class="border border-danger mb-4 d-none-empty"></div>
+
+    <div class="col-12 col-md mb-3">
+      <div class="card">
+        <div class="card-header">Details</div>
+        <div class="card-body p-0">
+          <table class="table mb-0">
+            <tr>
+              <td>Field</td>
+              <td>{{ nomination.profile.acad_field }}</td>
+            </tr>
+            <tr>
+              <td>Specialties</td>
+              <td id="profile-{{ nomination.profile.id }}-specialties-code-display">
+
+                {% include "profiles/_hx_profile_specialty_codes_edit.html" with profile=nomination.profile %}
+
+              </td>
+            </tr>
+            <tr>
+              <td>ORCID ID</td>
+              <td>
+
+                {% if nomination.profile.orcid_id %}
+                  <a href="//orcid.org/{{ nomination.profile.orcid_id }}"
+                     target="_blank"
+                     rel="noopener">{{ nomination.profile.orcid_id }}</a>
+                {% else %}
+                  unknown
+                {% endif %}
+
+              </td>
+            </tr>
+            <tr>
+              <td>Webpage</td>
+              <td>
+
+                {% if nomination.profile.webpage %}
+                  <a href="{{ nomination.profile.webpage }}"
+                     target="_blank"
+                     rel="noopener">{{ nomination.profile.webpage }}</a>
+                {% else %}
+                  unknown
+                {% endif %}
+
+              </td>
+            </tr>
+          </table>
+        </div>
+      </div>
+    </div>
+    <div class="col-12 col-md mb-3">
+      <div class="card">
+        <div class="card-header">Publications in SciPost Journals</div>
+        <div class="card-body">
+          <ul>
+
+            {% for pub in nomination.profile.publications.all %}
+              <li>
+                <a href="{{ pub.get_absolute_url }}">{{ pub.citation }}</a>
+              </li>
+            {% empty %}
+              <li>No Publication found</li>
+            {% endfor %}
+
+          </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+ 
+  <div class="row">
+    <div class="col">
+      <div class="card">
+        <div class="card-header">Affiliations</div>
+        <div class="card-body p-0">
+          {% include 'profiles/_affiliations_table.html' with profile=nomination.profile actions=False %}
+        </div>
+      </div>
+    </div>
+  </div>
+ 
+  <div class="row mb-0">
+
+    {% comment %} or "active_senior_fellow" in user_roles  {% endcomment %}
+
+    {% if is_ed_admin %}
+      <div class="col-12 col-md mb-3">
+        <details class="card">
+          <summary class="card-header d-flex flex-row justify-content-between list-triangle">
+            <span>Events</span>
+            <span>({{ nomination.events.all.count }})</span>
+          </summary>
+          <div class="card-body">{% include 'colleges/_nomination_events_table.html' with nomination=nomination %}</div>
+        </details>
+      </div>
+    {% endif %}
+
+    <div class="col-12 col-md mb-3">
+      <details class="card">
+        <summary class="card-header d-flex flex-row justify-content-between list-triangle">
+          <span>Comments</span>
+          <span>({{ nomination.comments.all.count }})</span>
+        </summary>
+        <div class="card-body">
+          <div class="p-3">
+
+            {% if nomination.nominator_comments %}
+              <div class="row">
+                <div class="fs-6">Nominator comments:</div>
+                <div>
+                  <em>{{ nomination.nominator_comments }}</em>
+                </div>
+              </div>
+              <hr class="text-muted" />
+            {% endif %}
+
+            <div id="nomination-{{ nomination.id }}-comments"
+                 hx-get="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}"
+                 hx-trigger="intersect once"></div>
+          </div>
+        </div>
+      </details>
+
+    </div>
+  </div>
+
+  {% if nomination.voting_rounds.exists or perms.scipost.can_manage_college_composition %}
+    <details 
+      {% if not nomination.invitation or 'edadmin' not in user_roles %}open{% endif %}
+       class="card mb-3">
+      <summary class="card-header list-triangle">Voting Rounds</summary>
+      <div class="card-body">
+        <div hx-get="{% url 'colleges:_hx_nomination_voting_rounds_tab' nomination_id=nomination.id round_id=nomination.latest_voting_round.id|default:0 %}"
+             hx-trigger="intersect once"></div>
+      </div>
+    </details>
+  {% endif %}
+
+  {% if is_ed_admin and nomination.decision.outcome == 'elected' %}
+    <details 
+      {% if nomination.invitation %}open{% endif %}
+       class="card">
+      <summary class="card-header d-flex flex-row justify-content-between list-triangle">
+        <div>Invitation</div>
+        <div>{{ nomination.invitation.get_response_display }}</div>
+      </summary>
+      <div class="card-body">
+        <div class="row mb-0">
+          <div class="col-auto d-flex flex-column justify-content-between">
+            <div>
+              <h3>Checklist</h3>
+              {% include "colleges/_nominations_invitation_checklist.html" with invitation=nomination.invitation %}
+            </div>
+ 
+            <div>
+              <h3>Invitation status</h3>
+              <div class="fs-6 badge bg-{{ nomination.invitation.get_response_color }}">
+                {{ nomination.invitation.get_response_display }}
+              </div>
+            </div>
+          </div>
+ 
+          <div class="col-12 col-md p-2">
+            <h4>Update the response to this invitation:</h4>
+            <div id="invitation-{{ nomination.invitation.id }}-update-response"
+                 hx-get="{% url 'colleges:_hx_fellowship_invitation_update_response' invitation_id=nomination.invitation.id %}"
+                 hx-trigger="intersect once"></div>
+          </div>
+ 
+        </div>
+      </div>
+    </details>
+  {% endif %}
+
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_eligible_voters_table.html b/scipost_django/colleges/templates/colleges/_hx_nomination_eligible_voters_table.html
new file mode 100644
index 0000000000000000000000000000000000000000..113fff51a6498b3671e87cf1bf6a72c50b2d9528
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_eligible_voters_table.html
@@ -0,0 +1,47 @@
+{% if round.eligible_to_vote.all %}
+  <table class="table">
+    <thead class="table-light">
+      <tr>
+        <th>Fellow</th>
+        <th>College</th>
+        <th>Specialties</th>
+        <th>Type</th>
+        <th></th>
+      </tr>
+    </thead>
+
+    <tbody>
+
+      {% for voter in round.eligible_to_vote.all %}
+        <tr class="align-middle">
+          <td>{{ voter.contributor }}</td>
+          <td>{{ voter.college.name }}</td>
+          <td>
+
+            {% for specialty in voter.contributor.profile.specialties.all %}
+              <div class="single d-inline 
+                {% if specialty in nominee_specialties %}text-success{% endif %}
+                 " data-specialty="{{ specialty.slug }}" data-bs-placement="bottom" title="{{ specialty }}">
+                {{ specialty.code }}
+              </div>
+            {% endfor %}
+
+
+          </td>
+          <td>{{ voter.get_status_display }}</td>
+          {% comment %} Actions {% endcomment %}
+          <td class="text-end">
+            <a class="btn btn-sm btn-danger"
+               role="button"
+               hx-get="{% url 'colleges:_hx_nomination_round_remove_voter' round_id=round.id voter_id=voter.id %}"
+               hx-target="closest tr"><small>{% include 'bi/trash-fill.html' %}</small></a>
+          </td>
+        </tr>
+      {% endfor %}
+
+
+    </tbody>
+  </table>
+{% else %}
+  <p class="text-danger">No eligible voters found.</p>
+{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_form.html b/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
index 5543d18466f0bd4b21a88f127f0d9cd311ccfc9d..3b12c708bd5c53abd570c467de7b17362ad64d0f 100644
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_form.html
@@ -1,11 +1,10 @@
 {% load crispy_forms_tags %}
-<div class="m-2 p-4 border border-warning">
-  <h3>Nomination to Fellowship:&emsp;<span class="bg-success bg-opacity-25 p-2"><em>{{ profile }}</em></span></h3>
-  <form
-      hx-post="{% url 'colleges:_hx_nomination_form' profile_id=profile.pk %}"
-      hx-target="#nomination_form_response"
-      hx-indicator="#nomination_form_response-indicator"
-  >
-    {% crispy nomination_form %}
-  </form>
-</div>
+
+<h3>
+  Nomination to Fellowship:&emsp;<span class="bg-success bg-opacity-25 p-2"><em>{{ profile }}</em></span>
+</h3>
+<form hx-post="{% url 'colleges:_hx_nomination_form' profile_id=profile.pk %}"
+      hx-target="#new-nomination-container"
+      hx-indicator="#nomination_form_response-indicator">
+  {% crispy nomination_form %}
+</form>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_invitation_update_response.html b/scipost_django/colleges/templates/colleges/_hx_nomination_invitation_update_response.html
index 93e3b3a96fdf875d148449139ba2a9e0ac558463..8969da1766f0485a125de5e4c3052cf658992c95 100644
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_invitation_update_response.html
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_invitation_update_response.html
@@ -1,8 +1,7 @@
 {% load crispy_forms_tags %}
 <div class="m-2 mt-4">
   <form hx-post="{% url 'colleges:_hx_fellowship_invitation_update_response' invitation_id=invitation.id %}"
-	hx-target="#invitations_tablist"
-  >
+        hx-target="#invitation-{{ invitation.id }}-update-response">
     {% crispy form %}
   </form>
 </div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li.html
deleted file mode 100644
index 66b4bb52a306265d35e95366d4b8a352fefee7a6..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_li.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<div class="border border-dark">
-  <details id="nomination-{{ nomination.id }}-li-details">
-    <summary class="bg-light p-2">
-      {{ nomination.profile }}
-      <span class="float-end">
-	{{ nomination.college }}
-	&emsp;{{ nomination.nominated_on|date:"Y-m-d" }}
-	<span class="ms-4">Outcome:</span>
-	{% if nomination.decision %}
-	  {{ nomination.decision.get_outcome_display }}
-	{% else %}
-	  pending
-	{% endif %}
-	{% if nomination.fellowship and nomination.fellowship.is_active %}
-	  &emsp;<span class="p-2 bg-success text-white">Fellow</span>
-	{% endif %}
-      </span>
-    </summary>
-
-    <div id="nomination-{{ nomination.id }}-li-contents"
-	 hx-get="{% url 'colleges:_hx_nomination_li_contents' nomination_id=nomination.id %}"
-	 hx-trigger="toggle from:#nomination-{{ nomination.id }}-li-details"
-	 hx-target="this"
-    >
-    </div>
-  </details>
-</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html
deleted file mode 100644
index 09273f0b9831677ab1402711e5befb8e3b13fcd9..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html
+++ /dev/null
@@ -1,223 +0,0 @@
-<div class="p-2">
-  <p>Nominated by {{ nomination.nominated_by }} on {{ nomination.nominated_on|date:"Y-m-d" }}</p>
-  <div class="row">
-    <div class="col">
-      <div class="card m-2 mt-4">
-	<div class="card-header">
-	  Details
-	</div>
-	<div class="card-body">
-	  <table class="table">
-	    <tr>
-	      <td>Field</td><td>{{ nomination.profile.acad_field }}</td>
-	    </tr>
-	    <tr>
-	      <td>Specialties</td>
-	      <td>
-		{% for specialty in nomination.profile.specialties.all %}
-    		  <div class="single d-inline" data-specialty="{{ specialty }}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ specialty }}">{{ specialty.code }}</div>
-		{% empty %}
-		  undefined
-		{% endfor %}
-	      </td>
-	    </tr>
-	    <tr>
-	      <td>ORCID ID</td>
-	      <td>
-		{% if nomination.profile.orcid_id %}
-		  <a href="//orcid.org/{{ nomination.profile.orcid_id }}" target="_blank" rel="noopener">{{ nomination.profile.orcid_id }}</a>
-		{% else %}
-		  unknown
-		{% endif %}
-	      </td>
-	    </tr>
-	    <tr><td>Webpage</td>
-	      <td>
-		{% if nomination.profile.webpage %}
-		  <a href="{{ nomination.profile.webpage }}" target="_blank" rel="noopener">{{ nomination.profile.webpage }}</a>
-		{% else %}
-		  unknown
-		{% endif %}
-	      </td>
-	    </tr>
-	  </table>
-	</div>
-      </div>
-    </div>
-    <div class="col">
-      <div class="card m-2 mt-4">
-	<div class="card-header">
-	  Publications in SciPost Journals
-	</div>
-	<div class="card-body">
-	  <ul>
-	    {% for pub in nomination.profile.publications.all %}
-	      <li><a href="{{ pub.get_absolute_url }}">{{ pub.citation }}</a></li>
-	    {% empty %}
-	      <li>No Publication found</li>
-	    {% endfor %}
-	  </ul>
-	</div>
-      </div>
-    </div>
-  </div>
-  <table class="table">
-    <tr>
-      <td>Affiliations</td>
-      <td>
-	{% include 'profiles/_affiliations_table.html' with profile=nomination.profile actions=False %}</td>
-    </tr>
-  </table>
-
-  <hr>
-
-  {% if "edadmin" in user_roles or "active_senior_fellow" in user_roles %}
-    <details class="m-2 mt-4 border border-danger">
-      <summary class="p-2 bg-light">Events</summary>
-      {% include 'colleges/_nomination_events_table.html' with nomination=nomination %}
-    </details>
-  {% endif %}
-
-  <div class="card m-2 mt-4">
-    <div class="card-header">
-      Comments
-    </div>
-    <div class="card-body">
-      {% if nomination.nominator_comments %}
-	<div class="row">
-	  <div class="col-lg-2">
-	    Nominator comments:
-	  </div>
-	  <div class="col-lg-10">
-	    <em>{{ nomination.nominator_comments }}</em>
-	  </div>
-	</div>
-      {% endif %}
-
-      <div id="nomination-{{ nomination.id }}-comments"
-	   hx-get="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}"
-	   hx-trigger="revealed"
-	   hx-target="this"
-      >
-      </div>
-    </div>
-  </div>
-
-  {% with ongoing_round=nomination.ongoing_voting_round latest_round=nomination.voting_rounds.first %}
-    {% if ongoing_round %}
-      <div class="card m-2 mt-4">
-	<div class="card-header">
-	  Ongoing voting round <em>(voting deadline: {{ ongoing_round.voting_deadline }})</em>
-	</div>
-	<div class="card-body">
-	  {% if session_fellowship and session_fellowship in ongoing_round.eligible_to_vote.all %}
-	    <p>You are eligible to vote {{ include_vote_buttons }}</p>
-	    <p><strong>Please go up to the main Vote dropdown to cast your vote</strong></p>
-	  {% else %}
-	    <p>You are not called upon to vote in this round.</p>
-	  {% endif %}
-	</div>
-      </div>
-    {% elif latest_round %}
-      <div class="card m-2 mt-4">
-	<div class="card-header">
-	  {{ latest_round }}
-	</div>
-	<div class="card-body">
-	  {% if session_fellowship and session_fellowship in latest_round.eligible_to_vote.all %}
-	    {% include "colleges/_voting_results_box.html" with voting_round=latest_round %}
-	  {% else %}
-	    <p>You were not called upon to vote in this round.</p>
-	  {% endif %}
-	</div>
-      </div>
-    {% endif %}
-  {% endwith %}
-
-  {% if "edadmin" in user_roles %}
-    <div class="border border-danger m-2 p-2">
-      <strong class="text-danger">Editorial Administration</strong>
-      <h3>Voting rounds</h3>
-      {% for round in nomination.voting_rounds.all %}
-	<div class="card m-2 mt-4">
-	  <div class="card-header">
-	    {{ round }}
-	  </div>
-	  <div class="card-body">
-	    <div class="row">
-	      <div class="col-lg-6">
-		<h4>Eligible to vote</h4>
-		<ul>
-		  {% for voter in round.eligible_to_vote.all %}
-		    <li>{{ voter }}</li>
-		  {% empty %}
-		    <li>None</li>
-		  {% endfor %}
-		</ul>
-	      </div>
-	      <div class="col-lg-6">
-		<h4>Results</h4>
-		{% include "colleges/_voting_results_box.html" with voting_round=round %}
-		<table class="table m-2">
-		  <tr>
-		    <th>Agree</th>
-		    <td>
-		      <ul class="list-unstyled">
-			{% for vote in round.votes.agree %}
-			  <li>{{ vote.fellow }}</li>
-			{% empty %}
-			  <li>None</li>
-			{% endfor %}
-		      </ul>
-		    </td>
-		  </tr>
-		  <tr>
-		    <th>Abstain</th>
-		    <td>
-		      <ul class="list-unstyled">
-			{% for vote in round.votes.abstain %}
-			  <li>{{ vote.fellow }}</li>
-			{% empty %}
-			  <li>None</li>
-			{% endfor %}
-		      </ul>
-		    </td>
-		  </tr>
-		  <tr>
-		    <th>Disagree</th>
-		    <td>
-		      <ul class="list-unstyled">
-			{% for vote in round.votes.disagree %}
-			  <li>{{ vote.fellow }}</li>
-			{% empty %}
-			  <li>None</li>
-			{% endfor %}
-		      </ul>
-		    </td>
-		  </tr>
-		</table>
-	      </div>
-	    </div>
-	  </div>
-	</div>
-      {% empty %}
-	<div>No voting round</div>
-      {% endfor %}
-
-      <div class="card m-2 mt-4">
-	<div class="card-header">
-	  Decision
-	</div>
-	<div class="card-body">
-	  <div id="nomination-{{ nomination.id }}-decision"
-	       hx-get="{% url 'colleges:_hx_nomination_decision' nomination_id=nomination.id %}"
-	       hx-trigger="revealed"
-	       hx-target="this"
-	  </div>
-	</div>
-      </div>
-
-    </div>
-  {% endif %}
-
-</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_new.html b/scipost_django/colleges/templates/colleges/_hx_nomination_new.html
new file mode 100644
index 0000000000000000000000000000000000000000..c7cfd7ed2d876ce2c146d45dead9ce271b4c661d
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_new.html
@@ -0,0 +1,74 @@
+{% load crispy_forms_tags %}
+
+<div class="p-3 border border-success rounded rounded-lg">
+  <h2 class="mb-4">Nominate a new potential Fellow</h2>
+  <div class="row">
+
+    <div class="col-lg-6">
+      <h3>Procedure</h3>
+      <ul>
+        <li>Type your search query in the search form</li>
+        <li>
+          When the name you're looking for appears in the
+          <em>Matching profiles</em> list, double-click on it
+        </li>
+        <li>The nomination form will appear below</li>
+        <li>Non-eligibility flags (if any) will appear</li>
+        <li>If eligible, fill the form in (comments are optional)</li>
+        <li>Submit! (the vote will be arranged by EdAdmin)</li>
+      </ul>
+      <div class="row mb-0">
+
+        <div class="col-12">
+          <form hx-post="{% url 'profiles:_hx_profile_dynsel_list' %}"
+                hx-trigger="keyup delay:200ms, change"
+                hx-target="#profile_dynsel_results"
+                hx-indicator="#profile_dynsel_results-indicator">
+            <div id="profile_dynsel_form">{% crispy profile_dynsel_form %}</div>
+          </form>
+        </div>
+ 
+      </div>
+    </div>
+
+    <div class="col-lg-6">
+      <h3>Matching profiles</h3>
+      <div id="profile_dynsel_results" class="border border-light m-2 p-1"></div>
+
+      <div class="row mb-0">
+ 
+        <div class="col-auto">
+          <div id="profile_dynsel_results-indicator" class="htmx-indicator">
+            <button class="btn btn-sm btn-warning" type="button" disabled>
+              <strong>Loading results...</strong>
+              <div class="spinner-grow spinner-grow-sm ms-2"
+                   role="status"
+                   aria-hidden="true"></div>
+            </button>
+          </div>
+        </div>
+
+        <div class="col-auto">
+          <div id="nomination_form_response-indicator" class="htmx-indicator">
+            <button class="btn btn-sm btn-warning" type="button" disabled>
+              <strong>Loading form...</strong>
+              <div class="spinner-grow spinner-grow-sm ms-2"
+                   role="status"
+                   aria-hidden="true"></div>
+            </button>
+          </div>
+        </div>
+ 
+      </div>
+    </div>
+
+  </div>
+
+  <div id="nomination_form_response">
+    <h3 class="mb-2">Not found?</h3>
+    <p>
+      Then add to our database by <a href="{% url 'profiles:profile_create' %}" target="_blank">creating a new Profile</a> (opens in new window).
+    </p>
+  </div>
+
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_summary.html b/scipost_django/colleges/templates/colleges/_hx_nomination_summary.html
new file mode 100644
index 0000000000000000000000000000000000000000..aac1bdbf96fb6bd17437cc88c7bae761b9a5c7ec
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_summary.html
@@ -0,0 +1,76 @@
+<div class="row mb-0">
+  <div class="col-12 col-md">
+    <div class="row mb-0">
+ 
+      <div class="col">
+        <div class="row mb-0">
+
+          <div class="col-12 col-lg-4">
+            <div class="row mb-0 h-100 align-content-between">
+              <div class="col col-lg-12 fs-5">{{ nomination.profile }}</div>
+              <div class="col-auto">
+                <div class="text-muted">nominated by</div>
+                <div>{{ nomination.nominated_by.profile.full_name }}</div>
+              </div>
+            </div>
+          </div>
+ 
+          <div class="col-12 col-md">
+            <div class="row mb-2">
+              <div class="col-auto text-nowrap">
+                <small class="text-muted">Editorial college</small>
+                <br />
+                {{ nomination.college.name }}
+              </div>
+              <div class="col-auto text-nowrap">
+                <small class="text-muted">Specialties</small>
+                <br />
+
+                {% for specialty in nomination.profile.specialties.all %}
+                  <span title="{{ specialty.name }}">{{ specialty.code }}</span>
+                {% empty %}
+                  None
+                {% endfor %}
+
+              </div>
+ 
+              <div class="col text-nowrap ">
+                <small class="text-muted">Last event</small>
+                <br />
+                {{ nomination.events.latest.on|date:'Y-m-d' }}
+                -
+                <span class="">{{ nomination.events.latest.description }}</span>
+              </div>
+ 
+            </div>
+            <div class="row mb-2 justify-content-between">
+
+              {% if nomination.invitation %}
+                <small class="col-auto text-muted text-nowrap">Invitation status</small>
+                <div class="col">
+                  <span class="badge bg-{{ nomination.invitation.get_response_color }}">{{ nomination.invitation.get_response_display }}</span>
+                </div>
+              {% else %}
+                <small class="col text-muted text-nowrap">Publications</small>
+                <div class="col-auto">{{ nomination.profile.publications.all.count }}</div>
+                <small class="col text-muted text-nowrap">Total rounds</small>
+                <div class="col-auto">{{ nomination.voting_rounds.all.count }}</div>
+              {% endif %}
+
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-12 col-md-5">
+
+        {% if nomination.latest_voting_round %}
+          {% include "colleges/_hx_voting_round_summary.html" with round=nomination.latest_voting_round %}
+        {% else %}
+          <div class="h-100 d-flex align-items-center justify-content-end">
+            <div class="badge bg-danger fs-6">No rounds created yet</div>
+          </div>
+        {% endif %}
+
+      </div>
+    </div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_vote.html b/scipost_django/colleges/templates/colleges/_hx_nomination_vote.html
index afe76b979cc66d23608b4e77d6e88974c6b30a37..a4425b79c7734737abcfde96d39f527648f9fc11 100644
--- a/scipost_django/colleges/templates/colleges/_hx_nomination_vote.html
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_vote.html
@@ -1,44 +1,19 @@
-<div class="row">
-  <div class="col">
-    {% if vote_object %}
-      <p>You have previously voted: {{ vote_object.get_vote_display }}.</p>
-    {% else %}
-      <p>You have not yet voted on this Nomination.</p>
-    {% endif %}
-    <ul class="list-inline m-2">
-      <li class="list-inline-item">
-	Cast your vote:
-      </li>
-      <li class="list-inline-item">
-	<form hx-post="{% url 'colleges:_hx_nomination_vote' voting_round_id=voting_round.id %}"
-	      hx-target="#nomination-{{ voting_round.nomination.id }}-vote"
-	>
-	  {% csrf_token %}
-	  <input type="hidden" name="vote" value="agree">
-	  <button class="btn btn-sm btn-success text-white">Agree</button>
-	</form>
-      </li>
-      <li class="list-inline-item">
-	<form hx-post="{% url 'colleges:_hx_nomination_vote' voting_round_id=voting_round.id %}"
-	      hx-target="#nomination-{{ voting_round.nomination.id }}-vote"
-	>
-	  {% csrf_token %}
-	  <input type="hidden" name="vote" value="abstain">
-	  <button class="btn btn-sm btn-warning text-white">Abstain</button>
-	</form>
-      </li>
-      <li class="list-inline-item">
-	<form hx-post="{% url 'colleges:_hx_nomination_vote' voting_round_id=voting_round.id %}"
-	      hx-target="#nomination-{{ voting_round.nomination.id }}-vote"
-	>
-	  {% csrf_token %}
-	  <input type="hidden" name="vote" value="disagree">
-	  <button class="btn btn-sm btn-danger text-white">Disagree</button>
-	</form>
-      </li>
-    </ul>
-  </div>
-  <div class="col">
-    {% include "colleges/_voting_results_box.html" with voting_round=voting_round %}
-  </div>
-</div>
+<h3>Cast your vote:</h3>
+
+{% for vote_option, color in VOTE_BS_CLASSES.items %}
+
+  <form hx-post="{% url 'colleges:_hx_nomination_vote' round_id=voting_round.id %}"
+        hx-target="#nomination-{{ voting_round.nomination.id }}-vote">
+    {% csrf_token %}
+    <input type="hidden" name="vote" value="{{ vote_option }}" />
+    <button class="btn d-flex justify-content-between align-items-center w-100 mb-2 bg-{{ color }} text-white">
+      <div>{{ vote_option|title }}</div>
+
+      {% if vote_object.vote == vote_option %}
+        {% include 'bi/check-square-fill.html' %}
+      {% endif %}
+
+    </button>
+  </form>
+
+{% endfor %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html b/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html
new file mode 100644
index 0000000000000000000000000000000000000000..edb03507be12b4179a322a48feb76218026ead4c
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html
@@ -0,0 +1,75 @@
+{% if voters %}
+  <table class="table mb-0 border">
+    <thead class="table-light">
+      <tr>
+        <th>Fellow</th>
+        <th>Specialties</th>
+
+        {% if "edadmin" in user_roles %}
+
+          {% if not round.is_unscheduled %}
+            <th>Vote</th>
+            <th>Voted on</th>
+          {% endif %}
+
+          <th>Actions</th>
+        {% endif %}
+
+      </tr>
+    </thead>
+
+    <tbody>
+
+      {% for voter in voters %}
+        <tr>
+          <td>{{ voter }}</td>
+
+          <td>
+
+            {% for specialty in voter.contributor.profile.specialties.all %}
+              <div class="single d-inline 
+                {% if specialty in nominee_specialties %}text-primary{% endif %}
+                 " data-specialty="{{ specialty.slug }}" data-bs-placement="bottom" title="{{ specialty }}">
+                {{ specialty.code }}
+              </div>
+            {% endfor %}
+
+
+          </td>
+
+          {% if "edadmin" in user_roles %}
+
+            {% if not round.is_unscheduled %}
+
+              {% if voter.vote %}
+                <td class="text-{{ voter.vote.get_vote_bs_class }}">{{ voter.vote.get_vote_display }}</td>
+              {% else %}
+                <td class="text-muted">No vote</td>
+              {% endif %}
+
+              <td>{{ voter.vote.on }}</td>
+            {% endif %}
+
+            <td>
+
+              {% if not round.is_closed %}
+                <button class="btn btn-sm btn-danger px-1 py-0 ms-auto"
+                        hx-get="{% url "colleges:_hx_nomination_round_eligible_voter_action" round_id=round.id fellowship_id=voter.id action='remove' %}"
+                        hx-target="#nomination-{{ round.nomination.id }}-round-{{ round.id }}-voters">
+                  {% include "bi/trash-fill.html" %}
+                </button>
+              {% endif %}
+
+            </td>
+          {% endif %}
+
+        </tr>
+      {% endfor %}
+
+
+
+    </tbody>
+  </table>
+{% else %}
+  <p class="text-danger">No eligible voters found.</p>
+{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html b/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html
new file mode 100644
index 0000000000000000000000000000000000000000..11fa485d7be94366c082acc79ae8157c3bdaa31c
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html
@@ -0,0 +1,66 @@
+<div id="nomination-{{ nomination.id }}-round-tab-holder">
+
+  <nav class="nav nav-pills m-2 overflow-scroll">
+
+    {% if should_show_new_round_tab_btn %}
+      <div id="nomination-{{ nomination.id }}-new-round-btn"
+           type="button"
+           class="me-2 px-2 nav-link border border-success"
+           hx-get="{% url 'colleges:_hx_nomination_voting_rounds_create' nomination_id=nomination.id %}"
+           hx-target="#nomination-{{ nomination.id }}-round-tab-holder"
+           hx-swap="outerHTML">
+        <span class="fs-1 align-items-center text-success">+</span>
+      </div>
+    {% endif %}
+
+    {% for voting_round in voting_rounds %}
+      <div id="nomination-{{ nomination.id }}-round-{{ voting_round.id }}-tab-btn" type="button" class="me-2 nav-link 
+        {% if selected_round and selected_round.id == voting_round.id %}active{% endif %}
+  
+        {% if voting_round.id in inaccessible_round_ids %}disabled opacity-50{% endif %}
+         " hx-get="{% url 'colleges:_hx_nomination_voting_rounds_tab' nomination_id=nomination.id round_id=voting_round.id %}" hx-target="#nomination-{{ nomination.id }}-round-tab-holder" hx-swap="outerHTML">
+        <span class="d-block text-nowrap">
+
+          {% if voting_round.voting_opens and voting_round.voting_deadline %}
+            <small>{{ voting_round.voting_opens|date:"d M Y" }} - {{ voting_round.voting_deadline|date:"d M Y" }}</small>
+          {% else %}
+            <span class="badge bg-warning">Unscheduled</span>
+          {% endif %}
+
+          <span class="d-flex justify-content-between align-items-center">
+            <span>Round #{{ forloop.revcounter }}</span>
+
+            {% if voting_round.is_scheduled %}
+              <span class="badge bg-primary">Scheduled</span>
+            {% elif voting_round.is_open %}
+              <span class="badge bg-success">Open</span>
+            {% endif %}
+
+          </span>
+        </span>
+      </div>
+    {% endfor %}
+
+
+
+    <div id="indicator-nomination-{{ nomination.id }}-details-contents"
+         class="htmx-indicator p-2 ms-auto">
+      <button class="btn btn-warning" type="button" disabled>
+        <strong>Loading ...</strong>
+	
+        <div class="spinner-grow spinner-grow-sm ms-2"
+             role="status"
+             aria-hidden="true"></div>
+      </button>
+    </div>
+
+  </nav>
+
+  {% if selected_round %}
+    <div id="nomination-{{ nomination.id }}-round-{{ selected_round.id }}-tab-content-holder"
+         hx-get="{% url 'colleges:_hx_voting_round_details' round_id=selected_round.id %}"
+         hx-trigger="intersect once"
+         class="p-3"></div>
+  {% endif %}
+
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations.html b/scipost_django/colleges/templates/colleges/_hx_nominations.html
deleted file mode 100644
index 6ba5b622f4669c21b423326e4ffcc27911415ecd..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nominations.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% for nomination in page_obj %}
-  <li class="p-2 mb-2" id="nomination_{{ nomination.id }}">
-    {% include 'colleges/_hx_nomination_li.html' with nomination=nomination %}
-  </li>
-{% empty %}
-  <li>No Nomination could be found</li>
-{% endfor %}
-{% if page_obj.has_next %}
-  <li hx-post="{% url 'colleges:_hx_nominations' %}?page={{ page_obj.next_page_number }}"
-      hx-include="#search-nominations-form"
-      hx-trigger="revealed"
-      hx-swap="afterend"
-      hx-indicator="#indicator-search-page-{{ page_obj.number }}"
-  >
-    <div id="indicator-search-page-{{ page_obj.number }}" class="htmx-indicator p-2">
-      <button class="btn btn-warning" type="button" disabled>
-	<strong>Loading page {{ page_obj.next_page_number }} out of {{ page_obj.paginator.num_pages }}</strong>
-	<div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div>
-      </button>
-    </div>
-  </li>
-{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html b/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html
deleted file mode 100644
index 0b9771d42358f9ae2dfc18ef4e4841716a0b4a90..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% include 'colleges/_hx_nominations_invitations_tablist.html' with selected=selected %}
-
-{% for invitation in invitations.all %}
-  <details id="invitation-{{ invitation.id }}-details"
-	   class="m-2 mt-4 border border-2"
-  >
-    <summary class="bg-light p-2">{{ invitation }}</summary>
-    <details class="m-2 mt-4 border">
-      <summary class="p-2 bg-light">Events for this nomination</summary>
-      {% include 'colleges/_nomination_events_table.html' with nomination=invitation.nomination %}
-    </details>
-    <div class="p-2">
-      <h4>Checklist</h4>
-      <ul>
-	{% if not invitation.nomination.profile.contributor %}
-	  <li class="text-danger">N.B.: this nominee is not yet registered as a Contributor</li>
-	{% else %}
-	  <li><span class="text-success">{% include 'bi/check-square-fill.html' %}</span>&nbsp;This nominee has a Contributor account</li>
-	{% endif %}
-	{% if selected == 'notyetinvited' %}
-	  <li>
-	    For named or elected, but not yet invited:
-	    <a class="btn btn-primary" href="{% url 'colleges:fellowship_invitation_email_initial' pk=invitation.id %}">prepare and send initial email</a>
-	  </li>
-	{% elif selected == 'accepted' %}
-	  <li>Accepted to serve as Fellow but not currently active in a College? <a href="{% url 'colleges:fellowship_create' contributor_id=invitation.nomination.profile.contributor.id %}" target="_blank">Set up a Fellowship</a></li>
-	{% endif %}
-      </ul>
-
-      <hr>
-
-      <h4>Update the response to this invitation:</h4>
-      <div id="invitation-{{ invitation.id }}-update-response"
-	   hx-get="{% url 'colleges:_hx_fellowship_invitation_update_response' invitation_id=invitation.id %}"
-	   hx-trigger="toggle from:#invitation-{{ invitation.id }}-details"
-	   hx-target="this"
-      >
-      </div>
-    </div>
-  </details>
-{% empty %}
-  <p class="p-2">No invitations of this kind</p>
-{% endfor %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations_tablist.html b/scipost_django/colleges/templates/colleges/_hx_nominations_invitations_tablist.html
deleted file mode 100644
index fe8cb52436a3a2d41003443a4abb075a604001e3..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations_tablist.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div class="tablist">
-  {% for choice in response_choices %}
-    <a hx-get="{% url 'colleges:_hx_nominations_invitations' %}?response={{ choice.0 }}"
-       {% if selected == choice.0 %}class="selected"{% endif %}
-    >{{ choice.1 }}</a>
-  {% endfor %}
-</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_list.html b/scipost_django/colleges/templates/colleges/_hx_nominations_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..d859d14af2e2824b18c554fd9c71f1956c4d4732
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nominations_list.html
@@ -0,0 +1,24 @@
+{% for nomination in page_obj %}
+  <div class="ms-1 mt-2">{% include 'colleges/_hx_nomination_details.html' with nomination=nomination %}</div>
+{% empty %}
+  <strong>No Nominations could be found</strong>
+{% endfor %}
+
+{% if page_obj.has_next %}
+  <div hx-post="{% url 'colleges:_hx_nominations_list' %}?page={{ page_obj.next_page_number }}"
+       hx-include="#search-nominations-form"
+       hx-trigger="revealed"
+       hx-swap="afterend"
+       hx-indicator="#indicator-nominations-search-page"></div>
+  <div id="indicator-nominations-search-page"
+       hx-swap-oob="true"
+       class="htmx-indicator p-2">
+    <button class="btn btn-warning" type="button" disabled>
+      <strong>Loading page {{ page_obj.next_page_number }} out of {{ page_obj.paginator.num_pages }}</strong>
+	
+      <div class="spinner-grow spinner-grow-sm ms-2"
+           role="status"
+           aria-hidden="true"></div>
+    </button>
+  </div>
+{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html b/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html
deleted file mode 100644
index 50d4c6abf771e0ad1cd8728ebe3f38401f3a038a..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% for nomination in nominations_needing_specialties %}
-  <details id="nomination-{{ nomination.id }}-specialties"
-	   class="border border-2 mt-4"
-  >
-    <summary class="p-2 bg-light">{{ nomination }}</summary>
-    <div id="profile-{{ nomination.profile.id }}-specialties"
-	 class="p-2 mt-2"
-	 hx-get="{% url 'profiles:_hx_profile_specialties' profile_id=nomination.profile.id %}"
-	 hx-trigger="toggle from:#nomination-{{ nomination.id }}-specialties"
-    >
-    </div>
-    <button class="btn btn-success text-white m-2"
-		   hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}"
-		   hx-target="#nominations_needing_specialties">
-      Done
-    </button>
-  </details>
-{% empty %}
-  <p>All nomination profiles have at least one specialty.</p>
-{% endfor %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_search_form.html b/scipost_django/colleges/templates/colleges/_hx_nominations_search_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..6c95f95a9462805b6093f3feda5751a88908d405
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_nominations_search_form.html
@@ -0,0 +1,10 @@
+{% load crispy_forms_tags %}
+
+<form hx-post="{% url 'colleges:_hx_nominations_list' %}"
+      hx-trigger="load, keyup delay:500ms, change delay:500ms, click from:#refresh-button"
+      hx-sync="#search-nominations-form:replace"
+      hx-target="#search-nominations-results"
+      hx-indicator="#indicator-search-nominations">
+ 
+  <div id="search-nominations-form">{% crispy form %}</div>
+</form>
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_round_details.html b/scipost_django/colleges/templates/colleges/_hx_voting_round_details.html
new file mode 100644
index 0000000000000000000000000000000000000000..1fab54c60cd3d7aed3b40dba734f480920404e6c
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_voting_round_details.html
@@ -0,0 +1,93 @@
+{% load crispy_forms_tags %}
+{% load user_groups %}
+{% is_ed_admin request.user as is_ed_admin %}
+
+<div class="row mb-0">
+  <div class="col mb-3">
+    <h3>Eligible voters</h3>
+    <div id="nomination-{{ round.nomination.id }}-round-{{ round.id }}-voters"
+         hx-get="{% url 'colleges:_hx_nomination_voter_table' round_id=round.id %}"
+         hx-trigger="intersect once"></div>
+  </div>
+
+  <div class="col-12 col-md-auto d-flex flex-column justify-content-between">
+
+    {% if not round.is_closed %}
+
+      {% if is_ed_admin %}
+ 
+        <div>
+          <h4>Add new voter</h4>
+          <form hx-post="{% url 'colleges:_hx_fellowship_dynsel_list' %}"
+                hx-trigger="keyup delay:200ms, change"
+                hx-target="#nomination-{{ round.nomination.id }}_round-{{ round.id }}_add_voter_results">
+            <div id="nomination-{{ round.nomination.id }}_round-{{ round.id }}_add_voter_form">{% crispy voter_add_form %}</div>
+          </form>
+          <div id="nomination-{{ round.nomination.id }}_round-{{ round.id }}_add_voter_results"></div>
+        </div>
+
+        <div>
+          <h5>Add senior fellows</h5>
+          <button type="button"
+                  class="mb-2 btn btn-primary btn-sm"
+                  hx-get="{% url 'colleges:_hx_nomination_round_add_eligible_voter_set' round_id=round.id  voter_set_name='with_specialty_overlap' %}"
+                  hx-target="#nomination-{{ round.nomination.id }}-round-{{ round.id }}-voters">
+            With specialty overlap
+          </button>
+          <button type="button"
+                  class="mb-2 btn btn-warning text-white btn-sm"
+                  hx-get="{% url 'colleges:_hx_nomination_round_add_eligible_voter_set' round_id=round.id  voter_set_name='all_seniors' %}"
+                  hx-target="#nomination-{{ round.nomination.id }}-round-{{ round.id }}-voters">ALL seniors</button>
+        </div>
+
+        {% comment %} If round is open and the viewer can vote, show the voting form {% endcomment %}
+      {% elif session_fellowship and session_fellowship in round.eligible_to_vote.all and round.is_open %}
+
+        <div id="nomination-{{ round.nomination.id }}-vote"
+             hx-get="{% url 'colleges:_hx_nomination_vote' round_id=round.id %}"
+             hx-trigger="intersect once"></div>
+
+      {% endif %}
+
+      {% comment %} If round is closed show results if they exist {% endcomment %}
+    {% else %}
+      <div>{% include "colleges/_voting_results_box.html" with voting_round=voting_round %}</div>
+ 
+
+      {% if round.decision %}
+        <div>
+          <h3>Decision</h3>
+
+          {% if round.decision.outcome == 'elected' %}
+            <div class="badge fs-5 mb-2 bg-success">{{ round.decision.get_outcome_display }}</div>
+          {% elif round.decision.outcome == 'notelected' %}
+            <div class="badge fs-5 mb-2 bg-danger">{{ round.decision.get_outcome_display }}</div>
+          {% endif %}
+
+          {% if round.decision.comments %}
+            <h4 class="mt-2">Decision comments</h4>
+            <span>{{ round.decision.comments }}</span>
+          {% endif %}
+        {% endif %}
+
+      </div>
+    {% endif %}
+
+  </div>
+</div>
+
+{% if is_ed_admin %}
+
+  {% if not round.is_closed %}
+
+    <div hx-get="{% url 'colleges:_hx_voting_round_start_form' round_id=round.id %}"
+         hx-trigger="intersect once"></div>
+
+  {% elif round.is_closed and not round.decision %}
+
+    <div hx-get="{% url 'colleges:_hx_nomination_decision_form' round_id=round.id %}"
+         hx-trigger="intersect once"></div>
+
+  {% endif %}
+
+{% endif %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_round_search_form.html b/scipost_django/colleges/templates/colleges/_hx_voting_round_search_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..6c95f95a9462805b6093f3feda5751a88908d405
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_voting_round_search_form.html
@@ -0,0 +1,10 @@
+{% load crispy_forms_tags %}
+
+<form hx-post="{% url 'colleges:_hx_nominations_list' %}"
+      hx-trigger="load, keyup delay:500ms, change delay:500ms, click from:#refresh-button"
+      hx-sync="#search-nominations-form:replace"
+      hx-target="#search-nominations-results"
+      hx-indicator="#indicator-search-nominations">
+ 
+  <div id="search-nominations-form">{% crispy form %}</div>
+</form>
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_round_start_form.html b/scipost_django/colleges/templates/colleges/_hx_voting_round_start_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..2fffd05b3e0d9880349e9ab2d8412eb9e2877c9c
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_voting_round_start_form.html
@@ -0,0 +1,7 @@
+{% load crispy_forms_tags %}
+
+<form id="voting-round-{{ round.id }}-start-round-form"
+      hx-post="{% url 'colleges:_hx_voting_round_start_form' round_id=round.id %}"
+      hx-target="#voting-round-{{ round.id }}-start-round-form">
+  {% crispy form %}
+</form>
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_round_summary.html b/scipost_django/colleges/templates/colleges/_hx_voting_round_summary.html
new file mode 100644
index 0000000000000000000000000000000000000000..119a04577893d38d18035df8513aabcc14c448de
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_hx_voting_round_summary.html
@@ -0,0 +1,96 @@
+<div class="row mb-0">
+
+  {% if not round.is_unscheduled %}
+    <div class="order-1 col-12 col-sm-6 col-md-12 col-xl-7">
+      <div class="row justify-content-between">
+        <small class="col text-muted text-nowrap">Voting opens</small>
+
+        <div class="col-auto">
+
+          {% if round.is_open %}
+            {{ round.voting_opens|timesince }} ago
+          {% else %}
+            {{ round.voting_opens|date:"Y-m-d" }}
+          {% endif %}
+
+        </div>
+      </div>
+    </div>
+    <div class="order-2 order-sm-3 order-md-2 order-xl-3 col-12 col-sm-6 col-md-12 col-xl-7">
+      <div class="row justify-content-between">
+        <small class="col text-muted text-nowrap">Voting deadline</small>
+
+        <div class="col-auto">
+
+          {% if round.is_open %}
+            In {{ round.voting_deadline|timeuntil }}
+          {% else %}
+            {{ round.voting_deadline|date:"Y-m-d" }}
+          {% endif %}
+
+        </div>
+
+      </div>
+    </div>
+  {% else %}
+    <div class="order-1 col-12 col-sm-6 col-md-12 col-xl-7"></div>
+    <div class="order-2 order-sm-3 order-md-2 order-xl-3 col-12 col-sm-6 col-md-12 col-xl-7"></div>
+  {% endif %}
+
+  <div class="order-3 order-sm-2 order-md-3 order-xl-2 col-12 col-sm-6 col-md-12 col-xl-5">
+    <div class="row justify-content-between">
+      <small class="col text-muted text-nowrap">Voting status</small>
+
+      <div class="col-auto">
+
+        {% if round.is_unscheduled %}
+          <span class="badge bg-warning">Unscheduled</span>
+        {% elif round.is_open %}
+          <span class="badge bg-success">Open</span>
+        {% elif round.is_scheduled %}
+          <span class="badge bg-primary">Scheduled</span>
+        {% elif round.is_closed %}
+          <span class="badge bg-primary">Closed</span>
+        {% endif %}
+
+      </div>
+
+    </div>
+  </div>
+ 
+  <div class="order-4 col-12 col-sm-6 col-md-12 col-xl-5">
+    <div class="row justify-content-between">
+
+      {% if round.is_closed %}
+        <small class="col text-muted text-nowrap">Decision</small>
+
+        <div class="col-auto">
+
+          {% if round.decision.outcome == "elected" %}
+            <span class="badge bg-success">{{ round.decision.get_outcome_display }}</span>
+          {% elif round.decision.outcome == "notelected" %}
+            <span class="badge bg-danger">{{ round.decision.get_outcome_display }}</span>
+          {% else %}
+            <span class="badge bg-warning">Pending</span>
+          {% endif %}
+
+        </div>
+      {% else %}
+        <small class="col text-muted text-nowrap">Voted / Total</small>
+
+        <div class="col-auto">
+
+          {% if round.eligible_to_vote.count > 0 %}
+            {{ round.votes.count }}  /  {{ round.eligible_to_vote.count }}
+          {% else %}
+            <span class="badge bg-danger">None</span>
+          {% endif %}
+
+        </div>
+      {% endif %}
+
+ 
+    </div>
+  </div>
+
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html b/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html
deleted file mode 100644
index a472a42bf9fc834d2e7b3a69595384e3549ca23f..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% include 'colleges/_hx_voting_rounds_tablist.html' with selected=selected %}
-
-{% for round in voting_rounds %}
-  <div class="mt-4 p-2 border border-2" id="voting_round_{{ round.id }}">
-
-    {% include 'colleges/_hx_nomination_li.html' with nomination=round.nomination %}
-    <h3 class="mt-4">Voting deadline: {{ round.voting_deadline }}</h3>
-    {% if session_fellowship and session_fellowship in round.eligible_to_vote.all %}
-      <div id="nomination-{{ round.nomination.id }}-vote"
-	   hx-get="{% url 'colleges:_hx_nomination_vote' voting_round_id=round.id %}"
-	   hx-trigger="revealed"
-	   hx-target="this"
-      >
-      </div>
-    {% endif %}
-  </div>
-{% empty %}
-  <div class="p-2">No voting round found</div>
-{% endfor %}
diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_rounds_tablist.html b/scipost_django/colleges/templates/colleges/_hx_voting_rounds_tablist.html
deleted file mode 100644
index 0758404ac3999f8e579bd4e18bd0294a70a2d97e..0000000000000000000000000000000000000000
--- a/scipost_django/colleges/templates/colleges/_hx_voting_rounds_tablist.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<div class="tablist">
-  {% for tab_choice in tab_choices %}
-    <a hx-get="{% url 'colleges:_hx_voting_rounds' %}?tab={{ tab_choice.0 }}"
-       {% if selected == tab_choice.0 %}class="selected"{% endif %}
-    >{{ tab_choice.1 }}</a>
-  {% endfor %}
-</div>
diff --git a/scipost_django/colleges/templates/colleges/_nomination_events_table.html b/scipost_django/colleges/templates/colleges/_nomination_events_table.html
index 366616e9443ed813565fade618cdd051417e05c7..33e0307e93caf1df6b46abf6b61fbacfc5625608 100644
--- a/scipost_django/colleges/templates/colleges/_nomination_events_table.html
+++ b/scipost_django/colleges/templates/colleges/_nomination_events_table.html
@@ -1,18 +1,20 @@
-<table class="table m-2">
+<table class="table mb-0">
   <thead>
     <tr>
-      <th>Date and time</th>
+      <th>Date</th>
       <th>Description</th>
       <th>By</th>
     </tr>
   </thead>
   <tbody>
+
     {% for event in nomination.events.all %}
       <tr>
-	<td>{{ event.on }}</td>
-	<td>{{ event.description }}</td>
-	<td>{{ event.by }}</td>
+        <td>{{ event.on }}</td>
+        <td>{{ event.description }}</td>
+        <td>{{ event.by }}</td>
       </tr>
     {% endfor %}
+
   </tbody>
 </table>
diff --git a/scipost_django/colleges/templates/colleges/_nominations_invitation_checklist.html b/scipost_django/colleges/templates/colleges/_nominations_invitation_checklist.html
new file mode 100644
index 0000000000000000000000000000000000000000..84d0a2f937959aab8ec43ecb2b142787d77eb36a
--- /dev/null
+++ b/scipost_django/colleges/templates/colleges/_nominations_invitation_checklist.html
@@ -0,0 +1,49 @@
+<div class="p-2">
+  <ul class="mb-0 list-group list-group-flush">
+
+    <li class="list-group-item p-2">
+
+      {% if not invitation.nomination.profile.contributor %}
+        <span class="text-danger">{% include 'bi/x-square-fill.html' %}</span>
+        <span>&nbsp;This nominee is not yet registered as a Contributor.</span>
+      {% else %}
+        <span class="text-success">{% include 'bi/check-square-fill.html' %}</span>
+        <span>&nbsp;This nominee has a Contributor account.</span>
+      {% endif %}
+
+    </li>
+
+    <li class="list-group-item p-2">
+
+      {% if invitation.response == 'notyetinvited' %}
+        <span class="text-danger">{% include 'bi/x-square-fill.html' %}</span>
+        <span>&nbsp;This nominee is elected, but not yet invited.</span>
+        <a class="btn btn-sm btn-primary"
+           href="{% url 'colleges:fellowship_invitation_email_initial' pk=invitation.id %}">Invite</a>
+      {% else %}
+        <span class="text-success">{% include 'bi/check-square-fill.html' %}</span>
+        <span>&nbsp;This nominee has been invited to serve as a Fellow.</span>
+      {% endif %}
+
+    </li>
+
+
+    {% if invitation.response == 'accepted' or invitation.response == 'postponed' %}
+      <li class="list-group-item p-2">
+
+        {% if invitation.nomination.fellowship %}
+          <span class="text-danger">{% include 'bi/x-square-fill.html' %}</span>
+          <span>&nbsp;This nominee has no associated Fellowship with this college.</span>
+          <a href="{% url 'colleges:fellowship_create' contributor_id=invitation.nomination.profile.contributor.id %}"
+             target="_blank">Set up a Fellowship</a>
+        {% else %}
+          <span class="text-success">{% include 'bi/check-square-fill.html' %}</span>
+          <span>&nbsp;A fellowship has been created from this nomination.</span>
+        {% endif %}
+
+ 
+      </li>
+    {% endif %}
+
+  </ul>
+</div>
diff --git a/scipost_django/colleges/templates/colleges/_voting_results_box.html b/scipost_django/colleges/templates/colleges/_voting_results_box.html
index 577d2c8c461aafa56bb037b96feeb5df9e0f21cd..11592a769aaf5d6b96d315a0d24e5f81bf95b4c3 100644
--- a/scipost_django/colleges/templates/colleges/_voting_results_box.html
+++ b/scipost_django/colleges/templates/colleges/_voting_results_box.html
@@ -1,9 +1,8 @@
-<div class="border border-2 p-2">
-  <h3>Voting results summary</h3>
-  <ul class="list-inline m-2">
-    <li class="list-inline-item p-2">Eligible: {{ voting_round.eligible_to_vote.count }}</li>
-    <li class="list-inline-item p-2 text-success">Agree: {{ voting_round.votes.agree.count }}</li>
-    <li class="list-inline-item p-2 text-warning">Abstain: {{ voting_round.votes.abstain.count }}</li>
-    <li class="list-inline-item p-2 text-danger">Disagree: {{ voting_round.votes.disagree.count }}</li>
-  </ul>
-</div>
+<h3>Summary</h3>
+<ul class="list-group list-group-flush m-2">
+  <li class="list-group-item p-2 text-muted">Eligible: {{ voting_round.eligible_to_vote.count }}</li>
+  <li class="list-group-item p-2 text-success">Agree: {{ voting_round.votes.agree.count }}</li>
+  <li class="list-group-item p-2 text-warning">Abstain: {{ voting_round.votes.abstain.count }}</li>
+  <li class="list-group-item p-2 text-danger">Disagree: {{ voting_round.votes.disagree.count }}</li>
+  <li class="list-group-item p-2 text-black">Veto: {{ voting_round.votes.veto.count }}</li>
+</ul>
diff --git a/scipost_django/colleges/templates/colleges/nominations.html b/scipost_django/colleges/templates/colleges/nominations.html
index 47dc3a937191affd4c2fa88cdee24449a18346a0..388feb729bf8b238b4bfe1727a962757d8d5053d 100644
--- a/scipost_django/colleges/templates/colleges/nominations.html
+++ b/scipost_django/colleges/templates/colleges/nominations.html
@@ -1,5 +1,4 @@
 {% extends 'colleges/base.html' %}
-
 {% load user_groups %}
 {% load crispy_forms_tags %}
 
@@ -9,16 +8,19 @@
   <span class="breadcrumb-item">Nominations</span>
 {% endblock %}
 
-{% block meta_description %}{{ block.super }} Nominations{% endblock meta_description %}
-{% block pagetitle %}: Nominations{% endblock pagetitle %}
+{% block meta_description %}
+  {{ block.super }} Nominations
+{% endblock meta_description %}
 
-{% block content %}
+{% block pagetitle %}
+  : Nominations
+{% endblock pagetitle %}
 
+{% block content %}
   {% is_ed_admin request.user as is_ed_admin %}
-
   <h1 class="highlight">Fellowship Nominations</h1>
-
-  <p>Consult the
+  <p>
+    Consult the
     <a href="{% url 'submissions:monitor' %}" target="_blank">Submissions Monitor</a> page.
     Any <span class="text-danger">red-highlighted</span>
     specialty is in need of more Fellows&nbsp;
@@ -26,151 +28,60 @@
     &nbsp;<strong>Help out by nominating candidates!</strong>
   </p>
 
-  <details class="border border-warning border-2 mt-4">
-    <summary class="bg-warning bg-opacity-10 p-2">
-      <h2 class="ms-2">Nominate</h2>
-    </summary>
-    <div class="p-2">
-      <div class="row">
-	<div class="col-lg-6">
-	  <h3>Procedure</h3>
-	  <ul>
-	    <li>Type your search query in the search form</li>
-	    <li>When the name you're looking for appears in the
-	      <em>Matching profiles</em> list, double-click on it</li>
-	    <li>The nomination form will appear below</li>
-	    <li>Non-eligibility flags (if any) will appear</li>
-	    <li>If eligible, fill the form in (comments are optional)</li>
-	    <li>Submit! (the vote will be arranged by EdAdmin)</li>
-	  </ul>
-	  <div class="row">
-	    <div class="col-8">
-	      <form
-		  hx-post="{% url 'profiles:_hx_profile_dynsel_list' %}"
-		  hx-trigger="keyup delay:200ms, change"
-		  hx-target="#profile_dynsel_results"
-		  hx-indicator="#profile_dynsel_results-indicator"
-	      >
-		<div id="profile_dynsel_form">{% crispy profile_dynsel_form %}</div>
-	      </form>
-	    </div>
-	    <div class="col-2">
-	      <div id="nomination_form_response-indicator" class="htmx-indicator">
-		<button class="btn btn-sm btn-warning" type="button" disabled>
-		  <strong>Loading form...</strong>
-		  <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div>
-		</button>
-	      </div>
-	    </div>
-	    <div class="col-2">
-	      <div id="profile_dynsel_results-indicator" class="htmx-indicator">
-		<button class="btn btn-sm btn-warning" type="button" disabled>
-		  <strong>Loading results...</strong>
-		  <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div>
-		</button>
-	      </div>
-	    </div>
-	  </div>
-	  <h3 class="mb-2">Not found?</h3>
-	  <p>Then add to our database by <a href="{% url 'profiles:profile_create' %}" target="_blank">creating a new Profile</a> (opens in new window).</p>
-	</div>
-	<div class="col-lg-6">
-	  <h3>Matching profiles</h3>
-	  <div id="profile_dynsel_results" class="border border-light m-2 p-1"></div>
-	</div>
-      </div>
-      <div id="nomination_form_response"></div>
-    </div>
-  </details>
-
-  {% if "edadmin" in user_roles or "active_senior_fellow" in user_roles %}
-    <details id="ensure-specialties-details"
-      class="border border-danger border-2 mt-4"
-    >
-      <summary class="bg-danger bg-opacity-10 p-2">
-	<h2 class="ms-2">
-	  <strong class="text-danger">EdAdmin/Senior Fellows</strong>:
-	  ensure specialties in each nominee's profile</h2>
-      </summary>
-      <div class="p-2 mt-2">
-	<div id="nominations_needing_specialties"
-	     hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}"
-	     hx-trigger="toggle from:#ensure-specialties-details"
-	>
-	</div>
-      </div>
-    </details>
-  {% endif %}
+  <div id="new-nomination-container"></div>
 
-  <details id="voting-details"
-	   class="border border-primary border-2 mt-4"
-  >
-    <summary class="bg-primary bg-opacity-10 p-2">
-      <h2 class="ms-2 text-primary">Vote{% if 'edadmin' in user_roles %}&emsp;<span class="text-danger">(EdAdmin: manage voting)</span>{% endif %}</h2>
-    </summary>
-    <div class="p-2 mt-2">
-      <div id="voting_tablist"
-	   hx-get="{% url 'colleges:_hx_voting_rounds' %}?tab={% if 'edadmin' in user_roles %}ongoing{% else %}ongoing-vote_required{% endif %}"
-	   hx-trigger="toggle from:#voting-details"
-	   hx-target="this"
-	   hx-swap="innerHTML"
-      >
-      </div>
-    </div>
-  </details>
+  <details id="nominations-filter-details" class="card my-4">
+    <summary class="card-header d-flex flex-row align-items-center justify-content-between list-triangle">
+      <div class="fs-3">Search / Filter</div>
+      <div class="d-none d-md-flex align-items-center">
+ 
+        <div id="indicator-search-nominations" class="htmx-indicator">
+          <button class="btn btn-warning text-white d-none d-md-block me-2"
+                  type="button"
+                  disabled>
+            <strong>Loading...</strong>
+ 
+            <div class="spinner-grow spinner-grow-sm ms-2"
+                 role="status"
+                 aria-hidden="true"></div>
+          </button>
+        </div>
 
-  {% if "edadmin" in user_roles %}
-    <details id="invitations-details"
-	     class="border border-success border-2 mt-4"
-    >
-      <summary class="bg-success bg-opacity-10 p-2">
-	<h2 class="ms-2">
-	  <strong class="text-success">EdAdmin</strong>:
-	  (for elected) invitations</h2>
-      </summary>
-      <div class="p-2 mt-2">
-	<div id="invitations_tablist"
-	     hx-get="{% url 'colleges:_hx_nominations_invitations' %}?response=notyetinvited"
-	     hx-trigger="toggle from:#invitations-details"
-	     hx-target="this"
-	     hx-swap="innerHTML"
-	>
-	</div>
+        <button class="btn btn-outline-secondary me-2"
+                type="button"
+                hx-get="{% url 'colleges:_hx_nominations_search_form' filter_set="empty" %}"
+                hx-target="#nominations-search-form-container">Clear Filters</button>
+ 
+        <button class="btn btn-success me-2 text-white"
+                type="button"
+                hx-get="{% url 'colleges:_hx_nomination_new' %}"
+                hx-trigger="click"
+                hx-target="#new-nomination-container">
+          {% include "bi/plus-square.html" %}
+          &nbsp;Add New
+        </button>
+ 
+        <a id="refresh-button" class="me-2 btn btn-primary">
+          {% include "bi/arrow-clockwise.html" %}
+        &nbsp;Refresh</a>
       </div>
-    </details>
-  {% endif %}
 
-  <details id="list-details"
-	   class="border border-2 mt-4"
-  >
-    <summary class="bg-light p-2">
-      <h2 class="ms-2">List / filter</h2>
     </summary>
-    <div class="p-2 mt-2">
-      <form
-	  hx-post="{% url 'colleges:_hx_nominations' %}"
-	  hx-trigger="toggle from:#list-details, keyup delay:500ms, change"
-	  hx-target="#search-nominations-results"
-	  hx-indicator="#indicator-search"
-      >
-	<div id="search-nominations-form">{% crispy search_nominations_form %}</div>
-      </form>
-
-      <div class="row">
-	<div class="col">
-	  <h3>Nominations list</h3>
-	</div>
-	<div class="col">
-	  <div id="indicator-search-nominations" class="htmx-indicator">
-	    <button class="btn btn-sm btn-warning" type="button" disabled>
-	      <strong>Loading...</strong>
-	      <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div>
-	    </button>
-	  </div>
-	</div>
-      </div>
-      <ul id="search-nominations-results" class="list-unstyled mt-2"></ul>
+    <div class="card-body">
+      <div id="nominations-search-form-container"
+           hx-get="{% url 'colleges:_hx_nominations_search_form' filter_set='default' %}"
+           hx-trigger="load, intersect once"></div>
     </div>
   </details>
 
+  <div id="search-nominations-results" class="mt-2"></div>
+  <div id="indicator-nominations-search-page" class="htmx-indicator p-2">
+    <button class="btn btn-warning" type="button" disabled>
+      <strong>Loading</strong>
+      <div class="spinner-grow spinner-grow-sm ms-2"
+           role="status"
+           aria-hidden="true"></div>
+    </button>
+  </div>
+
 {% endblock content %}
diff --git a/scipost_django/colleges/urls.py b/scipost_django/colleges/urls.py
index 8743084fab237623ce66c3762927c22d209cfcaa..21299fad2d69c5c2cb3b92289645d517d31434ab 100644
--- a/scipost_django/colleges/urls.py
+++ b/scipost_django/colleges/urls.py
@@ -2,7 +2,7 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
-from django.urls import path
+from django.urls import include, path
 
 from . import views
 
@@ -161,48 +161,120 @@ urlpatterns = [
         views.PotentialFellowshipListView.as_view(),
         name="potential_fellowships",
     ),
-    # Nominations
-    path("nominations", views.nominations, name="nominations"),
-    path(
-        "_hx_nomination_form/<int:profile_id>",
-        views._hx_nomination_form,
-        name="_hx_nomination_form",
-    ),
-    path("_hx_nominations", views._hx_nominations, name="_hx_nominations"),
-    path(
-        "_hx_nomination_li_contents/<int:nomination_id>",
-        views._hx_nomination_li_contents,
-        name="_hx_nomination_li_contents",
-    ),
-    path(
-        "_hx_nomination_comments/<int:nomination_id>",
-        views._hx_nomination_comments,
-        name="_hx_nomination_comments",
-    ),
-    path(
-        "_hx_nominations_needing_specialties",
-        views._hx_nominations_needing_specialties,
-        name="_hx_nominations_needing_specialties",
-    ),
-    path(
-        "_hx_voting_rounds",
-        views._hx_voting_rounds,
-        name="_hx_voting_rounds",
-    ),
-    path(
-        "_hx_nomination_vote/<int:voting_round_id>",
-        views._hx_nomination_vote,
-        name="_hx_nomination_vote",
-    ),
-    path(
-        "_hx_nomination_decision/<int:nomination_id>",
-        views._hx_nomination_decision,
-        name="_hx_nomination_decision",
-    ),
-    path(
-        "_hx_nominations_invitations",
-        views._hx_nominations_invitations,
-        name="_hx_nominations_invitations",
+    ##########################
+    # Nominations and Voting #
+    ##########################
+    path(
+        "nominations/",
+        include(
+            [
+                path("", views.nominations, name="nominations"),
+                path("_hx_new", views._hx_nomination_new, name="_hx_nomination_new"),
+                path(
+                    "_hx_new_form/<int:profile_id>",
+                    views._hx_nomination_form,
+                    name="_hx_nomination_form",
+                ),
+                path(
+                    "search",
+                    include(
+                        [
+                            path(
+                                "_hx_form/<str:filter_set>",
+                                views._hx_nominations_search_form,
+                                name="_hx_nominations_search_form",
+                            ),
+                            path(
+                                "_hx_list",
+                                views._hx_nominations_list,
+                                name="_hx_nominations_list",
+                            ),
+                        ]
+                    ),
+                ),
+                path(
+                    "<int:nomination_id>/",
+                    include(
+                        [
+                            path(
+                                "_hx_round_tab/<int:round_id>",
+                                views._hx_nomination_voting_rounds_tab,
+                                name="_hx_nomination_voting_rounds_tab",
+                            ),
+                            path(
+                                "_hx_details_contents",
+                                views._hx_nomination_details_contents,
+                                name="_hx_nomination_details_contents",
+                            ),
+                            path(
+                                "_hx_create_voting_round",
+                                views._hx_nomination_voting_rounds_create,
+                                name="_hx_nomination_voting_rounds_create",
+                            ),
+                            path(
+                                "_hx_comments",
+                                views._hx_nomination_comments,
+                                name="_hx_nomination_comments",
+                            ),
+                        ]
+                    ),
+                ),
+            ]
+        ),
+    ),
+    # Nomination Rounds
+    path(
+        "nomination_voting_round/<int:round_id>/",
+        include(
+            [
+                path("_hx_vote", views._hx_nomination_vote, name="_hx_nomination_vote"),
+                path(
+                    "_hx_details",
+                    views._hx_voting_round_details,
+                    name="_hx_voting_round_details",
+                ),
+                path(
+                    "_hx_voter_table",
+                    views._hx_nomination_voter_table,
+                    name="_hx_nomination_voter_table",
+                ),
+                path(
+                    "forms/",
+                    include(
+                        [
+                            path(
+                                "start_round",
+                                views._hx_voting_round_start_form,
+                                name="_hx_voting_round_start_form",
+                            ),
+                            path(
+                                "decision",
+                                views._hx_nomination_decision_form,
+                                name="_hx_nomination_decision_form",
+                            ),
+                        ]
+                    ),
+                ),
+                # Manage voters of a nomination round
+                path(
+                    "voters/",
+                    include(
+                        [
+                            path(
+                                "<int:fellowship_id>/action/<str:action>",
+                                views._hx_nomination_round_eligible_voter_action,
+                                name="_hx_nomination_round_eligible_voter_action",
+                            ),
+                            path(
+                                "add_set/<str:voter_set_name>",
+                                views._hx_nomination_round_add_eligible_voter_set,
+                                name="_hx_nomination_round_add_eligible_voter_set",
+                            ),
+                        ]
+                    ),
+                ),
+            ],
+        ),
     ),
     path(
         "fellowship_invitation/<int:pk>/email_initial",
diff --git a/scipost_django/colleges/utils.py b/scipost_django/colleges/utils.py
index 06095bf586a5f5ffa0b4fbd648df41cd4a8ff43c..cf61ef5c5ddff1ecc7d9c7df4b8a2575b0344968 100644
--- a/scipost_django/colleges/utils.py
+++ b/scipost_django/colleges/utils.py
@@ -3,6 +3,8 @@ __license__ = "AGPL v3"
 
 
 from .models import College, Fellowship, FellowshipNomination
+import datetime
+from django.utils import timezone
 
 
 def check_profile_eligibility_for_fellowship(profile):
diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py
index 4489a90a019b4c8ef28c7253eefa3f758921a41d..1e78d148a5d7668819fd58885ccf1eeb10b5b222 100644
--- a/scipost_django/colleges/views.py
+++ b/scipost_django/colleges/views.py
@@ -28,6 +28,7 @@ from colleges.permissions import (
     is_edadmin_or_advisory_or_active_regular_or_senior_fellow,
 )
 from colleges.utils import check_profile_eligibility_for_fellowship
+from scipost.permissions import HTMXResponse
 from submissions.models import Submission
 
 from .constants import (
@@ -41,6 +42,8 @@ from .constants import (
 )
 from .forms import (
     CollegeChoiceForm,
+    FellowshipNominationSearchForm,
+    FellowshipNominationVotingRoundStartForm,
     FellowshipSearchForm,
     FellowshipDynSelForm,
     FellowshipForm,
@@ -695,18 +698,7 @@ def nominations(request):
     """
     List Nominations.
     """
-    profile_dynsel_form = ProfileDynSelForm(
-        initial={
-            "action_url_name": "colleges:_hx_nomination_form",
-            "action_url_base_kwargs": {},
-            "action_target_element_id": "nomination_form_response",
-            "action_target_swap": "innerHTML",
-        }
-    )
-    context = {
-        "profile_dynsel_form": profile_dynsel_form,
-        "search_nominations_form": FellowshipNominationSearchForm(),
-    }
+    context = {}
     return render(request, "colleges/nominations.html", context)
 
 
@@ -734,9 +726,9 @@ def _hx_nomination_form(request, profile_id):
             by=request.user.contributor,
         )
         event.save()
-        return HttpResponse(
-            f'<div class="bg-success text-white p-2 ">{nomination.profile} '
-            f"successfully nominated to {nomination.college}.</div>"
+        return HTMXResponse(
+            f"{nomination.profile} successfully nominated to {nomination.college}.",
+            tag="success",
         )
     nomination_form.fields["nominated_by"].initial = request.user.contributor
     context = {
@@ -746,26 +738,52 @@ def _hx_nomination_form(request, profile_id):
     return render(request, "colleges/_hx_nomination_form.html", context)
 
 
+def _hx_nomination_round_remove_voter(request, round_id, voter_id):
+    """Remove a voter from a nomination's voting round."""
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+
+    voter = get_object_or_404(Fellowship, pk=voter_id)
+    if voter in round.eligible_to_vote.all():
+        round.eligible_to_vote.remove(voter)
+        round.save()
+        messages.success(
+            request, f"Removed {voter} from the voters list of this round."
+        )
+    else:
+        messages.error(request, f"{voter} was not in the voters list of this round.")
+    return HttpResponse("")
+
+
 @login_required
-@user_passes_test(is_edadmin_or_senior_fellow)
-def _hx_nominations_needing_specialties(request):
-    nominations_needing_specialties = FellowshipNomination.objects.filter(
-        profile__specialties__isnull=True,
-    )
+@user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow)
+def _hx_nomination_details_contents(request, nomination_id):
+    """For (re)loading the details if modified."""
+    nomination = get_object_or_404(FellowshipNomination, pk=nomination_id)
     context = {
-        "nominations_needing_specialties": nominations_needing_specialties,
+        "nomination": nomination,
     }
-    return render(
-        request,
-        "colleges/_hx_nominations_needing_specialties.html",
-        context,
+    return render(request, "colleges/_hx_nomination_details_contents.html", context)
+
+
+def _hx_nominations_search_form(request, filter_set: str):
+    form = FellowshipNominationSearchForm(
+        user=request.user,
+        session_key=request.session.session_key,
     )
 
+    if filter_set == "empty":
+        form.apply_filter_set({}, none_on_empty=True)
 
-@login_required
-@user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow)
-def _hx_nominations(request):
-    form = FellowshipNominationSearchForm(request.POST or None)
+    context = {
+        "form": form,
+    }
+    return render(request, "colleges/_hx_nominations_search_form.html", context)
+
+
+def _hx_nominations_list(request):
+    form = FellowshipNominationSearchForm(
+        request.POST or None, user=request.user, session_key=request.session.session_key
+    )
     if form.is_valid():
         nominations = form.search_results()
     else:
@@ -773,19 +791,63 @@ def _hx_nominations(request):
     paginator = Paginator(nominations, 16)
     page_nr = request.GET.get("page")
     page_obj = paginator.get_page(page_nr)
-    context = {"page_obj": page_obj}
-    return render(request, "colleges/_hx_nominations.html", context)
+    count = paginator.count
+    start_index = page_obj.start_index
+    context = {
+        "count": count,
+        "page_obj": page_obj,
+        "start_index": start_index,
+    }
+    return render(request, "colleges/_hx_nominations_list.html", context)
 
 
 @login_required
 @user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow)
-def _hx_nomination_li_contents(request, nomination_id):
-    """For (re)loading the details if modified."""
+def _hx_nomination_voting_rounds_tab(request, nomination_id, round_id):
+    """Render the selected voting round contents and display the others as tabs."""
     nomination = get_object_or_404(FellowshipNomination, pk=nomination_id)
+    voting_rounds = nomination.voting_rounds.all().order_by("-voting_opens")
+
+    inaccessible_round_ids = [
+        round.id for round in voting_rounds if not round.can_view(request.user)
+    ]
+
+    should_show_new_round_tab_btn = request.user.contributor.is_ed_admin and (
+        nomination.voting_rounds.count() == 0
+        or (
+            nomination.latest_voting_round.is_closed
+            and (decision := getattr(nomination.latest_voting_round, "decision", None))
+            and not decision.outcome == FellowshipNominationDecision.OUTCOME_ELECTED
+        )
+    )
+
     context = {
         "nomination": nomination,
+        "voting_rounds": voting_rounds,
+        "inaccessible_round_ids": inaccessible_round_ids,
+        "should_show_new_round_tab_btn": should_show_new_round_tab_btn,
     }
-    return render(request, "colleges/_hx_nomination_li_contents.html", context)
+
+    if round_id != 0:
+        selected_round = voting_rounds.get(id=round_id)
+        context["selected_round"] = selected_round
+
+    return render(request, "colleges/_hx_nomination_voting_rounds_tab.html", context)
+
+
+@login_required
+@user_passes_test(is_edadmin)
+def _hx_nomination_voting_rounds_create(request, nomination_id):
+    nomination = get_object_or_404(FellowshipNomination, pk=nomination_id)
+    new_round = FellowshipNominationVotingRound(
+        nomination=nomination, voting_opens=None, voting_deadline=None
+    )
+    new_round.save()
+    _ = _hx_nomination_round_add_eligible_voter_set(
+        request, new_round.id, "with_specialty_overlap"
+    )
+
+    return _hx_nomination_voting_rounds_tab(request, nomination_id, new_round.id)
 
 
 @login_required
@@ -810,63 +872,20 @@ def _hx_nomination_comments(request, nomination_id):
 
 @login_required
 @user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow)
-def _hx_voting_rounds(request):
-    selected = request.GET.get("tab", "ongoing")
-    tab_choices = []
-    if request.user.contributor.is_ed_admin:
-        tab_choices += [
-            ("ongoing", "Ongoing"),
-            ("closed-pending", "Closed"),
-            ("closed-elected", "Closed (elected)"),
-            ("closed-notelected", "Closed (not elected)"),
-        ]
-    elif request.user.contributor.is_active_fellow:
-        tab_choices += [
-            ("ongoing-vote_required", "Cast your vote (election ongoing)"),
-            ("ongoing-voted", "Votes you have cast (election ongoing)"),
-            ("closed-voted", "Votes you have cast (election closed)"),
-        ]
-    fellowship = request.user.contributor.session_fellowship(request)
-    voting_rounds = FellowshipNominationVotingRound.objects.all()
-    if "ongoing" in selected:
-        voting_rounds = voting_rounds.ongoing()
-    if "closed" in selected:
-        voting_rounds = voting_rounds.closed()
-    if "-pending" in selected:
-        voting_rounds = voting_rounds.filter(nomination__decision__isnull=True)
-    if "-elected" in selected:
-        voting_rounds = voting_rounds.filter(
-            nomination__decision__outcome=FellowshipNominationDecision.OUTCOME_ELECTED
-        )
-    if "-notelected" in selected:
-        voting_rounds = voting_rounds.filter(
-            nomination__decision__outcome=FellowshipNominationDecision.OUTCOME_NOT_ELECTED
-        )
-    if "vote_required" in selected:
-        # show all voting rounds to edadmin; for Fellow, filter
-        if not request.user.contributor.is_ed_admin:
-            voting_rounds = voting_rounds.filter(eligible_to_vote=fellowship).exclude(
-                votes__fellow=fellowship
-            )
-    if "voted" in selected:
-        voting_rounds = voting_rounds.filter(votes__fellow=fellowship)
-    context = {
-        "tab_choices": tab_choices,
-        "selected": selected,
-        "voting_rounds": voting_rounds,
-    }
-    return render(request, "colleges/_hx_voting_rounds.html", context)
-
-
-@login_required
-@user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow)
-def _hx_nomination_vote(request, voting_round_id):
+def _hx_nomination_vote(request, round_id):
     fellowship = request.user.contributor.session_fellowship(request)
     voting_round = get_object_or_404(
         FellowshipNominationVotingRound,
-        pk=voting_round_id,
+        pk=round_id,
         eligible_to_vote=fellowship,
     )
+
+    # Check if the voting round is still open
+    if not voting_round.is_open:
+        return HTMXResponse(
+            """You cannot vote in non-open rounds.""",
+            tag="danger",
+        )
     if request.method == "POST":
         vote_object, created = FellowshipNominationVote.objects.update_or_create(
             voting_round=voting_round,
@@ -894,15 +913,42 @@ def _hx_nomination_vote(request, voting_round_id):
     context = {
         "voting_round": voting_round,
         "vote_object": vote_object,
+        "VOTE_BS_CLASSES": FellowshipNominationVote.VOTE_BS_CLASSES,
     }
     return render(request, "colleges/_hx_nomination_vote.html", context)
 
 
 @login_required
 @user_passes_test(is_edadmin)
-def _hx_nomination_decision(request, nomination_id):
-    nomination = get_object_or_404(FellowshipNomination, pk=nomination_id)
-    decision_form = FellowshipNominationDecisionForm(request.POST or None)
+def _hx_voting_round_start_form(request, round_id):
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+    form = FellowshipNominationVotingRoundStartForm(
+        request.POST or None,
+        instance=round,
+    )
+    if form.is_valid():
+        form.save()
+        messages.success(
+            request,
+            f"Voting round for {round.nomination.profile} started "
+            f"from {round.voting_opens} until {round.voting_deadline}.",
+        )
+
+    return render(
+        request,
+        "colleges/_hx_voting_round_start_form.html",
+        {"form": form, "round": round},
+    )
+
+
+@login_required
+@user_passes_test(is_edadmin)
+def _hx_nomination_decision_form(request, round_id):
+    voting_round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+    nomination = voting_round.nomination
+    decision_form = FellowshipNominationDecisionForm(
+        request.POST or None, voting_round=voting_round
+    )
     if decision_form.is_valid():
         decision = decision_form.save()
         nomination.add_event(description="Decision fixed", by=request.user.contributor)
@@ -915,29 +961,29 @@ def _hx_nomination_decision(request, nomination_id):
             nomination.add_event(
                 description="Invitation created", by=request.user.contributor
             )
-    else:
-        decision_form.fields["nomination"].initial = nomination
     context = {
-        "nomination": nomination,
+        "voting_round": voting_round,
         "decision_form": decision_form,
     }
-    return render(request, "colleges/_hx_nomination_decision.html", context)
+    return render(request, "colleges/_hx_nomination_decision_form.html", context)
 
 
-@login_required
-@user_passes_test(is_edadmin)
-def _hx_nominations_invitations(request):
-    selected = request.GET.get("response", "notyetinvited")
-    invitations = FellowshipInvitation.objects.filter(
-        nomination__fellowship__isnull=True,
-        response=selected,
+# Check permission to create a new nomination
+def _hx_nomination_new(request):
+    """Render the contents of the new nomination form."""
+    profile_dynsel_form = ProfileDynSelForm(
+        initial={
+            "action_url_name": "colleges:_hx_nomination_form",
+            "action_url_base_kwargs": {},
+            "action_target_element_id": "nomination_form_response",
+            "action_target_swap": "innerHTML",
+        }
     )
     context = {
-        "response_choices": FellowshipInvitation.RESPONSE_CHOICES,
-        "selected": selected,
-        "invitations": invitations,
+        "profile_dynsel_form": profile_dynsel_form,
     }
-    return render(request, "colleges/_hx_nominations_invitations.html", context)
+
+    return render(request, "colleges/_hx_nomination_new.html", context)
 
 
 class FellowshipInvitationEmailInitialView(PermissionsMixin, MailView):
@@ -974,12 +1020,69 @@ def _hx_fellowship_invitation_update_response(request, invitation_id):
             description=f"Response updated to: {invitation.get_response_display()}",
             by=request.user.contributor,
         )
-        return redirect(
-            "%s?response=%s"
-            % (
-                reverse("colleges:_hx_nominations_invitations"),
-                form.cleaned_data["response"],
+
+        nonexpired_fellowship = (
+            Fellowship.objects.exclude(
+                until_date__lte=timezone.now().date(),
             )
+            .filter(
+                college=invitation.nomination.college,
+                contributor=invitation.nomination.profile.contributor,
+            )
+            .order_by("-start_date")
+            .first()
+        )
+
+        # If the invitation is accepted or postponed, create a Fellowship
+        if invitation.response in [
+            FellowshipInvitation.RESPONSE_ACCEPTED,
+            FellowshipInvitation.RESPONSE_POSTPONED,
+        ]:
+            # Create a new Fellowship if no object exists
+            if not nonexpired_fellowship:
+                fellowship = Fellowship.objects.create(
+                    college=invitation.nomination.college,
+                    contributor=invitation.nomination.profile.contributor,
+                    start_date=timezone.now()
+                    if invitation.response == FellowshipInvitation.RESPONSE_ACCEPTED
+                    else invitation.postpone_start_to,
+                    until_date=None,
+                )
+
+                invitation.nomination.add_event(
+                    description=f"Fellowship created (start: {fellowship.start_date.strftime('%Y-%m-%d')})",
+                    by=request.user.contributor,
+                )
+            else:
+                # Update the start date of the Fellowship if an object already exists
+                nonexpired_fellowship.start_date = (
+                    timezone.now()
+                    if invitation.response == FellowshipInvitation.RESPONSE_ACCEPTED
+                    else invitation.postpone_start_to
+                )
+                nonexpired_fellowship.until_date = None
+                invitation.nomination.add_event(
+                    description=f"Fellowship start date updated (start: {nonexpired_fellowship.start_date.strftime('%Y-%m-%d')})",
+                    by=request.user.contributor,
+                )
+                nonexpired_fellowship.save()
+        # Terminate the Fellowship if the invitation is declined
+        elif invitation.response == FellowshipInvitation.RESPONSE_DECLINED:
+            if nonexpired_fellowship:
+                nonexpired_fellowship.until_date = (
+                    timezone.now().date()
+                    if nonexpired_fellowship.is_active()
+                    else nonexpired_fellowship.start_date
+                )
+                invitation.nomination.add_event(
+                    description=f"Fellowship ended (end: {nonexpired_fellowship.until_date.strftime('%Y-%m-%d')})",
+                    by=request.user.contributor,
+                )
+                nonexpired_fellowship.save()
+
+        return HTMXResponse(
+            f"Response updated to: {invitation.get_response_display()}",
+            tag="success",
         )
     context = {
         "invitation": invitation,
@@ -990,3 +1093,99 @@ def _hx_fellowship_invitation_update_response(request, invitation_id):
         "colleges/_hx_nomination_invitation_update_response.html",
         context,
     )
+
+
+@login_required
+@user_passes_test(is_edadmin_or_senior_fellow)
+def _hx_nomination_voter_table(request, round_id):
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+    voters = round.eligible_to_vote.all()
+    nominee_specialties = round.nomination.profile.specialties.all()
+
+    for voter in voters:
+        voter.vote = round.votes.filter(fellow=voter).first()
+
+    context = {
+        "voters": voters,
+        "round": round,
+        "nominee_specialties": nominee_specialties,
+    }
+    return render(request, "colleges/_hx_nomination_voter_table.html", context)
+
+
+@login_required
+@user_passes_test(is_edadmin)
+def _hx_nomination_round_eligible_voter_action(
+    request, round_id, fellowship_id, action
+):
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+    fellowship = get_object_or_404(Fellowship, pk=fellowship_id)
+
+    if action == "add":
+        print(round.nomination.profile)
+        if round.nomination.profile.has_competing_interest_with(
+            fellowship.contributor.profile
+        ):
+            messages.error(
+                request,
+                f"{fellowship} has a competing interest with the nominee and cannot be added to the voters list.",
+            )
+        else:
+            round.eligible_to_vote.add(fellowship)
+    if action == "remove":
+        round.eligible_to_vote.remove(fellowship)
+    return redirect(
+        reverse("colleges:_hx_nomination_voter_table", kwargs={"round_id": round.id})
+    )
+
+
+@login_required
+@user_passes_test(is_edadmin)
+def _hx_nomination_round_add_eligible_voter_set(request, round_id, voter_set_name):
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+
+    voter_set = Fellowship.objects.none()
+
+    senior_active_fellows = (
+        Fellowship.objects.active()
+        .no_competing_interests_with(round.nomination.profile)
+        .senior()
+    )
+
+    if voter_set_name == "with_specialty_overlap":
+        specialties_slug_list = [
+            s.slug for s in round.nomination.profile.specialties.all()
+        ]
+        voter_set = senior_active_fellows.specialties_overlap(specialties_slug_list)
+    elif voter_set_name == "all_seniors":
+        voter_set = senior_active_fellows.filter(college=round.nomination.college)
+
+    round.eligible_to_vote.add(*voter_set.distinct())
+    return redirect(
+        reverse("colleges:_hx_nomination_voter_table", kwargs={"round_id": round.id})
+    )
+
+
+@login_required
+@user_passes_test(is_edadmin_or_senior_fellow)
+def _hx_voting_round_details(request, round_id):
+    round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)
+    context = {
+        "round": round,
+    }
+
+    if not round.can_view(request.user):
+        return HTMXResponse("You are not allowed to view this round.", tag="danger")
+
+    if not round.is_closed:
+        voter_add_form = FellowshipDynSelForm(
+            initial={
+                "action_url_name": "colleges:_hx_nomination_round_eligible_voter_action",
+                "action_url_base_kwargs": {"round_id": round_id, "action": "add"},
+                "action_target_element_id": f"nomination-{round.nomination.id}-round-{round_id}-voters",
+                "action_target_swap": "innerHTML",
+            }
+        )
+        context["voter_add_form"] = voter_add_form
+
+    return render(request, "colleges/_hx_voting_round_details.html", context)
diff --git a/scipost_django/common/urls.py b/scipost_django/common/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..62d8ae697bfac4596f6bd845824e3c664b30e5c9
--- /dev/null
+++ b/scipost_django/common/urls.py
@@ -0,0 +1,17 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.urls import path
+
+from . import views
+
+app_name = "common"
+
+urlpatterns = [
+    path(
+        "empty",
+        views.empty,
+        name="empty",
+    )
+]
diff --git a/scipost_django/common/views.py b/scipost_django/common/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..006780c0cef27c3a698ec9292262332e99b601fa
--- /dev/null
+++ b/scipost_django/common/views.py
@@ -0,0 +1,8 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+from django.http import HttpResponse
+
+
+def empty(request):
+    return HttpResponse("")
diff --git a/scipost_django/profiles/managers.py b/scipost_django/profiles/managers.py
index c185168a5b463de5377e0b2c0f17244399278245..887cc5307efb340fbebe6886890840cbe11a1339 100644
--- a/scipost_django/profiles/managers.py
+++ b/scipost_django/profiles/managers.py
@@ -72,6 +72,18 @@ class ProfileQuerySet(models.QuerySet):
         """
         return self.filter(specialties__slug__in=specialties_slug_list)
 
+    def no_competing_interests_with(self, profile):
+        """
+        Returns all Profiles which have no competing interests with the specified profile.
+        """
+        from ethics.models import CompetingInterest
+
+        profile_CI, related_CI = CompetingInterest.objects.filter(
+            Q(profile=profile) | Q(related_profile=profile)
+        ).values_list("profile", "related_profile")
+
+        return self.exclude(id__in=profile_CI + related_CI)
+
 
 class AffiliationQuerySet(models.QuerySet):
     def current(self):
diff --git a/scipost_django/profiles/models.py b/scipost_django/profiles/models.py
index 16fde268cd75b01aad22e84e860083ecb330b100..fe35187eb900a18ee85d82986ab40189cabc43ef 100644
--- a/scipost_django/profiles/models.py
+++ b/scipost_django/profiles/models.py
@@ -3,6 +3,7 @@ __license__ = "AGPL v3"
 
 
 import datetime
+from django.db.models import Q
 
 from django.urls import reverse
 from django.db import models
@@ -164,6 +165,17 @@ class Profile(models.Model):
             "fulfilled": invitations.filter(fulfilled=True).count(),
         }
 
+    def has_competing_interest_with(self, profile):
+        """
+        Returns True if this Profile has a CompetingInterest with the given Profile.
+        """
+        from ethics.models import CompetingInterest
+
+        return CompetingInterest.objects.filter(
+            Q(profile=self, related_profile=profile)
+            | Q(related_profile=self, profile=profile)
+        ).exists()
+
 
 class ProfileEmail(models.Model):
     """Any email related to a Profile instance."""
diff --git a/scipost_django/profiles/templates/profiles/_affiliations_table.html b/scipost_django/profiles/templates/profiles/_affiliations_table.html
index dc981e2ebf9693e2be638a51921f6aa721a3be19..2900c0bb3487a03a08dd4e671575ada8427268de 100644
--- a/scipost_django/profiles/templates/profiles/_affiliations_table.html
+++ b/scipost_django/profiles/templates/profiles/_affiliations_table.html
@@ -1,20 +1,24 @@
-<table class="table">
-  <thead class="table-light">
+<table class="table mb-0">
+  <thead>
     <tr>
       <th>Organization</th>
       <th>Category</th>
       <th>From</th>
       <th>Until</th>
-      {% if actions %}
-	<td>Actions</td>
-      {% endif %}
+
+      {% if actions %}<th>Actions</th>{% endif %}
+
     </tr>
   </thead>
   <tbody>
+
     {% for aff in profile.affiliations.all %}
       {% include 'profiles/_affiliations_table_row.html' with affiliation=aff actions=actions %}
     {% empty %}
-      <tr><td colspan="4">No Affiliation has been defined</td></tr>
+      <tr>
+        <td colspan="4">No Affiliation has been defined</td>
+      </tr>
     {% endfor %}
+
   </tbody>
 </table>
diff --git a/scipost_django/profiles/templates/profiles/_hx_profile_specialties.html b/scipost_django/profiles/templates/profiles/_hx_profile_specialties.html
index e695a1b549269a0fdcd43a6449f0040005c8c554..1168855e42c3eb14c8a92a05050f0b41ef43dd21 100644
--- a/scipost_django/profiles/templates/profiles/_hx_profile_specialties.html
+++ b/scipost_django/profiles/templates/profiles/_hx_profile_specialties.html
@@ -2,49 +2,63 @@
   <div class="col">
     <table class="table">
       <caption style="caption-side: top;">Specialties (current)</caption>
+
       {% for spec in profile.specialties.all %}
-	<tr>
-	  <td>{{ spec }}</td>
-	  <td>
-	    <form hx-post="{% url 'profiles:_hx_profile_specialties' profile_id=profile.id %}"
-		  hx-target="#profile-{{ profile.id }}-specialties"
-	    >
-	      {% csrf_token %}
-	      <input type="hidden" name="action" value="remove">
-	      <input type="hidden" name="spec_slug" value="{{ spec.slug }}">
-	      <button class="btn btn-sm btn-danger">Remove</button>
-	    </form>
-	  </td>
-	</tr>
+        <tr>
+          <td>{{ spec }}</td>
+          <td>
+            <form hx-post="{% url 'profiles:_hx_profile_specialties' profile_id=profile.id %}"
+                  hx-target="#profile-{{ profile.id }}-specialties">
+              {% csrf_token %}
+              <input type="hidden" name="action" value="remove" />
+              <input type="hidden" name="spec_slug" value="{{ spec.slug }}" />
+              <button class="btn btn-sm btn-danger">Remove</button>
+            </form>
+          </td>
+        </tr>
       {% empty %}
-	<tr>
-	  <td colspan="2">None defined</td>
-	</tr>
+        <tr>
+          <td colspan="2">None defined</td>
+        </tr>
       {% endfor %}
+
     </table>
   </div>
   <div class="col">
     <table class="table">
       <caption style="caption-side: top;">Other specialties</caption>
+
       {% for spec in other_specialties.all %}
-	<tr>
-	  <td>{{ spec }}</td>
-	  <td>
-	    <form hx-post="{% url 'profiles:_hx_profile_specialties' profile_id=profile.id %}"
-		  hx-target="#profile-{{ profile.id }}-specialties"
-	    >
-	      {% csrf_token %}
-	      <input type="hidden" name="action" value="add">
-	      <input type="hidden" name="spec_slug" value="{{ spec.slug }}">
-	      <button class="btn btn-sm btn-primary">Add</button>
-	    </form>
-	  </td>
-	</tr>
+        <tr>
+          <td>{{ spec }}</td>
+          <td>
+            <form hx-post="{% url 'profiles:_hx_profile_specialties' profile_id=profile.id %}"
+                  hx-target="#profile-{{ profile.id }}-specialties">
+              {% csrf_token %}
+              <input type="hidden" name="action" value="add" />
+              <input type="hidden" name="spec_slug" value="{{ spec.slug }}" />
+              <button class="btn btn-sm btn-primary">Add</button>
+            </form>
+          </td>
+        </tr>
       {% empty %}
-	<tr>
-	  <td colspan="2">None defined</td>
-	</tr>
+        <tr>
+          <td colspan="2">None defined</td>
+        </tr>
       {% endfor %}
+
     </table>
   </div>
 </div>
+
+<button class="btn btn-success mb-2 text-white"
+        hx-get="{% url "common:empty" %}"
+        hx-swap="innerHTML"
+        hx-target="#profile-{{ profile.id }}-specialties">Done</button>
+
+
+<div hx-swap-oob="innerHTML:#profile-{{ profile.id }}-specialties-code-display">
+
+  {% include "profiles/_hx_profile_specialty_codes_edit.html" with profile=profile %}
+
+</div>
diff --git a/scipost_django/profiles/templates/profiles/_hx_profile_specialty_codes_edit.html b/scipost_django/profiles/templates/profiles/_hx_profile_specialty_codes_edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..ce66b675f0ddc601652c03ef09d7f84cbf56836d
--- /dev/null
+++ b/scipost_django/profiles/templates/profiles/_hx_profile_specialty_codes_edit.html
@@ -0,0 +1,13 @@
+{% for specialty in profile.specialties.all %}
+  <div class="single d-inline"
+       data-specialty="{{ specialty }}"
+       data-bs-toggle="tooltip"
+       data-bs-placement="bottom"
+       title="{{ specialty }}">{{ specialty.code }}</div>
+{% empty %}
+  <span class="badge bg-danger">unknown</span>
+{% endfor %}
+
+<a class="p-2 mt-2"
+   hx-get="{% url 'profiles:_hx_profile_specialties' profile_id=profile.id %}"
+   hx-target="#profile-{{ profile.id }}-specialties">edit</a>
diff --git a/scipost_django/scipost/management/commands/add_groups_and_permissions.py b/scipost_django/scipost/management/commands/add_groups_and_permissions.py
index 4c3fdeffed1baec0d3db1555355e4b85c77a7694..e57c7baca207ba325135c8803b0b4797534c49bb 100644
--- a/scipost_django/scipost/management/commands/add_groups_and_permissions.py
+++ b/scipost_django/scipost/management/commands/add_groups_and_permissions.py
@@ -405,6 +405,16 @@ class Command(BaseCommand):
             content_type=content_type,
         )
 
+        # Fellowship Nominations
+        (
+            can_view_all_nomination_voting_rounds,
+            created,
+        ) = Permission.objects.get_or_create(
+            codename="can_view_all_nomination_voting_rounds",
+            name="Can view all voting rounds for Fellowship nominations",
+            content_type=content_type,
+        )
+
         # Assign permissions to groups
         SciPostAdmin.permissions.set(
             [
@@ -438,6 +448,7 @@ class Command(BaseCommand):
                 can_view_potentialfellowship_list,
                 can_add_potentialfellowship,
                 can_preview_new_features,
+                can_view_all_nomination_voting_rounds,
             ]
         )
 
@@ -497,6 +508,7 @@ class Command(BaseCommand):
                 can_view_potentialfellowship_list,
                 can_add_potentialfellowship,
                 can_preview_new_features,
+                can_view_all_nomination_voting_rounds,
             ]
         )
 
diff --git a/scipost_django/scipost/static/scipost/assets/config/preconfig.scss b/scipost_django/scipost/static/scipost/assets/config/preconfig.scss
index b47abe90de8a04b4e4464510922d8bba421bae13..ed517ef68361c1ac061ebda19dbb3fee55d79781 100644
--- a/scipost_django/scipost/static/scipost/assets/config/preconfig.scss
+++ b/scipost_django/scipost/static/scipost/assets/config/preconfig.scss
@@ -223,39 +223,44 @@ $theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value");
   height: 1.5em !important;
 }
 
-summary {
-  // Remove triangle for webkit browsers causing problems with flexbox
-  &::-webkit-details-marker {
-    display: none;
-  }
-
-  // Remove all list styles
-  &.list-none {
-    list-style: none;
-  }
-  
-  // List triangle for summary element (necessary with display: flex)
-  &.list-triangle {
-    position: relative;
-    padding-left: 2em !important;
-
-    // Styling the equilateral triangle
-    &::before {
-      content: "â–¶";
-      position: absolute;
-      left: 0.75em;
-      top: 50%;
-      transform: translateY(-50%);
+details {
+    summary {
+        // Remove triangle for webkit browsers causing problems with flexbox
+        &::-webkit-details-marker {
+            display: none;
+        }
+
+        // Remove all list styles
+        &.list-none {
+            list-style: none;
+        }
+        
+        // // List triangle for summary element (necessary with display: flex)
+        &.list-triangle {
+            position: relative;
+            padding-left: 2em !important;
+
+            // Styling the equilateral triangle
+            &::before {
+                content: "â–¶";
+                position: absolute;
+                left: 0.75em;
+                top: 50%;
+                transform: translateY(-50%);
+                transition: transform 0.05s linear;
+            }
+            
+            @at-root {
+                // Rotate the equilateral triangle when summary is open
+                details[open] > summary.list-triangle::before {
+                    content: "â–¶";
+                    transform: translateY(-50%) translateX(-25%) rotate(90deg);
+                }
+            }
+        }
     }
-  }
 }
 
-// Rotate the equilateral triangle when summary is open
-details[open] summary.list-triangle::before {
-  content: "â–¼";
-}
-
-
 // Utilities for details element
 // Hide details preview when open
 details[open] {
@@ -263,7 +268,7 @@ details[open] {
         display: none;
     }
 }
-details[closed] {
+details:not([open]) {
     .details-preview {
         display: unset;
     }