/* ==========================================================================
   Вариант D — «d-story»: тёплая история в один голос.

   Идея: не сайт-витрина, а личный рассказ Надежды с фотографиями внутри
   текста — ровно там, где о них заходит речь. Одна узкая колонка, мера
   ~60-70 символов, светлая палитра «Песок и море» без пере-взвешивания.
   Никакой сцены прокрутки, никакого HUD — только читаемый текст и кадры.

   Контраст (все пары уже в общем табеле, python3 scripts/contrast.py):
     основной текст #1f2e2c на песке #f2e6cc — 11.42:1
     основной текст на полотне #fbf3de — 12.78:1
     приглушённый #546663 на песке — 4.91:1, на полотне — 5.49:1
     ссылка --deep #0f6e84 на песке — 4.73:1
   --accent (#e07b2f) на светлом фоне даёт только 2.41:1 — здесь он служит
   ТОЛЬКО заливкой кнопки/тонкой линией, никогда цветом текста.
   ========================================================================== */

.d {
  background: var(--bg);
  color: var(--ink);
}

.d em { font-style: italic; color: var(--deep); }
.d a { color: var(--deep); }
/* --accent на светлом даёт только 2.41:1 — годится для заливок/декора, но не
   для текста ссылок, даже на hover. Ховер держим на --ink (11.42:1) с
   подчёркиванием, а не сменой на нечитаемый оранжевый. */
.d a:hover { color: var(--ink); text-decoration: underline; }

.d .lead { color: var(--ink); }

/* Мера чтения: узкая колонка для всей прозы и фотографий-«в тексте». */
.opening,
.story,
.chapter,
.finale {
  max-width: 40rem;
  margin: 0 auto;
  padding: 0 var(--gut);
}

.opening,
.story,
.chapter { padding-top: clamp(2.5rem, 6vw, 4rem); padding-bottom: clamp(2.5rem, 6vw, 4rem); }
.chapter { border-top: 1px solid var(--line); }

.opening > * + *,
.story > * + *,
.chapter > * + * { margin-top: var(--s-5); }

/* ==== Шапка ==============================================================
   Требование оси 3: не выше 64px на 390px. Одна строка, ничего кроме
   бренда и переключателя связи.
   ========================================================================= */

body.d { padding-top: var(--header-h); }

