Accessibility overhaul, mobile table fixes, faster previews
Accessibility overhaul - worked through a backlog of accessibility findings against WCAG 2.1 AA:
- Dialogs, notification panel, user menu, and the mobile menu now move focus inside themselves when they open, return focus to the trigger when they close, and announce themselves correctly to screen readers via proper roles and labels.
- The character and entity search dropdowns (used in the curator drawers and the bulk-appearances editor) now have full keyboard support: arrow keys to move between results, Enter to pick one, and Escape to dismiss, with the highlighted option announced as you move.
- Decorative icons across the site are now hidden from screen readers so they stop being announced as "image" between every word. Cover and portrait images that already have their caption text on the page no longer announce the title twice.
- Tables on detail and admin pages got proper captions, column scopes, and row headers so screen readers can announce "row 3 of 10, character Vin" instead of just reading every cell as plain text.
- Help text under form fields stays visible alongside the error message instead of being replaced by it, so format guidance is still there when you need it most. Buttons and controls keep a visible outline in Windows High Contrast Mode.
If you don't use a screen reader or a keyboard-only workflow, none of this is visible to you. If you do, the experience should be substantially smoother.
Tables don't overflow on phones any more - several curator tables (audit log, system settings, reading-order editors, the segment reorder table) previously pushed the whole page sideways when they didn't fit on a narrow viewport. They now scroll inside their own container so the rest of the page stays put.
Cover lookups for description previews - when a description mentions another book, series, or universe and a link preview pops up, the cover image used to be fetched in a separate database query per entity. They're now batched into a single query each, so previews resolve faster when there are several on the same page.
Smaller faceted character page work - the "browse by occupation" / "browse by nationality" pages were silently reading the entire character-aliases table on every load to build the alias list. That now joins through the filtered character set the same way the rest of the page does, so the work scales with the visible results.
Less JavaScript on entity descriptions - the description renderer and the cast summary block were running in the browser when they didn't need to. Moving them onto the server reduces the JavaScript your browser has to download on series, book, and universe pages.
Form fields say (optional) consistently - some labels on the new-book and new-series forms had "(optional)" baked into the label text; others marked optional fields differently or not at all. They now all use the same subdued "(optional)" hint after the label, matching the rest of the curator forms.
Loading skeletons on more pages - several pages that fetch data (the curator "new entity" forms, the "characters waiting to be completed" page, the social-content tool, the life-events list, and the nested character routes under series and books) showed a blank page during navigation. They now render a structured placeholder while the data loads.
Small SEO and sharing fixes - the sitemap no longer lists a URL that was a 301 redirect, the blog preview route is now hidden from search engines, blog post structured data includes the publisher and last-modified timestamp (needed for article rich results in search), Twitter previews default to the large-image card so detail pages that supply a cover render properly, and the mobile-only book cover loads with high priority so it doesn't lag behind the rest of the page.
Privacy and accessibility statement updates - the privacy policy now spells out your right to complain to the Information Commissioner's Office, lists the lawful basis under UK GDPR for each different kind of data we process, and states the retention period for the administrative audit log. The accessibility statement now points to the Equality Advisory and Support Service for anyone unhappy with how we've handled an accessibility issue. The contact page identifies us at the point of data collection, matching guidance from the ICO.
Account deletion ends all sessions immediately - scheduling your account for deletion now signs you out everywhere on the spot, rather than leaving any active sessions live for the 30-day grace period. If you change your mind and cancel the deletion during the grace period, you can sign back in normally.
Image cleanup on permanent delete - when an admin permanently deletes a character, the portrait files now get removed from storage at the same time. Previously the database rows were cleaned up but the image files themselves were left behind.
Consistent input borders across admin pages - the contrast fix from earlier this week was applied to a handful of admin form inputs that had been built with hand-rolled markup. They now use the same shared input component as the rest of the site, so the visible border meets the contrast guideline everywhere and the blog list's search box no longer stays bright white in dark mode.
Friendlier permission messages - three "Not authorized" error messages were replaced with more specific text explaining what the user is missing permission for, and the spelling now matches the rest of the site's British conventions.