/* ==========================================================================
   Иконки Welcome Home. Один файл на все страницы — и статические, и Next.

   Геометрия: сетка 24×24, только обводка currentColor. Иконка берёт цвет,
   толщину и размер от места, куда её поставили, поэтому одна и та же разметка
   живёт и на тёмной афише, и в светлой админке.

   Движение (shape motion): деталь иконки меняет форму или положение в ответ на
   действие — наведение, раскрытие блока, отметку пункта. Само появление иконки
   не анимируется: на странице их десятки, и одновременная «прописка» линий
   читается не как приём, а как сбой отрисовки, да ещё повторяется при каждой
   перерисовке React. Морфинг d() и SMIL не используем: первый работает только
   в Chromium, второй объявлен устаревшим.

   Разметка иконки:
   <svg class="site-icon site-icon--arrow-right" viewBox="0 0 24 24" aria-hidden="true">
     <path class="site-icon__shaft" pathLength="1" d="M4 12h13"></path>
     <path class="site-icon__head" pathLength="1" d="m12 6.5 5.5 5.5-5.5 5.5"></path>
   </svg>
   pathLength="1" оставляем у каждой линии: на нём держатся штриховые движения
   (пунктир считается в долях длины пути, а не в пикселях, поэтому одна анимация
   работает на любой кривой).
   ========================================================================== */

