/* GNS Education — раздел новостей: страница списка /news/ и страница новости. Подключается только на них
   (server/templates/layout.html), на главную не грузится. Токены, шапка, подвал, карточка новости и сетки карточек — в site.css.
   Порядок: 1 список · 2 шапка новости и обложка · 3 тело: текст, фото, галерея, видео, цитата · 4 конец страницы · 5 просмотр фотографий · 6 движение

   Что ставят скрипты и сервер (вёрстка реагирует только на это):
   · article.news-article[data-cover] — у новости есть обложка: она заходит на светлую часть страницы; [data-draft] — черновик на экране сотрудника;
   · article.news-article[data-cover="portrait"] — обложка вертикальная (высота файла больше ширины, признак ставит сервер): от 700 px
     шапка новости — разворот: слева заголовок, вступление и сведения, справа снимок целиком; уже 700 px — кадр 4:3 во всю ширину;
   · .js (класс на html) — галерея становится лентой; без скриптов снимки идут столбцом;
   · .news-gallery-box[data-ready] — скрипт новостей включил счётчик и кнопки листания (место под них держится заранее);
   · .news-video__start[hidden] — кнопка поверх видео-файла, пока скрипт её не включил; после нажатия снова hidden;
   · html.viewer-open — открыт просмотр фотографий: страница под ним не прокручивается;
   · dialog.news-viewer.is-closing — просмотр закрывается: окно затухает, по окончании затухания скрипт его закрывает;
   · .news-viewer__img.is-swapping — в просмотре сменился снимок: он входит сбоку; --dir на снимке — с какой стороны (1 — справа, −1 — слева). */

/* ───────── 1. Список ───────── */
.news-list { padding-top: clamp(40px, 5.5vw, 80px); }
/* «скоро»: короткая страница занимает экран, текст стоит у нижнего края, как на первом экране главной */
.news-empty { display: grid; align-content: end; min-height: min(100svh, 860px); }
.news-empty__actions { justify-content: flex-start; gap: 8px 36px; padding-top: 24px; }
.news-empty .tg-pill { margin-block: 0; }

/* ───────── 2. Шапка новости и обложка ───────── */
.news-article { --cover-drop: clamp(40px, 8vw, 136px); --gallery-h: clamp(220px, 60vw, 420px); }
.news-head { z-index: 1; }
.news-head__back { margin-bottom: clamp(8px, 1.6vw, 20px); }
/* слово длиннее строки переносится по слогам; где браузер этого не умеет — в любом месте, но за край не выходит */
.news-head__title { font-size: clamp(1.75rem, 1.18rem + 2.44vw, 3.375rem); line-height: 1; overflow-wrap: anywhere; hyphens: auto; hyphenate-limit-chars: 14 5 5; }
.news-head__title--long { font-size: clamp(1.5rem, 1.13rem + 1.6vw, 2.5rem); line-height: 1.04; }
.news-draft { justify-self: start; width: fit-content; margin-bottom: 20px; padding: 10px 16px; border: 1px dashed var(--edge-on-dark); border-radius: var(--radius); font-size: var(--fs-small); line-height: 1.4; color: var(--soft-on-dark); }
.news-head__meta { justify-content: flex-start; gap: 12px clamp(24px, 3vw, 44px); padding-top: 20px; }
.news-head__meta .news-date { font-size: var(--fs-small); font-weight: 600; line-height: 1.4; }
.news-facts { display: flex; flex-wrap: wrap; gap: 8px clamp(24px, 3vw, 44px); margin: 0; }
.news-facts__item { display: flex; align-items: baseline; gap: 10px; }
.news-facts dt { font-size: var(--fs-caps); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; line-height: 1.3; color: var(--fg-muted); }
.news-facts dd { margin: 0; font-size: var(--fs-small); font-weight: 600; line-height: 1.4; overflow-wrap: anywhere; }
.news-cover { position: relative; overflow: hidden; margin: clamp(28px, 4vw, 56px) 0 0; border-radius: var(--radius); background: color-mix(in srgb, var(--cream) 8%, var(--ink)); }
.news-cover img { height: auto; max-height: 84svh; object-fit: cover; }
/* кадр 16:9 во всю ширину — у горизонтальной и квадратной обложки; у вертикальной свои правила ниже (:where — вес правила прежний) */
:where(.news-article:not([data-cover="portrait"])) .news-cover img { width: 100%; aspect-ratio: 16 / 9; }
/* менять вместе: ширину обложки (вся ширина содержимого, до 600 px — весь экран) повторяет атрибут sizes — COVER_SIZES.cover в server/news-render.js */
/* обложка заходит на светлую часть: тёмная шапка новости кончается на её середине */
/* flow-root: отрицательный отступ обложки укорачивает саму тёмную шапку, а не утекает за неё */
[data-cover] .news-head { display: flow-root; padding-bottom: 0; }
[data-cover] .news-cover { margin-bottom: calc(-1 * var(--cover-drop)); }
[data-cover] .news-body { padding-top: calc(var(--cover-drop) + clamp(40px, 6vw, 88px)); }
@media (min-width: 900px) {
  .news-head__title { max-width: 14em; }
  .news-head__title--long { max-width: 20em; }
  .news-head__meta .news-tags { margin-left: auto; }
}
@media (max-width: 599px) {
  /* телефон: обложка под обрез экрана, вертикальнее */
  .news-cover { margin-inline: calc(-1 * var(--gutter)); border-radius: 0; }
  .news-cover img { aspect-ratio: 4 / 3; }
}
/* Вертикальная обложка. Уже 700 px рядом с ней нет места тексту: она стоит под сведениями во всю ширину кадром 4:3, как на телефоне. */
@media (max-width: 699px) {
  [data-cover="portrait"] .news-cover img { width: 100%; aspect-ratio: 4 / 3; }
}
/* От 700 px шапка — разворот: текст шапки в шести колонках сетки слева, снимок в пяти справа, между ними одна пустая.
   Строки сетки: пометка черновика, «Все новости», заголовок со вступлением (тянется), сведения; снимок стоит во всех четырёх
   и прижат к низу: сведения лежат на нижней линии текста, а низ снимка заходит на светлую часть, как у широкой обложки.
   У снимка здесь нет своей ширины и пропорции в стилях: их дают атрибуты width и height — снимок не бывает шире своего файла
   (маленький не растягивается до мыла) и место под него известно до загрузки. Кадр выше 5:8 подрезается по высоте.
   Менять вместе: порог 700 px и долю снимка (5 колонок из 12) повторяет атрибут sizes — COVER_SIZES.portrait в server/news-render.js. */
