/*
 * Стиль статей контент-завода — вынесен из ArticleRenderer::PAGE_CSS в отдельный физический
 * файл (update1.md, 2026-08-12: раньше CSS инлайнился в каждый article.html через <style>,
 * теперь один файл, подключаемый <link>, кэшируется браузером один раз на все статьи сайта —
 * повторные открытия страниц заметно быстрее, а вставка через <style> в head каждого файла того
 * же объёма всё равно не была причиной ощутимых тормозов сама по себе).
 *
 * Единственный источник правды для этого CSS — правки вносить здесь, не задваивать в PHP.
 * По авторскому шаблону пользователя (content-factory/example_template/Кардиган - статья
 * DAISYKNIT.dc.html) — editorial-дизайн: белый фон без карточек/теней, тонкие hairline-разделители
 * #e8e2db, Montserrat, акцент #7a5c48, тонированные плашки #f7f3ee только у лид-абзаца и CTA.
 * Светлая тема обязательна и безусловна: color-scheme: light, ни одного
 * @media (prefers-color-scheme: dark).
 */
:root {
  color-scheme: light;
  --text: #1a1a1a;
  --text-muted: #55504b;
  --text-soft: #3d3934;
  --text-faint: #9a938c;
  --text-crumb-current: #6b655f;
  --accent: #7a5c48;
  --border: #e8e2db;
  --tint: #f7f3ee;
  --link-underline: #c9beb4;
  --crumb-sep: #d8d2ca;
}
body { margin: 0; background: #ffffff; color: var(--text); font-family: "Montserrat", -apple-system, "Segoe UI", Arial, sans-serif; }
.page { max-width: 720px; margin: 0 auto; padding: clamp(24px, 6vw, 40px) 20px clamp(64px, 14vw, 96px); font-size: 16px; line-height: 1.7; }
a { color: var(--text); text-decoration: underline; text-decoration-color: var(--link-underline); text-underline-offset: 3px; transition: color .15s; }
a:hover { color: var(--accent); text-decoration-color: var(--accent); }

/* Доступность с клавиатуры (update3.md, B13). Без этого блока фокус на странице статьи не виден
   вообще: TOC-ссылки, <details> в FAQ, кнопки лайтбокса и ссылки на источники браузер подсвечивал
   бы дефолтной рамкой, которую сбрасывает нормализация, — клавиатурный пользователь не понимает,
   где он находится. :focus-visible, не :focus — мышиный клик рамку не показывает. */
:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}
[data-lb] :focus-visible { outline-color: #fff; }
/* Первая ссылка страницы, видима только с клавиатуры: пропустить крошки и оглавление. */
.skip-link { position: absolute; left: -9999px; top: 0; z-index: 100; padding: 10px 16px; background: var(--text); color: #fff; text-decoration: none; border-radius: 0 0 8px 0; }
.skip-link:focus-visible { left: 0; color: #fff; }
main:focus { outline: none; } /* фокус после перехода по skip-link — программный, рамка не нужна */

nav.breadcrumbs { padding: 0 4px; margin: 0 0 clamp(32px, 8vw, 48px); }
nav.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 0; margin: 0; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
nav.breadcrumbs a { color: var(--text-faint); text-decoration: none; }
nav.breadcrumbs a:hover { color: var(--accent); }
nav.breadcrumbs li[aria-current] { color: var(--text-crumb-current); }
nav.breadcrumbs li:not(:last-child)::after { content: "/"; margin-left: 6px; color: var(--crumb-sep); }

/* Шапка: полноширинный блок под текстом (не 2 колонки — откатили, см. историю правок: колонка
   требует cover_image, а он не у всех типов статьи, из-за чего разные типы статей выглядели
   несимметрично). Один и тот же порядок для любого типа — eyebrow/h1/excerpt/фото(если есть)/
   остальное, каждый элемент просто не рендерится, если его нет, без переверстки соседей. */
header .eyebrow { margin: 0 0 20px; font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); font-weight: 600; }
h1 { margin: 0 0 24px; font-size: clamp(29px, 7vw, 38px); line-height: 1.22; font-weight: 500; letter-spacing: -0.01em; }
.excerpt { margin: 0 0 28px; font-size: clamp(16px, 4.2vw, 18px); line-height: 1.6; color: var(--text-muted); font-weight: 400; }
.cover-image { width: 100%; aspect-ratio: 4 / 5; margin: 0; }
.header-meta { display: flex; flex-wrap: wrap; gap: 24px; justify-content: flex-end; align-items: baseline; padding: 14px 2px 0; font-size: 12px; color: var(--text-faint); }
.header-meta .reading-time { letter-spacing: 0.06em; text-transform: uppercase; }
ul.hero-promise { list-style: none; margin: 40px 0 0; padding: 24px 0 8px; border-top: 1px solid var(--border); display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 32px; font-size: 14px; line-height: 1.5; color: var(--text-muted); }
ul.hero-promise li { display: flex; gap: 10px; }
ul.hero-promise li::before { content: "—"; color: var(--accent); }
p.hero-meta { font-size: 12.5px; color: var(--text-faint); margin: 14px 0 0; }

nav.toc { margin: 40px 0 0; padding: 28px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
nav.toc .toc__title { margin: 0 0 18px; font-size: 11px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint); }
nav.toc ol { margin: 0; padding: 0; list-style: none; columns: 2 220px; column-gap: 48px; font-size: 14px; line-height: 1.5; counter-reset: toc; }
nav.toc li { break-inside: avoid; counter-increment: toc; }
nav.toc a { display: flex; gap: 12px; align-items: baseline; padding: 7px 0; text-decoration: none; color: var(--text); }
nav.toc a::before { content: counter(toc, decimal-leading-zero); color: var(--accent); font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; }
nav.toc a span { text-decoration: underline; text-decoration-color: var(--link-underline); text-underline-offset: 3px; }
nav.toc a:hover span { text-decoration-color: var(--accent); }

/* Тонкий hairline перед крупными разделами — тот же приём, что уже у nav.toc/.sources ниже, только
   раньше не был на h2/h3. Особенно нужен там, где идут секции .pair/.image-group__grid подряд —
   без явной линии граница между "ячейками" читалась плохо, только на отступах. */
h2 { margin: clamp(48px, 12vw, 72px) 0 20px; padding-top: 32px; border-top: 1px solid var(--border); font-size: clamp(21px, 5vw, 26px); line-height: 1.3; font-weight: 500; letter-spacing: -0.01em; }
h3 { margin: 48px 0 16px; padding-top: 24px; border-top: 1px solid var(--border); font-size: 20px; line-height: 1.3; font-weight: 500; }
p { margin: 0 0 20px; }

/* Только первый tldr в статье оформлен как лид-плашка (тот же приём, что у авторского референса —
   там боксом выделен только вводный абзац, остальные разделы читаются обычным текстом). Приём на
   чистом CSS: :first-of-type смотрит на первый <p> среди соседних элементов независимо от класса,
   а class=tldr сужает до тех случаев, когда этот первый <p> — действительно tldr. Все следующие
   tldr-абзацы (у каждого H2 по схеме) не совпадают с :first-of-type и остаются обычным текстом —
   PHP-код ничего не отслеживает, разметка одинаковая для всех tldr-блоков.
   article > — обязательно прямой потомок: с появлением .pair__text (ArticleRenderer::renderSection())
   у каждой такой обёртки свой независимый контекст :first-of-type, и tldr, оказавшийся первым
   абзацем внутри пары, иначе тоже получил бы лид-плашку — не только настоящий вводный tldr статьи. */
article > p.tldr:first-of-type { margin: 40px 0 20px; padding: 24px 28px; background: var(--tint); font-size: 15px; line-height: 1.7; color: var(--text-soft); border-radius: 12px; }

/* Обёртка со скроллом (table-wrap) — таблица шире контейнера на узких экранах скроллится вбок, не
   сжимает колонки в кашу; min-width на самой table задаёт порог, с которого появляется скролл. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 0 24px; }
.table-wrap table { margin: 0; }
table { border-collapse: collapse; width: 100%; min-width: 540px; font-size: 14px; line-height: 1.55; }
thead th { padding: 12px 16px; text-align: left; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-soft); font-weight: 600; background: var(--tint); border-bottom: 1px solid #e0d8ce; }
tbody td { padding: 14px 16px; vertical-align: top; border-bottom: 1px solid var(--border); }
tbody tr:nth-child(even) { background: #fbf9f6; }
tbody tr:last-child td { border-bottom: none; }
tbody td:first-child { font-weight: 500; }

ol.steps { list-style: none; margin: 0 0 32px; padding: 0; display: grid; gap: 12px; counter-reset: steps; }
ol.steps > li { display: flex; gap: 12px; font-size: 15px; line-height: 1.6; color: var(--text-soft); counter-increment: steps; }
ol.steps > li::before { content: counter(steps, decimal-leading-zero); color: var(--accent); flex-shrink: 0; }

ul.list, ol.list { list-style: none; margin: 0 0 32px; padding: 0; display: grid; gap: 12px; font-size: 15px; line-height: 1.6; color: var(--text-soft); }
ul.list > li, ol.list > li { display: flex; gap: 12px; }
ul.list > li::before { content: "—"; color: var(--accent); flex-shrink: 0; }
ol.list { counter-reset: litems; }
ol.list > li { counter-increment: litems; }
ol.list > li::before { content: counter(litems, decimal-leading-zero); color: var(--accent); flex-shrink: 0; }

blockquote { margin: 0 0 24px; padding: 18px 24px; border: 1px solid var(--border); font-size: 14px; line-height: 1.65; color: var(--text-muted); border-radius: 12px; }
blockquote p { margin: 0; }
blockquote cite { display: block; margin-top: 8px; font-size: 0.85em; color: var(--text-faint); font-style: normal; }

.callout { margin: 0 0 24px; padding: 18px 24px; border: 1px solid var(--border); border-left: 3px solid var(--accent); font-size: 14px; line-height: 1.65; color: var(--text-muted); border-radius: 12px; }
.callout--warning { border-left-color: #b8863f; }
.callout--info { border-left-color: #5e7391; }
.callout--tip { border-left-color: #6f7a5e; }

.cta { margin: 0 0 24px; background: var(--tint); padding: clamp(20px, 5vw, 32px); display: grid; gap: 18px; justify-items: start; border-radius: 12px; }
.cta p { margin: 0; font-size: 15px; line-height: 1.65; color: var(--text-soft); }
.cta a { display: inline-block; padding: 14px 28px; background: var(--text); color: #fff; font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; text-decoration: none; }
.cta a:hover { background: var(--accent); color: #fff; }

.sources { margin: 40px 0 0; padding-top: 20px; border-top: 1px solid var(--border); }
.sources h2 { margin-top: 0; }
.sources li { font-size: 14px; margin-bottom: 8px; }

.faq { border-bottom: 1px solid var(--border); margin: 0 0 24px; }
.faq-item { border-top: 1px solid var(--border); margin: 0; padding: 0; background: none; }
.faq-item summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 18px 2px; font-size: 15px; font-weight: 500; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: "+"; color: var(--accent); font-weight: 400; font-size: 18px; }
.faq-item[open] summary::after { content: "\2212"; }
.faq-item p { margin: 0; padding: 0 2px 20px; font-size: 14.5px; line-height: 1.7; color: var(--text-muted); }

.author-card { margin-top: 56px; padding-top: 28px; border-top: 1px solid var(--border); display: flex; align-items: center; gap: 16px; }
/* border-radius: 50% переопределяет базовые 12px из img — круглый аватар, не скруглённый угол;
   object-fit: cover унаследован от img, повторно не задаём. */
.author-card__avatar, .author-card__initials { width: 48px; height: 48px; border-radius: 50%; flex-shrink: 0; }
.author-card__initials { background: var(--tint); display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 600; color: var(--accent); }
.author-card__name { margin: 0; font-size: 14.5px; font-weight: 600; }
.author-card__position { margin: 2px 0 0; font-size: 12.5px; color: var(--text-faint); }

/* object-fit/border-radius/object-position — общие для ЛЮБОЙ фотографии статьи (.cover-image,
   .body-image, .pair__img img, .image-group__grid img — ни одна не обходится без обрезки под
   рамку и скруглённых углов), поэтому здесь, а не повторены в каждом из этих правил отдельно.
   Частные правила переопределяют только то, что у них реально отличается — ширину, aspect-ratio,
   отступы; .pair__img img — ещё и object-position (кадрирует не строго сверху, а чуть ниже). */
img { max-width: 100%; height: auto; display: block; object-fit: cover; object-position: top; border-radius: 12px; }
/* Одиночное фото само по себе в ряду (не часть .pair/.image-group__grid — тем ширину задают их
   собственные правила) — компактнее, чем во всю ширину колонки: 60%, по центру. */
.body-image { width: 60%; aspect-ratio: 3 / 4; margin: 32px auto; }
/* «Пара» фото+текст — секция с ровно одним фото под заголовком (ArticleRenderer::renderSection()).
   Настоящая группировка в PHP, не CSS-угадайка через float (та не прижилась — см. историю правок):
   фото и текст в одном <section>, порядок в DOM совпадает с видимым, скринридер/краулер не путаются.
   Чередование стороны — через .pair--reverse, которую расставляет PHP по счётчику пар, не nth-of-type
   (тот считал бы вообще все .pair подряд без разбора на «есть текст рядом» — незачем, PHP уже знает
   точно, у каких секций есть пара). */
.pair { display: flex; gap: clamp(24px, 4vw, 44px); align-items: center; margin: 0; padding-top: 32px; border-top: 1px solid var(--border); }
.pair--reverse { flex-direction: row-reverse; }
.pair__img { flex: 0 0 44%; max-width: 44%; margin: 0; }
.pair__img img { width: 100%; aspect-ratio: 4 / 5; max-height: 520px; object-position: 50% 15%; margin: 0; background: var(--tint); }
.pair__text { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.pair__text > h2:first-child, .pair__text > h3:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.pair__text p, .pair__text ul.list, .pair__text ol.list { margin: 0; }
@media (max-width: 720px) {
  .pair, .pair--reverse { flex-direction: column; }
  .pair__img { flex: none; max-width: 100%; }
}
/* Несколько фото под заголовком (ArticleRenderer::renderSection()), meta.gallery-чанки
   (renderGalleryChunk()) и карточки «сочетание» (DraftImporter::pushTable(), через
   renderImageGrid()) — один и тот же .image-group__grid: сетка 2-3 кадра в ряд (auto-fit), лишние
   переносятся на следующую строку и листаются обычной прокруткой страницы — не отдельный
   горизонтальный слайдер, одинаково на десктопе и на мобиле (общий CSS, без отдельной мобильной
   ветки). Один класс для всех источников набора фото — раньше meta.gallery отдельно жила в
   .gallery с чуть другими цифрами, без причины смотрелась иначе. */
.image-group { margin: 32px 0; padding-top: 24px; border-top: 1px solid var(--border); }
.image-group__caption { margin: 0 0 12px; font-size: 14.5px; font-weight: 600; color: var(--text-soft); }
/* margin здесь, не только на .image-group — сетка используется и "голой", без обёртки-figure
   (renderContentCollapsingImageRuns()/renderGalleryChunk()); без своего отступа она вплотную
   прилипала к следующему блоку — например к CTA сразу после серии фото товара (найдено на
   реальной статье, job 12). */
.image-group__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin: 24px 0; }
.image-group__grid img { width: 100%; aspect-ratio: 3 / 4; margin: 0; }
/* Единственное фото в сетке (renderGalleryChunk()/case 'image_group' может отдать 1 картинку) —
   auto-fit растягивает такую колонку на всю ширину, и фото при width:100% выходит крупнее
   .body-image, хотя визуально должно читаться так же компактно. :only-child трогает только этот
   случай — сетки с 2+ фото по-прежнему растягиваются на всю ширину колонок. margin:auto центрирует
   img как grid-item, без него сузившееся фото прилипло бы к левому краю растянутой колонки. */
.image-group__grid img:only-child { width: 60%; margin: 0 auto; }
pre { background: var(--tint); padding: 16px 20px; border-radius: 12px; overflow-x: auto; font-size: 13px; margin: 0 0 24px; }

/* Лайтбокс — полноэкранный просмотр фото по клику, assets/lightbox.js (структура из
   test/Article final layout.dc.html, п. «объединить лучшее из обоих макетов»). Курсор-подсказка на
   всех фото статьи — клик обрабатывает JS сам, per-image разметки не требуется. */
article img { cursor: zoom-in; }
[data-lb] { position: fixed; inset: 0; z-index: 9999; display: none; background: rgba(20, 17, 15, .94);
  padding: max(14px, env(safe-area-inset-top)) 14px max(14px, env(safe-area-inset-bottom)); overscroll-behavior: contain; }
[data-lb][data-open="1"] { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }
[data-lb-close] { position: fixed; top: max(10px, env(safe-area-inset-top)); right: 10px; width: 46px; height: 46px;
  display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, .1); border: 0;
  border-radius: 100px; color: #fff; font-size: 26px; line-height: 1; cursor: pointer; }
[data-lb-close]:hover { background: rgba(255, 255, 255, .2); }
[data-lb-nav] { position: fixed; top: 50%; transform: translateY(-50%); width: 46px; height: 46px; display: flex;
  align-items: center; justify-content: center; background: rgba(255, 255, 255, .1); border: 0; border-radius: 100px;
  color: #fff; font-size: 22px; cursor: pointer; }
[data-lb-nav="prev"] { left: 10px; } [data-lb-nav="next"] { right: 10px; }
[data-lb-nav]:hover { background: rgba(255, 255, 255, .2); }
[data-lb-img] { max-width: min(100%, 900px); max-height: calc(100vh - 132px); width: auto; height: auto; object-fit: contain; border-radius: 4px; }
[data-lb-cap] { margin: 0; max-width: 70ch; text-align: center; font-size: 13.5px; line-height: 1.45; color: rgba(255, 255, 255, .72); }
@media (max-width: 720px) {
  [data-lb-img] { max-height: calc(100vh - 156px); }
  [data-lb-nav] { bottom: max(16px, env(safe-area-inset-bottom)); top: auto; transform: none; }
  [data-lb-nav="prev"] { left: calc(50% - 58px); } [data-lb-nav="next"] { right: calc(50% - 58px); }
  [data-lb-cap] { margin-bottom: 64px; font-size: 13px; }
}
