/* ==========================================================================
   Viola Alba, питомник бенгальских кошек
   Первый экран: текст слева, фотография в родном масштабе справа.

   Шрифты только локальные, ни одного обращения к fonts.googleapis.com
   и fonts.gstatic.com: из России эти запросы тормозят загрузку.

   ШРИФТЫ: на странице их два, Jost и Onest. Пятым кругом клиент выбрала
   «название гротеском, заголовки разделов антиквой», и .hero__name, подпись
   под ним и название в шапке встали на Jost Light 300. Правкой Б1
   от 14.08.2026 она попросила снять засечки и с заголовков разделов:
   «Шрифт надо поменять заголовки везде "о питомнике", 2010, без засечек
   на другой». Теперь --font-display это тот же Jost Light 300, и он же
   идёт на «2010», имена котят и имена авторов отзывов.

   Классы-варианты v-font-onest-name, v-font-jost-name и v-font-jost-all
   удалены пятым кругом. Классы v-font-cormorant | v-font-forum |
   v-font-playfair оставлены запасными: они возвращают антикву и работают
   на любой обёртке, потому что переключают только переменные. Cormorant
   Garamond со страницы не удалён - лежит в assets/fonts/ и показан живым
   образцом в _variants.html.

   Классы v-field-clean/v-field-mark убраны: это была вертикальная надпись
   в боковых полях старой раскладки, поля были залиты --dark. Полей в этом
   смысле больше нет - на широких экранах справа от фотографии её же
   собственный правый край, растянутый фоном, а не пустое поле с текстом.
   Варианты кнопок отсюда убраны: клиент выбрала песочный, два других
   удалены. Блок «О питомнике» выбран светлый, тёмный со страницы убран,
   но класс .theme-dark в стилях остался: чередование светлых и тёмных
   секций дальше по странице сохраняем.

   ЗАЛИВКА ШАПКИ: два варианта на выбор клиенту, переключаются классом
   у body - без класса вариант A (сплошная --dark), с классом v-head-glass
   вариант B (полупрозрачная с размытием). Подробности в разделе
   ВЕРХНЯЯ ПОЛОСА.
   ========================================================================== */

/* ── Шрифт основного текста ────────────────────────────────────────────────
   Onest, вариативный по оси wght, одним файлом на подмножество закрывает
   начертания 300, 400, 500, 600. Меню, кнопки и весь текст на нём. */

@font-face {
  font-family: 'Onest';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/onest-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Onest';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/onest-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Onest';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/onest-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Onest';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/onest-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Шрифты названия, три варианта на выбор ────────────────────────────────
   Тонкая антиква с засечками, как в надписи BENGAL CATS на картинке клиента.
   Prata убран совсем: это тот шрифт, который клиент отвергла. */

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

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

/* Playfair Display, статический, 400. Подмножества cyrillic-ext у него нет. */
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/playfair-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/playfair-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/playfair-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Jost, гротеск без засечек, вариант шрифта названия ────────────────────
   Клиент: «можно попробовать название сделать без засечек? кажется этот
   шрифт смотрится устаревшим». Только вес 300, статический. Три файла,
   не четыре: у Jost на Google Fonts нет отдельного подмножества
   cyrillic-ext, обычная кириллица уже покрывает нужные буквы. */
@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/jost-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/jost-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/jost-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Запасное семейство под Jost, чтобы макет не прыгал ───────────────────
   Задача: если jost-latin.woff2 не доехал, строка «VIOLA ALBA» должна
   занимать ту же ширину, что и с Jost. Иначе название либо рвётся на две
   строки, либо наезжает на фотографию.

   Файла тут нет, только local(): берём шрифт, который уже стоит в системе,
   и правим ему ширину через size-adjust. Отдельное семейство, а не второй
   src у 'Jost': size-adjust действует на всё объявление целиком, и повесить
   его на настоящий Jost значило бы испортить основной шрифт.

   Замер на живой странице, кегль 45.34px, разрядка 0.18em, строка
   «VIOLA ALBA» в единицах кегля:

     Jost 300          7.0791   из них глифы 5.2791, разрядка 1.8
     Helvetica Neue    7.4493              5.6493
     Arial             7.4706              5.6706
     Helvetica         7.4717              5.6717

   Разрядка задана в em и от size-adjust не зависит, поэтому подгонять надо
   только глифовую часть: 5.2791 / 5.6493 = 0.9345 для Helvetica Neue,
   0.9310 для Arial. Берём середину 93.27%, тогда обе укладываются
   в 0.15% от Jost при допуске 2%.

   Мерить обязательно на боевом кегле: у системного шрифта macOS ширины
   зависят от размера (оптические начертания), на 200px те же замеры дают
   другие числа и подгонка уезжает.

   Liberation Sans метрически совпадает с Arial, он для Linux. */
@font-face {
  font-family: 'Jost fallback';
  font-style: normal;
  font-weight: 300;
  src: local('Helvetica Neue'), local('Arial'), local('Helvetica'),
       local('Liberation Sans');
  size-adjust: 93.27%;
}

/* ── Палитра ──────────────────────────────────────────────────────────────
   Снята пипеткой с картинки клиента.

   Фон затемнён по просьбе клиента, дважды: «светлый фон кажется слишком
   светлым», «светлый фон светловат, чуть темнее надо».
     было  #F7F1E8, отн. яркость 0.885, разница красного и синего 15
     стало #EFE4D3, отн. яркость 0.785, разница красного и синего 28
   То есть фон не только темнее на две ступени, но и заметно теплее:
   почти белый ушёл, остался песочный.

   Поверхность карточек разведена с фоном: прежний фон #F7F1E8 и новый
   #EFE4D3 отличались бы в 1.01 раза, то есть не отличались бы вовсе.
   Поверхность теперь светлее фона в 1.11 раза плюс тонкая граница. */

:root {
  --bg:      #EFE4D3;
  --surface: #F7F0E5;
  --dark:    #3E2F20;
  /* Плашка среднего тона и текст на ней. Пара подобрана замером для блока
     «Когда котёнок переедет» - клиент просила тон «ни светлый ни тёмный,
     как в шапке по середине под листом». Разбор, почему на этом фоне
     не берёт ни штатный тёмный текст, ни штатный светлый, лежит в этом же
     файле над правилом .moving; там же три показанных клиенту варианта.

     ПОДНЯТА СЮДА 16.08.2026. Раньше объявлялась внутри .moving, но тем же
     тоном теперь заняты две плашки на главной, и держать источник правды
     внутри блока, которого на главной больше нет, нельзя. Значения
     не изменились ни на единицу: #816448 и #F7F0E5, контраст 4.82
     при пороге 4.5. */
  --plate-bg:   #816448;
  --plate-text: #F7F0E5;
  /* Фон шапки. Осветлён по просьбе клиента: полоса меню была
     слишком тёмной. Контраст --gold-light на нём 6.48:1, порог 4.5
     проходит. Отдельная переменная, чтобы не двигать --dark,
     на котором стоят подвал и тёмные секции. */
  --header-bg: #4B3928;
  --brown:   #7A5432;
  --accent:  #A67B4E;
  --text:    #2B211A;
  --muted:   #6B5A48;

  /* Золотая гамма. Снята пипеткой с 02-референсы/6fcb179f...JPG, блок «О НАС»:
     брали ядро штриха, то есть самые светлые пиксели глифов, иначе тонкие
     края букв смешиваются с коричневым фоном и тянут выборку в тень.
     Снятые значения теплее присланных ориентиров: вся картинка залита тёплым
     светом, и это в ней читается как характер, поэтому оставляем как снято.
       заголовок «О НАС»     #E8C093  (ориентир был #E3CFA6)
       подзаголовки пунктов  #D8B796  (ориентир был #C9A87C)
       основной текст        #E3C4A7  (ориентир был #D9CDBA)
     Чистого белого и чистого чёрного на картинке нет нигде.

     --gold-deep на ней взять негде: светлого фона там нет. Раньше стоял
     присланный #8B6534. После затемнения фона он даёт на нём 4.17:1 и
     порог 4.5:1 не проходит, поэтому притемнён до #845E2C: на новом фоне
     4.62:1. Оттенок сохранён, тон тот же тёплый золотисто-коричневый,
     насыщенность даже чуть выше. */
  --gold-light: #E8C093;
  --gold:       #D8B796;
  --gold-deep:  #845E2C;
  --cream:      #E3C4A7;

  /* Цвет декора: линий, обводок и кружков иконок. Идёт за фоном, потому что
     светлое золото на светлом фоне почти не видно. */
  --deco: var(--accent);

  /* Типографическая шкала, четыре уровня. Разница между соседними видна
     сразу: у заголовка и подзаголовка отличаются и размер, и разрядка,
     и регистр, и цвет. */
  --fs-h2:      clamp(28px, 3.2vw, 44px);
  --fs-sub:     clamp(14px, 1.05vw, 16px);
  --fs-body:    clamp(16px, 1.3vw, 18px);
  --fs-caption: 13px;
  /* 0.16em, а не прежние 0.15: заголовки разделов переведены на Jost
     (правка Б1 от 14.08.2026), у гротеска строка плотнее антиквы.
     Запасной вариант .v-font-cormorant возвращает 0.15em. */
  --tr-h2:  0.16em;
  --tr-sub: 0.08em;

  /* Высота верхней полосы. Было 76px, пятым кругом ужата на четверть до 58:
     клиент про прежнюю версию - «тут шапка лучше выглядит, по масштабу»
     и «меню сверху потемнело». Полоса стала ниже, тёмного в ней меньше
     на 24%, а освободившиеся 18px ушли в высоту первого экрана. */
  --head-h: 58px;
  --wrap: 1280px;          /* полезная ширина контента и родной размер кадра */
  --ease: 200ms ease;      /* та же длительность, что у подчёркивания меню */
  --radius-pill: 999px;    /* скругление кнопок, общий стиль на весь сайт */

  /* Шрифт заголовков разделов. Правка Б1 от 14.08.2026, применён вариант 1.
     Клиент: «Шрифт надо поменять заголовки везде "о питомнике", 2010,
     без засечек на другой». Это требование, не выбор, поэтому значение
     стоит прямо здесь, а не в классе-переключателе у body - тем же
     приёмом, что и название первого экрана.

     Взят тот же Jost Light 300, что в названии «VIOLA ALBA»: на странице
     остаётся два шрифта вместо трёх, заголовок и название звучат одним
     голосом. Cormorant Garamond никуда не удалён, он остался запасным
     вариантом в классе .v-font-cormorant ниже и показан в _variants.html.

     Одной переменной меняются сразу: заголовки разделов, число «2010»,
     имена котят в карточках, имена авторов отзывов и телефон в мобильной
     панели - всё, что идёт через --font-display. */
  --font-display: 'Jost', 'Jost fallback', system-ui, -apple-system,
    BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  --name-tracking: 0.17em;
  --name-weight: 300;

  /* Цвета текста первого экрана. По умолчанию раскладка «фото сверху,
     текст под ним на светлом фоне», поэтому взяты тёмные оттенки золотой
     гаммы: светлое золото на светлом фоне даёт 1.36:1 и не читается.
     Поверх фотографии, от 1101px, значения переопределяются на светлые. */
  --hero-fg-1: var(--gold-deep);   /* название */
  --hero-fg-2: var(--gold-deep);   /* подпись под названием */
  --hero-fg-3: var(--gold-deep);   /* фраза «Красота диких линий» */
  --hero-fg-4: var(--text);        /* строка про 2010, информационная */
  /* Ромбы по краям фразы. На светлом фоне был --gold, он давал 1.5:1
     и практически не читался. Теперь тот же тон, что у самой фразы. */
  --hero-dot:  var(--gold-deep);

  /* Кнопки. Клиент выбрала песочный вариант, два других удалены.
     Шестой круг: «кнопка песочная ярковата, заменить на цвет потусклее».
     Приглушена по насыщенности и по светлоте сразу, тон тот же:
       было  #D8C3A5  H35 S40 L75
       стало #CBB89C  H36 S31 L70
     Контраст текста #2B211A к заливке 8.15:1 (порог 4.5), заливки
     к тёмному полю первого экрана 5.68:1 (порог 3). Замер по реальным
     пикселям - в README.
     Тем же цветом красится подчёркивание активного пункта меню:
     «полоску под меню что высвечивается такого же цвета». */
  /* Девятый круг. Выяснилось, что «цвет терактов» в замечании клиента -
     это терракотовый, а не «потусклее»: «про кнопку терракотовую забыли
     и полоску под разделами меню и контур кнопки ватсап - её тоже
     в такой же цвет». Терракота заводится отдельной переменной,
     палитра не трогается.

     Оттенок подобран по контрасту, а не на глаз. Замеры кандидатов:
       #C8785A  к полю 4.03, к шапке 3.28, тёмный текст 4.71  <- принят
       #BC6C4C  к полю 3.46, к шапке 2.81, тёмный текст 4.04
       #AD5F41  к полю 2.88, к шапке 2.34, светлый текст 4.13
       #9E5636  к полю 2.46, к шапке 2.00, светлый текст 4.83
     Темнее #C8785A нельзя: либо текст на кнопке проваливает порог 4.5,
     либо подчёркивание в меню перестаёт читаться на шапке. */
  --terracotta: #B0603F;
  --terracotta-deep: var(--terracotta);   /* один цвет во всех трёх местах */

  /* ── ПЕСОЧНАЯ ТРОЙКА: фон и два цвета текста на нём ──────────────────────
     Подложка и пара цветов, которые на ней берут порог 4.5. Тройка
     подобрана 14.08.2026 под карточку котёнка (правка А9, клиент: «тело
     карточки залить цветом бейджа Свободна»), с 16.08.2026 ею же
     заливаются «О питомнике», бегущая лента и карточки статей.

     ПЕРЕИМЕНОВАНА 16.08.2026 из --kitten-card-*. Имя врало: карточка
     котёнка теперь один из четырёх потребителей, а не единственный.
     Значения не тронуты ни на единицу, это чистое переименование.

     ЗАЧЕМ ВООБЩЕ ДВА ОТДЕЛЬНЫХ ЦВЕТА ТЕКСТА. Штатная пара сайта на этой
     подложке порог не берёт, замер по реальным пикселям:

         --muted     #6B5A48   3.86   порог 4.5   НЕ берёт
         --gold-deep #845E2C   3.39   порог 4.5   НЕ берёт
         --accent    #A67B4E   2.20   порог 3.0   НЕ берёт (декор)
         --text      #2B211A   9.19   порог 4.5   берёт

     То есть на песке живут только --text и эта тройка. Осветлить сам песок
     вместо затемнения текста нельзя: предел, при котором --gold-deep ещё
     берёт 4.5, это #ECE2D3, а --accent - #EEE4D7. Нынешний --bg #EFE4D3
     стоит ровно там же, и «песочный на тон светлее» выродился бы в тот же
     фон, что уже есть. Разбор с числами - в отчёте круга от 16.08.2026.

     --sand-label. Подпись и значение в строке характеристики. #5A4A3A
     даёт 4.96. Одним цветом на обе подложки не обойтись: на --surface
     стоит --muted #6B5A48 (5.83), на песке он проваливается до 3.86.

     --sand-name. Заголовок на песке: имя котёнка, заголовок карточки
     статьи, кнопка «Читать дальше». #6B4C24 даёт 4.57. Оттенок тот же
     золотисто-коричневый, что у --gold-deep, тон H31 против H32 -
     рядом их не отличить, а порог берётся.

     ПОЧЕМУ НЕ ПОДВИНУТЬ САМ --gold-deep. Он стоит ещё в двадцати с лишним
     местах и подбирался под ДРУГИЕ фоны: под --bg #EFE4D3 он даёт 4.62
     и порог берёт. Двигать его ради песочных блоков значит перемерять
     весь сайт.

     ПОСЛАБЛЕНИЯ ДЛЯ КРУПНОГО ТЕКСТА ЗДЕСЬ НЕТ. Имя котёнка 22px при весе
     300: порог 3.0 начинается с 18.66px только для полужирного, для light -
     с 24px. Нужен полный 4.5. Крупные заголовки .h-section (35px) и число
     «2010» (77px) под послабление подпадают и остаются на --gold-deep:
     3.39 при пороге 3.0. Запас там 0.39, число названо сознательно. */
  --sand-bg:    #D8C3A5;
  --sand-label: #5A4A3A;
  --sand-name:  #6B4C24;

  --btn-bg: var(--terracotta);
  --btn-fg: #2B211A;
  --btn-bd: var(--terracotta);
  --btn-bg-hover: #9A5236;
  --btn-out-bd: var(--terracotta);
  --btn-out-fg: #2B211A;
}

/* ── Запасные шрифты заголовков разделов ─────────────────────────────────
   Живая страница на Jost, значения стоят в :root. Классы ниже - запасные:
   вешаются на body или на любую обёртку и возвращают антикву, потому что
   переменные наследуются. Ими же собран живой образец в _variants.html.

   .v-font-cormorant возвращает и разрядку 0.15em: у антиквы строка
   и без того шире, 0.16em её распускает. */

/* Начертание 300, а не 400. Замер по надписи BENGAL CATS с картинки клиента:
   вес штриха относительно высоты прописных у неё 0.082, у Cormorant 300
   ровно 0.082, у Cormorant 400 уже 0.103. Cormorant вариативный, поэтому
   облегчить его можно, а Forum и Playfair статические, только 400. */
.v-font-cormorant {
  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --name-tracking: 0.17em;
  --name-weight: 300;
  --tr-h2: 0.15em;
}
.v-font-forum {
  --font-display: 'Forum', Georgia, 'Times New Roman', serif;
  --name-tracking: 0.15em;
  --name-weight: 400;
  --tr-h2: 0.15em;
}
.v-font-playfair {
  --font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --name-tracking: 0.11em;   /* шрифт шире остальных, разрядку убавляем */
  --name-weight: 400;
  --tr-h2: 0.15em;
}

/* ── Название гротеском: решение принято, не вариант ─────────────────────────
   Клиент: «название гротеском, заголовки разделов оставить антиквой».
   Поэтому здесь не класс-переключатель, а обычное правило: название
   на первом экране, подпись под ним, название в шапке и название
   в мобильной панели набраны Jost Light 300 заглавными, разрядка 0.18em.

   Заголовки разделов (.h-section, «2010», имена котят) НЕ трогаются:
   они идут через --font-display, то есть остаются антиквой. */
.hero__name,
.hero__tagline,
.brand__name,
.brand__sub,
.mobile-menu__name {
  /* 'Jost fallback' стоит сразу за Jost и впереди системных: это тот же
     системный шрифт, но с выправленной шириной (см. @font-face выше).
     -apple-system в Chromium не подхватывается и уходит в system-ui,
     проверено замером, поэтому system-ui записан явно. */
  font-family: 'Jost', 'Jost fallback', system-ui, -apple-system,
    BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  font-weight: 300;
  letter-spacing: 0.18em;
}

/* Вариантов цвета кнопок больше нет: клиент выбрала песочный,
   терракотовый и молочный удалены отсюда и из _variants.html.
   Значения выбранного варианта стоят прямо в :root, класса у body не нужно. */

/* ── База ─────────────────────────────────────────────────────────────────── */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Шапка фиксированная, поэтому переход по якорю без этого отступа
     кладёт заголовок под неё. */
  scroll-padding-top: var(--head-h);
}

/* ── Датчики прокрутки ────────────────────────────────────────────────────
   Невидимые прямоугольники, за ними следит IntersectionObserver вместо
   обработчика прокрутки. Ширина 1px, из потока выведены, фона нет.

   Датчики НЕ высотой в 1px, и это осознанно: тонкую полоску наблюдатель
   может не заметить. Событие приходит только когда область пересечения
   проходит через ноль, а рывок прокрутки переносит тонкий датчик из
   положения «ниже экрана» сразу в «выше экрана», не пересекая его.
   Прямоугольник, растянутый до самого порога, перескочить нельзя:
   его нижний край обязан пройти через границу наблюдения. */
.scroll-probe {
  position: absolute;
  left: 0;
  width: 1px;
  pointer-events: none;
  visibility: hidden;
}
/* Датчик шапки ставится скриптом внутрь .hero__media и занимает её целиком,
   поэтому едет вместе с фотографией и не требует пересчёта порога. */
.scroll-probe--hero { inset: 0; }
/* Датчик кнопки «наверх»: от начала документа до глубины 600px.
   Позиционированного предка у него нет, значит отсчёт идёт от начала
   документа. Кнопка появляется, когда нижний край уходит за верх окна. */
.scroll-probe--600 { top: 0; height: 600px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Onest', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* отступа под шапку нет: шапка прозрачная и лежит поверх фотографии,
     первый экран начинается сразу под верхом окна */
}

h1, h2, h3 { margin: 0; font-weight: 400; line-height: 1.16; }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 28px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   ВЕРХНЯЯ ПОЛОСА

   Правка клиента: «вы можете совместить фон с шапкой чтоб более понятно
   было». До неё шапка была полупрозрачным стеклом шириной ровно в кадр,
   1280px, а по бокам от него шли поля цветом --dark. Получалось три разных
   тона в одной строке: тёмное поле слева, стекло поверх светлой части
   фотографии посередине, тёмное поле справа. Плюс на нижнем крае стекла
   читалась горизонтальная линия - стык шапки и кадра.

   Теперь шапка залита сплошным --dark во всю ширину окна, тем же цветом,
   что и боковые поля и полоса над кадром. Три элемента слились в одно
   тёмное поле, границ между ними нет вовсе.

   Кадр при этом опущен под шапку целиком: секции первого экрана добавлен
   отступ сверху ровно в высоту шапки. Иначе шапка накрывала бы верх
   фотографии, а там у кошки уши, см. комментарий в блоке ПЕРВЫЙ ЭКРАН.

   При прокрутке, когда под шапкой оказывается светлый фон страницы,
   заливка становится светлой и появляется тонкая линия снизу: иначе меню
   сливается со страницей. Класс is-scrolled ставит скрипт.

   ПЯТЫЙ КРУГ. Клиент: «тут шапка лучше выглядит, по масштабу» (про раннюю
   версию) и «меню сверху потемнело». Сделано три вещи:

   1. Полоса ужата с 76 до 58px, на четверть. Тёмного в ней стало меньше
      ровно на столько же, а 18px ушли в высоту первого экрана.
   2. Название вернулось в шапку и стоит там постоянно, а не только после
      прокрутки: слева VIOLA ALBA и мелкой строкой подпись. Кегль подписи
      подобран так, чтобы не спорить с крупным названием первого экрана:
      18px против 34-64px, то есть от 1.9 до 3.5 раза мельче.
   3. Два варианта заливки на выбор клиенту, переключаются классом у body:

      вариант A, без класса      сплошная --dark, как была, только ниже;
      вариант B, .v-head-glass   rgba(--dark, 0.78) плюс backdrop-filter
                                 blur(10px), фотография поднята под шапку
                                 и просвечивает сквозь неё.

      Просили 0.55. Замерено по реальным пикселям кадра: под шапкой в этой
      раскладке оказывается самый светлый участок стены, отн. яркость 0.52
      на 1920 и 0.55 на 1101, и при 0.55 непрозрачности меню даёт 2.79:1
      против порога 4.5:1. Минимальное значение, при котором проходит, -
      0.77; поставлено 0.78 с небольшим запасом, замер в README.
   ========================================================================== */

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 60;
  height: var(--head-h);
  color: var(--gold-light);
  background: var(--header-bg);
  border-bottom: 1px solid transparent;

  /* Переход сужен с четырёх свойств до двух и с 200 до 120мс. Раньше вместе
     с заливкой ехали box-shadow и border-color: на телефоне это давало
     мигание в момент переключения класса. Тень и граница теперь встают
     сразу, на глаз этого не видно - они обе почти прозрачные. */
  transition: background-color 120ms ease, color 120ms ease;

  /* Своя плоскость композитора. Без неё Safari перерисовывает шапку вместе
     с содержимым страницы и отстаёт на кадр: кусок текста успевает лечь
     поверх шапки. Настоящий iOS проверить нечем, правка сделана
     по описанию симптома, см. README. */
  transform: translateZ(0);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

/* Вариант B. Непрозрачность 0.78, не 0.55: см. замер в комментарии выше.
   Фотография поднимается под шапку (padding-top у .hero снят), иначе
   просвечивать было бы нечему - там стояла бы тёмная полоса .hero::before. */
