:root{
  /* Светлая тема в духе TMDB: тёмная полоса навигации сверху, белая страница,
     один голубой акцент, зелёный — для оценок. Полоса петрольная (#0f3b42):
     фирменный тёмно-синий TMDB заменён по решению заказчика, а голубой акцент
     затемнён — на белом фоне их #01b4e4 даёт контраст 2,4:1 и не читается
     (проверка контраста считает числа, а не оценивает на вкус). */
  --bg:#ffffff; --bg-soft:#f4f6f8; --panel:#ffffff; --card:#ffffff;
  --line:#e3e3e3; --line-strong:#c9d0d6;
  --bar:#0f3b42; --bar-deep:#0a2b31; --bar-line:#2b5860; --bar-muted:#9fc0c4;
  --text:#0f1a24; --muted:#5a6672;
  --accent:#0b7285; --accent-soft:#e6f4f7; --on-accent:#ffffff;
  --brand-blue:#01b4e4; --brand-green:#90cea1;
  --rate-high:#90cea1; --rate-mid:#f5d67b; --rate-low:#eba1a1;
  --ok:#0f6f45; --warn:#8a6100; --err:#b3261e;
  --shadow:0 1px 2px rgba(15,59,66,.06), 0 8px 24px rgba(15,59,66,.08);
  --radius:12px;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg-soft);color:var(--text);
     font-family:"Segoe UI",Roboto,Arial,sans-serif;font-size:15px;line-height:1.5;
     -webkit-font-smoothing:antialiased}

/* ---------------------------------------------------------------- полоса навигации
   Одна строка, как у TMDB: знак слева, разделы с выпадающими списками, поиск справа.
   Липкая: разделы и поиск остаются на виду при прокрутке длинного каталога. */
.appbar{position:sticky;top:0;z-index:5;background:var(--bar);
        border-bottom:1px solid var(--bar-deep)}
.appbar header{display:flex;align-items:center;gap:14px;padding:10px 22px;
               color:#ffffff;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:10px;color:#ffffff;text-decoration:none;
       cursor:default}
.brand b{font-size:17px;font-weight:700;letter-spacing:-.01em}
/* Метка «демо MVP» убрана: сайт готовится к публичному запуску, и такая надпись в шапке
   сообщала бы о другом состоянии проекта. */
/* Меню ужимается и прокручивается само: при узком окне оно выталкивало поиск, имя
   пользователя и кнопку выхода за край экрана, и страница начинала ехать вбок. */
.mainnav{display:flex;align-items:center;gap:2px;flex:1 1 auto;min-width:0;overflow-x:auto;
         scrollbar-width:none}
.mainnav::-webkit-scrollbar{display:none}
.navitem{position:relative}
.navlink{display:inline-flex;align-items:center;gap:6px;padding:8px 12px;border-radius:8px;
         color:var(--bar-muted);text-decoration:none;font-size:14px;font-weight:600;
         white-space:nowrap}
