/* ============================================================
   Светлая минималистичная тема с синим акцентом. Mobile-first.
   ============================================================ */
:root {
    /* Notion-style: светлый, почти белый фон с едва заметным голубым оттенком */
    --bg: #f6f8fc;
    --surface: #ffffff;
    --surface-2: #eef2fa;
    --border: #e2e8f3;
    --text: #16202e;
    --muted: #66728a;
    /* Насыщенный, достаточно тёмный синий — читается как акцент, не
       вымывается на белом фоне; пастельным остаётся только фон-подложка (--accent-bg) */
    --accent: #3457d5;
    --accent-dark: #2643b0;

    --green-dark: #15803d;
    --green: #16a34a;
    --orange: #e0993c;
    --red: #dc2626;
    --gray: #6b7280;

    --green-bg: #e1f6e7;
    --red-bg: #fdeaea;
    --orange-bg: #fbf0dc;
    --gray-bg: #eef1f6;
    --green-dark-bg: #cdefd6;
    --accent-bg: #e6ecfd;

    /* Фиолетовый — только для статуса ДЗ «переделать». Нужен свой цвет:
       красный уже занят «не сдано», а переделка — это другое состояние
       (работу присылали и вернули), и в списке занятий их важно различать
       глазом, не вчитываясь в подпись. */
    --purple: #7c3aed;
    --purple-bg: #efe9fd;

    /* Шкала скруглений: мелкие элементы -> крупные поверхности */
    --radius-xs: 10px;
    --radius-sm: 14px;
    --radius: 20px;
    --radius-lg: 26px;

    /* Мягкие многослойные тени вместо жёстких границ */
    --shadow: 0 1px 2px rgba(22, 32, 46, 0.05), 0 8px 20px rgba(22, 32, 46, 0.06);
    --shadow-lift: 0 14px 34px rgba(22, 32, 46, 0.12);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* Плавный переход между светлой и тёмной темой — только цветовые свойства,
   не "всё подряд" (иначе даже нажатие кнопки .btn:active{transform:scale}
   начинало бы тормозить, унаследовав ту же долгую длительность). */
*, *::before, *::after {
    transition: background-color .25s ease, border-color .25s ease, color .25s ease, box-shadow .25s ease, fill .25s ease, stroke .25s ease;
}
/* Явный сброс на интерактивных элементах — некоторые мобильные браузеры
   (особенно старые версии Chrome/WebView на Android) игнорируют это
   свойство на *, если оно не продублировано прямо на самом элементе:
   иначе при тапе по <select> внутри ячейки таблицы подсвечивается синим
   вся строка целиком, а не сам элемент. */
a, button, summary, select, tr, td, .btn, .cal-slot, .today-row { -webkit-tap-highlight-color: transparent; }
html { -webkit-text-size-adjust: 100%; height: 100%; }

body {
    margin: 0;
    font-family: "Golos Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    font-size: 15.5px;
    min-height: 100%;
    display: flex;
    flex-direction: column;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { font-weight: 800; letter-spacing: -0.01em; color: var(--text); }

/* ===== Шапка =====
   Без backdrop-filter/blur: на слабых телефонах он подвешивает скролл —
   вместо "стеклянного" эффекта берём ровный непрозрачный фон + тень. */
.site-header {
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 1px 0 rgba(22,32,46,.02);
    position: sticky;
    top: 0;
    z-index: 20;
}
.header-inner {
    max-width: 1000px;
    margin: 0 auto;
    padding: 14px 18px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}
.header-right { display: flex; align-items: center; gap: 4px; }
.header-right .theme-toggle { margin-left: 10px; padding-left: 12px; border-left: 1px solid var(--border); }
.brand .logo { max-height: 52px; display: block; }
.brand-text { font-size: 21px; font-weight: 800; color: var(--text); letter-spacing: -0.02em; }

/* Пункты навигации — иконка + подпись, единый компонент .nav-link
   переиспользуется и в верхней строке (десктоп), и в нижнем таббаре (моб.) */
.main-nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.nav-icon { width: 19px; height: 19px; flex-shrink: 0; }
.nav-link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--muted);
    font-weight: 600;
    font-size: 14px;
    padding: 9px 13px;
    border-radius: var(--radius-sm);
    position: relative;
    list-style: none;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
}
.nav-link:hover, .main-nav a:hover { color: var(--accent-dark); background: var(--accent-bg); text-decoration: none; }
.nav-link[aria-current="page"], .nav-link.is-active { color: var(--accent-dark); background: var(--accent-bg); }
summary.nav-link::-webkit-details-marker { display: none; }
.nav-user { color: var(--text); font-size: 13.5px; font-weight: 700; padding: 9px 6px; }
.nav-dropdown-name { display: none; }
.nav-dropdown-theme { display: none; }
/* Включённый push — та же подсветка, что у активного пункта меню, чтобы
   было видно текущее состояние с первого взгляда, без чтения текста. */
.push-toggle-trigger.is-active { color: var(--accent-dark); }
.push-toggle-trigger.is-active .nav-icon { color: var(--accent); }
/* .nav-dropdown-theme (общий класс с переключателем темы) по умолчанию
   display:none — на десктопе тема переключается отдельной кнопкой в шапке,
   и без этого правила push тоже пропадал бы на десктопе, а отдельной
   кнопки для него там нет. !important — расположение самого правила
   .nav-dropdown-theme{display:none} ниже по файлу иначе перебивало бы это. */
button.push-toggle-trigger { display: flex !important; }
.nav-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--red);
    margin-left: 2px;
    vertical-align: top;
}

/* ===== Каркас приложения =====
   .app-scroll оборачивает шапку, контент и футер (открывается в
   includes/header.php, закрывается в includes/footer.php). В обычном
   браузере он ничего не меняет: такой же столбец, каким раньше был body.

   В установленном приложении (PWA, класс is-standalone на <html>) он
   становится единственным прокручиваемым элементом, а сам документ не
   прокручивается вовсе. Это и есть лечение «отклеивающейся» нижней панели
   на iPhone: панель fixed отсчитывается от окна, а iOS при прокрутке
   документа, «резинке» у края, открытии клавиатуры и возврате приложения
   из фона сдвигает окно относительно экрана — и панель уезжает вместе с
   ним. Когда документ неподвижен, сдвигать нечего: прокручивается только
   содержимое внутри, а окно и панель стоят на месте. Так устроено
   большинство мобильных веб-приложений.

   Только для PWA сознательно: в браузерной вкладке прокрутка документа
   нужна самому браузеру — чтобы прятать адресную строку. */
.app-scroll {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
    min-width: 0;
}
html.is-standalone,
html.is-standalone body {
    height: 100%;
    overflow: hidden;
}
html.is-standalone body { min-height: 0; }
html.is-standalone .app-scroll {
    flex: 1 1 auto;
    min-height: 0;
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    /* «Резинка» остаётся у самого списка и не передаётся окну */
    overscroll-behavior-y: contain;
    -webkit-overflow-scrolling: touch;
}

/* ===== Основной контейнер ===== */
.site-main {
    max-width: 960px;
    width: 100%;
    margin: 0 auto;
    padding: 18px 14px 70px;
    flex: 1 0 auto;
    box-sizing: border-box;
}
/* Немного воздуха перед футером на телефоне — саму защиту от нижнего
   таббара обеспечивает padding-bottom футера (см. ниже), не дублируем тут. */
/* Помимо ширины — ещё и по высоте: телефон в альбомной ориентации обычно
   шире 760px, но остаётся именно телефоном (мало места по высоте), а не
   планшетом/десктопом. Без второго условия при повороте телефона нижний
   таббар и весь мобильный вид пропадали, включалась десктопная раскладка,
   для которой на телефоне физически нет места — кнопки/пункты меню
   наезжали друг на друга или обрезались.
   (hover: none) and (pointer: coarse) — обязательно вместе с высотой:
   иначе это же условие ложно срабатывало и на компьютере, если окно
   браузера просто невысокое (не на весь экран) — тогда мобильная
   раскладка меню включалась поверх мышиного интерфейса и всё разъезжалось
   («то густо, то пусто» в отступах). hover/pointer отличают сенсорные
   устройства (телефон, где и нужна альбомная раскладка) от компьютера с
   мышью — на компьютере это условие теперь не срабатывает никогда. */
@media (max-width: 760px), ((max-height: 480px) and (hover: none) and (pointer: coarse)) {
    .site-main { padding-bottom: 26px; }
}

.site-footer {
    text-align: center;
    color: var(--muted);
    font-size: 12px;
    padding: 20px 0 40px;
}

/* ===== Заголовки страниц ===== */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 18px;
}
.page-head h1 { margin: 0; font-size: 21px; }
.head-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.muted { color: var(--muted); font-weight: 400; font-size: 14px; }
.back-link { font-size: 13px; color: var(--muted); }
.back-link:hover { color: var(--accent); }

/* ===== Карточки форм ===== */
.form-card, .auth-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px;
    max-width: 520px;
    box-shadow: var(--shadow);
}
.auth-box { margin: 8vh auto 40px; }
.auth-box h1 { margin-top: 0; font-size: 19px; }
.auth-hint { color: var(--muted); font-size: 13px; margin-top: 14px; text-align: center; }

form label {
    display: block;
    margin-bottom: 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
}
form input[type=text],
form input[type=password],
form input[type=date],
form input[type=time],
form input[type=number],
form input[type=url],
form input[type=file],
form select,
form textarea {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 11px 12px;
    border: 1px solid var(--border);
    border-radius: 12px;
    font-size: 15px;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
    -webkit-appearance: none;
}
form input:focus, form select:focus, form textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-bg);
}
form textarea { resize: vertical; }
/* Чекбоксы/радио без явного размера рендерятся браузером "нативно" — а
   нативный размер на некоторых мобильных WebView зависит от font-size
   ОКРУЖАЮЩЕГО контекста (у него это относительные em-единицы), из-за чего
   один и тот же с виду чекбокс на одной странице оказывался то крупнее, то
   мельче в зависимости от того, где именно на странице он стоит. Фиксируем
   размер явно и одинаково везде — глобально, а не только внутри форм. */
input[type="checkbox"],
input[type="radio"] {
    width: 17px;
    height: 17px;
    min-width: 17px;
    flex-shrink: 0;
    margin: 0;
    cursor: pointer;
}
.checkbox-label { display: flex; align-items: center; gap: 8px; font-weight: 500; color: var(--text); cursor: pointer; }
.checkbox-label input { width: 17px; height: 17px; margin: 0; cursor: pointer; }
.field-hint { display: block; color: var(--muted); font-size: 12px; font-weight: 400; margin-top: 4px; }

.btn {
    display: inline-block;
    padding: 12px 20px;
    border-radius: var(--radius-sm);
    border: none;
    font-size: 14.5px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    text-align: center;
    white-space: nowrap;
    transition: background .12s ease, border-color .12s ease, color .12s ease, transform .08s ease, box-shadow .12s ease;
}
.btn:active { transform: scale(.98); }
.btn-primary { background: var(--accent); color: #ffffff; box-shadow: 0 1px 2px rgba(22,32,46,.08); }
.btn-primary:hover { background: var(--accent-dark); text-decoration: none; color: #fff; box-shadow: 0 4px 14px rgba(52,87,213,.28); }
.btn-ghost { background: var(--surface); color: var(--text); border: 1px solid var(--border); }
.btn-ghost:hover { text-decoration: none; border-color: var(--accent); color: var(--accent-dark); background: var(--accent-bg); }
.btn-block { display: block; width: 100%; white-space: normal; }
/* Красная кнопка — только для действий, которые что-то отменяют или
   возвращают назад. Раньше такие действия оформлялись ссылкой, и рядом с
   синей кнопкой «сохранить» было непонятно, что из этого кнопка. */
.btn-danger { background: var(--red-bg); color: var(--red); border: 1px solid transparent; }
.btn-danger:hover { background: var(--red); color: #fff; text-decoration: none; }
.btn-sm { padding: 7px 12px; font-size: 12.5px; border-radius: var(--radius-xs); }

/* ===== Панель поиска/фильтров ===== */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px;
    box-shadow: var(--shadow);
}
.toolbar input[type=text], .toolbar select {
    display: inline-block;
    width: auto;
    margin-top: 0;
    padding: 9px 10px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 14px;
}
.toolbar form { display: flex; gap: 8px; flex-wrap: wrap; flex: 1; align-items: center; }
.toolbar input[type=text] { flex: 1 1 220px; min-width: 160px; }

/* ===== Общая статистика ===== */
.stats-row { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.text-red { color: var(--red); }
.text-green { color: var(--green); }
.text-orange { color: var(--orange); }
.text-accent { color: var(--accent); }

/* ===== Список учеников (карточки) ===== */
.student-list { display: flex; flex-direction: column; gap: 10px; }
.student-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow);
    transition: box-shadow .15s ease, border-color .15s ease;
}
@media (hover: hover) and (pointer: fine) {
    .student-card:hover { border-color: #d7e0f7; box-shadow: var(--shadow-lift); }
}
.student-name a { color: var(--text); }
.student-name a:hover { color: var(--accent-dark); }
.student-card-top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
}
.student-name { font-size: 16px; font-weight: 700; }
.student-login { color: var(--muted); font-size: 13px; }
.student-meta {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 8px;
    font-size: 12.5px;
    color: var(--muted);
}
.student-actions {
    margin-top: 10px;
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    font-size: 13.5px;
    font-weight: 600;
}
.danger-link { color: var(--red); }
.next-lesson-form { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.next-lesson-form input[type=date] {
    width: auto;
    margin: 0;
    padding: 6px 8px;
    font-size: 13px;
}
.due-today { color: var(--orange); font-weight: 700; }
.overdue { color: var(--red); font-weight: 700; }

/* ===== Таблица ===== */
.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td { padding: 10px 12px; text-align: left; font-size: 14px; }

/* ===== Бейджи ===== */
.badge {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 20px;
    font-size: 11.5px;
    font-weight: 700;
    white-space: nowrap;
}
.badge-green { background: var(--green-bg); color: var(--green); }
.badge-red { background: var(--red-bg); color: var(--red); }
.badge-gray { background: var(--gray-bg); color: var(--muted); }
.badge-purple { background: var(--purple-bg); color: var(--purple); }
.badge-grade-5 { background: var(--green-dark-bg); color: var(--green-dark); }
.badge-grade-4 { background: var(--green-bg); color: var(--green); }
.badge-grade-3 { background: var(--orange-bg); color: var(--orange); }
.badge-grade-2 { background: var(--red-bg); color: var(--red); }
.badge-grade-n { background: var(--gray-bg); color: var(--gray); }
.badge-grade-none { background: var(--gray-bg); color: var(--muted); }

/* ===== Карточки занятий ===== */
.lesson-list { display: flex; flex-direction: column; gap: 12px; }
.lesson-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow);
    transition: box-shadow .15s ease, border-color .15s ease;
}
.lesson-card:hover { border-color: #d7e0f7; box-shadow: var(--shadow-lift); }
.lesson-card-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 8px;
    font-size: 14.5px;
}
.lesson-date { font-weight: 700; }
.lesson-card p { margin: 6px 0; font-size: 13.5px; color: var(--text); }
.lesson-card p b { color: var(--muted); font-weight: 600; }
.lesson-card-actions { margin-top: 10px; display: flex; gap: 14px; flex-wrap: wrap; font-size: 13px; font-weight: 600; }

.hw-quick-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.hw-quick-actions form { display: inline; }

