/* =========================================================================
   Витрина преподавателей /catalog и /catalog/:id — серверный ERB под public-
   лейаутом (Задача 5, SEO-гибрид). Public-лейаут НЕ грузит Vite/Tailwind, поэтому
   продуктовые токены §2 DESIGN.md и стили переносим сюда bespoke — визуальный
   паритет с прежними Catalog.vue / CatalogTeacher.vue.
   Регистр — ПРОДУКТОВЫЙ (§2/§3 DESIGN.md), не витринный: компактная шкала,
   flat-by-default, синий = действие/статус. CSP style_src 'self' 'unsafe-inline':
   inline style="--mono-*" в аватаре допустим, но всё структурное — здесь.
   ========================================================================= */

/* ---- self-hosted Montserrat (те же файлы, что лендинг; только normal-начертания).
   latin-ext нужен для ₽ (U+20BD) и стрелок ↑↓; cyrillic — для русского. ---- */
@font-face{font-family:'Montserrat';font-style:normal;font-display:swap;font-weight:100 900;
  src:url("/fonts/montserrat-cyrillic-wght-normal.woff2") format('woff2-variations');
  unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:'Montserrat';font-style:normal;font-display:swap;font-weight:100 900;
  src:url("/fonts/montserrat-cyrillic-ext-wght-normal.woff2") format('woff2-variations');
  unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;}
@font-face{font-family:'Montserrat';font-style:normal;font-display:swap;font-weight:100 900;
  src:url("/fonts/montserrat-latin-wght-normal.woff2") format('woff2-variations');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Montserrat';font-style:normal;font-display:swap;font-weight:100 900;
  src:url("/fonts/montserrat-latin-ext-wght-normal.woff2") format('woff2-variations');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}

/* Знак рубля (U+20BD) — своим микро-subset'ом на 3.6 КБ вместо 70 КБ latin-ext,
   в котором он живёт. Объявлен ПОСЛЕ latin-ext намеренно: при пересечении
   unicode-range побеждает последнее объявление (см. landing.css). */
@font-face{font-family:'Montserrat';font-style:normal;font-display:swap;font-weight:100 900;
  src:url("/fonts/montserrat-rub-wght-normal.woff2") format('woff2-variations');
  unicode-range:U+20BD;}

/* ---- Токены §2 DESIGN.md (синхронно с app/frontend/entrypoints/application.css) ---- */
:root{
  color-scheme: light dark;
  --c-bg:#F5F7F9; --c-surface:#FFFFFF; --c-surface-2:#EDF1F4;
  --c-border:#DCE2E8; --c-border-strong:#C4CDD6;
  --c-text:#1A2230; --c-muted:#5B6675;
  --c-accent:#008CD2; --c-accent-ink:#0A6FA8; --c-accent-soft:#D6ECF8;
  --c-warn:#8A5A06; --c-crit:#B23A32; --c-crit-soft:#F3DBD8;
  --r-md:6px; --r-lg:8px; --r-xl:12px; --r-full:9999px;
  --sh-sm:0 1px 2px rgba(0,0,0,.05);
  --sh-md:0 8px 24px rgba(0,0,0,.12); /* выпадашки/поповеры (дропдаун фильтра) */
  /* Главная кнопка на accent-ink: белый текст на --c-accent давал 3.7:1, ниже AA. */
  --btn-primary-bg:var(--c-accent-ink); --btn-primary-fg:#fff; --btn-primary-hover:#075A89;
}
/* Тёмная тема — как в приложении: системная (ОС тёмная и явно не выбрана светлая)
   ИЛИ явный data-theme="dark". Роли и контраст ≥ AA сохранены (The Two-Theme Rule). */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --c-bg:#0F1319; --c-surface:#171C24; --c-surface-2:#1E242D;
    --c-border:#29313C; --c-border-strong:#3A4450;
    --c-text:#E7EBF1; --c-muted:#98A2B0;
    --c-accent:#33A8E0; --c-accent-ink:#5CBEEC; --c-accent-soft:#0C2C3E;
    --c-warn:#D6A34A; --c-crit:#E37167; --c-crit-soft:#3A1F1C;
    /* В тёмной теме accent-ink светлый: текст на нём — цвет фона (#0F1319), ≥ 4.5:1. */
    --btn-primary-fg:var(--c-bg); --btn-primary-hover:var(--c-accent);
  }
}
:root[data-theme="dark"]{
  color-scheme: dark;
  --c-bg:#0F1319; --c-surface:#171C24; --c-surface-2:#1E242D;
  --c-border:#29313C; --c-border-strong:#3A4450;
  --c-text:#E7EBF1; --c-muted:#98A2B0;
  --c-accent:#33A8E0; --c-accent-ink:#5CBEEC; --c-accent-soft:#0C2C3E;
  --c-warn:#D6A34A; --c-crit:#E37167; --c-crit-soft:#3A1F1C;
  --btn-primary-fg:var(--c-bg); --btn-primary-hover:var(--c-accent);
}
:root[data-theme="light"]{ color-scheme: light; }