.navlink:hover{background:var(--bar-deep);color:#ffffff;text-decoration:none}
.navlink.active{background:var(--bar-deep);color:#ffffff;box-shadow:inset 0 -2px 0 var(--brand-green)}
.caret{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;
       border-top:5px solid currentColor;opacity:.75}
.navitem:hover .dropdown,.navitem:focus-within .dropdown{display:block}
/* выпадающий список: белая панель поверх страницы, как подменю разделов у TMDB.
   Цвет текста задаём явно: панель лежит внутри тёмной шапки, и без этого текст наследовал
   белый цвет шапки — белым по белому. Так пропал заголовок фильма в результатах поиска
   (контраст 1:1), и снаружи это выглядело как «поиск показывает только постер». */
.dropdown{display:none;position:absolute;top:100%;left:0;z-index:6;min-width:230px;
          background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:8px;
          color:var(--text);
          box-shadow:0 12px 32px rgba(15,59,66,.18)}
.dropdown a{display:block;padding:8px 10px;border-radius:8px;color:var(--text);font-size:14px;
            text-decoration:none;white-space:nowrap}
.dropdown a:hover{background:var(--bg-soft);text-decoration:none}
.dropdown .drophead{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
                    color:var(--muted);padding:8px 10px 4px}
.dropsep{height:1px;background:var(--line);margin:6px 4px}
.dropgenres{display:flex;flex-wrap:wrap;gap:6px;padding:4px 6px 6px;max-width:260px}

/* поиск в шапке: главный вход в каталог, как у TMDB. Ширина гибкая — иначе на узком
   окне он выдавливал имя пользователя и кнопку выхода за край */
.searchbox{position:relative;margin-left:auto;flex:0 1 230px;min-width:132px}
.navsearch{width:100%;background:var(--bg);border:1px solid var(--bar-line);border-radius:999px;
           padding:8px 14px;font-size:14px;font-family:inherit;color:var(--text)}
.navsearch::placeholder{color:var(--muted)}
.navsearch:focus{outline:none;border-color:var(--brand-green)}
/* Результаты поиска: это тот же выпадающий блок, что и подменю разделов, но показывается он
   не по наведению, а тогда, когда поиск нашёл фильмы и снял атрибут hidden. Общее правило
   .dropdown{display:none} его прятало: поиск в шапке находил фильмы, а человек видел
   пустоту — ровно об этом и была жалоба «поиск наверху не работает». Поэтому показ здесь
   задаём явно, а скрытие — по атрибуту hidden, который ставит сам скрипт. */
.searchresults{display:block;left:auto;right:0;width:360px;max-height:60vh;overflow:auto;
               padding:6px}
.searchresults[hidden]{display:none}
.searchresults .result{display:flex;gap:10px;align-items:center;padding:8px;border-radius:8px;
                       cursor:pointer}
.searchresults .result:hover{background:var(--bg-soft)}
.searchresults .result img{width:34px;height:51px;border-radius:5px;object-fit:cover;
                           border:1px solid var(--line);flex:0 0 34px}
.searchresults .result b{display:block;font-size:14px;font-weight:600}
.searchresults .empty{padding:10px;color:var(--muted);font-size:13.5px}
/* Строка «показаны 8 из 17»: это не результат поиска, а путь к остальным, поэтому она
   отделена линией и ведёт себя как ссылка. */
.searchresults .more{padding:9px 8px 5px;margin-top:4px;border-top:1px solid var(--line);
                     color:var(--accent);font-size:13px;cursor:pointer}
.searchresults .more:hover{text-decoration:underline}
/* В узком окне список результатов привязан к полю справа, а поле стоит не у края окна —
   панель шириной 360 вылезала за левый край экрана (замер показывал x = -39). Поэтому на
   узком окне список растягиваем по окну: читать его в любом случае удобнее так. */
@media (max-width:640px){
  /* top задан числом как запасной вариант, а точный отступ считает скрипт от низа шапки:
     на узком окне шапка переносится на две строки, и её высота меняется. */
  .searchresults{position:fixed;left:10px;right:10px;width:auto;top:64px;max-height:50vh}
}
.whoname{color:var(--bar-muted);font-size:13px;white-space:nowrap}
@media (max-width:900px){.whoname{display:none}}

/* Контент занимает всю ширину окна: центрированная колонка оставляла по бокам пустые
   поля, из-за которых страница выглядела уже, чем окно. Поле сверху и по бокам —
   одинаковое и небольшое. */
main{padding:16px 22px 0;max-width:none;position:relative;z-index:1}

/* ---------------------------------------------------------------- фоновые титры
   Титры идут поверх белого фона крупными строками, как на экране в зале: сначала их было
   не видно вовсе — слой лежал под карточками и начинался ниже экрана, поэтому и «фона нет».
   Теперь слой выше содержимого и ниже шапки, а строки видны сразу.

   Контраст от этого не страдает: затемнение тринадцать процентов поверх белого даёт для
   текста карточек примерно 14:1 при пороге 7:1, а сам слой не принимает щелчки.
   Уровень подобран замером: при восьми процентах разница со снимком без слоя составляла
   всего 18 из 255 — «фон есть, а его не видно». Тринадцать даёт около 28 из 255.
   Мерить так: node tools/shot.mjs --url ... --out with.png --diff without.png,
   затем python tools/shot_stats.py with.png without.png.

   Движение: слой `.shift` сдвигается по прокрутке (это делает скрипт) — плавно, догоняя
   прокрутку по кадрам, и целыми пикселями: на дробных текст мылится и выглядит дрожащим.
   Покачивания внутри нет намеренно: два движения сразу читались как дрожь, а не как кино. */
.credits-bg{position:fixed;inset:0;z-index:2;overflow:hidden;pointer-events:none}
.credits-bg .shift{will-change:transform}
.credits-bg .roll{padding:7vh 22px 0;text-align:center;color:var(--bar);opacity:.13;
                  font-size:clamp(20px,3.6vw,44px);font-weight:700;letter-spacing:.03em;
                  line-height:1.75}
.credits-bg .roll b{display:block;font-size:clamp(12px,1.1vw,15px);font-weight:700;
                    letter-spacing:.4em;text-transform:uppercase;margin-bottom:2vh;opacity:.8}
.credits-bg .roll .roll-title{display:block;font-size:clamp(24px,4.4vw,54px);margin-bottom:1vh}
.credits-bg .roll span{display:block}
.credits-note{margin-top:12px;color:var(--muted);font-size:12.5px}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px;
      margin-bottom:14px;box-shadow:var(--shadow)}
h1{font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.2;margin:0 0 8px}
h2{font-size:19px;font-weight:600;letter-spacing:-.01em;line-height:1.25;margin:0 0 10px}
h3{font-size:16.5px;font-weight:600;line-height:1.3;margin:0 0 12px}
.label{display:block;font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
       color:var(--muted);margin:0 0 6px}
.muted{color:var(--muted)}
.small{font-size:13px;line-height:1.45}
.num{font-variant-numeric:tabular-nums}
.field{width:100%;background:var(--bg);border:1px solid var(--line-strong);border-radius:10px;
       padding:12px;color:var(--text);font-size:15px;margin:6px 0 10px;font-family:inherit}
.field:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.cta{background:var(--accent);border:0;color:#ffffff;font-weight:600;padding:12px 18px;
     border-radius:10px;cursor:pointer;font-family:inherit;font-size:15px}
.cta:hover{background:var(--bar)}
.cta.ghost{background:var(--bg);border:1px solid var(--line-strong);color:var(--accent);font-weight:500}
.cta.ghost:hover{background:var(--bg-soft)}
.ghost{background:var(--bg);border:1px solid var(--line-strong);color:var(--accent);padding:7px 12px;
       border-radius:8px;cursor:pointer;font-size:13px;font-family:inherit}
.ghost:hover{background:var(--bg-soft)}
.list{display:flex;flex-direction:column;gap:10px}
.item{border:1px solid var(--line);border-radius:var(--radius);padding:11px 13px;background:var(--bg)}
.item.head{display:flex;align-items:center;gap:10px}
.item .small{max-width:74ch}
.stars{color:var(--warn);letter-spacing:1px}

/* реакции: своя иконка вместо смайла-глифа — системные шрифты рисуют смайлы по-разному,
   а на части устройств они выходят чёрно-белыми. Иконка берёт цвет от места, где стоит. */
.reaction{display:inline-flex;align-items:center;gap:4px;vertical-align:-4px;color:var(--accent)}
.reaction svg{display:block}
.reaction-text{font-size:15px}
.reactionpick{display:flex;flex-wrap:wrap;gap:8px;margin:6px 0 10px}
.reaction-chip{display:inline-flex;flex-direction:column;align-items:center;gap:2px;
               padding:7px 9px;min-width:64px;cursor:pointer}
.reaction-chip .reaction{color:var(--muted);gap:0}
.reaction-chip .reaction svg{width:24px;height:24px}
.reaction-chip .reaction-label{font-size:11px;color:var(--muted);line-height:1.1}
.reaction-chip.on{background:var(--accent-soft);border-color:var(--accent)}
.reaction-chip.on .reaction,.reaction-chip.on .reaction-label{color:var(--accent);font-weight:600}
.reaction-chip:hover .reaction{color:var(--accent)}
/* Обсуждение записи: список реплик и поле ответа. Отделено полосой слева, чтобы чужой
   отзыв и ответы на него не сливались в один текст. */
.comments{margin-top:8px;border-left:2px solid var(--line);padding-left:10px}
.comments .comments-list{display:block}
.comments .comment{padding:4px 0}
.comments .comment .who{font-weight:600}
.comments .commentform{display:flex;gap:6px;align-items:center;margin-top:6px;flex-wrap:wrap}
.comments .commentform .field{margin:0;flex:1 1 220px}
.action.on{border-color:var(--accent);color:var(--accent);font-weight:600}
.action-count{font-variant-numeric:tabular-nums}
.chips{display:flex;gap:6px;margin:4px 0 10px;flex-wrap:wrap}
.chip{border:1px solid var(--line-strong);border-radius:999px;padding:5px 12px;cursor:pointer;
      background:var(--bg);font-size:13.5px;color:var(--text)}
.chip:hover{border-color:var(--accent)}
.chip.on{background:var(--accent);border-color:var(--accent);color:#ffffff;font-weight:600}
.row{display:flex;gap:8px;align-items:center}
.spacer{flex:1}
.error{color:var(--err);font-size:13.5px;margin-top:8px}
.ok{color:var(--ok)}
.hidden{display:none}
.hr{height:1px;background:var(--line);margin:12px 0}
.switch{width:44px;height:26px;border-radius:16px;background:var(--line-strong);position:relative;
        flex:0 0 44px;cursor:pointer}
.switch i{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#ffffff;
          box-shadow:0 1px 2px rgba(15,59,66,.25)}
.switch.on{background:var(--accent)}
.switch.on i{left:21px}
dialog{border:1px solid var(--line);border-radius:14px;background:var(--bg);color:var(--text);
       max-width:420px;width:92%;padding:18px;box-shadow:0 20px 60px rgba(15,59,66,.28)}
dialog::backdrop{background:rgba(15,59,66,.5)}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
.tag{display:inline-block;border:1px solid var(--line);border-radius:6px;padding:1px 7px;
     font-size:11.5px;color:var(--muted);margin-left:6px;background:var(--bg-soft)}

.rate{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:700;
      font-variant-numeric:tabular-nums;padding:2px 8px;border-radius:999px;
      background:var(--rate-high);color:var(--bar-deep)}
.rate.mid{background:var(--rate-mid)}
.rate.low{background:var(--rate-low)}
.rate span{font-weight:600;opacity:.75}

/* ---------------------------------------------------------------- разделы и страницы */
.view{display:none}
.view.active{display:block}

/* вкладки страницы фильма: текст с подчёркиванием, как «Обзор / Медиа» у TMDB */
.tabs{display:flex;gap:20px;border-bottom:1px solid var(--line);margin:0 0 14px;overflow-x:auto}
.tab{padding:9px 0;color:var(--muted);cursor:pointer;border-bottom:2px solid transparent;
     font-size:14px;font-weight:600;white-space:nowrap}
.tab:hover{color:var(--text)}
.tab.on{color:var(--text);border-bottom-color:var(--accent)}
.tabpanel{padding-top:2px}

/* переключатель вида каталога: сетка или список */
.vtoggle{display:flex;gap:4px;border:1px solid var(--line-strong);border-radius:8px;padding:2px}
.vtoggle .vt{padding:5px 10px;border-radius:6px;cursor:pointer;font-size:13px;color:var(--muted)}
.vtoggle .vt.on{background:var(--accent-soft);color:var(--accent);font-weight:600}

/* сетка постеров: основной вид каталога, как в разделах TMDB */
.postergrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:16px}
.postertile{cursor:pointer;border:0;background:transparent;padding:0;text-align:left;
            font-family:inherit;color:inherit}
.postertile .poster-img{width:100%;height:auto;aspect-ratio:2/3;border-radius:8px;flex:none}
.postertile b{display:block;margin-top:8px;font-size:14px;font-weight:600;line-height:1.3}
.postertile .small{display:block;color:var(--muted);font-size:12.5px}
.postertile .rate{margin-top:6px}
.postertile:hover b{color:var(--accent)}

/* список «хочу посмотреть»: та же плитка, но с двумя действиями — отметить просмотр
   или убрать. Делать это надо прямо в списке: иначе за каждым фильмом приходится
   открывать его страницу, а список для того и нужен, чтобы решить всё на месте. */
.wishitem{cursor:default}
.wishitem .poster-img{cursor:pointer}
.wishacts{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.wishacts button{padding:4px 9px;font-size:12.5px}
.wishsoon{color:var(--accent);font-weight:600}
/* Назначенный просмотр: дата и клуб — главное, что человек хочет видеть у фильма, поэтому
   строка стоит на месте подписи о добавлении, а не рядом с кнопками. */
.wishplan{color:var(--accent);font-weight:600}
/* Подсказка после просмотра: план был, дата прошла, а записи в дневнике нет. Это не
   справка, а приглашение к действию, и оно должно читаться как такое. */
.wishafter{display:inline-block;background:var(--accent-soft);border-radius:6px;
           padding:2px 7px;color:var(--accent);font-weight:600}

/* страница фильма: постер слева, факты и действия справа */
.titlehead{display:grid;grid-template-columns:220px 1fr;gap:20px;align-items:start}
@media (max-width:720px){.titlehead{grid-template-columns:1fr}}
.titlehead .poster-img.big{width:100%;height:auto;aspect-ratio:2/3;flex:none}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:10px 18px;
       margin-top:14px}
.facts div{border-top:1px solid var(--line);padding-top:8px}
.facts dt{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
          color:var(--muted)}
.facts dd{margin:3px 0 0;font-size:14px}

/* ---------------------------------------------------------------- главная
   Две колонки: слева подборки из каталога, справа свой дневник, итоги и уведомления.
   Подборки — горизонтальные ленты постеров, как ряды на главной у TMDB. */
/* Оболочка приложения: слева раздел, справа личная сводка. Сводка стоит на каждой
   вкладке, поэтому сетка общая, а не внутри главной. */
.appshell{display:grid;grid-template-columns:1fr 316px;gap:16px;align-items:start}
/* Без min-width:0 колонка не сжимается: у элемента сетки по умолчанию min-width:auto,
   поэтому горизонтальная лента постеров распирала её до своей полной ширины (замер:
   1956px при контейнере 944px), и правый блок уезжал за край экрана вместе с прокруткой. */
.appshell>*{min-width:0}
@media (max-width:900px){.appshell{grid-template-columns:1fr}}
.appaside{display:flex;flex-direction:column;gap:14px}
.appaside .card{margin-bottom:0}
.homenums{display:flex;gap:18px;flex-wrap:wrap}
.homenums b{display:block;font-size:21px;font-weight:700;font-variant-numeric:tabular-nums;
            letter-spacing:-.02em;line-height:1.1}
.homenums span{color:var(--muted);font-size:12px}
.rowblock{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
          padding:14px 16px;margin-bottom:14px;box-shadow:var(--shadow);min-width:0}
.posterrow{display:grid;grid-auto-flow:column;grid-auto-columns:124px;gap:14px;overflow-x:auto;
           padding:12px 2px 8px;scroll-snap-type:x proximity}
.posterrow .postertile{scroll-snap-align:start}
.posterrow .poster-img{width:100%;aspect-ratio:2/3}
.posterrow::-webkit-scrollbar{height:8px}
.posterrow::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:8px}
.diary-side{display:flex;gap:8px;align-items:center;padding:6px 0;border-top:1px solid var(--line)}
.diary-side .poster-img{width:28px;height:42px;flex:0 0 28px;border-radius:4px}
.diary-side div{min-width:0}
.diary-side b{display:block;font-size:13.5px;font-weight:600;overflow:hidden;
              text-overflow:ellipsis;white-space:nowrap}
