diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 76450ed9e6fdccb574a17ca23fde70e7ed0dbe7b..c57f93ce9a44e03b865a77db1500a5622715e0f5 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -48,6 +48,7 @@ Changed
 * Login and authorization pages for OAuth2/OpenID Connect now indicate that the user is in progress
   to authorize an external application.
 * Tables can be scrolled horizontally.
+* Overhauled person detail page
 
 `2.5`_ – 2022-01-02
 -------------------
diff --git a/aleksis/core/migrations/0033_update_photo_avatar.py b/aleksis/core/migrations/0033_update_photo_avatar.py
index 12dfa4fbc50a0119ed0e7fec0ce73a5e5cbc0f45..e20c6ee6bff00581fa7f586b2e9e9888ce1dfd1d 100644
--- a/aleksis/core/migrations/0033_update_photo_avatar.py
+++ b/aleksis/core/migrations/0033_update_photo_avatar.py
@@ -30,4 +30,12 @@ class Migration(migrations.Migration):
             name='photo',
             field=models.ImageField(blank=True, help_text='This is an official photo, used for official documents and for internal use cases.', null=True, upload_to='', verbose_name='Photo'),
         ),
+        migrations.AlterModelOptions(
+            name='globalpermissions',
+            options={'default_permissions': (), 'managed': False, 'permissions': (('view_system_status', 'Can view system status'), ('manage_data', 'Can manage data'), ('impersonate', 'Can impersonate'), ('search', 'Can use search'), ('change_site_preferences', 'Can change site preferences'), ('change_person_preferences', 'Can change person preferences'), ('change_group_preferences', 'Can change group preferences'), ('test_pdf', 'Can test PDF generation'))},
+        ),
+        migrations.AlterModelOptions(
+            name='person',
+            options={'ordering': ['last_name', 'first_name'], 'permissions': (('view_address', 'Can view address'), ('view_contact_details', 'Can view contact details'), ('view_photo', 'Can view photo'), ('view_avatar', 'Can view avatar image'), ('view_person_groups', 'Can view persons groups'), ('view_personal_details', 'Can view personal details')), 'verbose_name': 'Person', 'verbose_name_plural': 'Persons'},
+        ),
     ]
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index bd26f4f4edbc04bbef679ae92311b1215138f3ad..9c78211eac9dfabe6e1d0b8de8e2034f0dc9da2c 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -155,6 +155,7 @@ class Person(ExtensibleModel):
             ("view_address", _("Can view address")),
             ("view_contact_details", _("Can view contact details")),
             ("view_photo", _("Can view photo")),
+            ("view_avatar", _("Can view avatar image")),
             ("view_person_groups", _("Can view persons groups")),
             ("view_personal_details", _("Can view personal details")),
         )
@@ -311,6 +312,10 @@ class Person(ExtensibleModel):
         """Return the count of unread notifications for this person."""
         return self.unread_notifications.count()
 
+    @property
+    def initials(self):
+        return f"{self.first_name[0]}{self.last_name[0]}".upper()
+
     user_info_tracker = FieldTracker(fields=("first_name", "last_name", "email"))
 
     @property
diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py
index 9fc08709ec48e74f0a3801262d29a527764ac323..f989b7b0814aca40b9604512a4ac69690906f2e4 100644
--- a/aleksis/core/rules.py
+++ b/aleksis/core/rules.py
@@ -58,6 +58,12 @@ view_photo_predicate = has_person & (
 )
 rules.add_perm("core.view_photo_rule", view_photo_predicate)
 
