/* ==========================================================================
   Вариант B — «b-editorial»: журнальный разворот.

   Идея: сайт читается как печатный фоторепортаж, а не как экран. Палитра
   «Песок и море» остаётся светлой (тёмное пере-взвешивание уже забрал
   вариант A) — здесь инструмент иерархии не свет/тьма, а типографика:
   очень крупный Cormorant Garamond, щедрые поля, буквица, врезки-цитаты.
   Движение сведено к минимуму: только мягкое появление секций и один
   sticky-портрет в «Обо мне» — никакого скролл-скраббинга, как в A.

   Ключевое отличие от A по контрасту: здесь НЕТ текста поверх фотографий.
   Заголовок героя и цитата-призыв живут на чистом --bg, фото — отдельным
   вставным элементом (в рамке или sticky-колонкой). Это структурно снимает
   весь класс дефектов «текст тонет в светлом небе», который решался в A
   верхним и нижним слоями пелены.

   Контраст проверен: python3 scripts/contrast.py
     чернила #1f2e2c на песке #f2e6cc     — 11.42:1
     приглушённый #546663 на песке        — 4.91:1
     приглушённый #546663 на полотне #fbf3de — 5.49:1
     ссылка/акцент-текст --deep на песке  — 4.73:1
     кнопка --onaccent на --accent        — 5.41:1
     кнопка --ondeep на --deep            — 5.43:1
   --accent (#e07b2f) как ЦВЕТ ТЕКСТА на песке даёт только 2.41:1 — провал
   даже для крупного текста (нужно 3:1). Поэтому accent здесь только заливка
   кнопок (с --onaccent) и декоративные элементы с aria-hidden (кавычка
   манифеста, волосяные линии) — никогда не цвет читаемого текста.
   ========================================================================== */

.b {
  /* Более прямые, «печатные» углы вместо пилюль варианта A — единственная
     переменная, и все .btn/.chip/.menu__btn/.tab перекраиваются разом. */
  --rad: 3px;
  --rad-pill: 3px;
  --hair: var(--line);
}

/* .hdr — position: fixed, сам не занимает места в потоке (см. .mast).
   Компенсация здесь одна на весь документ (как в D), а не в каждой секции
   по отдельности — тогда баннер-поздравление .stop, когда он показан,
   просто занимает часть этого отступа как обычный блок потока, а когда
   закрыт — отступ остаётся ровно header-h без переключения классов и CLS. */
body.b { padding-top: var(--header-h); }

.b em { font-style: italic; color: var(--deep); }
.b a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Появление секций — то же общее правило, что и в A, но перемещение короче:
   печатный лист не должен «взлетать», только мягко проявляться. */
.has-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.has-reveal .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .has-reveal .reveal { opacity: 1; transform: none; }
}

/* ==== Общие мелочи варианта ============================================== */

.eyebrow {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--soft);
  margin: 0 0 var(--s-3);
}
.eyebrow--warm { color: var(--deep); }

.sec__head { max-width: 50ch; margin: 0 auto var(--s-7); text-align: center; }
.sec__head h2 { font-size: var(--t-h2); }
.sec__hint { color: var(--soft); font-size: var(--t-small); margin-top: var(--s-3); }

.btn--ghost { border-color: var(--deep); color: var(--deep); }

/* ==== Шапка ==============================================================
   Одна строка, flex-wrap запрещён — на 390px высота равна var(--header-h)
   (56px), с запасом до потолка оси 3 в 64px.
   ========================================================================= */

.hdr {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: nowrap;
  padding: 0 var(--gut);
  background: rgba(251, 243, 222, 0.88);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hair);
}

