/* .sidebar-overlay здесь не переопределяем: правило есть в app-base.css
   (z-index 998, под сайдбаром), дубль с меньшим z-index ронял затемнение
   под шапку. */

/* ==========================================================================
   Анимации левой колонки

   Железное правило: анимация сайдбара не двигает макет. Так устроен
   оригинал — у .layout там нет ни одного перехода, в правилах компакта
   тоже, а группы прячутся через display:none. Сжатие происходит одним
   кадром, и содержимое страницы не едет.

   Особенно это видно на странице полной новости: колонка тянула бы за
   собой плеер, блок серий и рекомендации — четверть секунды ползущей
   раскладки на каждое нажатие.

   Поэтому анимируем только то, что макета не касается: выезд панели
   поверх контента (transform), затемнение, иконки и цвета.
   ========================================================================== */

/* Переход у самой панели не назначаем: transform .25s ease уже задан
   в app-base.css. Постоянный will-change тут не нужен — он держал бы
   слой в памяти всё время ради анимации, которая случается по клику. */

/* Цвета и иконки — не влияют на раскладку. Высота, отступы и ширина
   колонки в компакте переключаются скачком, как в оригинале. */
.sidebar__link{transition:background-color .2s ease,color .2s ease}
.sidebar__icon{transition:transform .25s ease}
.sidebar__link:hover .sidebar__icon{transform:scale(1.08)}
.sidebar__link:active{transform:scale(.98)}

/*
 * Панель выезжает поверх контента в двух случаях: на узких экранах и на
 * страницах с классом overlay-sidebar (страница новости). Движение
 * одинаковое, поэтому задержки каскада и доворот бургера вынесены наружу,
 * а от контекста зависит только начальное состояние пунктов.
 *
 * Каскад считаем по прямым потомкам .sidebar__nav: вложенный блок гостя —
 * тоже .sidebar__group, и он сбивал нумерацию.
 */
body.sidebar-open .sidebar__nav > .sidebar__group:nth-child(1){transition-delay:.06s}
body.sidebar-open .sidebar__nav > .sidebar__group:nth-child(2){transition-delay:.1s}
body.sidebar-open .sidebar__nav > .sidebar__group:nth-child(3){transition-delay:.14s}
body.sidebar-open .sidebar__nav > .sidebar__group:nth-child(4){transition-delay:.18s}
body.sidebar-open .sidebar__nav > .sidebar__group:nth-child(5){transition-delay:.22s}

.burger .header-burger__icon{transition:transform .25s ease}
body.sidebar-open .burger .header-burger__icon{transform:rotate(90deg)}

/* Плавающий сайдбар на любой ширине — страница новости */
body.overlay-sidebar .sidebar__nav > .sidebar__group{
	opacity:0;
	transform:translateX(-10px);
	transition:opacity .2s ease,transform .25s ease
}
body.overlay-sidebar.sidebar-open .sidebar__nav > .sidebar__group{
	opacity:1;
	transform:none
}
body.overlay-sidebar .sidebar__footer{opacity:0;transition:opacity .2s ease .24s}
body.overlay-sidebar.sidebar-open .sidebar__footer{opacity:1}

@media(max-width:1279px){
	/* Селектор открытого состояния обязан быть не менее специфичным, чем
	   базовый с двумя :not() — иначе панель выезжает с невидимым
	   содержимым. */
	body:not(.no-sidebar):not(.overlay-sidebar) .sidebar__nav > .sidebar__group{
		opacity:0;
		transform:translateX(-10px);
		transition:opacity .2s ease,transform .25s ease
	}
	body.sidebar-open:not(.no-sidebar):not(.overlay-sidebar) .sidebar__nav > .sidebar__group{
		opacity:1;
		transform:none
	}

	body:not(.overlay-sidebar) .sidebar__footer{opacity:0;transition:opacity .2s ease .24s}
	body.sidebar-open:not(.overlay-sidebar) .sidebar__footer{opacity:1}
}

/* Системная настройка «уменьшить движение» отключает всё вышеперечисленное:
   панель по-прежнему открывается и закрывается, но без переходов. */
@media(prefers-reduced-motion:reduce){
	.sidebar,.sidebar__link,.sidebar__icon,
	.sidebar__nav > .sidebar__group,.sidebar__footer,
	.sidebar-overlay,.burger .header-burger__icon{
		transition:none !important;
		transition-delay:0s !important
	}
	.sidebar__link:hover .sidebar__icon,
	body.sidebar-open .burger .header-burger__icon{transform:none}
	/* Кроссфейд слайдера регистрации задан в app-base.css и туда не входит */
	.auth-landing__slide{transition:none}
}

/* В оригинале сетка жанров раскрывается их app.js (снимает max-height).
   Своего JS для этого нет — блок статичный, поэтому открываем его сразу. */
.home-genres{max-height:none;visibility:visible}

/* В палитре оригинала нет токена для текста поверх брендовой заливки
   (--bg-btn-primary): у него свои требования к контрасту, и #f1f1f1
   основного текста тут читается тускло. Заводим один и используем везде. */