/* Строка правой колонки без картинки: так показаны клубы — постера у клуба нет, а
   название и то, что в нём сейчас происходит, читаются и без него. */
.siderow{display:block;padding:6px 0;border-top:1px solid var(--line)}
.siderow b{display:block;font-size:13.5px;font-weight:600;overflow:hidden;
           text-overflow:ellipsis;white-space:nowrap}

/* актёры: горизонтальная лента квадратных портретов — как «В ролях» у TMDB.
   Без фотографии остаётся подпись и заглушка: роль известна и без снимка. */
.castrow{display:grid;grid-auto-flow:column;grid-auto-columns:116px;gap:14px;overflow-x:auto;
         padding:10px 2px 8px}
.castrow::-webkit-scrollbar{height:8px}
.castrow::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:8px}
.castcard img,.castno{width:116px;height:116px;object-fit:cover;border-radius:10px;
                      border:1px solid var(--line);display:block;background:var(--bg-soft)}
.castno{display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:12px}
.castcard b{display:block;margin-top:8px;font-size:13.5px;font-weight:600;line-height:1.3}
.castcard span{display:block;color:var(--muted);font-size:12.5px;margin-top:2px}

/* дневник: запись = плитка фильма + текст, кнопки не уезжают вниз */
.item.diary{display:flex;gap:12px;align-items:flex-start}
.diary-body{flex:1;min-width:0}