.hdr__brand {
  font-family: var(--sans);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  margin-right: auto;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  /* На 200% масштабе (прокси-тест reflow) даже самая тугая ступень сжатия
     ниже (@media max-width: 359px) не спасает: .hdr держит flex-wrap:
     nowrap намеренно (ось 3, высота шапки ≤64px, второй ряд её сломает),
     а рутовый кегль удваивает и бренд, и .hdr__cta одновременно — паре
     просто некуда деться, и .hdr__cta (защищена flex-shrink: 0 ниже)
     выталкивается за правый край. body{overflow-x:clip} при этом СКРЫВАЕТ
     переполнение от document.scrollWidth — кнопка реально уезжает за
     экран, недостижима, а обычная проверка ширины документа этого не
     покажет. Бренд — имя сайта, дублирует контент ниже — жертвует собой
     через min-width: 0 + эллипсис; кнопка «Связаться» остаётся целой. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hdr__brand em { font-style: normal; color: var(--deep); }

.hdr__nav {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2vw, 1.8rem);
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.hdr__nav a { color: var(--soft); padding: var(--s-2) 0; }
.hdr__nav a:hover { color: var(--deep); }

.hdr__cta {
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--onaccent);
  background: var(--accent);
  border-radius: var(--rad-pill);
  padding: 0 var(--s-4);
  min-height: var(--tap);
  white-space: nowrap;
  /* .tap (tokens.css) ставит на этот flex-элемент явный min-width: 44px —
     это ПЕРЕБИВАЕТ браузерный дефолт min-width: auto, который иначе не дал
     бы элементу сжаться уже собственного контента. На узких вьюпортах
     .hdr (flex, nowrap) поджимает кнопку до 44px, хотя тексту с паддингом
     нужно больше — отсюда scrollWidth 59 > clientWidth 53 на 320px.
     flex-shrink: 0 запрещает сжатие вовсе: ширина остаётся контентной
     (заведомо ≥ 44px за счёт паддинга), 44px из .tap работает только как
     пол по высоте/ширине, не источник сжатия. */
  flex-shrink: 0;
  transition: filter var(--dur) var(--ease);
}
.hdr__cta:hover { filter: brightness(1.06); text-decoration: none; }

.menu { display: none; position: relative; }
.menu__btn {
  list-style: none;
  cursor: pointer;
  border-radius: var(--rad-pill);
  border: 1px solid var(--hair);
}
.menu__btn::-webkit-details-marker { display: none; }
.menu__bars,
.menu__bars::before,
.menu__bars::after {
  display: block;
  width: 18px;
  height: 1.5px;
  background: var(--ink);
  content: "";
}
.menu__bars { position: relative; }
.menu__bars::before { position: absolute; top: -6px; }
.menu__bars::after { position: absolute; top: 6px; }
.menu[open] .menu__bars { background: var(--deep); }

/* <details>: браузер нативно прячет всё, кроме <summary>, пока нет [open].
   Правило ниже задавало display: grid без привязки к [open] и тем самым
   перебивало это нативное скрытие — закрытое меню получало реальную
   геометрию (rect с шириной/высотой) и было хит-тестируемым: пункты
   («Обо мне», «Прайс»…) реально попадали под курсор/палец поверх того,
   что под ними, и вылезали за пределы вьюпорта на 200% зуме текста. Тот
   же класс дефекта, что уже чинили для D (`.ctab[open] .ctab__panel`,
   коммит 0939e4f) и для лайтбокса — display: grid должен работать только
   когда .menu открыт. */
/* Явное скрытие обязательно, одного ограничения правила [open] мало: замерено
   при закрытом меню — display оставался block, а прямоугольник 44x881, почти
   во всю высоту страницы. Причина: элементу когда-либо задавали явный display,
   и браузер выводит такой элемент из-под родного скрытия закрытого <details>
   насовсем, даже когда правило с этим значением уже не совпадает. */
.menu__panel { display: none; }
.menu[open] .menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  min-width: 12rem;
  display: grid;
  background: var(--bg2);
  border: 1px solid var(--hair);
  border-radius: var(--rad);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
}
.menu__panel a {
  padding: 0 var(--s-5);
  min-height: var(--tap);
  display: flex;
  align-items: center;
  color: var(--ink);
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--hair);
}
.menu__panel a:last-child { border-bottom: 0; color: var(--deep); }
.menu__panel a:hover { background: var(--bg); text-decoration: none; }