.lesson-images { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.thumb {
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: 10px;
    border: 1px solid var(--border);
}
.thumb-wrap { text-align: center; font-size: 11px; }

/* Маленькие миниатюры прямо в строке занятия (список у ученика/в карточке
   ученика у админа) — раньше там был только текст "N фото" без единой
   ссылки, теперь можно реально посмотреть вложение в один клик. */
.lesson-thumbs { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 6px; }
.lesson-thumbs img {
    width: 34px;
    height: 34px;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid var(--border);
    display: block;
}
.logo-preview { max-height: 60px; }

/* ===== Прочее ===== */
.section-title { font-size: 15px; margin: 26px 0 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.moodle-btn { display: inline-block; margin-top: 6px; }
.notes-box {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 10px 12px;
    font-size: 13.5px;
    margin-bottom: 14px;
}

.alert {
    padding: 10px 14px;
    border-radius: 12px;
    font-size: 13.5px;
    margin-bottom: 14px;
}
.alert-error { background: var(--red-bg); color: var(--red); }
.alert-success { background: var(--green-bg); color: var(--green); }
.alert-warning { background: var(--orange-bg); color: var(--orange); }

/* Спокойная "инсайт"-плашка (например "падает рейтинг" на дашборде) —
   в отличие от .alert-warning (реальные проблемы — не запустился крон,
   сломалась интеграция), это просто наблюдение, не авария. Лёгкий жёлтый
   тон — чтобы не сливалась с обычными карточками и было видно, что это
   отдельная заметка, — но без яркого оранжевого текста/рамки, как у
   настоящего предупреждения: только мягкий фон, обычный цвет текста.
   Крестиком можно скрыть до следующего изменения списка (см. JS,
   admin/dashboard.php). */
.insight-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 34px 12px 14px;
    border-radius: 12px;
    background: var(--orange-bg);
    border: 1px solid transparent;
    font-size: 13.5px;
    margin-bottom: 14px;
    color: var(--text);
}
.insight-card b { font-weight: 600; color: var(--muted); font-size: 12.5px; text-transform: uppercase; letter-spacing: .02em; }
/* Список внутри — обычная строка текста со ссылками, НЕ крупные жирные
   .stat-chip (те рассчитаны на цифры в шапке страницы: белая плашка +
   огромное жирное число смотрелась аляповато на цветном фоне заметки). */
.insight-card-list { font-size: 13px; line-height: 1.7; color: var(--muted); }
.insight-card-list a { color: var(--text); font-weight: 600; text-decoration: underline; text-decoration-color: rgba(120, 95, 40, .3); text-underline-offset: 2px; }
.insight-card-list a:hover { text-decoration-color: currentColor; }
[data-theme="dark"] .insight-card-list a { text-decoration-color: rgba(242, 181, 99, .35); }
.insight-dismiss {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: none;
    color: var(--muted);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    border-radius: 6px;
}
.insight-dismiss:hover { background: var(--surface-2); color: var(--text); }

.empty-state { color: var(--muted); font-style: italic; }

/* ===== Десктоп ===== */
@media (min-width: 720px) {
    body { font-size: 15.5px; }
    .site-main { padding: 30px 20px 80px; }
    .page-head h1 { font-size: 25px; }
    .form-card { padding: 24px; }
}

/* ===== v3: аватары, прогресс-бары, блок Moodle ===== */
:root {
    --orange-bg2: #ece9fb;
}
.badge-orange { background: var(--orange-bg); color: var(--orange); }

.avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--accent-bg);
    color: var(--accent-dark);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    font-size: 15px;
    flex-shrink: 0;
}
.avatar-sm { width: 34px; height: 34px; font-size: 13px; }

.progress-bar {
    background: var(--gray-bg);
    border-radius: 20px;
    height: 6px;
    overflow: hidden;
    margin-top: 6px;
}
.progress-bar-fill {
    background: var(--accent);
    height: 100%;
    border-radius: 20px;
}

.plan-picker-box {
    background: var(--gray-bg);
    border-radius: 12px;
    padding: 10px 12px;
    margin-bottom: 14px;
}
.plan-picker-box .checkbox-label { align-items: flex-start; }
.plan-picker-box .checkbox-label input { margin-top: 3px; }
.plan-picker-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13.5px;
}
.plan-picker-summary > span { min-width: 0; overflow-wrap: anywhere; }
.plan-picker-summary .btn { flex-shrink: 0; }
.plan-picker-icon {
    width: 14px;
    height: 14px;
    vertical-align: -2px;
    color: var(--muted);
    margin-right: 1px;
}

/* Группа чекбоксов "уровни/теги" (admin/library.php) — компактные пары
   чекбокс+бейдж в ряд, а не одна метка под другой на всю ширину, как у
   обычных form label. */
.level-checks { display: flex; flex-wrap: wrap; gap: 8px 14px; margin: 6px 0 4px; }
.level-check { margin-bottom: 0 !important; font-weight: 400 !important; }

/* ===== Перетаскиваемые списки (учебный план ученика, темы уровня в
   Библиотеке тем) — обычные строки simple-table/data-table, без отдельных
   "плашек" на каждую тему; порядок меняется мышкой, а не кнопками
   ↑/↓ с перезагрузкой страницы (см. ajax_reorder.php + JS внизу
   admin/student_plan.php и admin/library.php). */
.drag-handle {
    width: 28px;
    text-align: center;
    color: var(--muted);
    cursor: grab;
    -webkit-user-select: none;
    user-select: none;
}
.drag-handle:active { cursor: grabbing; }
.reorder-row.is-dragging { opacity: .35; }
.reorder-row td { cursor: default; }
.plan-edit-row td { padding-top: 0 !important; border-top: none !important; }
.plan-edit-row input[type=text] { margin: 0 !important; }
/* Кнопка массовой отметки "пройдено" — видна только в режиме выбора (когда
   видны и сами чекбоксы, см. .cell-check / body.select-mode выше по файлу),
   иначе просто бесполезно висела бы на странице без единого чекбокса. */
.plan-bulk-btn { display: none; }
body.select-mode .plan-bulk-btn { display: inline-block; }

.moodle-block {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 16px;
    margin-bottom: 16px;
    box-shadow: var(--shadow);
}
.moodle-block-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
}
.moodle-summary {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
    margin-top: 10px;
}
.moodle-summary > div { min-width: 140px; }

.code-box {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 10px 12px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12.5px;
    word-break: break-all;
    margin: 8px 0;
}

/* ===== v4: пробники, простая таблица, аккуратные бейджи ===== */
.badge-blue-outline { background: var(--accent-bg); color: var(--accent-dark); }

.simple-table {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow);
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}
.simple-table th {
    background: var(--surface-2);
    color: var(--muted);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .03em;
    padding: 10px 14px;
    text-align: left;
}
.simple-table td {
    padding: 10px 14px;
    border-top: 1px solid var(--border);
    font-size: 13.5px;
    vertical-align: middle;
    text-align: center;
}
.simple-table tr:first-child td { border-top: none; }
.simple-table tbody tr { transition: background .1s ease; }
/* Наведение — только у преподавателя на компьютере: строки этих таблиц не
   кликабельны целиком (только отдельные контролы внутри), а на телефоне
   :hover эмулируется тапом и "залипает" — поэтому эффект только там, где
   он честно означает "мышь навелась", и только в админке. */
@media (hover: hover) and (pointer: fine) {
    body.role-admin .simple-table tbody tr:hover td { background: var(--surface-2); }
}

.goal-box {
    background: linear-gradient(135deg, var(--accent-bg), var(--surface));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 16px;
    margin-bottom: 16px;
}
.goal-box .goal-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--accent-dark);
    font-weight: 700;
}
.goal-box p {
    margin: 6px 0 0;
    font-size: 14px;
    color: var(--text);
}

/* ===== Таблица занятий: закруглённые строки-карточки, всё по центру ===== */
.lessons-table {
    border-collapse: separate;
    border-spacing: 0 8px;
    /* На телефоне долгий тап по ячейке иначе выделяет текст вместо простого
       нажатия на контрол (селект статуса, меню действий) — визуально
       выглядит как "залипание" синим выделением. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}
.lessons-table thead th {
    border: none;
    background: transparent;
    color: var(--muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    font-weight: 700;
    padding: 0 14px 6px;
}
.lessons-table tbody tr {
    background: var(--surface);
    box-shadow: var(--shadow);
    transition: box-shadow .12s ease;
}
@media (hover: hover) and (pointer: fine) {
    body.role-admin .lessons-table tbody tr:hover { box-shadow: var(--shadow-lift); }
}
.lessons-table tbody td {
    border-top: none;
    padding: 12px 14px;
    text-align: center;
    vertical-align: middle;
    font-size: 13.5px;
}
.lessons-table tbody td:first-child { border-radius: 14px 0 0 14px; }
.lessons-table tbody td:last-child { border-radius: 0 14px 14px 0; }
.lessons-table .topic-cell { max-width: 320px; text-align: left; }
.lessons-table .topic-cell .topic-line { text-align: left; }
.lessons-table .hw-text { text-align: left; }

/* Селекты быстрого редактирования — компактные закруглённые "таблетки" с цветом статуса */
.lessons-table .hw-select {
    padding: 5px 10px;
    font-size: 11.5px;
    font-weight: 600;
    border-radius: 20px;
    border: 1px solid transparent;
    background: var(--gray-bg);
    color: var(--muted);
    text-align: center;
    text-align-last: center;
    cursor: pointer;
    transition: filter .1s ease;
    /* Убирает жест "зум по двойному тапу" именно на этом элементе — не
       трогая пинч-зум остальной страницы (в отличие от maximum-scale в
       viewport, который выключил бы зум вообще везде). Раньше здесь
       поднимали font-size до 16px, думая, что дело в зуме при фокусе на
       select, — но ДЗ и Оценка используют тот же класс с тем же
       11.5px и не зумились никогда, только Оплата. Разница у Оплаты одна:
       под селектом сразу стоит цена (.payment-cell), то есть на телефоне
       там ДВА тесно расположенных элемента — и быстрый повторный тап рядом
       (промахнулся по селекту, задел цену, тапнул снова) Safari принимает
       за двойной тап и зумит весь блок. touch-action тут прицельно решает
       именно эту причину, без раздувания шрифта на компактной "таблетке". */
    touch-action: manipulation;
}
.lessons-table .hw-select:hover { filter: brightness(0.97); }
.lessons-table .hw-select:focus { outline: none; box-shadow: 0 0 0 3px var(--accent-bg); }
.hw-state-done .hw-select, .hw-state-paid .hw-select { background: var(--green-bg); color: var(--green); }
.hw-state-not_done .hw-select, .hw-state-unpaid .hw-select { background: var(--red-bg); color: var(--red); }
.hw-state-pending .hw-select { background: var(--gray-bg); color: var(--muted); }
/* Просрочено — тот же зелёный, что и «выполнено»: работа сдана и принята.
   Переделать — долг другого рода, чем «не сдано» (фиолетовый).
   См. homework_class() в functions.php. */
.hw-state-late .hw-select { background: var(--green-bg); color: var(--green); }
.hw-state-redo .hw-select { background: var(--purple-bg); color: var(--purple); }
.hw-state-grade-5 .hw-select { background: var(--green-dark-bg); color: var(--green-dark); }
.hw-state-grade-4 .hw-select { background: var(--green-bg); color: var(--green); }
.hw-state-grade-3 .hw-select { background: var(--orange-bg); color: var(--orange); }
.hw-state-grade-2 .hw-select { background: var(--red-bg); color: var(--red); }
.hw-state-grade-n .hw-select, .hw-state-grade-none .hw-select { background: var(--gray-bg); color: var(--gray); }

.tab-nav { display: flex; gap: 6px; margin-bottom: 18px; flex-wrap: wrap; }
.tab-nav a {
    padding: 9px 15px;
    border-radius: var(--radius-sm);
    font-size: 13.5px;
    font-weight: 600;
    color: var(--muted);
    background: var(--surface);
    border: 1px solid var(--border);
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.tab-nav a:hover { color: var(--accent-dark); background: var(--accent-bg); border-color: var(--accent-bg); text-decoration: none; }
.tab-nav a.active { color: var(--accent-dark); background: var(--accent-bg); border-color: var(--accent-bg); font-weight: 700; }

/* ===== v5: донат-диаграмма, компактные плашки, подсветка строк, архив ===== */
.profile-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 16px;
}
.profile-identity { display: flex; align-items: center; gap: 14px; }
.profile-identity h1 { margin: 0 0 2px; font-size: 20px; }
.profile-sub { color: var(--muted); font-size: 13px; }
.profile-goal { color: var(--accent-dark); font-size: 13px; font-weight: 600; margin-top: 2px; }

.info-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 18px;
}
.info-pill {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 20px;
    padding: 7px 14px;
    font-size: 12.5px;
    box-shadow: var(--shadow);
}
.info-pill .pill-label { color: var(--muted); }
.info-pill .pill-value { font-weight: 700; color: var(--text); }
.info-pill.pill-warn .pill-value { color: var(--red); }
.info-pill.pill-ok .pill-value { color: var(--green); }
.info-pill.pill-today .pill-value { color: var(--orange); }


.archive-toggle {
    margin-top: 10px;
    font-size: 13px;
}
.archive-toggle summary {
    cursor: pointer;
    color: var(--muted);
    font-weight: 600;
    padding: 8px 2px;
}
.archive-toggle summary:hover { color: var(--accent); }

.photo-upload-form { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.photo-upload-form input[type=file] { font-size: 12px; }

/* Пунктов со временем стало больше, чем помещается в ширину телефона —
   без overflow-x они просто переносились/вылезали за пределы контейнера,
   и это "разъезжание" тянуло за собой горизонтальную прокрутку у ВСЕЙ
   страницы (не только у самого меню), отсюда ощущение "шатающегося" экрана
   и полоски для скролла вправо-влево внизу. Теперь лишнее уезжает вбок
   только внутри самого меню, скроллится пальцем, страница остаётся на месте. */
.secondary-nav {
    display: flex;
    gap: 16px;
    margin: 26px 0 4px;
    font-size: 13.5px;
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    padding-bottom: 4px;
    padding-right: 12px; /* последний пункт не впритык к краю экрана при скролле */
}
.secondary-nav a { color: var(--muted); font-weight: 600; flex-shrink: 0; }
.secondary-nav a:hover { color: var(--accent); }
/* Переключатель между двумя видами одной страницы (например report.php /
   student_summary.php — "Для родителей" и "Для ученика, в баллах") —
   не список ссылок на разные разделы (для этого есть .secondary-nav), а
   именно состояние "где я сейчас": закруглённый сегмент-переключатель в
   стиле iOS/Notion, активная вкладка — на белой (тёмной в тёмной теме)
   подложке с лёгкой тенью, вторая — просто ссылка тем же размером рядом. */
.view-tabs {
    /* display:flex (не inline-flex) + width:max-content — блок на своей
       строке (inline-flex вёл себя как строчный элемент и на широком
       экране вставал В ОДНУ строку со следующим элементом формы,
       "уезжая" вправо — на телефоне из-за нехватки места это визуально
       пряталось само собой, поэтому баг был виден только на компьютере),
       но при этом не растягивается на всю ширину контейнера. */
    display: flex;
    width: max-content;
    gap: 3px;
    padding: 4px;
    background: var(--surface-2);
    border-radius: 999px;
    margin: 0 0 16px;
}
.view-tabs a, .view-tabs .tab-active {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
    text-decoration: none;
    white-space: nowrap;
}
.view-tabs a:hover { color: var(--text); text-decoration: none; }
/* Вкладка, которая ждёт действия («На проверку (3)») — заметна, но не
   кричит: это напоминание, а не ошибка */
.view-tabs a.tab-attention, .tab-nav a.tab-attention { color: var(--orange); font-weight: 700; }
.view-tabs .tab-active {
    background: var(--surface);
    color: var(--accent-dark);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .1);
}
@media (max-width: 760px) {
    /* width:max-content (см. выше) на телефоне делал контейнер ШИРЕ экрана,
       когда вкладок много (пять на «Проверка работ и статистика»), а
       white-space:nowrap не давал тексту ужаться. Из-за этого горизонтальную
       прокрутку получала ВСЯ страница — она «ездила» вправо-влево, и всё
       остальное вместе с ней. Теперь лишнее прокручивается внутри самих
       вкладок, а страница стоит на месте (тот же приём, что и .secondary-nav).
       flex:1 0 auto — когда вкладок мало (две в кабинете ученика), они
       по-прежнему растягиваются на всю ширину, но ужиматься до нечитаемого
       уже не могут. */
    .view-tabs {
        width: auto;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .view-tabs::-webkit-scrollbar { display: none; }
    .view-tabs a, .view-tabs .tab-active { flex: 1 0 auto; justify-content: center; }
}

/* ===== v6: фоновая текстура, мобильная таблица, ДЗ-акцент, аватар по клику ===== */

/* Едва заметный фоновый узор, медленно смещается */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image: url("../img/bg-pattern.svg");
    background-repeat: repeat;
    background-size: 260px 260px;
    opacity: 0.05;
    animation: bg-drift 90s linear infinite;
    pointer-events: none;
}
@keyframes bg-drift {
    0%   { background-position: 0 0; }
    100% { background-position: 520px 260px; }
}