*{box-sizing:border-box;}
html{background:var(--c-bg);-webkit-text-size-adjust:100%;}
body{margin:0;background:var(--c-bg);color:var(--c-text);
  font-family:'Montserrat',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  font-size:.875rem;line-height:1.45;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;}
img{max-width:100%;display:block;}
a{color:inherit;text-decoration:none;}
:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px;}

/* ---- Каркас (sticky-footer: main тянется, футер прижат вниз) ---- */
.catalog{min-height:100vh;display:flex;flex-direction:column;
  background:var(--c-bg);color:var(--c-text);}
.catalog__topbar{display:flex;align-items:center;justify-content:space-between;gap:12px;
  border-bottom:1px solid var(--c-border);background:var(--c-surface);padding:12px 16px;}
.catalog__brand{flex:0 0 auto;display:inline-flex;}
.catalog__logo{height:32px;width:auto;}
/* Вторичный CTA в шапке: контурная кнопка (/prepodavatelyam, /zal), в каталоге —
   тихая ссылка (модификатор --quiet ниже). nowrap + компактный паддинг на мобиле, чтобы не
   переполнять шапку на 360px. */
.catalog__topbar-cta{flex:0 0 auto;white-space:nowrap;}
/* Тихая CTA каталога: без рамки и заливки, но с целью касания 44px. */
.catalog__topbar-cta--quiet{display:inline-flex;align-items:center;min-height:44px;padding:0 12px;
  border-radius:var(--r-md);color:var(--c-accent-ink);font-size:.875rem;font-weight:600;
  transition:background-color .15s ease;}
.catalog__topbar-cta--quiet:hover{background:var(--c-surface-2);}
/* Скип-линк: первым в порядке Tab, виден только в фокусе. */
.skip-link{position:absolute;top:-100%;left:8px;z-index:30;padding:12px 16px;border-radius:var(--r-md);
  background:var(--c-surface);color:var(--c-accent-ink);font-weight:600;box-shadow:var(--sh-md);}
.skip-link:focus{top:8px;}
.catalog__main{flex:1 1 auto;width:100%;max-width:72rem;margin-inline:auto;padding:32px 16px;}
/* Листинг и анкета чуть уже: 70rem. /prepodavatelyam и /zal остаются на 72rem. */
.catalog--listing .catalog__main,.catalog--card .catalog__main{max-width:70rem;}
.catalog__main--narrow{max-width:48rem;}
.catalog__h1{margin:0 0 8px;font-size:1.5rem;font-weight:700;line-height:2rem;
  letter-spacing:-.01em;color:var(--c-text);text-wrap:balance;}
/* Лид-абзац под H1 (только index): ориентирует пользователя + SEO-текст. */
.catalog__lead{margin:0 0 24px;max-width:60ch;color:var(--c-muted);
  font-size:.875rem;line-height:1.55;text-wrap:pretty;}
/* impeccable: подсказка о нераспознанном ?locality= — нейтральная информационная строка,
   не алерт: тот же приглушённый тон, что у лида, но на мягкой плашке (surface-2, без
   акцентной рамки/полосы), чтобы отличаться от лида и не пугать warn/crit-цветом. */
.catalog__notice{margin:0 0 24px;max-width:60ch;padding:10px 14px;border-radius:var(--r-md);
  background:var(--c-surface-2);color:var(--c-muted);font-size:.875rem;line-height:1.5;text-wrap:pretty;}
/* Плашка превью для владельца (/owner/catalog/:id/preview): заметна, но не страница
   ошибки. В каталоге нет warn-токена, поэтому акцентная мягкая плашка из токенов обеих тем. */
.preview-plate{margin:0 0 16px;padding:10px 14px;border-radius:var(--r-md);
  background:var(--c-accent-soft);color:var(--c-text);border:1px solid var(--c-accent);
  font-size:.875rem;line-height:1.5;}
/* Инлайновые ссылки в текстовых блоках витрины (лид, подсказка о городе,
   параграфы пустого состояния) выглядели обычным текстом: цвет наследуется
   от приглушённого родителя, а глобальное a{text-decoration:none} (выше)
   гасит подчёркивание — перелинковка, ради которой блок существует,
   человеку не видна (класс дефекта, найдено ревью на «Показать все
   города», п.4, распространено на «Популярные направления»/«Все
   направления», п.5). Один паттерн на контейнер, а не класс на ссылке:
   новая ссылка внутри .catalog__lead/.catalog__notice/.catalog__empty p
   получает верный вид сама, ничего отдельно помнить не нужно. */
.catalog__lead a,.catalog__notice a,.catalog__empty p a{
  color:var(--c-accent-ink);font-weight:600;text-decoration:none;}
.catalog__lead a:hover,.catalog__notice a:hover,.catalog__empty p a:hover{
  text-decoration:underline;}
/* Приглашение преподавателю под лидом: адресат не покупатель, поэтому тихая строка
   без плашки и кнопки, ближе к лиду, чем к фильтрам. */
.catalog__lead:has(+ .catalog__invite){margin-bottom:6px;}
.catalog__invite{margin:0 0 24px;max-width:60ch;color:var(--c-muted);font-size:.8125rem;line-height:1.5;}
.catalog__invite a{color:var(--c-accent-ink);font-weight:600;}
.catalog__invite a:hover{text-decoration:underline;}
/* Перелинковка под выдачей: полные списки направлений и городов. Обычные <a href>,
   всегда раскрыты — краулеру и человеку нужна видимая ссылка. Подзаголовки — ступень
   Label без капса (DESIGN.md: капс-кикер над группой запрещён). */