@media (max-width: 860px) {
  .hdr__nav { display: none; }
  .menu { display: block; }
}
@media (max-width: 420px) {
  .hdr { gap: var(--s-2); padding: 0 var(--s-4); }
  .hdr__brand { font-size: 0.82rem; letter-spacing: 0.1em; }
  .hdr__cta { padding: 0 var(--s-3); font-size: 0.64rem; }
}
/* Замерено вживую: на 320-340px .hdr__cta.right уезжал за край экрана
   (339.5px правого края кнопки-меню при vw=320, ноль запаса на 340) —
   тройка «бренд + Связаться + меню» физически не помещается в тесной
   компоновке выше даже после первой ступени сжатия. Вторая, более тугая
   ступень — не убирает ни один элемент (Связаться остаётся видимой и
   кликабельной), только туже поджимает интервалы и паддинги. */
@media (max-width: 359px) {
  .hdr { gap: var(--s-1); padding: 0 var(--s-3); }
  .hdr__brand { font-size: 0.72rem; letter-spacing: 0.06em; }
  .hdr__cta { padding: 0 var(--s-2); font-size: 0.58rem; }
}

/* ==== Разворот / hero ====================================================
   Асимметричная сетка: заголовок и портрет — в разных колонках неравной
   ширины, gap между ними достаточен, чтобы фото не спорило с текстом.
   На мобильном раскладка схлопывается в одну колонку через смену areas.
   ========================================================================= */

.mast {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  grid-template-areas:
    "eyebrow figure"
    "head    figure"
    "lead    figure"
    "actions figure";
  column-gap: clamp(2rem, 6vw, 5rem);
  row-gap: var(--s-5);
  align-items: start;
  padding: var(--s-8) var(--gut) var(--s-9);
  max-width: 84rem;
  margin: 0 auto;
}
.mast__eyebrow { grid-area: eyebrow; margin-bottom: 0; }
.mast__head {
  grid-area: head;
  font-size: var(--t-display);
  line-height: 0.98;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.mast__head span { display: block; }
.mast__head em { font-style: italic; color: var(--deep); }

.mast__lead {
  grid-area: lead;
  font-size: var(--t-lead);
  max-width: 42ch;
  color: var(--soft);
}
.mast__actions {
  grid-area: actions;
  display: flex;
  gap: var(--s-4);
  flex-wrap: wrap;
}

.mast__figure {
  grid-area: figure;
  margin: 0;
  justify-self: end;
  align-self: start;
  max-width: 26rem;
  width: 100%;
  padding: var(--s-3);
  border: 1px solid var(--hair);
}
.mast__img { width: 100%; height: auto; }
.mast__cap {
  margin-top: var(--s-3);
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--soft);
  text-align: right;
}

@media (max-width: 900px) {
  .mast {
    grid-template-columns: 1fr;
    grid-template-areas: "eyebrow" "head" "figure" "lead" "actions";
  }
  .mast__figure { justify-self: stretch; max-width: none; }
  .mast__actions .btn { flex: 1 1 100%; }
}

/* ==== Обо мне ============================================================
   Портрет прилипает (position: sticky) к колонке, пока читатель идёт по
   тексту рядом — позиционный эффект, не анимация: prefers-reduced-motion
   его не касается.
   ========================================================================= */

.profile {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
  padding: var(--sec-y) var(--gut);
  background: var(--bg2);
}
.profile__media {
  position: sticky;
  top: calc(var(--header-h) + var(--s-6));
  max-width: 26rem;
}
.profile__img { width: 100%; border-radius: var(--rad); }

.profile__text { max-width: var(--measure); }
.profile__text h2 { font-size: var(--t-h2); margin-bottom: var(--s-5); }
.profile__text p { color: var(--soft); margin-bottom: var(--s-4); }

/* Буквица держит печатный ритм первого абзаца. */
.profile__drop::first-letter {
  float: left;
  font-family: var(--serif);
  font-size: 4.2rem;
  line-height: 0.82;
  font-weight: 600;
  color: var(--deep);
  padding: 0.1rem var(--s-3) 0 0;
}

/* Врезка — цитата, выдернутая дословно из собственного текста Надежды
   абзацем ниже (см. assets/BRIEF.md): классический журнальный приём
   pull-quote, а не новый текст. */
