13 · Academy Lesson-Style Pattern¶
Зачем¶
После apruv эталона lesson-viewer.html 2026-05-10 (8 итераций: размер шрифтов панели · collapse правой sidebar · font scale ×1.03 · light gold→bronze · light completed/time readability · dark tone-down active) — фиксируем как финальный эталон lesson-style для академии.
Расширяет 12-academy-premium-body.md (Premium Body Pattern v1.1.0 — 6 принципов body+blocks+chip+compact-fold). Pattern 13 добавляет 7 принципов специфичных для lesson-screens (3-col mirror layout) + cross-cutting theme-aware contrast fixes применимые ко всем academy/* экранам.
Применять: - Lesson-style (3-col mirror): lesson-viewer, lesson-quiz, lesson-completed - Cross-cutting (light/dark fixes): все academy/*.html где есть gold-on-cream contrast или active gold glare
7 принципов¶
1. Mirror panels symmetry (3-col layout)¶
.lesson-layout {
display: grid;
grid-template-columns: 280px 1fr 280px;
gap: 0;
min-height: calc(100vh - 72px);
}
@media (max-width: 1280px) { .lesson-layout { grid-template-columns: 280px 1fr; } .lesson-rightbar { display: none; } }
@media (max-width: 1024px) { .lesson-layout { grid-template-columns: 1fr; } .lesson-sidebar { display: none; } }
/* ОБЕ panels с FIXED высотой (НЕ max-height) для flex stretch и visual symmetry */
.lesson-sidebar,
.lesson-rightbar {
position: sticky;
top: 72px;
height: calc(100vh - 72px); /* НЕ max-height — иначе rightbar короче если контента меньше */
overflow-y: auto;
padding: 24px 20px;
}
.lesson-sidebar { border-right: 1px solid var(--border-faint); }
.lesson-rightbar {
border-left: 1px solid var(--border-faint);
display: flex;
flex-direction: column;
}
.rb-help-block { margin-top: auto; padding-top: 22px; } /* footer-pinned helper block */
Почему height вместо max-height: flex-stretch + sticky требуют фиксированной высоты у parent — иначе короткий контент справа не растягивает rightbar до full viewport, и панель визуально короче левой. CEO 2026-05-10: «справа меньше слева».
2. Font scale +3% для panel content¶
Все font-size в обеих panels масштабированы × 1.03 (round to 0.01 px). Hierarchy 11/12/14/18 сохранена.
/* 11→11.33 — captions (cap), times, chip metas, ::after стрелки */
.lesson-sidebar .module-progress-cap,
.lesson-sidebar .module-title::after,
.lesson-sidebar .lesson-time,
.lesson-rightbar .rb-cap::after,
.lesson-rightbar .rb-row .rb-row-time,
.lesson-rightbar .rb-next-num,
.lesson-rightbar .rb-next-meta { font-size: 11.33px; }
/* 12→12.36 — captions (sub-section labels) */
.lesson-sidebar .module-progress-stats,
.lesson-sidebar .module-title,
.lesson-rightbar .rb-cap { font-size: 12.36px; }
/* 14→14.42 — primary panel rows */
.lesson-sidebar .lesson-row,
.lesson-rightbar .rb-row,
.lesson-rightbar .rb-next-title,
.lesson-rightbar .rb-help-link { font-size: 14.42px; }
/* 18→18.54 — single-cell цифра прогресса */
.lesson-sidebar .module-progress-stats .num { font-size: 18.54px; }
Почему +3% а не +2% или +5%: CEO 2026-05-10 после 2 итераций (×1.02 → ×1.03). +3% даёт читабельность в 280px box без потери hierarchy и без необходимости перевёрстки layout.
3. Mirror typography/padding левой и правой panel¶
Правило: каждый row в правой panel должен match font-size + padding соответствующего row в левой panel.
| Слева | Справа | Match |
|---|---|---|
.lesson-row 14.42px / padding 8px 10px |
.rb-row 14.42px / padding 8px 10px |
✅ |
.lesson-time 11.33px Space Mono Bold |
.rb-row-time 11.33px Space Mono Bold |
✅ |
.module-title 12.36px JBM Bold |
.rb-cap 12.36px JBM Bold |
✅ |
| (нет) | .rb-help-link MUST be 14.42px / padding 8px 10px |
✅ Mirror правило |
Anti-pattern: .rb-help-link 13px / padding 7px 10px — это нарушение mirror (CEO 2026-05-10: «справа мелковато»). Любой row в правой panel = font-size как .lesson-row.
4. Right sidebar collapse mechanism (mirror module-title слева)¶
Каждый блок в правой panel схлопывается через клик по своему .rb-cap — зеркало .module-title collapse слева.
.rb-cap {
cursor: pointer; user-select: none;
display: flex; align-items: center; justify-content: space-between; gap: 8px;
transition: color 150ms ease;
}
.rb-cap:hover { color: #F8F080; } /* dark default — см. принцип 7 для light/dark tone */
.rb-cap::after { content: '↑'; font-size: 11.33px; opacity: 0.5; transition: opacity 150ms ease; }
.rb-block.is-collapsed .rb-cap::after { content: '↓'; }
.rb-block.is-collapsed .rb-cap { margin-bottom: 0; }
.rb-block.is-collapsed .rb-row,
.rb-block.is-collapsed .rb-next-card,
.rb-block.is-collapsed .rb-help-link { display: none; }
// JS: mirror module-title collapse — клик по .rb-cap toggle .is-collapsed на .rb-block
document.querySelectorAll('.rb-cap').forEach(cap => {
cap.addEventListener('click', () => {
cap.parentElement.classList.toggle('is-collapsed');
});
});
Зачем: длинный right sidebar (4 блока: outline + checklist + next + help) на CEO viewport ≤ 920px требует возможности схлопывать неактуальные блоки. Симметрия с module accordion слева.
5. Light theme · gold → deep bronze contrast fix (cross-cutting)¶
#EBC554 (gold) на #FFFCF6 (warm-white) даёт ~2:1 contrast → fail WCAG AA. Заменяем на #7A6614 (deep bronze) → ~7.4:1 (AAA pass) только в light theme.
/* Text colors: gold → bronze (для всех where #EBC554 use в light) */
[data-theme="light"] .module-progress-cap,
[data-theme="light"] .module-progress-stats .num,
[data-theme="light"] .module-title,
[data-theme="light"] .lesson-row.active,
[data-theme="light"] .lesson-row.active::before,
[data-theme="light"] .rb-cap,
[data-theme="light"] .rb-row.is-active,
[data-theme="light"] .rb-row.is-active::before,
[data-theme="light"] .rb-next-meta .arrow,
[data-theme="light"] .lesson-content blockquote strong,
[data-theme="light"] .lesson-nav-btn-primary { color: #7A6614; }
/* Hover states */
[data-theme="light"] .module-title:hover,
[data-theme="light"] .rb-cap:hover,
[data-theme="light"] .lesson-row:hover,
[data-theme="light"] .rb-row:hover,
[data-theme="light"] .rb-help-link:hover,
[data-theme="light"] .rb-help-link:hover .icon,
[data-theme="light"] .lesson-nav-btn:hover,
[data-theme="light"] .breadcrumb a:hover { color: #7A6614; }
/* Backgrounds + borders: rgba(235,197,84,X) → rgba(122,102,20,X) */
[data-theme="light"] .module-progress { background: rgba(122,102,20,0.04); border-color: rgba(122,102,20,0.30); }
[data-theme="light"] .module-title,
[data-theme="light"] .rb-cap { border-bottom-color: rgba(122,102,20,0.20); }
[data-theme="light"] .lesson-row:hover,
[data-theme="light"] .rb-row:hover,
[data-theme="light"] .rb-help-link:hover { background: rgba(122,102,20,0.04); }
[data-theme="light"] .lesson-row.active,
[data-theme="light"] .rb-row.is-active { background: rgba(122,102,20,0.10); border-left-color: #7A6614; }
[data-theme="light"] .rb-next-card { background: rgba(122,102,20,0.04); border-color: rgba(122,102,20,0.30); }
[data-theme="light"] .rb-next-card:hover { background: rgba(122,102,20,0.08); border-color: #7A6614; }
/* Module progress fill (gradient bronze) */
[data-theme="light"] .module-progress-fill { background: linear-gradient(90deg, #5C4D0E, #7A6614); }
/* Lesson content typography (blockquote + code chip) */
[data-theme="light"] .lesson-content blockquote { border-left-color: #7A6614; }
[data-theme="light"] .lesson-content code { background: rgba(122,102,20,0.06); border-color: rgba(122,102,20,0.20); }
/* Lesson navigation buttons (bottom CTA) */
[data-theme="light"] .lesson-nav-btn-primary { border-color: #7A6614; background: rgba(122,102,20,0.04); }
[data-theme="light"] .lesson-nav-btn-primary:hover { background: #7A6614; color: var(--bg-secondary); }
[data-theme="light"] .lesson-nav-btn:hover { border-color: #7A6614; }
/* Video placeholder + controls */
[data-theme="light"] .video-placeholder:hover { border-color: #7A6614; }
[data-theme="light"] .play-btn { border-color: #7A6614; }
[data-theme="light"] .play-icon { color: #7A6614; }
[data-theme="light"] .video-placeholder:hover .play-btn { background: #7A6614; box-shadow: 0 0 30px rgba(122,102,20,0.4); }
[data-theme="light"] .video-tag { color: rgba(122,102,20,0.92); border-color: rgba(122,102,20,0.40); }
Cross-applicable: этот блок раскатывается на ВСЕ academy/* где hardcoded #EBC554 используется в light theme как text/border (caption, active state, hover, button). Caption-only элементы можно оставить gold если они НЕ adjacent body text (single-cell stat number, brand tag).
Seed для master canon (v5.0.0): в roadmap — добавить design token --accent-amber-text-light: #7A6614 в eco-components.css и заменить hardcoded #EBC554 на var(--accent-amber-text) который автоматически разрешается в gold для dark / bronze для light. Тогда этот override-block становится не нужен.
6. Light theme · completed/time readability (cross-cutting)¶
Default tokens var(--text-faint) (~40%) и var(--text-subtle) (~30%) дают fail WCAG AA на cream. Поднимаем до читаемой secondary hierarchy.
/* Completed уроки + done items */
[data-theme="light"] .lesson-row.completed,
[data-theme="light"] .rb-row.is-done { color: rgba(26,26,26,0.65); }
/* Times (small monospace) */
[data-theme="light"] .lesson-time,
[data-theme="light"] .rb-row .rb-row-time { color: rgba(26,26,26,0.62); }
/* Help-block links + icons */
[data-theme="light"] .rb-help-link { color: rgba(26,26,26,0.65); }
[data-theme="light"] .rb-help-link .icon { color: rgba(26,26,26,0.55); }
3-уровневая hierarchy в light: - 0.85+ — primary text (h1, h2, active row text после bronze tone) - 0.65 — secondary state (completed уроки, helper links) - 0.62 — small captions (times)
Cross-applicable: любой academy экран где есть var(--text-faint) или var(--text-subtle) для нерегулярного secondary text в light theme.
7. Dark theme · tone-down активного gold (anti-glare)¶
#EBC554 (lightness 62%) в active state на dark #0C0C12 рядом с обычным var(--text-secondary) (lightness ~80% white) визуально воспринимается как «почти белое» — глазу больно. Заменяем на #D4B447 (lightness 55%) — всё ещё gold, но менее aggressive.
/* Active text + marker + border-left */
[data-theme="dark"] .lesson-row.active,
[data-theme="dark"] .rb-row.is-active { color: #D4B447; background: rgba(235,197,84,0.07); border-left-color: #D4B447; }
[data-theme="dark"] .lesson-row.active::before,
[data-theme="dark"] .rb-row.is-active::before { color: #D4B447; }
/* Hovers (was bright #F8F080 — теперь tone of D4B447) */
[data-theme="dark"] .module-title:hover,
[data-theme="dark"] .rb-cap:hover { color: #D4B447; }
[data-theme="dark"] .lesson-row:hover,
[data-theme="dark"] .rb-row:hover,
[data-theme="dark"] .rb-help-link:hover,
[data-theme="dark"] .rb-help-link:hover .icon { color: #D4B447; }
Что НЕ тушим:
- Static caption-only элементы (.module-title, .rb-cap неактивные, .module-progress-cap, .module-progress-stats .num) — оставлены #EBC554. Это brand identity, мелкие/одиночные, не сидят рядом с body text.
- Background tint понижен 0.10 → 0.07 — мягче подсветка active row.
Active background tint: rgba(235,197,84,0.07) (было 0.10) — чуть менее заметная подсветка row.
Cross-applicable: любой academy экран где .X.active использует bright #EBC554 как text color рядом с body text. Captions-only — не трогать.
Какие селекторы попадают под cross-cutting fixes (5+6+7)¶
При расширении на новые academy экраны — добавить page-specific селекторы в light/dark override blocks:
Принцип 5 (light gold→bronze):
- .X.active text/marker/border (active state)
- .X:hover text + bg (hover state)
- .X-cap (caption labels) — если adjacent body text
- .button-primary-style (CTA buttons)
- .X .accent (decorative gold borders/icons)
Принцип 6 (light completed/time readability):
- .X.completed, .X.is-done, .X.is-past
- .X-time, .X-meta, .X-cap-xs (small mono)
- .X-help-link, .X-secondary-link
Принцип 7 (dark anti-glare active):
- .X.active text/marker (where рядом с body text)
- .X:hover text (where bright)
- .X-title:hover (where ярчайший hover)
- НЕ caption-only static labels
Эталон + apruv-trail¶
academy/lesson-viewer.html — apruvено CEO 2026-05-10 после 8 итераций:
| # | Что | CEO feedback |
|---|---|---|
| 1 | Pattern 12 v1.1.0 baseline | (раскатка через Designer Agent) |
| 2 | .rb-help-link 13→14px + collapse mechanism |
принято |
| 3 | Height symmetry (max-height → height) | принято |
| 4 | Font scale ×1.02 в panels | «ещё +1%» |
| 5 | Font scale ×1.03 + light gold→bronze (#998018) | «бронзовый чуть темнее» |
| 6 | Bronze → #7A6614 | принято |
| 7 | Light completed/time + help-link readability (rgba 0.65/0.62) | «остальное идеально» |
| 8 | Dark tone-down active (#EBC554 → #D4B447) | «всё идеально, фиксируем» |
Anti-patterns¶
- ❌
max-heightдля panels (безheight) — короткий контент справа = rightbar короче слева, асимметрия - ❌ Разные font-size слева и справа (
.rb-help-link13px при.lesson-row14px — нарушение mirror правила) - ❌ Right sidebar без collapse — невозможно схлопнуть на CEO viewport ≤ 920px
- ❌
#EBC554text в light theme — fail WCAG AA (2:1 contrast) - ❌
var(--text-faint)для secondary state в light без override — еле видно (40% opacity) - ❌
var(--text-subtle)для time в light без override — практически невидимо (30%) - ❌ Bright
#F8F080hover в dark — yellow glare, бьёт по глазам - ❌
#EBC554для active state text в dark рядом с body text — визуально «как белое», глаз устаёт - ❌ Tone-down captions (
.module-progress-cap,.module-title,.rb-capstatic) в dark — теряется brand identity - ❌ Замена static gold на bronze в dark — pattern только light-theme
Применение на новом lesson-style экране (workflow)¶
Если экран ИСПОЛЬЗУЕТ 3-col mirror layout (lesson-viewer / lesson-quiz / lesson-completed):¶
- Скопировать 7 CSS блоков из эталона
lesson-viewer.html(принципы 1-7) - Добавить JS handler для
.rb-capcollapse (принцип 4) - Заменить page-specific aside структуру на
.lesson-sidebar+.lesson-rightbarесли другая - Adapt selector list под page-specific блоки в принципах 5-6-7
- Visual check обеих тем:
- Active state в dark: должен быть
#D4B447, не#EBC554 - Completed/time в light: должны читаться (0.65/0.62 opacity)
- Help-block links/icons в light: 0.65/0.55 opacity
- Visual check на CEO viewport ≤ 920px — обе panels equal height + collapse работает
- Bump VERSION patch + CHANGELOG entry
Если экран НЕ lesson-style (dashboard/courses/profile/etc.):¶
Apply ТОЛЬКО cross-cutting принципы 5+6+7 (light gold→bronze + completed/time + dark active tone-down). Адаптировать selector list под page-specific блоки. Принципы 1-4 (mirror layout / font scale / collapse) НЕ применять — не нужны.
Re-entry якорь¶
«прочти контекст academy-lesson-style» или «lesson-style pattern» или «делай как lesson эталон»
Скил перечитывает этот файл целиком + смотрит эталон academy/lesson-viewer.html + проверяет playbook 12 (academy-premium-body) как baseline.