.v-head-glass .header {
  background: rgba(75, 57, 40, 0.78);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.v-head-glass .hero { padding-top: 0; }
.v-head-glass .hero::before { display: none; }
/* Кадр поднялся под шапку, а текст подниматься не должен: верхний отступ
   отсчитывается от НИЖНЕГО края шапки, иначе название первого экрана
   наполовину уезжает под меню. Группа при этом остаётся центрированной,
   только уже в оставшемся под шапкой пространстве. */
.v-head-glass .hero__copy { padding-top: calc(var(--head-h) + 40px); }

/* Меню на тёмном поле светлым золотом, после прокрутки на светлом фоне
   переключается на тёмное золото. Замер: --gold-light на --dark даёт
   7.59:1, --gold-deep на новом --bg даёт 4.62:1. Оба проходят порог.

   ЗАЛИВКА НЕПРОЗРАЧНАЯ, правка 13.08 после независимой проверки.
   Было rgba(239,228,211,0.94) плюс backdrop-filter. Пока ниже первого
   экрана ничего не было, шесть процентов просвета ничего не портили.
   С появлением остальных блоков под шапку стали заезжать две тёмные
   секции и две с фотографиями, фон под меню темнел, и контраст падал
   до 4.15-4.36 при пороге 4.5. Замер по реальным пикселям под всеми
   девятью секциями - в README, раздел «Правки после независимой
   проверки».

   backdrop-filter снят вместе с прозрачностью: размывать нечего,
   а слой он создавал и композитор грел. Цвет тот же самый, --bg,
   поэтому над светлыми секциями вид шапки не изменился вовсе:
   там и раньше под ней был ровно этот цвет. */
.header.is-scrolled {
  color: var(--gold-deep);
  background: var(--bg);
  border-bottom-color: rgba(62, 47, 32, 0.10);
  box-shadow: 0 2px 16px rgba(62, 47, 32, 0.07);
}

.header__inner {
  position: relative;   /* выше стекла */
  z-index: 1;
  height: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 28px;
  display: flex;
  align-items: center;
  gap: 22px;
}

/* От 1101px шапка разворачивается во всю ширину окна, а её левое поле
   равно левому полю текстовой колонки первого экрана. Причина: первый
   экран идёт во всю ширину (фотография прижата к правому краю окна),
   и при прежней раскладке в 1280px по центру мелкое VIOLA ALBA в шапке
   стояло на 1920 в трёхстах пикселях правее крупного VIOLA ALBA под ней.
   Два одинаковых слова, сдвинутых друг относительно друга, читаются
   как ошибка вёрстки. Теперь они на одной вертикали. */
@media (min-width: 1101px) {
  .header__inner {
    max-width: none;
    padding-left: var(--hero-pad-l, 44px);
    padding-right: var(--hero-pad-l, 44px);
  }
}

/* ── Логотип и надпись в шапке ────────────────────────────────────────────
   Шестой круг. Клиент: «в углу повторяется название, как то не очень.
   Можете туда вставить Bengal cats из картинки новой. и логотип»,
   и отдельно: «чтоб он сильно не выделялся цветом. На остальных пусть
   логотип и название питомника».

   Отсюда две вещи.

   1. ЛОГОТИП НЕ КАРТИНКОЙ, А МАСКОЙ. Файл 02-референсы/Лого4.png взят
      вместо Лого3: контраст к фону шапки #4B3928 у четвёртого 8.45,
      у третьего 4.48 - на тёмном третий почти пропадает. Но собственный
      цвет четвёртого (250,224,151) желтее всей палитры и на шапке тянет
      взгляд. Поэтому в assets/img/logo-mask.png лежит только альфа
      рисунка, а заливку даёт CSS: --gold #D8B796, контраст к шапке 5.82.
      Виден уверенно, но приглушён и попадает в гамму сайта.
      Непрозрачность 0.9: на скриншоте при 1.0 логотип всё ещё был самым
      светлым пятном шапки. Контраст при 0.9 - 4.94, порог для графики
      3:1 проходит с запасом.

   2. НАДПИСЬ РАЗНАЯ НА ГЛАВНОЙ И НА ВНУТРЕННИХ. На главной BENGAL CATS,
      имя питомника из шапки убрано - оно стоит крупно на первом экране,
      и повторять его в углу незачем. На внутренних страницах крупного
      названия нет вовсе, поэтому там VIOLA ALBA и подпись под ним.
      Переключение классом page-home у body, разметка одна.

   Кегль везде намеренно мелкий: это подпись, а не второй заголовок. */
.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  flex: 0 0 auto;
  line-height: 1.1;
}

.brand__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.brand__logo {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  background-color: var(--gold);
  opacity: 0.9;
  -webkit-mask-image: url('../img/logo-mask.png');
          mask-image: url('../img/logo-mask.png');
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
  transition: background-color var(--ease), opacity var(--ease);
}
/* На прокрученной светлой шапке светлое золото пропадает: 1.4:1.
   Тот же рисунок заливается тёмным золотом, 4.62:1. */
.header.is-scrolled .brand__logo { background-color: var(--gold-deep); opacity: 1; }

/* BENGAL CATS. Приём взят с картинки клиента (02-референсы/WhatsApp Image
   2026-08-13 at 10.41.43.jpeg): слева круглый контурный значок, справа
   короткая надпись заглавными с широкой разрядкой. Пиксели оттуда не
   копировались, это сгенерированный макет, а не работающий сайт. */
.brand__bengal {
  display: none;
  font-size: 15px;
  letter-spacing: 0.22em;
  color: currentColor;
  white-space: nowrap;
}

/* Главная: BENGAL CATS вместо имени питомника. Внутренние: наоборот. */
.page-home .brand__bengal { display: block; }
.page-home .brand__name,
.page-home .brand__sub { display: none; }

.brand__name {
  font-size: 18px;
  /* Jost 300 и разрядка 0.18em заданы одним правилом вместе с названием
     первого экрана, см. раздел «Название гротеском» выше.
     text-transform здесь намеренно нет: заглавные стоят прямо в разметке.
     Текст правится через админку, и в редакторе клиент должна видеть
     ровно то, что на сайте. Плюс если правило слетит, название не
     превратится в строчные. */
  color: currentColor;
  white-space: nowrap;
}

/* Прозрачности нет по той же причине, что у подписи первого экрана: при
   0.72 и кегле 11px на светлой прокрученной шапке выходило 2.93:1.
   Тише названия эта строка и так: 12px против 18px. Разрядка убавлена
   до 0.06em - при 0.18em строка из 26 букв не влезала рядом с меню.

   КЕГЛЬ 12px, ОДНО ЗНАЧЕНИЕ НА ВСЕ ШИРИНЫ. Клиент 16.08.2026: подпись
   слишком мелкая. Было четыре разных значения по брейкпоинтам - 9px на
   1101-1340, 9px до 760, 10px до 1100 и 10px выше 1341; все три
   переопределения сняты, осталось это одно.

   Замер перед правкой опроверг опасение, что в шапке нет места. Занят
   не .nav (он flex: 1 1 auto и по определению съедает весь остаток),
   а .nav__list внутри него, и он уже: на 1101 список 547.9 при .nav
   613.2, то есть свободно 65.3px - по 54.6 с каждой стороны меню.
   При 12px блок названия растёт со 174.1 до 215.1, зазоры падают
   до 34.1 и 34.2 при пороге 16. Высота шапки 58/76/56 не меняется
   ни на одной ширине, блок .brand остаётся 40px по высоте.

   Разрядку, зазоры пунктов меню и поле шапки трогать не потребовалось.
   Поле шапки трогать и НЕЛЬЗЯ: .header__inner берёт --hero-pad-l,
   а та же переменная задаёт левое поле текстовой колонки первого экрана
   главной, который менять запрещено. */
.brand__sub {
  margin-top: 3px;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: currentColor;
  white-space: nowrap;
}

/* По центру: горизонтальное меню.
   position: relative - точка отсчёта для бегающей полоски: её координаты
   считаются от левого верхнего угла .nav. */
.nav {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
}

.nav__list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  align-items: center;
  gap: 20px;
}

/* СОБСТВЕННОГО ::after У ПУНКТА БОЛЬШЕ НЕТ и заводить обратно нельзя.
   Он рисовал полоску под каждым пунктом отдельно, и одновременно светились
   две: постоянная под активным и наведённая под соседним. Вместо него один
   .nav__indicator ниже. */
.nav__link {
  display: block;
  padding: 6px 0;
  font-size: 15px;
  font-weight: 400;
  color: currentColor;
  white-space: nowrap;
  transition: color var(--ease);
}

.nav__link:hover,
.nav__link:focus-visible { color: var(--gold); }
.header.is-scrolled .nav__link:hover,
.header.is-scrolled .nav__link:focus-visible { color: var(--brown); }

/* ── Бегающее подчёркивание, одно на всё меню ─────────────────────────────
   Полоска одна и та же: она переезжает под наведённый пункт и возвращается
   под активный, когда курсор ушёл с меню. Ширина берётся по ширине пункта,
   поэтому под коротким «Коты» линия короткая, под «Выпускники» длинная.

   Переходов ровно два, transform и width, оба на композиторе не считаются
   заново по раскладке. Длительность общая, --ease, та же что у цвета
   ссылки: полоска и подсветка текста доезжают вместе.

   left/top в переходе НЕТ намеренно. Вертикаль ставится скриптом разово
   (у пунктов разный padding на разных ширинах) и не должна ползти вслед
   за горизонтальным переездом.

   Стартовое состояние - width: 0 и transition: none. Класс is-ready вешает
   скрипт после первого замера: иначе при загрузке полоска приехала бы
   из нулевой ширины в левом углу, растягиваясь на глазах. */
.nav__indicator {
  position: absolute;
  left: 0;
  top: 0;
  height: 2px;
  width: 0;
  background: var(--btn-bg);
  transform: translateX(0);
  pointer-events: none;
}

.nav__indicator.is-ready {
  transition: transform var(--ease), width var(--ease);
}

/* Мгновенная перестановка без анимации: первый замер, изменение ширины окна
   и дозагрузка шрифта. Там переезд не жест пользователя, а пересчёт,
   и ехать полоске незачем. Тот же класс скрипт вешает при системной
   настройке «меньше движения». */
.nav__indicator.is-instant { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .nav__indicator.is-ready { transition: none; }
}

/* Прокрученная шапка светлая. Цвет тот же терракотовый, что и на тёмной:
   девятым кругом --terracotta-deep сведён к --terracotta, отдельная
   переменная оставлена как точка правки, если оттенки снова разойдутся. */
.header.is-scrolled .nav__indicator { background: var(--terracotta-deep); }

/* Без JS полоска не появится вовсе - и это рабочее состояние, а не потеря:
   текущая страница объявлена через aria-current="page", а меню в шапке
   всё равно продублировано мобильной панелью. Мёртвой линии в левом углу
   при этом не остаётся: ширина нулевая. */

/* Справа: телефон и две круглые кнопки */
.header__side {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
}

.header__phone {
  font-size: 17px;
  font-weight: 500;
  color: currentColor;
  white-space: nowrap;
  transition: color var(--ease);
}
.header__phone:hover { color: var(--gold); }
.header.is-scrolled .header__phone:hover { color: var(--brown); }

.circle {
  width: 38px; height: 38px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(62, 47, 32, 0.07);
  border: 1px solid rgba(62, 47, 32, 0.22);
  color: var(--text);
  transition: background var(--ease), border-color var(--ease),
              color var(--ease), transform var(--ease);
}
.circle svg { width: 19px; height: 19px; fill: currentColor; }
.circle:hover {
  background: var(--brown);
  border-color: var(--brown);
  color: #FBF6EE;
  transform: translateY(-2px);
}

/* Мессенджеры в фирменных цветах, значки белые.
   Кнопок первого экрана это не касается, у них свои варианты заливки. */
.circle--wa {
  background: #25D366;
  border-color: #25D366;
  color: #FFFFFF;
}
.circle--wa:hover {
  background: #1EBE5A;
  border-color: #1EBE5A;
  color: #FFFFFF;
}
.circle--tg {
  background: #229ED9;
  border-color: #229ED9;
  color: #FFFFFF;
}
.circle--tg:hover {
  background: #1C89BD;
  border-color: #1C89BD;
  color: #FFFFFF;
}

/* Бургер, виден только на телефоне */
.burger {
  display: none;
  width: 42px; height: 42px;
  padding: 0;
  background: none;
  border: 1px solid currentColor;
  border-radius: 8px;
  cursor: pointer;
  color: inherit;
}
.burger span {
  display: block;
  width: 20px; height: 1.5px;
  margin: 4px auto;
  background: currentColor;
  transition: transform var(--ease), opacity var(--ease);
}
.burger[aria-expanded='true'] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.burger[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded='true'] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* ==========================================================================
   ПЕРВЫЙ ЭКРАН

   Клиент: «Шапку очень затемнили особенно слева, хвост вообще в темноте.
   И сверху сбоку затуманили, я знаю что не хватает картинки, но я думала
   фон прибавить по бокам, не темнить картинку». И уточнение: «Поля ближе
   к фону картинки». Три слоя, которые раньше лежали поверх кадра -
   hero__fade (виньетка у краёв), hero__scrim (тёмный градиент под текст)
   и верхнее затухание под шапкой - убраны целиком. Поверх фотографии
   не лежит ничего.

   ДВЕ РАСКЛАДКИ.

   До 1101px - прежняя, не тронута этой правкой: фотография во всю ширину
   экрана сверху, текст под ней на --bg, обрезается по бокам object-fit:
   cover, полей нет.

   От 1101px - фотография вплотную к правому краю ОКНА, не к колонке.

   Четвёртый круг правок: «на hero-1920.jpg и hero-1440.jpg справа от
   кошки видна зона в горизонтальную полоску: тень листа монстеры
   обрывается на краю кадра и дальше идёт растянутыми полосами». Это была
   .hero__field-right - растянутый на всю оставшуюся ширину столбец
   hero-edge-right.png. Прошлый круг сам честно предупреждал, что это
   будет заметно на широких экранах, и оказался прав. Решение: правого
   поля больше не существует. Файл hero-edge-right.png удалён из проекта.

   Раньше .hero__media была ФЛЕКС-СОСЕДОМ .hero__copy: ширина фотографии
   считалась как «что осталось после текста», а остаток после фотографии
   заливался отдельным полем. Теперь .hero__media - position: absolute,
   right: 0 у самого .hero__row, ширина не зависит от того, сколько места
   занял текст. Фотография ВСЕГДА прижата к правому краю окна, ни при
   какой ширине там не может появиться зазор: и «правое поле» с его
   полосами перестаёт быть нужно не потому, что его чем-то прикрыли,
   а потому что классу задачи, для которой оно было придумано, больше
   неоткуда взяться.

   ПЯТЫЙ КРУГ. Клиент посмотрела 1440 и 1920 и сказала три вещи: «тут
   шапка лучше выглядит, по масштабу» (про раннюю версию, где кошка была
   крупнее), «пустой угол слева наверху смотрится плохо», «сейчас темно
   всё стало». Все три - про одно и то же: кадр вписывался в блок целиком,
   поэтому блок выходил низким (41.6vw), кошка мелкой, а над названием
   оставалась широкая тёмная пустота.

   Сделано:

   1. Высота ряда поднята с 41.6vw до 50vw. На 1440 это 599 -> 720px.
   2. Кадр переведён с «вписать целиком» на «заполнить с обрезкой»:
      object-fit: cover и срез 120px слева, там пустая стена. Кошка
      на 1440 выросла с 465 до 559px по высоте.
   3. Доля фотографии в окне поднята с 62.4% до 68.0%, левое поле
      соответственно сузилось: на 1440 с 541 до 461px.
   4. Текстовый блок собран в одну плотную группу с фиксированными
      интервалами и центрирован в колонке со смещением вверх на 5%.

   Числа и почему именно они - в комментарии у медиазапроса ниже.

   ЛЕВОЕ ПОЛЕ СОБРАНО ИЗ КРАЯ САМОГО КАДРА, а не из палитры сайта - это
   ключевое требование клиента, подтверждено: «там шов не виден». Пятым
   кругом файл assets/img/hero-edge-left.png пересобран: раньше это был
   крайний столбец исходника (2px), теперь столбцы 0-119, то есть ровно
   та полоса стены, которая уходит под срез кадра. Поле растягивается
   не на весь ряд, а ровно до левого края фотографии, поэтому его
   последний столбец (119) встаёт встык к первому видимому столбцу
   кадра (120). Замер стыка: перепад 0.34-0.45 единицы на 255 - меньше,
   чем естественный градиент стены на том же расстоянии.

   ЦВЕТ ТЕКСТА пересчитан заново по реальным пикселям, потому что поле
   теперь другое: оно светлеет слева направо, как настоящая стена.
   Худшее значение 5.07:1 при пороге 4.5:1, таблица в README.

   КАДР НАЧИНАЕТСЯ ПОД ШАПКОЙ, а не от верха окна: кончик уха кошки
   стоит на 68-й строке исходника из 853. Уши в кадре с запасом
   44-68px до верхнего края блока, по вертикали не срезано ничего.
   В варианте B шапки (класс v-head-glass) кадр наоборот поднимается
   под шапку - иначе просвечивать нечему.
   ========================================================================== */

.hero {
  position: relative;
  overflow: hidden;
  background: var(--bg);
  padding-top: var(--head-h);
}

/* Полоса под шапкой, цветом --dark. Шапка непрозрачная и в состоянии покоя
   закрывает её целиком, но при прокрутке кадр уезжает вверх, и без этой
   полосы под шапкой на секунду показывалась бы светлая щель. */
.hero::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--head-h);
  background: var(--dark);
}

.hero__row {
  position: relative;
  display: flex;
  flex-direction: column;
}

/* container-type делает колонку контейнером запроса: 1cqw это один процент
   её КОНТЕНТНОЙ ширины, то есть уже без левого поля. Проверено замером:
   на 1101 колонка 352.89px по внешней коробке и 320.89 по контентной,
   100cqw дал 320.891. Ширина колонки задана формулой от ширины ряда,
   а не содержимым, поэтому подключение containment раскладку не меняет. */
.hero__copy { padding: 26px 18px 34px; container-type: inline-size; }

/* Фотография ниже 1101: прежнее поведение без изменений, отдельные
   media-правила задают высоту и обрезку по бокам на телефоне. Она стоит
   в разметке после текста (в DOM текст важнее - это то, что зачитает
   читалка экрана первым), а на экране должна идти первой - order переносит
   её визуально наверх, самого текста в HTML это не касается. */
.hero__media { position: relative; aspect-ratio: 1280 / 853; order: -1; }
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* 0. Заголовочная группа: название, подпись, фраза.
   Обёртка нужна для раскладки от 1101px: она делит колонку на три
   смысловых куска - заголовочный, абзац, кнопки - и позволяет держать
   внутри группы маленькие интервалы (14px и 22-34px), а между группами
   чуть большие (32px и 40px), не задавая их каждому элементу отдельно. */
.hero__title { display: block; }

/* 1. Название, главный элемент экрана.
   Шрифт не через --font-display: клиент выбрала гротеск для названия
   и антикву для заголовков разделов, поэтому Jost задан отдельным
   правилом (см. раздел «Название гротеском» выше), а --font-display
   остался антиквой и обслуживает h2, «2010» и имена котят. */
.hero__name {
  /* Кегль задаётся переменной, а не напрямую: медиазапросы ниже меняют
     только её, а окончательное значение считается один раз здесь.
     Так предохранитель по ширине колонки действует на всех брейкпоинтах,
     а не только на тех, где о нём вспомнили. */
  --hero-name-fs: clamp(30px, 8.6vw, 44px);

  /* ПРЕДОХРАНИТЕЛЬ. 14.13cqw это ровно та тесность, что подобрана восьмым
     кругом на 1101: строка «VIOLA ALBA» занимает 7.079 кегля, колонка плюс
     отыгранная отрицательным отступом разрядка дают 6.899 кегля запаса,
     отсюда потолок 1/6.899 = 14.49% ширины колонки; берём 14.13%, как
     на 1101 сейчас. Правило срабатывает только там, где нижняя граница
     clamp просит больше, чем колонка способна дать. Замер до правки:
     320px при масштабе 150% это раскладка 213px, колонка под текст 177px,
     а clamp требовал не меньше 28px, то есть строку в 198px. Там оно
     и рвалось. Ни на одной ширине, где строка и так влезала, кегль
     не изменился. */
  font-size: min(var(--hero-name-fs), 14.13cqw);

  /* НЕ СНИМАТЬ. Жёсткая гарантия одной строки при любом шрифте.
     Разбор в README, раздел «Правки по замечаниям клиента». */
  white-space: nowrap;

  line-height: 1.04;
  /* заглавные в разметке, не в стилях, см. .brand__name */
  color: var(--hero-fg-1);
  /* разрядка добавляет пустоту после последней буквы, убираем её,
     чтобы блок был оптически выровнен по левому краю */
  margin: 0 -0.18em 0 0;
}

/* Браузеры без контейнерных запросов: остаётся прежнее правило на vw.
   Перенос там по-прежнему исключён через white-space, а предохранителя
   по ширине колонки нет - его не на чем построить. */
@supports not (container-type: inline-size) {
  .hero__name { font-size: var(--hero-name-fs); }
}

/* 2. Подпись под названием.
   Прозрачности здесь нет. Она была, 0.82, чтобы подпись звучала на
   полступени тише названия. На светлом фоне это давало 3.33:1 при кегле
   14px, то есть ниже порога 4.5:1. Прозрачность оставлена только поверх
   фотографии, где фон тёмный и запаса хватает: см. блок от 1101px.
   На светлом разница с названием и так очевидна: 14px против 33px. */
.hero__tagline {
  margin: 14px 0 0;
  font-size: clamp(14px, 1.5vw, 22px);
  color: var(--hero-fg-2);
}

/* 3. Фраза клиента, самая мелкая. Цвет --gold. */
.hero__eyebrow {
  margin: 18px 0 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.24em;
  color: var(--hero-fg-3);
}

/* Ромбы по краям фразы, а не между словами: «точки между словами не там,
   а перед и после». Раньше фраза была разбита на три поля админки, по
   одному на слово, и ромбы стояли в промежутках. Теперь это снова одно
   поле hero.eyebrow со значением «КРАСОТА ДИКИХ ЛИНИЙ».

   Ромбы висят на абзаце, а не на редактируемом span внутри него. Клиент
   правит только содержимое span, поэтому стереть ромбы она не может даже
   если сотрёт текст целиком. Символа в тексте нет. */
.hero__eyebrow::before,
.hero__eyebrow::after {
  content: '';
  display: inline-block;
  width: 0.36em;
  height: 0.36em;
  background: var(--hero-dot);
  transform: rotate(45deg);
  vertical-align: 0.08em;
}
.hero__eyebrow::before { margin-right: 0.9em; }
/* слева меньше на разрядку: letter-spacing добавляет пустоту после
   последней буквы, и без поправки правый ромб отходил бы дальше левого */
.hero__eyebrow::after { margin-left: 0.66em; }

/* 4. Строка про год и города, информационная.
   Поверх фотографии она --cream: фон там тёмный, и заданный --text
   давал бы на нём 2.5:1. Под фотографией, где фон светлый, она --text. */
.hero__text {
  margin: 18px 0 0;
  font-size: clamp(15px, 1.2vw, 18px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--hero-fg-4);
  max-width: 34em;
}

/* 5. Кнопки.
   Клиент: «кнопки сделать одинаковыми по длине». Ширину числом не задаём -
   на другом тексте кнопки разъедутся. Вместо этого сетка: обе кнопки
   лежат в дорожках 1fr, а сам контейнер сжат по содержимому (width:
   max-content). По спецификации дорожка 1fr в контейнере с внутренним
   размером получает максимум из вкладов всех таких дорожек, то есть обе
   кнопки становятся ровно шириной самой широкой из них - какой бы текст
   в них ни стоял.

   Работает одинаково в обеих раскладках: до 560px поток строками, кнопки
   одна под другой во всю ширину колонки (обе равны ей, значит равны друг
   другу); от 561px поток колонками, обе равны широкой.

   Текст внутри центрируется правилом .btn (justify-content: center). */
.hero__actions {
  margin: 26px 0 0;
  display: grid;
  grid-auto-flow: row;
  grid-auto-columns: 1fr;
  gap: 14px;
}

/* От 561px кнопки встают в ряд, места хватает. Правило стоит здесь,
   а не в общем адаптивном блоке в конце файла: ниже по файлу лежит
   исключение для полосы 1101-1499, и оно должно перебивать это,
   а не наоборот. */
@media (min-width: 561px) {
  .hero__actions {
    grid-auto-flow: column;
    width: max-content;
    max-width: 100%;
  }
}

/* Кнопка овальная: --radius-pill вместо прежних 6px.
   Общий стиль кнопки, не точечная правка первого экрана - здесь
   единственное место, где заданы форма и отступы кнопок сайта.

   Чтобы овал читался как овал, а не как таблетка со сплюснутыми
   боками, горизонтальный отступ задан явно и минимум в 2.2 раза
   больше вертикального: 40px против 16px, отношение 2.5. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 52px;
  padding-block: 16px;
  padding-inline: 40px;
  border: 1.5px solid transparent;
  border-radius: var(--radius-pill);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--ease), color var(--ease),
              border-color var(--ease), transform var(--ease);
}

.btn--primary {
  background: var(--btn-bg);
  border-color: var(--btn-bd);
  color: var(--btn-fg);
}
.btn--primary:hover {
  background: var(--btn-bg-hover);
  border-color: var(--btn-bg-hover);
  transform: translateY(-2px);
}

/* Вторая кнопка контурная во всех вариантах, обводка подстроена под оттенок */
.btn--outline {
  background: transparent;
  border-color: var(--btn-out-bd);
  color: var(--btn-out-fg);
}
.btn--outline:hover {
  background: var(--btn-out-bd);
  border-color: var(--btn-out-bd);
  color: #FBF6EE;
  transform: translateY(-2px);
}

/* ── Раскладка от 1101 ──────────────────────────────────────────────────────
   Текст слева, фотография прижата к правому краю ОКНА, не колонки.
   Четвёртый круг правок: правое поле снято совсем, см. общий комментарий
   выше по файлу - там разобрано, почему прошлая версия давала полосы. */