.profile__quote {
  margin: var(--s-6) 0;
  padding: 0 0 0 var(--s-5);
  border-left: 3px solid var(--accent);
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.1rem);
  line-height: 1.3;
  color: var(--ink);
}

.profile__facets {
  display: flex;
  gap: var(--s-6);
  flex-wrap: wrap;
  margin: var(--s-5) 0 var(--s-6);
}
.profile__facets em {
  font-family: var(--serif);
  font-size: 1.3rem;
  color: var(--deep);
  font-style: italic;
}
.profile__facets span { display: block; font-size: var(--t-small); color: var(--soft); }

@media (max-width: 900px) {
  .profile { grid-template-columns: 1fr; }
  .profile__media { position: static; max-width: 22rem; margin: 0 auto; }
}

/* ==== Прайс ===============================================================
   Расценки строкой, разделённые волосяной линией — не карточки варианта A.
   ========================================================================= */

.rate { padding: var(--sec-y) var(--gut); }

.rate__tiers {
  max-width: 60rem;
  margin: 0 auto var(--s-8);
  border-top: 1px solid var(--hair);
}
.rate__row {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--s-5);
  padding: var(--s-6) 0;
  border-bottom: 1px solid var(--hair);
}
.rate__id {
  /* var(--line) как цвет текста даёт 1.24:1 — провал; var(--soft) даёт 4.91:1. */
  font-family: var(--serif);
  font-size: var(--t-h3);
  color: var(--soft);
  font-weight: 600;
}
.rate__name { font-size: var(--t-h3); margin-bottom: var(--s-2); }
.rate__note { color: var(--soft); font-size: var(--t-small); max-width: 34ch; }
.rate__sum {
  font-family: var(--serif);
  font-size: clamp(1.8rem, 3.4vw, 2.4rem);
  color: var(--deep);
  white-space: nowrap;
}
.rate__sum strong { font-weight: 600; }

.rate__lists {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: clamp(2rem, 5vw, 4rem);
  max-width: 60rem;
  margin: 0 auto;
}
.rate__sub {
  font-family: var(--serif);
  font-size: var(--t-h4);
  font-weight: 600;
  padding-bottom: var(--s-2);
  margin-bottom: var(--s-4);
  border-bottom: 2px solid var(--deep);
}
.rate__list li {
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hair);
  color: var(--ink);
  display: flex;
  gap: var(--s-3);
}
.rate__list li::before { content: "—"; color: var(--deep); }
.rate__fine { margin-top: var(--s-4); font-size: var(--t-small); color: var(--soft); font-style: italic; }

@media (max-width: 720px) {
  .rate__row {
    grid-template-columns: auto 1fr;
    grid-template-areas: "id name" "id note" "sum sum" "cta cta";
    row-gap: var(--s-3);
  }
  .rate__id { grid-area: id; }
  .rate__name { grid-area: name; margin: 0; }
  .rate__note { grid-area: note; max-width: none; }
  .rate__sum { grid-area: sum; text-align: left; }
  .rate__row .btn { grid-area: cta; width: 100%; }
}

/* ==== Манифест ============================================================ */

.creed {
  position: relative;
  padding: clamp(5rem, 14vh, 9rem) var(--gut);
  display: flex;
  justify-content: center;
  background: var(--bg2);
  border-top: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
}
.creed__mark {
  position: absolute;
  top: clamp(1rem, 4vh, 2.5rem);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--serif);
  font-size: clamp(5rem, 14vw, 9rem);
  line-height: 1;
  color: var(--accent);
  opacity: 0.28;
}
.creed__text {
  position: relative;
  font-family: var(--serif);
  font-size: clamp(1.5rem, 3vw, 2.3rem);
  line-height: 1.45;
  max-width: 36ch;
  text-align: center;
  text-wrap: balance;
}

/* ==== Виды съёмок =========================================================
   Оглавление номера: нумерованная строка + квадратная миниатюра вместо
   полноэкранной фотокарточки.
   ========================================================================= */