.catalog__links{margin-top:48px;padding-top:28px;border-top:1px solid var(--c-border);}
.catalog__links-title{margin:0 0 16px;font-size:1.125rem;font-weight:700;letter-spacing:-.01em;color:var(--c-text);}
.catalog__links-wrap{display:grid;grid-template-columns:3fr 1fr;gap:32px;}
/* На городском срезе городов нет — направления занимают всю ширину, без пустой колонки. */
.catalog__links-wrap > :only-child{grid-column:1 / -1;}
.catalog__links-sub{margin:0 0 8px;font-size:.75rem;font-weight:600;color:var(--c-muted);}
.catalog__links-list{margin:0;padding:0;list-style:none;font-size:.875rem;line-height:1.5;}
.catalog__links-list li{break-inside:avoid;padding:3px 0;}
.catalog__links-list--cols{columns:3;column-gap:24px;}
.catalog__links-list a{color:var(--c-accent-ink);}
.catalog__links-list a:hover{text-decoration:underline;}
@media (max-width:640px){
  .catalog__links-wrap{grid-template-columns:1fr;gap:20px;}
  .catalog__links-list--cols{columns:2;}
}
@media (max-width:400px){
  .catalog__topbar{padding:12px;}
  .catalog__topbar-cta{padding:8px 12px;}
}

/* ---- Фильтры (GET-форма, без JS) ----
   Телефон: «Курс» на всю строку и кнопка «Фильтры · N» рядом; остальное в <details>.
   С 900px details рисуется display:contents, summary скрыт — все селекты в одну строку. */
.catalog__filters{display:flex;flex-wrap:wrap;align-items:flex-end;gap:8px;margin-bottom:12px;}
.catalog__course{flex:1 1 12rem;display:flex;flex-direction:column;}
.catalog__course select{width:100%;}
.catalog__sort,.catalog__locality,.catalog__district,.catalog__format{display:inline-flex;flex-direction:column;gap:4px;
  font-size:.75rem;font-weight:600;color:var(--c-muted);}
.catalog__filters select{appearance:none;font:inherit;font-size:.875rem;font-weight:400;min-height:44px;
  color:var(--c-text);background:var(--c-surface);
  border:1px solid var(--c-border-strong);border-radius:var(--r-md);
  padding:8px 34px 8px 12px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a8698' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .7rem center;background-size:1.1rem;}
.catalog__filters select:focus-visible{border-color:var(--c-accent);}
.catalog__more{display:contents;}
.catalog__more > summary{min-height:44px;list-style:none;}
.catalog__more > summary::-webkit-details-marker{display:none;}
.catalog__more[open] > summary{background:var(--c-surface-2);}
/* Закрытый details прячет тело сам; открытое тело встаёт отдельной строкой под курсом. */
.catalog__more-body{flex:1 1 100%;order:1;display:flex;flex-wrap:wrap;gap:8px;}
.catalog__more-body > label{flex:1 1 10rem;}
.catalog__apply{min-height:44px;}
@media (min-width:900px){
  .catalog__course{flex:0 1 16rem;}
  /* summary прячем только при JS: скрипт держит details открытым. Без JS кнопка
     «Фильтры» остаётся и раскрывает фильтры нативно. */
  .catalog__filters--js .catalog__more > summary{display:none;}
  .catalog__more-body{display:contents;}
  .catalog__more-body > label{flex:0 1 auto;}
}
/* Apply-on-change: при активном JS кнопка «Показать» не нужна (фильтр применяется
   сразу по change). Без JS правило не срабатывает — кнопка остаётся фолбэком. */
.catalog__filters--js .catalog__apply{display:none;}
/* Строка счётчика над выдачей. */
.catalog__count{margin:0 0 8px;font-size:.8125rem;color:var(--c-muted);}
.catalog__count a{color:var(--c-accent-ink);font-weight:600;}
.catalog__count a:hover{text-decoration:underline;}
@media(max-width:899px){.catalog__count a{display:inline-flex;align-items:center;min-height:44px;margin-block:-14px;}}

/* ---- Кнопки (§5 DESIGN.md) ---- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:8px 16px;border-radius:var(--r-md);border:1px solid var(--c-border-strong);
  background:var(--c-surface);color:var(--c-text);
  font:inherit;font-size:.875rem;font-weight:600;line-height:1.25rem;cursor:pointer;
  transition:background-color .15s ease,border-color .15s ease,color .15s ease;}
.btn:hover{background:var(--c-surface-2);}
.btn--primary{background:var(--btn-primary-bg);border-color:var(--btn-primary-bg);color:var(--btn-primary-fg);}
.btn--primary:hover{background:var(--btn-primary-hover);border-color:var(--btn-primary-hover);}

/* ---- Пустое состояние (приглашение, не ошибка — §Design Principles) ---- */
.catalog__empty{display:flex;flex-direction:column;align-items:center;gap:12px;
  max-width:48rem;margin-inline:auto;padding:32px 20px;text-align:center;
  background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-xl);}
