diff --git a/assets/app.css b/assets/app.css
index fb94cd0..d157749 100644
--- a/assets/app.css
+++ b/assets/app.css
@@ -210,3 +210,59 @@
backface-visibility: hidden;
transform: translateZ(0);
}
+
+/* Below `md`, a `.table-cards` table reads as a stack of cards instead of a
+ horizontally-scrolling grid: each row becomes a bordered block, each cell
+ becomes a label/value line pulling its label from `data-label` (set on the
+
in the template -- there's no way to read the matching
text from
+ pure CSS). A
with no `data-label` renders as plain full-width content
+ instead of a label/value row -- for an image cell, a heading-style link, or
+ an actions row that already lays itself out. At `md` and up this reverts to
+ an ordinary table with nothing left over from the mobile styling. */
+@media (width < 48rem) {
+ .table-cards, .table-cards :is(thead, tbody, tr, th, td) {
+ display: block;
+ width: 100%;
+ }
+
+ .table-cards thead {
+ display: none;
+ }
+
+ .table-cards tbody tr {
+ border: 1px solid var(--color-base-300);
+ border-radius: var(--radius-box);
+ padding: 0 0.75rem;
+ }
+
+ .table-cards tbody tr + tr {
+ margin-top: 0.75rem;
+ }
+
+ .table-cards td {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.75rem;
+ padding: 0.6rem 0;
+ border-bottom: 1px solid var(--color-base-200);
+ }
+
+ .table-cards td:last-child {
+ border-bottom: none;
+ }
+
+ .table-cards td[data-label]:before {
+ content: attr(data-label);
+ flex-shrink: 0;
+ font-size: 0.75rem;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+ opacity: 0.5;
+ }
+
+ .table-cards td:not([data-label]) {
+ justify-content: flex-start;
+ }
+}
diff --git a/controlpanel/templates/controlpanel/base.html b/controlpanel/templates/controlpanel/base.html
index b1e1133..cb3597a 100644
--- a/controlpanel/templates/controlpanel/base.html
+++ b/controlpanel/templates/controlpanel/base.html
@@ -5,6 +5,15 @@
{% block panel_title %}Control panel{% endblock panel_title %} · RosterChief
{% endblock title %}
+{% block nav_toggle %}
+
+{% endblock nav_toggle %}
+
+{% comment %} Kept in the navbar itself only at `lg`+, where there's no hamburger drawer to hold them instead -- see the comment on `nav_icons_class` in _base.html. {% endcomment %}
+{% block nav_icons_class %}hidden items-center lg:flex{% endblock nav_icons_class %}
+
{% block menu %}
{% comment %}
Outside , so it never scrolls with the content. Its own overflow-y-auto is for
@@ -18,6 +27,38 @@
{% endblock menu %}
{% block main %}
+ {# Below `lg` the sidebar is hidden and {% block nav_toggle %} above opens this instead. #}
+
+
{% if maintenance_on %}
- {# Below `lg` the sidebar is hidden, so the same links appear here rather than nowhere. #}
-
- {% include "controlpanel/_nav_items.html" %}
-
-
{% block panel %}{% endblock panel %}
{% endblock main %}
diff --git a/management/templates/management/_family_members_table.html b/management/templates/management/_family_members_table.html
index efc7f7e..a22f161 100644
--- a/management/templates/management/_family_members_table.html
+++ b/management/templates/management/_family_members_table.html
@@ -10,11 +10,10 @@ passes its own URL so admins land back on the member they were viewing; family_d
leaves it unset, since staying on the family page is already the right place there.
{% endcomment %}
-
+
-
{% trans "Last name" %}
-
{% trans "First name" %}
+
{% trans "Name" %}
{% trans "Email" %}
{% trans "Type" %}
@@ -23,10 +22,9 @@ leaves it unset, since staying on the family page is already the right place the