.toc { padding: var(--sec-y) var(--gut); }
.toc__list { max-width: 52rem; margin: 0 auto; border-top: 1px solid var(--hair); }
/* Было: 3 колонки (миниатюра/номер/1fr), но 4 плоских ребёнка (img, num, h3,
   p) — авто-раскладка грид заполняла ряд первыми тремя, а .svc__sub с
   явным grid-column: 3 уходил на СЛЕДУЮЩУЮ implicit-строку под ним же.
   Итог, замерено вживую: строка растягивалась на ~150px (заголовок в одной
   implicit-строке, описание — в следующей, с тем же большим левым отступом,
   что и у 56px-миниатюры), а колонка заголовка справа от номера пустовала
   под текстом на всю его ширину — ~300px воздуха. Именованные области на
   2 implicit-строки (номер/миниатюра растянуты на обе через повтор имени)
   ставят заголовок и описание рядом друг с другом в одном ряду по
   вертикальной середине, без лишней implicit-строки. */
.toc__item {
  display: grid;
  grid-template-columns: 4.5rem auto 1fr;
  grid-template-areas: "img num title" "img num sub";
  column-gap: var(--s-5);
  row-gap: 0.2rem;
  align-items: center;
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--hair);
  color: var(--ink);
}
.toc__item:hover { text-decoration: none; }
.toc__item:hover .svc__title { color: var(--deep); }
.toc__img {
  /* Увеличена с 3.5rem: на прежнем размере миниатюра не работала ни как
     иллюстрация, ни как акцент рядом с крупным номером и заголовком. */
  grid-area: img;
  width: 4.5rem;
  height: 4.5rem;
  object-fit: cover;
  border-radius: var(--rad);
}
.svc__num {
  /* var(--line) как цвет текста даёт 1.24:1 — провал; var(--soft) даёт 4.91:1.
     Кегль поднят до var(--t-h3) — тот же приём, что у .rate__id в прайсе
     (строка ниже), номер держит вес наравне с увеличенной миниатюрой. */
  grid-area: num;
  align-self: center;
  font-family: var(--serif);
  font-size: var(--t-h3);
  color: var(--soft);
  font-weight: 600;
}
.svc__title {
  grid-area: title;
  align-self: end;
  font-size: var(--t-h4);
  transition: color var(--dur) var(--ease);
}
.svc__sub {
  grid-area: sub;
  align-self: start;
  color: var(--soft);
  font-size: var(--t-small);
}

@media (max-width: 560px) {
  .toc__item { grid-template-columns: 2.75rem 1fr; grid-template-areas: "img num" "img title" "img sub"; }
  .svc__num { grid-area: num; }
  .svc__title { grid-area: title; }
  .svc__sub { grid-area: sub; }
  .toc__img { grid-area: img; width: 2.75rem; height: 2.75rem; }
}

/* ==== Галерея =============================================================
   Мозаика колонками: реальные пропорции портретов (0.75) и шести
   ландшафтных кадров (1.5) сами создают «разные размеры» — без искусственных
   модификаторов и без обрезки кадра.
   ========================================================================= */