.hdr {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Фиксированный px, не var(--s-3): это зазор между декоративным брендом
     и кнопкой контактов, не текст — ему не нужно расти вместе с шрифтом.
     На 200% масштабе rem-зазор удваивался (12px → 24px) и отбирал у
     .hdr__brand ровно те пиксели, которых не хватало, чтобы его тап-таргет
     не проваливался ниже 44px (см. min-width на .hdr__brand ниже). При
     обычном кегле совпадает с прежним var(--s-3) (12px) — визуально ничего
     не меняется. */
  gap: 12px;
  padding: 0 var(--gut);
  background: rgba(251, 243, 222, 0.9);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
/* На 200% масштабе (см. --font-size на <html>, стандартный прокси-тест
   reflow/WCAG 1.4.10 без настоящего браузерного зума) бренд-ссылка и
   кнопка «Написать» не помещаются в строку вместе: их суммарная
   min-content-ширина (обе с white-space: nowrap, обе уже упёрлись в
   защитный дефолт min-width: auto — тот же защитный дефолт, который в B
   был случайно ПЕРЕБИТ явным min-width и дал паразитное сжатие) больше
   доступной ширины `.hdr`. Здесь наоборот: защита сработала честно, но
   для ОБОИХ элементов сразу — а флекс-строке без wrap и без стратегии
   сжатия деть лишнюю ширину некуда, и `justify-content: space-between`
   просто толкает кнопку за правый край видимой области. Корень —
   отсутствие любой стратегии сжатия, не чужое поведение.
   Решение — не перенос (шапка `position: fixed; height: var(--header-h)`
   фиксированной высоты, второй ряд просто наложился бы на контент ниже)
   и не защита обоих сразу (тогда узкий экран решить нечем): бренд —
   декоративное имя сайта, дублирует заголовок h1 строкой ниже — ему
   разрешено сжиматься ниже своего текста и обрезаться многоточием.
   Кнопка контактов — единственный путь к письму без прокрутки до
   финала — защищена явным flex-shrink: 0 и никогда не участвует в
   сжатии вообще. */
.hdr__brand {
  font-family: var(--serif);
  font-size: 1.15rem;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* min-width: var(--tap), не 0: бренд разрешено сжимать ниже текста
     (см. комментарий выше), но не ниже минимального тап-таргета — это
     всё ещё ссылка (href="#top"). var(--tap) — фиксированный px-токен,
     не рем, поэтому пол не растёт вместе с зумом и не отъедает лишнего
     у кнопки контактов; на обычном кегле шире собственного текста, не
     влияет на видимую раскладку. */
  min-width: var(--tap);
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}
.hdr__brand em { color: var(--deep); }

/* Переключатель связи — ось 7: контакт достижим с любой точки прокрутки,
   потому что шапка зафиксирована, а не потому что где-то ещё висит док. */
.ctab { position: relative; flex-shrink: 0; }
.ctab__btn {
  list-style: none;
  cursor: pointer;
  padding: 0 var(--s-5);
  border: 1px solid var(--deep);
  border-radius: var(--rad-pill);
  color: var(--deep);
  font-size: var(--t-small);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  white-space: nowrap;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ctab__btn::-webkit-details-marker { display: none; }
.ctab[open] .ctab__btn,
.ctab__btn:hover { background: var(--deep); color: var(--ondeep); }

/* .ctab — <details>: нативно браузер прячет всё, кроме <summary>, пока
   нет [open]. Правило ниже раньше задавало display: grid без привязки к
   [open] и тем самым перебивало это нативное скрытие — закрытая панель
   получала реальную геометрию (rect с шириной/высотой) и pointer-events:
   auto, то есть ссылка на Instagram внутри ЗАКРЫТОГО аккордеона могла
   перехватывать клики/попадать под курсор поверх того, что реально под
   ней. Тот же класс дефекта, что и невидимый лайтбокс с реальной
   геометрией — только между кнопкой/панелью открытия, не лайтбоксом.
   display: grid должен работать только когда .ctab открыт. */
/* Явное скрытие обязательно, одного ограничения правила [open] мало: замерено
   при закрытой панели — display оставался block, прямоугольник 100x134 (при
   удвоенном тексте 200x265). Причина: элементу когда-либо задавали явный
   display, и браузер выводит такой элемент из-под родного скрытия закрытого
   <details> насовсем, даже когда правило с этим значением уже не совпадает. */
.ctab__panel { display: none; }
.ctab[open] .ctab__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  min-width: 11rem;
  display: grid;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: var(--rad);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
}
.ctab__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.06em;
  border-bottom: 1px solid var(--line);
}
.ctab__panel a:last-child { border-bottom: 0; color: var(--deep); }
.ctab__panel a:hover { background: var(--bg); color: var(--ink); text-decoration: underline; }

@media (max-width: 420px) {
  .hdr { padding: 0 var(--s-4); }
  .hdr__brand { font-size: 1rem; }
  .ctab__btn { padding: 0 var(--s-4); font-size: 0.68rem; }
}

/* ==== Кадры: единый компонент на всю страницу ============================
   Одна и та же кнопка используется и для больших фото внутри рассказа,
   и для маленьких миниатюр в закрывающей галерее — весь `<main>` целиком
   является ОДНОЙ группой лайтбокса (data-lb-group на #main), поэтому
   стрелками можно пролистать все фотографии эссе подряд, в порядке чтения.
   ========================================================================= */

.frame {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  text-align: left;
  border-radius: var(--rad);
  overflow: hidden;
}
.frame__img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform var(--dur-slow) var(--ease);
}
.frame:hover .frame__img,
.frame:focus-visible .frame__img { transform: scale(1.015); }

.frame--hero {
  aspect-ratio: 4 / 5;
  box-shadow: var(--shadow-lift);
}
/* Проценты по высоте у <img> разрешаются только если у его containing
   block (здесь — <picture>) есть ЯВНАЯ высота; иначе height:100% тихо
   игнорируется и обрезки не происходит. Растягиваем picture тоже. */
.frame--hero picture { display: block; height: 100%; }
.frame--hero .frame__img {
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
}

.frame--inline + .frame--inline { margin-top: var(--s-5); }