@media (min-width: 700px) {
  [data-cover="portrait"] .news-head > .wrap { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); grid-template-rows: auto auto 1fr auto; column-gap: calc(100% / 12); }
  [data-cover="portrait"] .news-head > .wrap > * { grid-column: 1; }
  [data-cover="portrait"] .news-draft { grid-row: 1; }
  [data-cover="portrait"] .news-head__back { grid-row: 2; justify-self: start; }
  [data-cover="portrait"] .news-head .section-head { grid-row: 3; grid-template-columns: minmax(0, 1fr); align-content: start; }
  [data-cover="portrait"] .news-head__meta { grid-row: 4; margin-bottom: clamp(40px, 5.5vw, 80px); }
  [data-cover="portrait"] .news-head__meta .news-tags { margin-left: 0; }
  [data-cover="portrait"] .news-head > .wrap > .news-cover { grid-column: 2; grid-row: 1 / -1; align-self: end; justify-self: end; margin-top: 0; }
  [data-cover="portrait"] .news-cover img { max-height: calc(min(100vw - 2 * var(--gutter), var(--wrap-max)) * 5 / 12 * 1.6); }
}

/* ───────── 3. Тело новости ─────────
   Колонка текста — 38em (60–75 знаков в строке). На десктопе у страницы одна ось: текст, подзаголовки и цитата стоят
   от четвёртой колонки сетки, фотографии и видео идут от той же оси до правого поля, лента галереи — до края экрана. */
.news-body__flow { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: clamp(24px, 3vw, 36px); }
.news-body__flow > * { min-width: 0; }
.news-text { max-width: 38em; gap: 1.05em; line-height: 1.6; }
.news-heading { max-width: 22em; margin-top: clamp(16px, 2.6vw, 36px); margin-bottom: -6px; font-size: clamp(1.5rem, 1.3rem + .85vw, 2.125rem); font-weight: 500; font-stretch: var(--semi); line-height: 1.12; letter-spacing: -.03em; text-wrap: balance; overflow-wrap: anywhere; hyphens: auto; hyphenate-limit-chars: 14 5 5; }
.news-body__flow > :first-child { margin-top: 0; }
.news-body__flow > :is(.news-photo, .news-gallery-box, .news-video-box, .news-quote) { margin-block: clamp(8px, 1.8vw, 24px); }