:root{--dle-on-primary:#fff}

/* ==========================================================================
   Фокус с клавиатуры

   app-base.css гасит рамку глобально (input,button,textarea,select{outline:none})
   и возвращает её точечно — только для своих классов вроде .pagination__link.
   Наши кнопки и ссылки, которые отдаёт движок, под эти селекторы не попадают,
   поэтому фокус не было видно нигде. Одно правило закрывает всё сразу.
   ========================================================================== */
:where(a,button,input,textarea,select,summary,[tabindex]):focus-visible{
	outline:2px solid var(--border-focus);
	outline-offset:2px
}

/* Пропуск навигации: на каждой странице перед контентом идёт сайдбар
   из десятка ссылок. Прячем до фокуса, при табуляции — первая цель. */
.skip-link{
	position:fixed;
	top:8px;left:8px;
	z-index:1001;
	padding:12px 20px;
	border-radius:12px;
	background:var(--bg-btn-primary);
	color:var(--dle-on-primary);
	font-size:1.4rem;
	font-weight:700;
	text-decoration:none;
	transform:translateY(-200%);
	transition:transform .2s ease
}
.skip-link:focus{transform:translateY(0)}
#content:focus{outline:none}

/* Подпись только для скринридера: сохраняет компактную форму входа
   и при этом даёт полям настоящий label. */
.visually-hidden{
	position:absolute;
	width:1px;height:1px;
	margin:-1px;padding:0;
	overflow:hidden;
	clip:rect(0 0 0 0);
	clip-path:inset(50%);
	white-space:nowrap;
	border:0
}

/* Растягиваем на весь вьюпорт только «голый» embed из доп. поля — тот,
   что лежит прямо в нашем фрейме. Раньше правило ловило ЛЮБУЮ iframe
   внутри вьюпорта, включая плеер конструктора: тот вырывался из потока
   и накрывал собой ленту выбора серий и плееров (.rl-lenta с кнопками
   .RlItem), да ещё с z-index поверх неё. Разметка кнопок при этом была
   на месте — их просто не было видно. */
.episode-player__viewport > .episode-player__frame > iframe{position:absolute;inset:0;width:100%;height:100%;border:0;z-index:1}

/* Внутри конструктора позиционирование — забота его собственных стилей */
.episode-player--constructor .RalodePlayer iframe,
.episode-player--constructor .playerCode iframe{position:static;width:100%;border:0}

/* Надпись «Загрузка...» — это ::before вьюпорта из app-base.css. Он
   позиционирован, а iframe конструктора по правилу выше остаётся в потоке,
   поэтому надпись рисуется ПОВЕРХ видео и висит по центру плеера навсегда,
   заодно перехватывая клик по кнопке воспроизведения. Ждать там нечего:
   конструктор кладёт первый балансер в разметку сразу. Голого embed из поля
   online это не касается — его iframe absolute с z-index и накрывает
   надпись сам, поэтому плейсхолдер там оставляем. */
.episode-player__viewport::before{pointer-events:none}
.episode-player__viewport:has(.RalodePlayer)::before{content:none}

/* ==========================================================================
   Кнопки выбора серий и плееров (скин Ralode xx-scrolling)

   Скин рисует их под светлую тему: мелкий шрифт 13px, padding 2px, светлая
   заливка с тёмным текстом и красная рамка outset вокруг ленты. В тёмном
   интерфейсе это читается как чужой элемент и тянет на себя внимание.

   Приводим к языку шаблона: те же поверхности и радиусы, что у остальных
   кнопок, спокойное активное состояние без цветовых акцентов, размер под
   палец. Файлы модуля не трогаем — он обновляется отдельно, поэтому всё
   переопределяем отсюда.

   Специфичность намеренно на ступень выше скина: его styles.css движок
   подключает в body, ПОСЛЕ нашего файла, и при равном весе выигрывал бы он.
   ========================================================================== */

/* Красная рамка outset вокруг ленты — снимаем */
.episode-show .episode-player--constructor .RalodePlayer .RlVisor{
	border:0;
	padding:2px 0
}

.episode-show .episode-player--constructor .RalodePlayer .rl-buttons{
	padding:8px 0
}

/* Сама кнопка серии/плеера */
.episode-show .episode-player--constructor .RalodePlayer .RlItem{
	display:inline-flex;
	align-items:center;
	justify-content:center;
	min-height:40px;
	padding:0 14px;
	margin:0 6px 0 0;
	border:0;
	border-radius:10px;
	background-color:var(--bg-surface-3);
	color:var(--color-between);
	font-size:1.4rem;
	line-height:1.2;
	white-space:nowrap;
	transition:background-color .2s ease,color .2s ease
}
.episode-show .episode-player--constructor .RalodePlayer .RlItem:hover{
	background-color:var(--bg-surface-4);
	color:var(--color-primary)
}

/* Текущая серия: заметна за счёт заливки и насыщенности текста, без
   цветового акцента — глаз находит её сразу, но она не кричит. */
.episode-show .episode-player--constructor .RalodePlayer .serie-active,
.episode-show .episode-player--constructor .RalodePlayer .RlItem.serie-active{
	background-color:var(--bg-surface-4);
	color:var(--color-primary);
	font-weight:600
}

/* Стрелки прокрутки: у скина это картинки 24x24 из его папки. Заменяем на
   кнопки размером под палец с нарисованной стрелкой, чтобы не тащить
   чужие спрайты и не зависеть от их цвета. */
.episode-show .episode-player--constructor .RalodePlayer .buttonLR{
	position:relative;
	width:40px;
	height:40px;
	border-radius:10px;
	background-image:none;
	background-color:var(--bg-surface-3);
	transition:background-color .2s ease
}
.episode-show .episode-player--constructor .RalodePlayer .buttonLR:hover{
	background-image:none;
	background-color:var(--bg-surface-4)
}
.episode-show .episode-player--constructor .RalodePlayer .buttonLR::before{
	content:"";
	position:absolute;
	inset:0;
	margin:auto;
	width:18px;height:18px;
	background-color:var(--color-primary);
	-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
	-webkit-mask-position:center;mask-position:center;
	-webkit-mask-size:contain;mask-size:contain
}
.episode-show .episode-player--constructor .RalodePlayer .ButtonLft::before{
	-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'/%3E%3C/svg%3E");
	mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'/%3E%3C/svg%3E")
}
.episode-show .episode-player--constructor .RalodePlayer .ButtonRgh::before{
	-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E");
	mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")
}

/* На сенсорных устройствах цели крупнее */
@media(pointer:coarse){
	.episode-show .episode-player--constructor .RalodePlayer .RlItem,
	.episode-show .episode-player--constructor .RalodePlayer .buttonLR{min-height:44px}
	.episode-show .episode-player--constructor .RalodePlayer .buttonLR{width:44px;height:44px}
}

/* Конструктор плееров рисует панель выбора плеера и серий сам, уже в
   браузере, и кладёт её ПОД видео. Жёсткая пропорция 16:9 с overflow:hidden
   у вьюпорта эту панель обрезала — на странице оставался только кадр с
   кнопкой воспроизведения. Для страниц с конструктором снимаем обрезку и
   фиксированную пропорцию, оставляя min-height, чтобы место под плеер
   всё-таки резервировалось и вёрстка не прыгала при загрузке. */
.episode-player--constructor .episode-player__viewport{
	aspect-ratio:auto;
	overflow:visible;
	min-height:min(56.25vw,480px)
}
.episode-player--constructor .episode-player__frame{position:static}
/* Возрастной гейт накрывает плеер целиком и уходит по кнопке — так и
   задумано. Ограничивать его высотой нельзя: панели выбора у конструктора
   две, сверху и снизу от видео, и обрезанный гейт накрывал верхнюю. */
.episode-player--constructor .episode-player__age-gate{z-index:3}
/* Ничто внутри конструктора не должно вылезать за ширину колонки */
.episode-player--constructor iframe,
.episode-player--constructor img,
.episode-player--constructor video{max-width:100%}

/* ==========================================================================
   Виджеты, которые движок рисует сам

   DLE отдаёт готовую разметку для рейтинга и панели тегов в форме
   комментария. В дизайн-системе оригинала стилей под неё нет, поэтому без
   этих правил рейтинг выпадает вертикальным списком цифр 1..5, а панель
   редактора — столбиком слов b, i, u, s, left, center и так далее.
   ========================================================================== */

/* Звёздный рейтинг: ul.unit-rating, где li.current-rating получает от
   движка инлайновый width в пикселях. Классическая вёрстка рассчитана на
   полосу из пяти звёзд по 17px; звёзды рисуем инлайновым SVG, чтобы не
   тащить в шаблон отдельный спрайт. */
.rating{display:inline-flex;align-items:center}
.unit-rating{
	position:relative;
	list-style:none;
	margin:0;padding:0;
	width:85px;height:17px;
	background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='17' height='17' viewBox='0 0 17 17'%3E%3Cpath fill='%23555' d='M8.5 1.6l2.1 4.3 4.7.7-3.4 3.3.8 4.7-4.2-2.2-4.2 2.2.8-4.7L1.7 6.6l4.7-.7z'/%3E%3C/svg%3E") repeat-x left center
}
.unit-rating li{margin:0;padding:0}
.unit-rating li.current-rating{
	position:absolute;
	top:0;left:0;
	height:17px;
	background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='17' height='17' viewBox='0 0 17 17'%3E%3Cpath fill='%23f5a623' d='M8.5 1.6l2.1 4.3 4.7.7-3.4 3.3.8 4.7-4.2-2.2-4.2 2.2.8-4.7L1.7 6.6l4.7-.7z'/%3E%3C/svg%3E") repeat-x left center;
	text-indent:-9999px;
	z-index:1
}
/* Сами ссылки-оценки лежат поверх полосы прозрачными зонами клика */
.unit-rating li a{
	position:absolute;
	top:0;left:0;
	width:17px;height:17px;
	text-indent:-9999px;
	overflow:hidden;
	z-index:2
}
.unit-rating a.r1-unit{left:0}
.unit-rating a.r2-unit{left:17px}
.unit-rating a.r3-unit{left:34px}
.unit-rating a.r4-unit{left:51px}
.unit-rating a.r5-unit{left:68px}
.unit-rating a:hover{background:rgba(245,166,35,.25)}

/* Панель тегов редактора комментариев */
.comments-editor{display:flex;flex-direction:column;gap:.8rem}
.bbcode-editor{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
.bbcode{
	display:inline-flex;
	align-items:center;
	justify-content:center;
	min-width:32px;height:32px;
	padding:0 .8rem;
	border-radius:8px;
	background:var(--bg-surface-3);
	color:var(--color-between);
	font-size:1.3rem;
	line-height:1;
	cursor:pointer;
	-webkit-user-select:none;user-select:none;
	transition:background-color .2s ease,color .2s ease
}
.bbcode:hover{background:var(--bg-surface-4);color:var(--color-primary)}
.bbcode.b-separator{min-width:1px;width:1px;height:20px;padding:0;background:var(--border-color);border-radius:0;pointer-events:none}
.bbcode.b-b{font-weight:700}
.bbcode.b-i{font-style:italic}
.bbcode.b-u{text-decoration:underline}
.bbcode.b-s{text-decoration:line-through}

/* ==========================================================================
   Обёртка движка внутри сетки карточек

   DLE оборачивает вывод списка новостей в <div id="dle-content"> — это
   контейнер для его ajax-подгрузки страниц. В результате у .episode-cards
   оказывается ровно один прямой потомок, и вся сетка схлопывается в одну
   колонку: карточки выстраиваются столбиком, а пагинация сплющивается до
   ширины колонки.

   display:contents убирает саму коробку обёртки, но оставляет элемент в
   DOM — ajax движка продолжает работать, а карточки становятся полноценными
   элементами сетки. Правило намеренно сужено до потомка .episode-cards:
   на других страницах #dle-content должен вести себя как обычный блок.
   ========================================================================== */
.episode-cards > #dle-content{display:contents}

/* ==========================================================================
   Обёртка комментариев в полной новости

   DLE 10.3 кладёт список комментариев в <div id="dle-comments-list">
   (см. comments.class.php). В дизайн-системе оригинала этот список —
   .comments/.comments__list: flex-колонка с зазором 1.6rem и шрифтом
   1.4rem. Без правила комментарии в бою стоят вплотную (блоки со
   сливающимся фоном) и наследуют 1.6rem вместо дизайновых 1.4rem.
   ========================================================================== */
#dle-comments-list{display:flex;flex-direction:column;gap:1.6rem;font-size:1.4rem}

/* Пагинация приходит внутри той же обёртки и после display:contents
   становится таким же элементом сетки — растягиваем её на всю строку,
   иначе она займёт одну ячейку и переносы поедут. */
.episode-cards > .pagination,
.episode-cards > #dle-content > .pagination,
.episode-cards > .navigation-block,
.episode-cards > #dle-content > .navigation-block{grid-column:1 / -1}

/* ==========================================================================
   Резерв места под содержимое, которое приходит позже

   Всё, что подгружается после разметки, обязано иметь заранее известный
   размер — иначе при загрузке страница дёргается, и это идёт в CLS.
   ========================================================================== */

/* Обложка в списках «Другие серии» и «Рекомендации»: у .episode-compact__thumb
   в оригинале нет ни высоты, ни пропорции, поэтому до загрузки картинки
   блок был нулевой высоты, а потом раздвигал весь список. */
.episode-compact__thumb{aspect-ratio:16/9}
.episode-compact__thumb-link{display:block;width:100%;height:100%}

/* Аватар в комментарии: размера не задавал никто, блок схлопывался в ноль
   и разъезжался при появлении картинки. Заодно выкладываем сам комментарий
   в строку — аватар слева, содержимое справа. */
.comment__box{display:flex;gap:12px;align-items:flex-start}
.comment__avatar{flex:0 0 40px;width:40px;height:40px;border-radius:50%;overflow:hidden}
.comment__avatar img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover}
.comment__body{min-width:0;flex:1 1 auto}

/* Кадры из доп. поля screens приходят как готовые img без размеров */
.episode-screens__list img{aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover}

/* Капча в формах: картинка приходит от движка, высота известна заранее */
.comment-form__captcha img,.auth-form__captcha img{display:block;min-height:40px}

/* Слайдер регистрации: картинки переведены с фона на <img>, чтобы отдавать
   WebP через srcset, ленить неактивные слайды и поднимать приоритет первого.
   Визуально эквивалентно background-size:cover: та же абсолютная подложка,
   поверх неё — затемнение и контент (z-index у контента уже в app-base). */
.auth-landing__slide{overflow:hidden}
.auth-landing__slide img{position:absolute;inset:0;width:100%;height:100%;-o-object-fit:cover;object-fit:cover;-o-object-position:center;object-position:center}

/* Теги эпизода. Движок отдаёт готовые ссылки (поле janre с поиском и {tags}),
   поэтому классы оригинала .episode-info__tag-wrap/.episode-info__tag на них
   не надеть — обёртка у оригинала прозрачная, так что эквивалентно стилизуем
   сами ссылки: пилюля + иконка метки через mask, как у .episode-info__tag. */
.episode-info__tags-list a{display:inline-flex;align-items:center;gap:.6rem;min-height:var(--tag-h);padding:0 1.2rem;border-radius:var(--tag-br);background:var(--tag-bg);font-size:1.4rem;text-decoration:none;color:var(--color-between);transition:background-color .2s ease,color .2s ease}
.episode-info__tags-list a:before{content:"";width:14px;height:14px;flex:0 0 auto;color:var(--color-secondary);opacity:.8;background-color:currentColor;-webkit-mask:var(--icon-tag) center/contain no-repeat;mask:var(--icon-tag) center/contain no-repeat}
.episode-info__tags-list a:hover{background:var(--bg-btn-hover)}

/* Студия в тулбаре — как канал на YouTube: аватар + имя ссылкой.
   Правила скопированы из app-base.css оригинала (там они были вычищены
   как неиспользуемые, поэтому лежат здесь). Картинок студий в DLE нет —
   используем букву-заглушку из того же набора. */
.episode-creator{display:grid;grid-template-columns:58px minmax(0,1fr);align-items:center;gap:12px;min-width:0}
.episode-creator__avatar{width:58px;height:58px;overflow:hidden;border-radius:50%;background:var(--bg-surface-2)}
.episode-creator__avatar img{display:block;width:100%;height:100%;-o-object-fit:cover;object-fit:cover}
.episode-creator__body{min-width:0}
.episode-creator__name{display:inline-block;max-width:100%;overflow:hidden;color:var(--color-primary);font-size:1.8rem;font-weight:700;line-height:1.25;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}
.episode-creator__count{color:var(--color-secondary);font-size:1.4rem;line-height:1.4}
.creator-avatar{width:var(--creator-avatar-size, 40px);height:var(--creator-avatar-size, 40px);flex-shrink:0}
.creator-avatar__image,.creator-avatar__placeholder{width:100%;height:100%;border-radius:50%}
.creator-avatar__image{display:block;-o-object-fit:cover;object-fit:cover}
.creator-avatar__placeholder{display:flex;align-items:center;justify-content:center;background:var(--creator-avatar-color, #666);color:#fff;font-size:calc(var(--creator-avatar-size, 40px) * .42);font-weight:600;line-height:1;-webkit-user-select:none;-moz-user-select:none;user-select:none}
.episode-details__link{color:var(--color-primary);text-decoration:none}
.episode-details__link:hover{color:var(--bg-btn-primary)}

.episode-description__text p{margin:0 0 1.2rem}
.episode-description__text h2,.episode-description__text h3{margin:1.6rem 0 .8rem;font-size:1.8rem;color:var(--color-primary)}
.episode-description__text a{color:var(--bg-btn-primary)}
.episode-description__text ul,.episode-description__text ol{padding-left:2rem;margin:0 0 1.2rem}
.episode-description__text img{border-radius:12px}
.episode-description__text table{width:100%;border-collapse:collapse}
.episode-description__text td,.episode-description__text th{border:1px solid var(--border-color);padding:8px}

.page__title{margin:0 0 16px;font-size:2.4rem;line-height:1.2}
.page__content{display:flex;flex-direction:column;gap:1.2rem;color:var(--color-between)}
.page__content p{margin:0}
.page__content a{color:var(--bg-btn-primary)}
.page__content h2,.page__content h3{color:var(--color-primary);margin:0}
.page__content img{border-radius:12px}

.offline{display:grid;place-items:center;align-content:center;min-height:100vh;gap:1rem;background:var(--bg-base);text-align:center;padding:2rem}
.offline__title{margin:0;font-size:2.6rem;color:var(--color-primary)}
.offline__text{margin:0;color:var(--color-secondary)}

.lastcomments{display:flex;flex-direction:column;gap:1.2rem}
.lastcomments__item{display:flex;flex-direction:column;gap:.4rem;padding:12px 16px;border-radius:16px;background:var(--bg-surface)}
.lastcomments__title{font-size:1.5rem;font-weight:700;color:var(--color-primary);text-decoration:none}
.lastcomments__title:hover{color:var(--bg-btn-primary)}
.lastcomments__text{font-size:1.4rem;color:var(--color-secondary)}

.search-page__select{width:100%;padding:12px 16px;border-radius:12px;background:var(--bg-input);border:1px solid var(--border-color);color:var(--color-primary);font-size:1.4rem}
.search-page__select[multiple]{min-height:120px}
.search-page__count{font-size:1.4rem;color:var(--color-secondary)}

.auth-form{display:flex;flex-direction:column;gap:14px}
.auth-form input[type=text],.auth-form input[type=password],.auth-form input[type=email],.auth-form input[type=login],.auth-form select{width:100%;height:56px;padding:0 18px;border:1px solid var(--border-color);border-radius:16px;background:var(--bg-input);color:var(--color-primary);font-size:1.6rem;transition:border-color .2s ease,box-shadow .2s ease}
.auth-form input:focus{border-color:var(--bg-btn-primary)}
.auth-form button[type=submit],.auth-form input[type=submit]{height:56px;padding:0 24px;border-radius:16px;background:var(--bg-btn-primary);color:var(--dle-on-primary);font-size:1.6rem;font-weight:700;cursor:pointer;transition:filter .2s ease}
.auth-form button[type=submit]:hover,.auth-form input[type=submit]:hover{filter:brightness(1.1)}
.auth-form .login_form__footer,.auth-form .auth-form__footer{display:flex;gap:8px;justify-content:center;color:var(--color-secondary);font-size:1.4rem}
.auth-form a{color:var(--bg-btn-primary)}

.comments{display:flex;flex-direction:column;gap:1.6rem}
.comments .comment{display:flex;flex-direction:column;gap:.8rem;padding:16px;border-radius:16px;background:var(--bg-surface)}
.comments .comment-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.comments .comment-head .avatar{border-radius:50%;overflow:hidden}
.comments .comment-head .avatar img{width:36px;height:36px;border-radius:50%;-o-object-fit:cover;object-fit:cover}
.comments .comment-author{font-weight:700;color:var(--color-primary);text-decoration:none}
.comments .comment-date{font-size:1.3rem;color:var(--color-secondary)}
.comments .comment-body{font-size:1.5rem;color:var(--color-between);line-height:1.6}
.comments .comment-body a{color:var(--bg-btn-primary)}
.comments .comment-reply{font-size:1.3rem;color:var(--bg-btn-primary);text-decoration:none}
.comments form textarea,.comments form input[type=text],.comments form input[type=email]{width:100%;padding:12px 16px;border-radius:12px;background:var(--bg-input);border:1px solid var(--border-color);color:var(--color-primary);font-size:1.4rem}
.comments form textarea{min-height:120px;resize:vertical}
.comments form input[type=submit],.comments form button{border-radius:12px;background:var(--bg-btn-primary);color:var(--dle-on-primary);padding:12px 24px;cursor:pointer;font-size:1.5rem;font-weight:700}
.comments .pagination,.comments .navigation{display:flex;gap:.8rem;align-items:center}

/* {pages} отдаёт голые <a> и <span> (текущая страница) плюс
   <span class="nav_ext"> для многоточия — стилизуем прямых потомков. */
.pagination__list{display:flex;flex-wrap:wrap;gap:.8rem;list-style:none;padding:0;margin:0}
.pagination__list > a,.pagination__list > span{display:inline-flex;align-items:center;justify-content:center;min-width:40px;height:40px;padding:0 12px;border-radius:10px;background:var(--bg-surface);color:var(--color-between);font-size:1.4rem;text-decoration:none;transition:background-color .2s ease,color .2s ease}
.pagination__list > a:hover{background:var(--bg-surface-3);color:var(--color-primary)}
.pagination__list > span{background:var(--bg-btn-primary);color:var(--dle-on-primary);font-weight:700}
.pagination__list > span.nav_ext{background:none;color:var(--color-secondary);font-weight:400;min-width:auto;padding:0 4px}
/* DLE-навигация в комментариях приходит без наших обёрток */
.comments .navigation a,.comments .navigation span{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;padding:0 10px;border-radius:10px;background:var(--bg-surface);color:var(--color-between);font-size:1.4rem;text-decoration:none}
.comments .navigation span{background:var(--bg-btn-primary);color:var(--dle-on-primary);font-weight:700}
.comments .navigation span.nav_ext{background:none;color:var(--color-secondary);font-weight:400;min-width:auto}
.pagination__btn{display:inline-flex;align-items:center;gap:.6rem;padding:0 16px;height:40px;border-radius:10px;background:var(--bg-surface);color:var(--color-between);font-size:1.4rem;text-decoration:none}
.pagination__btn:hover{background:var(--bg-surface-3);color:var(--color-primary)}
.pagination__btn--disabled{opacity:.4;pointer-events:none}

.header-search__input{width:100%;height:40px;padding:0 12px 0 44px;border-radius:20px;background:var(--bg-input);color:var(--color-primary);font-size:1.4rem}
.header-search__button{flex:none}


/* --- блоки, которых нет в исходном app-base.css --- */

.speedbar{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;font-size:1.4rem;color:var(--color-secondary)}
.speedbar a,.page-header__meta a{color:var(--color-secondary);text-decoration:none}
.speedbar a:hover,.page-header__meta a:hover{color:var(--color-primary)}
.page-header__meta{display:flex;flex-wrap:wrap;gap:.6rem;font-size:1.4rem;color:var(--color-secondary)}

.episode-card__badge{display:inline-flex;align-items:center;height:22px;padding:0 8px;border-radius:8px;background:var(--bg-surface-3);font-size:1.2rem;color:var(--color-between)}
.episode-card__thumb .episode-card__badge--quality{position:absolute;top:8px;left:8px;background:var(--bg-btn-primary);color:var(--dle-on-primary);font-weight:700}
.episode-card__duration{position:absolute;right:8px;bottom:8px;padding:2px 8px;border-radius:8px;background:rgba(0,0,0,.72);font-size:1.2rem;color:var(--dle-on-primary)}
.episode-card__badges{display:flex;flex-wrap:wrap;gap:.6rem}
.episode-card__meta-item--rating{gap:.4rem}

/* Компактная строка метаданных карточки: просмотры, дата, рейтинг,
   комментарии — всё в один ряд без переносов. В колонке 300px переносы
   растягивали карточки на разную высоту и рвали ритм сетки. */
.episode-card__meta--compact{
	display:flex;
	flex-wrap:nowrap;
	align-items:center;
	gap:.8rem;
	min-width:0;
	font-size:1.2rem;
	white-space:nowrap
}
.episode-card__meta--compact .episode-card__meta-item{flex:0 0 auto}
/* Рейтинг занимает фиксированные 85px, поэтому сжиматься должны соседи */
.episode-card__meta--compact .episode-card__meta-item--rating{flex:0 0 85px}
.episode-card__meta--compact .unit-rating{transform:scale(.85);transform-origin:left center}
.episode-card__meta--compact .episode-card__meta-item--fav{margin-left:auto}
.episode-card__meta--compact .episode-card__meta-item{display:inline-flex;align-items:center;gap:.4rem}

/* Иконки просмотров и даты рисуем из CSS, а не разметкой. Инлайновый SVG
   в шаблоне карточки размножается на все элементы списка: два значка
   давали лишние 45 КБ на страницу с шестью десятками карточек. Из CSS
   картинка приходит один раз и кэшируется. Маска вместо фона — чтобы
   значок наследовал цвет текста. */
.episode-card__meta-item--views::before,
.episode-card__meta-item--date::before{
	content:"";
	flex:0 0 14px;
	width:14px;height:14px;
	background-color:currentColor;
	opacity:.75;
	-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
	-webkit-mask-position:center;mask-position:center;
	-webkit-mask-size:contain;mask-size:contain
}
.episode-card__meta-item--views::before{
	-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
	mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E")
}
.episode-card__meta-item--date::before{
	-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4M16 2v4M3 10h18'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3C/svg%3E");
	mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4M16 2v4M3 10h18'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3C/svg%3E")
}

/* ==========================================================================
   Рекламные вставки внутри списка новостей

   Движок подмешивает баннеры прямо в ленту: <ins> становится таким же
   элементом сетки, как карточка. Без правил он раздувается по размеру
   объявления и ломает ряд — соседние карточки съезжают и меняют высоту.
   Приводим вставку к габаритам карточки: та же ширина ячейки, та же
   скруглённая подложка, содержимое обрезается по границам.
   ========================================================================== */
/* Селектор по тегу ins не годится: рекламный скрипт подменяет его своим
   контейнером, и правило перестаёт совпадать — именно поэтому пустые слоты
   выглядели аккуратными серыми ячейками, а заполненные разъезжались.
   Поэтому держим в габаритах ячейки ЛЮБОЙ прямой элемент сетки, который
   не карточка и не пагинация, чем бы он ни оказался. */
.episode-cards > *:not(.episode-card):not(.pagination):not(script):not(style),
.episode-cards > #dle-content > *:not(.episode-card):not(.pagination):not(script):not(style){
	display:flex;
	align-items:center;
	justify-content:center;
	min-width:0;
	max-width:100%;
	overflow:hidden;
	aspect-ratio:16/10;
	border-radius:12px;
	background:var(--bg-surface)
}

/* Слот, в который реклама не пришла, не показываем: пустая серая ячейка
   в сетке выглядит как поломка вёрстки. */
.episode-cards > *:not(.episode-card):not(.pagination):empty,
.episode-cards > #dle-content > *:not(.episode-card):not(.pagination):empty{display:none}
/* Само объявление не должно вылезать за ячейку */
.episode-cards > ins iframe,
.episode-cards > #dle-content > ins iframe,
.episode-cards > ins img,
.episode-cards > #dle-content > ins img{max-width:100%;height:auto;border:0}
.episode-card__meta-item--fav a{color:inherit;text-decoration:none}

.episode-player__frame{position:absolute;inset:0}
.episode-player__frame[hidden]{display:none}
.episode-player__tabs{display:flex;flex-wrap:wrap;gap:.8rem;margin-top:12px}
.episode-player__tab{display:inline-flex;align-items:center;height:40px;padding:0 16px;border:0;border-radius:12px;background:var(--bg-surface);color:var(--color-between);font-size:1.4rem;text-decoration:none;cursor:pointer;transition:background-color .2s ease,color .2s ease}
.episode-player__tab:hover{background:var(--bg-surface-3);color:var(--color-primary)}
.episode-player__tab.is-active{background:var(--bg-btn-primary);color:var(--dle-on-primary);font-weight:700}
.episode-player__tab--download{margin-left:auto}

/* Счётчик голосов рядом со звёздами. Движок отдаёт его разметкой
   (span itemprop), поэтому кладём только в содержимое элемента — в атрибут
   такой тег ставить нельзя, кавычка внутри закрывает атрибут и хвост
   разметки вываливается на страницу текстом. */
.episode-toolbar__votes{font-size:1.3rem;color:var(--color-secondary)}
.episode-toolbar__votes:empty{display:none}

/* Закладка приходит от движка и для гостя пустая — пустая «пилюля»
   в панели выглядит как недогруженный элемент. */
.episode-toolbar__favorites:empty{display:none}
.episode-toolbar__favorites a{color:inherit;text-decoration:none}
.episode-screens__list{display:flex;flex-wrap:wrap;gap:1rem}
.episode-screens__list img{max-width:200px;height:auto;border-radius:12px}

.comment__text--signature{margin-top:.8rem;padding-top:.8rem;border-top:1px solid var(--border-color);font-size:1.3rem;color:var(--color-secondary)}
.comment__action{cursor:pointer}
.comment__action--danger{color:var(--bg-btn-danger)}

.comment-form__label{display:block;margin-bottom:.6rem;font-size:1.4rem;color:var(--color-secondary)}
.comment-form__captcha img{border-radius:8px}
.comment-form__textarea textarea{width:100%;min-height:140px;padding:12px 16px;border-radius:12px;background:var(--bg-input);border:1px solid var(--border-color);color:var(--color-primary);font-size:1.4rem;resize:vertical}
.impot{color:var(--bg-btn-danger)}

.header-user-menu{position:relative;display:flex;align-items:center;gap:.8rem}
.header-user-menu__dropdown{position:absolute;top:calc(100% + 8px);right:0;z-index:120;display:flex;flex-direction:column;gap:.4rem;min-width:280px;padding:16px;border-radius:16px;background:var(--bg-surface-2, var(--bg-surface));box-shadow:0 18px 40px rgba(0,0,0,.45)}
.header-user-menu__dropdown[hidden]{display:none}
.header-user-menu__item{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:10px 12px;border-radius:12px;color:var(--color-between);font-size:1.4rem;text-decoration:none}
.header-user-menu__item:hover{background:var(--bg-surface-3);color:var(--color-primary)}
.header-user-menu__item-count{font-size:1.3rem;color:var(--color-secondary)}
.header-user-menu__header{padding:0 12px 8px;border-bottom:1px solid var(--border-color)}
.header-user-menu__profile-link{color:var(--color-primary);font-weight:700;text-decoration:none}

.lastcomments__meta{font-size:1.3rem;color:var(--color-secondary)}

.vote{display:flex;flex-direction:column;gap:1.2rem;padding:16px;border-radius:16px;background:var(--bg-surface)}
.vote__title{font-size:1.6rem;color:var(--color-primary)}
.vote__body{display:flex;flex-direction:column;gap:.6rem;font-size:1.4rem;color:var(--color-between)}
.vote__total{font-size:1.3rem;color:var(--color-secondary)}
.vote__actions{display:flex;gap:.8rem}

.tagcount{margin-left:.4rem;font-size:1.2rem;color:var(--color-secondary)}

/* ==========================================================================
   Сенсорные цели

   Правила заведены под pointer:coarse, а не под ширину экрана: увеличивать
   нужно там, где тыкают пальцем, а не там, где узкое окно. На мыши размеры
   остаются как в оригинале.
   ========================================================================== */
@media(pointer:coarse){
	.episode-player__tab,
	.pagination__list > a,
	.pagination__list > span:not(.nav_ext),
	.pagination__btn,
	.header-user-menu__item,
	.auth-form__footer-link,
	.home-section__link{
		min-height:44px
	}

	.btn-icon,
	.burger,
	.header-search-mobile-toggle,
	.header-search__button,
	.header-search__close{
		min-width:44px;
		min-height:44px
	}

	.sidebar__link{min-height:44px}

	/* {favorites} и действия тулбара движок отдаёт строчными ссылками —
	   у них своей высоты нет, добираем её здесь. */
	.episode-card__meta-item--fav a,
	.plus-fav,
	.episode-toolbar__action,
	.comment__action{
		display:inline-flex;
		align-items:center;
		min-height:44px
	}

	/* Заголовки в списках «Другие серии» и «Рекомендации» — основная
	   цель перехода в этих блоках. */
	.episode-compact__title-link{display:inline-flex;align-items:center;min-height:44px}
}

/* ==========================================================================
   Горизонтальное переполнение на мобильном

   Замер в браузере: viewport 440, scrollWidth 533. Шире экрана оказались
   не отдельные блоки, а сразу header, main.content и episode-show — все
   ровно 513px. Растягивал их заголовок: его min-content (иконки, поиск,
   кнопки «Регистрация» и «Войти» с подписями) больше ширины экрана.

   Колонка 1fr в гриде .layout не может стать уже min-content своего
   содержимого, поэтому весь макет раздувался до ширины шапки, а страница
   получала 93px горизонтальной прокрутки. minmax(0,1fr) снимает этот
   автоматический минимум; min-width:0 разрешает сжиматься флекс-детям.
   ========================================================================== */
.layout{grid-template-columns:minmax(0,1fr)}
@media(min-width:1280px){
	.layout{grid-template-columns:var(--sidebar-width) minmax(0,1fr)}
	body.sidebar-compact:not(.no-sidebar):not(.overlay-sidebar) .layout{
		grid-template-columns:var(--sidebar-width-compact) minmax(0,1fr)
	}
	body.no-sidebar .layout,
	body.overlay-sidebar .layout{grid-template-columns:minmax(0,1fr)}
}

.header,
.header-left,
.header-right,
.header-user-menu{min-width:0}

/* Ниже 560px в шапке остаётся только вход иконкой: «Регистрация» есть
   в боковом меню, а подпись «Войти» занимала 73px из 93px переполнения.
   Кнопка сохраняет доступное имя через aria-label в login.tpl. */
@media(max-width:560px){
	.header-login-button.btn-border{display:none}
	.header-user-menu__toggle .header-login-button__text{display:none}
	.header-user-menu__toggle{min-width:44px;justify-content:center}
}

/* ==========================================================================
   Типографика

   Оригинал набран Roboto — системным по духу шрифтом, который встречается
   на половине сайтов и не даёт интерфейсу собственного голоса. Manrope
   геометричнее и заметно характернее в заголовках, при этом с закрытыми
   апертурами и крупным очком, поэтому мелкая мета карточек (12–13px)
   на тёмном фоне читается лучше. Цифры одноширинные — счётчики просмотров
   и даты в сетке не пляшут по ширине.

   Подключается тем же способом, что и раньше (display=optional), поэтому
   подмены шрифта на глазах у посетителя не происходит.
   ========================================================================== */
body{font-family:Manrope,"Segoe UI",Arial,sans-serif}

/* Заголовки чуть плотнее: у Manrope на крупных кеглях широкие межбуквенные
   просветы, и без поджатия строки выглядят рыхло. */
.home-section__title,
.episode-info__title_primary,
.page-header__title,
.auth-card__title,
.episode-details__title,
.episode-secondary__title,
.feedback__title{letter-spacing:-.02em}

/* Числа в мете и статистике — табличными, чтобы столбцы не дрожали */
.episode-card__meta--compact,
.episode-info__meta,
.episode-details__value{font-variant-numeric:tabular-nums}

/* Жанры из доп. поля оформлены теми же чипами, что и теги: в один ряд
   попадали текст через запятую и готовые ссылки движка — читалось как
   две разные сущности. Разметку чипов строит dle.js. */
.episode-info__genres{display:contents}
.episode-info__tags-list .episode-info__genre{
	display:inline-flex;
	align-items:center;
	gap:.6rem;
	min-height:var(--tag-h);
	padding:0 1.2rem;
	border-radius:var(--tag-br);
	background:var(--tag-bg);
	font-size:1.4rem;
	text-decoration:none;
	color:var(--color-between);
	transition:background-color .2s ease,color .2s ease
}
.episode-info__tags-list .episode-info__genre:hover{background:var(--bg-btn-hover)}

/* ==========================================================================
   Логотип

   Прежний логотип был обведённым вензелем в SVG-путях: не масштабировался
   по-человечески, не наследовал цвет темы и жил отдельно от типографики
   шаблона. Собран заново из текста — тем же шрифтом, что и весь интерфейс.

   Марка R34 остаётся видимой всегда: на узких экранах слово скрывается,
   и в шапке остаётся компактный знак вместо обрезанной надписи.
   ========================================================================== */
.header-logo{
	display:inline-flex;
	align-items:center;
	gap:.8rem;
	min-width:0;
	line-height:1
}
.header-logo__mark{
	display:inline-flex;
	align-items:center;
	justify-content:center;
	flex:0 0 auto;
	width:34px;height:34px;
	border-radius:10px;
	background:var(--bg-btn-primary);
	color:var(--dle-on-primary,#fff);
	font-size:1.3rem;
	font-weight:800;
	letter-spacing:-.04em
}
.header-logo__word{
	font-size:2rem;
	font-weight:800;
	letter-spacing:-.03em;
	color:var(--color-primary);
	white-space:nowrap;
	overflow:hidden;
	text-overflow:ellipsis
}
.header-logo__word-accent{color:var(--bg-btn-primary)}
.header-logo-url{display:inline-flex;align-items:center;min-width:0;text-decoration:none}
.header-logo-url:hover .header-logo__word{color:var(--color-primary)}

@media(max-width:560px){
	.header-logo__word{display:none}
}

/* SEO-текст в шапках жанров и тегов (модули yummyfields и tagface).
   Шапку рисуют сами модули из yummyfields.tpl / tagface.tpl, здесь
   только абзац описания: читаемая ширина строки и чуть крупнее кегля,
   чем у служебных подписей .episodes-catalog-header__type. */
.episodes-catalog-header__description{margin:2px 0 0;max-width:70ch;color:var(--color-secondary);font-size:15px;line-height:1.6}

/* Сердечки вместо рейтинга: кнопка-лайк в карточках (shortstory) и в
   тулбаре эпизода (fullstory). Счётчик — span#vote-num-id-N из {vote-num}.
   Класс .is-liked ставит dle.js после успешного лайка или из localStorage.
   В тулбаре кнопка выглядит как чип (класс episode-toolbar__action даёт
   фон и скругления, как у комментариев и репорта), в карточке — плоская. */
.like-btn{
	display:inline-flex;
	align-items:center;
	gap:.5rem;
	cursor:pointer;
	line-height:1;
	transition:color .15s ease
}
.like-btn__icon{width:16px;height:16px;flex:0 0 auto;transition:transform .15s ease}
.like-btn:hover .like-btn__icon{transform:scale(1.15)}
.like-btn.is-liked{color:var(--like-color, #ff4d67)}
.like-btn.is-liked .like-btn__icon{fill:currentColor;stroke:currentColor}
.like-btn:disabled{opacity:.6;cursor:default}
.like-btn:focus-visible{outline:2px solid var(--like-color, #ff4d67);outline-offset:2px;border-radius:2rem}
.like-btn [id^="vote-num-id-"]{color:inherit}
/* в карточке — плоская кнопка без чипа */
.episode-card__meta-item--like{padding:0;border:0;background:none;color:var(--color-secondary);font-size:inherit;gap:.4rem}
.episode-card__meta-item--like [id^="vote-num-id-"]{font-size:1.3rem}
.episode-card__meta--compact .episode-card__meta-item--like{flex:0 0 auto}
/* в тулбаре эпизода — иконка в размер чипа */
.episode-toolbar__rating .like-btn__icon{width:2rem;height:2rem}
