Files
LMS/web/src/main/resources/static/css/app.css

769 lines
42 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
display: flex;
flex-direction: column;
background: var(--c-bg);
color: var(--c-text);
font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
/* Палитра Б3: нейтральный каркас + бордовый акцент.
Цвет несёт смысл: акцент — действия и фокус, зелёный/янтарный — статусы защиты,
винный — деструктивные действия и негативная тональность. */
:root {
--bs-body-font-family: 'Inter', system-ui, -apple-system, sans-serif;
--bs-body-bg: #fafafa;
--bs-body-color: #131316;
--bs-border-color: #e6e6e9;
--bs-border-radius: 0.5rem;
--bs-border-radius-lg: 0.625rem;
--bs-link-color: #7a2333;
--bs-link-hover-color: #9d2b3c;
--c-bg: #fafafa;
--c-surface: #ffffff;
--c-text: #131316;
--c-text-muted: #74747c;
--c-text-link: #7a2333;
--c-text-link-hover: #9d2b3c;
--c-border: #e6e6e9;
--c-border-strong: #d4d4da;
--c-accent: #7a2333;
--c-accent-hover: #5f1b28;
--c-accent-soft: #f7edee;
--c-badge-ok-bg: #f2f7f3;
--c-badge-ok-text: #2f6b3a;
--c-badge-ok-border: #b7cdbd;
--c-badge-warn-bg: #faf5e9;
--c-badge-warn-text: #8a5a12;
--c-badge-warn-border: #d3bd8f;
--c-tone-pos: #2f6b3a;
--c-tone-neg: #9d2b3c;
--c-tone-neu: #74747c;
--radius-xs: 0.125rem;
--radius-sm: 0.25rem;
--radius: 0.5rem;
--radius-lg: 0.625rem;
}
[data-theme="dark"] {
--c-bg: #101014;
--c-surface: #17181d;
--c-text: #e8e9ec;
--c-text-muted: #9a9ba4;
--c-text-link: #d98b98;
--c-text-link-hover: #f0b9c2;
--c-border: #26272e;
--c-border-strong: #34353d;
--c-accent: #a64d5f;
--c-accent-hover: #b86070;
--c-accent-soft: rgba(166, 77, 95, 0.16);
--c-badge-ok-bg: rgba(46, 107, 58, 0.25);
--c-badge-ok-text: #8fd4a1;
--c-badge-ok-border: rgba(143, 212, 161, 0.4);
--c-badge-warn-bg: rgba(138, 90, 18, 0.25);
--c-badge-warn-text: #e3b766;
--c-badge-warn-border: rgba(227, 183, 102, 0.4);
--c-tone-pos: #6fcf8f;
--c-tone-neg: #d98b98;
--c-tone-neu: #9a9ba4;
}
a { color: var(--c-accent); text-decoration: none; }
a:not(.btn):hover { color: var(--c-accent-hover); }
/* Атрибут hidden должен скрывать элемент даже если у него display из класса */
[hidden] { display: none !important; }
/* Layout */
.page { display: flex; flex-direction: column; min-height: 100vh; }
}
.page-main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 2.5rem 1.75rem 3.5rem; }
@media (max-width: 720px) { .page-main { padding: 1.5rem 0.875rem 2.5rem; } }
.page-footer { text-align: center; color: var(--c-text-muted); font-size: 0.75rem; padding: 1.5rem; }
.user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.84375rem; margin-left: auto; }
.nav-user { font-weight: 500; color: var(--c-text); }
.score-big { display: inline-block; margin-left: 0.5rem; font-size: 1.75rem; font-weight: 700; line-height: 1; color: var(--c-tone-pos); font-variant-numeric: tabular-nums; vertical-align: middle; }
.variant-name { font-weight: 600; }
.variant-name b { font-variant-numeric: tabular-nums; }
p { margin-top: 0; }
.theme-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.3rem 0.5rem; }
.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; }
.breadcrumb .nav-sep { user-select: none; }
.check-list { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.25rem; max-height: 12rem; overflow-y: auto; }
/* Buttons — по спецификации Б3: основная кнопка залита акцентом,
вторичная и опасная — контурные. Компактный кегль 13px. */
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
white-space: nowrap;
border: 1px solid var(--c-accent); border-radius: var(--radius);
background: var(--c-accent); color: #ffffff;
padding: 0.5rem 1rem; font-size: 0.8125rem; font-weight: 500;
cursor: pointer; text-decoration: none;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn:active { opacity: 0.85; }
.btn:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.btn:hover { background: var(--c-accent-hover); border-color: var(--c-accent-hover); }
.btn-primary { background: var(--c-accent); border-color: var(--c-accent); color: #ffffff; }
.btn-primary:hover { background: var(--c-accent-hover); border-color: var(--c-accent-hover); }
.btn-secondary { background: var(--c-surface); border-color: var(--c-border-strong); color: var(--c-text); }
.btn-secondary:hover { background: var(--c-bg); border-color: var(--c-border-strong); color: var(--c-text); }
.btn-danger { background: var(--c-surface); border-color: #dcb9be; color: var(--c-accent); }
.btn-danger:hover { background: var(--c-accent-soft); border-color: var(--c-accent); }
/* Forms */
.input {
width: 100%; border-radius: var(--radius); background: var(--c-surface); color: var(--c-text);
padding: 0.5rem 0.75rem; font-size: 0.875rem; border: 1px solid var(--c-border-strong);
outline: none;
}
.input:focus { border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-soft); }
.input::placeholder { color: var(--c-text-muted); }
.label { display: block; margin-bottom: 0.25rem; font-size: 0.875rem; font-weight: 500; }
.hint { margin-top: 0.25rem; font-size: 0.75rem; color: var(--c-text-muted); }
/* ===== B3-тема поверх Bootstrap: navbar, offcanvas, кнопки, ссылки ===== */
code { --bs-code-color: var(--c-text); color: var(--c-text); }
.b3-navbar { background: var(--c-surface); border-bottom: 1px solid var(--c-border); }
.b3-navbar .container, .page-main.container { max-width: 1200px; }
.b3-navbar .navbar-brand { color: var(--c-text); font-weight: 700; font-size: 1rem; }
.b3-navbar .navbar-brand b { color: var(--c-accent); }
.b3-navbar .navbar-toggler { border: 1px solid var(--c-border-strong); color: var(--c-accent); padding: 0.25rem 0.5rem; line-height: 1; }
.b3-navbar .navbar-toggler:focus { box-shadow: none; }
.nav-link { --bs-nav-link-color: var(--c-accent); --bs-nav-link-hover-color: var(--c-accent-hover); font-weight: 500; font-size: 0.875rem; }
.nav-link.active { color: var(--c-accent) !important; font-weight: 700; }
.navbar-close { border: 0; background: none; color: var(--c-text-muted); font-size: 1.1rem; line-height: 1; }
.navbar-close:hover { color: var(--c-text); }
.app-offcanvas { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-color: var(--c-text); --bs-offcanvas-border-color: var(--c-border); }
.app-offcanvas .offcanvas-header { border-bottom: 1px solid var(--c-border); justify-content: space-between; gap: 1rem; }
.app-offcanvas .navbar-nav { gap: 0.25rem; }
.app-offcanvas .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
@media (max-width: 767.98px) {
#mobileNav .offcanvas-body { display: flex; flex-direction: column; justify-content: space-between; gap: 1rem; }
}
.nav-user { font-weight: 500; color: var(--c-accent); text-decoration: none; }
.nav-user:hover { color: var(--c-accent-hover); }
.nav-user.defense-active::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--c-accent); margin-right: 0.4rem; vertical-align: middle; }
.page-main { padding: 2.5rem 1.75rem 3.5rem; }
@media (max-width: 720px) { .page-main { padding: 1.5rem 0.875rem 2.5rem; } }
/* Кнопки: B3-палитра через переменные Bootstrap */
.btn {
--bs-btn-bg: var(--c-accent); --bs-btn-border-color: var(--c-accent); --bs-btn-color: #ffffff;
--bs-btn-hover-bg: var(--c-accent-hover); --bs-btn-hover-border-color: var(--c-accent-hover); --bs-btn-hover-color: #ffffff;
--bs-btn-active-bg: #6a1d2c; --bs-btn-active-border-color: #6a1d2c; --bs-btn-active-color: #ffffff;
--bs-btn-disabled-bg: var(--c-accent); --bs-btn-disabled-border-color: var(--c-accent); --bs-btn-disabled-color: #ffffff;
--bs-btn-font-size: 0.8125rem; --bs-btn-padding-y: 0.5rem; --bs-btn-padding-x: 1rem;
--bs-btn-border-radius: var(--radius);
}
.btn-primary { --bs-btn-bg: var(--c-accent); --bs-btn-border-color: var(--c-accent); --bs-btn-color: #ffffff;
--bs-btn-hover-bg: var(--c-accent-hover); --bs-btn-hover-border-color: var(--c-accent-hover); --bs-btn-hover-color: #ffffff;
--bs-btn-active-bg: #6a1d2c; --bs-btn-active-border-color: #6a1d2c; --bs-btn-active-color: #ffffff; }
.btn-secondary { --bs-btn-bg: var(--c-surface); --bs-btn-border-color: var(--c-border-strong); --bs-btn-color: var(--c-text);
--bs-btn-hover-bg: var(--c-bg); --bs-btn-hover-border-color: var(--c-border-strong); --bs-btn-hover-color: var(--c-text);
--bs-btn-active-bg: var(--c-bg); --bs-btn-active-border-color: var(--c-border-strong); --bs-btn-active-color: var(--c-text); }
.btn-danger { --bs-btn-bg: var(--c-surface); --bs-btn-border-color: #dcb9be; --bs-btn-color: var(--c-accent);
--bs-btn-hover-bg: var(--c-accent-soft); --bs-btn-hover-border-color: var(--c-accent); --bs-btn-hover-color: var(--c-accent);
--bs-btn-active-bg: var(--c-accent-soft); --bs-btn-active-border-color: var(--c-accent); --bs-btn-active-color: var(--c-accent); }
.btn-sm { --bs-btn-padding-y: 0.25rem; --bs-btn-padding-x: 0.6rem; --bs-btn-font-size: 0.75rem; }
a { --bs-link-color: var(--c-accent); --bs-link-hover-color: var(--c-accent-hover); text-decoration: none; }
/* ---- Полосы прокрутки в стиле приложения (везде: страница, модалки, таблицы, pre) ---- */
* { scrollbar-width: thin; scrollbar-color: var(--c-border-strong) var(--c-bg); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--c-bg); }
::-webkit-scrollbar-thumb { background: var(--c-border-strong); border: 2px solid var(--c-bg); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--c-accent); }
::-webkit-scrollbar-corner { background: var(--c-bg); }
/* Cards */
.card { border-radius: var(--radius-lg); background: var(--c-surface); border: 1px solid var(--c-border); }
.card-flush { border-radius: var(--radius-lg); background: var(--c-surface); border: 1px solid var(--c-border); padding: 0; overflow: hidden; }
.card-body { padding: 1.5rem; }
/* Grid */
.grid { display: grid; gap: 1rem; }
.grid-2 { grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr)); }
.grid-stats { grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); }
/* Typography */
.page-title { margin: 0 0 1.5rem; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
.section-title { margin: 0 0 0.75rem; font-size: 1.125rem; font-weight: 500; }
/* Шапка страницы в стиле Б3: kicker + заголовок + мета, действия справа */
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1.75rem; flex-wrap: wrap; }
.page-head .page-title { margin: 0 0 0.5rem; }
.kicker { margin: 0 0 0.375rem; font-size: 0.75rem; font-weight: 500; color: var(--c-text-muted); }
.meta { margin: 0; color: var(--c-text-muted); font-size: 0.8125rem; }
.meta b { color: var(--c-text); font-weight: 600; }
.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.toolbar { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.stat-value { margin: 0.5rem 0 0; font-size: 1.875rem; font-weight: 600; }
.stat-title { font-size: 0.875rem; color: var(--c-text-muted); margin: 0; }
/* Badges — «этикетки»: строгая рамка, разрядка капсом; только индикаторы статуса */
.badge {
display: inline-flex; align-items: center;
border-radius: var(--bs-btn-border-radius, var(--radius-sm)); padding: 0.5rem 1rem;
font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
border: 1px solid transparent;
}
.badge-ok { background: var(--c-badge-ok-bg); color: var(--c-badge-ok-text); border-color: var(--c-badge-ok-border); }
.badge-warn { background: var(--c-badge-warn-bg); color: var(--c-badge-warn-text); border-color: var(--c-badge-warn-border); }
/* Tables */
table { width: 100%; font-size: 0.875rem; border-collapse: collapse; }
/* Прокручивается только таблица (обёртка ставится скриптом table-scroll.js), не карточка */
.table-scroll-box { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
th { text-align: left; font-weight: 500; color: var(--c-text-muted); padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--c-border); }
td { padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--c-border); }
tr:last-child td { border-bottom: none; }
/* Alerts */
.alert { padding: 0.75rem 1rem; border-radius: var(--radius); font-size: 0.875rem; margin-bottom: 1rem; }
.alert-error { background: #fef2f2; color: #991b1b; }
.alert-success { background: #dcfce7; color: #166534; }
.alert-warning { background: #fef3c7; color: #92400e; }
.list-pad { padding-left: 1.25rem; }
.import-card { border-color: var(--c-badge-ok-border); }
.mini-alert { padding: 0.5rem 0.75rem; border-radius: var(--radius-xs); margin-bottom: 0.5rem; }
/* Theme toggle */
.theme-btn { padding: 0.25rem 0.5rem; font-size: 0.75rem; }
/* Group assignment page */
.group-title { margin: 0 0 0.5rem; font-size: 1rem; font-weight: 600; }
.inline-form { display: inline-flex; align-items: center; gap: 0.375rem; margin: 0; }
/* Селект фокуса на лабу в тулбаре ведомости — по содержимому, не на всю ширину */
.input-lab-focus { width: auto; min-width: 11rem; }
.input-score { width: 4.5rem; }
.inline-form .input-score, input[type="number"].input-score { width: 4.5rem; min-width: 4.5rem; flex: 0 0 auto; }
.filter-select { width: auto; }
.hidden { display: none !important; }
/* На узком экране формы-строки растягиваются и переносят элементы:
нативный select иначе тянется по самому длинному пункту и вылезает за экран */
@media (max-width: 640px) {
.inline-form { display: flex; flex-wrap: wrap; width: 100%; }
.inline-form .input, .inline-form select { width: 100%; min-width: 0; }
.inline-form .btn { flex: 0 0 auto; }
.actions-cell .inline-form { display: inline-block; width: auto; }
.actions-cell .inline-form .input, .actions-cell .inline-form select { width: auto; }
}
/* Toast-уведомление */
.toast { position: fixed; top: 1rem; right: 1rem; z-index: 50; width: 20rem; }
/* Всплывающие уведомления (flash notice/error) вместо статичных алертов */
/* Уведомления: внизу по центру, в стиле Б3 (поверх .notice) */
.toast-host {
position: fixed; left: 50%; transform: translateX(-50%); bottom: 1.5rem; z-index: 100;
display: flex; flex-direction: column; gap: 0.5rem; align-items: stretch;
width: min(34rem, calc(100vw - 2rem)); pointer-events: none;
}
.toast-item {
pointer-events: auto; display: flex; align-items: flex-start; gap: 0.75rem;
padding: 0.75rem 1rem; border-radius: var(--radius); border: 1px solid var(--c-border);
border-left: 3px solid var(--c-accent); background: var(--c-surface); color: var(--c-text);
font-size: 0.8125rem;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
animation: toast-in 0.18s ease-out;
}
.toast-item .toast-text { flex: 1 1 auto; min-width: 0; white-space: pre-line; overflow-wrap: anywhere; }
.toast-item .toast-text .code { margin: 0 0.1rem; }
.toast-item.toast-success { border-left-color: var(--c-tone-pos); background: var(--c-badge-ok-bg); }
.toast-item.toast-error { border-left-color: var(--c-accent); background: var(--c-accent-soft); }
.toast-item.toast-warning { border-left-color: var(--c-badge-warn-border); background: var(--c-badge-warn-bg); }
.toast-close {
flex: 0 0 auto; border: none; background: none; cursor: pointer;
color: var(--c-text-muted); font-size: 1rem; line-height: 1; padding: 0 0.1rem;
}
.toast-close:hover { color: var(--c-text); }
@keyframes toast-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
.confirm-text { margin: 0; font-size: 0.875rem; white-space: pre-line; overflow-wrap: anywhere; }
/* Modals */
dialog.dlg {
border: 1px solid var(--c-border); border-radius: var(--radius-lg); padding: 0;
background: var(--c-surface); color: var(--c-text);
width: min(34rem, calc(100vw - 2rem));
box-shadow: 0 16px 48px rgba(19, 19, 22, 0.28);
}
dialog.dlg::backdrop { background: rgba(19, 19, 22, 0.5); }
/* Пока открыта модалка — страница не прокручивается, позиция скролла сохраняется;
прокрутка остаётся внутри .modal-body */
html.modal-open body {
position: fixed; left: 0; right: 0; width: 100%; top: var(--modal-top, 0);
padding-right: var(--modal-scrollbar, 0);
}
.dlg-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); }
.dlg-title { margin: 0; font-size: 1.0625rem; font-weight: 600; }
.dlg-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; }
.dlg-close:hover { color: var(--c-text); }
.dlg-body { padding: 1.5rem; max-height: 70vh; overflow-y: auto; display: flex; flex-direction: column; }
/* Кнопки действий — внизу справа; при увеличенной модалке пустота снизу не остаётся */
.dlg-body > form.form-stack:last-child { flex: 1 1 auto; }
.dlg-body > form.form-stack:last-child > button:last-child,
.dlg-body > form.form-stack:last-child > .flex:last-child,
.dlg-body.form-stack > button:last-child,
.dlg-body.form-stack > .flex:last-child,
.modal-body > button:last-child,
.modal-body > .flex:last-child {
margin-top: auto;
align-self: flex-end;
}
.defense-footer { margin-top: auto; justify-content: flex-end; align-items: center; }
.modal-body > #defense-status:empty { display: none; }
/* Двухуровневые формы уровней лабы */
.level-row { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; }
.level-row .input { flex: 1; }
/* Markdown body */
.md-body { font-size: 0.9375rem; }
.md-body h1, .md-body h2, .md-body h3, .md-body h4, .md-body h5, .md-body h6 { margin: 1rem 0 0.5rem; line-height: 1.3; }
.md-body h1 { font-size: 1.25rem; }
.md-body h2 { font-size: 1.125rem; }
.md-body h3 { font-size: 1rem; }
.md-body h4 { font-size: 0.9375rem; }
.md-body h5 { font-size: 0.875rem; }
.md-body h6 { font-size: 0.8125rem; }
.md-body p, .md-body ul, .md-body ol { margin: 0.5rem 0; }
.md-body ul, .md-body ol { padding-left: 1.5rem; }
.md-body pre { background: var(--c-bg); border: 1px solid var(--c-border); border-radius: var(--radius); padding: 0.75rem 1rem; overflow-x: auto; font-size: 0.8125rem; }
.md-body code { font-family: monospace; }
/* Ссылки в учебных материалах — акцентные, с подчёркиванием: их видно в тексте */
.md-body a { color: var(--c-accent); text-decoration: none; }
.md-body a:hover { color: var(--c-accent-hover); }
.md-body details.spoiler { border: 1px solid var(--c-border); border-radius: var(--radius); padding: 0.5rem 0.75rem; margin: 0.5rem 0; }
.md-body details.spoiler summary { cursor: pointer; font-weight: 500; color: var(--c-accent); }
.md-body img { max-width: 100%; }
.md-body table { margin: 0; }
/* Таблицы в статьях прокручиваются по горизонтали, как блоки кода */
.table-scroll { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0.5rem 0; }
/* Блок кода: кнопка копирования в правом верхнем углу */
.md-code-wrap { position: relative; margin: 0.5rem 0; }
.md-code-wrap pre { margin: 0; }
.md-copy {
position: absolute; top: 0.4rem; right: 0.4rem;
font: inherit; font-size: 0.72rem; line-height: 1;
padding: 0.25rem 0.5rem; cursor: pointer;
color: var(--c-text-muted); background: var(--c-surface);
border: 1px solid var(--c-border); border-radius: var(--radius-sm); opacity: 0.85;
}
.md-copy:hover { color: var(--c-text); opacity: 1; }
.md-copy.copied { color: var(--c-text-link); }
/* Empty state */
.empty { text-align: center; color: var(--c-text-muted); padding: 1.5rem; }
/* Mono inline code */
code.code { padding: 0.125rem 0.5rem; border-radius: var(--radius-xs); font-family: monospace; background: var(--c-bg); }
/* Containers */
.container-sm { max-width: 28rem; margin: 0 auto; }
.form-stack { display: flex; flex-direction: column; gap: 1rem; }
.form-card { padding: 1.5rem; }
/* Header logo */
.link-inherit { font-size: 0.875rem; }/* Chips (оценочные комментарии) */
.chip { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 8px; border-radius: var(--radius-sm); font-size: 11.5px; line-height: 1.5; }
.chip-pos { background: #2e6b3a; color: #fff; }
.chip-neu { background: #5d6570; color: #fff; }
.chip-neg { background: #8f2d3c; color: #fff; }
/* Слоты комментариев в диалоге */
.cs-row { display: flex; gap: 6px; align-items: center; }
.cs-text-wrap { position: relative; flex: 1 1 auto; min-width: 0; }
.cs-text-wrap .cs-text { width: 100%; }
.cs-row .cs-tone, .cs-row .btn { flex: 0 0 auto; }
.cs-tone { width: auto; }
.ac-list {
position: absolute; left: 0; right: 0; top: 100%; margin-top: 2px; z-index: 20;
max-height: 14rem; overflow-y: auto;
background: var(--c-surface); border: 1px solid var(--c-border);
border-radius: var(--radius-sm); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.ac-list.drop-up { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 2px; }
.ac-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.6rem; padding-left: 0.45rem; border-left: 3px solid transparent; cursor: pointer; font-size: 0.875rem; }
.ac-item:hover, .ac-item.active { background: var(--c-bg); }
.ac-item.ac-pos { border-left-color: var(--c-tone-pos); }
.ac-item.ac-neg { border-left-color: var(--c-tone-neg); }
.ac-item.ac-neu { border-left-color: var(--c-tone-neu); }
.ac-tone { flex: 0 0 auto; width: 1rem; text-align: center; font-size: 0.8rem; font-weight: 700; }
.ac-tone-pos { color: var(--c-tone-pos); }
.ac-tone-neg { color: var(--c-tone-neg); }
.ac-tone-neu { color: var(--c-tone-neu); }
.ac-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-count { flex: 0 0 auto; background: var(--c-border); color: var(--c-text-muted); }
.ac-del { flex: 0 0 auto; border: none; background: transparent; color: var(--c-text-muted); cursor: pointer; padding: 0 0.25rem; border-radius: var(--radius-xs); font-size: 0.75rem; line-height: 1.4; }
.ac-del:not(:disabled):hover { color: #dc2626; background: var(--c-bg); }
.ac-del:disabled { opacity: 0.3; cursor: not-allowed; }
.ac-empty { padding: 0.4rem 0.6rem; font-size: 0.875rem; color: var(--c-text-muted); }
/* Ячейка матрицы в стиле Б3: вариант и оценка — текстом, подстрока — сдача и защита с точкой */
.cell-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 0.375rem; }
.cell-main { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
/* Публикация в ячейке — «глаз»-точка: ○ скрыто, ◉ опубликовано (нативный checkbox под капотом) */
.pub-toggle {
appearance: none; -webkit-appearance: none;
width: 1rem; height: 1rem; margin: 0; padding: 0; cursor: pointer;
border-radius: 50%; border: 1.5px solid var(--c-border-strong);
background: transparent; vertical-align: middle;
transition: border-color 0.15s, box-shadow 0.15s;
}
.pub-toggle:checked {
border-color: var(--c-accent);
background: radial-gradient(circle, var(--c-accent) 0 42%, transparent 48%);
}
.pub-toggle:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.variant-btn {
display: inline-block; padding: 0; border: none; background: none;
font-size: 0.84375rem; font-weight: 600; white-space: nowrap; cursor: pointer;
color: var(--c-text); text-decoration: none;
}
.variant-btn:hover { color: var(--c-accent); text-decoration: underline; }
.variant-btn.manual { font-weight: 700; }
.variant-btn .cell-none { color: var(--c-text-muted); font-weight: 400; }
.variant-btn.manual .cell-none { font-weight: 600; }
.score-link {
display: inline-block; padding: 0; border: none; background: none;
font-size: 0.8125rem; font-weight: 600; font-variant-numeric: tabular-nums;
color: var(--c-text); cursor: pointer;
}
.score-link:hover { color: var(--c-accent); text-decoration: underline; }
.score-link.none { color: var(--c-text-muted); font-weight: 400; }
.cell-sub { display: flex; align-items: center; gap: 0.875rem; flex-wrap: wrap; font-size: 0.75rem; }
.sub-link { color: var(--c-text-muted); text-decoration: none; font-variant-numeric: tabular-nums; }
.sub-link:hover { color: var(--c-text); text-decoration: underline; }
.sub-dim { color: var(--c-text-muted); }
.cell-dim { color: var(--c-text-muted); }
/* Статус защиты: текст с цветной точкой вместо кнопки-плашки.
Класс cell-btn сохранён — по нему JS находит ячейку (defenseBtn). */
.cell-btn.st {
display: inline-flex; align-items: center; gap: 0.35rem;
min-width: 0; height: auto; padding: 0;
border: none; border-radius: 0; background: none;
color: var(--c-text-muted); font-size: 0.75rem; text-decoration: none; cursor: pointer;
}
.cell-btn.st:hover { background: none; color: var(--c-text); }
.cell-btn.st::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--c-border-strong); }
.cell-btn.st.ok { color: var(--c-tone-pos); }
.cell-btn.st.ok::before { background: var(--c-tone-pos); }
.cell-btn.st.warn { color: #b45309; }
.cell-btn.st.warn::before { background: #b45309; }
.cell-btn.st.dim { color: var(--c-text-muted); }
.cell-btn.st.dim::before { background: var(--c-border-strong); }
.mini-count { font-size: 0.72rem; margin-left: 0.15rem; color: var(--c-text-muted); }
.defense-cell-timer { font-variant-numeric: tabular-nums; }
.lab-head-actions { display: flex; gap: 0.2rem; }
.btn btn-secondary btn-sm p-2 {
display: inline-flex; align-items: center; justify-content: center;
min-width: 1.5rem; height: 1.5rem; padding: 0 0.3rem; cursor: pointer;
border: 1px solid var(--c-border); border-radius: var(--radius-sm);
background: var(--c-surface); color: var(--c-text); text-decoration: none; font-size: 0.85rem;
}
.btn btn-secondary btn-sm p-2:hover { background: var(--c-bg); }
.js-pub-eye .eye-closed { display: none; }
.js-pub-eye.is-empty .eye-open { display: none; }
.js-pub-eye.is-empty .eye-closed { display: inline-block; }
.js-pub-count.is-hidden { display: none; }
/* Увеличенный диалог (оценка + комментарии) */
dialog.dlg.dlg-lg { width: min(72rem, calc(100vw - 2rem)); }
dialog.dlg.dlg-lg .dlg-body { max-height: 88vh; min-height: 62vh; }
.btn btn-secondary btn-sm p-2 svg, .cell-btn svg { width: 1rem; height: 1rem; }
.chip { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 8px; border-radius: var(--radius-sm); font-size: 11.5px; line-height: 1.5; }
.chip-pos { background: #2e6b3a; color: #fff; }
.chip-neu { background: #5d6570; color: #fff; }
.chip-neg { background: #8f2d3c; color: #fff; }
/* Defense timer */
/* Материалы: ряды и ручки перетаскивания слева, одним столбцом */
.sort-row { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.sort-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sort-actions { margin-left: auto; display: flex; flex-wrap: nowrap; align-items: center; gap: 0.35rem; }
.sort-list { list-style: none; margin: 0; padding: 0; }
.sort-list > li { display: flex; align-items: center; gap: 0.5rem; min-width: 0; padding: 0.15rem 0; }
.chapter-card { padding: 0.75rem 1rem; }
.sub-acc { margin-top: 0.25rem; border-top: 1px solid var(--c-border); }
[data-section-list] > .sub-acc:first-of-type { border-top: none; }
.sub-acc > .sub-head { padding: 0.4rem 0; }
.sub-acc.collapsed > .section-body { display: none; }
.sub-toggle {
display: inline-flex; align-items: center; justify-content: center;
flex: 0 0 auto; width: 1rem; height: 1rem; padding: 0; border: none;
background: none; cursor: pointer; color: var(--c-text-muted);
}
.sub-toggle:hover { color: var(--c-text); }
.sub-arrow i { font-size: 1rem; line-height: 1; }
.sub-arrow { transform: rotate(0deg); transition: transform 0.2s; }
.sub-acc.collapsed .sub-arrow { transform: rotate(0deg); }
.sub-acc:not(.collapsed) .sub-arrow { transform: rotate(180deg); }
.section-body { padding-bottom: 0.4rem; }
/* ---- Матрица группы и карточки защиты ---- */
.scroll-x { overflow-x: auto; }
.matrix { border-collapse: separate; border-spacing: 0; }
.matrix th {
vertical-align: top; padding: 0.75rem 1rem; text-align: left;
font-size: 0.75rem; font-weight: 500; color: var(--c-text-muted);
background: var(--c-surface); white-space: nowrap;
}
.matrix td { vertical-align: top; padding: 1rem; }
.matrix tbody tr:hover td { background: rgba(19, 19, 22, 0.03); }
[data-theme="dark"] .matrix tbody tr:hover td { background: rgba(232, 233, 236, 0.045); }
.matrix tbody tr:last-child td { border-bottom: none; }
.matrix th.lab-col { min-width: 9.5rem; border-left: 1px solid var(--c-border); }
.matrix td.cell-lab { min-width: 9.5rem; border-left: 1px solid var(--c-border); }
.matrix td.student-cell { min-width: 12rem; }
.student-name { font-weight: 600; font-size: 0.84375rem; }
.student-cell .font-mono { margin-top: 0.125rem; }
.lab-col-head { display: flex; flex-direction: column; align-items: flex-start; gap: 0.375rem; }
.lab-col-title {
max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 0.7rem; font-weight: 400; color: var(--c-text-muted); letter-spacing: 0;
}
.cell-line { display: flex; align-items: center; gap: 0.375rem; font-size: 0.8125rem; text-align: left; }
.cell-label { color: var(--c-text-muted); min-width: 3.5rem; }
.cell-link { font-size: 0.8125rem; }
.cell-edit { padding: 0 0.4rem; }
.cell-grade-line { font-weight: 500; }
.defense-cell-actions { display: flex; gap: 0.35rem; justify-content: flex-end; flex-wrap: wrap; }
.th-w-sm { width: 4rem; }
.th-w-md { width: 12rem; }
.span-2 { grid-column: 1 / -1; }
.preview { max-width: 34rem; }
.md-preview { max-width: 22rem; }
/* ---- Комментарии к оценке (ЛК студента) ---- */
.review-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 1rem; }
.review-col h3 { margin-bottom: 0.35rem; }
.review-list { margin: 0; padding-left: 1.15rem; }
.review-list li { margin: 0.15rem 0; }
.tone-positive-text { color: #166534; }
.tone-negative-text { color: #991b1b; }
[data-theme="dark"] .tone-positive-text { color: #6ee7b7; }
[data-theme="dark"] .tone-negative-text { color: #fca5a5; }
.tone-label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; }
/* Чекбоксы — в акцентной (бордовой) гамме */
input[type="checkbox"] { accent-color: var(--c-accent); width: 1rem; height: 1rem; cursor: pointer; flex: 0 0 auto; }
/* Галочка-«пилюля»: компактная опция с рамкой, подсвечивается при выборе */
.tone-pill { border: 1px solid var(--c-border); border-radius: var(--radius); padding: 0.4rem 0.7rem; background: var(--c-surface); cursor: pointer; user-select: none; }
.tone-pill:hover { border-color: var(--c-border-strong); }
.tone-pill:has(input:checked) { border-color: var(--c-accent); color: var(--c-accent); background: var(--c-accent-soft); }
.pre-wrap { white-space: pre-wrap; word-break: break-word; }
/* Редактируемая матрица: закреплённый столбец и компактные селекты */
.matrix-sticky { position: sticky; left: 0; z-index: 2; background: var(--c-surface); box-shadow: 8px 0 8px -8px rgba(19, 19, 22, 0.1); }
.matrix thead .matrix-sticky { z-index: 3; }
.level-form { margin: 0; }
.level-select {
width: auto; min-width: 6rem; max-width: 9.5rem;
padding: 0.15rem 1.5rem 0.15rem 0.4rem; font-size: 0.75rem;
}
.cell-level { justify-content: center; }
.pin-hint { font-size: 0.75rem; }
/* Компактные ячейки матрицы группы */
.btn-xs { padding: 0.05rem 0.4rem; font-size: 0.7rem; line-height: 1.5; }
.badge-xs { font-size: 0.65rem; padding: 0.05rem 0.4rem; }
.chip-xs { font-size: 0.65rem; padding: 0.05rem 0.4rem; }
.cell-top { display: flex; align-items: center; justify-content: center; gap: 0.25rem; }
.cell-chips { display: flex; flex-wrap: wrap; gap: 0.18rem; justify-content: center; margin-top: 0.25rem; }
.cell-chip {
display: inline-flex; align-items: center; gap: 0.15rem;
font-size: 0.72rem; line-height: 1.7; padding: 0.05rem 0.45rem;
border: 1px solid var(--c-border); border-radius: var(--radius-sm);
background: var(--c-bg); color: var(--c-text); white-space: nowrap; cursor: pointer;
text-decoration: none; font-family: inherit;
}
.cell-chip:hover { border-color: var(--c-border-strong, var(--c-border)); filter: brightness(0.97); }
.chip-dim { color: var(--c-text-muted); }
.chip-warn { color: #92400e; background: #fef3c7; border-color: #fde68a; }
.chip-ok { color: #166534; background: #dcfce7; border-color: #bbf7d0; }
.chip-link:hover { color: var(--c-accent); }
[data-theme="dark"] .chip-warn { color: #fcd34d; background: rgba(146, 64, 14, 0.25); border-color: rgba(146, 64, 14, 0.5); }
[data-theme="dark"] .chip-ok { color: #86efac; background: rgba(22, 101, 52, 0.25); border-color: rgba(22, 101, 52, 0.5); }
.lab-head-row { display: flex; align-items: center; justify-content: center; gap: 0.3rem; }
.actions-cell { white-space: nowrap; }
.actions-cell .inline-form { display: inline-block; }
/* Действия столбиком: ровные одинаковые кнопки друг под другом */
.actions-col { display: inline-flex; flex-direction: column; gap: 0.35rem; align-items: stretch; min-width: 6.5rem; }
.actions-col .inline-form { display: block; width: 100%; }
/* Строки с кнопками-иконками: формы не растягиваются на всю ширину (иначе столбик на мобиле) */
.action-row .inline-form { display: inline-flex; width: auto; flex-wrap: nowrap; }
#articleSide { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-color: var(--c-text); --bs-offcanvas-border-color: var(--c-border); }
#articleSide .offcanvas-header { justify-content: space-between; align-items: center; border-bottom: 1px solid var(--c-border); }
.actions-col .btn { display: block; width: 100%; text-align: center; }
/* Иконки — SVG-файлы из /icons через CSS-маски: цвет наследуется от текста */
.cell-ico { font-size: 0.95rem; line-height: 1; }
/* tablekit: сортируемые таблицы и поиск */
th.th-sortable { cursor: pointer; user-select: none; }
th.th-sortable:hover { background: var(--c-surface); }
th.th-sortable.is-asc::after { content: " ▲"; color: var(--c-text-muted); font-size: 0.7rem; }
th.th-sortable.is-desc::after { content: " ▼"; color: var(--c-text-muted); font-size: 0.7rem; }
.row-hidden { display: none !important; }
.table-search { width: 14rem; }
@media (max-width: 640px) { .table-search { width: 100%; } }
.filter-row th { padding: 0.25rem 0.35rem; background: var(--c-bg); }
.filter-control {
width: 100%; min-width: 3.5rem; font-size: 0.72rem; line-height: 1.4;
padding: 0.1rem 0.25rem; border: 1px solid var(--c-border); border-radius: var(--radius-sm);
background: var(--c-surface); color: var(--c-text); font-family: inherit;
}
th.th-filterable { padding-bottom: 0.35rem; }
/* drag & drop материалов */
.drag-handle {
display: inline-block; flex: 0 0 auto; width: 1.5rem; text-align: center;
cursor: grab; user-select: none; color: var(--c-text-muted);
font-size: 1rem; line-height: 1; padding: 0.15rem 0; border-radius: var(--radius-sm);
}
.drag-handle:hover { background: var(--c-bg); color: var(--c-text); }
.btn btn-secondary btn-sm p-2.danger:hover { color: var(--c-accent); border-color: #dcb9be; background: var(--c-accent-soft); }
.drag-handle:active { cursor: grabbing; }
.dragging { opacity: 0.45; }
.drop-before { box-shadow: 0 -3px 0 0 var(--c-text); }
.drop-after { box-shadow: 0 3px 0 0 var(--c-text); }
.drop-into { outline: 2px dashed var(--c-border); outline-offset: 3px; border-radius: var(--radius-sm); }
/* индикатор сохранения порядка материалов */
.sort-status {
position: fixed; right: 1rem; bottom: 1rem; z-index: 40;
display: flex; align-items: center; gap: 0.6rem;
max-width: min(24rem, calc(100vw - 2rem));
background: var(--c-surface); border: 1px solid var(--c-border);
border-radius: var(--radius); padding: 0.5rem 0.75rem;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.15); font-size: 0.85rem;
}
/* Чтение материалов: контент + боковое содержание */
@media (min-width: 992px) {
/* на десктопе панель — обычный закреплённый блок, а не offcanvas */
.learn-side.offcanvas {
position: sticky; top: 4.5rem; max-height: calc(100vh - 5.5rem); overflow: auto;
transform: none !important; visibility: visible !important;
background: transparent; border: 0; width: auto;
}
.learn-side.offcanvas .offcanvas-header { display: none; }
.learn-side.offcanvas .offcanvas-body { padding: 0; overflow: visible; }
}
.learn-side { font-size: 0.875rem; }
.side-chapter { font-weight: 600; margin: 0.6rem 0 0.2rem; }
.side-section { margin: 0.25rem 0 0.5rem 0.75rem; }
.side-section > a { color: var(--c-text-muted); }
.side-articles { list-style: none; margin: 0.2rem 0 0 0.75rem; padding: 0; }
.side-articles li { margin: 0.1rem 0; }
.side-articles a { display: inline-block; }
.side-current { font-weight: 600; text-decoration: underline; }
.article-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: nowrap; }
.article-nav .ml-auto, .article-nav a:last-child:not(:only-child) { margin-left: auto; }
.article-nav .btn { min-width: 0; max-width: calc(50% - 0.4rem); overflow: hidden; white-space: nowrap; }
.article-nav .btn > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Панель форматирования markdown и встроенный редактор */
.md-toolbar {
display: flex; flex-wrap: wrap; align-items: center; gap: 0.1rem;
padding: 0.3rem; margin-bottom: 0.5rem;
border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-bg);
}
.md-sprite { display: none; }
.md-btn {
display: inline-flex; align-items: center; justify-content: center;
width: 2rem; height: 2rem; padding: 0; cursor: pointer;
border: 1px solid transparent; border-radius: var(--radius-sm);
background: transparent; color: var(--c-text);
}
.md-btn:hover { background: var(--c-surface); border-color: var(--c-border); }
.md-btn:active { transform: translateY(1px); }
.md-btn:focus-visible { outline: 2px solid var(--c-text-link); outline-offset: 1px; }
.md-ico { font-size: 1.15rem; line-height: 1; }
.md-sep { width: 1px; align-self: stretch; margin: 0.2rem 0.3rem; background: var(--c-border); }
.md-editor-head {
display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
padding: 0.75rem 1.25rem; border-bottom: 1px solid var(--c-border);
}
.md-editor-title { font-weight: 600; }
.md-editor-body {
width: 100%; min-height: 22rem; font-family: "DejaVu Sans Mono", Consolas, monospace;
font-size: 0.9rem; line-height: 1.5; white-space: pre; overflow-wrap: normal;
}
.md-figure { margin: 1rem 0; text-align: center; }
.md-figure img { width: 100%; max-width: 100%; height: auto; }
.md-figure figcaption, .md-video-figure figcaption {
margin-top: 0.4rem; font-size: 0.875rem; color: var(--c-text-muted);
}
.md-video-figure { margin: 1rem 0; text-align: center; }
.md-video { width: 100%; max-width: 100%; border-radius: var(--radius); background: #000; }
/* ---- Utilities: плоские классы поверх компонентов (в духе Bootstrap) ---- */
.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.m-0 { margin: 0; }
.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-4 { margin-top: 1rem; }
.mt-6 { margin-top: 1.5rem; }
.mt-8 { margin-top: 2rem; }
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: 0.25rem; }
.mb-2 { margin-bottom: 0.5rem; }
.mb-4 { margin-bottom: 1rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-8 { margin-bottom: 2rem; }
.ml-1 { margin-left: 0.25rem; }
.ml-2 { margin-left: 0.5rem; }
.ml-auto { margin-left: auto; }
.p-0 { padding: 0; }
.p-4 { padding: 1rem; }
.p-6 { padding: 1.5rem; }
.px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
.gap-4 { gap: 1rem; }
.w-full { width: 100%; }
.w-260 { width: 260px; }
.overflow-x-auto { overflow-x: auto; }
.text-sm { font-size: 0.875rem; }
.text-muted { color: var(--c-text-muted); }
.text-strong { font-weight: 600; color: var(--c-text); }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-break { overflow-wrap: anywhere; }
.font-mono { font-family: monospace; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.opacity-30 { opacity: 0.3; }
.offscreen { position: fixed; top: -1000px; left: 0; }
/* Материалы на мобильных: действия переносятся под заголовок */
@media (max-width: 720px) {
.sort-row, .sort-list > li { flex-wrap: wrap; row-gap: 0.35rem; }
.sort-row .sort-actions, .sort-list > li .sort-actions { margin-left: auto; flex-wrap: nowrap; justify-content: flex-end; }
.sort-row .sort-title, .sort-list > li .sort-title { flex: 1 1 auto; }
}