WCAG 1.4.1 — Active nav link had no non-colour indicator in the admin panel.
Public nav already had border-bottom via common.css; admin nav had nothing.
admin.css:
- Add `[aria-current="page"]` rule on admin nav links:
border-bottom: 2px solid currentColor; padding-bottom: 1px
This gives a visible underline as a non-colour signal for the active page.
- Fix `--admin-purple` undefined CSS variable in pagination button hover.
The variable was referenced but never defined in variables.css (which was
refactored to use --accent-primary / --accent-secondary). Replaced both
border-color and color usages with var(--accent-primary) (#9557b5 — same
value), restoring the intended purple hover tint on pagination buttons.
todo/01-css-semantic-refactor.md:
- Audited ~15 pending CSS/HTML tasks; all were already implemented.
Marked as done: .admin-main, .admin-page-title, .admin-form-row,
.admin-label, .admin-input/select/textarea, .admin-table, .admin-fieldset,
tfe.css class replacements, search.css h2 selector, admin-alert replacement,
login.php/edit.php inline style removal, form partial hints (<small>).
todo/04-accessibility.md:
- Marked WCAG 1.4.1 admin nav and --admin-purple audit items as completed.
- Add Database::getThesesListCount(array $filters) — runs the same WHERE
clauses as getThesesList() but with COUNT(DISTINCT t.id); used to compute
total pages without loading all rows.
- Extend Database::getThesesList() with $limit/$offset parameters; when
$limit > 0 appends LIMIT/OFFSET and re-binds positional params individually
to avoid the PDO mixed-style restriction.
- Fix getThesesList() SELECT: add LEFT JOIN access_types + at.name as
access_type — the column was referenced in the template but never fetched.
- Wire admin/index.php: read ?page=, compute $totalPages/$offset, pass
$perPage=25 + $offset to getThesesList(); include pagination.php partial
below the table with filter-preserving $baseParams.
- Add result-count line (<p class="admin-list-meta">) showing "X–Y sur Z TFE"
when multiple pages exist.
- Add .admin-body .pagination-wrap / .pagination-btn / .pagination-info styles
to admin.css (scoped to .admin-body to avoid colliding with public pages).
The file had accumulated severe corruption in its lower half (garbled
selector text, variable names spliced into property values, orphaned
declarations, broken nesting) alongside hardcoded hex colours throughout.
Rewrote the entire file cleanly:
- Every colour is now a var() referencing a token defined in variables.css:
--accent-primary/secondary/foreground, --accent-blue/green/yellow/red,
--bg-secondary/tertiary, --border-primary, --text-primary/secondary/tertiary,
--error, --warning, --success, --accent-muted.
- Zero raw hex values remain in admin.css.
- Removed the corrupted/dead CSS from the bottom half and reconstructed
all selectors from what the templates actually use (audited via grep).
- Fixed structural issues: broken border shorthand, nested rules that
were not valid CSS, orphaned declaration blocks.
- New/restored rules: .admin-maintenance-bar (was corrupted),
.status-access variants (was corrupted), .admin-section-title--danger,
.admin-danger-zone, .admin-account-status (all reconstructed cleanly).
- .admin-btn--warning and .admin-btn--danger now use var(--accent-yellow)
and var(--accent-red) instead of hardcoded dark hex values.
- .admin-btn-remove hover now uses var(--error) instead of #e55.
- .admin-btn-unpublish now uses var(--bg-secondary)/var(--text-tertiary)
instead of hardcoded grey hex values.
- select option background colours removed (browser chrome, not styleable
cross-platform).
Templates: replace 4 inline var(--admin-text-muted) with var(--text-secondary)
in index.php, thanks.php, import.php.
Remove five presentational classes from admin forms and replace with
structural CSS selectors scoped to .admin-form:
- .admin-form-row → .admin-form > div:not(.admin-submit-wrap)
Grid layout (260px label col + 1fr input col) applied directly to div
children of the form; submit-wrap div excluded via :not().
- .admin-label → .admin-form > div:not(.admin-submit-wrap) > label
Scoped to the direct label child of each form row div; does not bleed
into nested checkbox labels inside .admin-checkbox-list.
- .admin-input / .admin-select / .admin-textarea
→ .admin-form input:not([type=checkbox|radio|file|hidden|submit])
→ .admin-form select
→ .admin-form textarea
Also extended to .admin-inline-form input/select (tags page) so the
tags table inputs retain identical base styling and focus colour.
Templates updated: add.php, edit.php, login.php, account.php,
pages-edit.php, import.php, tags.php,
templates/partials/form/jury-fieldset.php — all class= attributes for
the five removed classes stripped.
import.php: added 'admin-form' class alongside 'admin-import-area' so
its single file-input row gets the grid row treatment; submit div was
already using admin-submit-wrap so it is correctly excluded.
No visual change — selectors target the same elements as before.
- admin.css: replace .admin-alert / .admin-alert--error / .admin-alert--success
selectors with [role="alert"][data-type="error"] and [role="status"][data-type="success"]
- All 10 admin templates updated: <div class="admin-alert admin-alert--{type}">
becomes <p role="alert|status" data-type="error|success"> (or <div> for the
import.php multi-item list that contains a <ul>)
- flash-messages.php partial updated to match
- WCAG benefit: role="alert" is an ARIA live region — errors are announced
immediately by screen readers without focus movement (fixes WCAG 3.3.1, 4.1.2)
- role="status" (polite live region) used for success messages — announced
without interrupting the user
- Removes two BEM modifier classes; CSS now targets element semantics directly
Replace four presentational class names in admin.css with structural selectors
that target native HTML elements already present in every admin template:
.admin-main → .admin-body main
.admin-page-title → .admin-body main > h1
.admin-table → .admin-body table
.admin-fieldset → .admin-body fieldset
.admin-fieldset-legend → .admin-body legend
Also migrate the .admin-main > section / h2 / dl / dt / dd block to
.admin-body main > section so the thanks-page section styles survive.
Add .admin-body main > table { margin-top: 1.5rem } to absorb the inline
style="margin-top:1.5rem" that was on tags.php's <table class="admin-table">.
All 10 affected admin templates updated (add, edit, account, index, import,
pages, pages-edit, tags, system, thanks) — class attributes removed where
the element alone is now the selector. Zero visual changes.
- admin.css: remove .admin-hint and .admin-field-hint class rules; add
.admin-body form small with the same font-size/color/margin properties
plus display:block so it stacks below sibling inputs; stub comment left
where .admin-field-hint was to document the change
- add.php: 5× <p class="admin-hint"> → <small>
- edit.php: 3× <p class="admin-hint"> → <small>
- import.php: <div class="admin-hint"> → <small> (block hint below CSV input)
- pages-edit.php: class="admin-hint" removed from already-correct <small>
- account.php: <p class="admin-field-hint"> → <small>
Hint text is now styled purely via the semantic element selector; no class
required on any hint element in admin templates.
- login.php: removed style= on .admin-form-row and .admin-label (already covered
by .admin-login-box scoped rules); extracted submit-wrap spacing and full-width
button to .admin-login-box .admin-submit-wrap and .admin-login-box .admin-btn
- account.php: style="margin-top:3rem" on danger-zone heading moved to
.admin-section-title--danger modifier; <span style="color:..."> replaced with
<small> element styled via .admin-danger-zone__description small
- add.php / edit.php / pages-edit.php: all style="align-items:start" removed from
.admin-form-row (redundant — already the CSS default at line 116 of admin.css);
banner preview inline styles extracted to .admin-banner-preview / .admin-banner-preview img;
add-jury button margin extracted to .admin-add-jury-btn; cancel links use .admin-cancel-link
Zero inline style= attributes remain in login, account, add, edit, pages-edit.
- admin/index.php: replace <div class="admin-stats"> with <dl>; inner
<div class="admin-stat__number"> → <dd>, <div class="admin-stat__label"> → <dt>;
use CSS order to keep number visually first; add scope="col" to all 9 <th> cells
- admin/thanks.php: replace all four <div class="admin-thesis-info"> wrappers
with <section> elements; remove the class entirely; add scope="col" to
the files table <th> cells
- admin/tags.php: add scope="col" to all 3 <th> cells
- admin/pages.php: add scope="col" to all 4 <th> cells
- admin.css: rename .admin-thesis-info selectors to .admin-main > section
(element + context selector — no class needed); add display:flex +
flex-direction:column to .admin-stat so CSS order property works correctly
Addresses TODO items: section X (admin-stats dl, th scope), XI (tags th scope),
XII (admin-thesis-info → section), XIII (pages.php th scope)
templates/admin/head.php:
- admin-nav__logo now href="/" with target="_blank" rel="noopener noreferrer"
- Left arrow prefix (← via ←, aria-hidden) signals leaving admin
- sr-only suffix "(site public, nouvel onglet)" for screen readers
public/admin/login.php:
- Same treatment on the standalone login nav (was a bare <span>)
public/assets/css/admin.css:
- admin-nav__list: flex:1 removed; margin-left:auto added
→ entire link list now right-justified inside the nav bar,
mirroring the layout of the public site header
- .admin-nav__logout { margin-left:auto } removed (no longer needed;
logout is just the last item in a right-aligned list)