.catalog__empty h2{margin:0;font-size:1.125rem;font-weight:700;line-height:1.35;color:var(--c-text);text-wrap:balance;overflow-wrap:anywhere;}
.catalog__empty p{margin:0;max-width:44ch;color:var(--c-muted);line-height:1.55;}
.catalog__empty .btn--primary{margin-top:4px;min-height:44px;}
/* Приглашение преподавателю в пустой выдаче — тихая ссылка под главной кнопкой. */
.catalog__empty-invite{display:inline-flex;align-items:center;min-height:44px;
  color:var(--c-accent-ink);font-size:.8125rem;font-weight:600;}
.catalog__empty-invite:hover{text-decoration:underline;}

/* ---- Список преподавателей: строки (спека 2026-10-18, §2) ----
   Имя класса .catalog__grid держат спеки. Одна колонка на телефоне (четыре строки в
   первом экране 390×844), с 900px две. */
.catalog__grid{list-style:none;margin:0;padding:0;display:grid;gap:8px;grid-template-columns:1fr;}

/* ---- Карточка преподавателя (страница анкеты) ---- */
.tcard{background:var(--c-surface);border:1px solid var(--c-border);
  border-radius:var(--r-xl);padding:20px;box-shadow:var(--sh-sm);}
.tcard__name{margin:0;font-size:1.125rem;font-weight:600;color:var(--c-text);}
.tcard__name a{color:inherit;text-decoration:none;}
/* --c-accent-ink вместо --c-accent (задача 20b/9): чистый --c-accent на белом
   фоне даёт ~3.7:1 — ниже нормы AA 4.5:1 для текста. */
.tcard__name a:hover{color:var(--c-accent-ink);text-decoration:underline;}
.tcard__name a:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px;}
.tcard__meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;
  font-size:.875rem;color:var(--c-muted);}
.tcard__meta b{font-weight:600;color:var(--c-text);}
.catalog__elsewhere{margin-top:40px;}
.catalog__elsewhere-title{margin:0 0 16px;font-size:1.125rem;font-weight:700;letter-spacing:-.01em;color:var(--c-text);}
/* Значок просмотров: иконка глаза + число. tabular-nums, чтобы в выдаче числа
   разной длины не дёргали иконку по горизонтали. */
.tviews{display:inline-flex;align-items:center;gap:5px;
  font-size:.875rem;color:var(--c-muted);font-variant-numeric:tabular-nums;}
.tviews svg{width:14px;height:14px;flex:none;}

/* ---- Строка-карточка списка ----
   Вся строка — ссылка на анкету через stretched link: ::after ссылки имени растянут на
   .trow (position:relative). Чипы курсов поднимаются над оверлеем своим z-index, иначе
   клик по чипу открыл бы анкету. Высота строки на 390px — 130–150px: аватар 88px,
   паддинг 10px, плотные строки текста. */
.trow{position:relative;display:grid;grid-template-columns:88px minmax(0,1fr);gap:10px;align-items:center;
  padding:10px 28px 10px 10px;background:var(--c-surface);border:1px solid var(--c-border);
  border-radius:var(--r-xl);transition:border-color .15s ease,background-color .15s ease;}
.trow:hover{border-color:var(--c-border-strong);}
/* Отклик на тап: на телефоне hover нет, без него нажатие на строку ничем не отвечает. */
.trow:active{background:var(--c-surface-2);}
/* Фокус рисуем на всей строке: обводка вокруг одного имени не показывала бы, что
   кликабельна строка целиком. */
/* Под @supports: без :has браузер оставит свою обводку на ссылке имени. */
@supports selector(:has(*)){
  .trow:has(.trow__link:focus-visible){outline:2px solid var(--c-accent);outline-offset:2px;}
  .trow .trow__link:focus-visible{outline:none;}
}
.trow__link::after{content:"";position:absolute;inset:0;border-radius:inherit;}
.trow__ava .tavatar{width:88px;height:88px;border-radius:var(--r-xl);}
.trow__ava .tavatar__initials{font-size:1.5rem;}
.trow__ava .tavatar__note{font-size:1.25rem;right:.375rem;}
.trow__body{display:flex;flex-direction:column;gap:2px;min-width:0;}
.trow .tcard__name{font-size:1rem;font-weight:700;line-height:1.25;color:var(--c-text);overflow-wrap:anywhere;}
.trow:hover .tcard__name a{color:var(--c-accent-ink);text-decoration:none;}
.trow__line{display:flex;flex-wrap:wrap;align-items:center;gap:2px 12px;margin:0;line-height:1.35;}
.trow__line .trating,.trow__line .tviews{font-size:.8125rem;}
/* Чипы в строке — одной линией: перенос раздувал бы строку по высоте. Длинное название
   обрезается многоточием. */