/* p732733315 — единственный кадр пула, чей исходник (640×1136 c камеры,
   Instagram больше не отдаёт) на любой плотной мобильной матрице мягче
   соседних кадров: под 350 CSS-пикселей нужен файл от ~700px, а больше
   400 не выжать без апскейла (build-images.py намеренно не апскейлит).
   Замены той же смысловой роли (лавандовое поле) в пуле нет — весь пул
   проверен по contact-sheet-{all,}.jpg, второго такого кадра нет.
   Решение — не растягивать кадр крупнее, чем 400px реально тянут на
   удвоенной плотности (200 CSS px), а не мириться с мягкостью: другой
   кадр в этом же абзаце заметно крупнее, но это дешевле нерезкости.
   Чёрные полосы леттербокса, которые раньше прятали здесь через
   aspect-ratio/object-fit, обрезаны у самого исходника (design/project/
   assets/photos/732733315_…) — они пропали и из лайтбокса тоже, отдельный
   crop-класс для инлайна больше не нужен. */
.frame--small { max-width: 200px; margin-inline: auto; }

/* Подпись под фотографией — как рукописный кэпшн, а не наклейка поверх
   картинки: это тише, чем оверлей-подпись в других вариантах. */
.frame__cap {
  display: block;
  margin-top: var(--s-3);
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--t-small);
  color: var(--soft);
}

/* ==== Открытие ============================================================ */

.opening { max-width: 46rem; text-align: center; }
.opening__quote {
  font-size: var(--t-small);
  letter-spacing: 0.04em;
  color: var(--soft);
  max-width: 34ch;
  margin-inline: auto;
}
.opening__quote-src {
  display: inline-block;
  margin-top: var(--s-2);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
}
.opening h1 { font-size: var(--t-h1); max-width: 14ch; margin-inline: auto; }
.opening .lead { font-size: var(--t-lead); max-width: 58ch; margin-inline: auto; text-align: left; }
/* Единственная уступка тем, кто пришёл по ссылке из Telegram за ценой, а не
   за рассказом целиком: тихая строка сразу в открытии, а не полноценное
   меню — иначе вариант перестаёт быть цельным письмом от первого лица и
   становится такой же витриной, как A/B/C. */
.opening__jump { max-width: 58ch; margin: var(--s-3) auto 0; font-size: var(--t-small); color: var(--soft); }

/* ==== Привет / приглашение ================================================ */

.story { text-align: left; }
.story .frame--inline { max-width: 30rem; margin-inline: auto; }

.facets {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-6);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}
.facets li { display: contents; }
.facets a {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-height: var(--tap);
  justify-content: center;
  text-align: center;
}
.facets em {
  font-family: var(--serif);
  font-size: 1.3rem;
  color: var(--deep);
  font-style: italic;
}
.facets span { font-size: var(--t-small); color: var(--soft); }

@media (max-width: 480px) {
  .facets { gap: var(--s-4); }
}

/* ==== Главы (Море / Поля / Люди / Несебр / Прайс / Вопросы / Галерея) ===== */

.chapter__eyebrow {
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--soft);
}
.chapter h2 { font-size: var(--t-h2); }
.chapter h3 {
  font-size: var(--t-h4);
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.chapter h3 .num {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  color: var(--deep);
}
.chapter__sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--t-lead);
  color: var(--soft);
}
.chapter p { color: var(--ink); }

.ig-quote {
  margin: 0;
  padding: var(--s-5) var(--s-6);
  border-left: 3px solid var(--accent);
  background: var(--bg2);
  border-radius: 0 var(--rad) var(--rad) 0;
}
.ig-quote p {
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--t-lead);
  line-height: 1.5;
  color: var(--ink);
}
.ig-quote cite {
  display: block;
  margin-top: var(--s-3);
  font-style: normal;
  font-size: var(--t-small);
  letter-spacing: 0.06em;
  color: var(--soft);
}

/* ==== Манифест (пауза посреди рассказа) =================================== */

