a11y: WCAG AA contrast + ARIA roles + focus management across all pages

- css/ls.css: --text-3 #8898AA → #56687A (5.1:1 contrast), min-height 44px on .btn-primary/.btn-ghost/.sb-link, new .icon-btn utility (44×44px)
- js/api.js: lsConfirm — role=dialog, aria-modal, aria-labelledby, Tab focus trap, restore focus on close; lsToast — aria-live=polite on container, role=alert on errors; live quiz — role=dialog, role=radiogroup, role=radio, aria-checked, keyboard support
- test-run.html: q-opt divs — role=radio/checkbox, aria-checked, tabindex, keyboard enter/space; confirm modal — role=dialog, aria-modal; btn-flag — aria-pressed; dots — aria-label, aria-current; touch targets 44px
- board.html: btn-del-ann — aria-label; reaction buttons — aria-label, aria-pressed
- All 18 HTML files: replace hardcoded color:#8898AA with color:var(--text-3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-04-16 11:42:38 +03:00
parent 3a4623a60a
commit 26ba289019
22 changed files with 362 additions and 299 deletions
+15 -15
View File
@@ -125,7 +125,7 @@
}
.section-title {
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
color: #8898AA; text-transform: uppercase; letter-spacing: 0.07em;
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.07em;
display: flex; align-items: center; gap: 7px;
}
.section-title::before {
@@ -151,7 +151,7 @@
background: rgba(15,23,42,0.05); border: 1.5px solid rgba(15,23,42,0.08);
display: flex; align-items: center; justify-content: center;
font-family: 'Unbounded', sans-serif; font-size: 0.72rem; font-weight: 800;
color: #8898AA; flex-shrink: 0;
color: var(--text-3); flex-shrink: 0;
}
.lesson-num.done {
background: rgba(5,150,82,0.1); border-color: rgba(5,150,82,0.2); color: #059652;
@@ -160,11 +160,11 @@
.lesson-title { font-size: 0.92rem; font-weight: 700; color: #0F172A; }
.lesson-meta-row { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
.lesson-draft-lbl {
font-size: 0.68rem; font-weight: 700; color: #8898AA;
font-size: 0.68rem; font-weight: 700; color: var(--text-3);
background: rgba(15,23,42,0.05); padding: 2px 7px; border-radius: 99px;
}
.lesson-read-time {
font-size: 0.68rem; color: #8898AA; display: flex; align-items: center; gap: 3px;
font-size: 0.68rem; color: var(--text-3); display: flex; align-items: center; gap: 3px;
}
.lesson-stat-lbl {
font-size: 0.7rem; font-weight: 700; color: #06D6A0;
@@ -204,9 +204,9 @@
background: #f8f9fc; border: 1.5px solid rgba(15,23,42,0.07);
border-radius: 14px; padding: 14px 16px;
}
.stat-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-bottom: 6px; }
.stat-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-bottom: 6px; }
.stat-chip-val { font-family: 'Unbounded', sans-serif; font-size: 1.1rem; font-weight: 800; color: #0F172A; }
.stat-chip-sub { font-size: 0.7rem; color: #8898AA; margin-top: 2px; }
.stat-chip-sub { font-size: 0.7rem; color: var(--text-3); margin-top: 2px; }
/* ── analytics dashboard ── */
.analytics-panel {
@@ -229,11 +229,11 @@
.an-chip-val {
font-family: 'Unbounded', sans-serif; font-size: 1.3rem; font-weight: 800;
}
.an-chip-label { font-size: 0.72rem; color: #8898AA; font-weight: 600; margin-top: 4px; }
.an-chip-label { font-size: 0.72rem; color: var(--text-3); font-weight: 600; margin-top: 4px; }
/* lesson bars */
.an-lessons-title {
font-size: 0.76rem; font-weight: 700; color: #8898AA; text-transform: uppercase;
font-size: 0.76rem; font-weight: 700; color: var(--text-3); text-transform: uppercase;
letter-spacing: 0.06em; margin-bottom: 12px;
}
.an-lesson-row {
@@ -276,14 +276,14 @@
}
.an-stuck-info { flex: 1; }
.an-stuck-name { font-size: 0.82rem; font-weight: 700; color: #0F172A; }
.an-stuck-detail { font-size: 0.72rem; color: #8898AA; margin-top: 2px; }
.an-stuck-detail { font-size: 0.72rem; color: var(--text-3); margin-top: 2px; }
/* students table */
.an-students-section { margin-top: 20px; }
.an-students-toggle {
background: none; border: 1.5px solid rgba(15,23,42,0.1); border-radius: 10px;
padding: 8px 16px; font-family: 'Manrope', sans-serif; font-size: 0.78rem;
font-weight: 700; color: #8898AA; cursor: pointer; transition: all 0.15s;
font-weight: 700; color: var(--text-3); cursor: pointer; transition: all 0.15s;
display: flex; align-items: center; gap: 6px;
}
.an-students-toggle:hover { border-color: var(--violet); color: var(--violet); }
@@ -293,7 +293,7 @@
}
.an-students-table th {
text-align: left; padding: 8px 10px; font-size: 0.7rem; font-weight: 700;
color: #8898AA; text-transform: uppercase; letter-spacing: 0.05em;
color: var(--text-3); text-transform: uppercase; letter-spacing: 0.05em;
border-bottom: 1.5px solid rgba(15,23,42,0.08);
}
.an-students-table td {
@@ -350,7 +350,7 @@
.form-input { width: 100%; padding: 11px 14px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 12px; font-family: 'Manrope', sans-serif; font-size: 0.92rem; color: var(--text); background: #f8f9fc; transition: border-color 0.2s; box-sizing: border-box; }
.form-input:focus { outline: none; border-color: var(--violet); background: #fff; }
.modal-footer { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: #8898AA; cursor: pointer; transition: all 0.18s; }
.btn-cancel { padding: 10px 22px; border: 1.5px solid rgba(15,23,42,0.15); border-radius: 999px; background: transparent; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 600; color: var(--text-3); cursor: pointer; transition: all 0.18s; }
.btn-cancel:hover { border-color: rgba(15,23,42,0.3); color: var(--text); }
.btn-primary { padding: 10px 28px; border: none; border-radius: 999px; background: var(--violet); color: #fff; font-family: 'Manrope', sans-serif; font-size: 0.88rem; font-weight: 700; cursor: pointer; box-shadow: 0 2px 10px rgba(155,93,229,0.3); transition: all 0.18s; }
.btn-primary:hover { background: #8a47d8; }
@@ -702,7 +702,7 @@
document.getElementById('lessons-count').textContent = `Уроки · ${lessons.length}`;
if (!lessons.length) {
list.innerHTML = `<div style="text-align:center;padding:40px;color:#8898AA;font-size:0.86rem">
list.innerHTML = `<div style="text-align:center;padding:40px;color:var(--text-3);font-size:0.86rem">
${isTeacher ? 'Нажмите «Урок», чтобы создать первый урок' : 'В курсе пока нет уроков'}
</div>`;
return;
@@ -795,7 +795,7 @@
const data = await LS.api(url);
if (!data.totalStudents && !data.lessons?.length) {
body.innerHTML = '<div style="text-align:center;padding:20px;color:#8898AA;font-size:0.84rem">Нет данных. Назначьте курс классу, чтобы видеть аналитику.</div>';
body.innerHTML = '<div style="text-align:center;padding:20px;color:var(--text-3);font-size:0.84rem">Нет данных. Назначьте курс классу, чтобы видеть аналитику.</div>';
return;
}
@@ -886,7 +886,7 @@
body.innerHTML = html;
lucide.createIcons();
} catch (e) {
body.innerHTML = '<div style="text-align:center;padding:20px;color:#8898AA;font-size:0.84rem">Ошибка загрузки аналитики</div>';
body.innerHTML = '<div style="text-align:center;padding:20px;color:var(--text-3);font-size:0.84rem">Ошибка загрузки аналитики</div>';
}
}