/* постеры */
.poster-img{width:42px;height:62px;border-radius:6px;flex:0 0 42px;object-fit:cover;
            border:1px solid var(--line);background:var(--bg-soft);display:block}
.poster-img.big{width:104px;height:156px;flex:0 0 104px;border-radius:8px}

/* аватарки: своя картинка или первая буква ника — пустой кружок выглядел бы поломкой */
.avatar{width:38px;height:38px;border-radius:50%;flex:0 0 38px;background:var(--accent-soft);
        border:1px solid var(--line);display:inline-flex;align-items:center;justify-content:center;
        overflow:hidden;font-weight:700;color:var(--accent);font-size:16px;text-transform:uppercase}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avatar.big{width:96px;height:96px;flex:none;font-size:32px}
.review{display:flex;gap:10px;align-items:flex-start}
.review-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.review .stars{font-size:13px}

/* источники данных: логотип TMDB обязан быть скромнее наших обозначений */
.credits{margin:18px 22px 40px;padding-top:14px;border-top:1px solid var(--line);color:var(--muted);
         font-size:12.5px}
.credits h3{font-size:13px;margin:0 0 6px;color:var(--muted);font-weight:600}
.credits ul{margin:6px 0 0;padding-left:18px}
.credits li{margin:2px 0}
.credits-row{display:flex;align-items:center;gap:8px;margin:6px 0}
.credits-row img{opacity:.85}