@media (min-width: 1101px) {

  /* ГЕОМЕТРИЯ ПЕРВОГО ЭКРАНА, пятый круг правок. Три числа связаны жёстко,
     менять их можно только вместе, иначе разъедется стык поля и кадра.

     --hero-h        высота ряда, 50vw с потолком 853px
     1160 / 853      видимая часть исходника: 1280-120 по ширине, вся высота
     --hero-photo-w  ширина фотографии, ровно высота × 1160/853

     Почему 50vw. Было 41.6vw, клиент: кошка мелкая, «шапка лучше выглядит,
     по масштабу». На 1440 высота выросла с 599 до 720px, кошка с 465
     до 559px по высоте, это +20% в линейном размере и +45% по площади.

     Почему 1160, то есть срез 120px слева. Ширина фотографии считается
     от её высоты, поэтому при 50vw фотография без обрезки заняла бы
     50 × 1280/853 = 75.0% окна и на текст осталось бы 275px на ширине
     1101 - туда не встают ни название, ни кнопка. Срез слева убирает
     пустую стену и приводит долю к 68.0%: 50 × 1160/853. Ровно 120px
     не случайны, это предел по контрасту: поле собирается из этой же
     полосы стены, а стена вправо светлеет, и на столбце 125 контраст
     --gold к самой светлой строке падает до 4.27:1, ниже порога 4.5:1.
     На столбце 120 он ещё 4.76:1. Замер в README.

     Снизу не режем. Это единственное расхождение с заданием, и вот почему:
     размер кошки на экране задаёт ШИРИНА фотографии (масштаб = ширина
     показа / ширина видимой части исходника), а не высота блока. При
     доле, ограниченной сверху 72%, срез снизу не увеличивает кошку
     ни на пиксель - он только укорачивает блок и на столько же опускает
     потолок высоты, после которого фотография упирается в родные 853px.
     То есть срез снизу здесь работает против двух других требований
     сразу: против «поднять высоту» и против доли на 1920. Если всё же
     нужен - меняются два числа: 853 в двух дробях ниже на 853 минус срез,
     и hero-edge-left.png пересобирается на столько же строк короче.

     Потолок 853px - родная высота файла. Апскейла нет ни при какой
     ширине окна: при высоте 853 фотография показывается ровно
     1:1 своими пикселями, 1160 из 1280 столбцов. Потолок вступает
     на 1706px ширины окна. Выше него высота и ширина фотографии стоят
     на месте, а окно растёт, поэтому доля падает: 60.4% на 1920.
     Это цена запрета на растягивание, разбор в README. */
  /* СЕДЬМОЙ КРУГ, СРЕЗ 60 СТОЛБЦОВ. Шестой круг с его срезом 300 отменён.

     История среза, чтобы не ходить по кругу третий раз:

       0    поля нет вообще, текст ставить некуда;
       120  режет ровно по касательной к краю пуфа, и пуф выходит
            из ниоткуда горкой - на это и жаловалась клиент;
       300  край пуфа потерян совсем, подушка уходит влево и растворяется,
            плюс поле, собранное из столбцов у нового края, тащило
            в себя светлые пиксели пуфа и растягивало их по всей ширине;
       60   между левой границей кадра и пуфом остаётся 50 столбцов
            чистой тёмной стены, и пуф читается круглым предметом
            с ясным краем.

     Замер по исходнику: левый край пуфа начинает проступать со столбца
     около 110, полностью светлым пуф становится со столбца 165, левее 110
     чистая тёмная стена и пол. Допустимый коридор среза 55-65 столбцов:
     меньше 55 поле становится слишком узким, больше 70 край пуфа снова
     начинает подрезаться.

     ВОСЬМОЙ КРУГ, ДОБАВЛЕН СРЕЗ СПРАВА. Кадр показывается со столбца 60
     по столбец 1190, то есть видимая часть исходника 1130 столбцов.

     Зачем. Кошка занимает столбцы 305-1038, справа от неё 242 столбца
     пустой стены с тенью: в кадре они не работают, а место в макете
     занимают. Срез справа отдаёт это место текстовой колонке, и делает
     это бесплатно по размеру кошки: её размер задаёт высота ряда, а не
     ширина кадра. На 1101 колонка выросла с 265 до 321px, кегль названия
     с 35 до 46px, при той же самой кошке 410px.

     Почему ровно 1190, а не 1208 из задания: на 1208 доля названия
     на 1440 выходит 29.2% при требовании не ниже 30%. На 1190 - 30.2%.
     Правее двигать нельзя по названию, левее - по воздуху справа
     от кошки: на 1190 его остаётся 152 столбца исходника, это 94px
     на экране при 1101 и 152px при 1920.

     ВЫСОТА не менялась, 48vw. Кошка та же, что была принята:
     410px на 1101, 536px на 1440, 662px от 1778 и выше. */
  :root {
    --hero-h: min(48vw, 853px);
    --hero-photo-w: calc(var(--hero-h) * 1130 / 853);
    --hero-gap: 48px;    /* зазор между текстом и краем фотографии */
    --hero-pad-l: 44px;
  }

  .hero__row {
    display: block;
    position: relative;
    height: var(--hero-h);
    /* ЛЕВОЕ ПОЛЕ ИЗ ДВУХ СЛОЁВ.

       НИЖНИЙ СЛОЙ, hero-edge-left.png - столбцы 40-59 исходника, то есть
       ровно та полоса стены, которая уходит за левую границу кадра при
       срезе 60. Пуфа в этой зоне нет ни одного пикселя: он начинает
       проступать только со столбца 110. Это принципиально - шестой круг
       собирал поле из столбцов 292-299, туда попадали светлые пиксели
       пуфа, и растянутые по всей ширине поля они давали то самое
       растекание, из-за которого круг и отменён.

       Полоса собрана не копией двадцати столбцов подряд, а растяжкой
       между двумя усреднёнными профилями (столбцы 36-43 и 56-63) плюс
       сглаживание по трём строкам: усреднение снимает шум JPEG, а стена
       на этом участке светлеет линейно, 65.4 -> 67.8 по красному, так что
       линейная растяжка её ход света повторяет точно. Правый край полосы
       приходится ровно на столбец 60, то есть встык к первому видимому
       столбцу кадра: перепад на стыке 0.26 единицы из 255 при естественном
       градиенте стены на тех же 20 столбцах 2.59.

       Поле тёмное само по себе, без всякой помощи: самый светлый его
       пиксель даёт --gold-light 6.24:1, --gold 5.60:1.

       ВЕРХНИЙ СЛОЙ - горизонтальный градиент от --header-bg, полностью
       непрозрачного слева, к полной прозрачности ровно на стыке. При
       нынешнем срезе он работает уже не на контраст (поле и так тёмное),
       а на стык с шапкой: левый край поля получается точно её цветом,
       границы между шапкой и полем нет вовсе. Цвет в rgba() продублирован
       числом, потому что var() внутри rgba() не работает: при правке
       --header-bg править и здесь. */
    background-image:
      /* ТРЕТИЙ СЛОЙ, ВОСЬМОЙ КРУГ: притемнение низа поля.
         Средний слой заливает поле цветом шапки (75,57,40), а стена
         на нижних строках кадра втрое темнее (33-40 по серому). Из-за
         этого нижний левый угол поля выходил на 20 единиц светлее, чем
         поле у самого стыка, и читался мягкой виньеткой.

         Эллипс с центром в левом нижнем углу поля, радиусы 100% ширины
         и 55% высоты. Остановки повторяют профиль среднего слоя, поэтому
         вдоль нижней строки оба слоя гаснут согласованно и горба
         посередине не появляется. На стыке (100% ширины) параметр
         эллипса равен единице при любой высоте, значит слой там ровно
         прозрачен и на перепад не влияет. Цвет - --text #2B211A,
         это самый тёмный тон палитры, он же почти точно совпадает
         со стеной на нижних строках. */
      radial-gradient(100% 55% at 0% 100%,
        rgba(43, 33, 26, 0.90)   0%,
        rgba(43, 33, 26, 0.90)  30%,
        rgba(43, 33, 26, 0.86)  46%,
        rgba(43, 33, 26, 0.74)  62%,
        rgba(43, 33, 26, 0.50)  78%,
        rgba(43, 33, 26, 0.22)  91%,
        rgba(43, 33, 26, 0)    100%),
      linear-gradient(to right,
        var(--header-bg)          0%,
        var(--header-bg)         30%,
        rgba(75, 57, 40, 0.94)   46%,
        rgba(75, 57, 40, 0.80)   62%,
        rgba(75, 57, 40, 0.56)   78%,
        rgba(75, 57, 40, 0.28)   91%,
        rgba(75, 57, 40, 0)     100%),
      url('../img/hero-edge-left.png');
    /* Все три слоя растягиваются РОВНО на ширину поля, а не на всю ширину
       ряда: иначе правая часть уходит под фотографию и на стык приходится
       не тот столбец. Правый край поля совпадает с левым краем кадра
       пиксель в пиксель. */
    background-size:
      calc(100% - var(--hero-photo-w)) 100%,
      calc(100% - var(--hero-photo-w)) 100%,
      calc(100% - var(--hero-photo-w)) 100%;
    background-position: left top, left top, left top;
    background-repeat: no-repeat, no-repeat, no-repeat;
  }

  /* Текстовая колонка.
     Ширина считается от ширины РЯДА, а не от 100vw: 100vw включает полосу
     прокрутки, и зазор до фотографии просел бы на её толщину. В такой
     записи зазор равен --hero-gap точно, на любой ширине и при любой
     полосе прокрутки.

     ПО ВЫСОТЕ: одна плотная группа с фиксированными интервалами.
     Свободный запас между элементами НЕ распределяется.

     Пятый круг сначала стоял на justify-content: space-between. Пустой
     угол сверху это убирало, но весь запас уезжал в промежутки внутри
     текста: на 1440 между фразой и абзацем получалось 136px, на 1920 -
     236px, и это читалось не как воздух, а как разъехавшаяся вёрстка.
     Заменено на центрирование группы целиком.

     Интервалы: 32px между заголовочной группой и абзацем, 40px между
     абзацем и кнопками. Внутренние интервалы заголовочной группы -
     14px и 22-34px, они заданы у самих элементов. Ни один вертикальный
     промежуток внутри блока не превышает 40px.

     Группа стоит по центру колонки, смещённая ВВЕРХ на 5% высоты ряда:
     иначе оптически проседает вниз. Смещение сделано нижним отступом
     у последнего элемента: при justify-content: center запас делится
     поровну сверху и снизу, поэтому margin-bottom в 10% высоты ряда
     поднимает всю группу ровно на 5%. */
  .hero__copy {
    position: relative;
    z-index: 2;
    width: calc(100% - var(--hero-photo-w) - var(--hero-gap));
    /* Прежний потолок 620px снят шестым кругом: название теперь набирается
       по ширине колонки, и на 1706+ этот потолок ломал строку надвое. */
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 40px 0 40px var(--hero-pad-l);
  }

  /* Фотография. Ширина задана явно той же формулой, что и в ширине
     колонки, поэтому сумма «колонка + зазор + фотография» равна ширине
     ряда тождественно, а не с точностью до округления.

     object-fit: cover при этих пропорциях коробки режет только
     по горизонтали: коробка уже исходника (1.3247 против 1.5006),
     значит масштаб задаёт высота, по вертикали кадр входит целиком -
     уши сверху и лапы снизу на месте.

     СРЕЗ ТЕПЕРЬ С ДВУХ СТОРОН, и его делит object-position. Всего
     за кадром остаётся 1280 - 1130 = 150 столбцов исходника, из них
     60 слева и 90 справа, значит доля левого среза 60/150 = 40%.
     Отсюда object-position: 40%. Само число долей, а не пикселей,
     поэтому пропорция срезов держится одинаково на любой ширине окна.
     Правый край блока при этом по-прежнему прижат к правому краю окна:
     режется содержимое кадра, а не его положение. */
  .hero__media {
    position: absolute;
    top: 0;
    right: 0;    /* вплотную к правому краю окна, без отступа и контейнера */
    z-index: 1;
    height: 100%;
    width: var(--hero-photo-w);
    /* Апскейла выше родного разрешения нет. Число равно видимой части
       исходника после обоих срезов: 1190 - 60. Менять вместе со срезом,
       иначе на широких экранах кадр подрежется сильнее, чем задумано,
       и край пуфа уедет за границу. */
    max-width: 1130px;
    aspect-ratio: auto;
    overflow: hidden;
  }
  .hero__media img { object-position: 40% 50%; }

  /* Кегли подобраны по замеру натуральной ширины строк против доступной
     ширины колонки на 1101, 1200, 1340, 1440, 1600, 1706, 1920 и 2560.
     Формула вида «vw минус константа» вместо чистого vw: колонка растёт
     не пропорционально ширине окна, а быстрее (доля фотографии постоянна,
     а зазор и левое поле - нет), поэтому чистый clamp по vw либо не влезал
     на 1101, либо не дорастал на 1920. */
  /* ── Кегли заголовочной группы ───────────────────────────────────────────
     Название набрано по всей ширине колонки, а не по фиксированной шкале.
     Замер: «VIOLA ALBA» в Jost 300 с разрядкой 0.18em занимает ровно
     7.079 кегля. Значит наибольший кегль, при котором строка не переносится
     и не заезжает на фотографию, равен 0.96 × ширина колонки / 7.079.

     ВОСЬМОЙ КРУГ. Срез справа отдал колонке 72px на 1101, и кегль вырос
     обратно почти до уровня шестого круга:

       окно   кегль   ширина строки   доля окна   (седьмой / шестой круг)
       1101    45.6        323           29.3%      35.0 / 50.0
       1280    54.8        388           30.3%      41.3 / 60.5
       1440    61.4        435           30.2%      46.9 / 70.0
       1920    86.2        610           31.8%      63.7 / 98.3

     Формул две, потому что на 1341 меняется --hero-pad-l (32 -> 44px)
     и колонка скачком теряет 12px. Одной прямой обе полосы не описать:
     она либо не дотягивает на 1101, либо ломает строку на 1341.
     Вторая формула стоит в блоке 1101-1340 ниже.

     ПРОПОРЦИИ ВНУТРИ ГРУППЫ прежние: подпись 0.29 кегля названия,
     фраза 0.22. На 1101 подпись упирается в нижнюю границу clamp (13px),
     поэтому там она чуть крупнее относительно названия, чем на широких
     экранах.

     ДЕВЯТЫЙ КРУГ, правка по замечанию клиента. Две формулы на vw заменены
     одной на ширину колонки. Причина: колонка растёт не пропорционально
     окну, и именно поэтому формул было две, а на 1341 кегль прыгал.
     В долях колонки коэффициент один и тот же на всей полосе:

       окно   кегль   колонка под текст   кегль / колонка
       1101   45.34         320.9              14.127%
       1200   50.43         356.9              14.127%
       1280   54.54         386.1              14.126%
       1340   57.63         407.9              14.127%
       1341   55.98         396.3              14.126%
       1440   61.07         432.3              14.126%
       1600   69.30         490.6              14.126%

     Отсюда 14.127cqw. Кегли на всех ширинах остаются прежние до сотых,
     ступенька на 1341 исчезает сама: перепад левого поля 32 -> 44px
     теперь учитывается тем же выражением, а не второй формулой.
     Отдельный блок 1101-1340 с кеглем названия больше не нужен. */
  .hero__name { --hero-name-fs: 14.127cqw; }
  .hero__tagline {
    margin-top: clamp(14px, calc(1.3vw - 0.7px), 24px);
    font-size: clamp(13px, calc(1.49vw - 3.77px), 32px);
  }
  /* Фраза внутри заголовочной группы, поэтому интервал у неё обычный,
     не растяжимый: это подпись к названию, а не отдельный ярус. */
  .hero__eyebrow {
    margin-top: clamp(22px, 2.2vw, 34px);
    font-size: clamp(11px, calc(1.13vw - 2.86px), 24px);
  }
  .hero__text {
    margin-top: 32px;
    font-size: clamp(16px, calc(0.62vw + 8.4px), 21px);
    /* 60 знаков в строке. Замер по Onest: средний знак этого текста
       0.511em, значит 60 знаков это 30.7em. Ставим 30em с запасом,
       фактическая длина строки проверена скриншотами, таблица в README. */
    max-width: 30em;
  }

  /* margin-bottom - не отступ, а рычаг центрирования: он поднимает всю
     группу на половину своего значения, то есть ровно на 5% высоты ряда.
     См. комментарий у .hero__copy. */
  .hero__actions {
    margin-top: 40px;
    margin-bottom: calc(var(--hero-h) * 0.10);
    gap: 14px;
  }

  /* Фон под кнопкой контурной - то же тёмное поле, обводка и текст золотые.
     Раньше здесь стояла полупрозрачная тёмная подложка: она была нужна,
     чтобы кнопка не терялась на неровном по яркости участке фотографии.
     Поле теперь ровное и стабильно тёмное по всей высоте (0.014-0.038,
     замер в README), подложка ничего больше не прибавляет. */
  /* Девятый круг: обводка терракотовая, по просьбе клиента - тем же цветом,
     что заливка первой кнопки. Текст остаётся --gold-light: терракота
     на тёмном поле даёт 4.03 (порог для обводки 3), а светлое золото
     для текста 6.47 (порог 4.5). Наведение - заливка терракотой
     с тёмным текстом, 4.71. */
  /* Правило ограничено первым экраном (.hero) 13.08. До этого оно стояло
     без префикса и красило светлым золотом ВСЕ контурные кнопки страницы
     от 1101px. Пока ниже первого экрана ничего не было, это не проявлялось;
     с появлением кнопок «Ориентальные котята», «Все статьи» и «Вся галерея»
     они получили светлое золото на светлом фоне. Первый экран правкой
     не затронут: его контурная кнопка лежит внутри .hero. */
  .hero .btn--outline {
    background: transparent;
    border-color: var(--terracotta);
    color: var(--gold-light);
  }
  .hero .btn--outline:hover {
    background: var(--terracotta);
    border-color: var(--terracotta);
    color: #2B211A;
  }

  /* Поле тёмное по всей высоте, поэтому берём светлую часть гаммы.
     Замер по реальному левому краю кадра (assets/img/hero-edge-left.png,
     он и есть фон этой колонки): отн. яркость 0.014-0.038 на всех 853
     строках, контраст --gold-light/--gold/--cream к нему 7.0-9.7:1 везде,
     подбирать положение текста по высоте не потребовалось. */
  .hero__copy {
    --hero-fg-1: var(--gold-light);
    --hero-fg-2: var(--gold-light);
    --hero-fg-3: var(--gold);
    --hero-fg-4: var(--cream);
    --hero-dot:  var(--gold-light);
  }
}

/* ==========================================================================
   ДЕКОРАТИВНЫЙ НАБОР
   Собран по картинке клиента с блоком «О НАС». Переиспользуемый: пойдёт
   на все страницы сайта, а не только на первый экран.

   Круглый значок с кошкой, который есть на её картинке сверху, в шапку
   не возвращаем: клиент просила его убрать, решение не менялось.
   Из картинки взяты разделитель, иконки, рамка и шкала размеров.
   ========================================================================== */

/* ── 1. Заголовок раздела и типографическая шкала ────────────────────────── */

.h-section {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--name-weight);
  line-height: 1.1;
  letter-spacing: var(--tr-h2);
  color: var(--gold-deep);
  margin: 0 calc(var(--tr-h2) * -1) 0 0;
}

.h-sub {
  font-size: var(--fs-sub);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: var(--tr-sub);
  color: var(--gold-deep);
  margin: 0;
}

.t-body {
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.72;
  color: var(--text);
  margin: 0;
}

.t-caption {
  font-size: var(--fs-caption);
  font-weight: 300;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--muted);
  margin: 0;
}

/* ── 2. Разделитель с лапкой ──────────────────────────────────────────────
   Линия слева, зазор, лапка, зазор, линия справа. Линии это два растущих
   отрезка по бокам, поэтому разрыв всегда ровно по размеру значка и не
   зависит от ширины блока. Толщина линии 1px.

   Ширина 340px, на телефоне 200px: «полосочку под о питомнике растянуть».
   Было 180 и 120. Значок при этом остался прежним, 20px: он стоит
   отдельной коробкой с fixed-размером, а тянутся только отрезки по бокам,
   поэтому вместе с линией он не вырос ни на пиксель.

   Зазор между линией и лапкой 16px, в середине запрошенных 14-18. */

.divider {
  display: flex;
  align-items: center;
  gap: 16px;
  /* Ширина не фиксированная: разделитель тянется на всю ширину колонки,
     в которой стоит. На MacBook 15 при фиксированных 340px линия
     не дотягивала до конца заголовка. Отрезки flex: 1 1 auto,
     значок 20px с fixed-размером, поэтому лапка не растёт вместе с линией. */
  width: 100%;
  margin: 18px 0 0;
  color: var(--deco);
}
.divider::before,
.divider::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: currentColor;
  opacity: 0.72;
}
/* Лапка - сплошная заливка, не контур: fill наследует currentColor,
   обводки нет вовсе, см. assets/img/icons.svg#icon-paw-print. */
.divider__icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.divider--center { margin-left: auto; margin-right: auto; }

/* ── 3. Контурные иконки в кружках ───────────────────────────────────────── */

.icon-circle {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--deco);
  border-radius: 50%;
  color: var(--deco);
}
.icon {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}
.icon-circle--sm { width: 42px; height: 42px; }
.icon-circle--sm .icon { width: 20px; height: 20px; }

/* ── 4. Рамка для выделенной мысли ───────────────────────────────────────── */

.note {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 20px 24px;
  border: 1px solid var(--deco);
  border-radius: 4px;
  background: none;
}
.note__text {
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--text);
  margin: 0;
}

/* ── 5. Пункты с иконками ────────────────────────────────────────────────── */

.features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 26px;
}
.feature {
  display: flex;
  align-items: flex-start;
  gap: 18px;
}
.feature__body { flex: 1 1 auto; }
.feature__text {
  margin: 7px 0 0;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--text);
}

/* ==========================================================================
   О ПИТОМНИКЕ
   Слева год основания, справа заголовок, разделитель, абзацы, пункты
   с иконками и рамка с выделенной мыслью.
   ========================================================================== */

/* ФОН ПЕСОЧНЫЙ --sand-bg, правка 16.08.2026. Клиент дословно: «О питомнике
   и карточки статей в разделе полезное о бенгалах, и блок с движущимися фото
   поменять на песочный цвет как у котят на карточке».

   ЗДЕСЬ СТОЯЛО ОБРАТНОЕ: «фон остаётся --bg, затемнять нельзя, порог упадёт».
   Прежний вывод был верен для своих условий и неверен как общее правило.
   Условие было такое: затемнить фон, НЕ ТРОГАЯ цвета текста. При нём любой
   фон темнее #EDE1CF валит --gold-deep, и это по-прежнему так - предел
   пересчитан, он #ECE2D3. Но клиент попросила именно песочный, а на песке
   уже полтора круга живёт карточка котёнка со своей парой цветов. Значит
   выход был не в фоне, а в том, чтобы взять на этот фон ту же пару.

   ЗАМЕР ПО РЕАЛЬНЫМ ПИКСЕЛЯМ на --sand-bg #D8C3A5, что стало с текстом:

     абзацы            --text        #2B211A   9.19   порог 4.5   берёт
     подпись «год…»    --sand-label  #5A4A3A   4.96   порог 4.5   берёт
     «Читать дальше»   --sand-name   #6B4C24   4.57   порог 4.5   берёт
     «О ПИТОМНИКЕ»     --gold-deep   #845E2C   3.39   порог 3.0   берёт (35px)
     число «2010»      --gold-deep   #845E2C   3.39   порог 3.0   берёт (77px)
     декор             --brown       #7A5432   3.91   порог 3.0   берёт

   Что было бы БЕЗ замены цветов, на тех же штатных:
     подпись --muted 3.86, кнопка --gold-deep 3.39, декор --accent 2.20 -
     три провала. Поэтому ниже переопределяются --deco и два цвета текста.

   Крупные заголовки оставлены на --gold-deep сознательно: 35px и 77px
   подпадают под послабление для крупного текста, порог им 3.0. Запас
   0.39 - назван прямо, не спрятан.

   Отступ 100px не тронут. */
.about {
  background: var(--sand-bg);
  padding: 100px 0;

  /* Декор секции: линия разделителя, лапка, кружок значка и рамка врезки.
     Все четыре идут от одной переменной --deco, поэтому хватает одной
     строки. --accent #A67B4E на песке даёт 2.20 при пороге 3.0 и не берёт;
     --brown #7A5432 даёт 3.91. Новый цвет не заводится, --brown уже
     в палитре. */
  --deco: var(--brown);
}
/* Подпись под числом и кнопка «Читать дальше» - на песочную пару.
   Разбор чисел в комментарии выше и у самой тройки в :root. */
.about .about__label { color: var(--sand-label); }
.about .about__more  { color: var(--sand-name); }

/* ЛЕВАЯ КОЛОНКА РАСШИРЕНА С 0.8fr ДО 1.1fr, правка 16.08.2026, вариант C.
   Замечание: «кадр читается чужим в этом месте: мельче колонки по ощущению,
   низ не сходится ни с чем, вокруг пусто».

   Кадр и до правки занимал ВСЮ ширину колонки - зазор по бокам был 0.00px
   на всех ширинах. Значит «шире» достигается только шириной самой колонки,
   а не размером кадра внутри неё. На 1101 это 329.7 -> 402.9, то есть +22%.
   Текстовая колонка соответственно 659.3 -> 586.1, ужатие принято осознанно.

   Вторая половина правки - растяжение кадра до низа текста, у .about__photo
   ниже. Порознь они дают половину результата, разбор трёх вариантов
   и снимки - в отчёте круга и в 05-скриншоты/2026-08-16-variant-p4-*. */
.about__grid {
  display: grid;
  grid-template-columns: minmax(200px, 1.1fr) 1.6fr;
  gap: 56px;
  align-items: start;
}

/* ── Выравнивание колонок по строкам, правка 16.08.2026 ───────────────────
   Клиент: «две тыщи 10-й вот где фотка она вниз спустилась, а питомники
   наверху вверх вылезла, и там вообще как бы криво всё стоит. Выровнять,
   чтоб всё было на уровне текста, они вот провалено как-то».

   ЧТО БЫЛО. Колонки выравнивались только по верхнему краю, а внутри левой
   фотография отступала от подписи на фиксированные 30px. Замер по верхам
   от начала сетки, окно 1101:

       2010            0.0     заголовок «О ПИТОМНИКЕ»   0.0
       подпись        91.0     первый абзац            102.7
       ФОТОГРАФИЯ    146.5     второй абзац            232.8

   То есть фотография вставала на 43.8px ниже первого абзаца и не совпадала
   ни с одной линией справа. Низ левой колонки при этом уходил на 16.7px
   ниже правой - это и есть «провалено».

   ЧТО СТАЛО. Обе колонки распускаются в саму сетку через display: contents,
   и сетка получает две строки: «2010 с подписью» рядом с заголовком,
   фотография рядом с текстом. Верх фотографии теперь равен верху первого
   абзаца ПО ПОСТРОЕНИЮ - это одна строка сетки, а не подобранный отступ.
   Ни одного нового числа в пикселях: row-gap 30px - это те же 30px,
   которыми фотография отступала раньше (см. .about__photo ниже).

   Ветка только для широких окон. На узких (max-width: 760px) действует
   своя раскладка в одну колонку, она сложилась раньше и здесь не трогается.
   ======================================================================== */
