/* ============================================================
   «ГРАНЬ» — переключатель аудиторий (компаниям / себе)
   Общий файл для главной (SPA) и двух хабов-дверей.

   Палитра и типографика бренда — целиком с fallback-значениями,
   чтобы стили работали и на styles.css, и на CSS лендингов.

   Два состояния кристалла:
     1) SVG — ПЕРВОЕ И ОСНОВНОЕ. Он лежит прямо в разметке
        (в app.js и в обоих хабах), поэтому виден в том же кадре,
        что и сам переключатель. Никакого «пустого слота».
     2) canvas (Three.js) — подмена поверх SVG кросс-фейдом
        ~200 мс, когда WebGL готов. Размер слота не меняется:
        SVG и canvas стоят в одной ячейке грида.

   Важно про движение: у SVG НЕТ анимации, которая двигает сам камень
   (наклон/масштаб/поворот). Иначе в момент подмены силуэты не совпали бы
   и камень «прыгал». «Живость» SVG даёт только свет: дыхание гало,
   пробегающий блик и мерцание искр — ровно то же, что делает WebGL.
   ============================================================ */

/* ---------- сам переключатель ---------- */
.prism-switch{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 6px;border:1.5px solid var(--line,#e4e2d5);border-radius:99px;
  background:var(--surface,#fff);
  font-family:'Onest',-apple-system,'Segoe UI',Roboto,sans-serif;
  flex:none;
}
.prism-opt{
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 12px;border-radius:99px;
  font-size:13px;font-weight:600;line-height:1.1;white-space:nowrap;
  color:var(--ink2,#555349);text-decoration:none;
  transition:background .2s,color .2s;
}
.prism-opt:hover{color:var(--pine,#0e4a38)}
.prism-opt.is-active{background:var(--pine,#0e4a38);color:#fff}
.prism-opt.is-active:hover{color:#fff}
.prism-opt:focus-visible{outline:2px solid var(--emerald,#06d6a0);outline-offset:2px}

/* ---------- слот кристалла ----------
   SVG и canvas живут в одной ячейке грида: подмена не двигает
   ни подписи, ни саму пилюлю переключателя. */
.prism-art{
  position:relative;display:inline-grid;place-items:center;
  width:44px;height:44px;flex:none;
}
.prism-art>*{grid-area:1/1;width:100%;height:100%;display:block;position:relative;z-index:1}
/* гало под камнем — общее для SVG и canvas: оно не часть картинки, поэтому
   при подмене не может ни исчезнуть, ни сдвинуться */
.prism-art::before{
  content:'';position:absolute;left:50%;top:52%;width:66%;height:62%;
  transform:translate(-50%,-50%);border-radius:50%;z-index:0;
  background:radial-gradient(circle at 50% 46%,
    rgba(242,255,207,.85) 0%,rgba(6,214,160,.45) 45%,rgba(6,214,160,0) 100%);
  pointer-events:none;
}
.prism-art.is-clickable{cursor:pointer}
.prism-canvas{opacity:0;transition:opacity .2s ease-out}
.prism-svg{opacity:1}
.prism-art.is-gl .prism-canvas{opacity:1}
.prism-art.is-gl .prism-svg{opacity:0}
/* после кросс-фейда SVG уходит из потока отрисовки, но остаётся в DOM:
   если контекст потеряется, вернуть его обратно — это одна строка */
.prism-art.is-gl .prism-svg{visibility:hidden;transition:opacity .2s ease-out,visibility 0s linear .2s}

/* страховочный слот (switch-prism.js, stubSlot): нужен только чтобы mountFly()
   не отказался лететь, пока главная SPA ещё не отрисовала шапку. Ничего не
   рисует и НЕ участвует в снимке: собственное имя view-transition-name у него
   отнято, иначе два элемента с именем prism-art отменили бы сам переход. */
.prism-art-stub{display:none;view-transition-name:none}

/* ---------- живой отклик SVG (только свет, без геометрии) ---------- */
.prism-svg .prism-glint{opacity:0}
.prism-svg .prism-spark{transform-box:fill-box;transform-origin:50% 50%}
@media (prefers-reduced-motion:no-preference){
  .prism-art::before{animation:prism-halo 6.4s ease-in-out infinite}
  .prism-svg .prism-core{animation:prism-core 6.4s ease-in-out infinite}
  /* блик проходит по камню раз в ~4,2 с — тот же ритм, что у автоблика в WebGL */
  .prism-svg .prism-glint{animation:prism-run 4.2s cubic-bezier(.35,0,.65,1) infinite}
  .prism-svg .prism-spark{animation:prism-twinkle 3.4s ease-in-out infinite}
  .prism-svg .prism-spark:nth-of-type(2){animation-delay:1.15s}
  .prism-svg .prism-spark:nth-of-type(3){animation-delay:2.3s}
  /* курсор на камне — быстрый блик, как glint() у canvas */
  .prism-art.is-hover .prism-svg .prism-glint{animation:prism-run 1.3s linear infinite}
  .prism-art.is-hover .prism-svg .prism-spark{animation:prism-twinkle 1.1s ease-in-out infinite}
  /* «взмах грани» — запасной переход там, где нет View Transitions */
  .prism-svg.is-spinning .prism-svg-g{animation:prism-spin .46s cubic-bezier(.22,.8,.28,1)}
  .prism-svg.is-spinning .prism-glint{animation:prism-run .46s cubic-bezier(.22,.8,.28,1)}
}
@keyframes prism-halo{
  0%,100%{opacity:.72;transform:translate(-50%,-50%) scale(1)}
  50%{opacity:.95;transform:translate(-50%,-50%) scale(1.06)}
}
@keyframes prism-core{
  0%,100%{opacity:.62}
  50%{opacity:1}
}
@keyframes prism-run{
  0%{opacity:0;transform:translateX(-15px)}
  8%{opacity:1}
  26%{opacity:1;transform:translateX(14px)}
  34%{opacity:0;transform:translateX(15px)}
  100%{opacity:0;transform:translateX(15px)}
}
@keyframes prism-twinkle{
  0%,100%{opacity:.55;transform:scale(.86)}
  45%{opacity:1;transform:scale(1.12)}
}
@keyframes prism-spin{
  from{transform:rotate(0deg) scale(1)}
  55%{transform:rotate(150deg) scale(1.14)}
  to{transform:rotate(180deg) scale(1)}
}

/* ============================================================
   Переход «грань поворачивается»
   ------------------------------------------------------------
   Основной путь — кросс-документный View Transition: страницы
   поворачиваются в объёме встречным движением, кристалл вылетает
   из шапки в центр кадра, растёт, оборачивается вокруг своей оси
   и садится на место в новом документе. Оверлея нет: снимки
   делает браузер, ждать загрузку документа не нужно.

   Почему летит ОТДЕЛЬНЫЙ крупный кристалл, а не сам слот:
     снимок элемента во View Transition — растровая картинка размером
     с его коробку. Слот в шапке — 44 px (34 px на телефоне), а в
     середине полёта камень показывается в ~7 раз крупнее: браузер
     растягивает 44-пиксельный растр, и грани расплываются.
     Поэтому в новом документе на pagereveal дорисовывается
     .prism-fly — ровно та же огранка, но векторная и сразу 320 px;
     снимок получается крупным, а дальше его только УМЕНЬШАЮТ
     (от 320 px до 44 px и назад) — уменьшение растр не мылит.
     Сам слот при этом никуда не летит: canvas в шапке не подменяется
     и не мигает.
   ============================================================ */
@view-transition{navigation:auto}

/* штатный слот сохраняет ИМЯ: это вырезает кристалл из снимков страниц,
   чтобы в шапке не оставалась «копия», пока летит .prism-fly (см. html.vt-fly ниже).
   Заголовок страницы морфится как обычно. */
.prism-art{view-transition-name:prism-art}
.prism-title{view-transition-name:prism-title}

/* Пока работает отдельный летящий камень, штатные снимки кристалла не показываем:
   единственный камень на экране — .prism-fly.
   Селектор НЕ привязан к html: ::view-transition-old/new — это псевдоэлементы
   дерева перехода, а не потомки <html>, поэтому html.vt-fly ::view-transition-*(prism-art)
   не совпадал никогда (замер: правило с префиксом не матчится, без префикса — работает).
   Гейт по классу тут и не нужен: снимок кристалла нужен ровно тогда, когда летит
   .prism-fly, а при prefers-reduced-motion все анимации перехода и так выключены
   (см. блок reduce-motion ниже). */
::view-transition-old(prism-art),
::view-transition-new(prism-art){animation:none;opacity:0}

/* ---------- летящий кристалл ----------
   320 px по стороне: в середине полёта он показывается в масштабе ~1,
   то есть растр снимка никогда не растягивается больше 1:1.
   --prism-fly-k — масштаб «камня в покое»: 44/320 (34/320 на телефоне). */
.prism-fly{
  position:fixed;left:0;top:0;width:320px;height:320px;
  display:grid;place-items:center;pointer-events:none;
  --prism-fly-k:.1375;
  view-transition-name:prism-fly;
}
.prism-fly>*{grid-area:1/1;width:100%;height:100%;display:block;position:relative;z-index:1}
.prism-fly::before{
  content:'';position:absolute;left:50%;top:52%;width:66%;height:62%;
  transform:translate(-50%,-50%);border-radius:50%;z-index:0;
  background:radial-gradient(circle at 50% 46%,
    rgba(242,255,207,.85) 0%,rgba(6,214,160,.45) 45%,rgba(6,214,160,0) 100%);
  pointer-events:none;
}

html{--vt-dir:1;                        /* 1 — вперёд (в хаб), -1 — назад (на главную) */
  /* полёт кристалла: смещение от слота к центру экрана и поправка на посадку.
     Значения по умолчанию — приблизительно (переключатель живёт в шапке),
     switch-prism.js пересчитывает их на pagereveal от центра слота; переход
     обязан летать и без этого, поэтому запас есть всегда. */
  --prism-fx:6vw;
  --prism-fy:calc(47vh - 24px);
  --prism-dx:0px;
  --prism-dy:0px;
}
html.vt-prev{--vt-dir:-1}

/* ---- страницы: не кросс-фейд, а поворот в объёме ---- */
::view-transition-old(root),
::view-transition-new(root){
  mix-blend-mode:normal;               /* иначе plus-lighter и белая вспышка */
  transform-origin:50% 50%;
  animation-duration:.62s;
  animation-timing-function:cubic-bezier(.22,.8,.28,1);
  animation-fill-mode:both;
  backface-visibility:hidden;
}
::view-transition-old(root){animation-name:prism-page-out}
::view-transition-new(root){animation-name:prism-page-in}
/* --vt-dir = 1 вперёд (к «себе»/в хаб), -1 назад: поворот в другую сторону */
@keyframes prism-page-out{
  from{transform:perspective(1500px) translateZ(0) rotateY(0deg);opacity:1}
  to{transform:perspective(1500px) translateZ(-170px) rotateY(calc(var(--vt-dir,1) * 24deg));opacity:0}
}
@keyframes prism-page-in{
  from{transform:perspective(1500px) translateZ(-170px) rotateY(calc(var(--vt-dir,1) * -24deg));opacity:0}
  to{transform:perspective(1500px) translateZ(0) rotateY(0deg);opacity:1}
}

/* ---- кристалл: полёт из шапки в центр кадра и обратно ----
   Коробка группы стоит сразу на месте слота: у летящего кристалла нет
   «старой» стороны (в предыдущем документе его не было), поэтому по
   умолчанию браузер ничего не интерполирует, а движение задаёт снимок.
   Два независимых твига — перенос+масштаб и поворот: только так поворот
   может идти своей скоростью и не дёргаться при смене фаз.
   Полёт: короткий «вдох» (9%) → разгон и рост к центру (46%) →
   возврат с длинным выбегом (92%) → досыпание на место (100%). */

/* группа — z-index и «посадка на поправку»: смещение, которое
   switch-prism.js считает уже по устоявшейся вёрстке нового документа.
   До 44% анимация держит ноль (fill both + задержка), поэтому уточнения,
   приходящие в первые сотни миллисекунд, не дают рывка. */
::view-transition-group(prism-fly){
  z-index:6;                            /* над обеими страницами */
  animation:prism-fly-land .30s cubic-bezier(.16,1,.3,1) .30s both;
}
::view-transition-new(prism-fly){
  transform-origin:50% 50%;
  animation:
    prism-fly-move .68s cubic-bezier(.22,.68,.3,1) both,
    prism-fly-spin .68s cubic-bezier(.5,.05,.2,1) both;
}
@keyframes prism-fly-land{
  from{translate:0 0}
  to{translate:var(--prism-dx,0px) var(--prism-dy,0px)}
}
/* --prism-fx/--prism-fy — смещение от центра слота до центра экрана,
   их считает switch-prism.js на pagereveal */
@keyframes prism-fly-move{
  0%{translate:0 0;scale:var(--prism-fly-k,.1375);animation-timing-function:cubic-bezier(.45,0,.55,1)}
  9%{translate:calc(var(--prism-fx,0px) * .03) calc(var(--prism-fy,0px) * .03);scale:calc(var(--prism-fly-k,.1375) - .02);animation-timing-function:cubic-bezier(.22,.68,.3,1)}
  46%{translate:var(--prism-fx,0px) var(--prism-fy,0px);scale:calc(var(--prism-fly-k,.1375) * 7.4);animation-timing-function:cubic-bezier(.16,1,.3,1)}
  92%{translate:0 0;scale:calc(var(--prism-fly-k,.1375) * .9);animation-timing-function:cubic-bezier(.3,0,.2,1)}
  100%{translate:0 0;scale:var(--prism-fly-k,.1375)}
}
@keyframes prism-fly-spin{
  0%{rotate:0deg;animation-timing-function:cubic-bezier(.45,0,.55,1)}
  9%{rotate:calc(var(--vt-dir,1) * -14deg);animation-timing-function:cubic-bezier(.5,.05,.2,1)}
  100%{rotate:calc(var(--vt-dir,1) * 360deg)}
}
::view-transition-group(prism-title){
  animation-duration:.62s;
  animation-timing-function:cubic-bezier(.22,.8,.28,1);
}

/* ---------- fallback: быстрый «взмах грани» ----------
   Показывается только там, где кросс-документных View Transitions
   нет. Навигация стартует СРАЗУ: оверлей живёт 220 мс и к концу
   анимации полностью прозрачен, поэтому он не может «висеть»,
   пока грузится следующий документ. Углы и длительность — те же,
   что у 3D-перехода (24° наклона, .62s общего хода, .46s сам взмах). */
.prism-swipe{position:fixed;inset:0;z-index:9999;pointer-events:none;overflow:hidden;
  perspective:1500px}
.prism-swipe .shard{
  position:absolute;left:var(--sx,50%);top:var(--sy,50%);
  width:var(--sw,60vmax);height:var(--sw,60vmax);
  margin-left:calc(var(--sw,60vmax) / -2);margin-top:calc(var(--sw,60vmax) / -2);
  clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%);
  opacity:0;will-change:transform,opacity;transform-origin:50% 50%;
}
.prism-swipe .shard.s1{background:linear-gradient(135deg,rgba(233,255,150,.95) 0%,#06d6a0 30%,#0e4a38 68%,rgba(14,74,56,0) 100%)}
.prism-swipe .shard.s2{background:linear-gradient(135deg,rgba(6,214,160,.75) 0%,#0e4a38 52%,rgba(7,42,31,0) 100%)}
@media (prefers-reduced-motion:no-preference){
  .prism-swipe .shard{animation:prism-shard .46s cubic-bezier(.22,.8,.28,1) both}
  .prism-swipe .shard.s2{animation-duration:.5s;animation-delay:.03s}
  .prism-swipe .shard.s3{animation-duration:.54s;animation-delay:.06s}
}
@keyframes prism-shard{
  0%{opacity:0;transform:rotate(var(--sr,0deg)) rotateY(0deg) scale(.05)}
  35%{opacity:.72}
  100%{opacity:0;transform:rotate(calc(var(--sr,0deg) + var(--sturn,26deg))) rotateY(24deg) scale(1.06)}
}
.prism-swipe .shard.s1{--sr:0deg;--sturn:24deg}
.prism-swipe .shard.s2{--sr:60deg;--sturn:-34deg}
.prism-swipe .shard.s3{--sr:-35deg;--sturn:38deg}

/* ---------- появление страницы после перехода ----------
   Чистый CSS: стартует с первым кадром, поэтому шва между
   переходом и хабом не видно. При reduce — не анимируем вообще.
   Когда работает View Transition, вход гасят: страницы поворачиваются
   сами, вторая анимация на .wrap их бы дёргала. Класс .vt-live ставит
   switch-prism.js на pagereveal — до первого рендера нового документа.
   Важно: гашение — только страховка на случай, если скрипт опоздал.
   Документ, пришедший переходом, вообще теряет .prism-enter
   (dropEnterFade в switch-prism.js): если оставить класс, гашение
   снимается ровно в момент окончания перехода, анимация стартует заново
   с opacity:0 — и это читается как вспышка при перезагрузке страницы. */
@media (prefers-reduced-motion:no-preference){
  .prism-enter .wrap{animation:prism-enter .5s cubic-bezier(.22,.8,.28,1) both}
}
html:active-view-transition .prism-enter .wrap,
html.vt-live .prism-enter .wrap{animation:none}
@keyframes prism-enter{
  from{opacity:0;transform:translateY(9px) scale(.996)}
  to{opacity:1;transform:none}
}

/* ---------- мобильные ---------- */
@media (max-width:640px){
  .prism-switch{gap:3px;padding:3px 5px}
  .prism-opt{padding:6px 9px;font-size:11.5px}
  .prism-art{width:34px;height:34px}
  /* камень в покое — 34 px, поэтому «приземление» идёт в тот же масштаб */
  .prism-fly{--prism-fly-k:.10625}
}

/* ---------- печать ---------- */
@media print{
  .prism-switch{display:none!important}
  .prism-swipe{display:none!important}
}

/* ---------- reduce-motion: переход мгновенный ---------- */
@media (prefers-reduced-motion:reduce){
  .prism-swipe{display:none}
  .prism-canvas{transition:none}
  .prism-svg .prism-glint{opacity:0}
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){animation:none!important}
}