/* фотография: ссылка на сам файл — рамка со скруглением; снимок не шире колонки и не выше экрана */
.news-photo { display: grid; gap: 12px; justify-items: start; margin: 0; }
.news-zoom { position: relative; display: block; max-width: 100%; overflow: hidden; border-radius: var(--radius); background: color-mix(in srgb, var(--fg) 8%, var(--bg)); cursor: zoom-in; }
.news-zoom img { width: auto; max-width: 100%; height: auto; max-height: min(82svh, 860px); transition: transform .45s var(--ease-photo); }
.news-photo__caption { max-width: 36em; font-size: var(--fs-small); line-height: 1.45; color: var(--fg-muted); text-wrap: pretty; overflow-wrap: anywhere; }
@media (hover: hover) { .news-zoom:hover img { transform: scale(1.035); } }

/* галерея: без скриптов — столбцом; со скриптами — лента одной высоты с прилипанием, листается пальцем, кнопками и стрелками */
.news-gallery-box { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.news-gallery { display: grid; gap: 16px; margin: 0; padding: 0; }
.news-gallery__bar { display: none; align-items: center; gap: 8px; }
.news-gallery__count { margin-right: auto; font-size: var(--fs-small); font-weight: 600; line-height: 1.4; color: var(--fg-muted); font-variant-numeric: tabular-nums; }
/* сама лента — общее правило лент с прилипанием в site.css (.js .news-gallery стоит в его списке); здесь — только снимки
   и то, чем лента отличается на десктопе (ниже, в блоке от 900 px) */
.js .news-gallery__item { flex: none; scroll-snap-align: start; }
.js .news-gallery .news-zoom img { width: auto; max-width: min(84vw, 960px); height: var(--gallery-h); max-height: none; object-fit: cover; }
/* место под счётчик и кнопки держится сразу; видны они, когда скрипт новостей их включил */
.js .news-gallery__bar { display: flex; visibility: hidden; }
.js [data-ready] > .news-gallery__bar { visibility: visible; }

/* круглая кнопка со стрелкой: листание галереи и просмотра */
.news-round {
  display: grid; place-items: center; flex: none; width: 44px; height: 44px; padding: 0; border: 1px solid color-mix(in srgb, currentColor 30%, transparent); border-radius: 50%;
  background: none; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease, opacity .2s ease, transform .15s ease;
}
.news-round svg { width: 20px; height: 20px; transform: rotate(45deg); }
.news-round:is([data-gallery-prev], [data-viewer-prev]) svg { transform: rotate(-135deg); }
.news-round:focus-visible { border-radius: 50%; }
.news-round:active { transform: scale(.96); }
.news-round:disabled { opacity: .32; cursor: default; }
@media (hover: hover) { .news-round:not(:disabled):hover { background: var(--fg); border-color: var(--fg); color: var(--bg); } }

/* видео: файл — проигрыватель с обложкой; ссылка — плитка с обложкой или заголовком, после нажатия на её месте проигрыватель сервиса */
.news-video-box { display: grid; gap: 12px; justify-items: start; margin: 0; }
.news-video__frame { position: relative; max-width: 100%; overflow: hidden; border-radius: var(--radius); background: var(--ink-deep); }
.news-video-file { width: auto; max-width: 100%; height: auto; max-height: min(82svh, 860px); }
.news-video, .news-video__player { position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; border: 0; border-radius: var(--radius); background: var(--ink-deep); color: var(--cream); text-decoration: none; }
.news-video__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .45s var(--ease-photo); }
/* затемнение под кнопкой: подпись читается на любом кадре */
.news-video::after, .news-video__start::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgba(27, 21, 20, .1) 0, rgba(27, 21, 20, .18) 45%, rgba(27, 21, 20, .72) 100%); }
.news-video--plain::after { background: none; }
.news-video--plain::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .97 0 0 0 0 .93 0 0 0 .09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.news-video__title {
  position: absolute; left: var(--video-pad); right: var(--video-pad); top: var(--video-pad); max-width: 18em;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
  font-size: clamp(1.1875rem, .95rem + 1.2vw, 2rem); font-weight: 500; font-stretch: var(--wide); line-height: 1.08; letter-spacing: -.04em; word-spacing: .1em; overflow-wrap: anywhere; hyphens: auto; hyphenate-limit-chars: 14 5 5;
}
.news-video-box { --video-pad: clamp(14px, 2.4vw, 28px); }
/* кнопка воспроизведения собрана как главное действие сайта: круглая кнопка и «пилюля» в общей рамке */
.news-video__play {
  position: absolute; z-index: 1; left: var(--video-pad); bottom: var(--video-pad); display: inline-flex; align-items: center; gap: 4px; padding: 6px;
  border-radius: 999px; background: var(--frame-on-dark); white-space: nowrap;
}
.news-video__icon, .news-video__play > span { display: inline-flex; align-items: center; justify-content: center; height: 48px; border-radius: 999px; background: var(--cream); color: var(--ink); transition: background-color .2s ease; }
.news-video__icon { width: 48px; padding: 14px 13px 14px 15px; fill: currentColor; }
.news-video__play > span { padding: 0 22px; font-size: 1rem; font-weight: 600; letter-spacing: -.005em; }
.news-video__start { position: absolute; inset: 0; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.news-video__start[hidden] { display: none; }
/* обложка видео-файла — снимок с отложенной загрузкой: он стоит в потоке и задаёт размеры рамки (не шире колонки и не выше
   экрана, как фотография), проигрыватель лежит под ним во всю рамку, кнопка — поверх. Обложка видна, только пока видна
   кнопка: после запуска она прозрачна и лишь держит место. Запасной размер — на случай, если снимок не загрузился.
   Без скриптов (содержимое <noscript> становится разметкой) поверх рамки лежит второй проигрыватель — с обложкой
   в атрибуте poster, а первый, без обложки, убран. */
.news-video__frame { isolation: isolate; min-width: min(100%, 320px); min-height: 180px; }
.news-video__frame .news-video-file { position: absolute; inset: 0; width: 100%; height: 100%; max-height: none; }
.news-video__frame noscript > .news-video-file { z-index: 3; }
.news-video__frame:has(noscript > video) > .news-video-file { display: none; }
.news-video__frame > .news-video__poster { position: relative; z-index: 1; display: block; width: auto; max-width: 100%; height: auto; max-height: min(82svh, 860px); }
.news-video__frame > .news-video__start { z-index: 2; }
.news-video__start[hidden] + .news-video__poster { visibility: hidden; }
.news-video:focus-visible, .news-video__start:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; border-radius: var(--radius); }
.news-video__start:focus-visible { outline-offset: -5px; outline-color: var(--cream); }
.news-video__note { max-width: 36em; font-size: var(--fs-small); line-height: 1.45; color: var(--fg-muted); text-wrap: pretty; }
.news-video__link { display: inline-block; padding-block: 11px; color: var(--fg); font-weight: 600; text-decoration-thickness: 1px; text-underline-offset: .25em; }
@media (hover: hover) {
  .news-video:hover .news-video__poster { transform: scale(1.035); }
  :is(.news-video, .news-video__start):hover :is(.news-video__icon, .news-video__play > span) { background: #fff; }
}
@media (max-width: 479px) {
  .news-video__icon, .news-video__play > span { height: 44px; }
  .news-video__icon { width: 44px; padding: 13px 12px 13px 14px; }
  .news-video__play > span { padding: 0 18px; }
}

/* цитата: между двумя волосяными линиями, ступенью подзаголовка */
.news-quote { display: grid; gap: 16px; margin: 0; padding-block: clamp(24px, 3vw, 36px); border-block: 1px solid var(--line); }
.news-quote blockquote { display: grid; gap: .6em; max-width: 26em; margin: 0; font-size: var(--fs-h3); font-weight: 500; font-stretch: var(--semi); line-height: 1.22; letter-spacing: -.025em; text-wrap: pretty; overflow-wrap: anywhere; }
.news-quote__author { font-size: var(--fs-caps); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; line-height: 1.4; color: var(--fg-muted); }

@media (min-width: 900px) {
  .news-article { --axis: 3; --gallery-h: clamp(340px, 36vw, 540px); }
  .news-body__flow { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .news-body__flow > * { grid-column: var(--axis) / -1; }
  /* лента галереи начинается на оси текста и уходит за правое поле до края экрана */
  .js .news-gallery {
    --edge: calc((100vw - min(100vw - 2 * var(--gutter), var(--wrap-max))) / 2);
    display: flex; gap: 12px; overflow-x: auto;
    margin-inline: 0 calc(-1 * var(--edge)); padding-inline: 0 var(--edge); scroll-padding-inline: 0 var(--edge);
  }
}
@media (min-width: 1200px) {
  .news-article { --axis: 4; }
}

/* ───────── 4. Конец страницы ───────── */
.news-end__inner { display: grid; gap: clamp(28px, 4vw, 48px); justify-items: start; }
.news-end__text { max-width: 17em; font-size: var(--fs-say); font-weight: 500; font-stretch: var(--wide); line-height: 1.06; letter-spacing: -.045em; word-spacing: .12em; text-wrap: balance; }
.news-more .section-head { margin-bottom: clamp(32px, 4vw, 56px); }
.news-more__all { margin-top: clamp(28px, 4vw, 56px); }
@media (min-width: 900px) {
  .news-end__inner { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); column-gap: calc(100% / 12); align-items: end; }
  /* кнопка может выйти из своей колонки в поле страницы, но не ближе 20 px к краю экрана: подпись переносится, только когда не хватает и этого */
  .news-end__inner .cta { width: max-content; max-width: calc(100% + var(--gutter) - 20px); }
}
@media (max-width: 899px) {
  .news-end__text { font-size: min(var(--fs-say), (100vw - 2 * var(--gutter)) / 12.4); }
}

/* ───────── 5. Просмотр фотографий ─────────
   <dialog> собирает скрипт новостей при первом нажатии на снимок: снимок во весь экран, подпись, счётчик, кнопки. */
.viewer-open body { overflow: hidden; }
.news-viewer {
  position: fixed; inset: 0; width: 100%; max-width: none; height: 100%; max-height: none; margin: 0; padding: 0; border: 0;
  background: var(--ink-deep); color: var(--cream); --fg: var(--cream); --bg: var(--ink-deep); overflow: hidden;
}
.news-viewer[open] { display: grid; grid-template: minmax(0, 1fr) auto / minmax(0, 1fr); }
.news-viewer::backdrop { background: none; }
/* дорожки сцены — определённого размера: от них считается наибольший размер снимка */
.news-viewer__stage { display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); place-items: center; min-height: 0; padding: calc(68px + env(safe-area-inset-top)) var(--gutter) 12px; touch-action: pan-y pinch-zoom; cursor: zoom-out; }
.news-viewer__img { width: auto; max-width: 100%; height: auto; max-height: 100%; min-height: 0; object-fit: contain; border-radius: var(--radius); cursor: default; }
.news-viewer__bar { display: flex; align-items: center; gap: 8px; min-height: 76px; padding: 12px var(--gutter) calc(16px + env(safe-area-inset-bottom)); }
.news-viewer__caption { flex: 1; min-width: 0; margin-right: 16px; max-width: 44em; font-size: var(--fs-small); line-height: 1.45; color: var(--soft-on-dark); text-wrap: pretty; overflow-wrap: anywhere; }
.news-viewer__count { margin-left: auto; margin-right: 8px; font-size: var(--fs-small); font-weight: 600; color: var(--muted-on-dark); font-variant-numeric: tabular-nums; white-space: nowrap; }
.news-viewer__close { position: absolute; top: calc(14px + env(safe-area-inset-top)); right: var(--gutter); }
/* крестик — две линии, как у кнопки меню в открытом виде */
.news-viewer__close::before, .news-viewer__close::after { content: ""; grid-area: 1 / 1; width: 18px; height: 1.5px; background: currentColor; transform: rotate(45deg); }
.news-viewer__close::after { transform: rotate(-45deg); }
.news-viewer [hidden] { display: none; }
@media (max-width: 599px) {
  .news-viewer__stage { padding-inline: 0; }
  .news-viewer__img { border-radius: 0; }
  .news-viewer__bar { flex-wrap: wrap; }
  .news-viewer__caption { flex-basis: 100%; margin-right: 0; }
  .news-viewer__count { margin-left: 0; margin-right: auto; }
}