/* Заголовки таблиц по центру */
.simple-table th, .data-table th { text-align: center; }

/* Тема занятия крупнее и жирнее, ДЗ — мельче и обычным текстом под ней */
.topic-line { font-weight: 700; color: var(--text); font-size: 14px; }
@media (max-width: 700px) {
    .topic-line { font-size: 13.5px; line-height: 1.3; }
    .hw-text { font-size: 12.5px; margin-top: 3px; }
    .lessons-table td.topic-cell { padding: 4px 0 6px; }
    .lessons-table .badge { font-size: 11px; padding: 2px 8px; }
}
.hw-text { font-size: 12px; color: var(--muted); margin-top: 4px; line-height: 1.4; }
.hw-text b { color: var(--text); font-weight: 600; }

/* Раскрытие длинного текста (ДЗ, заметки) — ограничение по высоте (в
   строках), а не по числу символов: одинаково аккуратно смотрится в узкой
   ячейке таблицы и в широком блоке заметок, не обрезает слова посередине. */
.expand-wrap .expand-body {
    max-height: 4.3em; /* около 3 строк при line-height 1.4 */
    overflow: hidden;
}
.expand-wrap.expand-open .expand-body { max-height: none; }
.expand-btn {
    display: block;
    margin-top: 4px;
    padding: 0;
    background: none;
    border: none;
    font: inherit;
    font-size: 11px;
    font-weight: 700;
    color: var(--accent);
    cursor: pointer;
    /* Иначе на телефоне при нажатии весь текст на миг заливало синей
       подсветкой браузера по умолчанию — выглядело как визуальный глюк */
    -webkit-tap-highlight-color: transparent;
}
.expand-btn:hover { text-decoration: underline; }
/* Текст физически не обрезан (уместился в отведённые 3 строки, часто
   бывает на широком экране или при коротковатом тексте чуть за порогом
   в 110 символов) — тогда кнопка "Развернуть" не нужна и только сбивает
   с толку: клик по ней ничего не меняет, ведь скрывать нечего. Прячем её
   через JS после отрисовки (см. header.php) сравнением scrollHeight. */
.expand-wrap.no-clip .expand-btn { display: none; }

/* Аватар/фото — клик открывает выбор файла */
.avatar-edit {
    position: relative;
    display: inline-block;
    cursor: pointer;
    border-radius: 50%;
}
.avatar-edit input[type=file] {
    position: absolute;
    inset: 0;
    opacity: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
}
.avatar-edit-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.55);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    border-radius: 50%;
    opacity: 0;
    transition: opacity .15s ease;
    text-align: center;
    pointer-events: none;
}
.avatar-edit:hover .avatar-edit-overlay { opacity: 1; }
.avatar-photo {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    border: 1px solid var(--border);
    flex-shrink: 0;
}
.avatar-photo-sm { width: 34px; height: 34px; }

/* Курсы Moodle — несколько строк на профиле */
.moodle-course-row { padding: 10px 0; border-top: 1px solid var(--border); }
.moodle-course-row:first-of-type { border-top: none; }
.moodle-course-label { font-weight: 700; font-size: 13px; color: var(--text); margin-bottom: 4px; }

/* Контейнер таблицы — на мобильном превращается в карточки */
.table-scroll { width: 100%; }

/* ===== Форма проверки работы =====
   Балл, файл и отзыв — разными строками с подписями, а не одной тесной
   лентой полей: в ленте было неясно, что куда вводить, а на телефоне она
   разъезжалась. */
.grade-form {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.grade-form label { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.grade-form input[type=text],
.grade-form textarea {
    display: block;
    width: 100%;
    margin-top: 4px;
    padding: 9px 11px;
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
}
.grade-form textarea { resize: vertical; min-height: 62px; line-height: 1.45; }
.grade-form input[type=file] { display: block; width: 100%; margin-top: 6px; font-size: 12px; max-width: 100%; }
.grade-form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.grade-form-score { flex: 0 0 150px; }
.grade-form-file { flex: 1 1 220px; min-width: 0; }
.grade-form-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.grade-form-danger { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; }

@media (max-width: 700px) {
    .grade-form-score, .grade-form-file { flex: 1 1 100%; }
    .grade-form-actions .btn, .grade-form-danger .btn { width: 100%; }
}

/* ===== Список оценок (кабинет ученика) =====
   Намеренно НЕ таблица: у таблицы на телефоне либо разъезжаются колонки,
   либо каждая строка превращается в отдельную карточку с рамкой — а тут
   строк много и они короткие. Здесь простой список «название слева, балл
   справа», который одинаково читается на любой ширине.

   Уровни, и у каждого своё оформление — раньше все они были одним и тем
   же белым цветом и сливались в одну простыню:
     0) .grade-hero    — ОБЩИЙ итог, залитая фирменным цветом полоса сверху;
     1) .grade-section — ОДНА группа (раздел Moodle / один месяц) — обычная
                         карточка, но с тонированной шапкой — видно, где
                         начинается и кончается группа;
     2) .grade-row      — ОТДЕЛЬНАЯ оценка внутри группы — без своего фона,
                         просто строка списка, самый тихий уровень. */
.grade-hero {
    display: flex;
    align-items: center;
    gap: 8px 16px;
    flex-wrap: wrap;
    background: var(--accent-bg);
    border: 1px solid var(--accent);
    border-radius: var(--radius-xs);
    padding: 10px 16px;
    margin-bottom: 14px;
}
.grade-hero-main { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
.grade-hero-label {
    font-size: 10.5px;
    font-weight: 800;
    color: var(--accent-dark);
    text-transform: uppercase;
    letter-spacing: .04em;
    opacity: .85;
    white-space: nowrap;
}
.grade-hero-value {
    font-size: 16px;
    font-weight: 800;
    color: var(--accent-dark);
    letter-spacing: -0.01em;
    line-height: 1.2;
    overflow-wrap: anywhere;
}
.grade-hero-side { display: flex; gap: 16px; flex-wrap: wrap; margin-left: auto; }
.grade-hero-stat { display: flex; align-items: baseline; gap: 5px; white-space: nowrap; }
.grade-hero-stat b { font-size: 14px; font-weight: 800; color: var(--accent-dark); }

.grade-section {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    margin-bottom: 12px;
    overflow: hidden;
}
.grade-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 14px;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
}
.grade-section-name { font-size: 14.5px; font-weight: 700; color: var(--text); }
.grade-section-marks { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; justify-content: flex-end; }

/* Подытог РАЗДЕЛА — сознательно другой стиль, чем у заливной плашки
   оценки за отдельное задание ниже: одинаковый процент (например "10 из
   10" у раздела и у единственного задания внутри) давал два одинаковых
   зелёных пятна подряд, было непонятно, где итог, а где просто первое
   задание списка. Здесь — контурная плашка (цветная рамка, без заливки):
   тот же цвет говорит "какой уровень оценки", а другая ФОРМА читается
   как "это итог", а не повтор. Точку-маркер перед числом убрали — она
   выглядела лишним значком, а не частью числа. Размер и отступы — те же,
   что у вторичного балла рядом, чтобы они смотрелись парой, а не "один
   большой жирный, другой едва заметный". */
.grade-tone {
    display: inline-flex;
    align-items: center;
    font-weight: 700;
    font-size: 12.5px;
    letter-spacing: -.005em;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1.5px solid currentColor;
    background: none;
    white-space: nowrap;
}
.grade-tone.badge-grade-5 { color: var(--green-dark); }
.grade-tone.badge-grade-4 { color: var(--green); }
.grade-tone.badge-grade-3 { color: var(--orange); }
.grade-tone.badge-grade-2 { color: var(--red); }
.grade-tone.badge-grade-n,
.grade-tone.badge-grade-none,
.grade-tone.badge-blue-outline { color: var(--muted); }
/* Вторичный балл рядом с подытогом — та же плашка, но ЗАЛИТАЯ фирменным
   цветом, а не контурная: разница видна сразу (контур/заливка), а
   размер — специально один в один с .grade-tone, чтобы не получалось
   "один огромный, другой крошечный" */
.grade-secondary-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: -.005em;
    color: var(--accent-dark);
    background: var(--accent-bg);
    padding: 3px 10px;
    border-radius: 999px;
    white-space: nowrap;
}
.grade-secondary-chip .ui-icon { width: .9em; height: .9em; }

.grade-list { display: flex; flex-direction: column; padding: 0 14px; }
.grade-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
}
.grade-row:last-child { border-bottom: none; }
.grade-row-main { min-width: 0; flex: 1 1 auto; }
.grade-row-title { font-size: 13.5px; color: var(--text); overflow-wrap: anywhere; }
.grade-row-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.grade-row .badge { flex-shrink: 0; }

/* Список без карточки-группы вокруг (не используется сейчас — оценки за
   занятия тоже сгруппированы по месяцам через .grade-section, — но
   оставлен для одиночного списка без заголовка). */
.grade-list-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    padding: 2px 14px;
}

@media (max-width: 700px) {
    .grade-hero { padding: 9px 14px; }
    .grade-hero-side { width: 100%; margin-left: 0; justify-content: space-between; }
    /* Оценки специально ОСТАЮТСЯ справа и на телефоне (не переносятся под
       название) — так же, как на компьютере: это работало нормально, а
       перенос вниз только портил вид. Название и так само перетечёт на
       вторую строку, если не помещается — переносить нужно было не его. */
    .grade-section-head { padding: 10px 12px; gap: 6px 10px; }
    .grade-section-name { font-size: 14px; }
    .grade-list { padding: 0 12px; }
    .grade-row { padding: 9px 0; }
    .grade-row-title { font-size: 13px; }
}

/* ===== Разбор теста по вопросам (admin/moodle_work.php) =====
   Вопрос — карточкой на всю ширину, а не в узкой ячейке таблицы: у
   вопросов по русскому языку сам текст часто держится на форматировании
   (таблица, несколько абзацев, выделения жирным/курсивом), а втиснутое в
   колонку сравнения оно превращалось в нечитаемую кашу. Формат внутри —
   тот же безопасно пересобранный HTML, что и в Moodle (см.
   moodle_extract_question_html()), поэтому стили ниже — на голые теги
   (p/table/ul), а не на классы: разметка приходит без классов. */
.quiz-review-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.quiz-review-item {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
}
.quiz-review-label { font-size: 12px; font-weight: 800; color: var(--muted); margin-bottom: 6px; }
.quiz-review-question {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--text);
}
.quiz-review-question p { margin: 0 0 8px; }
.quiz-review-question p:last-child { margin-bottom: 0; }
.quiz-review-question ul, .quiz-review-question ol { margin: 0 0 8px; padding-left: 20px; }
.quiz-review-question table {
    border-collapse: collapse;
    margin: 6px 0 8px;
    max-width: 100%;
    display: block;
    overflow-x: auto; /* таблица из вопроса шире экрана — прокручивается внутри себя, а не ломает страницу */
}
.quiz-review-question td, .quiz-review-question th {
    border: 1px solid var(--border);
    padding: 5px 9px;
    font-size: 13px;
}
.quiz-review-answers {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
    font-size: 13px;
}
.quiz-review-answer-label { font-weight: 700; color: var(--muted); }

/* Карта попытки: клетка на вопрос, цвет = результат. Нужна, чтобы всю
   картину было видно одним взглядом, до чтения самих вопросов; клик —
   прыжок к вопросу в полном разборе. */
.quiz-map { display: flex; flex-wrap: wrap; gap: 5px; margin: 10px 0 2px; }
.quiz-map-cell {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    height: 30px;
    padding: 0 6px;
    border-radius: var(--radius-xs);
    border: 1px solid transparent;
    font-size: 12.5px;
    font-weight: 700;
    text-decoration: none;
}
.quiz-map-cell:hover { text-decoration: none; filter: brightness(.96); }
.quiz-map-cell.is-right   { background: var(--green-bg);  color: var(--green); }
.quiz-map-cell.is-partial { background: var(--orange-bg); color: var(--orange); }
.quiz-map-cell.is-wrong   { background: var(--red-bg);    color: var(--red); }

/* Цветная полоса слева у карточки вопроса — тот же язык цвета, что и в
   карте выше, чтобы при прокрутке не терять, о каком результате речь. */
.quiz-review-item.is-right   { border-left: 3px solid var(--green); }
.quiz-review-item.is-partial { border-left: 3px solid var(--orange); }
.quiz-review-item.is-wrong   { border-left: 3px solid var(--red); }
.quiz-review-label { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.quiz-status-tag {
    font-size: 11px;
    font-weight: 700;
    text-transform: lowercase;
    padding: 2px 8px;
    border-radius: 999px;
    flex-shrink: 0;
}
.quiz-status-tag.is-right   { background: var(--green-bg);  color: var(--green); }
.quiz-status-tag.is-partial { background: var(--orange-bg); color: var(--orange); }
.quiz-status-tag.is-wrong   { background: var(--red-bg);    color: var(--red); }

/* ===== Сроки у самого задания =====
   Свёрнутая карточка: главное (когда закрывается) видно сразу в заголовке,
   настройка раскрывается по клику и не занимает экран, пока не нужна. */
.deadline-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    margin-bottom: 16px;
}
.deadline-card > summary {
    cursor: pointer;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 14px;
    font-size: 13.5px;
}
.deadline-summary-title { font-weight: 700; color: var(--text); }
.deadline-summary-value { color: var(--accent-dark); font-weight: 600; }
.deadline-summary-value.is-past { color: var(--muted); }
.deadline-body { padding: 0 14px 14px; }
.deadline-base {
    font-size: 13px;
    color: var(--muted);
    line-height: 1.5;
    padding-bottom: 10px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.deadline-base b { color: var(--text); }
.deadline-hint { font-size: 12.5px; color: var(--muted); margin: 0 0 10px; }
.deadline-fields { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 12px; }
.deadline-fields label { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.deadline-fields input[type=datetime-local] {
    display: block;
    margin-top: 4px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13.5px;
    max-width: 100%;
}
.deadline-students {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-bottom: 12px;
    max-height: 260px;
    overflow-y: auto;
}
.deadline-all, .deadline-student {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    padding: 5px 2px;
    cursor: pointer;
}
.deadline-all { font-weight: 700; border-bottom: 1px solid var(--border); margin-bottom: 4px; padding-bottom: 8px; }
.deadline-list { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 10px; }
.deadline-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    padding: 5px 0;
}

.deadline-scope { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 12px; font-size: 13.5px; }
.deadline-scope label { display: flex; align-items: center; gap: 7px; cursor: pointer; }
.deadline-fields input[type=text] {
    display: block;
    margin-top: 4px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13.5px;
    min-width: 220px;
    max-width: 100%;
}

/* Уже оставленный отзыв преподавателя — визуально отделён от работы
   ученика: это две разные вещи, и путать их нельзя. */
.feedback-box {
    margin-top: 10px;
    padding: 10px 12px;
    background: var(--accent-bg);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    font-size: 13.5px;
}
.feedback-box-title { font-size: 11.5px; font-weight: 700; color: var(--accent-dark); margin-bottom: 6px; }

/* Ближайшие дедлайны на «Сегодня» — сгруппированы по разделу (курс —
   подписью рядом), внутри раздела одна строка = одна работа, по дате.
   Порядок разделов задаёт их самый близкий срок, поэтому «сверху раньше»
   читается и на уровне групп. */
.deadline-panel { margin-top: 4px; }

/* Раздел целиком — свёрнут/развёрнут обычным <details>; заголовок должен
   выглядеть как строка списка, а не как ссылка или кнопка.

   Наведение специально НЕ красит всю строку серой плашкой (так было
   сначала — получался тяжёлый квадрат во всю ширину, который на глаз
   выглядел как чужой элемент): меняется только цвет — заголовка и
   галочки, — и меняется плавно. */
.deadline-group { border-bottom: 1px solid var(--border); }
.deadline-group:last-child { border-bottom: none; }
.deadline-group-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 2px;
    cursor: pointer;
    list-style: none;
    font-size: 13.5px;
    border-radius: 8px;
}
.deadline-group-head::-webkit-details-marker { display: none; }
/* Галочка нарисована двумя рамками, а не символом «▸»: у глифа в каждом
   шрифте своя толщина и свой оптический центр, и ровно посадить его в
   строку нельзя. Эта — всегда одинаковая и разворачивается плавно. */