.site-icon { width: var(--icon-size,15px); height: var(--icon-size,15px); flex: none; fill: none; stroke: currentColor; stroke-width: var(--icon-stroke,1.8); stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
/* Обёртки, где раньше стоял символ, часто выстроены по базовой линии текста:
   inline-svg добавил бы под собой место под descender и иконка съехала бы вниз.
   inline-block + vertical-align снимают это и не ломают строку, если иконка
   стоит внутри строчной ссылки. */
.site-icon { display: inline-block; vertical-align: middle; }
/* Части иконки. transform-box: fill-box — чтобы поворот и сдвиг считались от
   собственного центра детали, а не от угла всей сетки 24×24. */
.site-icon > * { stroke-dasharray: 1; stroke-dashoffset: 0; transform-box: fill-box; transform-origin: 50% 50%; }

/* Движение формы (наведение, фокус, отметка) ведёт Motion — motion.dev:
   apps/web/src/lib/icon-motion.ts для Next и icons-motion.js для статических
   страниц. Ключевых кадров здесь больше нет: у @keyframes один маршрут «туда и
   обратно» за фиксированное время, поэтому деталь возвращалась в покой, пока
   курсор всё ещё стоял на кнопке, а уход курсора на середине давал рывок.
   Пружина уезжает и держит положение, а возвращается из того места, где её
   застали. CSS остаётся хозяином геометрии: сдвиг деталей читается из
   --icon-nudge-* ниже. */

/* --- Геометрия движения --------------------------------------------------- */
/* Куда уходит деталь при наведении — в единицах сетки 24×24, поэтому сдвиг
   одинаково выглядит на иконке 12px и на 30px. Значения читает Motion.
   Одного набора хватает на все четыре стрелки, диагональ, рукоять лупы,
   стрелку скачивания, крышку корзины и язычок папки. */
.site-icon--arrow-right { --icon-nudge-x: 2.8px; }
.site-icon--arrow-left { --icon-nudge-x: -2.8px; }
.site-icon--arrow-up { --icon-nudge-y: -2.8px; }
.site-icon--arrow-down { --icon-nudge-y: 2.8px; }
.site-icon--arrow-up-right { --icon-nudge-x: 2.1px; --icon-nudge-y: -2.1px; }
.site-icon--search { --icon-nudge-x: 1.8px; --icon-nudge-y: 1.8px; }
/* Скачивание: стрелка опускается в лоток, сам лоток стоит на месте. */
.site-icon--download { --icon-nudge-y: 2.2px; }
/* Выгрузка — то же движение наоборот: стрелка выходит из лотка вверх. */
.site-icon--upload { --icon-nudge-y: -2.2px; }
/* Корзина: крышка приподнимается. Крышка и ручка для глаза одна деталь, поэтому
   идут без оттяжки — иначе ручка отрывается от крышки (список в icon-motion). */
.site-icon--trash { --icon-nudge-y: -2.4px; }
/* Папка: язычок приоткрывается. */
.site-icon--folder { --icon-nudge-y: -1.6px; }

/* Плей залит: контур на такой мелкой детали читается хуже, чем плотный треугольник. */
.site-icon--play > .site-icon__blade { fill: currentColor; }

/* Плюс, который становится минусом: вертикальная перекладина складывается в ноль.
   Это и есть смена формы — не подмена символа и не поворот на 45°. */
.site-icon--plus > * { transition: transform .26s cubic-bezier(.5,0,.2,1); }
details[open] > summary .site-icon--plus > .site-icon__bar--v,
:where([aria-expanded='true'],.is-open) .site-icon--plus > .site-icon__bar--v,
.site-icon--plus.is-minus > .site-icon__bar--v { transform: scaleY(0); }

/* Петля хлопушки — у левого нижнего угла планки, а не в её центре. */
.site-icon > .site-icon__clap { transform-origin: 6% 100%; }

/* Обработка: кольцо стоит, дуга крутится. Дуге нужен центр всей сетки 24×24, а не
   своей рамки, — иначе она болтается вокруг собственного угла. Бесконечное
   вращение оставлено ключевыми кадрами намеренно: у него нет ни начала, ни конца
   по действию пользователя, и композитор браузера крутит его без участия JS. */
@keyframes wh-icon-spin { to { transform: rotate(360deg); } }
.site-icon > .site-icon__arc { transform-box: view-box; transform-origin: 50% 50%; animation: wh-icon-spin 1.05s linear infinite; }

/* Смена камеры: полукруги ходят вокруг общей оси — центра всей сетки 24×24, а не
   своей рамки, иначе каждая половинка вертелась бы сама по себе. Пол-оборота
   вместо четверти: знак симметричен относительно центра, и по окончании движения
   он совпадает с собой — как крест на своём повороте. */
.site-icon > .site-icon__turn { transform-box: view-box; transform-origin: 50% 50%; }

/* Иконки, которые обязаны остаться псевдоэлементами: точка сигнала, три слэша и
   плюс на плитке галереи стоят в ::before/::after у элементов, куда вложенный узел
   поставить нельзя — их текст перерисовывает JS или он сам и есть содержимое.
   Форма всё равно svg, только приходит маской. */
:root {
  --wh-mask-dot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='7' fill='%23000'/%3E%3C/svg%3E");
  --wh-mask-slashes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 14'%3E%3Cpath d='M4 12 8 2M11 12 15 2M18 12 22 2' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'/%3E%3C/svg%3E");
  --wh-mask-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5v14' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E");
  --wh-mask-arrow-up-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 17 17 7M8.5 7H17v8.5' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.wh-mask { background: currentColor; -webkit-mask: var(--wh-mask) center/contain no-repeat; mask: var(--wh-mask) center/contain no-repeat; }
/* Живой сигнал: точка сжимается и снова набирает размер. */
@keyframes wh-dot-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(.42); } }
/* Слэши подъезжают по одному — маска целиком, поэтому ведём её сдвигом. */
@keyframes wh-slashes-in { from { -webkit-mask-position: -30% center; mask-position: -30% center; opacity: 0; } }

/* Приведённое движение. Ключевые кадры и переходы снимаем здесь, движение
   Motion — в самом рантайме (`icon-motion.ts` / `icons-motion.js`): он при
   таком запросе просто не подписывается на наведение. */
@media (prefers-reduced-motion: reduce) {
  .site-icon > * { animation: none !important; stroke-dashoffset: 0 !important; transition: none !important; }
  .site-icon--play > .site-icon__blade { fill-opacity: 1; }
  .wh-mask { animation: none !important; }
}