@media (min-width: 761px) {
  .about__year,
  .about__body { display: contents; }

  .about__grid {
    grid-template-areas:
      "year head"
      "photo copy";
    row-gap: 30px;
  }
  .about__year-head { grid-area: year; }
  .about__head      { grid-area: head; }
  .about__photo     { grid-area: photo; }
  .about__copy      { grid-area: copy; }

  /* НИЗ КАДРА САДИТСЯ НА НИЗ ТЕКСТА, правка 16.08.2026, вариант C.
     Вторая половина правки, первая - ширина колонки у .about__grid выше.

     Было: кадр держал пропорцию 4:5, и его низ вставал на 27.2px ВЫШЕ низа
     текстовой колонки. Ни с чем не совпадал - это и есть «низ не сходится
     ни с чем, вокруг пусто».

     Стало: строка сетки растягивается, кадр берёт всю её высоту, низ
     совпадает с низом врезки «А дальше - сердце и душа» ровно, 0.0px.
     Верх при этом остаётся на верхе первого абзаца - он держится
     строкой сетки, а не отступом, и правкой не тронут.

     ПРОПОРЦИЯ 4:5 ЗДЕСЬ БОЛЬШЕ НЕ ДЕЙСТВУЕТ, и это осознанное отступление
     от прежнего согласования. На 1101 бокс выходит 403x439, то есть 0.917
     вместо 0.800. object-fit: cover срезает 12.9% ПО НИЗУ - у кадра
     с двумя котятами это лапы. Головы лежат в верхней трети и под нож
     не попадают ни на одной проверенной ширине; object-position: center top
     у .about__photo это и гарантирует. Заказчик принял срез явно.

     На узких окнах (max-width: 760px) правило не действует: там колонка
     одна, кадр уходит под текст и растягиваться ему не к чему. Там
     по-прежнему честные 4:5 из базового правила .about__photo.

     САМО РАСТЯЖЕНИЕ ЛЕЖИТ НЕ ЗДЕСЬ, А НИЖЕ, в отдельном блоке
     @media (min-width: 1064px) под правилом .about__photo. Там же разбор,
     откуда взят порог 1064 - это не круглое число, а ширина, на которой
     .about__copy перестаёт переноситься лишней строкой при нынешнем тексте. */
}
/* Сброс собственных отступов у обоих узлов второй строки вынесен НИЖЕ,
   к самим правилам .about__photo и .about__copy: обе их margin-top
   объявлены дальше по файлу, и отсюда, при равной специфичности, сброс
   до них не дотягивался. Замер, который это поймал: фотография стояла
   на 4px ниже текста - ровно разница между её 30px и 26px у обёртки. */

/* font-weight задан явно, а не унаследован от body. У Jost в проекте
   лежит единственное начертание 300, и при наследованных 400 браузер
   всё равно рисовал бы им же - но молча, по правилу подбора ближайшего
   веса. Явное значение убирает эту зависимость от подбора: под запасной
   антиквой, где начертаний много, число получает тот же вес,
   что и заголовки разделов. */
.about__number {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(58px, 7vw, 104px);
  font-weight: var(--name-weight);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--gold-deep);
}

/* Кегль поднят с 13 на 17px, правка 14.08.2026. Клиент: «подпись мелкая
   рядом с числом». Ориентир в замечании 16-18px, взята середина.

   Почему именно 17, а не 18. Число на 1101 идёт 77px, подпись читается
   как его вторая строка, а не как самостоятельный текст, поэтому у неё
   должен остаться заметный отрыв по размеру. При 17px отношение к числу
   4.5, при 18px - 4.3, при прежних 13px было 5.9. Плюс граница строки:
   «год основания питомника» при 17px занимает 187px в колонке 330px
   на 1101 и встаёт одной строкой на всех ширинах от 320 до 2560.

   Разрядка 0.02em не тронута: это общая разрядка подписей в проекте,
   она же у .t-caption и у строки под отзывом.

   Цвет тоже прежний, --muted #6B5A48. На фоне --bg #EFE4D3 он даёт 5.26
   при пороге 4.5, запас есть, притемнять не за чем. Кегль на порог
   не влияет: 17px при весе 300 - обычный текст, порог для крупного
   начинается с 18.66px, то есть мы к нему даже не подходим.

   --fs-caption не трогаем: он стоит ещё в четырёх местах страницы,
   и там кегль менять никто не просил. */
.about__label {
  margin: 14px 0 0;
  font-size: 17px;
  font-weight: 300;
  letter-spacing: 0.02em;
  color: var(--muted);
  max-width: 18em;
}

.about__text {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.72;
  color: var(--text);
  max-width: 46em;
}
/* Заголовок и разделитель под ним - одна группа шириной ровно по надписи.
   fit-content: ширина берётся от самой длинной строки внутри, то есть
   от самого заголовка, а не от колонки. Разделитель внутри стоит на 100%,
   поэтому линия получается ровно такой длины, как надпись, а лапка -
   по центру этой линии. */
.about__head { width: fit-content; max-width: 100%; }
/* Было `.about__head + .about__text`. После обёртки .about__copy соседство
   заголовка и первого абзаца разорвано, и правило перестало срабатывать
   молча - отступ считается от обёртки. На широких окнах его снимает
   строка сетки, разбор выше. */
.about__copy { margin-top: 26px; }
.about__text + .about__text { margin-top: 20px; }

.about__features { margin-top: 34px; }
.about__note { margin-top: 30px; }

/* ── Фотография под числом ────────────────────────────────────────────────
   Правка 14.08.2026. Два коротких факта (Б4, вариант 3) убраны целиком,
   вместе с ключами about.fact1 и about.fact2. Клиент: «мелкие, стоят
   не к месту». На их месте вертикальный кадр взрослой кошки питомника -
   это ровно вариант 2 того же Б4, который ей показывали.

   Пропорция 4:5 задана в CSS, а не только размерами файла: кадр правится
   через админку по ключу about.yearPhoto, и клиент поставит туда что
   угодно - хоть квадрат, хоть горизонталь. object-fit срежет лишнее,
   и колонка не поедет.

   object-position: center top - тем же приёмом, что у карточек котят,
   и по той же причине: если срезать придётся, отрезать надо низ.
   Сверху уши, и любой сдвиг вниз отъедает именно их.

   Скругление 10px - то же, что у .card, клиент просила «как у карточек
   котят». Оно на самом picture, а не на img: у img своя коробка,
   и без overflow на родителе углы фотографии вылезали бы поверх.

   Отступ 30px сверху - тот же, что был у списка фактов, ритм колонки
   не менялся.

   Центрирование по горизонтали, правка 15.08.2026. Клиент: «фото стоит
   не по центру». По замеру фотография и до правки стояла ровно по колонке:
   на всех 27 ширинах от 320 до 2560 зазор слева и справа выходил 0.00px,
   потому что коробка идёт width: 100% и других правил ширины у неё нет.
   Съехавшим читался не блок, а КАДР ВНУТРИ него: в прежнем снимке кошка
   сидела в левой части, центр её массы стоял на 48px левее середины кадра
   (9 процентов ширины), справа оставалась пустая стена. Это исправлено
   заменой кадра, разбор в README.

   `margin-inline: auto` добавлен здесь не как исправление, а как замок:
   сегодня он ничего не двигает (при width: 100% двигать нечего), но если
   у коробки когда-нибудь появится max-width - ради честного 2x под узкий
   исходник, например, - фотография останется по центру колонки, а не
   прижмётся к её левому краю вслед за числом и подписью. Число и подпись
   центрировать нельзя: они стоят по левому краю колонки и это их место.

   Важно: «по центру колонки» и «по центру» для клиента - два разных места.
   0.00px здесь - это зазор ВНУТРИ .about__year, а не от края окна.
   Второй заход по этой же жалобе и другая зона центрирования - ниже,
   в правиле `@media (min-width: 1101px)`. */
.about__photo {
  display: block;
  position: relative;
  margin: 30px auto 0;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface);
}
.about__photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* Вторая половина правки выравнивания, начало - у .about__grid выше.
   Собственные верхние отступы обоих узлов второй строки снимаются: разрыв
   между строками держит row-gap сетки, а не они. Стоит здесь, а не рядом
   с сеткой, потому что оба правила выше по файлу и при равной
   специфичности выигрывает последнее. */
@media (min-width: 761px) {
  .about__photo,
  .about__copy { margin-top: 0; }
}

/* ── Вторая половина варианта C: кадр берёт всю высоту строки сетки ───────
   Стоит ЗДЕСЬ, ниже правила .about__photo, а не в блоке выравнивания выше:
   .about__photo объявлен между ними, специфичность равная, и сверху правило
   до него не дотягивалось. Поймано замером - пропорция оставалась 0.800
   вместо 0.917, то есть выходил отклонённый вариант B.

   ПОРОГ РАСТЯЖЕНИЯ - НЕ 761 И НЕ КРУГЛОЕ ЧИСЛО. Растяжение делает пропорцию
   кадра зависимой от того, какой высоты вышел текст рядом. На широких окнах
   текст короткий и кадр выходит почти квадратным - это нормально. На узких
   текстовая колонка становится высокой, и кадр вытягивается в полосу,
   а object-fit: cover срезает его по бокам. Замер по всей шкале, первая
   версия правки (порог 1101):

       окно   бокс      пропорция   срез низа   срез боков
        761   277x600     0.462          0%        42.2%   <- брак
        800   293x600     0.488          0%        38.9%   <- брак
        900   334x520     0.643          0%        19.6%   <- брак
       1024   385x520     0.740          0%         7.5%
       1100   416x519     0.800          0%           0%   свис 80.2px  <- брак другого рода
       1101   403x439     0.917       12.8%           0%   свис    0px
       1280   476x451     1.055       24.2%           0%
       1440   476x477     0.998       19.9%           0%

   На 768 правого котёнка резало по телу - проверено на снимке, не на глаз.
   Порог 1101 закрывал боковой срез, но открывал ДРУГОЙ брак ровно на границе
   снизу: при фиксированных 4:5 кадр растёт вместе с колонкой быстрее, чем
   текст рядом с ним, и на самой границе, на 1100px, свисает на 80.2px ниже
   врезки - это РАБОЧАЯ ШИРИНА ОКНА ЗАКАЗЧИКА. Жалобу «низ не сходится»
   это воспроизводило заново на её экране.

   ПОРОГ 1064 - ЭТО ГРАНИЦА, ГДЕ ТЕКСТ ПЕРЕСТАЁТ ПЕРЕНОСИТЬСЯ ЛИШНЕЙ СТРОКОЙ,
   а не подобранное число. При нынешнем тексте about.text1-4 высота
   .about__copy идёт по слому переносов: 492px (окна 1041-1052), 465px
   (1053-1063), 439px (1064 и до 1280, где .wrap упирается в max-width
   и колонки перестают расти). С 1064 высота больше не меняется - ровно
   в этой точке растяжение кадра под высоту текста перестаёт гнаться
   за движущейся целью и начинает совпадать с ней с первого пикселя.
   Если текст .about__text1-4 отредактируют через админку настолько, что
   разметка переносов сместится, число надо снять заново тем же способом:
   искать в консоли высоту .about__copy по 1px окна, а не пересчитывать
   на глаз - при равной специфичности и характере правил здесь легко
   промахнуться, как это уже было с порядком правил выше в этом файле.

   Замер после переноса порога на 1064:

       окно   бокс      пропорция   срез низа   срез боков   свис
       1024   385x481     0.800          0%           0%    -39.1   (до порога, без изменений)
       1044   393x491     0.800          0%           0%     -1.4   (до порога, без изменений)
       1064   401x439     0.913       12.4%           0%        0
       1080   407x439     0.928       13.8%           0%        0
       1100   416x439     0.946       15.5%           0%        0   <- было 80.2, стало 0
       1101   403x439     0.917       12.8%           0%        0   (не изменилось)

   Боковой срез не появляется нигде в диапазоне 1064-1200: аспект кадра
   на этом отрезке 0.913-0.946, близко к исходным 0.8, и cover срезает
   только по низу. Ниже 1064 растяжения по-прежнему нет, там работают
   прежние 4:5: срез нулевой, низ кадра с текстом не сходится - ровно так,
   как было до этой правки и на этих ширинах вопросов не вызывало.

   СРЕЗ ПО НИЗУ НА ШИРОКИХ ОКНАХ ВЫШЕ СОГЛАСОВАННОГО. Заказчик принимал
   12.9% по замеру на 1101; на 1280 выходит 24.2%, на 1440 и шире - 19.9%.
   Срезаются лапы и нижняя часть подстилки, головы обеих кошек лежат
   в верхней трети и не задеты ни на одной ширине. Число названо
   в отчёте круга отдельной строкой. */
@media (min-width: 1064px) {
  .about__grid  { align-items: stretch; }
  .about__photo { aspect-ratio: auto; height: 100%; }
}

/* ── Центрирование колонки «2010» ПО ЗОНЕ ОКНА: СНЯТО 16.08.2026 ─────────────
   ЗДЕСЬ БОЛЬШЕ НЕТ НИ ОДНОГО ПРАВИЛА. Ниже - разбор, почему приём снят
   и почему три круга правок по нему шли вслепую. Текст оставлен целиком:
   без него следующий, кто увидит жалобу «фото не по центру», начнёт
   четвёртый заход с той же точки.

   ЧТО БЫЛО СЛОМАНО. В комментарии третьего захода стоял лишний закрывающий
   маркер - звёздочка со слэшем - в конце строки «а не обнуляется, как было
   у прежнего ограничителя». Записать его здесь буквально нельзя: он закроет
   и этот комментарий тоже, на чём я и попался, когда писал этот разбор.
   Маркер закрывал комментарий раньше времени, следующие семь строк
   оставались голым текстом
   в CSS, и парсер собирал из них селектор, а вместе с ним съедал целиком
   идущий следом @media-блок. Проверка счётом: в файле 431 верхнеуровневое
   правило, в CSSOM их 430, и недостающее - ровно этот блок. Других обрывов
   в файле нет, весь styles.css прогнан разбором.

   ЧЕМ ЭТО ОБЕРНУЛОСЬ. Правило transform на .about__year-head и .about__photo
   не доезжало до браузера НИ РАЗУ. getComputedStyle давал `none` на 1101
   и на 1440. То есть третий заход существовал только в тексте файла, а мы
   три круга правили формулу и сверяли её с числами, которые к экрану
   отношения не имели. Второй заход (коммит 95fecac) до браузера доезжал,
   третий - нет.

   ПОЧЕМУ ПРИЁМ СНЯТ, А НЕ ПОЧИНЕН. Правило впрыснули в браузер и замерили
   то, чего никто не видел. Формула точна: отклонение центра кадра от центра
   зоны становится 0.00px на всех ширинах от 1101. Но цена - разрыв между
   кадром и текстом:

       окно   сдвиг     зазор фото-текст
       1101   +14px     56 -> 42
       1280   +14px     56 -> 42
       1440   -26px     56 -> 82
       1710   -93.5px   56 -> 149.5     <- окно, с которого смотрит заказчик
       1920   -146px    56 -> 202
       2560   -306px    56 -> 362

   Кадр отрывается от текста тем сильнее, чем шире окно. А жалоба, ради
   которой собирается правка 4, звучит как «низ не сходится ни с чем, вокруг
   пусто» - то есть приём усиливает ровно ту претензию, которую мы правим.
   Решение заказчика от 16.08.2026: обрыв комментария починить, transform
   снять, а его возврат рассматривать отдельной осью в вариантах правки 4.
   Вернуть - значит вставить сюда блок из истории, он записан ниже дословно:

       @media (min-width: 1101px) {
         .about__year-head,
         .about__photo {
           transform: translateX(calc(14px - max(0px, (100vw - 1280px) / 4)));
         }
       }

   УРОК, вынесен в README отдельным пунктом: замер снимается с CSSOM
   и getComputedStyle, а не с текста файла. Текст файла три круга показывал
   правило, которого в браузере не существовало.

   ── ниже - история приёма, как она была записана третьим заходом ──────────

   Третий заход по одной и той же жалобе «фото не по центру». Второй заход
   (коммит 95fecac) двигал только .about__photo и ограничивал сдвиг снизу
   -28px, чтобы на 1920/2560 фото не отрывалось от числа «2010» больше, чем
   на поле .wrap. Инструментально правка подтвердилась (0.00px на 1101/1440,
   118px на 1920, 278px на 2560), но у клиента окно 1710px - там ограничение
   уже включено и даёт 65.5px, и он видит ровно ту же картину, что и раньше.
   Ограничитель работает на любом окне шире ~1450px, то есть на большей части
   реальных широких мониторов, а не только на 1920+.

   Решение: двигать не фотографию отдельно, а всю колонку .about__year -
   число, подпись и кадр под ними, всё вместе. Тогда группа встаёт точно
   по центру зоны на любой ширине, а число и фото не могут разъехаться
   между собой, потому что двигаются одним трансформом.

   Формула сдвига не меняется - она и раньше была точна как центрирующая
   зону формула, менялся только объект, к которому её применяли, и нижняя
   граница. zoneCenter = bodyLeft / 2, bodyLeft = yearLeft + yearWidth +
   gap(56px), при переносе на .about__year (а не только на фото) сдвиг
   для центра колонки ровно тот же: 14px - max(0px, (100vw - 1280px) / 4).
   yearLeft = wrapLeft + 28, wrapLeft = max(0px, (100vw - 1280px) / 2).

   Отклонение варианта B на четырёх ширинах (было / стало 0):
   1101: расчёт 14, факт 14 (ограничитель не включался) - отклонение 0
   1440: расчёт -26, факт -26 (ограничитель не включался) - отклонение 0
   1920: расчёт -146, факт -28 (упор в ограничитель) - отклонение 118
   2560: расчёт -306, факт -28 (упор в ограничитель) - отклонение 278
   Отклонение и было именно разницей между расчётным и фактическим сдвигом -
   значит сама формула верна, лишний был только max(-28px, ...).

   Два других варианта рассмотрены и отклонены:
   - двигать только фото без ограничителя (буквальный центр, вариант A
     второго захода) - на 2560 фото уходит на 306px левее числа «2010»,
     кадр повисает в пустом поле отдельно от подписи. Разбор и кадры -
     `01-от-клиента/variant-photo-center-A.jpg`, README;
   - растянуть фото до края зоны вместо сдвига - при пропорции 4:5 высота
     на 2560 вышла бы 1391px, колонка переросла бы текстовую половину блока.
     Плюс источник `year-cat.jpg` 936x1170 вертикальный, горизонтального
     кадра нужного качества у клиента нет.

   Побочный эффект решения: число и подпись больше не стоят по левому краю
   колонки на широких экранах - раньше это было намеренным правилом (см.
   комментарий у .about__photo выше), теперь клиент явно попросил обратное,
   двигать группу целиком. Левый край колонки после сдвига равен
   wrapLeft / 2 + 42px на любой ширине - в .wrap не упирается никогда,
   к краю окна не прилипает: слагаемое wrapLeft/2 растёт вместе с окном,
   а не обнуляется, как было у прежнего ограничителя.

   ПРАВКА 16.08.2026, куда переехал трансформ. Колонка .about__year теперь
   display: contents - своего бокса у неё нет, и transform на ней браузер
   просто игнорирует. Формула не тронута ни на символ, она переехала
   на оба узла колонки сразу: .about__year-head и .about__photo. Сдвиг
   у них общий, значит число, подпись и кадр по-прежнему не могут
   разъехаться между собой - ровно то свойство, ради которого решение
   и выбиралось.

   ── конец истории. Сам блок снят, разбор в шапке этого комментария. ──── */

/* ── Третий и четвёртый абзацы под кнопкой ────────────────────────────────
   Механика ровно как у отзывов: класс сворачивания вешает скрипт, кнопка
   лежит в разметке с атрибутом hidden и показывается тем же скриптом.
   Значит без JS видны все четыре абзаца и мёртвой кнопки на странице нет.

   Свёрнутое состояние - display: none, а не line-clamp с затуханием.
   У отзывов режется середина абзаца, и там затухание объясняет обрыв;
   здесь границей служит конец второго абзаца, обрывать нечего. */
.about__rest { margin-top: 20px; }
.about__rest--collapsed { display: none; }
.about__more { margin: 18px 0 0; }

/* ==========================================================================
   Мобильная панель меню
   ========================================================================== */

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: var(--dark);
  padding: 22px 24px 40px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity var(--ease), transform var(--ease), visibility var(--ease);
}

.mobile-menu.is-open {
  visibility: visible;
  opacity: 1;
  transform: none;
}

body.menu-open { overflow: hidden; }

.mobile-menu__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 26px;
}

/* Шрифт не задаём: название в мобильной панели идёт тем же Jost 300,
   что и название в шапке и на первом экране, правило выше по файлу. */
.mobile-menu__name {
  font-size: 20px;
  color: var(--bg);
}

.mobile-menu__close {
  width: 42px; height: 42px;
  background: none;
  border: 1px solid rgba(239, 228, 211, 0.22);
  border-radius: 8px;
  color: var(--bg);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease);
}
.mobile-menu__close:hover { background: var(--accent); border-color: var(--accent); }

.mobile-menu__list {
  list-style: none;
  margin: 0 0 28px;
  padding: 0;
}
.mobile-menu__list li + li { border-top: 1px solid rgba(239, 228, 211, 0.12); }

.mobile-menu__link {
  display: block;
  padding: 15px 2px;
  font-size: 19px;
  color: #EFE4D4;
  border-bottom: 2px solid transparent;
  transition: color var(--ease), border-color var(--ease);
}
.mobile-menu__link:hover { color: #FFF6E8; border-bottom-color: var(--accent); }

/* Текущая страница в мобильной панели. До 760px меню шапки скрыто целиком,
   и панель остаётся единственным местом, где видно, где человек находится.
   Приём тот же, что у бегущей полоски в шапке: терракота под пунктом.
   Полоска здесь не ездит и ездить не должна - пункты стоят столбцом,
   переезжать между строками не за чем, состояние статическое. */
.mobile-menu__link[aria-current="page"] {
  color: var(--gold-light);
  border-bottom-color: var(--terracotta);
}

.mobile-menu__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.mobile-menu__phone {
  font-family: var(--font-display);
  font-size: 24px;
  letter-spacing: 0.04em;
  color: var(--bg);
}

.mobile-menu__circles { display: flex; gap: 12px; }

/* внутри тёмной панели круглые кнопки светлые */
.mobile-menu .circle {
  background: rgba(239, 228, 211, 0.10);
  border-color: rgba(239, 228, 211, 0.22);
  color: var(--bg);
}
.mobile-menu .circle:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #FBF6EE;
}

/* ==========================================================================
   КАРТОЧКА КОТЁНКА И ПОЛОСА ПРЕИМУЩЕСТВ
   Приёмы взяты с макетов клиента: фото сверху, бейдж статуса пилюлей на фото,
   имя со значком пола, строки характеристик с иконками, ниже полоса из
   четырёх пунктов. Из макетов НЕ берём фильтры, кнопки «Подробнее»,
   сердечки избранного, хлебные крошки и цены: цены там выдуманы генератором.
   ========================================================================== */

/* ── Заголовок раздела по центру с линиями по бокам ──────────────────────── */

.sec-head { text-align: center; }
.sec-head__over {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 0 0 14px;
  font-size: var(--fs-caption);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--deco);
}
.sec-head__over::before,
.sec-head__over::after {
  content: '';
  width: 54px;
  height: 1px;
  background: currentColor;
  opacity: 0.7;
}
.sec-head__note {
  margin: 12px auto 0;
  max-width: 62ch;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--muted);
}
.theme-dark .sec-head__note { color: var(--cream); }

/* ── Сетка карточек ─────────────────────────────────────────────────────── */

.cards {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
}

/* ── Карточка ───────────────────────────────────────────────────────────── */

/* Карточка светлее фона в 1.11 раза плюс граница: после затемнения фона
   прежняя поверхность #EDE3D4 сливалась с ним, отличие было в 1.01 раза. */
.card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid rgba(62, 47, 32, 0.14);
  border-radius: 10px;
  overflow: hidden;
  transition: transform var(--ease), box-shadow var(--ease);
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 34px rgba(62, 47, 32, 0.16);
}

/* Пропорция 1:1, а не прежние 4:5 - Б5, вариант 1, «карточки пониже».
   Кадр ПРИЖАТ К ВЕРХУ, и это не мелочь. Исходник снят 4:5, то есть при
   4:5 контейнер совпадал с ним и не резал ничего. При 1:1 отрезается
   100 строк из 500, и любой сдвиг вниз отъедает именно верх, где уши.
   С center top верхняя граница кадра совпадает с исходной: уши и морда
   целы, обрезается низ. */
.card__media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--bg);
}
/* Фотография ВЫВЕДЕНА ИЗ ПОТОКА, и без этого пропорция не работает вовсе.
   Проверено замером: при картинке в потоке height: 100% упирается
   в родителя с высотой auto, процент разрешить не от чего, и высота
   становится auto - то есть коробку растягивает сама картинка своими
   родными 400x500. Пока стояло 4:5, это совпадало с aspect-ratio
   и подмены было не видно; с 1:1 карточка осталась прежних 541px,
   а не стала ниже. absolute + inset: 0 отдаёт высоту aspect-ratio,
   и object-fit наконец получает что резать. */
.card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* бейдж статуса пилюлей в левом верхнем углу фотографии */
/* ── Главный кадр карточки как вход в галерею, 16.08.2026 ────────────────
   Клиент: «при нажатии на фотографию котёнка открывается его галерея».
   Ссылка растягивается на весь кадр карточки. Собственного фона и рамки
   у неё нет: видимая часть - сама фотография, ссылка только собирает
   по ней клик и фокус.

   Класса .photos__item на ней сознательно НЕТ, хотя открывает она тот же
   просмотрщик. Причина в стилях: у .photos__item img стоит
   aspect-ratio: 1/1 и height: auto, и это правило лежит ниже по файлу,
   чем .card__media img - то есть перебило бы раскладку карточки. Скрипт
   находит эти ссылки по data-gallery, класс ему не нужен. */
.card__open {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: inherit;
}
.card__open:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: -3px;
}

/* Плашка «Свободна» лежит поверх ссылки и своим прямоугольником гасила бы
   клик в левом верхнем углу кадра. Интерактивной она не бывает нигде,
   поэтому просто пропускает указатель насквозь. */
.card__open ~ .badge { pointer-events: none; }

/* Полоса кадров бывает спрятана: на главной она нужна скрипту как источник
   набора, а миниатюры там не показываются. Правило нужно потому, что
   display: grid у .photos перебивает атрибут hidden. */
.photos[hidden] { display: none; }