.deadline-group-head::before {
    content: '';
    flex-shrink: 0;
    width: 6px;
    height: 6px;
    margin: 0 3px 0 1px;
    border-right: 1.6px solid var(--muted);
    border-bottom: 1.6px solid var(--muted);
    transform: rotate(-45deg);
    transition: transform .22s cubic-bezier(.2, .8, .3, 1), border-color .18s;
}
.deadline-group[open] > .deadline-group-head::before { transform: rotate(45deg); }
.deadline-group-head:hover .deadline-group-title { color: var(--accent-dark); }
.deadline-group-head:hover::before { border-color: var(--accent-dark); }
/* Клавиатурный фокус — единственное место, где рамка уместна, и та скруглённая */
.deadline-group-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deadline-group-title {
    flex: 1 1 auto;
    font-weight: 700;
    color: var(--text);
    transition: color .18s;
}
.deadline-group-course { font-weight: 400; color: var(--muted); font-size: 12px; margin-left: 6px; }
.deadline-group-meta { flex-shrink: 0; color: var(--muted); font-size: 12.5px; white-space: nowrap; }
/* Строки работ — с отступом, чтобы вложенность была видна без линий, и
   появляются не рывком, а короткой мягкой подачей сверху */
.deadline-group > .deadline-feed { padding: 0 0 8px 16px; }
.deadline-group[open] > .deadline-feed { animation: deadline-reveal .2s cubic-bezier(.2, .8, .3, 1); }
@keyframes deadline-reveal { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

@media (max-width: 700px) {
    .deadline-group-head { flex-wrap: wrap; }
    .deadline-group-course { display: block; margin-left: 0; }
    .deadline-group-meta { flex-basis: 100%; padding-left: 19px; }
    .deadline-group > .deadline-feed { padding-left: 10px; }
}
@media (prefers-reduced-motion: reduce) {
    .deadline-group-head::before { transition: none; }
    .deadline-group[open] > .deadline-feed { animation: none; }
}
.deadline-feed { display: flex; flex-direction: column; gap: 2px; }
.deadline-feed-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 9px 2px;
    border-bottom: 1px solid var(--border);
    font-size: 13.5px;
}
.deadline-feed-row:last-child { border-bottom: none; }
.deadline-feed-name { font-weight: 600; color: var(--text); }
.deadline-feed-sub { font-size: 12px; color: var(--muted); }
/* Контурная плашка — тот же приём, что и .grade-tone на «Оценках»: рамка
   цветом смысла, без заливки. Колонка фиксированной ширины и центрирует
   плашку внутри себя (не жмёт её к правому краю) — иначе у короткого
   «завтра» и длинного «через 3 дня, 14.09» ровным был бы только один
   край, а другой — рваным. */
.deadline-feed-when {
    flex-shrink: 0;
    width: 158px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1.5px solid var(--border);
    font-size: 12.5px;
    font-weight: 700;
    color: var(--muted);
    white-space: nowrap;
}
.deadline-feed-when.is-soon { border-color: var(--orange); color: var(--orange); }
.deadline-feed-when.is-past { border-color: var(--red); color: var(--red); }

@media (max-width: 700px) {
    /* Раньше строка просто "переносилась" (flex-wrap), а куда денется
       плашка — решала длина конкретного названия: короткое оставляло ей
       место сбоку, длинное вытесняло вниз. На одном экране половина строк
       оказывалась с плашкой справа, половина — снизу, без всякой системы.
       Разница глазами читалась как поломка, хотя каждая строка сама по
       себе была правильной. Теперь строка ВСЕГДА в столбец — плашка
       всегда на своей строке, у всех работ одинаково, независимо от
       длины названия. */
    .deadline-feed-row { flex-direction: column; align-items: flex-start; gap: 4px; }
    .deadline-feed-when { width: auto; align-self: flex-start; }
}

/* Кнопка сохранения срока и галочка «сообщить ученикам» — в одну строку:
   решение «писать или не писать» принимается ровно в момент сохранения,
   и прятать его в другой конец формы было бы неудобно. */
.deadline-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
.deadline-notify {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    margin: 0;
}
.deadline-clear-form { margin: 10px 0 0; }

/* ===== Дедлайны ===== */
/* Название курса над группой разделов на странице ученика */
.dl-course {
    font-size: 12px;
    font-weight: 800;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .08em;
    margin: 26px 0 10px;
}
.dl-course:first-of-type { margin-top: 2px; }

/* Карточка раздела — тот же язык, что и «Оценки» (.grade-section):
   тонированная шапка отделяет группу от белого списка строк. Срочность
   несёт ЦВЕТ ТЕКСТА, а не заливка фона или плашка — заметно на нужных
   строках, но не превращает список в цветное полотно, когда просроченного
   вдруг оказывается несколько подряд. */
.dlc {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    margin-bottom: 10px;
    overflow: hidden;
}
.dlc-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px 14px;
    flex-wrap: wrap;
    padding: 12px 14px;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
}
.dlc-title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
.dlc-name { font-size: 14.5px; font-weight: 700; color: var(--text); }
/* «1 из 2» — сколько частей раздела уже сдано. Простым текстом, не
   плашкой: это подпись к названию, а не отдельный статус. */
.dlc-progress { font-size: 12px; color: var(--muted); white-space: nowrap; }
.dlc-course-tag { font-size: 11.5px; color: var(--muted); }

/* «Когда» в шапке раздела — контурная плашка, тот же приём, что и
   .grade-tone на «Оценках»: рамка цветом смысла, без заливки, единый
   стиль с остальным сайтом. Текст собран ОДНОЙ строкой в PHP
   (deadline_when_text()), а не разведён на два элемента с CSS-отступом
   между ними: единственный способ гарантированно не потерять пробел ни
   при какой раскладке — не давать браузеру возможности их развести. */
.dlc-when {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1.5px solid var(--border);
    font-size: 12.5px;
    font-weight: 700;
    color: var(--muted);
    white-space: nowrap;
}
.dlc-when.is-overdue { border-color: var(--red); color: var(--red); }
.dlc-when.is-today,
.dlc-when.is-soon    { border-color: var(--orange); color: var(--orange); }
.dlc-when.is-done    { border-color: var(--green); color: var(--green-dark); }

.dlc-items { list-style: none; margin: 0; padding: 0 14px; }
.dlc-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 0;
    border-top: 1px solid var(--border);
    font-size: 13.5px;
}
.dlc-item:first-child { border-top: none; }

/* Галочка — маленькая, без кружка вокруг: просто зелёная отметка перед
   сданным. У несданного на её месте пусто, а не контур-заглушка — раз уж
   от неё явно решили отказаться, лучше не рисовать её вовсе, чем рисовать
   плохо. Ширина всё равно зарезервирована (min-width), чтобы названия
   работ в списке начинались с одной вертикальной линии, а не прыгали. */
.dlc-check {
    flex-shrink: 0;
    min-width: 16px;
    display: inline-flex;
    color: var(--green);
}
.dlc-check .ui-icon { width: 15px; height: 15px; stroke-width: 3; }

.dlc-item-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* Сдано — приглушённый цвет и зачёркнутое название, как в любом чек-листе.
   Без заливки фона: полосу такой ширины (во всю строку) телефон не всегда
   укладывал ровно в границы карточки, да и выглядела она тяжелее, чем
   нужно для одной выполненной строчки в списке. */
.dlc-item.is-done .dlc-item-name { color: var(--muted); text-decoration: line-through; text-decoration-color: var(--border); }
.dlc-tag {
    display: inline-block;
    font-size: 10.5px;
    font-weight: 800;
    color: var(--accent);
    text-transform: uppercase;
    letter-spacing: .03em;
    margin-left: 6px;
}
.dlc-note { font-size: 11.5px; color: var(--muted); margin-left: 6px; }
/* Та же контурная плашка, что и в шапке (.dlc-when) — только чуть мельче:
   это уже частность (своя дата у одной работы), а не главный статус
   раздела. */
.dlc-item-when {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    border: 1.5px solid var(--border);
    font-size: 11.5px;
    font-weight: 700;
    color: var(--muted);
    white-space: nowrap;
}
.dlc-item-when.is-overdue { border-color: var(--red); color: var(--red); }
.dlc-item-when.is-today,
.dlc-item-when.is-soon    { border-color: var(--orange); color: var(--orange); }
.dlc-item-when.is-done    { border-color: var(--green); color: var(--green-dark); }

.dlc.is-archived { opacity: .8; }

/* «Уже сдано» — свой треугольник вместо системного маркера <details>:
   стандартный «▸» в этом месте выглядел чужеродно среди карточек. */
.dl-done-wrap { margin-top: 26px; }
.dl-done-wrap > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--muted);
    padding: 6px 2px;
    margin-bottom: 10px;
}
.dl-done-wrap > summary::-webkit-details-marker { display: none; }
.dl-done-chevron {
    width: 7px;
    height: 7px;
    border: solid var(--muted);
    border-width: 0 1.6px 1.6px 0;
    transform: rotate(-45deg);
    transition: transform .15s ease;
}
.dl-done-wrap[open] > summary .dl-done-chevron { transform: rotate(45deg); }
.dl-done-count {
    font-size: 11px;
    font-weight: 800;
    color: var(--muted);
    background: var(--surface-2);
    border-radius: 999px;
    padding: 2px 8px;
    letter-spacing: 0;
}

/* Работы внутри раздела на вкладке «Дедлайны» в админке.
   Колонки фиксированной ширины, а не «как получится»: названия работ
   разной длины, и при выравнивании по содержимому даты прыгали бы по
   строке туда-сюда — глазами такой столбец не читается. */
.dl-items { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 8px; }
.dl-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 0;
    font-size: 13px;
    border-bottom: 1px solid var(--border);
}
.dl-item:last-child { border-bottom: none; }
.dl-item-name { min-width: 0; flex: 1 1 auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dl-item-when {
    flex: 0 0 auto;
    width: 190px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.dl-item-act { flex: 0 0 auto; width: 118px; display: flex; gap: 4px; justify-content: flex-end; }
.dl-inline-form { margin: 0; display: inline-flex; }
.dl-left { font-size: 12.5px; font-weight: 700; white-space: nowrap; }
.dl-left.is-overdue { color: var(--red); }
.dl-left.is-today   { color: var(--orange); }
.dl-left.is-soon    { color: var(--orange); }
.dl-left.is-ok      { color: var(--text); }

@media (max-width: 700px) {
    .deadline-fields { flex-direction: column; gap: 10px; }
    .deadline-fields input[type=datetime-local] { width: 100%; }
    .deadline-row { flex-direction: column; align-items: flex-start; gap: 4px; }
    /* На узком экране фиксированные колонки не помещаются — название
       занимает строку целиком, дата и кнопки уходят под него */
    .dl-item { flex-wrap: wrap; }
    .dl-item-name { width: 100%; flex: 1 1 100%; }
    .dl-item-when { width: auto; flex: 1 1 auto; }
    .dl-item-act { width: auto; }

    /* Название раздела и плашка срока в шапке в одну строку не помещаются
       вместе — плашка сама переносится на свою строку (обычный перенос
       flex-wrap), пилюлей, а не растянутой на всю ширину полосой. */
    .dlc-head { flex-direction: column; align-items: flex-start; gap: 6px; padding: 11px 13px; }
    .dlc-name { font-size: 14.5px; }
    .dlc-items { padding: 0 13px; }
    .dlc-item { font-size: 13px; gap: 8px; padding: 9px 0; }
    .dlc-check { min-width: 15px; }
    .dlc-check .ui-icon { width: 14px; height: 14px; }
    /* Плашка срока работы — тоже переносится своей строкой, если рядом с
       названием не помещается, а не сбоку ломается пополам */
    .dlc-item { flex-wrap: wrap; }
    .dlc-item-name { flex: 1 1 auto; }
}

.quiz-full { margin-top: 12px; }
.quiz-full > summary {
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    color: var(--accent);
    padding: 8px 2px;
}
.quiz-full > summary:hover { color: var(--accent-dark); }

/* Значки в тексте и в бейджах (ui_icon() в includes/functions.php) —
   вместо смайлов: наследуют цвет текста и масштабируются вместе с ним,
   поэтому одинаково выглядят в любой системе и в любой теме. */
.ui-icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    vertical-align: -0.13em;
}
.badge .ui-icon { margin-right: 4px; }

/* ===== Матрица оценок Moodle (ученики × разделы или ученики × задания) =====
   Обычные таблицы на телефоне разворачиваются в карточки (см. медиазапрос
   ниже), но матрице это противопоказано: весь её смысл — сравнивать
   учеников между собой построчно. Поэтому у неё свой класс: она всегда
   остаётся таблицей и прокручивается вбок, а колонка с именем
   примагничена к левому краю, чтобы при прокрутке было видно, чья строка. */
.matrix-scroll {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--surface);
}
.grade-matrix {
    border-collapse: separate;
    border-spacing: 0;
    width: auto;
    min-width: 100%;
    font-size: 13px;
}
.grade-matrix th, .grade-matrix td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.grade-matrix thead th {
    background: var(--surface-2);
    font-size: 11.5px;
    font-weight: 700;
    color: var(--muted);
    text-align: center;
    vertical-align: bottom;
    max-width: 150px;
    white-space: normal;
    line-height: 1.3;
}
.grade-matrix thead th a { color: var(--muted); }
.grade-matrix tbody td { text-align: center; }
.grade-matrix tbody tr:last-child th,
.grade-matrix tbody tr:last-child td { border-bottom: none; }
.grade-matrix tbody tr:hover td,
.grade-matrix tbody tr:hover th.matrix-sticky { background: var(--accent-bg); }
.matrix-sticky {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--surface);
    text-align: left;
    font-weight: 700;
    min-width: 150px;
    max-width: 220px;
    white-space: normal;
    box-shadow: 1px 0 0 var(--border);
}
.grade-matrix thead th.matrix-sticky { z-index: 3; background: var(--surface-2); }
.matrix-parent { display: block; font-weight: 400; font-size: 10px; color: var(--muted); opacity: .8; }
/* Вторичный балл рядом с первичным — намеренно тише основного числа:
   это пересчёт, а не сама оценка */