.trow .chips{flex-wrap:nowrap;overflow:hidden;gap:4px;margin:2px 0;}
.trow .chips > li{min-width:0;flex:0 1 auto;}
.trow .chip{display:block;padding:2px 8px;line-height:1.125rem;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;}
.trow .chip--link{position:relative;z-index:1;}
.trow .chip--link:focus-visible{outline-offset:-2px;}
.trow .chip--more{flex:none;}
.trow__geo,.trow__facts{margin:0;font-size:.8125rem;line-height:1.35;color:var(--c-muted);}
.trow__price{margin:0;font-size:.875rem;font-weight:700;line-height:1.35;color:var(--c-text);}
.trow__price b{font-weight:700;}
.trow__chev{pointer-events:none;position:absolute;right:14px;top:50%;width:9px;height:9px;margin-top:-5px;
  border-right:2px solid var(--c-border-strong);border-top:2px solid var(--c-border-strong);transform:rotate(45deg);}
@media (min-width:900px){
  .catalog__grid{grid-template-columns:1fr 1fr;}
  .trow{padding-right:12px;gap:12px;}
  .trow__chev{display:none;}
}

/* ---- Страница анкеты (show, спека 2026-10-18-catalog-student-first, §3) ----
   Шапка: аватар 96px слева, имя/курсы/факты/цена справа, под ними на всю ширину кнопка
   «Связаться» и условия контакта. С 900px — две колонки: анкета и липкая боковая колонка
   с той же кнопкой и похожими; кнопка шапки там скрыта, полоса внизу тоже. */
/* Запас под липкую полосу (её высота 65px) — у подвала, а не у main: под main идёт
   подвал, и полоса закрыла бы его кнопку в самом низу. Фон подвала уходит под полосу,
   без пустой полоски фона страницы между ними. */
.catalog--card .catalog__footer{padding-bottom:calc(65px + env(safe-area-inset-bottom));}
.tback{display:inline-flex;min-height:44px;align-items:center;margin:-8px 0 8px;
  font-weight:600;color:var(--c-accent-ink);}
.tback:hover{text-decoration:underline;}
.tcard--page{display:flex;flex-direction:column;min-width:0;}
.thead{display:grid;grid-template-columns:96px minmax(0,1fr);gap:12px 14px;align-items:start;}
.tcard__avatar{position:relative;}
.tcard__avatar .tavatar{width:96px;height:96px;border-radius:var(--r-xl);}
.tcard__avatar .tavatar__initials{font-size:1.75rem;}
.tcard__avatar .tavatar__note{font-size:1.375rem;right:.375rem;}
.tcard__zoom{position:absolute;inset:0;width:100%;height:100%;padding:0;border:0;
  background:transparent;border-radius:var(--r-xl);cursor:zoom-in;}
.tcard__zoom:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px;}
.tcard__body{display:flex;flex-direction:column;gap:6px;min-width:0;}
.tcard__body .tcard__name{font-size:1.375rem;font-weight:700;line-height:1.2;letter-spacing:-.01em;overflow-wrap:anywhere;text-wrap:balance;}
.thead__meta{margin:0;font-size:.8125rem;line-height:1.5;color:var(--c-muted);}
.thead__meta .tviews,.thead__meta .trating{font-size:.8125rem;vertical-align:-1px;}
.thead__fact:not(:last-child)::after{content:" ·";}
.tprice{margin:0;font-size:.875rem;color:var(--c-muted);}
.tprice b{font-size:1.125rem;font-weight:700;color:var(--c-text);}
.tcta{grid-column:1/-1;display:flex;flex-direction:column;gap:8px;margin-top:4px;}
.tcta .btn{width:100%;min-height:44px;}
.tcta__note{margin:0;font-size:.8125rem;line-height:1.5;color:var(--c-muted);text-wrap:pretty;}
.tcard--page .tsection{margin-top:20px;padding-top:20px;border-top:1px solid var(--c-border);}
/* Боковая колонка: до 900px в ней только похожие, под анкетой. */
.taside{display:flex;flex-direction:column;gap:24px;min-width:0;margin-top:32px;}
.taside__cta{display:none;}
.taside .tsection{margin-top:0;}
.taside__who{display:flex;align-items:center;gap:12px;}
.taside__ava{flex:none;width:48px;}
.taside__ava .tavatar{width:48px;height:48px;border-radius:var(--r-lg);}
.taside__ava .tavatar__initials{font-size:1rem;}
.taside__ava .tavatar__note{display:none;}
.taside__name{display:flex;flex-direction:column;min-width:0;font-size:.8125rem;line-height:1.35;}
.taside__name b{font-size:.9375rem;font-weight:700;color:var(--c-text);overflow-wrap:anywhere;}
.taside__cta .btn{width:100%;min-height:44px;}
/* Липкая полоса: fixed, а не sticky — как панель решения владельца. sticky держится
   только внутри своего родителя и отпускает полосу у подвала, а кнопка нужна до
   конца страницы. Прячется, пока видна кнопка шапки или открыт баннер cookie
   (catalog_card.js); [hidden] явным селектором, иначе свой display перебивает атрибут. */
.tbar{position:fixed;left:0;right:0;bottom:0;z-index:20;background:var(--c-surface);
  border-top:1px solid var(--c-border);padding:10px 16px calc(10px + env(safe-area-inset-bottom));
  display:flex;justify-content:space-between;align-items:center;gap:12px;}
