Перейти к содержанию

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-link 13px при .lesson-row 14px — нарушение mirror правила)
  • ❌ Right sidebar без collapse — невозможно схлопнуть на CEO viewport ≤ 920px
  • #EBC554 text в 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 #F8F080 hover в dark — yellow glare, бьёт по глазам
  • #EBC554 для active state text в dark рядом с body text — визуально «как белое», глаз устаёт
  • ❌ Tone-down captions (.module-progress-cap, .module-title, .rb-cap static) в dark — теряется brand identity
  • ❌ Замена static gold на bronze в dark — pattern только light-theme

Применение на новом lesson-style экране (workflow)

Если экран ИСПОЛЬЗУЕТ 3-col mirror layout (lesson-viewer / lesson-quiz / lesson-completed):

  1. Скопировать 7 CSS блоков из эталона lesson-viewer.html (принципы 1-7)
  2. Добавить JS handler для .rb-cap collapse (принцип 4)
  3. Заменить page-specific aside структуру на .lesson-sidebar + .lesson-rightbar если другая
  4. Adapt selector list под page-specific блоки в принципах 5-6-7
  5. Visual check обеих тем:
  6. Active state в dark: должен быть #D4B447, не #EBC554
  7. Completed/time в light: должны читаться (0.65/0.62 opacity)
  8. Help-block links/icons в light: 0.65/0.55 opacity
  9. Visual check на CEO viewport ≤ 920px — обе panels equal height + collapse работает
  10. 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.