.badge {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge--free   { background: #D8C3A5; color: #2B211A; }          /* свободен */
/* Резерв, правка А9 от 14.08.2026. Заливка терракотовая, текст белый.
   Тёмный #2B211A на терракоте даёт 3.44, светлый #F7F0E5 из задания 4.04,
   оба ниже порога 4.5, а кегль бейджа 12px, то есть послабления
   для крупного текста здесь нет. Чистый белый даёт 4.57 и порог проходит.
   Сам оттенок терракоты не тронут: он выбран клиентом, см. раздел
   «Правка вне Claude Code: терракотовые акценты». */
.badge--hold   { background: var(--terracotta); color: #FFFFFF; }          /* резерв */
.badge--sold   { background: rgba(43, 33, 26, 0.82); color: #E8DCC8; }     /* продан */

.card__body {
  padding: 18px 20px 22px;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

/* text-transform у имени котёнка оставлен сознательно: это повторяющееся
   поле данных, клиент будет добавлять котят и печатать имена как привычно.
   Правило гарантирует, что все карточки выглядят одинаково. То же у бейджей
   статуса и у мелкой надписи над заголовком. */
.card__name {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(22px, 1.9vw, 27px);
  font-weight: var(--name-weight);
  line-height: 1.15;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold-deep);
}
/* Значка пола в заголовке карточки БОЛЬШЕ НЕТ и заводить обратно нельзя.
   Клиент 16.08.2026: «иконки палитра, красок, и где пол мальчик девочка -
   они уже устаревшие такие-то». Значок заменился строкой характеристик
   «Пол: кот» с ключом <база>.sex. Для читающего экраном это строго лучше:
   было <svg aria-label="кот">, стало обычный текст.

   Заодно закрылся висевший долг по контрасту: значки пола и характеристик
   давали 2.20 при пороге 3.0. Мерить больше нечего.

   ВТОРАЯ ПРАВКА ТОГО ЖЕ ДНЯ, строка пола осталась только у котят.
   Клиент 16.08.2026: «пол у котят девочка, мальчик, а у кошек и котов пол
   не надо писать». Логика её: страница называется «Коты» или «Кошки»,
   пол читается из названия раздела.
     - коты и кошки: строки нет вовсе, ключи cats.*.sex и queens.*.sex
       выведены из употребления, всего девять;
     - котята и ориенталы: строка на месте, значения сменились с
       «кот» и «кошка» на «мальчик» и «девочка», ключи kitten.N.sex
       и orientals.N.sex остались.
   У взрослых в карточке теперь две строки вместо трёх: окрас и тесты. */

/* строки характеристик */
.card__specs {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 9px;
}
.spec {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  line-height: 1.4;
  color: var(--text);
}
/* .spec__icon удалён вместе со значками строк, см. комментарий выше.
   Строка теперь начинается прямо с метки: первым flex-элементом стоит
   .spec__label, никакого отступа от бывшего значка не остаётся -
   проверено замером, левый край метки совпадает с левым краем
   .card__specs до пикселя. gap: 9px у .spec теперь работает между
   меткой и значением, а не между значком и меткой. */
.spec__label {
  color: var(--muted);
}

/* ЗНАЧЕНИЕ ТОГО ЖЕ ЦВЕТА, ЧТО И ПОДПИСЬ. Правка 16.08.2026, замечание
   клиента: «убрать чёрный, значения должны быть того же цвета, что
   и подписи Пол, Окрас». До неё цвет здесь не задавался вовсе и приходил
   наследованием от .spec (color: var(--text), #2B211A).

   Различие подписи и значения держит ВЕС, а не цвет: 500 против 400.
   Поэтому font-weight остаётся и снимать его нельзя - иначе строка
   «Окрас: розетка на золоте» станет однородной и перестанет читаться
   как пара «поле - значение».

   Цвет НЕ прописан здесь константой, а взят той же переменной, что
   у подписи. Это не стилистика, а требование контраста: подпись на этом
   сайте контекстная, на карточке котёнка она перекрашивается в
   --sand-label (см. блок .kittens ниже). Замер по реальным фонам,
   порог 4.5:

     карточка кота и кошки, фон --surface #F7F0E5
       подпись и значение #6B5A48            5.83   порог берёт
     карточка котёнка, фон --sand-bg #D8C3A5
       подпись и значение #5A4A3A            4.96   порог берёт

   Поставить #6B5A48 единым цветом на обе подложки НЕЛЬЗЯ: на #D8C3A5
   он даёт 3.86 и порог проваливает. Отсюда парное правило в блоке
   .kittens - оно ведёт значение за подписью, а не заводит третий цвет. */
.spec__value {
  font-weight: 500;
  color: var(--muted);
}

/* ── Полоса преимуществ, четыре пункта в ряд ─────────────────────────────── */

.perks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
  text-align: center;
}
.perk {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.perk__text {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
  max-width: 22ch;
}
.theme-dark .perk__text,
.theme-dark .spec,
.theme-dark .spec__value { color: var(--cream); }
.theme-dark .spec__label { color: var(--gold); opacity: 0.8; }
.theme-dark .card {
  background: rgba(20, 15, 11, 0.34);
  border-color: rgba(216, 183, 150, 0.22);
}
.theme-dark .card__name { color: var(--gold-light); }
.theme-dark .card__media { background: #241B14; }

/* ==========================================================================
   БЛОК «КОТЯТА»
   Сетка карточек и полоса преимуществ уже есть выше, здесь только обвязка
   раздела: кнопки под карточками, мелкая строка под ними и подраздел
   «В новом доме».

   Карточка изменена по решению клиента от 13.08: строки «Дата рождения»
   больше нет вовсе, вместо строки статуса стоит цена по запросу. Правка
   сделана в разметке, отдельных стилей ей не потребовалось - строка
   характеристики та же .spec, поменялись только значок и подписи.
   ========================================================================== */

/* ── Заголовок раздела по центру: длина разделителя ──────────────────────────
   .divider объявлен на 100% ширины - это правка от 13.08 под блок «О
   питомнике», где ширину задаёт .about__head { width: fit-content }.
   Само правило не трогаем. Но у центрированного .sec-head контейнер
   на всю полезную ширину, и под коротким словом «КОТЯТА» линия шла
   бы через все 1280px. Ограничиваем её здесь, в области .sec-head:
   тогда и модификатор .divider--center с его auto-полями снова работает,
   ради чего он и заводился. */
.sec-head .divider {
  width: min(100%, 340px);
  margin-top: 20px;
}
.sec-head__note { margin-top: 18px; }

/* ФОН --bg, правка 16.08.2026. Клиент дословно: «А светлые блоки котята,
   полезное о бенгалах, отзывы сделать цветом как сейчас О питомнике».
   На тот момент «О питомнике» стоял на --bg #EFE4D3 - его и берём.

   ЗДЕСЬ СТОЯЛО: «фон --surface, а не --bg, потому что выше блок О питомнике
   тоже на --bg и два одинаковых фона подряд сливаются». Причина снята тем же
   кругом: «О питомнике» уехал на песочный --sand-bg, соседних одинаковых
   фонов больше нет. Чередование теперь такое:
       hero -> песочный about -> светлый kittens -> плашки на --bg ->
       светлый articles с песочными карточками -> песочная лента ->
       светлые отзывы -> тёмные контакты. */
.kittens {
  background: var(--bg);
  padding: 76px 0;
}

/* ЗАТЫЧКА .kittens .card { background: var(--bg) } СНЯТА 16.08.2026.
   Она заводилась под секцию --surface: карточка --surface на секции
   --surface давала отношение 1.00 и пропадала. Секция стала --bg, значит
   и затычка стала бы окраской фона в цвет фона.

   Карточка от этого не пропадает, и это замерено, а не предположено:
   видимое тело карточки - это фотография сверху и песочный .card__body
   снизу, собственный фон .card под ними не виден нигде. Отношение
   песочного тела к новому фону секции 1.36 (было 1.51 на --surface).
   Волосяная рамка карточки к фону даёт 1.28 - столько же, сколько
   и раньше у карточек статей; это известный долг, он записан в README
   отдельным списком и в этот круг не входит. */

/* Тело карточки котёнка, правка А9 от 14.08.2026. Клиент: залить цветом
   бейджа «Свободна». Замер контраста по реальным пикселям на этой подложке:

     значение окраса и цены   --text #2B211A     9.19   порог берёт
     подпись «Окрас:», «Цена:» #5A4A3A           4.96   порог берёт
     имя котёнка              #6B4C24            4.57   порог берёт

   Третья строка закрыта правкой того же 14.08: клиент выбрала оттенок
   из показанных ей вариантов, вопрос снят. Было --gold-deep #845E2C
   и 3.39. Переменная своя, --sand-name, разбор рядом с ней.

   Селектор из .kittens: сама переменная объявлена в :root, но красить
   ею ВСЕ .card__name нельзя. На тёмных блоках имя идёт --gold-light,
   а карточка статьи стоит на другом фоне, и там прежний --gold-deep
   порог берёт. Правка касается ровно карточек котят. */
.kittens .card__body { background: var(--sand-bg); }
.kittens .card__body .spec__label { color: var(--sand-label); }
/* Значение идёт за подписью, правка 16.08.2026. Клиент попросила снять
   с значений чёрный и сравнять их по цвету с подписями. На этой подложке
   подпись уже перекрашена строкой выше, поэтому значение берёт ту же
   переменную, а не --muted: #6B5A48 здесь даёт 3.86 при пороге 4.5,
   #5A4A3A даёт 4.96. Разбор у базового правила .spec__value выше. */
.kittens .card__body .spec__value { color: var(--sand-label); }
.kittens .card__body .card__name  { color: var(--sand-name); }

/* Пустое состояние обоих разделов котят: ключи kittens.empty
   и orientals.empty. Показывается снятием атрибута hidden, снимает
   и возвращает его админка при удалении и добавлении карточек.
   Своего display здесь нет намеренно - иначе hidden перестал бы
   работать: у элемента с display в авторских стилях правило
   [hidden]{display:none} из таблицы браузера проигрывает по происхождению. */
.kittens__empty {
  margin: 34px auto 0;
  max-width: 52ch;
  text-align: center;
  color: var(--muted);
}

/* Две кнопки в ряд, одинаковой ширины. Приём тот же, что у кнопок первого
   экрана: дорожки 1fr в контейнере, сжатом по содержимому, поэтому обе
   кнопки принимают ширину самой широкой, какой бы текст в них ни стоял. */
.kittens__actions {
  margin: 44px auto 0;
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
  gap: 14px;
  width: max-content;
  max-width: 100%;
}

.kittens__btn-note {
  margin: 14px 0 0;
  text-align: center;
}

/* Подраздел «В новом доме». Карточка одна, а сетка карточек выше
   трёхколоночная, поэтому просто вложенная .cards оставляла бы карточку
   в левой трети и две пустые колонки справа - это читается как обрубок
   сетки, а не как отдельная мысль. Поэтому колонка ровно одна, шириной
   в колонку той же сетки, и она вместе с подзаголовком стоит по центру,
   как весь остальной ритм раздела. */
/* Правила .kittens__home убраны 14.08.2026 вместе с самим подразделом,
   см. замечание клиента А1. Класс .card--plain оставлен: он общий
   и понадобится на странице котят. */

/* Карточка без тела, только фотография. Подъём при наведении снят:
   кликать в ней нечего, а карточка, которая шевелится впустую,
   обещает действие, которого нет. */
.card--plain:hover {
  transform: none;
  box-shadow: none;
}

/* ==========================================================================
   БЛОК «ЧТО УЕЗЖАЕТ ВМЕСТЕ С КОТЁНКОМ»
   Тёмная секция. Пункт полосы преимуществ стал двухстрочным: заголовок
   заглавными и строка под ним. Правила ниже сознательно перебивают
   компонентные: у .perk промежуток раздавался одинаково между всеми
   детьми, а теперь между значком и заголовком он должен быть больше,
   чем между заголовком и его же строкой, иначе две строки читаются
   как два отдельных пункта.
   ========================================================================== */

/* Заливка: Б3, вариант 1. Клиент просила блок светлее. Градиент поднят
   к цвету шапки: #443322 - #4B3928 - #55412D, то есть середина ровно
   --header-bg. Селектор из двух классов, а не один .perks-sec: общая
   заливка приходит из .theme-dark, а тот объявлен ниже по файлу
   и по одному классу выигрывал бы по порядку следования.

   Отступы: Б5, вариант 1, было 100px. */
.perks-sec.theme-dark {
  background: linear-gradient(150deg, #443322 0%, #4B3928 46%, #55412D 100%);
}

.perks-sec { padding: 76px 0; }
.perks-sec .perks { margin-top: 36px; }

.perk { gap: 0; }
.perk__title {
  margin: 14px 0 0;
  max-width: 22ch;
}
.perk__text { margin: 7px 0 0; }

/* ==========================================================================
   БЛОК «КОГДА КОТЁНОК ПЕРЕЕДЕТ К ВАМ»
   Фон --surface: между двумя более контрастными соседями, тёмной полосой
   преимуществ сверху и отзывами на --bg снизу.
   ========================================================================== */

/* ── Заливка блока «Когда котёнок переедет», правка 16.08.2026 ────────────
   Клиент: «можете его цветом сделать ни светлым ни тёмным, а как в шапке
   по середине под листом».

   Оттенок снят пипеткой с самого кадра первого экрана, assets/img/hero-b.jpg:
   средний тон центральной трети кадра #816448, самый частый пиксель там
   #B09070. Взят средний - он и есть «ни светлый, ни тёмный».

   ГЛАВНАЯ НАХОДКА ЗАМЕРА, из-за неё пришлось менять и цвет текста.
   Средний тон - это провал по контрасту: на нём НЕ проходит ни штатный
   тёмный текст, ни штатный светлый. Замер по реальным пикселям на #816448:

       --text  #2B211A  тёмный текст          2.88   порог 4.5   не берёт
       --cream #E3C4A7  светлый текст         3.30   порог 4.5   не берёт
       --gold-deep      заголовок и ссылка    1.06   порог 3.0   не берёт
       --gold-light     заголовок и ссылка    3.22   порог 4.5   не берёт (ссылка)

   Проходные диапазоны считались по всей тёплой гамме от #4B3928 до #CDB697:
   штатная светлая пара живёт только до #654E39, штатная тёмная - только
   от #A88B6A. Оба края уже читаются как «тёмный» и «светлый», то есть ровно
   то, чего клиент просила избежать.

   Выход найден один: оставить её тон и поднять светлоту текста до #F7F0E5.
   Тогда на #816448 выходит 4.82 при пороге 4.5 - берут и текст, и заголовок,
   и ссылка одним цветом. Это единственная комбинация, в которой держится
   и просьба клиента, и порог.

   Три варианта, снятые для показа, лежат в 01-от-клиента/:
       variant-moving-bg-1.jpg  #654E39, штатная светлая пара, 4.71/4.59
       variant-moving-bg-2.jpg  #816448, текст #F7F0E5, 4.82   <- применён
       variant-moving-bg-3.jpg  #A88B6A, весь текст --text, 4.92
   ======================================================================== */

/* Собственные имена оставлены: на них завязаны все правила ниже, а сами
   значения теперь берутся из :root - с 16.08.2026 этой парой пользуется
   не только .moving, но и обе плашки на главной. */
.moving {
  --moving-bg:   var(--plate-bg);
  --moving-text: var(--plate-text);
  background: var(--moving-bg);
  color: var(--moving-text);
  padding: 76px 0;
}

/* Заголовок, абзацы, текст рамки и ссылка - одним цветом. Золотая гамма
   здесь не работает ни в одном оттенке, замер выше. */
.moving .h-section,
.moving .t-body,
.moving .note__text { color: var(--moving-text); }

.moving .link { color: var(--moving-text); }
.moving .link:hover { color: var(--gold-light); }

/* Контурные элементы: порог для них 3.0, не 4.5.

   ЗДЕСЬ СТОЯЛО «непрозрачность подобрана замером, не на глаз - см. README»,
   и это было неправдой дважды. В README такого замера нет вовсе, а сама
   непрозрачность 0.62 порога НЕ БЕРЁТ: на #816448 смесь даёт #CABBA9
   и контраст 2.90 при пороге 3.0. Поймано 16.08.2026 при сборке плашек
   на главной, когда число копировалось отсюда.

   Развёртка по непрозрачности на этом фоне:

       0.62  #CABBA9  2.90   не берёт
       0.66  #CFC0B0  3.08
       0.70  #D4C6B6  3.26   <- взято здесь и в .plate, одно число на оба
       0.80  #DFD4C6  3.74
       1.00  #F7F0E5  4.82   кольцо перестаёт быть контуром и спорит
                             с подписью рядом

   Блок живёт на bengalskie-kotyata.html и orientalnye-kotyata.html. */
.moving .icon-circle {
  border-color: rgba(247, 240, 229, 0.70);
  color: var(--moving-text);
}

/* Рамка выделенной мысли поднята тем же числом и по той же причине:
   на 0.62 она давала те же 2.90. Это не «заодно» - рамка отделяет
   врезку от текста вокруг, то есть несёт смысл, а не украшает. */
.moving .note { border-color: rgba(247, 240, 229, 0.70); }
/* Здесь стояло `.moving .divider__line { background: … }`. Правило было
   мёртвым: класса .divider__line нет ни на одной из семи страниц -
   проверено grep-ом, в браузере узлов ноль. Линии разделителя рисуют
   ::before и ::after у самого .divider, и до них селектор не доставал.
   Удалено, а не починено, и вот почему: линия чистый декор, .divider
   помечен aria-hidden="true", порог 3.0 к ней не применяется. Замер
   для протокола - #9C754C на #816448, контраст 1.31; лапка 3.84.
   Захотим линию светлее - это `.moving .divider { color: … }`,
   одна строка, но это уже правка внешнего вида двух живых страниц. */
.moving .divider__icon { color: rgba(247, 240, 229, 0.82); }

/* Колонка уже полезной ширины: два абзаца в 1280px дали бы строку
   в 130 знаков, читать такую невозможно. */
.moving__inner { max-width: 880px; }

.moving__text { margin: 20px 0 0; }
.moving__text:first-of-type { margin-top: 26px; }
.moving__note { margin-top: 34px; }

/* ==========================================================================
   ПЛАШКИ НА ГЛАВНОЙ, 16.08.2026
   Две вставки на месте снятых «Что уезжает» и «Когда переедет».

   ПЛАШКА, А НЕ ПОЛОСА. Секция стоит на --bg во всю ширину, а цветной
   прямоугольник лежит внутри .wrap - так просила клиент. Отсюда
   скругление 10px и внутренние поля: это те же 10px, что у карточек
   животных, отдельного радиуса не заводим.

   ПОТОЛОК ВЫСОТЫ 260px НА ОКНЕ 1101. Он задан не свойством, а раскладкой:
   высоту первой плашки держит кадр 340x243, второй - строка значков.
   Если содержимое вырастет, резать надо внутренние отступы, а не кегль -
   так стоит в задании.
   ========================================================================== */

.plate-sec {
  background: var(--bg);
  padding: 48px 0;
}
/* Вторая плашка идёт сразу за первой: между ними один отступ, а не два. */
.plate-sec--follow { padding-top: 0; }

.plate {
  background: var(--plate-bg);
  color: var(--plate-text);
  border-radius: 10px;
  overflow: hidden;
}

/* Кружки значков на плашке. Порог для контурных элементов 3.0, не 4.5.

   НЕПРОЗРАЧНОСТЬ 0.70, А НЕ 0.62, КАК У .moving. Сначала было взято её
   число, но замер по реальным пикселям его не подтвердил: кольцо
   rgba(247,240,229,0.62) на #816448 даёт смесь #CABBA9 и контраст 2.90
   при пороге 3.0 - не берёт. Развёртка по непрозрачности на этом фоне:

       0.62  #CABBA9  2.90   не берёт
       0.66  #CFC0B0  3.08
       0.70  #D4C6B6  3.26   <- взято, с запасом на округление
       0.80  #DFD4C6  3.74
       1.00  #F7F0E5  4.82   сливается с текстом, кольцо перестаёт быть
                             контуром и начинает спорить с подписью

   Кольца в .moving остались на 0.62: блок живёт на двух страницах котят,
   в этот круг он не входил, и трогать его тут значило бы править то,
   о чём не просили. Число названо в отчёте отдельной строкой. */
.plate .icon-circle {
  border-color: rgba(247, 240, 229, 0.70);
  color: var(--plate-text);
}

/* ── Плашка 1: здоровье, социализация, поддержка + кадр ─────────────────── */

.care {
  display: grid;
  grid-template-columns: 1fr 340px;
}

.care__list {
  list-style: none;
  margin: 0;
  padding: 26px 32px;
  display: grid;
  gap: 18px;
  align-content: center;
}
.care__item {
  display: flex;
  align-items: center;
  gap: 16px;
}
.care__title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--plate-text);
}
.care__text {
  margin: 5px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--plate-text);
}

/* Кадр тянется на всю высоту плашки, а min-height задаёт саму высоту,
   пока список короче. 243px - это высота бокса, под которую нарезана
   полоса; менять здесь, не пересобрав кадр, нельзя. */
.care__media {
  position: relative;
  min-height: 243px;
  background: var(--dark);
}
.care__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── Плашка 2: договор, метрика, ветеринарный паспорт ───────────────────── */

.docs {
  display: grid;
  grid-template-columns: minmax(210px, 290px) 1fr;
  gap: 40px;
  align-items: center;
  padding: 28px 32px;
}
.docs__lead {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(20px, 1.9vw, 26px);
  font-weight: var(--name-weight);
  line-height: 1.25;
  letter-spacing: 0.03em;
  color: var(--plate-text);
}
.docs__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
}
.docs__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* Две строки под заголовок держатся всегда: «ВЕТЕРИНАРНЫЙ ПАСПОРТ»
   переносится, два соседних заголовка - нет, и без этого пояснения
   под ними вставали на разной высоте. Число не в пикселях, а в строках
   собственного line-height, поэтому переживёт смену кегля. */
.docs__title {
  margin: 12px 0 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  min-height: 2.6em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--plate-text);
}
.docs__text {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--plate-text);
  max-width: 24ch;
}

/* Строка под второй плашкой - остаток блока «Когда переедет». Лежит
   на фоне страницы, не на плашке, поэтому цвета здесь штатные.

   КЕГЛЬ ПОДНЯТ ДО ОСНОВНОГО, правка 16.08.2026. Замечание: «строка набрана
   слишком мелко для своего места». Было 14px/22.4 (1.6), стало
   var(--fs-body) и 1.72 - ровно то, чем набран обычный абзац .t-body
   (styles.css, .t-body). Произвольного числа здесь нет: и кегль,
   и межстрочный взяты у основного текста, чтобы строка не разошлась
   с ним при следующей правке шкалы.

   На 1101 это 16px/27.52 вместо 14px/22.4, на 1440 - 18px/30.96:
   --fs-body это clamp(16px, 1.3vw, 18px), то есть строка теперь едет
   за окном так же, как абзацы.

   max-width: 66ch НЕ ТРОНУТ намеренно. ch едет за кеглем, поэтому длина
   строки в знаках осталась прежней - выросла только высота букв. Если
   заменить на пиксели, строка при 18px станет короче на четверть.

   Контраст не менялся и мерить его заново не пришлось: цвет тот же --text
   #2B211A, фон тот же --bg #EFE4D3 (секция .plate-sec в правку цветов
   не входила, плашки клиент не упоминала). Отношение 12.51. */
.plate-note {
  margin: 18px auto 0;
  max-width: 66ch;
  text-align: center;
  font-size: var(--fs-body);
  line-height: 1.72;
  color: var(--text);
}

/* Адаптив плашек держим здесь же, а не в общем хвосте файла: правила
   ссылаются на числа из соседних строк (340px кадра, три колонки значков),
   и разносить их по файлу значит потерять связь. */

/* Строка слева отнимает у трёх значков слишком много, как только окно
   уходит ниже 1100: замер на 768 давал колонку 133px под заголовок
   «ВЕТЕРИНАРНЫЙ ПАСПОРТ». Поэтому строка встаёт над значками. */
@media (max-width: 1100px) {
  .plate-sec { padding: 40px 0; }
  .docs {
    grid-template-columns: 1fr;
    gap: 22px;
    align-items: start;
  }
}

@media (max-width: 760px) {
  .plate-sec { padding: 32px 0; }

  /* Кадр уходит под список: на узком экране колонка 340px съела бы
     половину плашки, а котёнок в ней стал бы нечитаемым. */
  .care { grid-template-columns: 1fr; }
  .care__list { padding: 22px 20px; }
  /* Пропорция, а не высота. Фиксированные 190px на ширине 350 давали бокс
     1.84 против полосы 1.40, и cover срезал 24% высоты - ровно по ушам.
     С aspect-ratio бокс совпадает с полосой и срез нулевой. */
  .care__media {
    min-height: 0;
    aspect-ratio: 340 / 243;
  }

  .docs { padding: 22px 20px; }
  .docs__list { grid-template-columns: 1fr; gap: 18px; }
  /* Значок уходит влево от текста: столбиком три пункта заняли бы
     экран целиком. */
  .docs__item {
    flex-direction: row;
    align-items: center;
    gap: 14px;
  }
  /* В строку заголовку резерв в две строки не нужен: он и так слева
     от текста, а не над ним. */
  .docs__title { margin: 0; min-height: 0; }
  .docs__text { max-width: none; }
}

/* Ссылка внутри текста. Подчёркивание не убираем: это единственный
   признак, по которому ссылку в абзаце видно. */