.tbar[hidden]{display:none;}
.tbar__price{min-width:0;}
.tbar .btn{flex:none;min-height:44px;padding-inline:24px;}
@media (min-width:640px){
  .tcard__body .tcard__name{font-size:1.5rem;}
}
@media (min-width:900px){
  .catalog--card .catalog__footer{padding-bottom:0;}
  /* Аватар 120px — вместе с колонкой 120px: раньше колонки он наезжал на имя. */
  .thead{grid-template-columns:120px minmax(0,1fr);}
  .tcard__avatar .tavatar{width:120px;height:120px;}
  .tpage{display:grid;grid-template-columns:minmax(0,720px) 320px;gap:48px;align-items:start;}
  /* Липнет вся колонка, а не один CTA: липкий CTA в потоке ездит поверх «Похожих»
     под ним. На низком окне колонка прокручивается сама, низ «Похожих» не теряется. */
  .taside{margin-top:0;position:sticky;top:20px;max-height:calc(100vh - 40px);overflow-y:auto;}
  .taside__cta{display:flex;flex-direction:column;gap:12px;padding:20px;background:var(--c-surface);
    border:1px solid var(--c-border);border-radius:var(--r-xl);box-shadow:var(--sh-sm);}
  .thead .tcta{display:none;}
  .tbar{display:none;}
}

/* ---- Хлебные крошки (label-шкала: xs, muted; §3 DESIGN) ---- */
.crumbs{margin:0 0 16px;font-size:.75rem;line-height:1.4;}
.crumbs__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px;}
.crumbs__item{display:flex;align-items:baseline;gap:6px;color:var(--c-muted);}
.crumbs__item + .crumbs__item::before{content:"/";color:var(--c-muted);}
/* --c-accent-ink, не --c-accent (тот же приём, что у .tcard__name a:hover выше
   по файлу): чистый --c-accent на белом даёт ~3.7:1 — ниже AA 4.5:1 для текста
   ссылки. accent-ink даёт 5.45:1 в светлой теме и остаётся ≥ AA в тёмной. */
.crumbs__item a{color:var(--c-accent-ink);font-weight:600;text-decoration:none;}
.crumbs__item a:hover{text-decoration:underline;}

/* ---- Чипы курсов (label-шкала: xs semibold muted, §3) ---- */
.chips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px;}
.chip{padding:4px 10px;border-radius:var(--r-full);background:var(--c-surface-2);
  font-size:.75rem;font-weight:600;color:var(--c-muted);}
/* Кликабельный чип обязан выглядеть кликабельным: без hover/focus получился бы
   элемент-ссылка без единого признака ссылки (бэклог 2026-08-16, п.2, «Гоча»). */
/* display:block, не inline-block (находка финального ревью, необязательный пункт):
   родитель — голый <li> (флекс-элемент .chips), inline-block внутри него формирует
   анонимную line-box с vertical-align:baseline и оставляет запас под дескендер —
   строка чипов на карточке становилась выше грида на ~4px. Блок убирает line-box
   целиком, высота <li> берётся из паддинга/line-height самой ссылки. */
.chip--link{display:block;text-decoration:none;transition:background .2s,color .2s;}
/* Находка ревью задачи 2: фон .chip уже залит --c-surface-2, тем же токеном, что
   раньше стоял здесь на hover, — подсветки не было видно ни в одной теме. Берём
   --c-accent-soft — ту же пару «мягкий акцентный фон + --c-accent-ink», что уже
   используют аватар-плейсхолдер (.tavatar__mono) и бейдж просмотров ниже по файлу.
   Текст на hover — c-text, не c-accent-ink (находка финального ревью): accent-ink
   на accent-soft даёт 4.47:1 в светлой теме при пороге AA 4.5:1 для 12px-текста —
   не дотягивает буквально по границе. c-text на том же фоне даёт ~13:1, подчёркивание
   на hover уже есть, аффорданс не теряется. В тёмной теме прежняя пара была в норме
   (6.94:1), но токен один на обе темы. */
.chip--link:hover{background:var(--c-accent-soft);color:var(--c-text);text-decoration:underline;}
.chip--link:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px;}
/* «+N» в строке — просто текст в виде чипа: остальные курсы видны на странице анкеты.
   Курсы после второго лежат в HTML (краулер видит все ссылки), но на экране скрыты. */
.chips > li[data-chip-extra]{display:none;}
.chip--more{cursor:default;}

.tabout{margin:20px 0 0;max-width:70ch;color:var(--c-muted);font-size:.875rem;line-height:1.55;}

/* ---- Секции детальной анкеты ---- */
.tsection{margin-top:24px;}
.tsection h2{margin:0 0 8px;font-size:1.125rem;font-weight:600;color:var(--c-text);}
.tlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px;
  font-size:.875rem;line-height:1.5;color:var(--c-text);}
.muted{color:var(--c-muted);}

/* Методика — свободный текст до 3000 символов: переносы строк, которые ввёл
   преподаватель, должны сохраняться. */
.tmethodology{white-space:pre-line;margin:0;font-size:.875rem;line-height:1.5;color:var(--c-text);}