.gallery { padding: var(--sec-y) var(--gut); background: var(--bg2); }

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  justify-content: center;
  margin-bottom: var(--s-6);
}
.chip {
  min-height: var(--tap);
  padding: 0 var(--s-5);
  border: 1px solid var(--hair);
  border-radius: var(--rad-pill);
  background: transparent;
  color: var(--soft);
  font-size: var(--t-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.chip:hover { color: var(--ink); border-color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--deep);
  border-color: var(--deep);
  color: var(--ondeep);
}

/* Было: CSS columns (браузер сам балансирует высоту колонок — многопроходная
   раскладка). Заменено на CSS grid — тот же класс дефектов, что уже нашли и
   починили в c-gallery/style.css (коммит 8612461), измерено заново здесь:
   1) columns требует multi-pass балансировки высоты ДО первой отрисовки, и
      в момент этого прохода Chromium решал, что все 22 плитки "достаточно
      близко" к экрану — loading="lazy" переставал действовать, грузились
      все 22 разом одним скачком вместо порционной подгрузки по прокрутке.
   2) DOM-порядок расходился с визуальным: columns заполняет колонку сверху
      вниз целиком, потом следующую — Tab прыгал вниз первой колонки прежде
      чем перейти в начало второй, хотя глаз читает слева направо.

   В отличие от c-gallery, здесь НЕ нужен приём с единой aspect-ratio
   3/4 + object-fit: cover — там он был вынужденной ценой за то, что 4
   ландшафтных фото пытались занять 2 колонки (non-dense grid не может
   вставить широкую плитку в последний свободный столбец ряда и уходит на
   новую строку целиком, оставляя дыру). Здесь ни одна плитка не растягивается
   на несколько колонок — все 22 фото уже занимают ровно одну колонку своей
   естественной ширины, разная "рваная" высота идёт из настоящих пропорций
   кадра (0.75 портрет / 1.5 ландшафт), а не из ширины. Поэтому обычный grid
   (без dense, без обрезки) сохраняет и порядок, и родные пропорции разом —
   единственная плата за отказ от многоколоночной балансировки: под более
   короткими кадрами в ряду остаётся немного воздуха до начала следующего
   ряда (высота ряда = высота самого высокого кадра в нём) — это не дыра
   между занятыми и незанятыми ячейками, как было бы у C, а просто чуть
   меньше плотная упаковка, сама «рваная» пропорция кадров никуда не делась. */
.mosaic {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-flow: row; /* не dense — DOM-порядок должен совпадать с Tab-порядком */
  align-items: start;  /* каждая плитка — своя естественная высота, не тянется на высоту ряда */
  gap: var(--s-4);
  max-width: 78rem;
  margin: 0 auto;
}
@media (min-width: 640px) { .mosaic { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 980px) { .mosaic { grid-template-columns: repeat(4, 1fr); } }

.shot {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.shot picture {
  overflow: hidden;
  border-radius: var(--rad);
}
.shot__img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform var(--dur-slow) var(--ease);
}
.shot:hover .shot__img,
.shot:focus-visible .shot__img { transform: scale(1.04); }
.shot[hidden] { display: none; }
.shot__cap {
  display: block;
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--hair);
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--t-small);
  line-height: 1.3;
  text-align: left;
  color: var(--soft);
}

/* ==== Призыв ==============================================================
   Фотопластина в тонкой рамке рядом с текстом — не полноэкранная тёмная
   пелена варианта A. Текст остаётся на --bg2, поэтому контраст тот же,
   что и везде в этом варианте.
   ========================================================================= */