.link {
  color: var(--gold-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color var(--ease);
}
.link:hover { color: var(--terracotta); }

/* ==========================================================================
   БЛОК «ОТЗЫВЫ»
   Один li - один отзыв, все поля с ключами: блок наполняется через админку.
   Скриншотов нет, только текст. Фотографии из отзывов не используются:
   на обоих google-отзывах стоит пометка про авторское право.
   ========================================================================== */

/* ФОН --bg, правка 16.08.2026, второй заход за день. Клиент: «светлые блоки
   котята, полезное о бенгалах, отзывы сделать цветом как сейчас О питомнике».

   ПЕРВЫЙ ЗАХОД ЭТОГО ЖЕ ДНЯ увёл отзывы с --bg на --surface, и причина была
   не вкусовая: клиент передвинула отзывы вниз, под бегущую ленту, лента
   стояла на --bg, и два одинаковых фона встали вплотную. Причина снята
   тем же кругом - лента уехала на песочный --sand-bg. Соседства двух
   одинаковых фонов снова нет: песочная лента сверху, --bg отзывы,
   тёмные контакты снизу.

   Карточки отзывов остаются на --surface. Отношение карточки к секции
   выросло с 1.00 (карточка --surface на секции --surface, то есть граница
   держалась только на волосяной рамке) до 1.11. Внутренности карточки
   не тронуты, мерить их заново не пришлось: фон под ними тот же --surface. */
.reviews {
  background: var(--bg);
  padding: 76px 0;
}

.reviews__list {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  /* Карточки не тянутся до высоты самой высокой. Без этого раскрытие
     длинного отзыва (А5) растягивало соседние карточки до 766px
     и оставляло в них пустое поле в две трети высоты. */
  align-items: start;
}

.review {
  display: flex;
  flex-direction: column;
  padding: 26px 24px 28px;
  background: var(--surface);
  border: 1px solid rgba(62, 47, 32, 0.14);
  border-radius: 10px;
}

.review__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(21px, 1.7vw, 25px);
  font-weight: var(--name-weight);
  line-height: 1.15;
  letter-spacing: 0.05em;
  color: var(--gold-deep);
}

/* Пять звёзд в ряд. Звезда - свой символ спрайта, сплошной заливкой:
   контурная при 15px превращается в кашу. Цвет идёт через color,
   потому что в символе стоит fill="currentColor". */
.stars {
  display: flex;
  gap: 4px;
  margin: 11px 0 0;
}
/* Цвет: применён вариант 1 из _variants.html. Клиент просила жёлтые.
   Сам по себе #E8A317 на кремовой карточке даёт 1.92 при пороге 3
   для графики - жёлтый на светлом порог не берёт в принципе, лучший
   реалистичный тёплый жёлтый около 2.9. Поэтому у звезды добавлена
   тонкая обводка цветом --gold-deep: форма читается по контуру,
   а заливка остаётся жёлтой.

   paint-order: stroke fill кладёт обводку ПОД заливку, иначе она съедает
   половину толщины лучей и звезда полнеет. Обводка на use, а не на .star:
   символ объявляет fill="currentColor" у себя, снаружи задавать нечего.

   ЭТИ ТРИ СТРОКИ ДО 14.08.2026 НЕ РАБОТАЛИ ВОВСЕ. У пути внутри символа
   стоял свой stroke="none", а атрибут представления на самой фигуре бьёт
   значение, наследуемое от <use>: наследование доходит только туда, где
   элемент СВОЕГО значения не объявил. Правило считалось живым, потому что
   в вычисленных стилях <use> stroke действительно менялся - но красился
   не он, а путь внутри. Атрибут из спрайта снят, обводка применилась.
   Замер после, по реальным пикселям снимка звёзд при масштабе 4:
   обводка легла ровно #845E2C, 945 пикселей из 71936, контраст к фону
   карточки отзыва #F7F0E5 - 5.13 при пороге 3 для графики. Сама жёлтая
   заливка на том же фоне даёт 1.92 и порог не берёт в принципе, любой
   реалистичный тёплый жёлтый на светлом упирается примерно в 2.9.
   То есть за форму звезды теперь отвечает контур, а не заливка.

   ВАЖНО ДЛЯ БУДУЩИХ ЗАМЕРОВ. Автопроверка по-прежнему покажет здесь
   1.92: она читает у <use> свойство color, а это заливка. Обводку
   она не видит и увидеть не может. Это не провал, это предел метода -
   проверяется отдельным замером по пикселям.

   Оценка продублирована текстом в aria-label="Оценка 5 из 5",
   то есть цветом информация не передаётся. */
.star {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  color: #E8A317;
}
.star use {
  stroke: var(--gold-deep);
  stroke-width: 1.1px;
  paint-order: stroke fill;
}

.review__meta {
  margin: 11px 0 0;
  font-size: var(--fs-caption);
  letter-spacing: 0.02em;
  color: var(--muted);
}

.review__text {
  margin: 15px 0 0;
  font-size: 15px;
  line-height: 1.66;
  color: var(--text);
}

/* ── Свёрнутый отзыв, правка А5 от 14.08.2026 ─────────────────────────────
   Класс вешает скрипт и только тем карточкам, где текст действительно
   не влезает в четыре строки. Пока скрипт не отработал, текст виден
   целиком: без JS отзыв читается полностью, а не обрезается навсегда.

   Затухание сделано маской, а не полосой-градиентом поверх текста.
   Причина: полоса пришлось бы красить в цвет карточки, а карточка меняет
   фон в тёмных секциях, и полоса там выдавала бы себя прямоугольником.
   Маска работает от прозрачности и фон знать не обязана. Заодно
   многоточие, которое line-clamp дорисовывает в конце четвёртой строки,
   попадает в размытую зону и не мозолит глаз. */
.review__text--clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}

/* Кнопка «Читать дальше» одна на два места: отзывы и блок «О питомнике».
   Общий вид собран в .more-btn, чтобы две кнопки на одной странице
   не разъехались по кеглю и подчёркиванию. Своё у каждой только
   положение в потоке. */
.more-btn {
  /* Отступа здесь нет намеренно: его задаёт место, где кнопка стоит.
     Общее правило лежит ниже по файлу, чем .about__more, и «margin: 0»
     тут молча стирало бы его отступ. */
  padding: 4px 0;
  border: none;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--gold-deep);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  cursor: pointer;
  transition: color var(--ease);
}
.more-btn:hover { color: var(--terracotta); }
.more-btn:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Карточка отзыва - флекс-колонка, поэтому кнопке нужен align-self:
   без него она растянулась бы на всю ширину карточки. */
.review__more {
  align-self: flex-start;
  margin: 10px 0 0;
}

/* Правила .reviews__link убраны 14.08.2026 вместе со ссылкой
   на Яндекс.Карты, см. замечание клиента А2. */

/* ==========================================================================
   БЛОК «ПОЛЕЗНОЕ О БЕНГАЛАХ»
   Четыре карточки без фотографий, со значком в кружке. Причина - правило
   единообразия из задания: либо иллюстрации есть у всех четырёх, либо
   ни у одной. Своя картинка в бэкапе годится только у двух статей.

   ЦВЕТА, правка 16.08.2026. Клиент: секцию «сделать цветом как сейчас
   О питомнике» (то есть --bg), а карточки «поменять на песочный цвет
   как у котят на карточке». Приём стал общим для всей главной: светлая
   секция с песочными карточками внутри. Ровно так же собран блок котят.
   Разбор контраста - у самой карточки .art__link ниже.

   Правило одно на два места: карточки на главной и на /eto-interesno.html
   (.articles--index). Разметка там и там одинаковая, отдельных стилей
   у страницы статей нет.
   ========================================================================== */

.articles {
  background: var(--bg);
  padding: 76px 0;
}

.articles__list {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 22px;
}

.art { display: flex; }

/* Ссылка на всю карточку: кликается вся площадь, а не только заголовок.

   ПОДЛОЖКА ПЕСОЧНАЯ --sand-bg, правка 16.08.2026, прямая просьба клиента.
   Была --bg на секции --surface, стала --sand-bg на секции --bg. Отношение
   карточки к секции при этом ВЫРОСЛО: было 1.11, стало 1.36 - карточка
   читается лучше, чем читалась.

   ВЕСЬ ТЕКСТ И ДЕКОР КАРТОЧКИ ПЕРЕСОБРАН ПОД ЭТУ ПОДЛОЖКУ. На песке
   штатные цвета порог не берут, замер по реальным пикселям:

     заголовок  --gold-deep #845E2C   3.39   порог 4.5   НЕ берёт
     анонс      --muted     #6B5A48   3.86   порог 4.5   НЕ берёт
     кружок и значок --accent         2.20   порог 3.0   НЕ берёт

   Поставлено, замерено на той же подложке:

     заголовок  --sand-name  #6B4C24   4.57   порог 4.5   берёт
     анонс      --sand-label #5A4A3A   4.96   порог 4.5   берёт
     кружок и значок --brown  #7A5432   3.91   порог 3.0   берёт

   Заголовок 17px при весе 600 под послабление для крупного текста
   не подпадает - оно начинается с 18.66px, - поэтому порог полный 4.5,
   а не 3.0. Новых цветов не заведено ни одного. */
.art__link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  width: 100%;
  padding: 26px 22px 28px;
  background: var(--sand-bg);
  border: 1px solid rgba(62, 47, 32, 0.14);
  border-radius: 10px;
  transition: transform var(--ease), box-shadow var(--ease),
              border-color var(--ease);

  /* Кружок значка и сам значок. Одной строкой на оба, как в .about. */
  --deco: var(--brown);
}
.art__link:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 34px rgba(62, 47, 32, 0.16);
  border-color: var(--deco);
}

.art__title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: var(--sand-name);
}

.art__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.62;
  color: var(--sand-label);
}

.articles__more { margin: 34px 0 0; text-align: center; }

/* ==========================================================================
   БЛОК «НАШИ КОШКИ», бегущая лента
   Двенадцать кадров, следом тот же ряд второй раз с aria-hidden: это
   и даёт бесшовную петлю.

   Едет только transform: translateX, без left и без таймеров в JS.
   Ключ к незаметному шву - хвостовой padding-right у ряда: он ровно
   в размер промежутка между кадрами, поэтому обе половины дорожки
   одинаковой ширины и -50% попадает точно в начало второго ряда.
   Сдвиг в процентах, а не в пикселях: ширины кадров разные, пиксельная
   арифметика тут не сошлась бы.

   Полный проход 60 секунд, linear: с ease лента дёргалась бы на стыке
   каждого цикла.
   ========================================================================== */

/* ФОН ПЕСОЧНЫЙ --sand-bg, правка 16.08.2026. Клиент: «блок с движущимися
   фото поменять на песочный цвет как у котят на карточке».

   Мерить здесь нечего и это не отговорка: секция собрана модификатором
   .gallery-sec--bare, у неё нет ни заголовка, ни разделителя, ни подписи -
   только полоса кадров. Текстовых узлов внутри ноль, проверено обходом
   дерева. Единственное, что видно от самого фона, - поля сверху и снизу
   от полосы. */
.gallery-sec {
  background: var(--sand-bg);
  padding: 76px 0;
}

/* Лента во всю ширину окна, поэтому лежит вне .wrap. */
.gallery {
  margin-top: 34px;
  overflow: hidden;
}

/* Секция без заголовка (А3). Собственный отступ ленты снят: он был
   расстоянием от разделителя с лапкой до кадров, а разделителя больше нет,
   и лента отъезжала от статей на 134px вместо 100. Отступы секции
   при этом не тронуты, поэтому расстояние до статей сверху и до контактов
   снизу осталось прежним, 100px на компьютере и 56px на телефоне. */
.gallery-sec--bare .gallery { margin-top: 0; }

.gallery__track {
  display: flex;
  width: max-content;
  animation: gallery-run 60s linear infinite;
}

.gallery__row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0;
  padding: 0 14px 0 0;   /* хвостовой промежуток, см. комментарий выше */
  list-style: none;
}

.gallery__item { flex: 0 0 auto; }

.gallery__item img {
  height: 260px;
  width: auto;
  border-radius: 4px;
}

@keyframes gallery-run {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* Останов при наведении. focus-within добавлен не для красоты: без него
   лента увозила бы ссылку из-под клавиатурного фокуса. */
.gallery:hover .gallery__track,
.gallery:focus-within .gallery__track { animation-play-state: paused; }

.gallery__more { margin: 34px 0 0; text-align: center; }

/* ==========================================================================
   БЛОК «НАПИСАТЬ НАМ»
   Тёмная секция. Формы заявки и карты нет: клиент от них отказалась.
   Улица и точный адрес не выводятся, остаётся только город.
   ========================================================================== */

.contacts { padding: 76px 0; }

.contacts__list {
  list-style: none;
  margin: 36px auto 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 330px));
  gap: 18px 44px;
  width: fit-content;
  max-width: 100%;
}

.contact {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* Значку не задаём ни fill, ни stroke: часть символов контурные, часть
   залитые (WhatsApp и Telegram - фирменные знаки), и каждый объявляет
   это у себя. Снаружи задаём только размер и color. */
.contact__icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--gold);
}

/* Номер и подпись под ним одной колонкой, значок телефона слева от обоих */
.contact__stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}
/* ИМЯ ПОДНЯТО ДО 17px, правка 16.08.2026. Клиент дословно: «Имя моё
   в подвале изменить на размер как телегр, инстаграм». «Телеграм»
   и «Инстаграм» - это .contact__link, у них 17px, поэтому число взято
   у них, а не подобрано.

   ЗДЕСЬ СТОЯЛО «подпись мельче номера: 13px против 17px». На 13px строка
   читалась служебной сноской, хотя это имя человека, которому пишут.

   ЧЕМ ИМЯ ТЕПЕРЬ ОТЛИЧАЕТСЯ ОТ НОМЕРА, раз кегль сравнялся. Тремя вещами
   сразу, и ни одна из них не кегль:
     цвет           --gold #D8B796 против --cream #E3C4A7 у ссылки;
     подчёркивание  у номера есть, у имени нет - это не ссылка;
     разрядка       0.02em против нуля.
   Спорить по весу они не могут: начертание у обоих одно.

   Межстрочный задан явно. При 13px хватало наследованного, при 17px
   в паре с gap: 2px строки вставали слишком тесно. 1.3 - то же
   отношение, что у .card__name и .docs__title.

   Контраст к фону тёмной секции замерен заново после подъёма кегля,
   число в отчёте круга. */
.contact__name {
  font-size: 17px;
  line-height: 1.3;
  letter-spacing: 0.02em;
  color: var(--gold);
}

.contact__link,
.contact__text {
  font-size: 17px;
  color: inherit;
}
.contact__link {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(227, 196, 167, 0.45);
  transition: color var(--ease), text-decoration-color var(--ease);
}
.contact__link:hover {
  color: var(--gold-light);
  text-decoration-color: currentColor;
}

/* ==========================================================================
   РАЗДЕЛ «СТАТЬИ» И СТРАНИЦА КОНТАКТОВ
   Влито 16.08.2026 из assets/css/_draft-articles.css, который собирался
   отдельным файлом, пока styles.css держало соседнее окно. Тот круг
   закрыт, файл влит целиком и удалён, временное подключение снято
   с девяти страниц.

   Проверено перед вливанием: из 25 селекторов черновика НИ ОДИН
   не совпадает с 374 селекторами этого файла, то есть ни одно
   существующее правило не переопределяется. Новых переменных,
   цветов и порогов @media не заведено: только 1100 и 760, те же,
   на которых стоит весь файл.
   ========================================================================== */

/* ── Секция тела статьи ────────────────────────────────────────────────────
   Фон и отступы ровно те же, что у .articles (styles.css:2815 и :3458):
   раздел статей и страница статьи должны читаться одним разделом.

   Карточка на .articles светлее фона наоборот, чем в блоке котят, и здесь
   этот приём не нужен - у страницы статьи карточек нет вовсе, есть колонка
   текста прямо на фоне секции. Поэтому просто --surface. */

.article {
  background: var(--surface);
  padding: 76px 0;
}

/* Колонка чтения. 72ch, а не «сколько влезет»: при --fs-body 18px это
   примерно 700px, и рядом с кадром шириной 300px остаётся ещё 376px
   текста - около 45 знаков в строке. При 68ch оставалось бы 336px,
   то есть 40 знаков, и обтекание рвало бы строки в лапшу.

   overflow-wrap: anywhere - под длинные слова и адреса. В текстах клиента
   встречаются «овариогистероэктомия» (21 знак) и «фелинологических»;
   на 360px в колонке около 300px, и без этого правила такое слово
   вылезало бы за край вместе с горизонтальной прокруткой всей страницы. */
.article__body {
  max-width: 72ch;
  margin: 0 auto;
  overflow-wrap: anywhere;
}

/* ── Ритм внутри статьи ────────────────────────────────────────────────────
   Отступ задаётся сверху и только соседям, а не всем подряд: у первого
   элемента колонки верхнего отступа быть не должно, его уже дало поле
   секции. Тот же приём, что у .show__plate > :first-child. */

.art-p { margin: 0; }
.art-p + .art-p { margin-top: 16px; }

/* Подзаголовок статьи. Тот же голос, что у заголовка раздела: --font-display
   (Jost Light 300), тот же --gold-deep, та же разрядка по смыслу, только
   мельче и тише. Регистр НЕ трогаем: заголовки написаны клиентом строчными,
   а text-transform: uppercase менял бы её текст на экране.

   clear: both обязателен. Без него заголовок следующего раздела заезжает
   вбок к кадру предыдущего: в «Что нужно приобрести» кадры и подзаголовки
   идут вперемежку, и каждый второй раздел начинался бы в узкой щели
   рядом с чужой картинкой. Кадр, который относится к самому заголовку,
   стоит в разметке ПОСЛЕ него и поэтому этим правилом не сбрасывается. */
.art-h2 {
  clear: both;
  margin: 36px 0 0;
  font-family: var(--font-display);
  font-size: clamp(21px, 1.9vw, 26px);
  font-weight: var(--name-weight);
  line-height: 1.25;
  letter-spacing: 0.06em;
  color: var(--gold-deep);
}
.article__body > .art-h2:first-child { margin-top: 0; }
.art-h2 + .art-p { margin-top: 14px; }

/* Вложенный подзаголовок. Нужен ровно в одной статье, «Стандарты
   бенгальской породы»: там под «Общепринятые стандарты» лежат
   «Телосложение животного», «Голова животного» и «Шерсть и окрас».
   Взят основной шрифт, а не --font-display: два уровня подряд одним
   шрифтом отличались бы только кеглем, а это плохо читается. */
.art-h3 {
  clear: both;
  margin: 26px 0 0;
  font-size: 18px;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: var(--gold-deep);
}
.art-h3 + .art-p { margin-top: 12px; }

/* Список. Маркер свой, а не браузерный: у стандартного disc нет способа
   покрасить его отдельно от текста, а он должен идти цветом декора,
   как все линии и кружки на сайте. 6px кружок на --deco даёт на --surface
   3.33 при пороге 3 для графики. */
.art-list {
  clear: both;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}
.art-li {
  position: relative;
  padding-left: 22px;
  font-size: var(--fs-body);
  line-height: 1.72;
  color: var(--text);
}
.art-li + .art-li { margin-top: 10px; }
.art-li::before {
  content: '';
  position: absolute;
  left: 4px;
  /* 0.72em от верха строки, а не 50% высоты пункта: пункт в четыре строки
     иначе получал бы маркер посередине абзаца вместо первой строки. */
  top: 0.72em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--deco);
}
.art-list + .art-p { margin-top: 16px; }

/* ── Кадры в тексте ────────────────────────────────────────────────────────
   Ширина не задаётся стилями вовсе. У каждого <img> стоят свои width
   и height атрибутами, собранные tools/build-article-photos.py, и кадр
   показывается ровно в своём размере. Апскейла нет ни одного: кадр
   185x185 так и стоит 185x185, до ширины колонки не растягивается.

   max-width: 100% - страховка для узких экранов: на 320px в колонке
   остаётся около 264px, и кадр в 300px без неё вылез бы за край. */

/* width: fit-content обязателен, и это поймано замером, а не придумано.
   Без него .art-fig это обычный блок во всю ширину колонки, кадр внутри
   прижат к левому краю, и `margin: auto` на телефоне ничего не центрует:
   на 390 колонка 354px, кадр «Переноска» 185px и слева от него 0px,
   справа 169. С fit-content коробка садится по кадру и поля выходят
   ровные. На широких экранах правило ничего не меняет: float и так
   ужимает коробку по содержимому. */
.art-fig {
  margin: 0;
  width: fit-content;
  max-width: 100%;
}
.art-fig img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

.art-fig--left  { float: left;  margin: 6px 26px 18px 0; }
.art-fig--right { float: right; margin: 6px 0 18px 26px; }

/* Пара кадров. Обтекать их текстом нельзя: между двумя floats шириной
   300px у абзаца осталось бы около ста пикселей. Идут своим рядом,
   по центру колонки, и сбрасывают всё, что плавает выше. */
.art-figs {
  clear: both;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin: 20px 0 4px;
}
.art-figs .art-fig--left,
.art-figs .art-fig--right { float: none; margin: 0; }

/* Хвост секции обязан быть ниже последнего кадра: без этого кнопка
   «Все статьи» заезжала бы вбок к кадру последнего раздела. */
.article__body::after { content: ''; display: block; clear: both; }

/* ── Список без заголовка секции над ним ───────────────────────────────────
   На главной и .articles__list, и .contacts__list идут следом за .sec-head,
   и собственный верхний отступ у них - это расстояние от разделителя
   с лапкой до первой карточки: 34px и 36px соответственно.

   На новых страницах заголовок раздела стоит выше, в .page-head, а список
   лежит первым в своём .wrap. Отступ в этом случае складывается с полем
   секции и превращается в лишнюю пустую полосу: замер на 1101 - 110px
   от разделителя до карточек вместо 76, и 127px до первого контакта.
   Обнуляем его модификатором, сам компонент не трогаем. */
.articles--index .articles__list { margin-top: 0; }
.contacts--page .contacts__list { margin-top: 0; }

/* ── Страница контактов ────────────────────────────────────────────────────
   Пункт про регистрации стоит на всю ширину списка. Причина замерена:
   строка «Зарегистрирован в европейской системе WCF и в американской
   системе TICA» это 71 знак, а колонка списка 330px минус значок и зазор,
   то есть около 294px - при 13px строка рвалась на пять кусков и пункт
   становился вдвое выше соседей. На всю ширину она встаёт в две строки. */
.contact--wide { grid-column: 1 / -1; }

/* ── Адаптив ───────────────────────────────────────────────────────────────
   Пороги те же, что у всего файла: 1100 и 760. Своих не заводим. */

@media (max-width: 1100px) {
  .article { padding: 76px 0; }
}

@media (max-width: 760px) {
  .article { padding: 56px 0; }

  /* Обтекание снято. На 760px колонка уже около 700px, но на 390 в ней
     остаётся 334px, и кадр в 300px оставлял бы тексту 34px. Кадр встаёт
     своим рядом по центру - и одиночный, и парный. */
  .art-fig--left,
  .art-fig--right {
    float: none;
    margin: 20px auto;
  }
  .art-figs { gap: 12px; }

  .art-h2 { margin-top: 30px; }
  .art-h3 { margin-top: 22px; }

  /* Список на телефоне: отступ под маркер меньше, строка и так короткая. */
  .art-li { padding-left: 18px; }
  .art-li::before { left: 2px; }
}

/* ==========================================================================
   ПОДВАЛ
   Фон --dark, от блока контактов отделён тонкой линией сверху.
   Ничего сверх двух строк: ни счётчиков, ни «сделано в», ни года.

   БЫЛО ТРИ, СТАЛО ДВЕ, 17.08.2026. Третьей строкой шла ссылка на политику
   обработки персональных данных. Убрана по решению клиента вместе с самой
   страницей: форм на сайте нет, счётчики решено не ставить, cookie
   не используются - собирать персональные данные нечем.
   Разметка подвала это колонка flex с gap 9px, поэтому удаление строки
   ничего не сдвинуло: колонка просто стала короче на строку и один зазор.
   ========================================================================== */

.footer {
  background: var(--dark);
  color: var(--cream);
  border-top: 1px solid rgba(216, 183, 150, 0.20);
  padding: 42px 0 48px;
}

.footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  text-align: center;
}

.footer__line {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
}

/* Первая строка подвала крупнее остальных двух, правка 16.08.2026.
   Клиент: «имя моё в подвале изменить на размер как телеграм, инстаграм,
   а то что-то уж совсем мелкие».

   «Как телеграм, инстаграм» - это подписи .contact__link в блоке контактов,
   у них 17px. Строка подвала шла 15px. Разница была 2px и на тёмном фоне
   почти не читалась как разница, поэтому строка и выглядела мелкой.

   Подняты ТОЛЬКО эти строки: она назвала одну строку и один ориентир.
   Вторая строка (город) осталась 15px намеренно - получилась лестница
   17/15, где имя питомника главное, а служебная строка тише. Если
   окажется, что «мелкие» относилось к обеим, правка на одну строку:
   снять этот селектор и поднять сам .footer__line.

   Лестница была 17/15/15 на трёх строках; третью, ссылку на политику,
   сняли 17.08.2026, разбор выше. */
.footer__line--name { font-size: 17px; }

/* .footer__link сейчас в разметке не используется: единственной ссылкой
   в подвале была политика обработки персональных данных, и её сняли
   17.08.2026. Правило оставлено намеренно, а не забыто: если на сайте
   появится форма или счётчик, страницу и ссылку придётся вернуть,
   и оформление должно найтись на месте, а не собираться заново. */
.footer__link {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  transition: color var(--ease);
}
.footer__link:hover { color: var(--gold-light); }

/* ── Кнопка «наверх» ──────────────────────────────────────────────────────
   Показывается после 600px прокрутки. Скрытое состояние сделано
   прозрачностью, а не display: none: элемент остаётся в раскладке,
   поэтому появление и уход плавные, а не рывком. pointer-events снят,
   чтобы невидимая кнопка не перехватывала клики по странице. */
.to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 55;            /* ниже шапки (60), выше содержимого */
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--terracotta);
  color: var(--surface);  /* светлая стрелка, контраст к заливке 4.04 при пороге 3 */
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity 200ms ease, transform 200ms ease, background-color 200ms ease;
  box-shadow: 0 6px 18px rgba(62, 47, 32, 0.28);
}
.to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.to-top svg {
  width: 22px;
  height: 22px;
  pointer-events: none;   /* клик всегда достаётся кнопке, а не значку */
}
.to-top:hover { background: var(--btn-bg-hover); }
/* Кольцо фокуса своё, не системное: на терракоте системное почти не видно.
   Два слоя - светлый вплотную к кнопке и тёмный снаружи, чтобы кольцо
   читалось и на светлой секции, и на тёмной. */
.to-top:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 6px var(--dark);
}