/* Сертификаты и дипломы. Плитка квадратная, скан вписан целиком (contain): пропорции
   сертификатов разные, резать их нельзя, а явные width/height у img держат место без
   сдвига вёрстки. Плитка — кнопка лайтбокса, поэтому своя рамка, фон и курсор. */
.tcerts{list-style:none;margin:0;padding:0;display:grid;gap:12px;
  grid-template-columns:repeat(auto-fill,minmax(140px,1fr));}
.tcerts__btn{display:block;width:100%;padding:0;border:1px solid var(--c-border);
  border-radius:var(--r-lg);background:var(--c-surface-2);cursor:zoom-in;overflow:hidden;}
.tcerts__btn:hover{border-color:var(--c-border-strong);}
.tcerts__btn:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px;}
.tcerts__img{display:block;width:100%;height:auto;aspect-ratio:1/1;object-fit:contain;}
.tcerts__caption{margin:6px 0 0;font-size:.75rem;line-height:1.4;color:var(--c-muted);}

/* ---- Аватар: фото 1:1 или монограмма (порт TeacherAvatar.vue) ---- */
.tavatar{position:relative;aspect-ratio:1/1;width:100%;overflow:hidden;
  border-radius:var(--r-lg);background:var(--c-surface-2);}
.tavatar__img{width:100%;height:100%;object-fit:cover;}
.tavatar__mono{display:flex;align-items:center;justify-content:center;
  width:100%;height:100%;background:var(--mono-bg);color:var(--mono-fg);}
.tavatar__initials{font-size:2.25rem;font-weight:700;letter-spacing:.02em;}
.tavatar__note{position:absolute;right:.5rem;bottom:.25rem;
  font-size:1.875rem;opacity:.25;line-height:1;}

/* ---- Футер (общий партиал index/show) ---- */
.catalog__footer{margin-top:48px;border-top:1px solid var(--c-border);
  background:var(--c-surface);}
.catalog__footer-inner{display:flex;flex-wrap:wrap;align-items:center;gap:16px 24px;
  max-width:72rem;margin-inline:auto;padding:24px 16px;}
.catalog__footer-brand{display:flex;flex-direction:column;gap:2px;margin-right:auto;}
.catalog__footer-name{font-size:1.125rem;font-weight:700;color:var(--c-text);}
.catalog__footer-tagline{font-size:.75rem;font-weight:600;color:var(--c-muted);}
.catalog__footer-nav{display:flex;flex-wrap:wrap;gap:8px 20px;}
/* --c-accent-ink, не --c-accent: тот же AA-фикс, что у .crumbs__item a/
   .catalog__lead a выше по файлу (чистый --c-accent на белом ~3.7:1, ниже
   AA 4.5:1 для текста ссылки). Фон футера — --c-surface (белый в светлой
   теме), тот же случай. */
.catalog__footer-link{font-size:.875rem;font-weight:600;color:var(--c-accent-ink);}
.catalog__footer-link:hover{text-decoration:underline;}
.catalog__footer-cta{flex:0 0 auto;white-space:nowrap;}
@media (max-width:400px){
  .catalog__footer-cta{width:100%;}
}

/* Текстовые блоки витрины (FAQ). Раньше это была строка текста
   под тонкой линией — блок читался как обрезок страницы. Теперь карточка на
   surface: та же плоская подача, что у остальной витрины, но с собственными
   границами. Цвета — только токенами, иначе поедет тёмная тема. */
.cblock{margin-top:32px;padding:24px;border:1px solid var(--c-border);
  border-radius:var(--r-xl);background:var(--c-surface);}
.cblock h2{margin:0 0 16px;font-size:1.125rem;font-weight:700;letter-spacing:-.01em;color:var(--c-text);}
/* FAQ живёт в той же карточке .cblock, но вопросы сами дают внутренние отбивки —
   нижний паддинг карточке не нужен. */
.cblock--faq{padding-bottom:8px;}
.cfaq + .cfaq{border-top:1px solid var(--c-border);}
/* display:flex заодно убирает нативный треугольник в WebKit/Blink, поэтому
   индикатор рисуем сами: «+» поворачивается в «×» на открытом вопросе. Без него
   блок выглядел как список жирных строк без намёка, что он раскрывается. */
.cfaq__q{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;
  gap:16px;padding:14px 0;font-size:.875rem;font-weight:600;color:var(--c-text);}
.cfaq__q::-webkit-details-marker{display:none;}
.cfaq__q::after{content:"+";flex:none;font-size:1.125rem;font-weight:400;line-height:1;
  color:var(--c-accent-ink);transition:transform .2s;}
.cfaq[open] .cfaq__q::after{transform:rotate(45deg);}
.cfaq__q:hover{color:var(--c-accent-ink);}
.cfaq__a{margin:0 0 16px;max-width:70ch;color:var(--c-muted);font-size:.875rem;line-height:1.55;}

.csimilar{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px;}
.csimilar__item{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;font-size:.875rem;}
.csimilar__item a{color:var(--c-accent-ink);text-decoration:none;font-weight:600;}
.csimilar__item a:hover{text-decoration:underline;}

/* ---- Reduced motion: гасим все переходы (The Two-Theme Rule + a11y §PRODUCT) ---- */
@media (prefers-reduced-motion:reduce){
  *{transition-duration:.01ms !important;animation-duration:.01ms !important;}
}