.closer {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
  padding: var(--sec-y) var(--gut);
  max-width: 84rem;
  margin: 0 auto;
}
.closer__head h2 { font-size: var(--t-h2); margin-bottom: var(--s-4); }
.closer__head p { color: var(--soft); margin-bottom: var(--s-6); max-width: 40ch; }
.closer__channels { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.closer__frame {
  margin: 0;
  padding: var(--s-3);
  border: 1px solid var(--hair);
}
.closer__img { width: 100%; height: auto; }

@media (max-width: 900px) {
  .closer { grid-template-columns: 1fr; }
  .closer__frame { order: -1; }
}

/* ==== FAQ =================================================================
   Сноски номера: короткие ответы двумя колонками через CSS columns —
   тот же приём, что и в мозаике галереи, только для текста.
   ========================================================================= */

.notes { padding: var(--sec-y) var(--gut); background: var(--bg2); }
.notes__list { max-width: 56rem; margin: 0 auto; columns: 2; column-gap: clamp(2rem, 4vw, 3.5rem); }
.faq__item { break-inside: avoid; border-bottom: 1px solid var(--hair); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: var(--tap);
  padding: var(--s-4) 0;
  font-family: var(--serif);
  font-size: var(--t-h4);
  cursor: pointer;
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: "+";
  color: var(--deep);
  font-size: 1.4rem;
  line-height: 1;
  transition: transform var(--dur) var(--ease);
}
.faq__item[open] .faq__q::after { transform: rotate(45deg); }
.faq__a { padding: 0 0 var(--s-5); color: var(--soft); max-width: 62ch; }

@media (max-width: 700px) {
  .notes__list { columns: 1; }
}

/* ==== Колофон (подвал) ==================================================== */

.colophon {
  text-align: center;
  padding: var(--s-8) var(--gut) calc(var(--s-8) + var(--dock-h, 0px));
  background: var(--ink);
  color: var(--bg2);
}
.colophon__brand { font-family: var(--sans); font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; font-size: 1.05rem; }
.colophon__brand em { font-style: normal; color: var(--heroem); }
.colophon__where { color: rgba(251, 243, 222, 0.66); font-size: var(--t-small); margin: var(--s-2) 0 var(--s-5); }
.colophon__links { display: flex; gap: var(--s-5); justify-content: center; flex-wrap: wrap; }
.colophon__links a {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  color: var(--bg2);
  font-size: var(--t-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* Контраст колофона (тёмный низ страницы, единственное тёмное место в B):
   python3 scripts/contrast.py '#fbf3de' '#1f2e2c' → 12.78:1 (бренд/ссылки)
   python3 scripts/contrast.py '#ffce7a' '#1f2e2c' → 9.67:1 (em в бренде)
   rgba(251,243,222,.66) поверх --ink → композит #b0b0a1 → 6.44:1 (локация) */

/* ==== Док связи ===========================================================
   Ось 7: три канала в пределах одного экрана с любой точки прокрутки.
   Здесь — узкая текстовая закладка сбоку вместо иконок-пилюль варианта A.
   ========================================================================= */

.b { --dock-h: 0px; }

.tab {
  position: fixed;
  /* right: 0 без зазора — оставлено сознательно и после сужения до 44px:
     это язычок-закладка, приклеенный к обрезу листа, тот же приём, что и
     бумажная закладка в журнале. Зазор превратил бы его в подвешенную
     кнопку и снял бы этот приём; вплотную к краю он читается как часть
     переплёта, не как обрезанный элемент. */
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 65;
  display: grid;
  border: 1px solid var(--hair);
  border-right: 0;
  background: var(--bg2);
  box-shadow: var(--shadow-lift);
}
.tab__link {
  /* Замерено скриптом (пересечение прямоугольников по горизонтали) на
     b-editorial: закладка шириной 130px (горизонтальные подписи в один
     ряд каждая) перекрывала колонку текста — 19 пересечений на 1280px
     (легла прямо на h2/p «Обо мне»), 15 на 1440px (галерея и подписи),
     3 даже на 1680px. Горизонтальные подписи INSTAGRAM/TELEGRAM/WHATSAPP
     не сжать без потери формы закладки-язычка (это её характер, не
     иконки-пилюли варианта A) — поэтому текст ставится вертикально, и
     закладка сужается до ширины одной строки текста вместо длины слова. */
  writing-mode: vertical-rl;
  /* mixed-ориентация по умолчанию поворачивает латиницу на 90° по часовой
     (читалась бы сверху вниз, наклонив голову вправо) — ещё один разворот
     на 180° даёт чтение снизу вверх, привычное для боковых язычков/корешков.
     transform не меняет вклад элемента в layout (в отличие от поворота на
     90°), поэтому все расчёты ширины/высоты ниже остаются в физических осях. */
  transform: rotate(180deg);
  min-height: var(--tap);
  /* До поворота min-height по высоте гарантировал тап-таргет ≥44px, а ширина
     была свободной (задавалась паддингом+контентом). После поворота именно
     ширина стала «короткой» осью — без явного пола она бы сжалась до толщины
     одной строки текста (~18-20px), провалив размер цели. min-width держит
     физическую ширину ≥44px и заодно ЗАДАЁТ итоговую ширину закладки — при
     таком паддинге контент уже, чем 44px, так что пол побеждает. */
  min-width: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Было: padding: 0 var(--s-5) — отступ вдоль ГОРИЗОНТАЛЬНОГО чтения (лево-
     право). После поворота ось чтения вертикальна: тот же отступ по бокам
     раздул бы физическую ширину значительно за пределы 44px и свёл на нет
     сужение закладки. Отступ переезжает на верх/низ (вдоль нового чтения),
     по бокам — 0, ширину целиком определяет min-width выше. */
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hair);
  color: var(--ink);
  /* Зафиксировано в px, не var(--t-small) (rem): .tab — постоянный
     навигационный хром (fixed, поверх контента), не читаемый текст
     страницы, и WCAG 1.4.4 требует масштабируемость КОНТЕНТА, не то,
     чтобы каждый пиксель UI рос вместе с ним — так же не растягивается
     системная панель браузера. Замерено вживую на 320×900 при
     document.documentElement.style.fontSize=200%: с var(--t-small) три
     подписи раздували .tab (fixed, bottom:0) с обычных ~150px до 324px
     высоты, и он физически перекрывал .mast__eyebrow в потоке документа
     (getBoundingClientRect: пересечение по Y даже при scrollY=0 — то
     есть без единой прокрутки, не «временно скрыто пока скроллишь»,
     а стабильно нечитаемо). Фиксированный px держит высоту дока ~198px
     на том же зуме — пересечения нет (проверено тем же замером,
     eyebrow заканчивается на y=677, док начинается на y=702). Тап-таргет
     по высоте не страдает — 44px это min-height, тоже px. */
  font-size: 13.28px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tab__link:hover { background: var(--deep); color: var(--ondeep); text-decoration: none; }
.tab__link:last-child { border-bottom: 0; }

@media (max-width: 860px) {
  .b { --dock-h: 58px; }
  .tab {
    right: 0;
    left: 0;
    top: auto;
    bottom: 0;
    transform: none;
    /* minmax(0, 1fr), не голый 1fr: у грид-трека тот же защитный дефолт
       minmax(auto, 1fr), что у флекс-айтема min-width: auto — колонка не
       сжимается ниже min-content своего текста. На 200% масштабе
       («WhatsApp», самое длинное слово) три колонки вместе требуют больше
       контейнера (353px против 320) и уезжают за правый край. minmax(0,…)
       снимает защиту явно — колонки честно делят ширину поровну, текст
       переносится внутри своей трети, а не раздвигает сетку. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    border: 0;
    border-top: 1px solid var(--hair);
    background: rgba(251, 243, 222, 0.98);
    backdrop-filter: blur(10px);
  }
  .tab__link {
    justify-content: center;
    border-bottom: 0;
    border-right: 1px solid var(--hair);
    /* px, не rem — тот же приём, что уже обоснован выше для десктопного
       .tab__link (13.28px): на 200% масштабе rem-подпись раздувала эту
       нижнюю панель настолько, что она наезжала на .mast__eyebrow/.mast__head
       в потоке документа (пересечение по Y без единой прокрутки). Тут этот
       брейкпоинт (≤860px) переопределял font-size обратно на rem и терял
       защиту именно там, где её и замеряли — на мобильном. */
    font-size: 10.88px;
  }
  .tab__link:last-child { border-right: 0; }
}

/* ==== Баннер-поздравление ================================================
   В потоке документа сразу под шапкой (отступ под фиксированную шапку —
   на body.b, см. выше) — раздвигает разворот вниз вместо того, чтобы лечь
   fixed-плашкой поверх него, как было раньше. Полоса-«молния»: тонкая
   рамка снизу вместо стеклянной пилюли A.
   ========================================================================= */

.stop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--gut);
  background: var(--bg2);
  border-bottom: 1px solid var(--accent);
  text-align: center;
}
.stop[hidden] { display: none; }
.stop__text {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1rem;
  line-height: 1.25;
  color: var(--ink);
}
.stop__text em { color: var(--deep); }
.stop__heart { color: var(--accent); }
.stop__heart svg { width: 0.85em; height: 0.85em; vertical-align: -0.08em; fill: currentColor; }
.stop__close {
  flex: none;
  background: none;
  border: 0;
  color: var(--soft);
  font-size: 1rem;
  cursor: pointer;
}
.stop__close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; display: block; }
.stop__close:hover { color: var(--ink); }

@media (max-width: 520px) {
  .stop__text { font-size: 0.9rem; }
  .stop { padding-left: var(--s-4); }
}