@media (max-width: 760px) {
  .to-top {
    right: 16px;
    bottom: 16px;
    width: 44px;
    height: 44px;
  }
  .to-top svg { width: 20px; height: 20px; }
}

/* Мгновенная прокрутка и никакого выезда, если пользователь просил
   убрать анимацию. Само поведение прокрутки переключается в скрипте. */
@media (prefers-reduced-motion: reduce) {
  .to-top { transform: none; transition: opacity 0.01ms; }
  .to-top.is-visible { transform: none; }
}

/* ==========================================================================
   ТЁМНАЯ ТЕМА БЛОКА
   Стоит после компонентных стилей сознательно: тема должна их перебивать.
   Раньше блок стоял выше, и .about с background: var(--bg) выигрывал
   по порядку следования, тёмный фон не появлялся вообще.
   Второй вариант оформления, ровно как на картинке клиента: тёмно-коричневый
   фон с градиентом, светлое золото в заголовке, золото потемнее в
   подзаголовках, кремовый основной текст. */

.theme-dark {
  background: linear-gradient(150deg, #2E241C 0%, #3E2F20 46%, #4A3828 100%);
  color: var(--cream);
}
.theme-dark .h-section { color: var(--gold-light); }
.theme-dark .h-sub     { color: var(--gold); }
.theme-dark .t-body,
.theme-dark .feature__text,
.theme-dark .note__text { color: var(--cream); }
.theme-dark .t-caption  { color: var(--gold); opacity: 0.72; }
.theme-dark .about__number { color: var(--gold-light); }
.theme-dark .about__label  { color: var(--gold); opacity: 0.8; }
.theme-dark .about__text   { color: var(--cream); }
.theme-dark { --deco: var(--gold); }

/* ── Б6, вариант 1: терракота в тёмных блоках ─────────────────────────────
   Клиент: «В подвале иконки и подчёркивания, и написать вам, сделать
   терракотовым цветом».

   Оттенок ОТДЕЛЬНЫЙ, --terracotta не тронута. Причина замерена: рабочая
   терракота #B0603F на тёмном фоне даёт 2.81 при пороге 3 для графики,
   на цвете шапки 2.40. То есть на тёмном она просто не читается.
   Осветлённая #C8785A берёт порог, а в светлых блоках терракота остаётся
   прежней - кнопки и подчёркивание меню не трогаются вовсе.

   Переменная объявлена внутри .theme-dark: она нужна только там,
   и в светлые блоки не протекает. */
.theme-dark { --terracotta-on-dark: #C8785A; }
.theme-dark .h-section     { color: var(--terracotta-on-dark); }
.theme-dark .contact__icon { color: var(--terracotta-on-dark); }
.theme-dark .icon-circle {
  border-color: var(--terracotta-on-dark);
  color: var(--terracotta-on-dark);
}
.theme-dark .contact__link { text-decoration-color: var(--terracotta-on-dark); }
/* Подвал не .theme-dark, у него своя заливка --dark, поэтому цвет здесь
   числом. Тот же #C8785A. */
.footer__link { text-decoration-color: #C8785A; }


/* ==========================================================================
   Адаптив. Три состояния: до 760, 761-1100, от 1101 и выше.
   ========================================================================== */

/* Название в шапке видно всегда, на всех ширинах.
   Прежде оно пряталось на двух полосах - до 760 и от 1101 - и появлялось
   только после прокрутки. Правило снято пятым кругом: клиент попросила
   вернуть название в шапку и показывать постоянно. Опасение прошлого
   круга («две подписи подряд читаются как ошибка») снято кеглем: в шапке
   18px, на первом экране 34-64px, и они разнесены по горизонтали -
   название шапки слева от меню, название первого экрана ниже. */

/* ── Среднее состояние: 761-1100 ─────────────────────────────────────────── */
@media (max-width: 1100px) {
  /* Было 100px. Ужато на четверть, как и полоса на компьютере. */
  :root { --head-h: 76px; }

  .header__inner { gap: 0 16px; padding: 6px 20px; }
  .brand__name { font-size: 17px; }
  /* Кегль подписи здесь больше не переопределяется: 12px на всех ширинах,
     см. базовое правило. Разрядка остаётся своя. */
  .brand__sub { letter-spacing: 0.04em; }
  .header__phone { font-size: 16px; }
  .circle { width: 34px; height: 34px; }
  .circle svg { width: 17px; height: 17px; }

  .wrap { padding: 0 20px; }

  .about { padding: 76px 0; }
  .about__grid { gap: 40px; }
}

/* Полоса 761-1100. Девять пунктов меню не встают в один ряд рядом с
   названием, телефоном и кнопками, поэтому меню переносим на вторую строку
   шапки. Телефон и обе кнопки при этом остаются на виду. */
@media (min-width: 761px) and (max-width: 1100px) {
  .header__inner { flex-wrap: wrap; align-content: center; }
  .brand { order: 1; }
  .header__side { order: 2; margin-left: auto; }
  .nav { order: 3; flex: 0 0 100%; justify-content: center; }
  .nav__list { gap: 17px; }
  .nav__link { font-size: 14px; padding: 2px 0; }
}

/* Полоса 1101-1340. Всё встаёт в один ряд, но шаг меню и телефон приходится
   уменьшить, иначе правый блок выходит за границу полезной ширины.
   Название в шапке теперь стоит здесь постоянно и тоже занимает место,
   поэтому кегли ужаты сильнее прежнего. Левое поле на этих ширинах самое
   узкое, отсюда и меньший отступ текстовой колонки слева. */
/* Полоса 1101-1749: в текстовую колонку такой ширины две кнопки рядом
   не встают - им нужно 520px, а колонка даёт 321-545. Поэтому там они
   идут одна под другой. Ширина при этом всё та же, по самой широкой
   из них: поток сетки становится строчным, дорожка остаётся одна.
   Порог считан: две кнопки помещаются с 1735px, взято 1750 с запасом
   на случай более длинного текста кнопки из админки. Восьмым кругом
   порог опущен с 1850: срез справа вернул колонке ширину. */
@media (min-width: 1101px) and (max-width: 1749px) {
  .hero__actions { grid-auto-flow: row; }
}

/* От 1777px фотография упирается в собственные 853px по высоте и перестаёт
   расти, а колонка с этого места растёт быстрее окна. Держать здесь долю
   колонки нельзя: на 2560 название вышло бы 189px вместо нынешних 118.7,
   то есть первый экран пришлось бы пересогласовывать заново. Поэтому выше
   этой границы возвращается прежняя формула от ширины окна - она держит
   долю ОКНА, а не колонки, как и было задумано восьмым кругом.

   Граница 1777 не на глаз: 48vw = 853px ровно при 1777px. В этой точке обе
   формулы дают один и тот же кегль 78.41px, перехода не видно. */
@media (min-width: 1777px) {
  .hero__name { --hero-name-fs: clamp(30px, calc(5.144vw - 13.0px), 130px); }
}

@media (min-width: 1101px) and (max-width: 1340px) {
  /* Кегля названия здесь больше нет: перепад --hero-pad-l с 44 на 32px
     теперь целиком учитывается формулой 14.127cqw, потому что она считает
     от контентной ширины колонки, а поле входит в неё автоматически.
     Прежняя вторая формула на vw убрана девятым кругом. */

  .nav__list { gap: 10px; }
  .nav__link { font-size: 13px; }
  .header__phone { font-size: 14px; }
  .brand__name { font-size: 16px; }
  /* Кегль подписи здесь больше не переопределяется, см. базовое правило. */
  .brand__sub { letter-spacing: 0.04em; }
  .circle { width: 32px; height: 32px; }
  .circle svg { width: 16px; height: 16px; }

  :root { --hero-pad-l: 32px; }
}

/* ── Планшет и телефон: до 1100 ───────────────────────────────────────────
   Фотография сверху, текст под ней на светлом фоне. Так до 1100, а не до 760,
   как было раньше. Причина замерена: при 768 кадр всего 768 на 512, текстовый
   блок занимает по высоте больше половины, и осветление, достаточное для
   тёмного текста, неизбежно наползает на морду кошки (55% осветления на
   морде) либо кнопка остаётся на неосветлённом тёмном участке и даёт 2.9:1.
   Под фотографией текст лежит на --bg и читается с запасом без всяких
   подложек, а кадр остаётся нетронутым. */
@media (max-width: 1100px) {
  .hero__copy { padding: 30px 20px 38px; }
  .hero__name { --hero-name-fs: clamp(34px, 5.4vw, 56px); }
  .hero__tagline { font-size: clamp(15px, 1.9vw, 19px); }
}

@media (min-width: 561px) and (max-width: 1100px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
  .perks { grid-template-columns: repeat(4, 1fr); }
}

/* Полоса 571-1100: тот же срез 60 столбцов, что и на компьютере. В этой
   полосе фотография показывалась целиком, от нулевого столбца, и левый
   край кадра приходился ровно на угол пуфа. Теперь между границей кадра
   и пуфом остаётся та же полоса тёмной стены, что и на широких экранах.
   По вертикали не режется ничего: коробка уже исходника по пропорции,
   значит масштаб задаёт высота, уши и лапы входят целиком.
   На 768 высота кадра 537px (была 512 при полном кадре и 570 при срезе
   130 шестого круга). */
@media (min-width: 571px) and (max-width: 1100px) {
  .hero__media { aspect-ratio: 1220 / 853; }
  .hero__media img { object-position: 100% 50%; }
}

/* ── Телефон: до 760 ─────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  /* 56px. Внутри помещаются и бургер (42px), и вернувшееся название:
     16px плюс подпись 9px это 30px по высоте. */
  :root { --head-h: 56px; }

  .header__phone { display: none; }

  body { font-size: 16px; }

  .nav { display: none; }
  .header__side { margin-left: auto; }
  .header__side .circle { display: none; }
  .burger { display: block; }
  .brand__name { font-size: 16px; }

  .wrap { padding: 0 18px; }

  .hero__copy { padding: 26px 18px 34px; }
  .hero__name { --hero-name-fs: clamp(30px, 8.6vw, 44px); }
  .hero__tagline { margin-top: 14px; font-size: 13px; }
  .hero__eyebrow { margin-top: 18px; letter-spacing: 0.18em; font-size: 12px; }
  .hero__text { margin-top: 16px; font-size: 15px; }
  .hero__actions { margin-top: 22px; }

  .about { padding: 56px 0; }
  .about__grid { grid-template-columns: 1fr; gap: 26px; }
  .about__label { max-width: none; }

  /* Порядок блока на телефоне: число, заголовок с текстом, фотография.
     Колонка года раскрывается в поток сетки, поэтому её содержимое
     можно переставить относительно текстовой колонки - иначе фотография
     встала бы ПЕРЕД заголовком «О ПИТОМНИКЕ», и заголовок раздела
     оказался бы третьим элементом сверху.

     Если display: contents браузер не поддержит, раскладка вернётся
     к прежнему порядку - это рабочее состояние, а не поломка. */
  .about__year { display: contents; }
  .about__year-head { order: 1; }
  .about__body { order: 2; }
  /* Ширина остаётся по колонке, то есть во весь экран за полями: 354x443
     на 390. Пробовал ограничить 260px ради честного 2x - на снимке видно,
     что так фотография перестаёт держать левый и правый край блока
     и читается как случайно забытая картинка, а не как часть колонки.
     Сравнение трёх вариантов снято, разбор в README.
     Свой отступ сверху снят: на телефоне колонка раскрыта в поток сетки,
     и расстояние до рамки с выделенной мыслью задаёт gap самой сетки,
     26px. Оставь margin - отступ сложился бы вдвое. */
  .about__photo { order: 3; margin-top: 0; }

  /* карточки и полоса преимуществ на телефоне */
  .cards { grid-template-columns: 1fr; gap: 20px; }
  .perks { grid-template-columns: repeat(2, 1fr); gap: 22px; }
  .sec-head__over::before, .sec-head__over::after { width: 32px; }

  /* декоративный набор на телефоне: кружки меньше.
     Ширину разделителя не задаём: он и так по ширине колонки. */
  .feature { gap: 14px; }
  .icon-circle { width: 48px; height: 48px; }
  .icon-circle .icon { width: 22px; height: 22px; }
  .icon-circle--sm { width: 40px; height: 40px; }
  .note { gap: 14px; padding: 16px 18px; }
  .features { gap: 22px; }
  .about__features { margin-top: 28px; }
  .about__note { margin-top: 24px; }
}

/* ── Телефон, кадр по фиксированной высоте: до 570 ───────────────────────────
   Пропорция кадра давала на телефоне слишком низкий блок, кошка получалась
   мелкой, а левая половина кадра пустой стеной. Здесь высота фиксированная,
   а кадр режется по бокам: так кошка крупнее, и по бокам резать не жалко.

   По вертикали не режем ни на пиксель. При фиксированной высоте масштаб
   задаёт именно высота, поэтому в кадр всегда попадает вся высота
   исходника: и уши сверху, и пуф снизу.

   Высота 324, было 380. Разница ушла в полосу шапки: кадр теперь начинается
   под ней, а не от верха окна, иначе меню срезает кошке уши. Общая высота
   первого экрана от этого не изменилась ни на пиксель, 56 + 324 = 380,
   поэтому кнопки внизу стоят там же, где стояли.

   Кошка с хвостом занимает 733px ширины исходника из 1280.
   Видно при высоте H на экране шириной W ровно W * 853 / H:
     380 -> на 360px видно 808px;
     324 -> видно 948px, кошка с хвостом входит с запасом 107px слева
            и 108px справа, то есть режется только пустая стена.

   Порог 570px оставлен прежним: он считался от 380px и означает ширину,
   с которой высота по пропорции перестаёт быть меньше заданной.

   aspect-ratio обязательно гасим: вместе с заданной высотой он растягивает
   блок ещё и по ширине и блок вылезает за экран. */
@media (max-width: 570px) {
  .hero__media {
    aspect-ratio: auto;
    height: 324px;
  }

  /* 57%: кошка с хвостом занимает x=305..1038 из 1280, её середина 671,
     а не 640. Сдвиг вправо ставит кошку в центр видимой части кадра. */
  .hero__media img { object-position: 57% center; }
}

/* Узкие Android-телефоны: до 370.
   Высота кадра 284 вместо 324, то есть прежние 340 минус полоса шапки,
   плюс подрезанные отступы текста. Вместе это отыгрывает те пиксели,
   из-за которых вторая кнопка уходила за нижний край на 360x800.
   Граница 370, чтобы не задеть 390x844. */
@media (max-width: 370px) {
  .hero__media { height: 284px; }

  .hero__copy { padding-top: 22px; padding-bottom: 22px; }
  .hero__name { --hero-name-fs: clamp(28px, 8.4vw, 36px); }
  .hero__tagline { margin-top: 12px; font-size: 13px; }
  .hero__eyebrow { margin-top: 15px; }
  .hero__text { margin-top: 13px; font-size: 14px; }
  .hero__actions { margin-top: 18px; gap: 11px; }
}

/* Совсем узкие телефоны.

   Здесь стояло `.brand__sub { display: none }` - подпись пряталась ниже
   380px. Правило снято 16.08.2026 вместе с подъёмом кегля до 12px:
   клиент пожаловалась, что подпись мелкая, а на маленьком телефоне она
   не видела её вовсе. Замер: при 12px на 320px блок названия 215.1,
   правый край 235.1, бургер на 258 - зазор 22.9px при пороге 16,
   подпись в одну строку (scrollWidth 164 = clientWidth 164),
   переполнения нет, высота шапки те же 56px.

   Обратно не прятать: условие задания - подпись видна на всех ширинах. */

/* ── Адаптив новых блоков главной ─────────────────────────────────────────
   Те же три полосы, что и у всего остального: до 760, 761-1100, от 1101.
   Сетки карточек и полосы преимуществ переключаются правилами выше,
   здесь только обвязка разделов. */

@media (max-width: 1100px) {
  .kittens,
  .perks-sec,
  .moving,
  .reviews,
  .articles,
  .gallery-sec,
  .contacts { padding: 76px 0; }

  /* Четыре колонки при полезной ширине 1060 дают карточке 250px:
     в неё не встаёт ни заголовок статьи, ни анонс. */
  .articles__list { grid-template-columns: repeat(2, 1fr); }

  /* Отзывы в две колонки вместо трёх, как карточки котят на этой же полосе.
     Правка 14.08.2026 вместе с А5. На 768 три колонки давали карточку
     в 220px, то есть около 25 знаков в строке: короткий отзыв
     разворачивался на 10 строк, и кнопка «Читать дальше» появлялась
     у всех трёх карточек, хотя клиент просила её только у длинного.
     В двух колонках карточка 343px, примерно как на 1101. */
  .reviews__list { grid-template-columns: repeat(2, 1fr); }

  /* сетка карточек тут двухколоночная, значит и одиночная колонка другая */
}

@media (max-width: 760px) {
  .kittens,
  .perks-sec,
  .moving,
  .reviews,
  .articles,
  .gallery-sec,
  .contacts { padding: 56px 0; }

  .reviews__list,
  .articles__list,
  .contacts__list { grid-template-columns: 1fr; }
  .contacts__list { width: 100%; }

  .kittens__actions { margin-top: 34px; }

  .review { padding: 22px 20px 24px; }
  .art__link { padding: 22px 18px 24px; }

  .gallery__item img { height: 180px; }
  .gallery__row { gap: 10px; padding-right: 10px; }

  /* Нижний отступ увеличен с 38 до 92px под кнопку «наверх». Она висит
     фиксированно в правом нижнем углу (44px плюс отступ 16px) и на 390
     накрывала хвост ссылки «Политика обработки персональных данных»:
     ссылка по центру занимает 340px из 390, её правый край на 365,
     а левый край кнопки на 330. Автопроверка по центру кнопки это
     пропустила, увидено глазами на скриншоте. Отступ уводит последнюю
     строку выше зоны кнопки. */
  .footer { padding: 34px 0 92px; }
}

/* Две кнопки под карточками требуют около 520px. Порог взят с запасом
   на более длинный текст кнопки из админки. */
@media (max-width: 620px) {
  .kittens__actions {
    grid-auto-flow: row;
    width: 100%;
  }
}

/* Лента на телефоне: статическая полоса, листается пальцем.
   Непрерывная анимация transform и жест несовместимы - пока идёт
   трансформация, прокрутка ловится рывками. Поэтому на телефоне
   лента не едет, а листается, и дубликат-ряд скрыт: иначе человек
   пролистает одно и то же дважды. */
@media (max-width: 760px) {
  .gallery {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-inline: 18px;
  }
  .gallery__track {
    animation: none;
    width: max-content;
  }
  .gallery__row[aria-hidden='true'] { display: none; }
  .gallery__item { scroll-snap-align: start; }
}

/* Уважаем системную настройку «меньше движения».
   Лента при этом не просто замирает, а становится обычной полосой
   с прокруткой и прилипанием: замершая наполовину петля читалась бы
   как обрезанная вёрстка. */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; }

  .gallery {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
  }
  .gallery__track {
    animation: none !important;
    width: max-content;
  }
  .gallery__row[aria-hidden='true'] { display: none; }
  .gallery__item { scroll-snap-align: start; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ВНУТРЕННИЕ СТРАНИЦЫ РАЗДЕЛОВ: коты, кошки, котята
   Круг от 15.08.2026. Блок стоит последним в файле сознательно: здесь есть
   правила, которые обязаны перебивать общие (.cats .cards поверх .cards),
   а порядок в каскаде тут единственный источник приоритета - специфичность
   у них одинаковая.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Шапка внутренней страницы ────────────────────────────────────────────
   Большой фотографии здесь нет и не будет: в архиве нет ни одного широкого
   кадра выше 700px, а растягивать в этом проекте запрещено. Вместо неё
   компактная шапка на --bg из уже собранных частей - .sec-head, .h-section,
   .divider--center, .sec-head__note.

   Отступ сверху обязателен. У body своего padding-top нет, под фиксированную
   шапку подставляется только .hero (styles.css:1048), и без этого правила
   заголовок раздела уехал бы под шапку. Высота шапки берётся переменной,
   поэтому по брейкпоинтам пересчитывать нечего: 58 / 76 / 56. */
.page-head {
  background: var(--bg);
  padding: calc(var(--head-h) + 56px) 0 56px;
}
.page-head .sec-head__note { max-width: 58ch; }

/* ── Фото-шапки страниц котят СНЯТЫ 16.08.2026 ────────────────────────────
   Здесь стоял модификатор .page-head--photo: фотография во всю высоту
   шапки, прижатая к правому краю окна, плюс .page-head__media--cap -
   потолок ширины кадра под крой 2.12. Обе страницы котят его носили.

   Снято по решению клиента: она посмотрела шапки вживую и отказалась
   от фотографий в них на обеих страницах. Правила удалены целиком,
   а не оставлены про запас: разметка их больше не использует нигде,
   а мёртвый модификатор в файле на 4800 строк - это то, что через круг
   начнут копировать как рабочий образец.

   Обе страницы вернулись к базовому .page-head выше: фон --bg, отступ
   calc(var(--head-h) + 56px) сверху и 56px снизу. Замер после снятия -
   в отчёте круга.

   ДОПОЛНЕНО 17.08.2026: КОНТАКТАМ БОЛЬШАЯ ШАПКА НЕ НУЖНА ЭТИМ ПУТЁМ.
   В тот день клиент попросила «шапку как на главной» для kontakty.html.
   Первая версия круга вернула этот же модификатор для одной страницы
   контактов и написала здесь «ВЕРНУТА 17.08.2026, ТОЛЬКО КОНТАКТЫ» -
   постановка была неверной, клиент попросила не отдельную фото-шапку,
   а переиспользование готового .hero с главной, тем же файлом кадра.
   Правки откачены, .page-head--photo снова нигде не стоит.
   Урок остаётся в силе на будущее, если модификатор понадобится
   для чего-то ещё: порог боковой раскладки у него был 1101, а рабочая
   ширина заказчика 1100 - на ней конструкция без правки порога
   работает не как раскладка «фото сбоку», а как раскладка «фото сверху».

   ГДЕ ВЗЯТЬ ОБРАТНО, если понадобится: правила лежат в
   zhanna-violaalba/backup-krug-20260816-210324.zip и в любом коммите
   panflow-site до этого круга. Кадры - в 03-сайт/_prev-assets/page-head/,
   сборщик - tools/build-page-head-photos.py, он не тронут. */

/* ── Разделы взрослых животных ───────────────────────────────────────────
   Фон --surface против --bg у шапки страницы: два одинаковых фона подряд
   на этом сайте не ставим, правило круга от 13.08. Карточка внутри
   переводится на --bg тем же приёмом, что в .kittens и .articles, иначе
   она сливается с секцией и отношение фонов падает до 1.00.

   Песочный вид карточки котёнка (--sand-bg) сюда НЕ переносится
   и это осознанно: взрослые животные не продаются, у них нет ни бейджа,
   ни цены, и карточка должна читаться иначе. Здесь обычный вид: --surface
   у тела карточки, имя --gold-deep, замеренный контраст 5.13. */
/* Отступ сверху 40, а не 76. Замер до правки: от низа .page-head до первого
   ряда карточек было 110px (76 у секции плюс 34 у сетки) на всех ширинах.
   На странице котов, где карточек три и текста мало, это читалось как провал
   между двумя разными экранами. Стало 40 + 26 = 66px на компьютере и
   22 + 20 = 42px на телефоне. Низ секции не трогаем: там граница с подвалом,
   и воздух перед ней нужен. */
.cats,
.queens { background: var(--surface); padding: 40px 0 76px; }
.cats .cards,
.queens .cards { margin-top: 26px; }
.cats .card,
.queens .card { background: var(--bg); }

/* Полоса миниатюр прижата к низу карточки.

   Третий заход по высоте ряда, первые два записаны в README. Растягивание
   по самой высокой давало дыру под текстом у карточки без миниатюр;
   align-items: start убрал дыру, но развалил ряд по нижнему краю - разброс
   доходил до 115px на котах.

   Здесь карточки снова одной высоты, а свободное место уходит НАД полосой
   миниатюр, а не под весь текст: полоса стоит внизу у всех, и нижние края
   в ряду совпадают. У Джонатана, у которого миниатюр нет вовсе, воздух
   остаётся внизу карточки и читается как место под будущие снимки.

   Работает потому, что .card__body это flex-колонка с flex: 1 1 auto:
   margin-top: auto у последнего элемента съедает весь свободный остаток. */
.cats .photos,
.queens .photos { margin-top: auto; padding-top: 16px; }

/* Имя взрослого животного мельче, чем у котёнка. У котят подпись короткая,
   «Котёнок 1», а здесь полная кличка латиницей: самая длинная,
   BENNVOYAGEE KATCHOO OF VIOLA ALBA, при кегле карточки котёнка вставала
   в четыре строки и ломала ритм ряда. */
.cats .card__name,
.queens .card__name { font-size: clamp(17px, 1.35vw, 21px); }

/* Строки характеристик прижимаются к верху, а не центрируются: у строки
   окраса под значением идёт вторая строка с латинским кодом, и при
   align-items: center метка «Окрас:» уезжала бы в середину двухстрочного
   блока, то есть ниже своего значения. Правило пережило снятие значков
   и остаётся нужным: теперь оно держит по верху метку, а не значок.
   Парного .spec__icon { margin-top: 3px } больше нет - выравнивать нечего. */
.cats .spec,
.queens .spec { align-items: flex-start; }

/* Латинский код окраса. Техническая приписка рядом с русским названием:
   на сайте окрас пишется по-русски, это требование клиента, а код нужен
   тем, кто читает родословные. Цвет --muted на --bg даёт 5.25 при пороге
   4.5 - меряется наравне с остальным текстом, а не как декор. */
.cats__code {
  display: block;
  margin-top: 1px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--muted);
}

/* ── Якоря карточек ──────────────────────────────────────────────────────
   На эти id следующим этапом лягут 301 с семи старых детальных адресов
   и с 61 адреса галерей. У html уже стоит scroll-padding-top: var(--head-h),
   то есть высота шапки учтена; здесь добавляется только зазор, чтобы верх
   карточки не касался нижнего края шапки вплотную. Итог: карточка встаёт
   на 24px ниже шапки на всех трёх полосах. */
.card[id] { scroll-margin-top: 24px; }

/* ── Полоса миниатюр в карточке ──────────────────────────────────────────
   Компонент, а не часть раздела: одна и та же полоса работает у котов,
   кошек и котят, поэтому имя без приставки раздела, как у .card и .badge.

   max-width 466px не косметика, а ограничение по разрешению. Полоса
   трёхколоночная, зазор 8px, значит самая крупная миниатюра выходит
   (466 - 16) / 3 = 150.0px - ровно натуральный размер файла миниатюры.
   Без ограничения на широкой карточке (в полосе 561-760 карточка доходит
   до 724px) миниатюра показывалась бы крупнее натурального размера. */
.photos {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  max-width: 466px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.photos__item {
  position: relative;
  display: block;
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface);
  transition: transform var(--ease);
}
.photos__item:hover { transform: translateY(-2px); }
.photos__item:focus-visible {
  outline: 2px solid var(--gold-deep);
  outline-offset: 2px;
}
.photos__item img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center top;
}