/* ---- Звёзды оценки (спека 2026-10-09-teacher-reviews). Закрашенная — semantic warn,
   а не новый бренд-цвет (The One Accent Rule, DESIGN.md). ---- */
.tstars{display:inline-flex;gap:2px;vertical-align:-2px;}
.tstars__star{width:14px;height:14px;fill:var(--c-border-strong);}
.tstars--md .tstars__star{width:18px;height:18px;}
.tstars__star--on{fill:var(--c-warn);}

/* ---- Форма отзыва ---- */
.rform{display:grid;gap:20px;max-width:36rem;}
.rform__fieldset{margin:0;padding:0;border:0;}
.rform__label{display:block;margin-bottom:6px;font-weight:600;color:var(--c-text);}
.rform__field{display:grid;gap:6px;}
.rform__input{width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--c-border-strong);
  border-radius:var(--r-md);background:var(--c-surface);color:var(--c-text);font:inherit;}
.rform__input[readonly]{background:var(--c-surface-2);color:var(--c-muted);}
.rform__hint{margin:0;font-size:.875rem;color:var(--c-muted);}
.rform__errors{margin:0;padding:12px 16px;list-style:none;border-radius:var(--r-md);
  background:var(--c-crit-soft);color:var(--c-crit);display:grid;gap:6px;}
.rform__consent{display:flex;gap:10px;align-items:flex-start;font-size:.9375rem;line-height:1.45;cursor:pointer;}
.rform__consent input{flex:none;width:18px;height:18px;margin:1px 0 0;accent-color:var(--c-accent);cursor:pointer;}
.rform__consent a,.rform__hint a,.catalog__lead a{color:var(--c-accent-ink);text-decoration:underline;}
/* row-reverse: в разметке 5…1, на экране 1…5; «~» красит выбранную и всех левее. */
.rform__stars{position:relative;display:inline-flex;flex-direction:row-reverse;justify-content:flex-end;gap:0;margin-left:-6px;}
.rform__star-input{position:absolute;opacity:0;width:1px;height:1px;margin:0;}
.rform__star{cursor:pointer;padding:6px;line-height:0;} /* 32 + 2×6 = 44px — палец попадает */
.rform__star svg{width:32px;height:32px;fill:var(--c-border-strong);transition:fill .12s;}
.rform__star-input:checked ~ .rform__star svg,
.rform__star:hover svg,.rform__star:hover ~ .rform__star svg{fill:var(--c-warn);}
.rform__star-input:focus-visible + .rform__star{outline:2px solid var(--c-accent);outline-offset:2px;border-radius:var(--r-md);}
.rform__input:focus-visible{outline:2px solid var(--c-accent);outline-offset:0;border-color:var(--c-accent);}
.rform__input::placeholder{color:var(--c-muted);opacity:1;}
.rform__submit{justify-self:start;}
.rform__submit:disabled{opacity:.7;cursor:progress;}
@media (prefers-reduced-motion: reduce){.rform__star svg{transition:none;}}

/* ---- Отзывы на витрине (спека 2026-10-09-teacher-reviews) ---- */
/* Бейдж: на плитке — приглушённая строка, как .tviews; на анкете — ссылка на блок.
   Своя отделка ссылки обязательна: глобальное a{color:inherit} прячет аффорданс. */
.trating{font-size:.875rem;color:var(--c-muted);font-variant-numeric:tabular-nums;}
.trating__avg{font-weight:600;color:var(--c-text);}
.trating__star{color:var(--c-warn);}
a.trating{color:var(--c-accent-ink);text-decoration:underline;text-underline-offset:2px;}
a.trating .trating__avg{color:inherit;}
a.trating:hover{text-decoration-thickness:2px;}
/* Список без карточек: страница анкеты плоская (секции без рамок), отзывы делятся
   тонкой линией, как разделы анкеты. */
.treviews__list{list-style:none;margin:0;padding:0;}
.treview{padding:16px 0;border-top:1px solid var(--c-border);}
.treview:first-child{border-top:0;padding-top:4px;}
/* .treview держит свой display (block у li), поэтому hidden — явным селектором. */
.treview[hidden],.treviews__more[hidden]{display:none;}
.treview__head{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;font-size:.875rem;}
.treview__name{font-weight:600;color:var(--c-text);overflow-wrap:anywhere;}
.treview__date{color:var(--c-muted);}
.treview__body{margin:8px 0 0;max-width:70ch;white-space:pre-line;overflow-wrap:anywhere;
  font-size:.875rem;line-height:1.55;color:var(--c-text);text-wrap:pretty;}
.treview__reply{margin-top:12px;max-width:70ch;padding:12px 14px;border-radius:var(--r-lg);background:var(--c-surface-2);}
.treview__reply-label{margin:0;font-size:.75rem;font-weight:600;color:var(--c-muted);}
.treview__reply .treview__body{margin-top:4px;}
.treviews__more{margin-top:4px;}
.treviews__note{margin:16px 0 0;font-size:.875rem;color:var(--c-muted);}
@media (max-width:480px){.treviews__more{width:100%;}}