.matrix-secondary { display: block; font-size: 11px; font-weight: 700; color: var(--accent-dark); margin-top: 2px; }
.matrix-note { display: block; font-weight: 400; font-size: 11px; color: var(--red); }

@media (max-width: 700px) {
    .grade-matrix { font-size: 12px; }
    .grade-matrix th, .grade-matrix td { padding: 6px 8px; }
    .grade-matrix thead th { max-width: 110px; }
    .matrix-sticky { min-width: 118px; max-width: 140px; font-size: 12px; }
}

/* ===== Мобильная адаптация таблиц ===== */
@media (max-width: 700px) {
    .lessons-table { border-spacing: 0; }
    .lessons-table thead, .simple-table thead { display: none; }
    .lessons-table, .lessons-table tbody, .lessons-table tr, .lessons-table td,
    .simple-table, .simple-table tbody, .simple-table tr, .simple-table td { display: block; width: 100%; }
    .lessons-table tr, .simple-table tr {
        border: 1px solid var(--border);
        border-radius: 14px;
        margin-bottom: 8px;
        padding: 10px 12px;
        background: var(--surface);
        box-shadow: var(--shadow);
    }
    /* .cell-check исключён отсюда: вне режима выбора он должен быть скрыт
       (display:none), а это правило иначе перебивало бы скрытие своей
       специфичностью — из-за чего чекбоксы были видны на телефоне всегда,
       а не только при нажатой "Выбрать несколько" */
    .lessons-table td:not(.cell-check), .simple-table td:not(.cell-check) {
        border-top: none;
        padding: 2px 0;
        font-size: 13px;
        min-height: 0;
        line-height: 1.35;
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 10px;
        text-align: right;
    }
    .lessons-table tbody td:first-child,
    .lessons-table tbody td:last-child { border-radius: 0; }
    .lessons-table td.topic-cell {
        display: block;
        text-align: left;
        padding: 2px 0 8px;
        margin-bottom: 4px;
        border-bottom: 1px solid var(--border);
    }
    .lessons-table td.topic-cell .topic-line { text-align: left; padding-right: 0; }
    .lessons-table td.topic-cell::before { content: none; }
    .lessons-table td.topic-cell .hw-text,
    .lessons-table td.topic-cell .muted { padding-right: 0; }
    .lessons-table .hw-text { margin-left: 0; text-align: left; max-width: none; }
    .lessons-table td::before, .simple-table td::before {
        content: attr(data-label);
        font-size: 10px;
        font-weight: 700;
        color: var(--muted);
        text-transform: uppercase;
        letter-spacing: .03em;
        text-align: left;
        flex-shrink: 0;
    }
    .lessons-table td[data-label=""]::before,
    .simple-table td[data-label=""]::before,
    .simple-table td:not([data-label])::before { display: none; }
    .lessons-table .hw-select { max-width: 140px; }


    /* Компактные таблицы (учебная программа, темы уровня в Библиотеке тем) —
       короткие однострочные пункты, для которых "карточка на каждую строку"
       (общее мобильное правило выше) выглядит слишком тяжеловесно: одна
       строка текста внутри рамки со своими отступами и тенью, повторённая
       N раз подряд. Здесь вместо этого — плоский список с тонким
       разделителем, всё в одну строку, как и на компьютере. */
    .compact-table tr {
        border: none;
        border-radius: 0;
        margin-bottom: 0;
        padding: 9px 2px;
        box-shadow: none;
        background: none;
        border-bottom: 1px solid var(--border);
        display: flex;
        align-items: center;
        gap: 8px;
    }
    .compact-table tbody tr:last-child { border-bottom: none; }
    .compact-table td {
        display: block;
        width: auto;
        padding: 0;
        border-top: none;
        font-size: 13.5px;
    }
    .compact-table td::before { display: none; }
    .compact-table td.drag-handle,
    .compact-table td.cell-check,
    .compact-table td.cell-actions { flex: 0 0 auto; }
    .compact-table td:not(.drag-handle):not(.cell-check):not(.cell-actions) {
        flex: 1 1 auto;
        min-width: 0;
        overflow-wrap: anywhere;
    }
    /* Перетаскивание — только мышью (см. JS): на тач-экране ⠿ всё равно не
       работает, показывать его тут — просто лишняя "плашка" без функции. */
    .compact-table .drag-handle { display: none; }
    .compact-table .plan-edit-row { border-bottom: none; padding-top: 0; }
    .compact-table .plan-edit-row td { width: 100%; }
}

/* ===== Футер с контактами ===== */
.site-footer-contacts {
    text-align: center;
    padding: 22px 0 8px;
    color: var(--muted);
    font-size: 13px;
}
.site-footer-contacts .name { font-weight: 700; color: var(--text); }
.site-footer-contacts .site { margin-top: 2px; font-size: 11.5px; letter-spacing: .04em; }
/* Футер идёт сразу после .site-main — ему нужен тот же отступ снизу под
   нижний таббар (≈60-90px с учётом safe-area), иначе имя/домен прячутся
   под фиксированной панелью, когда страница короче экрана. */
/* Помимо ширины — ещё и по высоте: телефон в альбомной ориентации обычно
   шире 760px, но остаётся именно телефоном (мало места по высоте), а не
   планшетом/десктопом. Без второго условия при повороте телефона нижний
   таббар и весь мобильный вид пропадали, включалась десктопная раскладка,
   для которой на телефоне физически нет места — кнопки/пункты меню
   наезжали друг на друга или обрезались.
   (hover: none) and (pointer: coarse) — обязательно вместе с высотой:
   иначе это же условие ложно срабатывало и на компьютере, если окно
   браузера просто невысокое (не на весь экран) — тогда мобильная
   раскладка меню включалась поверх мышиного интерфейса и всё разъезжалось
   («то густо, то пусто» в отступах). hover/pointer отличают сенсорные
   устройства (телефон, где и нужна альбомная раскладка) от компьютера с
   мышью — на компьютере это условие теперь не срабатывает никогда. */
@media (max-width: 760px), ((max-height: 480px) and (hover: none) and (pointer: coarse)) {
    .site-footer-contacts { padding-bottom: calc(86px + env(safe-area-inset-bottom, 0px)); }
}


/* ===== Выпадающее меню в шапке "Ещё" =====
   Визуал самой кнопки задаёт .nav-link (см. выше) — тут только позиционирование
   и поведение самого раскрывающегося списка. */
.nav-dropdown { position: relative; display: inline-block; }
.nav-dropdown summary { list-style: none; }
.nav-dropdown summary::-webkit-details-marker { display: none; }
.nav-dropdown-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 56;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lift);
    padding: 6px;
    min-width: 220px;
    display: flex;
    flex-direction: column;
    /* Пунктов меню со временем стало много — без этого список обрезался
       краем экрана без возможности пролистать. overscroll-behavior не даёт
       прокрутке "перетечь" на страницу целиком, когда доскроллили до конца
       списка — иначе именно это и закрывало меню (см. JS ниже). */
    max-height: min(70vh, 480px);
    /* dvh — «динамическая» высота вьюпорта, учитывает реальный размер
       видимой области (без адресной строки/после поворота); vh выше —
       фолбэк для браузеров без поддержки dvh, переопределяется этой
       строкой, если она понятна браузеру. */
    max-height: min(70dvh, 480px);
    overflow-y: auto;
    overscroll-behavior: contain;
}
/* Граница смысловой группы пунктов — на самом первом пункте новой группы
   (border-top + отступ), а не отдельным пустым <div>-разделителем между
   пунктами: тот в этом же flex-списке почему-то вызывал непропорционально
   большие "пустые" промежутки в части браузеров — так безопаснее и даёт
   тот же зрительный эффект (см. класс "group-start" в includes/header.php). */
.nav-dropdown-menu a.group-start, .nav-dropdown-theme.group-start {
    border-top: 1px solid var(--border);
    margin-top: 6px;
    padding-top: 14px;
}
/* Подпись смысловой группы. Одних разделительных линий стало мало:
   пунктов в меню под два десятка, и без названий групп список читается
   как сплошная простыня. Подпись некликабельна — она только называет
   группу, поэтому и <span>, а не ссылка. */
.nav-dropdown-group {
    padding: 4px 12px 4px;
    font-size: 10.5px;
    font-weight: 800;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .06em;
    -webkit-user-select: none;
    user-select: none;
}
/* Отделяем группу от предыдущей — но только если перед ней действительно
   что-то было (у самой первой отступ сверху не нужен) */
.nav-dropdown-menu a + .nav-dropdown-group,
.nav-dropdown-menu button + .nav-dropdown-group {
    margin-top: 8px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}
.nav-dropdown-menu a, .nav-dropdown-theme {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 12px;
    border-radius: var(--radius-xs);
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    transition: background .12s ease;
}
.nav-dropdown-menu a:hover, .nav-dropdown-theme:hover { background: var(--surface-2); text-decoration: none; }
/* Раздел, который сейчас открыт — чтобы в длинном листе было видно, где ты */
.nav-dropdown-menu a.is-active { background: var(--accent-bg); color: var(--accent-dark); font-weight: 700; }
.nav-dropdown-menu a.is-active .nav-icon { color: var(--accent); }
.nav-dropdown-menu .nav-icon { width: 17px; height: 17px; flex-shrink: 0; color: var(--muted); }
.nav-dropdown-menu a.danger-link .nav-icon { color: var(--red); }
.nav-dropdown-theme {
    display: none;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    font: inherit;
    /* "font: inherit" — шорткод, который заодно сбрасывает font-weight и
       font-size обратно к значениям родителя, перебивая font-weight:500 и
       font-size:14px, заданные чуть выше общим правилом для этого же
       класса (см. ".nav-dropdown-menu a, .nav-dropdown-theme") — из-за
       этого кнопка Push выглядела другим шрифтом, не как остальные пункты
       меню. Возвращаем эти два свойства явно, уже после сброса. */
    font-weight: 500;
    font-size: 14px;
    cursor: pointer;
}
.nav-dropdown-theme .theme-icon-dark { display: none; }
[data-theme="dark"] .nav-dropdown-theme .theme-icon-light { display: none; }
[data-theme="dark"] .nav-dropdown-theme .theme-icon-dark { display: inline; }
.nav-dropdown-menu .danger-link { color: var(--red); }
.nav-dropdown-menu .danger-link:hover { background: var(--red-bg); }

/* ===== Сворачиваемый блок "Подробнее" ===== */
.details-toggle { margin-bottom: 16px; }
.details-toggle summary {
    cursor: pointer;
    list-style: none;
    font-size: 13px;
    font-weight: 600;
    color: var(--accent);
    display: inline-block;
}
.details-toggle summary::-webkit-details-marker { display: none; }
.details-toggle summary::before { content: "+ "; }
.details-toggle[open] summary::before { content: "− "; }

/* ===== Донат посещаемости ===== */
.donut-wrap { display: flex; align-items: center; gap: 12px; }
.donut {
    width: 72px; height: 72px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.donut-hole {
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--surface);
    display: flex; align-items: center; justify-content: center;
    flex-direction: column;
}
.donut-hole span { font-weight: 800; font-size: 16px; color: var(--text); letter-spacing: -0.02em; }
.donut-caption { font-size: 12px; color: var(--muted); font-weight: 600; }

/* ===== Компактные плашки статистики (главная) ===== */
.stat-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.stat-chip {
    display: flex;
    align-items: baseline;
    gap: 7px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 7px 15px;
    font-size: 13px;
    color: var(--muted);
    text-decoration: none;
}
.stat-chip b { font-size: 15px; font-weight: 800; color: var(--text); letter-spacing: -0.02em; }
a.stat-chip:hover { border-color: var(--accent); text-decoration: none; }
.stat-chip.is-warn b { color: var(--red); }
.stat-chip.is-ok b { color: var(--green); }

/* ===== Карточка группы: двухколоночная раскладка (admin/group_lessons.php) =====
   Правая колонка — не пустует: действия, финансы, план, участники. На узких
   экранах сайдбар уходит под основную колонку одной обычной колонкой. */
.group-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 20px;
    align-items: start;
}
.group-main { min-width: 0; }
.group-aside {
    display: flex;
    flex-direction: column;
    gap: 14px;
    position: sticky;
    top: 16px;
}
.group-aside-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 16px 18px;
}
.group-aside-card h3 {
    margin: 0 0 12px;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    font-weight: 700;
}
.group-aside-actions { display: flex; flex-direction: column; gap: 8px; }
.group-period-inputs { display: flex; gap: 6px; }
.group-period-inputs input { flex: 1 1 0; min-width: 0; padding: 6px 8px; font-size: 12.5px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.group-kv {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    color: var(--muted);
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
}
.group-kv:last-of-type { border-bottom: none; }
.group-kv b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.group-member-row { padding: 9px 0; border-bottom: 1px solid var(--border); }
.group-member-row:last-child { border-bottom: none; padding-bottom: 0; }
.group-member-name { font-size: 13px; font-weight: 600; }
.group-member-meta { font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.5; }

@media (max-width: 900px) {
    .group-layout { grid-template-columns: 1fr; }
    .group-aside { position: static; }
}

/* ===== Подсветка строки с невыполненным ДЗ ===== */
.lessons-table tbody tr.row-hw-pending td { background: #fffdf5; }
.lessons-table tbody tr.row-hw-pending td:first-child {
    box-shadow: inset 3px 0 0 var(--accent);
}
/* ===== Подсветка строки с неявкой (санкция) — едва заметная, чтобы не резала глаз ===== */
.lessons-table tbody tr.row-no-show td { background: rgba(220, 38, 38, 0.05); }
.lessons-table tbody tr.row-no-show td:first-child {
    box-shadow: inset 3px 0 0 rgba(220, 38, 38, 0.45);
}
.no-show-note {
    text-align: left;
    font-weight: 700;
    color: var(--red);
    font-size: 13px;
}
.link-btn {
    background: none; border: none; padding: 0; cursor: pointer;
    font: inherit; color: var(--muted); text-decoration: underline;
}
.link-btn:hover { color: var(--accent); }


/* ===== Календарь расписания (месяц, без горизонтальной прокрутки) ===== */
.cal { margin-bottom: 12px; }
.cal-head, .cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 4px;
}
.cal-head {
    margin-bottom: 4px;
}
.cal-head div {
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    padding-bottom: 4px;
}
.cal-day {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 5px 5px 6px;
    min-height: 74px;
    position: relative;
}
.cal-out { opacity: .4; }
.cal-past { background: #fafbfc; }
.cal-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.cal-date {
    position: relative;
    display: flex; align-items: center; justify-content: space-between;
    font-size: 11px; font-weight: 700; color: var(--muted); margin-bottom: 4px;
}
.cal-add {
    background: none; border: none; cursor: pointer; padding: 0 2px;
    color: var(--border); font-size: 14px; line-height: 1; font-weight: 700;
}
.cal-day:hover .cal-add { color: var(--accent); }
.cal-today .cal-date { color: var(--accent); }

.cal-slot {
    position: relative;
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    line-height: 1.25;
    padding: 3px 5px;
    border-radius: 8px;
    margin-bottom: 3px;
    border-left: 3px solid transparent;
}
.cal-slot-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-slot-time { font-size: 10px; font-weight: 700; opacity: .75; }
.cal-slot.slot-done  { background: var(--green-bg);  border-left-color: var(--green);  color: var(--green-dark); }
.cal-slot.slot-plan  { background: var(--gray-bg);   border-left-color: var(--gray);   color: var(--muted); }
/* "Запланировано", но дата уже прошла — вероятно, забыли отметить.
   Остаётся серым, как обычный план (не хочется ярких цветов), но чуть
   заметнее: более плотная полоса слева и текст чуть темнее нейтрального. */
.cal-slot.slot-plan-overdue {
    background: var(--gray-bg);
    border-left-color: var(--muted);
    border-left-width: 4px;
    color: var(--text);
}
.cal-slot.slot-off   { background: var(--red-bg);    border-left-color: var(--red);    color: var(--red); }
.cal-slot.slot-moved { background: var(--orange-bg); border-left-color: var(--orange); color: var(--orange); }
.cal-slot.slot-moved .cal-slot-name { text-decoration: line-through; opacity: .8; }
/* Неявка — не то же самое, что отмена (тут санкция, ученик был должен
   прийти и не пришёл), поэтому цвет отдельный, не путаем с обычным "off" */
.cal-slot.slot-no_show { background: var(--red-bg); border-left-color: var(--red); color: var(--red); }
.cal-slot.slot-no_show .cal-slot-name::after { content: " ⚠"; }
.cal-slot.slot-movedin { background: var(--accent-bg); border-left-color: var(--accent); color: var(--accent-dark); }
.cal-slot.slot-movedin .cal-slot-name::before { content: "→ "; font-weight: 700; }
.cal-slot-group { color: var(--accent); font-weight: 900; flex-shrink: 0; }

.cal-slot-menu {
    background: none; border: none; padding: 0 2px; cursor: pointer;
    color: var(--muted); font-size: 13px; line-height: 1; flex-shrink: 0;
}
.cal-slot-menu:hover { color: var(--accent); }

/* Всплывающая форма — поверх сетки, не растягивает ячейку */
.cal-pop {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 40;
    width: 190px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 6px 20px rgba(16,24,40,.16);
    padding: 8px;
}
.cal-pop.open { display: block; }
.cal-pop-title { font-size: 12px; font-weight: 700; color: var(--text); margin-bottom: 4px; }
.cal-pop-note { font-size: 11px; color: var(--muted); margin-bottom: 6px; line-height: 1.35; }
.cal-pop hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 9px 0;
}
.cal-pop-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    margin-bottom: 5px;
}
.cal-day:nth-child(7n) .cal-pop,
.cal-day:nth-child(7n-1) .cal-pop { left: auto; right: 0; }
.cal-pop select, .cal-pop input {
    display: block; width: 100%; margin: 0 0 6px;
    padding: 5px 7px; font-size: 11.5px; border-radius: 8px;
    border: 1px solid var(--border); background: var(--surface); color: var(--text);
}

