Accessibility pass: ARIA roles, label associations, CSS class migrations

- Add role=dialog/aria-modal/aria-labelledby to all 12 modal overlays (JS + PHP)
- Add aria-label="Close" to all 14 modal close buttons
- Add full ARIA combobox pattern to @mention autocomplete (listbox, option, aria-selected, aria-expanded)
- Add for= attributes to admin filter form labels (AuditLog, UserActivity, ApiKeys)
- Remove dead closeOnAdvancedSearchBackdropClick() from advanced-search.js

CSS/JS style cleanup:
- Move .ascii-banner static styles from JS inline to CSS class; add .ascii-banner--glow
- Add .ascii-banner-cursor, .loading-overlay--hiding, .has-overlay, tr[data-clickable]
- Add .animate-fadein/.animate-fadeout/.comment--deleting to ticket.css
- Add .lt-toast--hiding to base.css; remove opacity/transition inline JS
- Remove redundant cursor:pointer JS (already in th{} CSS rule)
- Remove trailing space in lt-select class attributes

Bug fixes:
- base.js: boot overlay opacity inline style was overriding .fade-out class opacity via
  specificity (1000 vs 20), preventing the fade-out animation — removed
- ascii-banner.js: cursor used blink-caret (border-color only) instead of blink-cursor
  (opacity-based), so the █ cursor never actually blinked — fixed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 20:29:58 -04:00
parent 11f75fd823
commit 7695c6134c
21 changed files with 929 additions and 610 deletions

View File

@@ -124,8 +124,7 @@
function _dismissToast(toast) {
if (!toast || !toast.parentNode) return;
clearTimeout(toast._lt_timer);
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.3s ease';
toast.classList.add('lt-toast--hiding');
setTimeout(() => {
if (toast.parentNode) toast.parentNode.removeChild(toast);
_toastActive = false;
@@ -176,11 +175,11 @@
lt.modal.closeAll();
HTML contract:
<div id="my-modal-id" class="lt-modal-overlay">
<div id="my-modal-id" class="lt-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="myModalTitle">
<div class="lt-modal">
<div class="lt-modal-header">
<span class="lt-modal-title">Title</span>
<button class="lt-modal-close" data-modal-close>✕</button>
<span class="lt-modal-title" id="myModalTitle">Title</span>
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
</div>
<div class="lt-modal-body">…</div>
<div class="lt-modal-footer">…</div>
@@ -295,7 +294,6 @@
if (!overlay || !pre) return;
overlay.style.display = 'flex';
overlay.style.opacity = '1';
const name = (appName || 'TERMINAL').toUpperCase();
const titleStr = name + ' v1.0';
@@ -653,7 +651,6 @@
const ths = Array.from(table.querySelectorAll('th[data-sort-key]'));
ths.forEach((th, colIdx) => {
th.style.cursor = 'pointer';
let dir = 'asc';
th.addEventListener('click', () => {