diff --git a/src/lembas/web/static/css/admin.css b/src/lembas/web/static/css/admin.css
index 9b48b21..2d77d7e 100644
--- a/src/lembas/web/static/css/admin.css
+++ b/src/lembas/web/static/css/admin.css
@@ -72,23 +72,64 @@
.tabs__panel { display: none; }
-/* Each radio activates its own label and its own panel. Written out because
- CSS has no way to derive one from the other. */
-#tab-account:checked ~ label[for="tab-account"],
-#tab-models:checked ~ label[for="tab-models"],
-#tab-appearance:checked ~ label[for="tab-appearance"],
-#tab-security:checked ~ label[for="tab-security"] {
+/* The active tab's label. Each radio is immediately followed by its own label,
+ so this needs to know nothing about how many tabs there are or what they are
+ called. */
+.tabs__bar input:checked + .tabs__tab {
color: var(--ink);
border-bottom-color: var(--accent);
}
-.tabs__bar:has(#tab-account:checked) ~ .tabs__body [data-tab="tab-account"],
-.tabs__bar:has(#tab-models:checked) ~ .tabs__body [data-tab="tab-models"],
-.tabs__bar:has(#tab-appearance:checked) ~ .tabs__body [data-tab="tab-appearance"],
-.tabs__bar:has(#tab-security:checked) ~ .tabs__body [data-tab="tab-security"] {
+
+/*
+ The active panel, matched by position.
+
+ CSS cannot compare a radio's id with a panel's data-tab, so this used to name
+ every tab twice -- and a tab added without also adding its two rules here
+ rendered a label that selected nothing. That is not a failure anyone spots in
+ review; it looks like a blank page.
+
+ Position is derivable, so it is used instead: the Nth radio shows the Nth
+ panel. Both lists are rendered in the same order, and a conditional tab drops
+ out of both at once, so they cannot drift apart. :nth-of-type counts by
+ element name, which is why the panels are and the alerts above them
+ are
-- the alerts are not counted.
+
+ Enumerated to eight, comfortably more than exist. A ninth tab needs one line.
+*/
+.tabs__bar:has(input:nth-of-type(1):checked) ~ .tabs__body .tabs__panel:nth-of-type(1),
+.tabs__bar:has(input:nth-of-type(2):checked) ~ .tabs__body .tabs__panel:nth-of-type(2),
+.tabs__bar:has(input:nth-of-type(3):checked) ~ .tabs__body .tabs__panel:nth-of-type(3),
+.tabs__bar:has(input:nth-of-type(4):checked) ~ .tabs__body .tabs__panel:nth-of-type(4),
+.tabs__bar:has(input:nth-of-type(5):checked) ~ .tabs__body .tabs__panel:nth-of-type(5),
+.tabs__bar:has(input:nth-of-type(6):checked) ~ .tabs__body .tabs__panel:nth-of-type(6),
+.tabs__bar:has(input:nth-of-type(7):checked) ~ .tabs__body .tabs__panel:nth-of-type(7),
+.tabs__bar:has(input:nth-of-type(8):checked) ~ .tabs__body .tabs__panel:nth-of-type(8) {
display: block;
}
.tabs__tab:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
+/*
+ A form's action row, and the space after the form it closes.
+
+ Not a plain .btn-row: a settings form is a stack of cards, and Save has to
+ read as belonging to the cards above it rather than to whatever comes next.
+ The gap that matters is the one *after* the form -- a card following it (the
+ "Try it" panel on the search page, say) otherwise sits flush against Save and
+ looks like another field of the same form. That margin therefore belongs to
+ the form, not to the action row: the action row is always its form's last
+ child, so a bottom margin there would have nothing to push away from.
+*/
+.form-actions {
+ display: flex;
+ align-items: center;
+ gap: var(--sp-2);
+ flex-wrap: wrap;
+ margin-top: var(--sp-5);
+}
+
+.admin-page > form { margin-bottom: var(--sp-8); }
+.admin-page > form:last-child { margin-bottom: 0; }
+
/* --- Cards ----------------------------------------------------------------- */
.card {
background: var(--surface);
diff --git a/src/lembas/web/templates/admin/audio.html b/src/lembas/web/templates/admin/audio.html
index d06d865..caf500d 100644
--- a/src/lembas/web/templates/admin/audio.html
+++ b/src/lembas/web/templates/admin/audio.html
@@ -61,8 +61,9 @@
- Sent even to servers that only host one; a router in front of several
- needs it.
+ A server hosting one model ignores this and uses
+ whatever it was started with — whisper-1 is then just a
+ label. It only selects anything on a server that hosts several.