audit pass 6: accessibility, ARIA, and keyboard fixes

- JS: fix checkbox/radio required validation using .checked not .value
- JS: guard _cpTrigger.focus() with document.contains() check
- JS: add arrow/Home/End key navigation to tab groups (WCAG 2.1)
- JS: clamp context menu left edge with Math.max(8, ...) to prevent off-screen
- JS: fix wizard _show() to removeAttribute aria-hidden on active step
- HTML: add role="region" + aria-label to notification panel
- HTML: convert Assigned To span+div to label+select with for/id association
- HTML: add role="article" tabindex="0" aria-label to all kanban cards
- HTML: remove aria-hidden="false" anti-pattern from wizard active step
- CSS/HTML/JS: replace aria-hidden="false" show-hook with :not([aria-hidden])
  so open state is represented by absent attribute rather than false value

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 19:51:21 -04:00
parent fdcadad23b
commit d08007cdd7
3 changed files with 102 additions and 44 deletions
+46 -6
View File
@@ -1792,6 +1792,7 @@ select option:checked {
transition: transform 0.2s ease, opacity 0.2s ease;
box-shadow: var(--glow-cyan);
}
.lt-menu-btn:active { opacity: 0.7; }
.lt-menu-btn:focus-visible { outline: 1px solid var(--accent-cyan); outline-offset: 2px; }
.lt-menu-btn.open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.lt-menu-btn.open span:nth-child(2) { opacity: 0; }
@@ -2472,7 +2473,9 @@ select option:checked {
transform: translateX(-50%) translateY(4px);
}
[data-tooltip]:hover::before,
[data-tooltip]:hover::after {
[data-tooltip]:focus-visible::before,
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
@@ -2490,7 +2493,9 @@ select option:checked {
transform: translateX(-50%) translateY(-4px);
}
[data-tooltip][data-tooltip-pos="bottom"]:hover::before,
[data-tooltip][data-tooltip-pos="bottom"]:hover::after {
[data-tooltip][data-tooltip-pos="bottom"]:focus-visible::before,
[data-tooltip][data-tooltip-pos="bottom"]:hover::after,
[data-tooltip][data-tooltip-pos="bottom"]:focus-visible::after {
transform: translateX(-50%) translateY(0);
}
@@ -2551,6 +2556,12 @@ select option:checked {
box-shadow: var(--glow-orange);
font-weight: 700;
}
.lt-page-btn:focus-visible {
outline: 2px solid var(--accent-cyan);
outline-offset: 1px;
border-color: var(--accent-cyan);
color: var(--accent-cyan);
}
.lt-page-btn:disabled,
.lt-page-btn[aria-disabled="true"] {
opacity: 0.35;
@@ -2583,7 +2594,8 @@ select option:checked {
width: 100%;
text-align: left;
}
.lt-accordion-header:hover { background: var(--bg-tertiary); color: var(--accent-cyan); }
.lt-accordion-header:hover { background: var(--bg-tertiary); color: var(--accent-cyan); }
.lt-accordion-header:active { background: var(--bg-tertiary); opacity: 0.8; }
.lt-accordion-header:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: -2px; }
.lt-accordion-header[aria-expanded="true"] { color: var(--accent-orange); }
.lt-accordion-icon {
@@ -2641,6 +2653,7 @@ select option:checked {
transition: color 0.15s;
}
.lt-alert-close:hover { color: var(--accent-red); }
.lt-alert-close:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; border-radius: 2px; }
.lt-alert.dismissed { max-height: 0 !important; opacity: 0; padding-top: 0; padding-bottom: 0; pointer-events: none; }
@@ -2655,7 +2668,21 @@ select option:checked {
font-family: var(--font-mono);
font-size: 0.8rem;
}
.lt-toggle input { display: none; }
/* Visually hidden but still keyboard-focusable */
.lt-toggle input {
position: absolute;
opacity: 0;
width: 1px; height: 1px;
margin: -1px; padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.lt-toggle input:focus-visible ~ .lt-toggle-track {
outline: 2px solid var(--accent-cyan);
outline-offset: 2px;
}
.lt-toggle-track {
width: 36px;
height: 18px;
@@ -2909,6 +2936,7 @@ input[type="range"].lt-range::-moz-range-thumb {
transition: all 0.15s;
}
.lt-code-copy:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.lt-code-copy:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }
.lt-code-copy.copied { border-color: var(--accent-green); color: var(--accent-green); }
.lt-code-block pre {
margin: 0;
@@ -4275,6 +4303,7 @@ html[data-theme="light"] ::-webkit-scrollbar-thumb:hover { background: var(--acc
white-space: nowrap;
}
.lt-context-menu-item:hover { background: var(--accent-cyan-dim); color: var(--accent-cyan); }
.lt-context-menu-item:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: -2px; background: var(--accent-cyan-dim); color: var(--accent-cyan); }
.lt-context-menu-item.is-danger:hover { background: var(--accent-red-dim); color: var(--accent-red); }
.lt-context-menu-item .icon { width: 1rem; text-align: center; opacity: 0.7; font-size: 0.75rem; }
.lt-context-menu-item kbd {
@@ -4900,6 +4929,9 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
.lt-lightbox-close:hover,
.lt-lightbox-prev:hover,
.lt-lightbox-next:hover { color: var(--accent-cyan); border-color: var(--accent-cyan-border); box-shadow: var(--box-glow-cyan); }
.lt-lightbox-close:focus-visible,
.lt-lightbox-prev:focus-visible,
.lt-lightbox-next:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; color: var(--accent-cyan); }
.lt-lightbox-caption {
position: fixed;
bottom: 3rem;
@@ -4947,6 +4979,7 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
border-radius: 2px;
}
.lt-sidebar-group-label:hover { color: var(--text-secondary); }
.lt-sidebar-group-label:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 1px; border-radius: 2px; }
.lt-sidebar-group-label .chevron {
font-size: 0.5rem;
transition: transform 0.2s ease;
@@ -5066,7 +5099,7 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
transition: opacity 0.15s ease, transform 0.15s ease;
overflow: hidden;
}
.lt-notif-panel[aria-hidden="false"] {
.lt-notif-panel:not([aria-hidden]) {
opacity: 1;
transform: scale(1);
pointer-events: auto;
@@ -5111,6 +5144,7 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
transition: background 0.1s;
}
.lt-notif-item:hover { background: var(--bg-tertiary); }
.lt-notif-item:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: -2px; background: var(--bg-tertiary); }
.lt-notif-item--unread { background: rgba(0, 212, 255, 0.04); }
.lt-notif-dot {
@@ -5179,7 +5213,7 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
right: 0;
transform-origin: top right;
}
.lt-dropdown-panel[aria-hidden="false"] {
.lt-dropdown-panel:not([aria-hidden]) {
opacity: 1;
transform: scale(1);
pointer-events: auto;
@@ -5206,6 +5240,12 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
background: var(--bg-tertiary);
color: var(--text-primary);
}
.lt-dropdown-item:focus-visible {
outline: 2px solid var(--accent-cyan);
outline-offset: -2px;
background: var(--bg-tertiary);
color: var(--text-primary);
}
.lt-dropdown-item--danger { color: var(--accent-red); }
.lt-dropdown-item--danger:hover { background: rgba(255,45,85,0.1); color: var(--accent-red); }