.manifesto {
  padding: clamp(3.5rem, 10vh, 6rem) var(--gut);
  display: flex;
  justify-content: center;
  background: var(--bg2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.manifesto p {
  font-family: var(--serif);
  font-size: clamp(1.35rem, 2.6vw, 2rem);
  line-height: 1.45;
  max-width: 30ch;
  text-align: center;
  text-wrap: balance;
}

/* ==== Прайс — честный ответ внутри текста, не карточки-витрина =========== */

.tier { padding-top: var(--s-3); border-top: 1px solid var(--line); }
.tier h3 { justify-content: space-between; font-size: var(--t-h4); }
.tier__sum {
  font-family: var(--serif);
  color: var(--deep);
  white-space: nowrap;
}
.tier__sum strong { font-weight: 600; }

.plain-h3 {
  font-size: var(--t-h4);
  font-weight: 600;
  font-family: var(--sans);
  padding-bottom: var(--s-2);
  border-bottom: 2px solid var(--deep);
}
.plain-list li {
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--line);
  display: flex;
  gap: var(--s-3);
}
.plain-list li::before { content: "·"; color: var(--accent); font-weight: 600; }
.fine { font-size: var(--t-small); color: var(--soft); font-style: italic; }

.chapter--price .btn { margin-top: var(--s-3); }

/* ==== Вопросы ============================================================= */

.faq__list { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.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(--accent);
  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); }

/* ==== Закрывающая галерея — тихая, не витрина ============================= */

.chapter--gallery { max-width: 60rem; }
.chapter--gallery h2,
.chapter--gallery .chapter__eyebrow,
.chapter--gallery .hint { max-width: 40rem; margin-inline: auto; text-align: center; }
.hint { color: var(--soft); font-size: var(--t-small); }

.frames-grid {
  display: grid;
  /* min(9rem, 100%) — тот же приём, что уже стоит на всех auto-fit/auto-fill
     сетках A/B/C: голый minmax(9rem, 1fr) не уменьшается вслед за
     контейнером, если 9rem (на 200% масштабе — 288px) сам по себе шире
     доступной ширины, и тогда одна-единственная колонка раздвигает сетку
     за край экрана. min(...,100%) отдаёт трек либо 9rem, либо всю
     доступную ширину — какая меньше. */
  grid-template-columns: repeat(auto-fill, minmax(min(9rem, 100%), 1fr));
  gap: var(--s-4);
  margin-top: var(--s-6);
}
.frame--thumb .frame__cap { font-size: 0.78rem; }

/* ==== Финал ================================================================ */

.finale { text-align: center; padding-top: clamp(3rem, 8vw, 5rem); padding-bottom: clamp(3rem, 8vw, 5rem); }
.finale h2 { font-size: var(--t-h2); }
.finale p { color: var(--soft); margin-top: var(--s-3); }
.finale__channels {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-3);
  margin-top: var(--s-6);
}
.btn--ghost { border-color: var(--deep); color: var(--deep); }
.btn--ghost:hover { background: var(--deep); color: var(--ondeep); }

@media (max-width: 480px) {
  .finale__channels .btn { flex: 1 1 100%; }
}

/* ==== Подвал ================================================================ */

.foot {
  text-align: center;
  padding: var(--s-8) var(--gut);
  background: var(--bg2);
  border-top: 1px solid var(--line);
}
.foot__brand { font-family: var(--serif); font-size: 1.4rem; color: var(--ink); }
.foot__brand em { color: var(--deep); }
.foot__where { color: var(--soft); font-size: var(--t-small); margin: var(--s-2) 0 var(--s-5); }
.foot__links { display: flex; gap: var(--s-5); justify-content: center; flex-wrap: wrap; }
.foot__links a {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ==== Баннер-поздравление ================================================
   В потоке документа сразу под шапкой — раздвигает текст вниз вместо того,
   чтобы лечь поверх него (шапка и так фиксированная, второй слой поверх
   первого экрана здесь ни к чему). Никогда не перекрывает лайтбокс
   (z-index 100 у .lb, у баннера обычный поток, z-index не нужен).
   ========================================================================= */

.bday {
  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;
}
.bday[hidden] { display: none; }
.bday__text { font-family: var(--serif); font-size: 0.96rem; line-height: 1.25; color: var(--ink); }
.bday__heart { color: var(--accent); }
.bday__heart svg { width: 0.85em; height: 0.85em; vertical-align: -0.08em; fill: currentColor; }
.bday__close { flex: none; background: none; border: 0; color: var(--soft); font-size: 1rem; cursor: pointer; border-radius: 50%; }
.bday__close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; display: block; }
.bday__close:hover { color: var(--ink); }

@media (max-width: 520px) {
  .bday__text { font-size: 0.86rem; }
}