/* Счётчик остатка на последней видимой миниатюре. Полоса обрезается шестью
   кадрами: у Ванессы их двадцать, у Джонатана один, и без обрезки карточки
   в одном ряду растянулись бы по самой высокой, оставив соседние пустыми.
   Прячет лишние и ставит этот счётчик скрипт, поэтому без JS видны все
   миниатюры - деградация в сторону большего, а не меньшего. */
.photos__item--more::after {
  content: attr(data-more);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(43, 33, 26, 0.72);
  color: #F7F0E5;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.02em;
}
.photos__item[hidden] { display: none; }

/* ── Просмотр кадра поверх страницы ──────────────────────────────────────
   Разметку целиком строит скрипт, в html её нет: без JS на странице
   не должно остаться ни мёртвого окна, ни мёртвых кнопок, а миниатюры
   остаются обычными ссылками на файлы и работают сами по себе. */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 90;                 /* выше шапки (60) и мобильной панели (70) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 22px 16px;
  background: rgba(30, 22, 16, 0.92);
  animation: viewer-in 180ms ease;
}
@keyframes viewer-in { from { opacity: 0 } to { opacity: 1 } }

/* Кадр НИКОГДА не растягивается выше натурального размера. Исходники здесь
   от 579 до 700px по длинной стороне, и апскейл в этом проекте запрещён
   без оговорок. Ключевое - width: auto: с width: 100% кадр растянуло бы
   на всю ширину окна. max-width и max-height только ограничивают сверху. */
.viewer__img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(100vh - 150px);
  border-radius: 6px;
  background: var(--dark);
}
.viewer__caption {
  margin: 0;
  max-width: 60ch;
  text-align: center;
  font-size: 14px;
  line-height: 1.5;
  color: var(--cream);
}
.viewer__count {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  color: var(--gold);
}
/* Заметность кнопок листания на ЛЮБОМ кадре, круг от 15.08.2026.

   На узких экранах кадр показывается почти во всю ширину просмотра
   (padding у .viewer 12px), и кнопки на 8px от края встают ПРЯМО НА ФОТО,
   не на тёмную подложку - замерено на 46 живых кадрах трёх животных.
   Крайние фоны, какие реально нашлись: почти чёрная тень в траве у Валета
   (0,12,7) и светлая стена у Пресли (204,205,209). Прежняя заливка
   rgba(43,33,26,0.68) давала кнопке контраст к соседнему кадру 1.03-1.68
   на тёмных участках и 4.39 на светлых - на тёмном кнопка тонула.

   Один приём здесь не решает оба крайних случая сразу: у тёмного угла
   и светлого угла разница в светлоте, а не в цвете, и симметричная деталь
   одного тона не может выделиться из обоих сразу. Поэтому решают ДВЕ
   разные детали:
     - тёмная плотная заливка спорит со светлым кадром;
     - светлая непрозрачная обводка спорит с тёмным кадром;
     - тень под кнопкой держит контур там, где заливка и обводка обе
       близки по светлоте к фону - типовой приём для плавающих кнопок
       поверх произвольного изображения.
   Подобрано симуляцией альфа-смешения по обоим крайним фонам, проверено
   реальным рендером - замеры в README. */
.viewer__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1.5px solid rgba(232, 192, 147, 0.88);
  border-radius: 50%;
  background: rgba(20, 15, 11, 0.90);
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(0, 0, 0, 0.16);
  color: var(--gold-light);
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease), box-shadow var(--ease);
}
.viewer__btn:hover { background: var(--terracotta); border-color: var(--terracotta); }
.viewer__btn:focus-visible { outline: 2px solid var(--gold-light); outline-offset: 3px; }
.viewer__btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.2; }
.viewer__prev { left: 14px; }
.viewer__next { right: 14px; }
.viewer__close {
  position: absolute;
  top: 14px;
  right: 14px;
  transform: none;
}

/* Блокировка фона своим классом, а не menu-open. У menu-open стоит голый
   overflow: hidden без компенсации полосы прокрутки: до 760px полоса
   наложенная и сдвига нет, а просмотр открывается и на компьютере, где
   исчезновение полосы дёрнуло бы всю страницу вбок. Ширину полосы считает
   скрипт и кладёт в --sbw. */
body.viewer-open {
  overflow: hidden;
  padding-right: var(--sbw, 0px);
}

@media (prefers-reduced-motion: reduce) {
  .viewer { animation: none; }
  .photos__item { transition: none; }
  .photos__item:hover { transform: none; }
}

/* ── Ширина карточки на узких полосах ────────────────────────────────────
   ВРЕМЕННОЕ РАСХОЖДЕНИЕ С ГЛАВНОЙ, зафиксировано в README.

   В полосе до 760px сетка одноколоночная, и карточка растёт до 724px при
   окне 760. Кадры взрослых животных 463-611px по стороне, то есть без
   ограничения они показывались бы там крупнее натурального размера.
   Ограничение стоит ТОЛЬКО на новых разделах: главную и страницу котят
   клиент уже согласовала, и разъезжаться с принятой вёрсткой без её слова
   нельзя. Как свести обратно одной правкой: снять эти два блока и добавить
   max-width карточке в общем @media (max-width: 760px) - тогда правило
   станет общим для всех страниц сразу.

   460px, а не 463: ровно натуральный размер самого мелкого кадра
   (passion 463) минус запас на округление субпиксельной сетки. */
@media (min-width: 761px) and (max-width: 1100px) {
  /* Две колонки по 460 плюс зазор 26. Ниже 972px окна ограничение
     не срабатывает вовсе: карточка и так уже 460. */
  .cats .cards,
  .queens .cards { max-width: 946px; margin-inline: auto; }
}
@media (max-width: 760px) {
  .cats .cards,
  .queens .cards { max-width: 460px; margin-inline: auto; }
}

@media (max-width: 1100px) {
  .page-head { padding: calc(var(--head-h) + 44px) 0 44px; }
}
@media (max-width: 760px) {
  .page-head { padding: calc(var(--head-h) + 32px) 0 32px; }
  /* 22 + 20 = 42px от шапки страницы до карточек, было 110. */
  .cats,
  .queens { padding: 22px 0 56px; }
  .cats .cards,
  .queens .cards { margin-top: 20px; }
  .photos { gap: 6px; }
  .viewer { padding: 16px 12px; }
  .viewer__img { max-height: calc(100vh - 170px); }
  .viewer__btn { width: 42px; height: 42px; }
  .viewer__prev { left: 8px; }
  .viewer__next { right: 8px; }
}

/* Атрибут hidden сам по себе тут не работает: у .viewer стоит display: flex,
   у кнопок display: grid, и оба перебивают display: none из стилей браузера.
   Без этих двух правил закрытое окно осталось бы на экране. */
.viewer[hidden] { display: none; }
.viewer__btn[hidden] { display: none; }

/* Своего символа «влево» и «вправо» в спрайте нет, и заводить два новых
   ради поворота на 90 градусов незачем: берём стрелку вверх и поворачиваем. */
.viewer__prev svg { transform: rotate(-90deg); }
.viewer__next svg { transform: rotate(90deg); }

/* Здесь стояло `.cats .cards, .queens .cards { align-items: start }` -
   второй заход по высоте ряда. Он убирал дыру под текстом, но разваливал
   ряд по нижнему краю: замер дал разброс 115px на котах и 134.9px на 1440.
   Снято и заменено прижатием полосы миниатюр к низу карточки, см. правило
   `.cats .photos { margin-top: auto }` выше. Обратно не возвращать. */

/* Страница котят: тот же отступ от шапки страницы до карточек, что у котов
   и кошек. Модификатор нужен потому, что секция .kittens общая с главной,
   где над ней стоит блок «О питомнике», а не .page-head. Замер: было 110px
   (76 у секции плюс 34 у сетки), стало 40 + 26 = 66px, на телефоне 42px. */
.kittens--page { padding-top: 40px; }
.kittens--page .cards { margin-top: 26px; }
@media (max-width: 760px) {
  .kittens--page { padding-top: 22px; }
  .kittens--page .cards { margin-top: 20px; }
}

/* ── Карточка животного без фотографии ───────────────────────────────────
   Решение клиента от 15.08.2026: «Публикуйте этих 4. Сделайте ещё на двух,
   пока их фото нет». Клички и окрас двух новых кошек она не прислала,
   поэтому сегодня сделана МЕХАНИКА, а сами карточки не поставлены: пустых
   карточек с подписью «имя уточняется» на сайте не будет.

   Приём взят у карточек статей: там фотографий нет вовсе, и вместо кадра
   стоит контурный значок в кружке. Коробка той же пропорции 1:1, что
   и у карточки с фотографией, поэтому в ряду ничего не разъезжается.

   Значок - лапка, фирменный знак проекта из разделителей. Она ЗАЛИВНАЯ,
   а не контурная (README, «Лапка: срисована с референса»), поэтому общий
   класс .icon с его fill: none здесь перекрывается: иначе символ
   не нарисуется вовсе. */
.card__media--empty {
  display: grid;
  place-items: center;
  background: var(--surface);
  border-bottom: 1px solid rgba(62, 47, 32, 0.10);
}
.card__media--empty .icon-circle { width: 84px; height: 84px; }
.card__media--empty .icon {
  width: 36px;
  height: 36px;
  fill: currentColor;
  stroke: none;
}
/* Карточка стоит на --bg, значит коробка значка на --surface читается
   как отдельный слой. В тёмной теме наоборот. */
.theme-dark .card__media--empty { background: rgba(20, 15, 11, 0.34); }
@media (max-width: 760px) {
  .card__media--empty .icon-circle { width: 72px; height: 72px; }
  .card__media--empty .icon { width: 30px; height: 30px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   РАЗДЕЛЫ «ВЫПУСКНИКИ» И «ВЫСТАВКИ»
   Круг от 16.08.2026. Блок стоит последним в файле по той же причине, что
   и предыдущий: здесь есть правила, которые обязаны перебивать общие
   (.photos--grid поверх .photos), а специфичность у них одинаковая
   и порядок в каскаде тут единственный источник приоритета.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Сетка фотографий раздела ─────────────────────────────────────────────
   Это тот же компонент .photos, что стоит в карточке животного, плюс
   модификатор. Так сделано не ради экономии строк: просмотр фотографий
   (script.js, модуль 6) цепляется именно к классу .photos, и своя сетка
   с другим именем осталась бы без просмотра.

   Что модификатор переопределяет и почему:
     max-width  у полосы в карточке стоит 466px - ограничение по разрешению
                миниатюры 150px. Здесь плитка 463px, ограничитель не нужен;
     колонки    полоса трёхколоночная, сетке нужно 4/2/2;
     потолок ячейки 463px - это ровно квадрат девяти самых мелких кадров
                (исходники 700x463). Без него в полосе двух колонок ячейка
                доходит до (1100 - 2*20 - 26) / 2 = 517px, и эти девять
                показывались бы крупнее натурального размера.

   ВАЖНО ПРО ОБРЕЗКУ. Полосе в карточке скрипт оставляет три миниатюры
   и вешает счётчик «+N». Сетке раздела это смертельно: она и есть весь
   раздел. Поэтому в разметке у неё стоит data-max="0" - порог, который
   модуль читает с 16.08.2026. Без атрибута сетка схлопнется до трёх.

   Выравнивание по левому краю, не по центру: у выпускников 14 кадров,
   последний ряд из двух. По центру эти два повисли бы посреди пустого
   ряда, по левому краю ряд читается как обычное продолжение сетки. */
.photos--grid {
  max-width: none;
  margin-top: 0;
  grid-template-columns: repeat(4, minmax(0, 463px));
  justify-content: start;
  gap: 26px;
}

/* Плитка сетки крупная, скругление полосы (6px) на ней смотрится как
   случайность. Берём радиус карточки. */
.photos--grid .photos__item { border-radius: 10px; }

@media (max-width: 1100px) {
  .photos--grid { grid-template-columns: repeat(2, minmax(0, 463px)); gap: 22px; }
}
@media (max-width: 760px) {
  .photos--grid { gap: 14px; }
}

/* ── Раздел «Выпускники» ──────────────────────────────────────────────────
   Фон --surface против --bg у .page-head: два одинаковых фона подряд
   на этом сайте считаются дефектом, правило круга от 13.08.

   Отступ сверху 40px, как у .kittens--page: он подобран замером на круге
   от 15.08 и даёт 66px до сетки вместе с её margin-top. Здесь margin-top
   у сетки снят (см. .photos--grid), поэтому 66 стоят прямо тут. */
.grads {
  background: var(--surface);
  padding: 66px 0 76px;
}

/* ── Раздел «Выставки» ────────────────────────────────────────────────────
   Тот же фон и тот же отступ, что у выпускников. */
.shows {
  background: var(--surface);
  padding: 66px 0 76px;
}

/* Год. Якорь, на который лягут 301 с шести старых адресов
   /nashi-pobedy/novosti-*.html.

   ЗАЗОР 24px, А НЕ var(--head-h). У html уже стоит
   scroll-padding-top: var(--head-h) (styles.css выше), то есть высота
   шапки в переходе по якорю УЖЕ учтена. Добавить сюда ещё --head-h
   значило бы отсчитать её дважды и уронить заголовок года на 116px ниже
   шапки. Здесь добавляется только зазор, чтобы верх секции не касался
   нижнего края шапки вплотную - ровно как у .card[id]. */
.shows__year[id] { scroll-margin-top: 24px; }

.shows__year + .shows__year { margin-top: 58px; }

/* Число года крупное, но тише заголовка страницы: это не второй h1,
   а разделитель ленты. Prata, как все заголовки сайта.

   ОТСТУП СНИЗУ 33px, А НЕ ПРЕЖНИЕ 6px. Правка 16.08.2026: клиент попросила
   убрать декоративную линию под годом. Раньше расстояние от года до первой
   записи набиралось втроём - 6px этого отступа, 1px самой линии и 26px её
   margin-bottom, итого 33. Линию сняли, и если оставить 6px, год прилипнет
   к записи. Поэтому те же 33px просто переехали сюда: убрана линия,
   а не воздух вокруг года. Датировка записи при этом не тронута. */
.shows__year-title {
  font-family: var(--font-display);
  font-size: 34px;
  line-height: 1.1;
  color: var(--gold-deep);
  margin: 0 0 33px;
}

/* Правило .shows__year-rule удалено 16.08.2026 вместе с разметкой линии
   (четыре <div class="shows__year-rule"> в nashi-pobedy.html). Заводить
   обратно нельзя: это прямая просьба клиента убрать разграничения годов. */

/* Запись события. Своя карточка не заводится: фон один на весь раздел,
   а границы между записями держит воздух, как в ленте статей. */
.show + .show { margin-top: 42px; }

/* ── Запись с фотографией слева и текстом справа, .show--side ─────────────
   Правка 16.08.2026. Клиент: короткие тексты вынести вправо от фотографии,
   в одну строку с ней, и положить текст в плашку, а не голым на фон.

   КОМУ ДОСТАЁТСЯ. Ровно записям с одной и двумя фотографиями. Раскладка
   по странице: 1, 1, 3, 3, 1, 1, 2 - значит модификатор стоит у пяти
   записей из семи, а две записи с тремя кадрами остаются как были,
   текст сверху. Это прямое условие правки, а не выбор вёрстки: три
   кадра в ряд занимают всю колонку, и слева от них места под текст нет.

   ПОРЯДОК В РАЗМЕТКЕ НЕ ТРОГАЕТСЯ. Плашка стоит первой, фотографии
   второй - то есть заголовок записи читалка экрана произносит раньше
   картинок, как и раньше. Влево фотографии ставит явное размещение
   в сетке, а не order и не перестановка узлов.

   ФОТОБЛОК НЕ ПЕРЕСОБИРАН. <ul class="photos"> со всеми data-атрибутами
   остался тем же самым узлом: просмотрщик в script.js ищет .photos,
   читает data-max и data-name, и от переезда в колонку сетки не страдает.

   ШИРИНА ЛЕВОЙ КОЛОНКИ 226px, правка 16.08.2026, вариант 1.

   ЗДЕСЬ СТОЯЛО 459px - «ровно размер собранной плитки, плотность 1x».
   Число сменилось, потому что сменилось требование: замечание было
   «записи разной высоты, фотографии разного размера, текст загромождён».

   ЕДИНЫЙ РАЗМЕР ПЛИТКИ - 226px НА ВСЕЙ СТРАНИЦЕ. До правки показанных
   размеров было три при одном и том же файле 459x459: 459 у одиночных,
   331 в тройном ряду, 226 в двойном. Разброс 2.03x - у двух записей кадры
   показывались вдвое мельче, чем у пяти остальных, хотя файлы одинаковые.

   226 ВЫБРАНО НЕ ПО ВКУСУ. Это единственный из трёх показанных размеров,
   при котором держится ЧЕСТНАЯ ДВОЙНАЯ ПЛОТНОСТЬ: 459 / 226 = 2.03x.
   У 300 выходит 1.53x, у 331 - 1.39x. Заказчик: «на retina мыльные кадры
   заметнее мелких», плюс плитка кликабельна - по ней открывается полный
   кадр, то есть её размер не ограничивает просмотр. */
.show--side {
  display: grid;
  grid-template-columns: 226px minmax(0, 1fr);
  gap: 26px;
  align-items: start;
}
.show--side .show__plate  { grid-column: 2; grid-row: 1; }
.show--side .show__photos { grid-column: 1; grid-row: 1; margin-top: 0; }

/* ДВА КАДРА ЛОЖАТСЯ СТОЛБИКОМ, а не рядом. Правка 16.08.2026, решение
   перевёрнуто, и вот почему.

   ЗДЕСЬ СТОЯЛО «рядом, потому что столбиком две плитки по 459 дают колонку
   459x944 при плашке 250-300px, справа пустая шахта». Довод был верен
   ДЛЯ ПЛИТКИ 459. При плитке 226 столбик даёт колонку 226x460 при плашке
   285 - шахта 175px против 944-300 = 644 в прежнем расчёте.

   ЗАЧЕМ ВООБЩЕ СТОЛБИК. Только так плитка этой записи равна плитке
   остальных. Рядом внутри колонки 226 они стали бы по 109px, то есть
   вдвое мельче всех прочих - ровно тот дефект, который правится.
   Развернуть колонку под два кадра рядом (2*226 + 8 = 460) тоже нельзя:
   плашка ужалась бы до 559, и её строка села бы на 48 знаков против
   70 у остальных - развалилась бы единая мера строки.

   ЦЕНА НАЗВАНА ЧИСЛОМ: шахта 175px на одной записи из семи, 2015 год,
   «Цветок Сакуры». Это МЕНЬШЕ, чем нынешние 253px у записи «Felis Russica»
   с одиночным кадром 459. То есть по самому этому признаку страница
   становится ровнее, а не хуже. */
.show--side .show__photos { grid-template-columns: minmax(0, 226px); gap: 8px; }
.show--side .show__photos--one { grid-template-columns: minmax(0, 226px); }

/* Плашка. Фон --bg на секции --surface - тот же приём «карточка темнее
   секции», что в .articles и .kittens, новых цветов не заведено.

   Контраст на плашке #EFE4D3, порог 4.5:
     .show__date, .show__text   --text  #2B211A   12.51
     .show__place               --muted #6B5A48    5.25
   Оба берут порог с запасом.

   Поле 24px со всех сторон: на 1024 плашка ужимается до 313px, и при
   меньшем поле строка «Международная выставка «Pearl Jubilee Show»»
   вставала вплотную к краю. 24px держат воздух на всех проверенных
   ширинах, замер в отчёте круга. */
.show__plate {
  background: var(--bg);
  border: 1px solid rgba(62, 47, 32, 0.14);
  border-radius: 10px;
  padding: 24px;
}
/* Внутри плашки первый элемент не должен отбивать свой верхний отступ:
   его уже дало поле плашки. */
.show__plate > :first-child { margin-top: 0; }
.show__plate .show__text:first-of-type { margin-top: 10px; }

/* ── Узкие экраны: плашка уходит ПОД фотографию, одна колонка ─────────────
   Порог 900px. Прежнее обоснование опиралось на колонку 459px; она стала
   226px, и до 900 плашке остаётся ещё больше места, чем считалось. Порог
   не двигаем: ниже 900 колонка кадров рядом с текстом всё равно перестаёт
   читаться как ряд.
   grid-template-columns в одну дорожку плюс явные grid-row переставляют
   блоки местами: фотография первой, плашка второй. */
@media (max-width: 900px) {
  .show--side {
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
  }
  .show--side .show__photos { grid-column: 1; grid-row: 1; }
  .show--side .show__plate  { grid-column: 1; grid-row: 2; }
  /* Плитка держит те же 226px, что и на широких окнах: единый размер
     кадра - это условие правки, а не свойство одной ширины. */
  .show--side .show__photos,
  .show--side .show__photos--one { grid-template-columns: minmax(0, 226px); }
  .show--side .show__photos { gap: 8px; }
}
/* На телефоне поле плашки ужимается до 18px: при 24px и ширине 360
   строка внутри плашки становится 310px и рвётся на слишком короткие
   куски. 18px оставляют 322px и заметный отступ от края. */
@media (max-width: 560px) {
  .show--side .show__photos { grid-template-columns: minmax(0, 1fr); }
  .show__plate { padding: 18px; }
}

.show__date {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.25;
  color: var(--text);
  margin: 0;
}

/* Название выставки. Тише даты и не заголовок: в базе это отдельная
   строка, а не подзаголовок раздела. */
.show__place {
  margin: 6px 0 0;
  font-size: 16px;
  color: var(--muted);
}

.show__text { margin: 14px 0 0; }
.show__text + .show__text { margin-top: 8px; }

/* ── ДЛИНА СТРОКИ: ОДНО ЧИСЛО НА ВСЕ СЕМЬ ЗАПИСЕЙ ─────────────────────────
   Правка 16.08.2026, главная половина правки «текст выглядит загромождённым».

   ЧТО БЫЛО. Мера разъезжалась вдвое, замер на 1101 по реальным пикселям
   (истинная ширина знака 10.64px тем же шрифтом):

       пять записей в плашке      510px  =  48 знаков
       две записи с тремя кадрами 1045px =  98 знаков

   Девяносто восемь знаков в строке - это и есть «загромождённо». Для
   сравнения тело статьи на той же ширине: 814px = 76.5 знака.

   СТАЛО 72ch, одно объявление на дату, название и абзацы сразу. Число взято
   от эталона, а не подобрано: 72ch это 766px, то есть чуть плотнее статьи
   и внутри классического коридора 45-75 знаков. Записи в плашке при этом
   выходят на 70 знаков - их ограничивает не потолок, а ширина плашки,
   разница с потолком 23px.

   ch, А НЕ ПИКСЕЛИ, специально: единица едет за кеглем, и при смене
   типографической шкалы мера в знаках останется прежней. */
.show__date, .show__place, .show__text { max-width: 72ch; }

/* Кадры записи. Три колонки по 226px - тот же размер плитки, что и у записей
   с плашкой. Ряд занимает 3*226 + 2*26 = 730px из 1045 на окне 1101.
   Плотность 459 / 226 = 2.03x, честная двойная, апскейла нет.
   Прежние 331px в ряду давали 1.39x и были третьим размером плитки
   на странице - разбор у .show--side выше. */
.show__photos {
  grid-template-columns: repeat(3, minmax(0, 226px));
  margin-top: 18px;
}

/* ОДИНОЧНЫЙ КАДР: тот же размер, что и все остальные.
   ЗДЕСЬ СТОЯЛО 459px с доводом «в трёхколоночном ряду он занимал бы 331px
   и висел бы узким квадратом слева при пустых семистах справа». Довод снят
   вместе со своим условием: одиночные кадры больше не лежат в общем ряду,
   у них своя колонка 226px слева от плашки, и пустого места справа нет -
   там текст. Модификатор оставлен: он по-прежнему отличает одиночный ряд
   от тройного и ставится генератором страницы, а не селектором :has(). */
.show__photos--one { grid-template-columns: minmax(0, 226px); }

/* До 1100 тройной ряд ложится в две колонки. Плитка держит те же 226px:
   на 1024 в ряду остаётся 916px под две дорожки, потолок 226 не даёт им
   разъехаться шире плитки. На 768 остаётся 686px - тоже с запасом. */
@media (max-width: 1100px) {
  .show__photos { grid-template-columns: repeat(2, minmax(0, 226px)); }
}
/* На телефоне кадр занимает всю ширину колонки: 354px при окне 390.
   Это единственное место, где показанный размер отходит от 226 - и это
   осознанно, узкий экран показывает по одному кадру за раз. Апскейла
   всё равно нет, 459 натуральных против 354 показанных. */
@media (max-width: 560px) {
  .show__photos { grid-template-columns: minmax(0, 1fr); }
}

/* Ссылка на видео. Плеер не встраивается: правило проекта «ноль внешних
   запросов со страницы» проверяется каждый круг, а встроенный плеер
   YouTube тянет и скрипт, и превью, и куки. Обычная ссылка запросов
   не делает. Подпись нейтральная, название ролика в неё не выносится:
   у обоих роликов оно «13 декабря 2017 г.» - это дата загрузки на канал,
   а не дата выставки, и рядом с блоками «2-3 декабря» и «11-12 ноября»
   она читалась бы как ошибка. */
.show__video { margin: 16px 0 0; }
.show__video .link { font-size: 16px; }