+# View person avatar image
+view_avatar_predicate = has_person & (
+    has_global_perm("core.view_avatar") | has_object_perm("core.view_avatar") | is_current_person
+)
+rules.add_perm("core.view_avatar_rule", view_avatar_predicate)
+
 # View persons groups
 view_groups_predicate = has_person & (
     has_global_perm("core.view_person_groups")
diff --git a/aleksis/core/static/img/hero.svg b/aleksis/core/static/img/hero.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e11b51689d359a713f0bf5482a91c388a8632b60
--- /dev/null
+++ b/aleksis/core/static/img/hero.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="1080px" width="1920px">
+  <defs>
+    <pattern id="doodad" width="92.38" height="80" viewBox="0 0 34.64101615137755 30" patternUnits="userSpaceOnUse" patternTransform="rotate(134)">
+      <path d="M-20-20h200v200h-200M33.77 25.5L25.98 21L18.19 25.5L18.19 34.5L25.98 39L33.77 34.5zM16.45 25.5L8.66 21L0.87 25.5L0.87 34.5L8.66 39L16.45 34.5zM7.79 10.5L0 6L-7.79 10.5L-7.79 19.5L0 24L7.79 19.5zM16.45-4.5L8.66-9L0.87-4.5L0.87 4.5L8.66 9L16.45 4.5zM33.77-4.5L25.98-9L18.19-4.5L18.19 4.5L25.98 9L33.77 4.5zM42.43 10.5L34.64 6L26.85 10.5L26.85 19.5L34.64 24L42.43 19.5zM25.11 10.5L17.32 6L9.53 10.5L9.53 19.5L17.32 24L25.11 19.5z" fill="#2222"/>
+      <path d="M-20-20h200v200h-200M24.21 25.25L15.98 20.5L7.75 25.25L7.75 34.75L15.98 39.5L24.21 34.75zM6.89 25.25L-1.34 20.5L-9.57 25.25L-9.57 34.75L-1.34 39.5L6.89 34.75zM-1.77 10.25L-10 5.5L-18.23 10.25L-18.23 19.75L-10 24.5L-1.77 19.75zM6.89-4.75L-1.34-9.5L-9.57-4.75L-9.57 4.75L-1.34 9.5L6.89 4.75zM24.21-4.75L15.98-9.5L7.75-4.75L7.75 4.75L15.98 9.5L24.21 4.75zM32.87 10.25L24.64 5.5L16.41 10.25L16.41 19.75L24.64 24.5L32.87 19.75zM41.53 25.25L33.3 20.5L25.07 25.25L25.07 34.75L33.3 39.5L41.53 34.75zM15.55 40.25L7.32 35.5L-0.91 40.25L-0.91 49.75L7.32 54.5L15.55 49.75zM-10.43 25.25L-18.66 20.5L-26.89 25.25L-26.89 34.75L-18.66 39.5L-10.43 34.75zM-10.43-4.75L-18.66-9.5L-26.89-4.75L-26.89 4.75L-18.66 9.5L-10.43 4.75zM15.55-19.75L7.32-24.5L-0.91-19.75L-0.91-10.25L7.32-5.5L15.55-10.25zM41.53-4.75L33.3-9.5L25.07-4.75L25.07 4.75L33.3 9.5L41.53 4.75zM32.87 40.25L24.64 35.5L16.41 40.25L16.41 49.75L24.64 54.5L32.87 49.75zM-1.77 40.25L-10 35.5L-18.23 40.25L-18.23 49.75L-10 54.5L-1.77 49.75zM-19.09 10.25L-27.32 5.5L-35.55 10.25L-35.55 19.75L-27.32 24.5L-19.09 19.75zM-1.77-19.75L-10-24.5L-18.23-19.75L-18.23-10.25L-10-5.5L-1.77-10.25zM32.87-19.75L24.64-24.5L16.41-19.75L16.41-10.25L24.64-5.5L32.87-10.25zM50.19 10.25L41.96 5.5L33.73 10.25L33.73 19.75L41.96 24.5L50.19 19.75zM15.55 10.25L7.32 5.5L-0.91 10.25L-0.91 19.75L7.32 24.5L15.55 19.75z" fill="#7777"/>
+    </pattern>
+  </defs>
+  <rect fill="url(#doodad)" height="200%" width="200%"/>
+</svg>
diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js
index 119103b5ea3885f290410a42758a5f672caffdc4..0610cbae2c6904572ae4b8b6714a12b67382c133 100644
--- a/aleksis/core/static/js/main.js
+++ b/aleksis/core/static/js/main.js
@@ -84,6 +84,9 @@ $(document).ready(function () {
     // Initialize Modals [MAT]
     $('.modal').modal();
 
+    // Initialize image boxes [Materialize]
+    $('.materialboxed').materialbox();
+
     // Intialize Tabs [Materialize]
     $('.tabs').tabs();
 
diff --git a/aleksis/core/static/public/style.scss b/aleksis/core/static/public/style.scss
index bd8f2e4d621a8dd89a897b14ef25d68c2a88395c..9d3a7f5609c20400d3addbd86e4e0e6efe965393 100644
--- a/aleksis/core/static/public/style.scss
+++ b/aleksis/core/static/public/style.scss
@@ -96,8 +96,11 @@ header, main, footer {
 /* MAIN */
 /********/
 
+$main-padding-lr: 20px;
+$main-padding-tb: 10px;
+
 main {
-  padding: 10px 20px;
+  padding: $main-padding-tb $main-padding-lr;
   flex: 1 0 auto;
 }
 
@@ -809,6 +812,112 @@ main figure.alert {
   margin-bottom: 8px;
 }
 
+/* Person overview */
+$person-logo-size: 20vh;
+
+.clip-circle:not(.active) {
+  width: $person-logo-size;
+  height: $person-logo-size;
+  background: #f9f9f9;
+  border-radius: 50%;
+
+  & img {
+    border-radius: 50%;
+    width: 20vh;
+    height: 20vh;
+    object-fit: cover;
+  }
+}
+
+.clip-circle.no-image, .clip-circle.no-image>i.material-icons {
+  font-size: calc(#{$person-logo-size} * 0.5);
+  color: #6f6f6f;
+  background: #f2f2f2;
+  line-height: $person-logo-size;
+  width: $person-logo-size;
+  text-align: center;
+  user-select: none;
+  cursor: default;
+  border-radius: 50%;
+}
+
+#hero-bg {
+  position: absolute;
+  width: calc(100% + #{$main-padding-lr});
+  height: 30vh;
+  left: -$main-padding-lr;
+  top: 0;
+  overflow: hidden;
+  background-color: lighten($primary-color, 30%);
+  z-index: -1;
+  box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14) inset,
+  0 1px 10px 0 rgba(0, 0, 0, 0.12) inset,
+  0 2px 4px -1px rgba(0, 0, 0, 0.3) inset;
+}
+
+.person-buttons {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  width: max-content;
+  position: absolute;
+  right: $main-padding-lr;
+  margin: 0;
+  align-items: end;
+  & a {
+    -webkit-transition: width 0.5s 0s ease;
+    -moz-transition: width 0.5s 0s ease;
+    -o-transition: width 0.5s 0s ease;
+    transition: width 0.5s 0s ease;
+
+    &:hover {
+      width: max-content;
+    }
+  }
+}
+
+@media (pointer: fine) {
+  .person-buttons a {
+    width: 50px;
+  }
+}
+
+.person-container {
+  margin: calc(30vh - #{$main-padding-tb} - #{$navbar-height} - 10vh) 0 0 0;
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  justify-content: space-around;
+  flex-direction: column;
+}
+
+.person-collection .collection-item.avatar {
+  display: flex;
+  align-items: center;
+
+  & img.circle {
+    object-fit: cover;
+  }
+}
+
+.materialboxed {
+  &:not(.active) {
+    opacity: 100% !important;
+    & > img:hover {
+      opacity: 80%;
+    }
+  }
+
+  &.active {
+    box-shadow: none;
+
+    & > img {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+    }
+  }
+
 .application-circle {
   border-radius: 50%;
   width: 20vh;
diff --git a/aleksis/core/templates/core/partials/hero_background.html b/aleksis/core/templates/core/partials/hero_background.html
new file mode 100644
index 0000000000000000000000000000000000000000..33a4890586a18f5f0b5e486d6fb750707ac805e8
--- /dev/null
+++ b/aleksis/core/templates/core/partials/hero_background.html
@@ -0,0 +1,2 @@
+{% load static %}
+<div id="hero-bg" style="background-image: url('{% static "img/hero.svg" %}'); background-size: 3840px"></div>
diff --git a/aleksis/core/templates/core/person/collection.html b/aleksis/core/templates/core/person/collection.html
index c23fa2360c00977485a9d32373ae826d7fe66b6d..fb8518e97e3e8d770260c8e6b004df420d8efa15 100644
--- a/aleksis/core/templates/core/person/collection.html
+++ b/aleksis/core/templates/core/person/collection.html
@@ -1,7 +1,15 @@
-<div class="collection">
+{% load rules %}
+
+<div class="collection person-collection">
   {% for person in persons %}
-    <a class="collection-item" href="{% url "person_by_id" person.pk %}">
-      <i class="material-icons left">person</i>
+    <a class="collection-item avatar waves-effect" href="{% url "person_by_id" person.pk %}">
+      {% has_perm 'core.view_photo_rule' user person as can_view_photo %}
+      {% if person.photo and can_view_photo %}
+        <img class="circle" src="{{ person.photo.url }}"
+             alt="{{ person.first_name }} {{ person.last_name }}"/>
+      {% else %}
+        <i class="material-icons materialize-circle">person</i>
+      {% endif %}
       {{ person }}
     </a>
   {% endfor %}
diff --git a/aleksis/core/templates/core/person/full.html b/aleksis/core/templates/core/person/full.html
index 4a2e68a09517d1888f708b8ece3f757c6b1d8b1f..749ba164229845057c965e4efd3e8d0fb9423f32 100644
--- a/aleksis/core/templates/core/person/full.html
+++ b/aleksis/core/templates/core/person/full.html
@@ -6,9 +6,9 @@
 {% load render_table from django_tables2 %}
 
 {% block browser_title %}{{ person.first_name }} {{ person.last_name }}{% endblock %}
+{% block no_page_title%}{% endblock %}
 
 {% block content %}
-  <h1>{{ person.first_name }} {{ person.last_name }}</h1>
 
   {% has_perm 'core.edit_person_rule' user person as can_change_person %}
   {% has_perm 'core.change_person_preferences_rule' user person as can_change_person_preferences %}
@@ -16,99 +16,175 @@
   {% has_perm "core.impersonate_rule" user person as can_impersonate %}
   {% has_perm "core.can_invite" user person as can_invite %}
 
-  {% if can_change_person or can_change_person_preferences or can_delete_person or can_impersonate %}
-    <p>
-      {% if can_change_person %}
-        <a href="{% url 'edit_person_by_id' person.id %}" class="btn waves-effect waves-light">
-          <i class="material-icons left">edit</i>
-          {% trans "Edit" %}
-        </a>
-      {% endif %}
+  {% include "core/partials/hero_background.html" %}
 
-      {% if can_delete_person %}
-        <a href="{% url 'delete_person_by_id' person.id %}" class="btn waves-effect waves-light red">
-          <i class="material-icons left">delete</i>
-          {% trans "Delete" %}
-        </a>
-      {% endif %}
+  {% if can_change_person or can_change_person_preferences or can_delete_person or can_impersonate or can_invite %}
+      <p class="person-buttons hide-on-med-and-down">
+        {% if can_change_person %}
+          <a href="{% url 'edit_person_by_id' person.id %}" class="btn waves-effect waves-light">
+            <i class="material-icons left">edit</i>
+            {% trans "Edit" %}
+          </a>
+        {% endif %}
 
-      {% if can_change_person_preferences %}
-        <a href="{% url "preferences_person" person.id %}" class="btn waves-effect waves-light">
-          <i class="material-icons left">settings</i>
-          {% trans "Change preferences" %}
-        </a>
-      {% endif %}
+        {% if can_delete_person %}
+          <a href="{% url 'delete_person_by_id' person.id %}" class="btn waves-effect waves-light red">
+            <i class="material-icons left">delete</i>
+            {% trans "Delete" %}
+          </a>
+        {% endif %}
 
-    {% if can_impersonate and person.user %}
-        <a href="{% url "impersonate-start" person.user.id %}" class="btn waves-effect waves-light">
-          <i class="material-icons left">portrait</i>
-          {% trans "Impersonate" %}
-        </a>
-    {% endif %}
-    {% if can_invite and not person.user %}
-        <a href="{% url "invite_person_by_id" person.id %}" class="btn waves-effect waves-light">
-          <i class="material-icons left">card_giftcard</i>
-          {% trans "Invite user" %}
-        </a>
+        {% if can_change_person_preferences %}
+          <a href="{% url 'preferences_person' person.id %}" class="btn waves-effect waves-light">
+            <i class="material-icons left">settings</i>
+            {% trans "Change preferences" %}
+          </a>
+        {% endif %}
+
+        {% if can_impersonate and person.user %}
+          <a href="{% url 'impersonate-start' person.user.id %}" class="btn waves-effect waves-light">
+            <i class="material-icons left">portrait</i>
+            {% trans "Impersonate" %}
+          </a>
+        {% endif %}
+
+        {% if can_invite and not person.user %}
+          <a href="{% url "invite_person_by_id" person.id %}" class="btn waves-effect waves-light">
+            <i class="material-icons left">card_giftcard</i>
+            {% trans "Invite user" %}
+          </a>
+        {% endif %}
+      </p>
     {% endif %}
-    </p>
-  {% endif %}
 
-  <h2>{% blocktrans %}Contact details{% endblocktrans %}</h2>
-  <div class="row">
-    <div class="col s12 m4">
-      {% has_perm 'core.view_photo_rule' user person as can_view_photo %}
-      {% if person.photo and can_view_photo %}
-        <img class="person-img" src="{{ person.photo.url }}"
-             alt="{{ person.first_name }} {{ person.last_name }}"/>
+  <header class="person-container">
+    <div class="image-wrapper">
+      {% has_perm 'core.view_avatar_rule' user person as can_view_avatar %}
+      {% if person.avatar and can_view_avatar %}
+        <div class="clip-circle materialboxed z-depth-2">
+          <img class="hundred-percent" src="{{ person.avatar.url }}"
+               alt="{{ person.first_name }} {{ person.last_name }}"/>
+        </div>
+
       {% else %}
-        <img class="person-img" src="{% static 'img/fallback.png' %}"
-             alt="{{ person.first_name }} {{ person.last_name }}"/>
+
+        <div class="clip-circle no-image z-depth-2">
+          {{ person.initials }}
+        </div>
       {% endif %}
     </div>
-    <div class="col s12 m8">
-      <table class="responsive-table highlight">
-        <tr>
-          <td rowspan="6">
+    <h1>
+      {{ person.first_name }} {{ person.last_name }}
+      {% if person.user %}
+        <small class="grey-text">{{ person.user.username }}</small>
+      {% endif %}
+    </h1>
+  </header>
 
-          </td>
+  <div class="row">
+    {% if person.description %}
+      <div class="col s12">
+        <p class="container center-align">
+          {{ person.description }}
+        </p>
+      </div>
+    {% endif %}
+    {% if can_change_person or can_change_person_preferences or can_delete_person or can_impersonate or can_invite %}
+      <div class="col s12 hide-on-large-only">
+        <div class="collection">
+          {% if can_change_person %}
+            <a href="{% url 'edit_person_by_id' person.id %}" class="collection-item waves-effect waves-dark">
+              <i class="material-icons left">edit</i>
+              {% trans "Edit" %}
+            </a>
+          {% endif %}
+
+          {% if can_delete_person %}
+            <a href="{% url 'delete_person_by_id' person.id %}" class="collection-item waves-effect waves-red red-text">
+              <i class="material-icons left">delete</i>
+              {% trans "Delete" %}
+            </a>
+          {% endif %}
+
+          {% if can_change_person_preferences %}
+            <a href="{% url 'preferences_person' person.id %}" class="collection-item waves-effect waves-dark">
+              <i class="material-icons left">settings</i>
+              {% trans "Change preferences" %}
+            </a>
+          {% endif %}
+
+        {% if can_impersonate and person.user %}
+            <a href="{% url 'impersonate-start' person.user.id %}" class="collection-item waves-effect waves-dark">
+              <i class="material-icons left">portrait</i>
+              {% trans "Impersonate" %}
+            </a>
+          {% endif %}
+
+        {% if can_invite and not person.user %}
+          <a href="{% url "invite_person_by_id" person.id %}" class="collection-item waves-effect waves-light">
+            <i class="material-icons left">card_giftcard</i>
+            {% trans "Invite user" %}
+          </a>
+        {% endif %}
+        </div>
+      </div>
+    {% endif %}
+    <div class="col s12 l4">
+      <h2>{% blocktrans %}Contact details{% endblocktrans %}</h2>
+      <div class="card-panel">
+        <table class="highlight">
+        <tr>
           <td>
             <i class="material-icons small">person</i>
           </td>
-          <td>{{ person.first_name }}</td>
-          <td>{{ person.additional_name }}</td>
-          <td>{{ person.last_name }}</td>
+          <td>{{ person.first_name }} {{ person.additional_name }} {{ person.last_name }}</td>
         </tr>
         <tr>
           <td>
             <i class="material-icons small">face</i>
           </td>
-          <td colspan="3">{{ person.get_sex_display }}</td>
+          <td>{% firstof person.get_sex_display "–" %}</td>
         </tr>
         {% has_perm 'core.view_address_rule' user person as can_view_address %}
         {% if can_view_address %}
           <tr>
-            <td>
+            <td rowspan="2">
               <i class="material-icons small">home</i>
             </td>
-            <td colspan="2">{{ person.street }} {{ person.housenumber }}</td>
-            <td colspan="2">{{ person.postal_code }} {{ person.place }}</td>
+            <td>{% firstof person.street "–" %} {{ person.housenumber }}</td>
+          </tr>
+          <tr>
+            <td>{{ person.postal_code }} {% firstof person.place "–" %}</td>
           </tr>
         {% endif %}
         {% has_perm 'core.view_contact_details_rule' user person as can_view_contact_details %}
         {% if can_view_contact_details %}
           <tr>
-            <td>
+            <td rowspan="2">
               <i class="material-icons small">phone</i>
             </td>
-            <td>{{ person.phone_number }}</td>
-            <td>{{ person.mobile_number }}</td>
+            <td>
+              <a href="tel:{{ person.phone_number }}">{{ person.phone_number }}</a>
+              <small>({% trans "home number" %})</small>
+            </td>
+          </tr>
+          <tr>
+            <td>
+              <a href="tel:{{ person.phone_number }}">{{ person.mobile_number }}</a>
+              <small>({% trans "mobile number" %})</small>
+            </td>
           </tr>
           <tr>
             <td>
               <i class="material-icons small">email</i>
             </td>
-            <td colspan="3">{{ person.email }}</td>
+            <td>
+              {% if person.email %}
+                <a href="mailto:{{ person.email }}">{{ person.email }}</a>
+              {% else %}
+                –
+              {% endif %}
+            </td>
           </tr>
         {% endif %}
         {% has_perm 'core.view_personal_details_rule' user person as can_view_personal_details %}
@@ -117,39 +193,63 @@
             <td>
               <i class="material-icons small">cake</i>
             </td>
-            <td colspan="2">{{ person.date_of_birth|date }}</td>
-            <td colspan="2">{{ person.place_of_birth }}</td>
+            <td>
+              <time datetime="{{ person.date_of_birth|date:'c' }}">{{ person.date_of_birth|date }}</time>
+              {% firstof person.place_of_birth "–" %}
+            </td>
           </tr>
         {% endif %}
       </table>
-    </div>
-    {% if person.description %}
-      <div class="col s12 m12">
-        <h2>{% trans "Description" %}</h2>
-        <p>
-          {{ person.description }}
-        </p>
       </div>
-    {% endif %}
-  </div>
+      {% has_perm 'core.view_photo_rule' user person as can_view_photo %}
+      {% if person.photo and can_view_photo %}
+        <div class="card">
+          <div class="card-image">
+            <img src="{{ person.photo.url }}" alt="{{ person.first_name }} {{ person.last_name }}" class="materialboxed">
+            <span class="card-title">{{ person.first_name }} {{ person.last_name }}</span>
+          </div>
+        </div>
 
-  {% if person.children.all and can_view_personal_details %}
-    <div class="col s12 m12">
-      <h2>{% trans "Children" %}</h2>
-      {% include "core/person/collection.html" with persons=person.children.all %}
+      {% else %}
+        <div class="card-panel">
+          <i class="material-icons left">image_not_supported</i>
+          {% trans "This person didn't upload a personal photo." %}
+        </div>
+      {% endif %}
     </div>
-  {% endif %}
 
-  {% if person.guardians.all and can_view_personal_details %}
-    <div class="col s12 m12">
-      <h2>{% trans "Guardians / Parents" %}</h2>
-      {% include "core/person/collection.html" with persons=person.guardians.all %}
+    {% if person.children.all or person.guardians.all and can_view_personal_details %}
+    <div class="col s12 m6 l4">
+      {% if person.children.all and can_view_personal_details %}
+        <h2>{% trans "Children" %}</h2>
+        <div class="card-panel">
+          {% include "core/person/collection.html" with persons=person.children.all %}
+        </div>
+      {% endif %}
+
+      {% if person.guardians.all and can_view_personal_details %}
+        <h2>{% trans "Guardians / Parents" %}</h2>
+        <div class="card-panel">
+          {% include "core/person/collection.html" with persons=person.guardians.all %}
+        </div>
+      {% endif %}
     </div>
-  {% endif %}
+    {% endif %}
 
-  {% has_perm 'core.view_person_groups_rule' user person as can_view_groups %}
-  {% if can_view_groups %}
-    <h2>{% blocktrans %}Groups{% endblocktrans %}</h2>
-    {% render_table groups_table %}
-  {% endif %}
+    {% has_perm 'core.view_person_groups_rule' user person as can_view_groups %}
+    {% if can_view_groups and groups %}
+      <div class="col s12 m6 l4">
+        <h2>{% blocktrans %}Groups{% endblocktrans %}</h2>
+        <div class="card-panel">
+          <div class="collection">
+            {% for group in groups %}
+              <a href="{{ group.get_absolute_url }}" class="collection-item">
+                {{ group.name }} ({{ group.school_term }})
+              </a>
+            {% endfor %}
+          </div>
+        </div>
+      </div>
+    {% endif %}
+  </div>
 {% endblock %}
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index 49ef723df8d5fdb27d810c8668d9ec3559d9272e..33af719a6a2dd22471740b2dc5dbc4ab357293bd 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -326,12 +326,7 @@ def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     context["person"] = person
 
     # Get groups where person is member of
-    groups = Group.objects.filter(members=person)
-
-    # Build table
-    groups_table = GroupsTable(groups)
-    RequestConfig(request).configure(groups_table)
-    context["groups_table"] = groups_table
+    context["groups"] = person.member_of.all()
 
     return render(request, "core/person/full.html", context)