/* ───────── 6. Движение ─────────
   Обложка раскрывается сама, без скрипта: она — первое, что видит читатель, и ждать ей нечего.
   Остальное — общие приёмы сайта (data-words, data-rise, data-reveal, data-stagger из site.css). */
@media (prefers-reduced-motion: no-preference) {
  .news-cover img { animation: news-cover-in 1.2s var(--ease) both; }
  @keyframes news-cover-in { from { transform: scale(1.06); } }
  .js .news-gallery { scroll-behavior: smooth; }
  .news-viewer[open] { animation: news-viewer-in .3s ease both; }
  .news-viewer[open] .news-viewer__bar, .news-viewer[open] .news-viewer__close { animation: rise-in .5s var(--ease) .12s both; }
  .news-viewer.is-closing { animation: news-viewer-out .2s ease both; }
  @keyframes news-viewer-in { from { background-color: rgba(27, 21, 20, 0); } }
  @keyframes news-viewer-out { to { opacity: 0; } }
  .news-viewer__img.is-swapping { animation: news-photo-swap .35s var(--ease) both; }
  @keyframes news-photo-swap { from { opacity: 0; transform: translateX(calc(var(--dir, 1) * 16px)); } }
}
@media (prefers-reduced-motion: reduce) {
  .news-zoom img, .news-video__poster, .news-round { transition: none; }
}