/* Триггер окна "причина" (см. reason_field_html() в admin/schedule.php) —
   маленькая ссылка внутри тесного 190px попапа, не полноразмерная кнопка. */
.reason-link {
    display: block; width: 100%; margin: 0 0 6px; padding: 0;
    background: none; border: none; text-align: left;
    font-size: 11px; line-height: 1.3; color: var(--accent);
    text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.reason-link.is-set { color: var(--text); font-weight: 600; text-decoration: none; }

.reason-dialog {
    border: none; padding: 20px; width: min(380px, 92vw);
    background: var(--surface); color: var(--text);
    border-radius: var(--radius-sm); box-shadow: var(--shadow-lift);
}
.reason-dialog::backdrop { background: rgba(15, 21, 32, .45); }
.reason-dialog h3 { margin: 0 0 12px; font-size: 15px; }
.reason-dialog textarea {
    width: 100%; box-sizing: border-box; min-height: 92px; resize: vertical;
    padding: 9px 11px; font: inherit; font-size: 13.5px;
    border: 1px solid var(--border); border-radius: var(--radius-xs);
    background: var(--bg); color: var(--text); margin-bottom: 14px;
}
.reason-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; }

.cal-legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11.5px; color: var(--muted); margin-bottom: 18px; }
.cal-legend .lg { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; vertical-align: middle; }
.lg-done { background: var(--green); }
.lg-plan { background: var(--gray); }
.lg-off { background: var(--red); }
.lg-moved { background: var(--orange); }
.lg-overdue { background: var(--gray-bg); border-left: 4px solid var(--muted); }
.lg-movedin { background: var(--accent); }
.lg-no_show { background: var(--red); }

.done-row { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; padding: 3px 0; font-size: 13px; }
.done-num { color: var(--muted); font-weight: 700; min-width: 18px; }

/* Переключатель раскладки календаря — на компьютере не нужен: там сетка
   и так помещается целиком, показываем его только в мобильной вёрстке */
.cal-mode-bar { display: none; }
.cal-mode-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
.cal-mode-btn:active { background: var(--accent-bg); }
/* Кнопка называет то, КУДА переключит, а не то, что сейчас: «Сеткой» в
   режиме списка и «Списком» в режиме сетки */
.cal-mode-btn .cal-mode-to-list { display: none; }
.cal-mode-btn[aria-pressed="true"] .cal-mode-to-grid { display: none; }
.cal-mode-btn[aria-pressed="true"] .cal-mode-to-list { display: inline; }

/* На телефоне календарь превращается в вертикальный список дней */
@media (max-width: 700px) {
    .cal-mode-bar {
        display: flex;
        align-items: center;
        gap: 10px;
        flex-wrap: wrap;
        margin-bottom: 10px;
    }

    .cal-head { display: none; }
    .cal-grid { display: block; }
    .cal-day {
        display: none;
        min-height: 0;
        margin-bottom: 6px;
        padding: 8px 10px;
    }
    /* показываем только дни, где что-то есть */
    .cal-day:has(.cal-slot) { display: block; }
    .cal-out { display: none !important; }
    .cal-date {
        font-size: 13px;
        color: var(--text);
        margin-bottom: 6px;
        padding-bottom: 5px;
        border-bottom: 1px solid var(--border);
    }
    .cal-date::after {
        content: attr(data-full);
        font-weight: 500;
        color: var(--muted);
        font-size: 11.5px;
        margin-left: 6px;
    }
    .cal-slot { font-size: 13px; padding: 6px 8px; margin-bottom: 4px; }
    .cal-slot-name { white-space: normal; }
    .cal-slot-time { display: inline; font-size: 11px; }
    .cal-pop {
        width: calc(100% - 20px); left: 10px; right: auto;
        /* Выше нижнего таббара (z-index: 45): попап, открытый у нижнего края
           экрана, должен рисоваться ПОВЕРХ панели, иначе его нижние кнопки
           окажутся под ней и по ним нельзя будет попасть. */
        z-index: 50;
        /* Попап может открыться у самого низа списка дней — без ограничения
           высоты и скролла его нижняя часть (с кнопками действий) уходила
           под нижний таббар и была недоступна для нажатия. */
        max-height: min(60vh, 420px);
        max-height: min(60dvh, 420px);
        overflow-y: auto;
        margin-bottom: calc(70px + env(safe-area-inset-bottom, 0px));
    }
    .cal-add { font-size: 18px; color: var(--accent); }

    /* Меню дня на телефоне было заметно выше экрана: полноразмерные кнопки,
       крупные поля и щедрые отступы, рассчитанные на мышь. Из-за этого
       «отменить/перенести» уезжало вниз, и до него приходилось скроллить
       внутри попапа, не понимая, что там ещё что-то есть. Здесь всё то же
       самое, но плотнее — меню помещается целиком. */
    .cal-pop .btn { padding: 8px 10px; font-size: 12.5px; }
    .cal-pop .btn-block { margin-top: 0; }
    .cal-pop form { gap: 5px !important; margin-bottom: 6px !important; }
    .cal-pop hr { margin: 7px 0; }
    .cal-pop select, .cal-pop input { padding: 7px 8px; font-size: 12.5px; margin-bottom: 5px; }
    /* Чьё это меню, видно и после прокрутки внутри него */
    .cal-pop-title {
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--surface);
        padding: 2px 0 6px;
        margin-bottom: 2px;
        border-bottom: 1px solid var(--border);
        font-size: 13px;
    }

    /* ===== Режим «сеткой» на телефоне (.cal.is-grid) =====
       Возвращает раскладку, ради которой телефон приходилось поворачивать:
       настоящие 7 колонок с неделями по строкам.

       Сетка ВПИСЫВАЕТСЯ в экран, а не листается вбок: месяц нужен как раз
       для того, чтобы охватить его целиком одним взглядом, и прокрутка
       вбок этот смысл убивала. Колонка получается узкой (~48px на обычном
       телефоне) — имя в ней помещается не целиком, но статус занятия
       читается цветом, а полное имя видно в меню дня.

       overflow-x оставлен на совсем узкий экран как аварийный выход. */
    .cal.is-grid { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .cal.is-grid .cal-head,
    .cal.is-grid .cal-grid {
        display: grid;
        grid-template-columns: repeat(7, minmax(44px, 1fr));
        gap: 3px;
    }
    .cal.is-grid .cal-head { display: grid; margin-bottom: 4px; }
    .cal.is-grid .cal-head div { font-size: 10px; }
    /* В сетке нужны ВСЕ дни, включая пустые и «хвосты» соседних месяцев:
       без них недели разъедутся и разметка перестанет быть календарём */
    .cal.is-grid .cal-day {
        display: block;
        min-height: 62px;
        margin-bottom: 0;
        padding: 3px;
        border-radius: 8px;
    }
    .cal.is-grid .cal-out { display: block !important; }
    .cal.is-grid .cal-date {
        font-size: 10px;
        margin-bottom: 2px;
        padding-bottom: 2px;
        border-bottom: none;
    }
    /* Полная подпись «14.09, пн» нужна была списку, где нет шапки с днями
       недели; в сетке шапка есть, и подпись только съедала бы место */
    .cal.is-grid .cal-date::after { content: none; }
    .cal.is-grid .cal-slot {
        position: relative;
        font-size: 9.5px;
        line-height: 1.25;
        padding: 2px 3px;
        margin-bottom: 2px;
        border-left-width: 2px;
        border-radius: 4px;
    }
    .cal.is-grid .cal-slot-name { white-space: nowrap; }
    .cal.is-grid .cal-slot-time { display: none; }
    /* Кнопка «⋯» съедала треть и без того узкой ячейки. В сетке она
       растягивается на всю плашку и становится прозрачной: нажатие в любое
       место занятия открывает то же самое меню, а место остаётся имени. */
    .cal.is-grid .cal-slot-menu {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        padding: 0;
        opacity: 0;
    }
    .cal.is-grid .cal-add { font-size: 13px; }

    /* Попап внутри .cal.is-grid оказался бы в контейнере с overflow-x: auto,
       а он обрезает и по вертикали тоже (CSS не позволяет скроллить одну ось
       и не обрезать другую) — меню действий просто не было бы видно.
       Поэтому в этом режиме попап становится листом снизу экрана, как это
       уже сделано у выпадающего меню в шапке. */
    .cal.is-grid .cal-pop {
        position: fixed;
        left: 8px;
        right: 8px;
        bottom: calc(74px + env(safe-area-inset-bottom, 0px));
        top: auto;
        width: auto;
        margin-bottom: 0;
        max-height: min(72vh, 560px);
        max-height: min(72dvh, 560px);
        overflow-y: auto;
        z-index: 60;
        box-shadow: var(--shadow-lift);
    }
}

/* Компактный инлайн-фильтр в строке статистики */
.inline-filter { display: inline-flex; }
.inline-filter select {
    display: inline-block;
    width: auto;
    margin: 0;
    padding: 6px 12px;
    font-size: 13px;
    font-weight: 600;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}
.inline-filter select:hover { border-color: var(--accent); }

/* Разовое занятие вне регулярного расписания */
.cal-slot.slot-extra .cal-slot-name::after {
    content: " •";
    color: var(--accent);
    font-weight: 700;
}

