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

:root {
  /* Фон — чистый чёрный: работы висят в пустоте, а не на подложке.
     Карточка на чёрном отделена собственной рамкой (см. scene.css). */
  --bg: #000;
  --fg: #fff;
  --fg-dim: #8a8880;
  --fg-mute: #4e4c48;

  /* Шкала кеглей визитки. Ступеней ПЯТЬ, и это потолок: их было
     восемь, причём три соседние (15.6, 14.4, 14 на телефоне)
     различались на пиксель — глаз такую разницу не читает как ступень,
     только как неряшливость набора. Каждая ступень тут отличается от
     соседней заметно, и любой новый текст обязан взять одну из них,
     а не завести свою.

       fs-1  имя автора
       fs-2  «Контент-маркетинг», «Работал с:» — разделы страницы
       fs-3  название заказчика
       fs-4  весь остальной текст: описания, подписи, плашки, перечни,
             род деятельности, кнопка «Работы»

     Четвёртая — рабочая: ею набрано почти всё, и три верхние только
     расставляют над ней заголовки. Ступени между fs-4 и заголовками
     нет намеренно: она была (16px против 15px на десктопе, 14 против
     13.3 на телефоне) и не работала — разница меньше пикселя читается
     не как ранг, а как сбой набора. Либо заметно крупнее, либо так же.

     Строка контактов набрана мельче (11–13px, base.css): она не часть
     текста страницы, а служебная строка поверх него. */
  --fs-1: clamp(30px, 8.5vw, 52px);
  --fs-2: clamp(24px, 6.5vw, 36px);
  --fs-3: clamp(20px, 5.4vw, 27px);
  --fs-4: clamp(13px, 3.4vw, 15px);

  --pad: clamp(16px, 3.2vw, 34px);
  /* Высота кнопки чата: 10px паддинга сверху и снизу, строка 1.2em при
     13px кегля, рамка 1px с каждой стороны. И высота строки контактов —
     13px кегля без межстрочного запаса. Держим числами, потому что по ним
     выравнивается пара «контакты — кнопка чата» (см. .contacts ниже). */
  --chat-btn-h: 38px;
  --contacts-line-h: 14px;
  /* Общий нижний отступ для пары «контакты — кнопка чата». Обе величины
     обязаны считаться от одного значения, иначе они разъезжаются. */
  --pad-bottom: max(var(--pad), env(safe-area-inset-bottom));
  /* Сколько низа занимает закреплённая строка контактов. Список и услуги
     прокручиваются под ней, и без этого запаса последняя строка текста
     уезжала бы ровно ей под низ. Считается от того же --pad-bottom, что и
     сама строка: её отступ снизу плюс высота плюс воздух над текстом. */
  --contacts-clear: calc(var(--pad-bottom) + var(--chat-btn-h) + 12px);
  /* Inter — основная гарнитура сцены. Подключена локально (css/fonts.css),
     системный стек остаётся запасным на время загрузки шрифта. */
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;              /* прокрутка страницы — это зум сцены */
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

/* Сцену таскают мышью, и любое перетаскивание выделяло бы текст и картинки
   под курсором. Выделять здесь нечего — это не документ, а пространство.
   Исключение — лайтбокс: там текст можно скопировать. */
body {
  user-select: none;
  -webkit-user-select: none;
}
.lb-content {
  user-select: text;
  -webkit-user-select: text;
}

body {
  opacity: 0;
  transition: opacity .5s ease;
}
body.is-ready { opacity: 1; }

button { font: inherit; color: inherit; }

::selection { background: var(--fg); color: var(--bg); }

/* Шапки с надписью «arkheya» больше нет: имя автора написано в самой
   сцене — крупным ярлыком в центре композиции. Дублировать его в углу
   значило спорить с этим ярлыком за ту же роль. */

/* Подсказки «скролл — вглубь · тянуть — вбок» больше нет: сцена читается
   сама, а надпись объясняла то, что зритель и так делает первым же
   движением. */

/* ── контакты ────────────────────────────────────────────────────────
   Стоят в неподвижном углу, а не в ярлыке автора: ярлык живёт в сцене
   и уезжает с камерой, а адрес, который уплыл от зрителя, бесполезен.
   Левый угол свободен — чат стоит справа. */
.contacts {
  position: fixed;
  left: var(--pad);
  /* Выравнивание с кнопкой чата (#chat в chat.css).
     Оба элемента прижаты к низу одним отступом, но кнопка выше строки на
     свои паддинги и рамку: её низ оказывался на 44 px ниже строки, и пара
     читалась как случайно рассыпавшаяся. Поднимаем строку на половину
     разницы высот — совпадают не низы, а оптические оси, что глаз и
     считает «на одной линии».

     Отступ повторяет формулу #chat дословно (--pad-bottom), а не пишет
     свою: env(safe-area-inset-bottom) внутри #stage и снаружи разрешается
     по-разному, и две «одинаковые» записи давали 60 px против 16 px.
     Один токен на оба элемента исключает такое расхождение. */
  bottom: calc(var(--pad-bottom)
               + (var(--chat-btn-h) - var(--contacts-line-h)) / 2);
  /* Выше списка и услуг (z-index 40 в list.css) и ниже чата с лайтбоксом.
     Строка одна на все три вида — она лежит снаружи #stage (см. index.html),
     иначе её накрывал бы чёрный лист списка.

     Собственный стекающий контекст инверсии не мешает: смешивание идёт
     не с фоном самой строки, а с тем, что нарисовано под ней в корневом
     контексте — с листом списка или с работой сцены (#stage намеренно
     без isolation). Проверено в Chromium и WebKit. */
  z-index: 45;
  font-style: normal;            /* address курсивит по умолчанию */
  font-size: 13px;
  color: var(--fg-dim);
  white-space: nowrap;
  /* Сцену таскают мышью через всё окно; ловить указатель должны только
     сами ссылки, иначе угол экрана перестаёт быть частью пространства. */
  pointer-events: none;
  /* Инверсия относительно подложки, как у ярлыков сцены: на чёрном фоне
     строка белая, на светлой работе — чёрная. Плашка тут стояла раньше
     и была убрана: её край обрывался поперёк карточки. Тень оставлена
     слабой страховкой на среднесерых кадрах, где exclusion даёт тот же
     серый и текст пропал бы. */
  mix-blend-mode: exclusion;
  color: #fff;                   /* exclusion считает от белого: инверсия фона */
  /* Собственный composited-слой — ради настоящего Safari: он блендит
     только слой с слоем, и не-композитная строка смешивалась бы с тайлом
     страницы вместо работ под ней (см. tools/SAFARI-BLEND.md).
     Контекст на самом элементе бленду не мешает — мешает контекст
     на предке. Здесь fixed и так делает контекст, слой лишь добавляет
     к нему промоушен в композиторе. */
  transform: translateZ(0);
  text-shadow:
    0 0 3px rgba(0, 0, 0, .35),
    0 0 12px rgba(0, 0, 0, .25);
}
.contacts a {
  pointer-events: auto;
  /* Собственный цвет ссылке не задаём: инверсию считает родитель, а серый
     здесь дал бы грязный оттенок вместо чистого негатива. Приглушает
     строку opacity — она с exclusion работает предсказуемо. */
  color: inherit;
  opacity: .82;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: opacity .2s ease, border-color .2s ease;
  /* адрес и ник нужно уметь выделить и скопировать */
  user-select: text;
  -webkit-user-select: text;
}
.contacts a:hover,
.contacts a:focus-visible { opacity: 1; border-bottom-color: currentColor; }
.contacts-sep { opacity: .5; margin: 0 .45em; }

@media (max-width: 760px) {
  /* Подъёма над чатом здесь больше нет. Он был нужен, потому что
     контейнер #chat тянется во всю ширину и его пустая половина
     перехватывала клики по ссылкам; теперь контейнер прозрачен для
     кликов (pointer-events в chat.css), и контакты стоят на своей линии,
     оптически совпадая с кнопкой. */
  .contacts { font-size: 11px; }
  /* Открытый чат занимает низ целиком — контакты уступают ему место.
     Класс ставит сам чат на <body>: соседним селектором сюда уже не
     дотянуться, контакты переехали внутрь #stage (см. index.html). */
  body.chat-open .contacts { opacity: 0; pointer-events: none; }
}