/* Инлайн-форма редактирования (список курсов Moodle) */
.inline-edit { display: none; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.inline-edit.open { display: block; }
.inline-edit form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.inline-edit input {
    display: inline-block; width: auto; margin: 0;
    padding: 7px 10px; font-size: 13px;
    border: 1px solid var(--border); border-radius: 10px;
    background: var(--surface); color: var(--text);
}
.inline-edit input[name="label"] { flex: 1 1 200px; }

/* ══════════════════════════════════════════════
   ТОСТЫ — подтверждение действий
   ══════════════════════════════════════════════ */
.toast-wrap {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 200;
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: max-content;
    max-width: calc(100vw - 32px);
    transition: opacity .35s ease, transform .35s ease, bottom .2s ease;
}
/* Приподнимаем над нижним таббаром, чтобы тост не прятался под ним */
/* Помимо ширины — ещё и по высоте: телефон в альбомной ориентации обычно
   шире 760px, но остаётся именно телефоном (мало места по высоте), а не
   планшетом/десктопом. Без второго условия при повороте телефона нижний
   таббар и весь мобильный вид пропадали, включалась десктопная раскладка,
   для которой на телефоне физически нет места — кнопки/пункты меню
   наезжали друг на друга или обрезались.
   (hover: none) and (pointer: coarse) — обязательно вместе с высотой:
   иначе это же условие ложно срабатывало и на компьютере, если окно
   браузера просто невысокое (не на весь экран) — тогда мобильная
   раскладка меню включалась поверх мышиного интерфейса и всё разъезжалось
   («то густо, то пусто» в отступах). hover/pointer отличают сенсорные
   устройства (телефон, где и нужна альбомная раскладка) от компьютера с
   мышью — на компьютере это условие теперь не срабатывает никогда. */
@media (max-width: 760px), ((max-height: 480px) and (hover: none) and (pointer: coarse)) {
    .toast-wrap { bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
}
.toast-hide { opacity: 0; transform: translate(-50%, 12px); }
.toast {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    border-radius: 14px;
    background: #eef2f7;
    color: #1f2937;
    border: 1px solid #d7dfe9;
    font-size: 13.5px;
    font-weight: 600;
    box-shadow: 0 8px 24px rgba(16, 24, 40, .12);
    animation: toast-in .28s cubic-bezier(.2, .8, .3, 1);
}
@keyframes toast-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.toast-success { background: #e8f6ee; border-color: #bfe3cd; color: #14532d; }
.toast-error { background: #fdecec; border-color: #f4c9c9; color: #7f1d1d; }
.toast-text { flex: 1; }
.toast-undo {
    color: inherit;
    text-decoration: underline;
    font-weight: 700;
    white-space: nowrap;
}
.toast-undo:hover { opacity: .7; }
.toast-close {
    background: none; border: none; color: currentColor; opacity: .5;
    font-size: 18px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.toast-close:hover { opacity: 1; }

/* ══════════════════════════════════════════════
   ПУСТЫЕ СОСТОЯНИЯ
   ══════════════════════════════════════════════ */
.empty-block {
    text-align: center;
    padding: 40px 20px;
    background: var(--surface);
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    margin-bottom: 18px;
}
.empty-block .empty-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 4px;
}
.empty-block .empty-sub {
    font-size: 13px;
    color: var(--muted);
    margin-bottom: 14px;
}

/* ══════════════════════════════════════════════
   ТИПОГРАФИКА — единая шкала
   ══════════════════════════════════════════════ */
body {
    font-family: "Golos Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-feature-settings: "tnum" 1;   /* цифры одинаковой ширины — таблицы не «прыгают» */
}
h1 { font-size: 22px; letter-spacing: -0.02em; font-weight: 800; }
h2 { font-size: 16px; letter-spacing: -0.01em; font-weight: 700; }

/* ══════════════════════════════════════════════
   ГРАФИКИ
   ══════════════════════════════════════════════ */
.chart-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px 8px;
    margin-bottom: 20px;
    box-shadow: var(--shadow);
}
.chart-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.chart-title { font-size: 14px; font-weight: 700; color: var(--text); }
.chart-note { font-size: 11.5px; color: var(--muted); }
.chart { width: 100%; height: auto; display: block; overflow: visible; }
.chart-grid { stroke: var(--border); stroke-width: 1; }
.chart-axis { font-size: 10px; fill: var(--muted); font-weight: 600; }
.chart-label { font-size: 10.5px; fill: var(--muted); }
.chart-value { font-size: 11px; fill: var(--text); font-weight: 700; }
.chart-line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.chart-area { fill: var(--accent); opacity: .10; }
.chart-dot { fill: var(--surface); stroke: var(--accent); stroke-width: 2.5; }

@media (max-width: 700px) {
    .chart-card { padding: 12px 12px 4px; }
    .chart-value { font-size: 10px; }
    .chart-label { font-size: 9.5px; }
}

/* ══════════════════════════════════════════════
   МАССОВЫЕ ДЕЙСТВИЯ
   ══════════════════════════════════════════════ */
/* !important здесь осознанно: колонка выбора должна быть скрыта всегда,
   кроме явного режима "Выбрать несколько" — а мобильная адаптация таблиц
   (эта же страница) описывает display для td общими правилами, которые
   иначе перебивали бы скрытие на телефоне из-за порядка каскада. */
.cell-check { width: 34px; text-align: center; display: none !important; }
body.select-mode .cell-check { display: table-cell !important; }
.table-tools { display: flex; justify-content: flex-end; margin-bottom: 10px; }
.cell-check input { width: 16px; height: 16px; cursor: pointer; margin: 0; }

.bulk-bar {
    display: none;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    background: var(--surface);
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    padding: 10px 14px;
    margin-bottom: 12px;
    box-shadow: var(--shadow);
}
.bulk-bar.open { display: flex; }
.bulk-count { font-size: 13px; color: var(--muted); margin-right: 4px; }
.bulk-count b { color: var(--text); font-size: 15px; }

@media (max-width: 700px) {
    body.select-mode .lessons-table td.cell-check {
        display: flex !important;
        justify-content: flex-start;
        gap: 8px;
        padding-bottom: 6px;
    }
    .lessons-table td.cell-check::before { content: "Выбрать"; }
    .bulk-bar {
        position: sticky;
        bottom: calc(72px + env(safe-area-inset-bottom, 0px));
        z-index: 50;
    }
}

/* ══════════════════════════════════════════════
   ТЁМНАЯ ТЕМА
   ══════════════════════════════════════════════ */
[data-theme="dark"] {
    --bg: #0f1520;
    --surface: #171f2e;
    --surface-2: #1e2738;
    --border: #2b3a52;
    --text: #e6ecf5;
    --muted: #94a3b8;
    --accent: #6f97fc;
    --accent-dark: #9db6fd;
    --accent-bg: rgba(111, 151, 252, .16);

    --green: #4ade80;
    --green-dark: #86efac;
    --green-bg: rgba(74, 222, 128, .15);
    --green-dark-bg: rgba(134, 239, 172, .18);
    --red: #f87171;
    --red-bg: rgba(248, 113, 113, .15);
    --orange: #f2b563;
    --orange-bg: rgba(242, 181, 99, .16);
    --gray: #94a3b8;
    --gray-bg: rgba(148, 163, 184, .14);
    --purple: #c4a4fb;
    --purple-bg: rgba(196, 164, 251, .16);
    --shadow: 0 1px 3px rgba(0, 0, 0, .35), 0 8px 20px rgba(0, 0, 0, .2);
}
[data-theme="dark"] body::before { opacity: .025; }
[data-theme="dark"] .cal-past { background: #131c2e; }
[data-theme="dark"] .cal-today { background: #16243d; }
[data-theme="dark"] .lessons-table tbody tr.row-hw-pending td { background: #1d2536; }
[data-theme="dark"] .lessons-table tbody tr.row-no-show td { background: rgba(248, 113, 113, .05); }
[data-theme="dark"] .btn-primary { color: #0b1220; }
[data-theme="dark"] .toast { background: #1e293b; color: #e6ecf5; border-color: #2b3a52; }
[data-theme="dark"] .toast-success { background: #16301f; border-color: #245534; color: #86efac; }
[data-theme="dark"] .toast-error { background: #331b1b; border-color: #5a2a2a; color: #fca5a5; }

.theme-toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 16px;
    color: var(--muted);
    padding: 6px 8px;
    border-radius: 10px;
    line-height: 1;
}
.theme-toggle:hover { color: var(--accent); background: var(--surface-2); }
.theme-icon-dark { display: none; }
[data-theme="dark"] .theme-icon-light { display: none; }
[data-theme="dark"] .theme-icon-dark { display: inline; }

/* ══════════════════════════════════════════════
   НИЖНЯЯ НАВИГАЦИЯ (моб./PWA) — вместо гамбургера
   Тот же <nav id="mainNav">, что и на десктопе: на телефоне мы не
   показываем/скрываем его, а просто переверстываем в фиксированный
   таббар снизу — так пункты меню не дублируются в разметке.
   ══════════════════════════════════════════════ */
/* Помимо ширины — ещё и по высоте: телефон в альбомной ориентации обычно
   шире 760px, но остаётся именно телефоном (мало места по высоте), а не
   планшетом/десктопом. Без второго условия при повороте телефона нижний
   таббар и весь мобильный вид пропадали, включалась десктопная раскладка,
   для которой на телефоне физически нет места — кнопки/пункты меню
   наезжали друг на друга или обрезались.
   (hover: none) and (pointer: coarse) — обязательно вместе с высотой:
   иначе это же условие ложно срабатывало и на компьютере, если окно
   браузера просто невысокое (не на весь экран) — тогда мобильная
   раскладка меню включалась поверх мышиного интерфейса и всё разъезжалось
   («то густо, то пусто» в отступах). hover/pointer отличают сенсорные
   устройства (телефон, где и нужна альбомная раскладка) от компьютера с
   мышью — на компьютере это условие теперь не срабатывает никогда. */
@media (max-width: 760px), ((max-height: 480px) and (hover: none) and (pointer: coarse)) {
    .header-inner { padding: 12px 16px; }
    .brand .logo { max-height: 40px; }
    .brand-text { font-size: 18px; }

    /* Эти элементы на телефоне переезжают внутрь листа "Ещё"
       (.nav-dropdown-name / .nav-dropdown-theme) — в самом таббаре
       для них нет места. */
    .nav-user, .theme-toggle { display: none; }

    /* Шапка на телефоне — обычная, НЕ «липкая». Причина не косметическая.
       Разметка у нас одна на все экраны: нижний таббар — это тот же
       <nav id="mainNav">, что лежит ВНУТРИ .site-header (на компьютере он
       строкой в шапке, на телефоне — панелью снизу). А position: sticky
       вместе с z-index у шапки создаёт отдельный слой отрисовки и
       собственный контекст наложения, внутрь которого попадает и таббар.
       Формально fixed всё равно должен считаться от окна, но часть
       браузеров и WebView (а установленное PWA — это именно WebView) после
       поворота экрана, скрытия клавиатуры или восстановления страницы из
       фона начинают позиционировать такой вложенный fixed-элемент
       относительно этого слоя, а не окна. Внешне это и есть та самая
       поломка: таббар «отклеивается» и уезжает вместе со страницей —
       оказывается посреди экрана; лечится только полным перезапуском
       приложения, потому что состояние слоя живёт дольше страницы.
       Со static-шапкой такого слоя и контекста нет — таббару просто не от
       чего отвязаться, он остаётся привязан к окну.
       Потери на телефоне при этом нулевые: имя пользователя и
       переключатель темы в мобильной шапке и так скрыты (см. выше),
       навигация вынесена вниз — «залипал» сверху один логотип. */
    .site-header { position: static; }

    .main-nav {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 45;
        display: flex;
        flex-direction: row;
        align-items: stretch;
        gap: 2px;
        margin: 0;
        padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
        background: var(--surface);
        border-top: 1px solid var(--border);
        box-shadow: 0 -8px 24px rgba(22, 32, 46, 0.07);
    }
    .main-nav .nav-link {
        flex: 1 1 0;
        min-width: 0;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 7px 2px 6px;
        font-size: 10.5px;
        font-weight: 700;
        border-radius: 14px;
        text-align: center;
    }
    .main-nav .nav-link:hover { background: none; }

    /* Текущий раздел — «таблетка» за иконкой и акцентный цвет подписи, как
       в нижних панелях мобильных приложений. Подсвечиваем именно иконку, а
       не всю высокую плитку: закрашенный прямоугольник во всю высоту панели
       выглядел бы тяжело и спорил бы с точками-уведомлениями.
       Отступы у иконки заданы у ВСЕХ пунктов, а не только у активного —
       иначе при переходе подписи прыгали бы на несколько пикселей. */
    .main-nav .nav-link .nav-icon {
        box-sizing: content-box;
        padding: 4px 16px;
        border-radius: 999px;
        transition: background-color .2s ease, color .2s ease;
    }
    .main-nav .nav-link.is-active { background: none; color: var(--accent-dark); }
    .main-nav .nav-link.is-active .nav-icon { background: var(--accent-bg); color: var(--accent); }
    .main-nav .nav-link.is-active span { font-weight: 800; }
    /* Точка-уведомление — в правом верхнем углу иконки, поверх таблетки.
       Обычная (строчная) точка в пункте-столбце вставала отдельной строкой
       под подписью и сдвигала её вверх относительно соседних пунктов. */
    .main-nav .nav-link > .nav-dot {
        position: absolute;
        top: 6px;
        left: calc(50% + 13px);
        margin: 0;
        box-shadow: 0 0 0 2px var(--surface);
    }
    /* Отклик на нажатие — та же таблетка, но только на время касания.
       СВОЙ класс, а не псевдокласс :active: на iOS переключение приложений
       иногда начинается системным жестом прямо над таббаром (смахивание
       снизу), и touchend/pointerup в этом случае браузер не присылает —
       :active у пункта, на который в этот момент попал палец, "залипает"
       и выглядит как is-active (тот же var(--accent-bg)) до следующего
       касания где угодно ещё. Снаружи это читалось как «два раздела горят
       синим сразу». JS ниже (includes/header.php) сам снимает .is-pressed
       по pointerup/cancel/leave и, для верности, при возврате в приложение
       из фона — то, чего с нативным :active сделать нельзя. */
    .main-nav .nav-link.is-pressed { background: none; }
    .main-nav .nav-link.is-pressed .nav-icon { background: var(--accent-bg); }
    .main-nav .nav-link span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
    .nav-icon { width: 22px; height: 22px; }
    .nav-dropdown { flex: 1 1 0; width: auto; }
    .nav-dropdown > summary.nav-link { width: 100%; justify-content: center; }
    .nav-dropdown[open] > summary { background: none; color: var(--accent-dark); }
    .nav-dropdown[open] > summary .nav-icon { background: var(--accent-bg); color: var(--accent); }

    /* Лист "Ещё" открывается ВВЕРХ от таббара, а не вниз за экран */
    .nav-dropdown-menu {
        position: fixed;
        top: auto;
        bottom: calc(72px + env(safe-area-inset-bottom, 0px));
        right: 10px;
        left: 10px;
        width: auto;
        max-height: min(65vh, 460px);
        max-height: min(65dvh, 460px); /* см. комментарий у .nav-dropdown-menu выше по файлу */
        border-radius: var(--radius-sm);
    }
    .nav-dropdown-name {
        display: block;
        padding: 10px 12px 8px;
        font-size: 13px;
        font-weight: 700;
        color: var(--muted);
        border-bottom: 1px solid var(--border);
        margin-bottom: 4px;
    }
    .nav-dropdown-theme { display: block; }
}


/* ══════════════════════════════════════════════
   МЕНЮ ДЕЙСТВИЙ В СТРОКЕ ТАБЛИЦЫ
   ══════════════════════════════════════════════ */
.cell-actions { position: relative; width: 40px; }
.row-menu[open] { position: relative; z-index: 61; }
.row-menu summary {
    list-style: none;
    cursor: pointer;
    color: var(--muted);
    font-size: 16px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 10px;
    display: inline-block;
}
.row-menu summary::-webkit-details-marker { display: none; }
.row-menu summary:hover { color: var(--accent); background: var(--surface-2); }
.row-menu-body {
    /*
     * position:fixed относительно окна (не относительно .cell-actions —
     * та колонка узкая, всего ~40px, и left/right внутри неё как
     * containing block ломают ширину). Запасные top/right — на случай,
     * если скрипт (placeMenu) на каком-то устройстве не выполнился: тогда
     * меню всё равно откроется в разумном видимом месте у верхнего края,
     * а не пропадёт. При успешном запуске скрипт просто перезаписывает
     * top/left/right точными координатами под конкретную кнопку.
     */
    position: fixed;
    top: 64px;
    right: 12px;
    z-index: 60;
    min-width: 180px;
    max-width: calc(100vw - 24px);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 8px 24px rgba(16, 24, 40, .14);
    padding: 6px;
    display: flex;
    flex-direction: column;
    text-align: left;
}
.row-menu-body a,
.row-menu-body button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    border: none;
    background: none;
    border-radius: 10px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
}
.row-menu-body a:hover,
.row-menu-body button:hover { background: var(--surface-2); text-decoration: none; }
.row-menu-body .danger-link { color: var(--red); }

@media (max-width: 700px) {
    /* Карточка-строка: подсветку даём самой карточке, иначе фон рвётся на куски */
    .lessons-table tbody tr.row-hw-pending {
        background: #fffdf5;
        border-color: #e8dcc0;
        box-shadow: inset 3px 0 0 var(--accent);
    }
    .lessons-table tbody tr.row-hw-pending td { background: transparent; }
    .lessons-table tbody tr.row-hw-pending td:first-child { box-shadow: none; }

    .lessons-table tbody tr.row-no-show {
        background: rgba(220, 38, 38, 0.05);
        border-color: #f4d6d6;
        box-shadow: inset 3px 0 0 rgba(220, 38, 38, 0.45);
    }
    .lessons-table tbody tr.row-no-show td { background: transparent; }
    .lessons-table tbody tr.row-no-show td:first-child { box-shadow: none; }

    .cell-actions { width: auto; position: static; }
    .lessons-table td.cell-actions { justify-content: flex-end; }
    .row-menu-body { left: 12px; right: 12px; width: auto; min-width: 0; }
}

[data-theme="dark"] .lessons-table tbody tr.row-hw-pending {
    background: #1d2536;
    border-color: #35415c;
}
[data-theme="dark"] .lessons-table tbody tr.row-no-show {
    background: rgba(248, 113, 113, .05);
    border-color: #4a2626;
}

/* ══════════════════════════════════════════════
   ОТЧЁТ ДЛЯ РОДИТЕЛЕЙ
   ══════════════════════════════════════════════ */
.report {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 26px 28px;
    box-shadow: var(--shadow);
}
.report-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    padding-bottom: 16px;
    border-bottom: 2px solid var(--accent);
    margin-bottom: 18px;
}
.report-title { font-size: 22px; font-weight: 800; letter-spacing: -.02em; }
.report-period { font-size: 13px; color: var(--muted); margin-top: 2px; }
.report-goal { font-size: 13px; color: var(--accent-dark); font-weight: 600; margin-top: 6px; }
.report-logo { max-height: 46px; }

.report-kpi { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 22px; }
.report-kpi div {
    flex: 1 1 130px;
    background: var(--surface-2);
    border-radius: 14px;
    padding: 12px 14px;
    font-size: 12px;
    color: var(--muted);
}
.report-kpi span {
    display: block;
    font-size: 24px;
    font-weight: 800;
    color: var(--text);
    letter-spacing: -.02em;
    margin-bottom: 2px;
}

.report-h {
    font-size: 14px;
    font-weight: 700;
    margin: 22px 0 8px;
    color: var(--text);
}
.report-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.report-table th {
    text-align: left;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
}
.report-table td { padding: 7px 8px; border-bottom: 1px solid var(--border); }
.report-table tr:last-child td { border-bottom: none; }

.report-footer {
    margin-top: 26px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
    font-size: 11.5px;
    color: var(--muted);
    text-align: center;
}

@media print {
    .site-header, .site-footer-contacts, .no-print, .toast-wrap { display: none !important; }
    body { background: #fff; font-size: 11pt; }
    body::before { display: none; }
    .site-main { padding: 0; max-width: none; }
    .report { border: none; box-shadow: none; padding: 0; }
    .report-kpi div { background: #f7f9fc; }
    .report-table { page-break-inside: auto; }
    .report-table tr { page-break-inside: avoid; }
}

/* Подсказки для комментария к отчёту */
.hint-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.hint-chip {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 6px 12px;
    font: inherit;
    font-size: 12px;
    color: var(--muted);
    cursor: pointer;
    text-align: left;
}
.hint-chip:hover { border-color: var(--accent); color: var(--accent); }

.report-comment {
    margin: 24px 0 0;
    padding: 16px 18px;
    background: var(--accent-bg);
    border-left: 4px solid var(--accent);
    border-radius: 14px;
    font-size: 13.5px;
    line-height: 1.55;
}
.report-comment-label {
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: .07em;
    font-weight: 700;
    color: var(--accent-dark);
    margin-bottom: 6px;
}

/* Группы подсказок для комментария */
.hint-group { margin-top: 12px; }
.hint-group-title {
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-weight: 700;
    color: var(--muted);
    margin-bottom: 5px;
}
.hint-chips { margin-top: 0; }

/* ══════════════════════════════════════════════
   ЭКРАН «СЕГОДНЯ»
   ══════════════════════════════════════════════ */
.today-block {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
    margin-bottom: 16px;
    box-shadow: var(--shadow);
}
/* Свой заголовок карточки — .section-title рассчитан на обычный поток
   страницы и добавляет большой верхний отступ (26px), из-за чего внутри
   карточки появлялась заметная пустота перед текстом */
.today-block-title {
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    margin: 0 0 12px;
}
.today-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
    /* margin-bottom у карточек внутри грида не создаёт видимого отступа
       ПОСЛЕ самого грид-контейнера (особенность CSS Grid) — поэтому отступ
       между строками задаём прямо здесь, а не полагаемся на детей */
    margin-bottom: 16px;
}
/* Без этого блоки внутри грида не сжимаются меньше своего "минимального
   содержимого" (например, двух кнопок в один ряд у "Просит отработку") —
   из-за чего вся страница на телефоне раздувалась шире экрана целиком. */
.today-grid > .today-block { min-width: 0; }
.today-list { display: flex; flex-direction: column; gap: 6px; }
.today-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 9px 10px;
    border-radius: 12px;
    background: var(--surface-2);
}
.today-row-done { background: var(--green-bg); }
.today-row-off  { background: var(--red-bg); }  /* отменённое занятие видно сразу, а не «серым фоном где-то там» */
.today-row-moved{ background: var(--orange-bg); }
.today-row-no_show{ background: var(--red-bg); }

/* Левая часть (имя + подпись) не переносится и не толкает правую часть
   (сумму/кнопки) на отдельную строку — вместо этого длинное имя обрезается
   многоточием. На телефоне это выглядит намного аккуратнее, чем перенос. */
.today-row-main {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
}
.today-row-main-line { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.today-name {
    font-weight: 700;
    font-size: 13.5px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.today-name:hover { color: var(--accent); }
.today-time { font-size: 12px; font-weight: 700; color: var(--muted); flex-shrink: 0; }
.today-sub {
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Правая часть (сумма/бейдж/кнопки) никогда не сжимается и не переносится */
.today-row > .btn, .today-row > b, .today-row > .badge, .today-row > a.muted, .today-row-actions {
    flex-shrink: 0;
}
.today-row-actions { display: flex; gap: 6px; }
/* "Давно не появлялся": подпись идёт не внутри today-row-main, а рядом с
   ним (там нечего показывать вторым пунктом кроме имени) — не даём ей
   сжиматься в ноль и не разрешаем переносить слова посередине */
.today-row > .today-sub { flex-shrink: 0; text-align: right; white-space: nowrap; }
@media (max-width: 480px) {
    .today-row > .today-sub { font-size: 11px; }
}

@media (max-width: 420px) {
    /* На совсем узких экранах подпись убираем — оставляем только имя и суть */
    .today-sub { display: none; }
    .today-row-actions .btn { padding: 5px 8px; font-size: 12px; }
}

@media (max-width: 900px) {
    .today-grid { grid-template-columns: 1fr; }
}
/* Обёртка ячейки оплаты — на мобильном её содержимое (селект + цена)
   должно вести себя как один flex-элемент, а не два */
/* На десктопе колонка "Оплата" центрирована, как и остальные — align-items
   переключается на flex-end только в мобильной раскладке (там ячейки
   выстраиваются в строку "подпись слева - значение справа") */
.payment-cell { display: flex; flex-direction: column; align-items: center; touch-action: manipulation; }
@media (max-width: 700px) {
    .payment-cell { align-items: flex-end; width: 100%; }
}

/* ══════════════════════════════════════════════
   PWA: баннер установки
   ══════════════════════════════════════════════ */
.install-banner {
    display: none;
    position: fixed;
    left: 50%;
    bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    z-index: 190;
    align-items: center;
    gap: 12px;
    max-width: calc(100vw - 24px);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 12px 14px;
    box-shadow: 0 10px 30px rgba(16, 24, 40, .16);
    font-size: 13px;
}
.install-banner.open { display: flex; }
.install-text { color: var(--text); flex: 1; min-width: 160px; }
.install-close {
    background: none;
    border: none;
    color: var(--muted);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
    flex-shrink: 0;
}
.install-close:hover { color: var(--text); }

@media (max-width: 600px) {
    .install-banner { flex-wrap: wrap; bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
}

/* Невидимая подложка под открытыми меню/попапами — надёжно ловит клик
   мимо, даже если попап визуально накладывается на другой контент */
.ui-backdrop {
    position: fixed;
    inset: 0;
    z-index: 55;
    background: transparent;
}

/* ══════════════════════════════════════════════
   ФИНАНСЫ
   ══════════════════════════════════════════════ */
.finance-kpi { display: flex; gap: 10px; flex-wrap: wrap; }
.finance-kpi > div { flex: 1 1 140px; min-width: 0; }
.finance-kpi-value { display: block; font-size: 22px; font-weight: 800; letter-spacing: -.02em; color: var(--text); word-break: break-word; }
.finance-kpi-label { font-size: 12px; color: var(--muted); }
.finance-kpi-label b { display: inline-block; margin-left: 4px; font-weight: 700; }

.finance-goal { margin-top: 16px; }
.finance-goal-bar { height: 8px; border-radius: 8px; background: var(--gray-bg); overflow: hidden; margin-bottom: 6px; }
.finance-goal-fill { height: 100%; background: var(--accent); border-radius: 8px; }

/* Форма плана: на узком экране в один ряд не помещается (подпись + поле +
   кнопка) — оборачиваем и даём полю тянуться, а не фиксированные 150px,
   из-за которых кнопка "уезжала" за пределы экрана */
.finance-goal-form {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.finance-goal-form label { font-size: 12px; color: var(--muted); flex: 1 1 160px; min-width: 0; }
.finance-goal-form input {
    display: block;
    width: 100%;
    max-width: 200px;
    margin-top: 4px;
    padding: 7px 10px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    box-sizing: border-box;
}
.finance-goal-form button { flex-shrink: 0; }

@media (max-width: 500px) {
    .finance-kpi > div { flex: 1 1 calc(50% - 5px); }
    .finance-goal-form label { flex-basis: 100%; }
    .finance-goal-form input { max-width: none; }
    .finance-goal-form button { width: 100%; }
}

/* ══════════════════════════════════════════════
   ПОЛОСА ЗАГРУЗКИ СВЕРХУ (переходы между страницами)
   ══════════════════════════════════════════════ */
.page-progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0%;
    z-index: 300;
    background: linear-gradient(90deg, var(--accent), #60a5fa);
    box-shadow: 0 0 8px var(--accent);
    opacity: 0;
    pointer-events: none;
}

/* Каркас страницы во время перехода между разделами. Сама «начинка»
   (.sk-*) свёрстана инлайново в includes/header.php — она нужна ещё до
   загрузки этого файла, на самом первом экране приложения; здесь только
   позиционирование оверлея, которое до загрузки CSS никому не нужно.

   z-index: 15 — НИЖЕ шапки (20) и нижнего таббара (45) специально: во
   время загрузки меняется только контент, а навигация остаётся на месте и
   доступна, как в приложении. top выставляется скриптом по фактической
   высоте шапки. */
/* Явный сброс: у элемента задан position/background, и без этого правила
   атрибут hidden в некоторых движках не гасит его надёжно. */
.page-skeleton[hidden] { display: none; }
.page-skeleton {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 15;
    overflow: hidden;
    background: var(--bg);
}

/* Бейдж "Загрузка…" — появляется, только если переход между страницами
   реально затянулся (см. таймаут в includes/header.php), а не при каждом
   клике. Обычный быстрый переход его никогда не видит — страница успевает
   смениться раньше. */
.page-loading-badge {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translate(-50%, 8px);
    z-index: 300;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 16px;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-lift, 0 8px 24px rgba(16,24,40,.14));
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease, transform .25s ease;
}
.page-loading-badge.show { opacity: 1; transform: translate(-50%, 0); }
.page-loading-spinner {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: btn-spin .7s linear infinite;
}
@media (max-width: 760px) {
    /* Над нижним таббаром, а не под ним */
    .page-loading-badge { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) {
    .page-loading-badge { transition: none; }
    .page-loading-spinner { animation: none; }
}

/* ══════════════════════════════════════════════
   СОСТОЯНИЕ КНОПКИ ПРИ ОТПРАВКЕ ФОРМЫ
   ══════════════════════════════════════════════
   Раньше текст кнопки пропадал (color:transparent) и посередине повисала
   одинокая крутящаяся точка — на широких кнопках ("Отправить ученику" и
   т.п.) смотрелось странно, будто кнопка сломалась. Сам факт "идёт
   загрузка" и так уже виден отдельно — полоса сверху страницы и бейдж
   "загрузка…" снизу (см. includes/header.php) — кнопке этого дублировать
   не нужно, достаточно просто заблокировать повторный клик и слегка
   притушить, не трогая её содержимое. */
button[type="submit"].is-loading,
.btn.is-loading {
    opacity: .6;
    pointer-events: none;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .page-progress { transition: none !important; }
}

/* ══════════════════════════════════════════════
   УРОВНИ УЧЕНИКОВ — карточки настроек
   (сама метка рядом с именем рисуется инлайн-стилем в PHP —
   см. student_level_badge() — там она гарантированно круглая
   независимо от каскада; здесь только окружение витрины)
   ══════════════════════════════════════════════ */
.level-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 8px;
    margin-bottom: 24px;
}
/* Карточка уровня — всё друг под другом, а не в строку: строчная
   раскладка (метка + счётчик + две ссылки в одном ряду) не помещалась
   почти ни при какой ширине и "уезжала". */
.level-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 14px 16px;
    box-shadow: var(--shadow);
    border-left: 3px solid var(--lv-color, var(--accent));
}
.level-card-preview { margin-bottom: 8px; }
.level-card-count { font-size: 11.5px; color: var(--muted); margin-bottom: 10px; }
.level-card-actions {
    display: flex;
    gap: 14px;
    font-size: 12.5px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

/* Выбор цвета — компактные кружки, кликабельны через JS (не через
   вложенный input), поэтому используется не <label>, а простой <span>.
   flex-shrink:0 — иначе на узкой форме кружки сплющивались в овалы. */
.color-swatches { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; align-items: center; }
.color-swatch { flex-shrink: 0; }
.color-swatch {
    position: relative;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid transparent;
    transition: transform .12s ease;
}
.color-swatch:hover { transform: scale(1.1); }
.color-swatch::after {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #fff;
    opacity: 0;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,.2);
}
.color-swatch.is-selected { border-color: var(--text); }
.color-swatch.is-selected::after { opacity: 1; }
.color-swatch-custom {
    background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red);
    padding: 0;
}
.color-swatch-custom::after { display: none; }
.color-swatch-custom.is-selected::after {
    opacity: 1;
    display: block;
}
.color-swatch-custom input[type="color"] {
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    position: absolute;
    inset: 0;
    padding: 0;
    border: none;
}

/* Страница "Удаление" — панель массовых действий и колонка действий строки */
.trash-bulk-bar { display: flex; gap: 10px; margin-bottom: 10px; }
.trash-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }

/* ══════════════════════════════════════════════
   СТРАНИЦА "УВЕДОМЛЕНИЯ" — единообразные карточки-блоки
   ══════════════════════════════════════════════ */
.notify-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow);
    max-width: 560px;
    margin-bottom: 16px;
}
.notify-card h2 { margin: 0 0 4px; font-size: 16px; }
.notify-card-warn { border-color: var(--red); }
.notify-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.notify-btn-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.notify-personal {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}
.notify-group-title {
    margin: 22px 0 10px;
    font-size: 13px;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.notify-tpl-card { transition: opacity .15s ease; }
.notify-tpl-disabled { opacity: .5; }

/* Рассылка — выбор получателя в виде трёх плашек вместо голых radio-строк */
.target-picker { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
.target-option {
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 10px 12px;
    cursor: pointer;
    font-size: 13px;
    transition: border-color .12s ease, background .12s ease;
}
.target-option:has(input:checked) { border-color: var(--accent); background: var(--accent-bg); }
.target-option input { margin: 0; flex-shrink: 0; }
.target-sub-block {
    max-height: 240px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px;
    margin-bottom: 14px;
}
@media (max-width: 600px) {
    .target-picker { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════
   Кабинет ученика — компактный ряд: Telegram/ВК/пароль одной строкой,
   а не тремя большими блоками друг под другом
   ══════════════════════════════════════════════ */
.quick-access-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 18px; }
/* position:relative — панель ниже позиционируется абсолютно относительно
   именно этого элемента, а не занимает место в потоке. Без этого
   раскрытая панель растягивала свой <details> под свою же ширину и
   расталкивала соседние чипы в ряду (на мобильном не так заметно, там
   чипы и так переносятся по одному в строку, а на широком экране это
   выглядело как "всё съезжает"). */
.quick-chip-toggle { display: inline-block; position: relative; }
.quick-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
    background: var(--accent-bg);
    color: var(--accent-dark);
    border: 1px solid transparent;
}
.quick-chip::-webkit-details-marker { display: none; }
.quick-chip-on { background: rgba(21,128,61,.12); color: #15803d; }
.quick-chip-muted {
    background: var(--surface-2);
    color: var(--muted);
    text-decoration: none;
}
.quick-chip-muted:hover { color: var(--text); }
.quick-chip-panel {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    /* Выше нижнего таббара (z-index: 45) — раскрытая панель у нижнего края
       экрана должна оставаться видимой и нажимаемой поверх него. */
    z-index: 50;
    width: max-content;
    max-width: min(320px, 85vw);
    padding: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: var(--shadow);
    font-size: 13px;
}
