/* ============================================================
   База
   Все размеры в px макета 1073x679 (фигма @2x → делим на 2),
   умножаются на --u, поэтому сцена масштабируется целиком.
   ============================================================ */
:root {
  /* --us: единица сцены (макет 1073x679). --uf: единица интерфейса, у неё есть пол 0.8 px,
     чтобы подписи, навигация и бабл не становились мельче ~12-13 px на телефонах.
     --u по умолчанию равна --us, а у интерфейсных блоков (.ui, .note, .about) переопределена на --uf */
  /* Ширина кадра 860u, а не 1073u: на окнах с пропорциями ближе к квадрату сцена растёт по высоте
     и не оставляет пустого неба сверху. Края сцены (цветы, пчёлы) привязаны к краям окна */
  --vh: 100dvh;
  --home-dy: 0px; /* подъём персонажа на главной у коротких вертикальных экранов, считает main.js; на десктопе всегда 0 */                            /* видимая высота; loader.js уточняет её в px */
  --us0: min(100vw / 860, var(--vh) / 679);   /* базовая единица */
  --us: var(--us0);                        /* единица сцены (на высоких телефонах крупнее базовой) */
  --uf: max(var(--us0), .8px);             /* единица интерфейса */
  --u: var(--us);
  --sat: env(safe-area-inset-top, 0px);
  --sar: env(safe-area-inset-right, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --magenta: #ed00ff;
  --ink: #242524;
  --font-ui: "Inter", system-ui, sans-serif;
  --font-display: "Inter", system-ui, sans-serif;
}

/* Вертикальный экран: сцена по ширине ~640 px макета */
@media (max-aspect-ratio: 1/1) {
  :root {
    --us0: calc(100vw / 640);
    /* Высокий телефон: сцена крупнее, чтобы небо не занимало полэкрана. Кадр не уже 420u */
    --us: max(var(--us0), min(var(--vh) / 900, 100vw / 420));
  }
}

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

html, body {
  margin: 0;
  height: 100%;
  background: #0a28fc;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  /* Запасной курсор, пока не отработал cursor.js */
  cursor: url("assets/cursor-arrow.svg") 4 3, auto;
}

/* Свой курсор (cursor.js): системный прячем */
.has-cursor, .has-cursor * { cursor: none !important; }
.cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2147483000;
  width: 63px; /* было 42px, увеличено в 1.5 раза */
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s;
  will-change: transform;
}
.cursor.is-visible { opacity: 1; }
.cursor__img {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: 14% 3%; /* кончик пальца */
  transition: transform .22s cubic-bezier(.3, 1.6, .5, 1);
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .35));
}
/* Над интерактивным: рука чуть вырастает, поворачивается и «тычет» пальцем */
.cursor.is-hover .cursor__img {
  transform: rotate(-10deg) scale(1.16);
  animation: cursor-poke 1.1s ease-in-out .25s infinite;
}
.cursor.is-down .cursor__img {
  transform: rotate(3deg) scale(.84);
  animation: none;
  transition-duration: .06s;
}
@keyframes cursor-poke {
  0%, 100% { translate: 0 0; }
  50%      { translate: -2.2px -3.7px; }
}

a, button { cursor: url("assets/cursor-hand.svg") 13 4, pointer; }

img { display: block; user-select: none; -webkit-user-drag: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================
   Сцена (всё привязано к низу и центру)
   ============================================================ */
.stage {
  position: relative;
  height: var(--vh);
  overflow: hidden;
  isolation: isolate;
}
.stage > *, .world > * { position: absolute; }

/* Мир: вся сцена главной (небо, поляна, персонаж, пчёлы, бабл). UI лежит рядом, не внутри.
   Переход на другие страницы делает camera.js: слои мира уезжают вниз с разной скоростью
   (--c-near, --c-hill, --c-cloud, --c-sun, --c-sky от 0 до 1), за ними остаётся сплошной фон */
.world {
  position: absolute;
  inset: 0;
}
:root {
  --c-near: 0; --c-hill: 0; --c-cloud: 0; --c-sun: 0; --c-sky: 0;
  /* Полёт вперёд над шаром (contacts), пишет camera.js: --f-near контент главной летит мимо
     камеры, --f-flow трава течёт навстречу, --f-arr антенна поднимается из-за горизонта.
     Все слои главной масштабируются вокруг точки схода (центр горизонта поляны, 379.4u от низа) */
  --f-near: 0; --f-flow: 0; --f-arr: 0;
  --f-s: calc(1 + var(--f-near) * 4);                                  /* масштаб пролетающего слоя */
  --f-fade: clamp(0, calc((var(--f-near) - .2) * 2.6), 1);            /* контент гаснет, когда уже за камерой */
  --f-fadeb: clamp(0, calc((var(--f-near) - .08) * 3), 1);             /* бабл гаснет раньше */
  --f-dip: calc(4 * var(--f-flow) * (1 - var(--f-flow)));              /* горизонт проседает на изгибе шара */
  --f-comp: calc(var(--f-near) * 4 * 190.5 * var(--u));                /* перенос точки масштаба с ног персонажа на горизонт */
  /* Зум к персонажу (about), пишет camera.js: --z-near у персонажа, --z-far у дальних слоёв */
  --z-near: 0; --z-far: 0;
  /* About. Бабл: правый отступ 50u (не залезает на кнопку звука), низ 45.23u как у реплики на главной.
     Ширина до 640u, но на узких окнах уступает место персонажу. Левый край бабла Lp = 100vw - 50u - ширина.
     Персонаж ставится так, чтобы от края ноутбука до малого кружка было 16u, как на главной:
     центр персонажа = Lp - 190u (ноутбук ±92u от центра, кружки 82.3u до бабла, зазор 16u) */
  --about-w: min(calc(640 * var(--uf)), calc(100vw - 422 * var(--uf)));
  --about-m: calc(50 * var(--uf));
  --about-dx: calc(50vw - 240 * var(--uf) - var(--about-w)); /* сдвиг персонажа влево от центра экрана */
  --about-dy: calc(40 * var(--uf));              /* и чуть вниз, чтобы шляпа не упиралась в верх */
  --about-s: .45;                               /* насколько персонаж вырастает: ×1.45 */
  --cam-dist: calc(1.12 * var(--vh)); /* на сколько слой уезжает вниз, чтобы полностью уйти с экрана */
}

/* Небо: ступенчатый градиент (16 одинаковых полос по 26.0u, как в старых играх) высотой 832.7 px макета (416.35u) снимается с эталона по пикселям,
   потому что в Figma поверх него лежит blend-режим. Нижний край на 262.65u выше низа
   сцены, там, где поляна выходит к краям экрана. Выше градиента сплошной цвет верха */
.sky {
  inset: 0;
  /* Отсчёт от низа сцены: ниже 262.65u сплошной низ градиента (он скрыт поляной,
     но не даёт просветов на нестандартных пропорциях), выше 679u сплошной верх */
  background: linear-gradient(
    to top,
    #f7b9b4 0 calc(262.65 * var(--u)),
    #efb7be calc(262.65 * var(--u)) calc(288.67 * var(--u)),
    #daaed1 calc(288.67 * var(--u)) calc(314.69 * var(--u)),
    #c2a2e3 calc(314.69 * var(--u)) calc(340.72 * var(--u)),
    #aa98f2 calc(340.72 * var(--u)) calc(366.74 * var(--u)),
    #938bf7 calc(366.74 * var(--u)) calc(392.76 * var(--u)),
    #7a81f8 calc(392.76 * var(--u)) calc(418.78 * var(--u)),
    #6274f5 calc(418.78 * var(--u)) calc(444.80 * var(--u)),
    #4a68f3 calc(444.80 * var(--u)) calc(470.83 * var(--u)),
    #325ef4 calc(470.82 * var(--u)) calc(496.85 * var(--u)),
    #2154f5 calc(496.85 * var(--u)) calc(522.87 * var(--u)),
    #1c4af6 calc(522.87 * var(--u)) calc(548.89 * var(--u)),
    #1845f8 calc(548.89 * var(--u)) calc(574.91 * var(--u)),
    #1540fa calc(574.91 * var(--u)) calc(600.93 * var(--u)),
    #103afc calc(600.93 * var(--u)) calc(626.96 * var(--u)),
    #0d34fd calc(626.96 * var(--u)) calc(652.98 * var(--u)),
    #0a28fc calc(652.98 * var(--u)) calc(679.00 * var(--u)),
    #0a28fc calc(679 * var(--u))
  );
}

/* Фон страницы projects: ступенчатый градиент от #000 (верх) до #0A28FC (низ), 24 одинаковые
   полосы. Элемент выше экрана на высоту хода камеры, внизу сплошной #0A28FC, который стыкуется
   с верхней полосой неба. Едет вместе с небом (--c-sky): камера уходит вверх, и космос
   заходит сверху */
.space {
  left: 0;
  right: 0;
  top: 0;
  height: var(--cam-dist);
  pointer-events: none;
  translate: 0 calc((var(--c-sky) - 1) * var(--cam-dist));
  background:
    linear-gradient(to bottom,
      #000105 0.0000% 4.1667%,
      #010210 4.1667% 8.3333%,
      #01041a 8.3333% 12.5000%,
      #010625 12.5000% 16.6667%,
      #02082f 16.6667% 20.8333%,
      #02093a 20.8333% 25.0000%,
      #030b44 25.0000% 29.1667%,
      #030c4f 29.1667% 33.3333%,
      #040e59 33.3333% 37.5000%,
      #041064 37.5000% 41.6667%,
      #04126e 41.6667% 45.8333%,
      #051379 45.8333% 50.0000%,
      #051583 50.0000% 54.1667%,
      #06168e 54.1667% 58.3333%,
      #061898 58.3333% 62.5000%,
      #061aa3 62.5000% 66.6667%,
      #071cad 66.6667% 70.8333%,
      #071db8 70.8333% 75.0000%,
      #081fc2 75.0000% 79.1667%,
      #0820cd 79.1667% 83.3333%,
      #0922d7 83.3333% 87.5000%,
      #0924e2 87.5000% 91.6667%,
      #0926ec 91.6667% 95.8333%,
      #0a27f7 95.8333% 100.0000%
    ) 0 0 / 100% var(--vh) no-repeat,
    #0a28fc;
}

/* Солнце: Ellipse 81, 742.83 px (371.4u), верх на 333.4 px. Цвет #ffbf00 в макете
   перекрыт небом, итоговый вертикальный градиент снят с эталона */
.sun {
  left: 50%;
  bottom: calc(140.8 * var(--u));
  width: calc(371.4 * var(--u));
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  background: linear-gradient(to bottom, #ffbf00, #ffffff);
}

/* Параллакс и камера. translate у слоёв складывается из смещения за курсором
   (--px/--py, пишет parallax.js) и ухода камеры (--c-*, пишет camera.js).
   У пчёл сдвигается каждая .bee, а не .bees: иначе контейнер станет слоем и пчёлы
   окажутся под персонажем даже при подлёте. Свойство translate не мешает transform
   и анимациям слоёв */
.sky    { translate: 0 calc(var(--c-sky) * var(--cam-dist)); }
.sun    { translate: calc(var(--px, 0) * -2 * var(--u) + var(--z-far) * var(--about-dx) * .3)  calc(var(--py, 0) * -1 * var(--u) + var(--c-sun) * var(--cam-dist) + var(--z-far) * var(--about-dy) * .3); scale: calc(1 + var(--z-far) * var(--about-s) * .3); transform-origin: 50% calc(323.6 * var(--u)); }
.clouds { translate: calc(var(--px, 0) * -4 * var(--u) + var(--z-far) * var(--about-dx) * .35)  calc(var(--py, 0) * -2 * var(--u) + var(--c-cloud) * var(--cam-dist) + var(--z-far) * var(--about-dy) * .35); scale: calc(1 + var(--z-far) * var(--about-s) * .35); transform-origin: 50% calc(100% - 188.6 * var(--u)); }
.hill, .turf { translate: calc(var(--px, 0) * -7 * var(--u) + var(--z-far) * var(--about-dx) * .6) calc(var(--py, 0) * -3 * var(--u) + var(--c-hill) * var(--cam-dist) + var(--z-far) * var(--about-dy) * .6 + var(--f-dip) * 24 * var(--u)); scale: calc(1 + var(--z-far) * var(--about-s) * .6); transform-origin: 50% calc(190.85 * var(--u)); }
.ground-shadow, .flowers, .hero { translate: calc(var(--px, 0) * -11 * var(--u) + var(--z-near) * var(--about-dx)) calc(var(--py, 0) * -4.5 * var(--u) + var(--c-near) * var(--cam-dist) + var(--z-near) * var(--about-dy) + (1 - var(--z-near)) * var(--home-dy) + var(--f-comp)); opacity: calc(1 - var(--f-fade)); }
.bee { translate: calc(var(--px, 0) * -11 * var(--u) + var(--z-near) * var(--about-dx)) calc(var(--py, 0) * -4.5 * var(--u) + var(--c-near) * var(--cam-dist) + var(--z-near) * var(--about-dy) + (1 - var(--z-near)) * var(--home-dy)); }
.bubble { translate: 0 calc(var(--c-near) * var(--cam-dist)); }
.haha { translate: 0 calc(var(--c-near) * var(--cam-dist) + var(--home-dy)); }
.bubble { scale: var(--f-s); transform-origin: 50% calc(100% - 334.2 * var(--u)); opacity: calc(1 - var(--f-fadeb)); }

/* Зум на about: это смена ракурса камеры, а не отдельные эффекты. Все слои масштабируются
   вокруг одной точки (под ногами персонажа) и сдвигаются влево с коэффициентом глубины:
   персонаж, тень и цветы 1, поляна 0.6, облака 0.35, солнце 0.3, небо стоит на месте.
   Поэтому ближние слои уезжают сильнее дальних, а солнце остаётся на горизонте за поляной.
   Пчёлы на этом экране исчезают, чтобы не мешать тексту */
.hero { scale: calc((1 + var(--z-near) * var(--about-s)) * var(--f-s)); }
.flowers { scale: calc((1 + var(--z-near) * var(--about-s)) * var(--f-s)); transform-origin: 50% calc(100% - 188.6 * var(--u)); }
.ground-shadow { scale: calc((1 + var(--z-near) * var(--about-s)) * var(--f-s)); transform-origin: calc(69.44 * var(--u)) calc(74.02 * var(--u)); opacity: calc(.5 * (1 - var(--f-fade))); }
.bee { opacity: calc(max(0, 1 - var(--z-near) * 3) * (1 - var(--f-fade))); scale: var(--f-s); }

/* Облака */
.clouds { inset: 0; pointer-events: none; }

.cloud {
  position: absolute;
  left: 0;
  bottom: calc(var(--b) * var(--u));
  width: calc(var(--w) * var(--u));
  /* Одна скорость у всех: путь и время общие (от -420u до правого края экрана),
     места на пути разведены отрицательной задержкой через --p */
  --far: calc(420 * var(--u));
  /* позиция в покое (для prefers-reduced-motion) */
  transform: translateX(calc(var(--p) * (100vw + var(--far)) - var(--far)));
  animation: drift 200s linear infinite;
  animation-delay: calc(200s * var(--p) * -1);
  will-change: transform;
}
.cloud img { width: 100%; height: auto; }
.cloud--flip img { transform: scaleX(-1); }

@keyframes drift {
  from { transform: translateX(calc(-420 * var(--u))); }
  to   { transform: translateX(100vw); }
}

/* Поляна: Ellipse 79, 2954.2 x 1517.7 px (1477.1u x 758.85u), центр на нижней кромке.
   Радиальный градиент из макета: центр в 50% / 12.66%, радиус 50.65% по обеим осям.
   Если экран шире макета, эллипс растягивается по ширине (138vw), чтобы края не оголялись */
.hill {
  left: 50%;
  bottom: calc(-379.4 * var(--u));
  width: max(calc(1477.1 * var(--u)), 137.65vw);
  height: calc(758.85 * var(--u));
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(
    ellipse 50.65% 50.65% at 50% 12.66%,
    #42e349 0%,
    #009006 61.06%,
    #000 98.08%
  );
}

/* Текстура травы: тот же эллипс, что у поляны. Плоскость с тайлом наклонена в перспективе,
   поэтому к горизонту крапинки мельчают и сходятся, а маска гасит её к кромке: у земли
   шарообразность поляны остаётся чистой градиентом */
.turf {
  left: 50%;
  bottom: calc(-379.4 * var(--u));
  width: max(calc(1477.1 * var(--u)), 137.65vw);
  height: calc(758.85 * var(--u));
  transform: translateX(-50%);
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 4%, #000 70%);
  mask-image: linear-gradient(to bottom, transparent 4%, #000 70%);
}
.turf::before {
  content: "";
  position: absolute;
  left: -100%;
  width: 300%;
  top: 0;
  height: 1400%;
  background: url("assets/grass-tile.png") 0 0 / calc(220 * var(--u)) auto repeat;
  /* полёт к contacts: плоскость с травой едет на зрителя, шесть тайлов за перелёт */
  background-position-y: calc(var(--f-flow) * 6 * 220 * var(--u));
  transform-origin: 50% 0;
  transform: perspective(calc(520 * var(--u))) rotateX(66deg);
  opacity: .6;
}

/* Тень под персонажем: Ellipse 80, #233c24, 50%, layer blur 25 px (sigma 6.25u) */
.ground-shadow {
  left: calc(50% - 69.44 * var(--u));
  bottom: calc(188.95 * var(--u));
  width: calc(134.15 * var(--u));
  height: calc(73.67 * var(--u));
  border-radius: 50%;
  background: #233c24;
  filter: blur(calc(6.25 * var(--u)));
}

/* ============================================================
   Персонаж
   ============================================================ */
/* Component 6: картинка 2000x2000 показана на 611.7 px, персонаж внутри кадра занимает
   область 349..1635 x 50..1931. Берём именно её: 196.7u шириной, левый край на 99.55u
   левее центра, низ на 188.6u выше низа сцены */
.hero {
  z-index: 3;
  left: calc(50% - 99.55 * var(--u));
  bottom: calc(188.6 * var(--u));
  width: calc(196.7 * var(--u));
  display: grid;
}
.hero__frame { grid-area: 1 / 1; width: 100%; height: auto; }

/* Пауза: персонаж застывает в basic. Класс .is-typing переключает main.js */
.hero__frame--idle { opacity: 1; }
/* Кадры печати не 0, а почти 0: при opacity 0 браузер не растрит и не держит декодированную картинку, и персонаж моргает при первом показе (разница 1/255, не видна) */
.hero__frame--a, .hero__frame--b { opacity: .004; }

/* Печатание: два спрайта попеременно */
.hero.is-typing .hero__frame--idle { opacity: 0; }
.hero.is-typing .hero__frame--a { animation: type-a .32s steps(1, end) infinite; }
.hero.is-typing .hero__frame--b { animation: type-b .32s steps(1, end) infinite; }

@keyframes type-a { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }
@keyframes type-b { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 0; } }

/* Цветы: по три слева и справа. 159.49u (318.97 px макета) в квадрате,
   --x от своего края экрана, --b от низа сцены */
.flowers { inset: 0; pointer-events: none; }
.flower {
  position: absolute;
  z-index: 1;
  bottom: calc(var(--b) * var(--u));
  width: calc(159.49 * var(--u));
  height: auto;
}
.flower--l { left: calc(var(--x) * var(--u)); }
.flower--r { right: calc(var(--x) * var(--u)); }

/* Клик по персонажу: «ha-ha» (Inter Black 100.59 px, 297x122, поворот 30 против часовой,
   центр на (955.5; 368.8) px макета). Стиль как у навигации */
.hero { cursor: url("assets/cursor-hand.svg") 13 4, pointer; -webkit-tap-highlight-color: transparent; }
.hero:focus { outline: none; }
.hero { transform-origin: 50% 100%; transition: transform .22s cubic-bezier(.3, 1.6, .5, 1); }
.hero:active { transform: scale(.985, .97); transition-duration: .06s; }
.haha {
  /* Фразы создаёт main.js на каждый клик. --cx: сдвиг центра от середины экрана (u),
     --rot: наклон в градусах (-30 слева, +30 справа) */
  z-index: 5;
  left: calc(50% + var(--cx, -58.75) * var(--u));
  top: calc(100% - 494.6 * var(--u)); /* от низа сцены, как персонаж: макет 679u, верх 184.4u */
  margin: 0;
  color: var(--magenta);
  font: 900 calc(50.3 * var(--u)) / normal var(--font-display);
  white-space: nowrap;
  -webkit-text-stroke: calc(10.5 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
  transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)) scale(0);
  opacity: 0;
  pointer-events: none;
  animation: haha 1.5s cubic-bezier(.3, 1.5, .5, 1) both;
}
@keyframes haha {
  0%   { transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)) scale(0); opacity: 0; }
  14%  { transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)) scale(1.12); opacity: 1; }
  24%  { transform: translate(-50%, -50%) rotate(calc((var(--rot, -30) - 3) * 1deg)) scale(1); }
  34%  { transform: translate(-50%, -50%) rotate(calc((var(--rot, -30) + 3) * 1deg)) scale(1.05); }
  44%  { transform: translate(-50%, -50%) rotate(calc((var(--rot, -30) - 1) * 1deg)) scale(1); opacity: 1; }
  80%  { transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)) scale(.85); opacity: 0; }
}

/* ============================================================
   Пчёлы
   ============================================================ */
/* .bees сам не создаёт слой: z-index каждой пчелы (его ставит bees.js) сравнивается
   напрямую с персонажем и репликой. Все пчёлы летают в плоскости персонажа, перед ним
   и под репликой, а при подлёте по клику пчела идёт поверх всего (6..9), кроме UI (10) */
.bees { inset: 0; pointer-events: none; }

/* Якорь .bee стоит в точке схода (центр, линия горизонта поляны).
   Позицию, масштаб (глубину) и блюр каждый кадр пишет bees.js в .bee__pos */
.bee {
  position: absolute;
  left: 50%;
  bottom: calc(379 * var(--u));
  width: 0;
  height: 0;
}
.bee__pos {
  position: absolute;
  left: calc(var(--size) * var(--u) / -2);
  top: calc(var(--size) * var(--u) * -.464);
  width: calc(var(--size) * var(--u));
  will-change: transform, filter;
}
.bee__bob { animation: bee-bob var(--bob) ease-in-out infinite; animation-delay: var(--delay); }
/* Пчела летает всё время в своей плоскости (глубина фиксирована), глубину меняет
   только подлёт по клику */
/* Разворот мгновенный: картинка смотрит вправо, scaleX(-1) = летит влево */
.bee__turn.is-left { transform: scaleX(-1); }
/* По пчеле можно кликнуть: она подлетает к экрану */
.bee__img {
  transition: scale .22s cubic-bezier(.3, 1.6, .5, 1);
  width: 100%;
  height: auto;
  pointer-events: auto;
  cursor: url("assets/cursor-hand.svg") 13 4, pointer;
  animation: bee-flutter .11s linear infinite alternate;
}

/* Нажатие: «продавливается» как персонаж */
.bee__img:active { scale: .88; transition-duration: .06s; }

@keyframes bee-bob {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  30%      { transform: translateY(calc(-8 * var(--u))) rotate(2deg); }
  65%      { transform: translateY(calc(4 * var(--u))) rotate(-1deg); }
}
/* Взмах крыльев: едва заметная дрожь картинки */
@keyframes bee-flutter {
  from { transform: scale(1, .988) rotate(-.5deg); }
  to   { transform: scale(1, 1.012) rotate(.5deg); }
}

/* ============================================================
   Реплика
   ============================================================ */
/* .bubble задаёт место и размер, вид самого бабла у .bubble__body,
   поэтому три части (малый круг, большой круг, бабл) появляются по отдельности */
/* Frame 2131328761: 820.9 x 268 px, отступы 50, радиус 50, низ на 45.23u выше низа сцены.
   Обводка #242524 4 px снаружи (в CSS это кольцо box-shadow 2u), тень чёрная,
   y 10 px, blur 20 px, и считается от рамки вместе с обводкой (spread 2u) */
.bubble {
  --step: .2s; /* пауза между частями, в секундах; main.js читает это значение для звуков */
  z-index: 4;
  left: 50%;
  --wb: min(calc(410.45 * var(--u)), calc(100vw - 24px - var(--sal) - var(--sar)));
  width: var(--wb);
  bottom: max(calc(45.23 * var(--u) + var(--sab)), clamp(0px, calc((var(--hit) - 50vw + var(--wb) / 2) * 1000), var(--clr)));
  transform: translateX(-50%);
}
.bubble.is-reset { opacity: 0; }
.bubble__body {
  position: relative;
  padding: calc(25 * var(--u));
  background: #fff;
  border-radius: calc(25 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) var(--ink),
    0 calc(5 * var(--u)) calc(10 * var(--u)) calc(2 * var(--u)) #000;
  color: var(--ink);
  text-align: center;
  font: 500 calc(21.12 * var(--u)) / .9928 var(--font-ui);
  transform-origin: 75% 0; /* растёт от кружков, которые идут от персонажа */
}
.bubble p { margin: 0; }
/* между абзацами одна пустая строка */
.bubble p + p { margin-top: calc(20.97 * var(--u)); }
.bubble p:first-of-type { white-space: nowrap; }

/* Появление из трёх частей: малый круг, круг побольше, бабл с текстом.
   Класс .is-animated есть с загрузки; main.js снимает и возвращает его, чтобы
   повторить показ вместе со звуками при включении звука */
.bubble.is-animated .bubble__dot--s {
  animation: bubble-pop .26s cubic-bezier(.3, 1.6, .5, 1) both;
  animation-delay: var(--step);
}
.bubble.is-animated .bubble__dot--l {
  animation: bubble-pop .26s cubic-bezier(.3, 1.6, .5, 1) both;
  animation-delay: calc(var(--step) * 2);
}
.bubble.is-animated .bubble__body {
  animation: bubble-pop-body .3s cubic-bezier(.3, 1.4, .5, 1) both;
  animation-delay: calc(var(--step) * 3);
}
@keyframes bubble-pop      { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes bubble-pop-body { from { transform: scale(.55); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* Текст: слова слегка всплывают снизу одно за другим, как только бабл раскрылся */
.bubble .w { display: inline-block; }
.bubble.is-animated .w {
  animation: word-in .26s cubic-bezier(.2, .8, .2, 1) both;
  animation-delay: calc(var(--step) * 3 + .1s + var(--i) * 26ms);
}
@keyframes word-in {
  from { transform: translateY(.45em); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* Табличка с именем */
/* Frame 2131328762: 229.3 x 104 px, радиус 30, поворот 45 против часовой, центр на
   (3.55u, 5.16u) от левого верха бабла. Обводка белая 4 px снаружи, тень (5, 5) blur 10
   чёрная 75%: в Figma смещение считается по экрану, поэтому в повёрнутых координатах
   это (0, 3.54u) */
.bubble__tag {
  position: absolute;
  left: calc(3.55 * var(--u)); top: calc(5.16 * var(--u));
  z-index: 1;
  display: grid;
  place-items: center;
  width: calc(114.67 * var(--u));
  height: calc(52 * var(--u));
  transform: translate(-50%, -50%) rotate(-45deg);
  background: var(--magenta);
  border-radius: calc(15 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) #fff,
    0 calc(3.54 * var(--u)) calc(5 * var(--u)) calc(2 * var(--u)) rgba(0, 0, 0, .75);
  color: #fff;
  text-align: center;
  font: 900 calc(21.12 * var(--u)) / .9928 var(--font-display);
}
/* Один раз, мягко, сразу после того, как бабл раскрылся */
.bubble.is-animated .bubble__tag {
  animation: tag-pop .7s ease-out calc(var(--step) * 3 + .25s) both;
}
@keyframes tag-pop {
  0%   { rotate: 0deg; scale: .9; opacity: 0; }
  35%  { rotate: -4deg; scale: 1.05; opacity: 1; }
  70%  { rotate: 2deg; scale: 1; }
  100% { rotate: 0deg; scale: 1; opacity: 1; }
}

/* Пузыри мысли */
/* Ellipse 83 (малый, 41.2 px) и Ellipse 82 (большой, 73.3 px): тот же стиль, что у бабла */
.bubble__dot {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  box-shadow:
    0 0 0 calc(2 * var(--u)) var(--ink),
    0 calc(5 * var(--u)) calc(10 * var(--u)) calc(2 * var(--u)) #000;
}
.bubble__dot--s { width: calc(20.6 * var(--u));  height: calc(20.6 * var(--u));  left: calc(291.2 * var(--u)); top: calc(-78.6 * var(--u)); }
.bubble__dot--l { width: calc(36.63 * var(--u)); height: calc(36.63 * var(--u)); left: calc(310.2 * var(--u)); top: calc(-53.1 * var(--u)); }

/* ============================================================
   Страница projects
   ============================================================ */
/* Пять карточек-превью лежат поверх сплошного фона, пока мир ушёл вниз. Каждая это кейс.
   Раскладка в u от центра экрана (--x, --y), базовый наклон --r в градусах (по z),
   --k глубина параллакса. У карточки .card живут параллакс (translate) и покачивание
   по z (rotate), у ссылки внутри: базовый наклон, наведение и нажатие */
.projects {
  z-index: 5;
  inset: 0;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0s .45s;
}
html[data-view="projects"] .projects { visibility: visible; transition-delay: 0s; }
.cards { list-style: none; margin: 0; padding: 0; }

.card {
  --w: 253.5;
  position: absolute;
  /* Карусель (carousel.js): позицию на эллипсе, масштаб, прозрачность, слой и въезд считает скрипт,
     он пишет --cx, --cy (u от центра экрана), --cs, --co, --cz, --ey, --k. У карточки живут
     параллакс и въезд (translate), покачивание по z (rotate) и глубина (scale, opacity) */
  left: calc(50% + var(--cx, 0) * var(--u));
  top: calc(50% + var(--cy, 0) * var(--u));
  width: calc(var(--w) * var(--u));
  margin: calc(var(--w) * var(--u) * -.5) 0 0 calc(var(--w) * var(--u) * -.5);
  margin-top: calc(var(--w) * var(--u) * -.3352); /* половина высоты, макет 507 x 340 */
  translate: calc(var(--px, 0) * -1 * var(--k, 10) * var(--u)) calc(var(--py, 0) * -.6 * var(--k, 10) * var(--u) + var(--ey, 0) * var(--u));
  rotate: 0deg;
  scale: var(--cs, .55);
  opacity: var(--co, 0);
  z-index: var(--cz, 0);
  animation: card-sway var(--sway) ease-in-out var(--sd) infinite alternate;
  pointer-events: none;
}
html[data-view="projects"] .card { pointer-events: auto; }
/* Перетаскивание карусели: тач не должен скроллить, ссылки не должны уезжать как файлы */
html[data-view="projects"] .stage { touch-action: none; }
.card__link { -webkit-user-drag: none; user-select: none; }
html.is-dragging .card__link { pointer-events: none; }

/* Покачивание по z: каждая карточка со своим периодом и фазой */
@keyframes card-sway {
  from { rotate: calc(var(--amp, 2.2) * -1deg); }
  to   { rotate: calc(var(--amp, 2.2) * 1deg); }
}

.card__link {
  position: relative;
  display: block;
  rotate: calc(var(--r) * 1deg);
  border-radius: calc(14 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) #fff,
    0 calc(8 * var(--u)) calc(16 * var(--u)) rgba(0, 0, 0, .35);
  transition:
    scale .3s cubic-bezier(.3, 1.6, .5, 1),
    rotate .35s cubic-bezier(.3, 1.4, .5, 1),
    box-shadow .25s;
}
.card__link img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 507 / 340;
  object-fit: cover;
  border-radius: calc(14 * var(--u));
}
/* Наведение: карточка выпрямляется и вырастает. Область нажатия чуть шире самой карточки */
.card__link::before {
  content: "";
  position: absolute;
  inset: calc(-8 * var(--u));
}
.card__link:hover,
.card__link:focus-visible {
  scale: 1.08;
  rotate: calc(var(--r) * .15deg);
  box-shadow:
    0 0 0 calc(2 * var(--u)) #fff,
    0 calc(14 * var(--u)) calc(26 * var(--u)) rgba(0, 0, 0, .4);
  outline: none;
}
.card__link:focus-visible { box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 0 0 calc(5 * var(--u)) var(--magenta); }
.card__link:active { scale: .95; transition-duration: .06s; }

/* Название кейса выпрыгивает наклейкой в стиле навигации */
.card__title {
  position: absolute;
  left: calc(-6 * var(--u));
  bottom: calc(-14 * var(--u));
  color: var(--magenta);
  font: 900 calc(21.845 * var(--u)) / .95 var(--font-display);
  width: max-content;
  max-width: calc(330 * var(--u));
  white-space: normal;
  line-height: .95;
  -webkit-text-stroke: calc(10.5 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
  opacity: 0;
  transform: translateY(calc(8 * var(--u))) rotate(-3deg) scale(.7);
  transform-origin: 0 100%;
  transition: opacity .15s, transform .3s cubic-bezier(.3, 1.6, .5, 1);
  pointer-events: none;
}
.card__link:hover .card__title,
.card__link:focus-visible .card__title {
  opacity: 1;
  transform: rotate(-3deg);
}

/* Вертикальный экран: две колонки */
@media (max-aspect-ratio: 1/1) {
}

/* ------------------------------------------------------------
   Звёзды на фоне projects
   ------------------------------------------------------------ */
/* Лежат внутри .space и едут вместе с ним. Раскладка снята не с макета, а посчитана: звёзды
   разнесены не ближе заданного расстояния друг от друга, вверху (в тёмной части) их больше,
   внизу меньше, и они не попадают под карточки, модалку и UI. --x от центра, --y от верха (u),
   --k глубина параллакса (звёзды дальше карточек, поэтому двигаются слабо) */
.star {
  position: absolute;
  left: calc(50% + var(--x) * var(--u));
  top: calc(var(--y) * var(--u));
  width: calc(var(--s) * var(--u));
  aspect-ratio: 1;
  margin: calc(var(--s) * var(--u) * -.5) 0 0 calc(var(--s) * var(--u) * -.5);
  border-radius: 50%;
  background: #fff;
  translate: calc(var(--px, 0) * -1 * var(--k) * var(--u)) calc(var(--py, 0) * -.6 * var(--k) * var(--u));
  animation: star-twinkle calc(var(--t) * 1s) ease-in-out calc(var(--d) * -1s) infinite alternate;
}
@keyframes star-twinkle {
  from { opacity: 1; }
  to   { opacity: .45; }
}

/* ------------------------------------------------------------
   Нижняя модалка на projects
   ------------------------------------------------------------ */
/* Frame 2131328785: 1436.2 x 224 px, отступы 25 / 50, радиус 50, между аватаркой и текстом 50,
   аватарка 174 px, текст Inter Medium 42.23 px. Низ на 22.25u выше низа сцены. Появляется как
   реплика на главной: сначала бабл, потом табличка, потом слова по очереди */
.note {
  position: absolute;
  z-index: 500; /* выше карточек карусели (до 150) */
  left: calc(50% - 359.05 * var(--u));
  bottom: max(calc(22.25 * var(--u) + var(--sab)), clamp(0px, calc((var(--hit) - 50vw + 359.05 * var(--u)) * 1000), var(--clr)));
  width: calc(718.1 * var(--u));
  pointer-events: none;
  opacity: 0;
  translate: 0 calc(24 * var(--u));
  transition: opacity .2s, translate .25s;
}
.note--contacts {
  translate: 0 calc(24 * var(--u) + var(--c-near) * var(--cam-dist));
  transition: opacity .2s .35s;
}
html[data-view="projects"] .note:not(.note--contacts),
html[data-view="contacts"] .note--contacts {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
  transition: none;
}
html[data-view="contacts"] .note--contacts { translate: 0 calc(var(--c-near) * var(--cam-dist)); }
.note__body {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(25 * var(--u));
  box-sizing: border-box;
  padding: calc(12.5 * var(--u)) calc(25 * var(--u));
  background: #fff;
  border-radius: calc(25 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) var(--ink),
    0 calc(5 * var(--u)) calc(10 * var(--u)) calc(2 * var(--u)) #000;
  color: var(--ink);
  transform-origin: 50% 100%;
}
html[data-view="projects"] .note__body {
  animation: bubble-pop-body .3s cubic-bezier(.3, 1.4, .5, 1) .65s both;
}
html[data-view="contacts"] .note--contacts .note__body {
  animation: bubble-pop-body .3s cubic-bezier(.3, 1.4, .5, 1) calc(var(--c-delay, 1.2s) + .2s) both;
}
/* Табличка: центр на (6.4u; 5.35u) от левого верха модалки */
.note__tag {
  position: absolute;
  left: calc(6.4 * var(--u)); top: calc(5.35 * var(--u));
  z-index: 2;
  display: grid;
  place-items: center;
  width: calc(114.67 * var(--u));
  height: calc(52 * var(--u));
  transform: translate(-50%, -50%) rotate(-45deg);
  background: var(--magenta);
  border-radius: calc(15 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) #fff,
    0 calc(3.54 * var(--u)) calc(5 * var(--u)) calc(2 * var(--u)) rgba(0, 0, 0, .75);
  color: #fff;
  text-align: center;
  font: 900 calc(21.12 * var(--u)) / .9928 var(--font-display);
  pointer-events: none;
}
html[data-view="projects"] .note__tag { animation: tag-pop .7s ease-out .9s both; }
html[data-view="contacts"] .note--contacts .note__tag { animation: tag-pop .7s ease-out calc(var(--c-delay, 1.2s) + .45s) both; }

.note__avatar {
  position: relative;
  flex: none;
  width: calc(87 * var(--u));
  height: calc(87 * var(--u));
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #0b2a2a;
  overflow: hidden;
  cursor: pointer;
  transition: scale .18s cubic-bezier(.3, 1.6, .5, 1);
  -webkit-tap-highlight-color: transparent;
}
.note__avatar:hover, .note__avatar:focus-visible { scale: 1.06; outline: none; }
.note__avatar:active { scale: .92; transition-duration: .06s; }
.note__avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }
.note__avatar:focus-visible { box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 0 0 calc(4 * var(--u)) var(--magenta); }

.note__text {
  flex: 1;
  margin: 0;
  font: 500 calc(21.12 * var(--u)) / .9928 var(--font-ui);
  /* слова всплывают одно за другим, как в реплике на главной; --wd задаёт старт */
}
.note__text .w {
  display: inline-block;
  animation: word-in .26s cubic-bezier(.2, .8, .2, 1) calc(var(--wd, 0s) + var(--i) * 20ms) both;
}

/* Глитч аватарки: пока играет звук. Два цветных слоя со сдвигом и нарезкой, дрожь самой картинки */
.note__avatar::before,
.note__avatar::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: url("assets/avatar.webp") center / cover;
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
}
.note--contacts .note__avatar::before, .note--contacts .note__avatar::after { background-image: url("assets/avatar-hat.webp"); }
.note__avatar::before { filter: sepia(1) saturate(8) hue-rotate(-60deg); }
.note__avatar::after  { filter: sepia(1) saturate(8) hue-rotate(140deg); }
.note__avatar.is-glitch img { animation: glitch-shake .42s steps(1, end) infinite; }
.note__avatar.is-glitch::before { opacity: .85; animation: glitch-a .5s steps(1, end) infinite; }
.note__avatar.is-glitch::after  { opacity: .85; animation: glitch-b .43s steps(1, end) infinite; }
@keyframes glitch-shake {
  0%   { translate: 0 0; filter: none; }
  12%  { translate: calc(-3 * var(--u)) 0; filter: contrast(1.4) saturate(1.6); }
  24%  { translate: calc(2 * var(--u)) calc(1 * var(--u)); filter: none; }
  38%  { translate: 0 calc(-2 * var(--u)); filter: hue-rotate(40deg) contrast(1.3); }
  52%  { translate: calc(3 * var(--u)) 0; filter: none; }
  66%  { translate: calc(-1 * var(--u)) calc(2 * var(--u)); filter: invert(.15); }
  80%  { translate: 0 0; filter: none; }
  90%  { translate: calc(2 * var(--u)) calc(-1 * var(--u)); filter: contrast(1.5); }
}
@keyframes glitch-a {
  0%   { translate: calc(-4 * var(--u)) 0; clip-path: inset(10% 0 70% 0); }
  20%  { translate: calc(3 * var(--u)) 0;  clip-path: inset(55% 0 20% 0); }
  40%  { translate: calc(-2 * var(--u)) 0; clip-path: inset(0 0 85% 0); }
  60%  { translate: calc(5 * var(--u)) 0;  clip-path: inset(70% 0 5% 0); }
  80%  { translate: calc(-3 * var(--u)) 0; clip-path: inset(35% 0 45% 0); }
}
@keyframes glitch-b {
  0%   { translate: calc(4 * var(--u)) 0;  clip-path: inset(60% 0 15% 0); }
  25%  { translate: calc(-3 * var(--u)) 0; clip-path: inset(15% 0 65% 0); }
  50%  { translate: calc(2 * var(--u)) 0;  clip-path: inset(80% 0 0 0); }
  75%  { translate: calc(-5 * var(--u)) 0; clip-path: inset(40% 0 40% 0); }
}
/* Текст в этот момент тоже подрагивает */
.note__text.is-glitch { animation: glitch-text .3s steps(1, end) infinite; }
@keyframes glitch-text {
  0%   { translate: 0 0; }
  25%  { translate: calc(-2 * var(--u)) 0; }
  50%  { translate: calc(2 * var(--u)) calc(1 * var(--u)); }
  75%  { translate: calc(1 * var(--u)) calc(-1 * var(--u)); }
}

/* Вертикальный экран: модалка уже и ниже по высоте */
@media (max-aspect-ratio: 1/1) {
  .note { left: calc(20 * var(--u) + var(--sal)); width: calc(100% - 40 * var(--u) - var(--sal) - var(--sar)); bottom: max(calc(92 * var(--u) + var(--sab)), calc(var(--clr) + 4px)); }
  .note__text br { display: none; }
  .note__avatar { width: calc(80 * var(--u)); height: calc(80 * var(--u)); }
  .note__text { font-size: calc(21 * var(--u)); }
  .note__body { gap: calc(18 * var(--u)); padding: calc(16 * var(--u)) calc(20 * var(--u)); }
}

/* ============================================================
   Страница about
   ============================================================ */
/* Камера приблизилась к персонажу (он слева), справа большой бабл. Вид как у реплики на
   главной: белый бабл с обводкой, табличка в углу и два кружка к персонажу. Внутри скролл */
.about {
  z-index: 6;
  right: calc(var(--about-m) + var(--sar));
  top: calc(136 * var(--u));
  bottom: max(calc(45.23 * var(--u) + var(--sab)), var(--clr)); /* не ниже кнопки звука */
  width: var(--about-w);
  visibility: hidden;
  pointer-events: none;
  opacity: 0;
  translate: 0 calc(24 * var(--u));
  scale: .92;
  transform-origin: 0 75%; /* растёт от кружков, которые идут от персонажа */
  transition: opacity .2s, translate .25s, scale .25s, visibility 0s .3s;
}
html[data-view="about"] .about {
  visibility: visible;
  pointer-events: auto;
  opacity: 1;
  translate: 0 0;
  scale: 1;
  transition:
    opacity .2s .5s,
    translate .5s cubic-bezier(.3, 1.4, .5, 1) .5s,
    scale .5s cubic-bezier(.3, 1.4, .5, 1) .5s,
    visibility 0s .5s;
}
.about__body {
  position: relative;
  height: 100%;
  background: #fff;
  border-radius: calc(25 * var(--u));
  box-shadow:
    0 0 0 calc(2 * var(--u)) var(--ink),
    0 calc(5 * var(--u)) calc(10 * var(--u)) calc(2 * var(--u)) #000;
  color: var(--ink);
}
.about__dot {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  box-shadow:
    0 0 0 calc(2 * var(--u)) var(--ink),
    0 calc(5 * var(--u)) calc(10 * var(--u)) calc(2 * var(--u)) #000;
}
/* Кружки как на главной (те же размеры, шаг между ними 43u, зазор большого до бабла 16.5u).
   Цепочка идёт от ноутбука персонажа вправо к баблу. Отсчёт от низа бабла */
.about__dot--s { width: calc(20.6 * var(--u));  height: calc(20.6 * var(--u));  left: calc(-82.3 * var(--u)); bottom: calc(169.5 * var(--u)); }
.about__dot--l { width: calc(36.63 * var(--u)); height: calc(36.63 * var(--u)); left: calc(-53.1 * var(--u)); bottom: calc(140 * var(--u)); }
html[data-view="about"] .about__dot--s { animation: bubble-pop .26s cubic-bezier(.3, 1.6, .5, 1) .5s both; }
html[data-view="about"] .about__dot--l { animation: bubble-pop .26s cubic-bezier(.3, 1.6, .5, 1) .6s both; }
html[data-view="about"] .about__body    { animation: bubble-pop-body .3s cubic-bezier(.3, 1.4, .5, 1) .7s both; transform-origin: 0 75%; }

/* Скролл внутри бабла: плавное затухание у краёв, акцент синий, отступы из общей шкалы --s1..--s8 */
.about__scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  box-sizing: border-box;
  padding: var(--s4) var(--s4) var(--s5);
  font: 500 calc(18 * var(--u)) / 1.35 var(--font-ui);
  text-wrap: pretty;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--s3), #000 calc(100% - var(--s3)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--s3), #000 calc(100% - var(--s3)), transparent 100%);
  scrollbar-width: thin;
  scrollbar-color: var(--case-blue) transparent;
  outline: none;
}
.about__scroll::-webkit-scrollbar { width: 8px; }
.about__scroll::-webkit-scrollbar-thumb { background: var(--case-blue); border-radius: 8px; }
.about__scroll::-webkit-scrollbar-track { background: transparent; }
.about__scroll > :first-child { margin-top: 0; }
.about__scroll h2 {
  margin: 0 0 var(--s2);
  color: var(--case-blue);
  font: 900 calc(40 * var(--u)) / 1.05 var(--font-display);
}
.about__scroll h3 {
  clear: both;
  margin: var(--s5) 0 var(--s2);
  color: var(--case-blue);
  font: 900 calc(24 * var(--u)) / 1.1 var(--font-display);
}
.about__scroll p { margin: 0 0 var(--s2); }
.about__scroll ul { margin: 0; padding-left: 1.2em; }
.about__scroll li { margin: 0 0 var(--s1); }
.about__scroll li::marker { color: rgba(36, 37, 36, .45); }
.about__scroll h3 small { margin-left: .5em; color: var(--ink); opacity: .45; font: 700 .7em / 1 var(--font-ui); letter-spacing: .02em; }
.about__scroll a { color: var(--magenta); font-weight: 900; text-underline-offset: calc(3 * var(--u)); text-decoration-thickness: max(1px, calc(1.5 * var(--u))); overflow-wrap: anywhere; }
.about__scroll a:hover, .about__scroll a:focus-visible { text-decoration-color: var(--ink); outline: none; }
.about__strike { text-decoration: line-through; text-decoration-thickness: max(1.5px, calc(2 * var(--u))); opacity: .25; }
/* Фото справа от вступления */
.about__photo { float: right; width: 36%; margin: var(--s1) 0 var(--s2) var(--s3); position: relative; border-radius: calc(18 * var(--u)); overflow: hidden; aspect-ratio: 1 / 1; background: #e8ebff; }
.about__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.about__ph { display: none; }
.about__photo.is-empty { background: repeating-linear-gradient(135deg, #e8ebff 0 calc(8 * var(--u)), #fff calc(8 * var(--u)) calc(16 * var(--u))); box-shadow: inset 0 0 0 max(1.5px, calc(1.5 * var(--u))) var(--case-blue); }
.about__photo.is-empty img { display: none; }
.about__photo.is-empty .about__ph { display: grid; place-items: center; position: absolute; inset: 0; color: var(--case-blue); font: 900 .72em / 1.2 var(--font-ui); text-align: center; }
/* Опыт: компания и должность слева, даты справа, без цветных акцентов */
.about__scroll .about__jobs { list-style: none; padding: 0; }
.about__jobs li { display: grid; grid-template-columns: auto 1fr auto; gap: var(--s2); align-items: start; margin: 0; padding: var(--s2) 0; border-top: max(1px, calc(1 * var(--u))) solid rgba(36, 37, 36, .14); }
.about__jobs li:last-child { border-bottom: max(1px, calc(1 * var(--u))) solid rgba(36, 37, 36, .14); }
.about__jobs b { display: block; font-weight: 700; }
.about__scroll .about__jobs b a { color: inherit; font-weight: inherit; text-decoration: none; }
.about__jobs b a:hover { text-decoration: underline; text-underline-offset: calc(3 * var(--u)); }
.about__jobs b a:focus-visible { outline: max(2px, calc(2 * var(--u))) solid var(--case-blue); outline-offset: 2px; border-radius: 2px; }
/* Место под логотип компании: заменить содержимое на <img> */
.about__logo { display: grid; place-items: center; width: calc(36 * var(--u)); height: calc(36 * var(--u)); border-radius: calc(9 * var(--u)); background: rgba(36, 37, 36, .06); box-shadow: inset 0 0 0 max(1px, calc(1 * var(--u))) rgba(36, 37, 36, .14); color: rgba(36, 37, 36, .45); font: 900 calc(11 * var(--u)) / 1 var(--font-ui); overflow: hidden; align-self: start; }
.about__logo { position: relative; }
.about__logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.about__jobs div > span { display: block; opacity: .6; line-height: 1.3; }
.about__jobs time { white-space: nowrap; font-weight: 500; opacity: .6; font-variant-numeric: tabular-nums; }
.about__tools { color: var(--ink); }
.about__scroll .about__links { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s4); margin: 0; }

/* ============================================================
   Страница contacts
   ============================================================ */
/* Камера улетела вперёд над шаром: контент главной остался за спиной, на той же поляне
   стоит спутниковая антенна вместо персонажа. Она поднимается из-за кривизны земли:
   --f-arr растёт, антенна растёт вокруг точки схода (центр горизонта), а нижнюю часть
   скрывает срез, пока она ещё за изгибом. Слой .contacts без z-index, поэтому антенна и бабл
   сравниваются по z-index прямо со слоями мира */
.contacts { inset: 0; pointer-events: none; }
.contacts > * { position: absolute; }
/* Антенна выходит из-за горизонта по шару. Обёртка .dish-clip не двигается и режет по самой
   поляне: видно только то, что выше дуги горизонта, а дуга (эллипс поляны) по ходу прилёта
   уезжает вниз (--sh), и антенна открывается снизу вверх. Сама .dish растёт вокруг точки схода
   и поднимается из-за дуги (translate); при уходе всё идёт в обратную сторону */
.dish-clip {
  /* дуга ниже точки схода на (ступни антенны) + запас, пока антенна не вышла целиком: вначале дуга выше антенны и скрывает её */
  --sh: calc((17.5 + 157.5 * var(--f-arr) + 90 * var(--f-arr) * var(--f-arr) * var(--f-arr) - 260 * (1 - var(--f-arr)) * (1 - var(--f-arr))) * var(--u) + var(--f-dip) * 24 * var(--u) - var(--py, 0) * 3 * var(--u) + var(--c-near) * var(--cam-dist));
  z-index: 3;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse max(calc(738.55 * var(--u)), 68.82vw) calc(379.4 * var(--u)) at 50% calc(100% + var(--sh)), transparent 99.6%, #000 100%);
  mask-image: radial-gradient(ellipse max(calc(738.55 * var(--u)), 68.82vw) calc(379.4 * var(--u)) at 50% calc(100% + var(--sh)), transparent 99.6%, #000 100%);
}
.dish {
  --ds: calc(.1 + .9 * var(--f-arr));
  position: absolute;
  /* Макет: картинка 1033 x 1033 px (516.4u), верх на 31.3u от верха кадра, по центру */
  left: calc(50% - 258.2 * var(--u));
  bottom: calc(131.2 * var(--u));
  width: calc(516.4 * var(--u));
  transform-origin: 50% calc(100% - 248.2 * var(--u)); /* горизонт на 379.4u от низа сцены */
  scale: var(--ds);
  translate: calc(var(--px, 0) * -11 * var(--u) * var(--f-arr)) calc(var(--py, 0) * -4.5 * var(--u) * var(--f-arr) + var(--c-near) * var(--cam-dist));
  opacity: clamp(0, calc(var(--f-arr) * 400), 1);
}
.dish { pointer-events: none; }
.dish__svg { display: block; width: 100%; height: auto; overflow: visible; pointer-events: none; transform-origin: 50% 85%; transition: transform .22s cubic-bezier(.3, 1.6, .5, 1); }
.dish__hit { pointer-events: all; cursor: url("assets/cursor-hand.svg") 13 4, pointer; -webkit-tap-highlight-color: transparent; }
.dish:focus, .dish *:focus, .dish__hit:focus { outline: none; }
.dish:active .dish__svg { transform: scale(.985, .97); transition-duration: .06s; }
.dish:focus-visible .dish__svg { filter: drop-shadow(0 0 calc(5 * var(--u)) var(--magenta)); }

/* Радиоволны по клику на антенну: кольца расходятся от чаши и растут, как будто летят на зрителя,
   то есть назад по дороге, которой камера прилетела с главной. Стиль наклейки: белое кольцо с
   магентой по краям. Кольца делает main.js, слой не режется горизонтом, как сама антенна */
.waves {
  z-index: 3;
  left: calc(50% - 258.2 * var(--u));
  bottom: calc(131.2 * var(--u));
  width: calc(516.4 * var(--u));
  height: calc(516.4 * var(--u));
  pointer-events: none;
  translate: calc(var(--px, 0) * -11 * var(--u)) calc(var(--py, 0) * -4.5 * var(--u) + var(--c-near) * var(--cam-dist));
}
.wave {
  position: absolute;
  left: 50%;
  top: 43.7%;
  width: 58%;
  aspect-ratio: 1;
  translate: -50% -50%;
  box-sizing: border-box;
  border: calc(4 * var(--u)) solid #fff;
  border-radius: 50%;
  box-shadow: 0 0 0 calc(2 * var(--u)) var(--magenta), inset 0 0 0 calc(2 * var(--u)) var(--magenta);
  opacity: 0;
  animation: wave 1.5s cubic-bezier(.25, .55, .3, 1) calc(var(--i) * .18s) both;
}
@keyframes wave {
  0%   { scale: .4; opacity: 0; }
  12%  { opacity: 1; }
  100% { scale: 3.6; opacity: 0; }
}

/* Кнопки контактов: круг 87.5u (175 px макета), магента, белая обводка 2u снаружи, иконка 48u.
   Ведут себя как кнопка звука: при наведении поворот и увеличение, при нажатии «продавливается».
   Появляются после прилёта антенны по очереди, как слова и кружки на других страницах */
.cbtn {
  --cx: 0;
  --cb: 296; /* низ кнопки от низа сцены, u */
  z-index: 4;
  /* центр не дальше края окна: на узких экранах боковые кнопки подъезжают к центру */
  --lim: calc(50vw - 43.75 * var(--u) - 12px);
  left: calc(50% + clamp(calc(-1 * var(--lim)), calc(var(--cx) * var(--u)), var(--lim)) - 43.75 * var(--u));
  bottom: calc(var(--cb) * var(--u));
  display: grid;
  place-items: center;
  width: calc(87.5 * var(--u));
  height: calc(87 * var(--u));
  box-sizing: border-box;
  border-radius: 50%;
  background: var(--magenta);
  color: #fff;
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  translate: calc(var(--px, 0) * -14 * var(--u)) calc(var(--py, 0) * -5.5 * var(--u) + var(--c-near) * var(--cam-dist));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1), opacity .15s .35s, visibility 0s .5s;
}
.cbtn--ig   { --cx: -236.7; }
.cbtn--mail { --cx: 236.7; }
.cbtn--tg   { --cx: 0; --cb: 190.8; }
@keyframes cbtn-pop { from { scale: 0; opacity: 0; } to { scale: 1; opacity: 1; } }
.cbtn__icon { width: calc(48 * var(--u)); height: auto; }
.cbtn:hover, .cbtn:focus-visible { transform: rotate(-8deg) scale(1.1); outline: none; }
.cbtn:active { transform: scale(.88); transition-duration: .06s; }
.cbtn:focus-visible { box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 0 0 calc(4 * var(--u)) var(--ink); }
html[data-view="contacts"] .cbtn {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1);
  animation: cbtn-pop .26s cubic-bezier(.3, 1.6, .5, 1) calc(var(--c-delay, 1.2s) + .45s + var(--d) * .12s) both;
}


/* Вертикальный экран: персонаж сверху, бабл about внизу */
@media (max-aspect-ratio: 1/1) {
  :root {
    --about-dx: 0px;
    --about-dy: calc(-1 * (.52 * var(--vh) + 66 * var(--uf) - 188.6 * var(--us)));
    --about-s: .3;
  }
  .about {
    left: calc(44 * var(--u) + var(--sal));
    right: calc(20 * var(--u) + var(--sar));
    top: auto;
    bottom: max(calc(66 * var(--u) + var(--sab)), calc(var(--clr) + 4px)); /* выше кнопок cv и звука */
    width: auto;
    height: calc(.52 * var(--vh));
    transform-origin: 50% 0;
  }
  .about__dot { display: none; }
  .about__scroll { font-size: min(calc(24 * var(--u)), 22px); }
  .about__scroll h2 { font-size: min(calc(48 * var(--u)), 44px); }
  .about__scroll h3 { font-size: min(calc(30 * var(--u)), 27px); }
}

/* ============================================================
   Экран загрузки (драфт)
   ============================================================ */
.loader {
  position: fixed;
  inset: 0;
  z-index: 2147482000; /* выше всего, но ниже своего курсора */
  overflow: hidden;
  /* Фон: ступенчатые полосы, как у неба на главной и космоса на projects.
     16 одинаковых полос от #0a28fc (верх) к чуть более светлому синему #3258f4 */
  background: linear-gradient(to bottom,
    #0a28fc 0.0% 6.25%,
    #0d2bfb 6.25% 12.5%,
    #0f2efb 12.5% 18.75%,
    #1232fa 18.75% 25.0%,
    #1535fa 25.0% 31.25%,
    #1738f9 31.25% 37.5%,
    #1a3bf9 37.5% 43.75%,
    #1d3ef8 43.75% 50.0%,
    #1f42f8 50.0% 56.25%,
    #2245f7 56.25% 62.5%,
    #2548f7 62.5% 68.75%,
    #274bf6 68.75% 75.0%,
    #2a4ef6 75.0% 81.25%,
    #2d52f5 81.25% 87.5%,
    #2f55f5 87.5% 93.75%,
    #3258f4 93.75% 100.0%);
  transition: opacity .5s ease, scale .5s cubic-bezier(.6, 0, .8, .4);
}
.loader.is-leaving { opacity: 0; scale: 1.08; pointer-events: none; }
/* Всё по центру кадра; позиции сняты с макета 2146 x 1358, отсчёт от центра экрана (u) */
.loader__inner { position: absolute; inset: calc(-85 * var(--u)) 0 calc(85 * var(--u)) 0; opacity: 0; transition: opacity .25s; }
.loader.is-shown .loader__inner { opacity: 1; }
.loader__inner > * { position: absolute; left: 50%; margin: 0; translate: -50% -50%; }
.loader__title {
  top: calc(50% - 11.5 * var(--u));
  color: #0b29fc;
  font: 900 calc(74.5 * var(--u)) / 1 var(--font-display);
  letter-spacing: -.04em;
  white-space: nowrap;
  -webkit-text-stroke: calc(11.5 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
}
.loader__role {
  top: calc(50% + 42.5 * var(--u));
  color: var(--magenta);
  font: 900 calc(23 * var(--u)) / 1 var(--font-display);
  letter-spacing: -.03em;
  white-space: nowrap;
  -webkit-text-stroke: calc(7 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
}
.loader__bee {
  top: calc(50% + 138 * var(--u));
  left: calc(50% - 5 * var(--u));
  width: calc(77 * var(--u));
  pointer-events: none;
}
.loader__bee .bee__img { pointer-events: none; cursor: default; }
.loader.is-ready .loader__bee { animation: loader-bounce .6s cubic-bezier(.3, 1.6, .5, 1); }
.loader__pct {
  top: calc(50% + 206 * var(--u));
  color: #fff;
  font: 900 calc(24.5 * var(--u)) / 1 var(--font-display);
  white-space: nowrap;
}
.loader.is-ready .loader__pct { display: none; }
.loader.is-ready { cursor: pointer; }
.loader__enter {
  top: calc(50% + 202 * var(--u));
  appearance: none;
  background: none;
  border: 0;
  padding: calc(6 * var(--u)) calc(14 * var(--u));
  color: var(--magenta);
  font: 900 calc(34 * var(--u)) / 1 var(--font-display);
  -webkit-text-stroke: calc(10.5 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
  cursor: pointer;
  animation: loader-pop .4s cubic-bezier(.3, 1.6, .5, 1) both;
  transition: scale .18s cubic-bezier(.3, 1.6, .5, 1), rotate .18s cubic-bezier(.3, 1.6, .5, 1);
}
.loader__enter[hidden] { display: none; }
.loader__enter:hover, .loader__enter:focus-visible { rotate: -3deg; scale: 1.1; outline: none; }
.loader__enter:active { rotate: -3deg; scale: .94; transition-duration: .06s; }
@keyframes loader-pop    { from { opacity: 0; scale: .3; } to { opacity: 1; scale: 1; } }
@keyframes loader-bounce { 0% { transform: translateY(0); } 40% { transform: translateY(calc(-16 * var(--u))); } 100% { transform: translateY(0); } }

/* ============================================================
   UI
   ============================================================ */
.ui { z-index: 10; margin: 0; color: #fff; }
.loader, .case { --u: var(--us0); }
.ui, .note, .about, .bubble {
  --u: var(--uf);
  --btn: max(44px, calc(36 * var(--u)));          /* кнопки cv и звука: размер */
  --cvw: calc(var(--btn) * 1.9);                  /* ширина кнопки cv */
  --clr: calc(14 * var(--u) + var(--sab) + var(--btn) + 12px); /* низ реплики над кнопками, зазор 12 px */
  /* Расстояние, на которое реплика заходит на кнопку cv слева (px). Умножаем на 1000 и обрезаем
     clamp: пока захода нет, подъём 0, как только появился, реплика встаёт над кнопками */
  --hit: calc(20 * var(--u) + var(--sal) + var(--cvw) + 12px);
}

/* Лого: svg 379x379, снят с текста «ä» (Inter Black 136 px) на (40, 40) с белой обводкой
   14 px. Масштаб svg к макету 0.4426, позиция посчитана по контуру буквы без обводки */
.logo {
  left: calc(-1.75 * var(--u) + var(--sal));
  top: calc(19.2 * var(--u));
  width: calc(83.9 * var(--u));
  transition: transform .2s;
}
.logo img { width: 100%; height: auto; }
.logo:hover { transform: rotate(-6deg) scale(1.08); }
.logo:active { transform: rotate(-6deg) scale(.94); transition-duration: .06s; }

/* Локация это ссылка на карту: при наведении подчёркивается вся надпись */
.location {
  left: 50%;
  top: calc(20 * var(--u));
  transform: translateX(-50%);
  white-space: nowrap;
  font: 500 calc(16 * var(--u)) / .9928 var(--font-ui);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: max(1px, calc(1.5 * var(--u)));
  text-underline-offset: calc(3 * var(--u));
  transition: text-decoration-color .15s;
}
.location { transition: text-decoration-color .15s, scale .22s cubic-bezier(.3, 1.6, .5, 1); }
.location:active { scale: .94; transition-duration: .06s; }
.location:hover,
.location:focus-visible {
  text-decoration-color: currentColor;
  outline: none;
}
.location__time { white-space: nowrap; }
.location__clock { font-variant-numeric: tabular-nums; }
/* На узком экране время уходит на свою строку, чтобы локация не рвалась по словам */
@media (max-aspect-ratio: 1/1) {
  .location__sep { display: none; }
  .location__time { display: block; }
}

/* Навигация: белая «наклейка» вокруг маджентового текста */
/* Inter Black 43.69 px, по правому краю на 20u от края, сверху 20u, шаг 36.45u
   (строка 26.5u плюс зазор 10u). Обводка белая, снаружи около 5u */
.nav {
  right: calc(20 * var(--u) + var(--sar));
  top: calc(20 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(10 * var(--u));
}
.nav a {
  color: var(--magenta);
  text-decoration: none;
  font: 900 calc(21.845 * var(--u)) / normal var(--font-display);
  -webkit-text-stroke: calc(10.5 * var(--u)) #fff;
  paint-order: stroke fill;
  stroke-linejoin: round;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1);
}
.nav a:hover,
.nav a:focus-visible { transform: rotate(-3deg) scale(1.1); outline: none; }
/* Нажатие: короткая «продавленная» кнопка, замена тактильного отклика на десктопе */
.nav a[aria-current="page"] { transform: rotate(-3deg) scale(1.1); color: #0b29fc; }
.nav a:active { transform: rotate(-3deg) scale(.94); transition-duration: .06s; }

/* Кнопка «download cv» слева внизу, на всех экранах */
.cvbtn {
  left: calc(20 * var(--u) + var(--sal));
  bottom: calc(14 * var(--u) + var(--sab));
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--u));
  justify-content: center;
  width: var(--cvw);
  min-height: var(--btn);
  padding: 0;
  border-radius: 999px;
  background: var(--magenta);
  color: #fff;
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
  font: 900 max(14px, calc(15 * var(--u))) / 1 var(--font-display);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1);
}
.cvbtn svg { width: max(16px, calc(18 * var(--u))); height: max(16px, calc(18 * var(--u))); flex: none; }
.cvbtn:hover, .cvbtn:focus-visible { transform: rotate(-8deg) scale(1.1); outline: none; }
.cvbtn:active { transform: scale(.94); transition-duration: .06s; }

/* Кнопка звука: иконка 24u на 20u от правого и нижнего края; область нажатия 36u
   (Frame 2131328770 из макета, круг 72 px), центр совпадает с центром иконки */
.sound {
  right: calc(14 * var(--u) + var(--sar));
  bottom: calc(14 * var(--u) + var(--sab));
  display: grid;
  place-items: center;
  width: var(--btn);
  height: var(--btn);
  padding: 0;
  background: var(--magenta);
  border: 0;
  border-radius: 50%;
  /* Frame 2131328770: круг 72 px, заливка магента, белая обводка 4 px снаружи */
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
  cursor: pointer;
}
/* Нажатие: «продавливается» */
.sound { transition: transform .18s cubic-bezier(.3, 1.6, .5, 1); }
.sound:hover, .sound:focus-visible { transform: rotate(-8deg) scale(1.1); }
.sound:active { transform: scale(.88); transition-duration: .06s; }
.sound__icon { width: max(22px, calc(24 * var(--u))); height: auto; }
.sound:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

/* Состояния: выключен = зачёркнутый динамик, включён = волны */
.sound__slash { display: none; }
.sound[aria-pressed="false"] .sound__waves { display: none; }
.sound[aria-pressed="true"]  .sound__cut   { display: none; }
.sound[aria-pressed="false"] .sound__slash { display: block; }

/* ============================================================
   Уменьшенная анимация
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .cloud, .bee__bob, .bee__img { animation: none; }
  .bubble.is-animated .bubble__tag { animation: none; }
  .haha { animation: none; opacity: 1; transform: translate(-50%, -50%) rotate(calc(var(--rot, -30) * 1deg)); }
  .nav a:active, .sound:active, .hero:active, .logo:active { transform: none; }
  .bee__img:active, .location:active { scale: none; }
  .cursor.is-hover .cursor__img, .cursor.is-down .cursor__img { animation: none; transform: none; }
  .card { animation: none; transition-duration: 0s; transition-delay: 0s; }
  .about, html[data-view="about"] .about { transition-duration: 0s; transition-delay: 0s; }
  .wave { display: none; }
  html[data-view="contacts"] .cbtn, html[data-view="contacts"] .note--contacts .note__body, html[data-view="contacts"] .note--contacts .note__tag { animation: none; }
  html[data-view="about"] .about__dot--s, html[data-view="about"] .about__dot--l, html[data-view="about"] .about__body { animation: none; }
  .loader, .loader__enter, .loader.is-ready .loader__bee { animation: none; transition-duration: 0s; }
  .star, .note__avatar.is-glitch img, .note__avatar.is-glitch::before, .note__avatar.is-glitch::after, .note__text.is-glitch { animation: none; }
  html[data-view="projects"] .note__body, html[data-view="projects"] .note__tag, .note__text .w { animation: none; }
  .bubble.is-animated .bubble__dot--s,
  .bubble.is-animated .bubble__dot--l,
  .bubble.is-animated .bubble__body,
  .bubble.is-animated .w { animation: none; }
  .hero.is-typing .hero__frame--idle { opacity: 1; }
  .hero.is-typing .hero__frame--a,
  .hero.is-typing .hero__frame--b { animation: none; opacity: 0; }
}

/* ============================================================
   Страница кейса (поверх projects)
   Белый лист в стиле реплики: обводка 2u, наклейки магентой, номера кружками как кнопки контактов.
   Закрывается крестом, Esc, кликом по затемнению и кнопкой внизу
   ============================================================ */
/* Единая шкала отступов: 6u (около 8 px) с шагом вверх: 6, 12, 18, 24, 36, 48, 72, 96. Внутри блока отступы меньше внешних, заголовок ближе к своему тексту, чем к предыдущему разделу */
.case, .about {
  --s1: calc(6 * var(--u)); --s2: calc(12 * var(--u)); --s3: calc(18 * var(--u)); --s4: calc(24 * var(--u));
  --s5: calc(36 * var(--u)); --s6: calc(48 * var(--u)); --s7: calc(72 * var(--u)); --s8: calc(96 * var(--u));
  --case-blue: #0b29fc;
}
.case {
  inset: 0;
  z-index: 900; /* выше реплики (500) и UI (10), ниже экрана загрузки */
  display: grid;
  justify-items: center;
  visibility: hidden;
  pointer-events: none;
  --case-w: min(calc(780 * var(--u)), calc(100vw - 32px));
}
.case.is-open { visibility: visible; pointer-events: auto; }
.case__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(4, 10, 70, .72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity .25s;
}
.case.is-open .case__backdrop { opacity: 1; }
.case__sheet {
  position: relative;
  align-self: stretch;
  width: var(--case-w);
  margin: calc(28 * var(--u)) 0 0;
  background: #fff;
  color: var(--ink);
  border-radius: calc(25 * var(--u)) calc(25 * var(--u)) 0 0;
  box-shadow: 0 0 0 calc(2 * var(--u)) var(--ink), 0 calc(5 * var(--u)) calc(30 * var(--u)) rgba(0, 0, 0, .55);
  overflow: hidden;
  opacity: 0;
  translate: 0 calc(60 * var(--u));
  scale: .97;
  transform-origin: 50% 100%;
  transition: opacity .2s, translate .3s, scale .3s;
}
.case.is-open .case__sheet {
  opacity: 1;
  translate: 0 0;
  scale: 1;
  transition: opacity .2s .05s, translate .5s cubic-bezier(.3, 1.3, .5, 1) .05s, scale .5s cubic-bezier(.3, 1.3, .5, 1) .05s;
}
.case__scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: calc(60 * var(--u)) calc(60 * var(--u)) var(--s7);
  font: 500 max(16px, min(calc(19 * var(--u)), 2.5vw)) / 1.5 var(--font-ui);
  outline: none;
  scrollbar-color: var(--magenta) transparent;
  scrollbar-width: thin;
}
.case__scroll::-webkit-scrollbar { width: 8px; }
.case__scroll::-webkit-scrollbar-thumb { background: var(--magenta); border-radius: 8px; }
.case__scroll::-webkit-scrollbar-track { background: transparent; }

/* Крест: наклейка-кружок справа сверху, всегда на виду */
.case__close {
  position: absolute;
  z-index: 3;
  top: calc(20 * var(--u));
  right: max(16px, calc(50% - var(--case-w) / 2 - 84 * var(--u)));
  display: grid;
  place-items: center;
  width: max(44px, calc(62 * var(--u)));
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  filter: drop-shadow(0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .55));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  opacity: 0;
  scale: .6;
  transition: opacity .2s, scale .25s cubic-bezier(.3, 1.6, .5, 1), transform .18s cubic-bezier(.3, 1.6, .5, 1);
}
.case.is-open .case__close { opacity: 1; scale: 1; transition-delay: .2s, .2s, 0s; }
.case__close svg { width: 70%; stroke-width: 3.8; }
/* Наведение и нажатие как у остальных кнопок: поворот и увеличение, при нажатии «продавливается» */
.case__close:hover, .case__close:focus-visible { transform: rotate(-8deg) scale(1.1); outline: none; }
.case__close:active { transform: scale(.88); transition-duration: .06s; }
.case__close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 50%; }
@media (max-width: 900px) {
  .case__close { right: 16px; top: 12px; }
}

/* Шапка */
.case__tag {
  display: inline-grid;
  place-items: center;
  height: calc(40 * var(--u));
  min-height: 26px;
  padding: 0 calc(22 * var(--u));
  background: var(--magenta);
  color: #fff;
  border-radius: calc(12 * var(--u));
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 calc(3 * var(--u)) calc(5 * var(--u)) calc(2 * var(--u)) rgba(0, 0, 0, .6);
  font: 900 max(13px, calc(18 * var(--u))) / 1 var(--font-display);
  rotate: -4deg;
  margin-bottom: calc(18 * var(--u));
}
.case__head h1 {
  margin: 0 0 var(--s3);
  color: var(--case-blue);
  font: 900 max(34px, min(calc(64 * var(--u)), 6.8vw)) / .98 var(--font-display);
  letter-spacing: -.02em;
  text-wrap: balance;
}
.case__lead { margin: 0 0 var(--s5); max-width: 40em; text-wrap: pretty; }
.case__meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(120px, calc(150 * var(--u))), 1fr));
  gap: calc(14 * var(--u)) calc(20 * var(--u));
  margin: 0 0 var(--s5);
  padding: var(--s4) 0;
  border-block: calc(2 * var(--u)) solid var(--ink);
}
.case__meta dt { font: 900 max(11px, calc(13 * var(--u))) / 1 var(--font-display); color: var(--case-blue); text-transform: lowercase; letter-spacing: .06em; margin-bottom: var(--s1); }
.case__meta dd { margin: 0; font-weight: 700; }

/* Кнопки: магента с белой обводкой, как кнопки контактов; ghost для «назад» */
.case__btn {
  display: inline-grid;
  place-items: center;
  min-height: max(44px, calc(56 * var(--u)));
  padding: 0 calc(30 * var(--u));
  border: 0;
  border-radius: 999px;
  background: #fff;
  color: var(--magenta);
  font: 900 max(15px, calc(20 * var(--u))) / 1 var(--font-display);
  text-decoration: none;
  box-shadow: 0 0 0 max(2px, calc(3 * var(--u))) var(--magenta);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1);
}
.case__btn:hover, .case__btn:focus-visible { transform: rotate(-3deg) scale(1.06); outline: none; }
.case__btn:active { transform: scale(.94); transition-duration: .06s; }
.case__btn:focus-visible { box-shadow: 0 0 0 max(2px, calc(3 * var(--u))) var(--magenta), 0 0 0 calc(7 * var(--u)) rgba(237,0,255,.3); }
.case__btn--ghost { }

/* Медиа */
.case__fig {
  position: relative;
  margin: var(--s5) 0 0;
  border-radius: calc(18 * var(--u));
  overflow: hidden;
  background: #0a28fc;
  aspect-ratio: 1780 / 1234;
}
.case__fig--hero { margin-top: var(--s6); }
.case__fig img, .case__fig video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Пока файла нет, на его месте плашка с именем: так видно, что и куда положить */
.case__ph {
  position: absolute;
  inset: 0;
  display: none;
  place-items: center;
  background: repeating-linear-gradient(135deg, #0a28fc 0 calc(14 * var(--u)), #1737ff calc(14 * var(--u)) calc(28 * var(--u)));
  color: #fff;
  font: 700 max(12px, calc(15 * var(--u))) / 1 var(--font-ui);
  letter-spacing: .04em;
}
.case__fig.is-empty .case__ph { display: grid; }
.case__fig.is-empty img, .case__fig.is-empty video { visibility: hidden; }

/* Разделы */
.case__sec { position: relative; margin-top: var(--s8); content-visibility: auto; contain-intrinsic-size: auto 600px; }
.case__sec h2 { margin: 0 0 var(--s2); color: var(--case-blue); font: 900 max(22px, min(calc(34 * var(--u)), 4.4vw)) / 1.05 var(--font-display); letter-spacing: -.01em; text-wrap: balance; }
/* Тег-подпись в заголовке секции: контекст работы (клиенты, формат) */
.case__tagline { display: block; margin-top: var(--s2); color: var(--ink); opacity: .55; font: 700 max(12px, calc(15 * var(--u))) / 1.2 var(--font-ui); letter-spacing: .04em; text-transform: uppercase; }
/* Ссылка в теле кейса */
.case__link { color: var(--magenta); font-weight: 900; text-underline-offset: calc(3 * var(--u)); text-decoration-thickness: max(1px, calc(1.5 * var(--u))); }
.case__link:hover, .case__link:focus-visible { text-decoration-color: var(--ink); outline: none; }
/* Сноска под текстом */
.case__note { margin-top: var(--s2) !important; opacity: .6; font-size: .85em; line-height: 1.5; }
.case__sec p { margin: 0 0 var(--s3); text-wrap: pretty; max-width: 40em; }
.case__sec p:last-of-type { margin-bottom: 0; }
/* Абзац после картинки или рилсов: свой отступ, иначе он прилипает к медиа */
.case__sec .case__fig + p, .case__sec .reels + p { margin-top: var(--s4); }
/* Метрика: наклейка */
.case__metric {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s2);
  margin: var(--s4) 0 0 !important; /* под кадром: итог блока */
  padding: var(--s2) var(--s3);
  border-radius: calc(14 * var(--u));
  background: #eceeff;
  color: var(--ink);
  rotate: -1.5deg;
}
.case__metric b { font: 900 max(20px, calc(30 * var(--u))) / 1 var(--font-display); color: var(--ink); }
.case__metric span { font: 700 max(13px, calc(16 * var(--u))) / 1.1 var(--font-ui); color: var(--ink); opacity: .75; }
/* Ряд метрик в конце кейса: наклейки в строку, с переносом на мобильном */
.case__metrics { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s4); }
.case__metrics .case__metric { margin: 0 !important; }
.case__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s4);
  justify-content: center;
  margin-top: var(--s8);
  padding-top: var(--s6);
  border-top: calc(2 * var(--u)) solid var(--ink);
}
.case__thanks { flex: 1 0 100%; margin: 0 0 var(--s2); text-align: center; color: var(--case-blue); font: 900 max(22px, min(calc(34 * var(--u)), 4.4vw)) / 1.05 var(--font-display); letter-spacing: -.01em; text-wrap: balance; }

/* Появление блоков при прокрутке */
.case__sec, .case__fig--hero { opacity: 0; translate: 0 calc(28 * var(--u)); transition: opacity .4s, translate .5s cubic-bezier(.3, 1.2, .5, 1); }
.case__sec.is-in, .case__fig--hero.is-in { opacity: 1; translate: 0 0; }

@media (max-width: 700px) {
  .case__sheet { margin-top: 12px; }
  .case__scroll { padding: 28px 18px 40px; }
  .case__head h1 { padding-right: 52px; }
  .case__sec { margin-top: 56px; }
}
@media (prefers-reduced-motion: reduce) {
  .case__sheet, .case.is-open .case__sheet, .case__close, .case.is-open .case__close, .case__sec, .case__fig--hero { transition: none; }
}

/* Кейс pearl: высокие кадры уже обычных, кнопка «скоро», ссылка на рилсы */
.case__btn--soon { opacity: .6; cursor: default; }
.case__more { margin: var(--s4) 0 0 !important; max-width: 40em; }
.case__more a { color: var(--magenta); font-weight: 900; text-underline-offset: calc(3 * var(--u)); text-decoration-thickness: max(1px, calc(1.5 * var(--u))); }
.case__more a:hover, .case__more a:focus-visible { text-decoration-color: var(--ink); outline: none; }


.case__more small { display: block; margin-top: var(--s1); opacity: .6; font-size: .8em; line-height: 1.4; }
.case__soon { text-align: center; opacity: .6; margin-top: var(--s7) !important; font-weight: 700; max-width: none; }
.case__sec .case__fig + .case__fig, .case__sec .case__fig + .reels, .case__sec .reels + .case__fig { margin-top: var(--s4); }

/* Рилсы: вертикальные плееры, играют только по нажатию на play. Ширина своя, не как у блоков кейса */
.reels {
  display: flex;
  justify-content: center;
  gap: var(--s4);
  margin: var(--s5) 0 0;
}
.reel {
  position: relative;
  flex: 0 1 calc(270 * var(--u));
  min-width: 0;
  border-radius: calc(26 * var(--u));
  overflow: hidden;
  background: #0a0a14;
}
.reel video { display: block; width: 100%; height: 100%; object-fit: cover; cursor: pointer; }
.reel__play {
  position: absolute;
  left: 50%; top: 50%;
  display: grid;
  place-items: center;
  width: max(52px, calc(78 * var(--u)));
  aspect-ratio: 1;
  padding: 0 0 0 calc(4 * var(--u));
  border: 0;
  border-radius: 50%;
  background: var(--magenta);
  color: #fff;
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 calc(4 * var(--u)) calc(14 * var(--u)) rgba(0, 0, 0, .5);
  translate: -50% -50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s cubic-bezier(.3, 1.6, .5, 1), opacity .2s, scale .2s;
}
.reel__play svg { width: 42%; }
.reel__play:hover, .reel__play:focus-visible { transform: rotate(-8deg) scale(1.1); outline: none; }
.reel__play:active { transform: scale(.88); transition-duration: .06s; }
.reel__play:focus-visible { box-shadow: 0 0 0 calc(2 * var(--u)) #fff, 0 0 0 calc(5 * var(--u)) var(--ink); }
.reel.is-playing .reel__play { opacity: 0; scale: .6; pointer-events: none; }
.reel__bar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: calc(8 * var(--u));
  min-height: 5px;
  background: rgba(255, 255, 255, .3);
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s;
}
.reel.is-started .reel__bar { opacity: 1; }
.reel__bar i { position: absolute; left: 0; top: 0; bottom: 0; width: 100%; background: var(--magenta); transform-origin: 0 50%; transform: scaleX(var(--p, 0)); }
@media (max-width: 700px) {
  .reels { gap: 12px; }
  .reel { flex-basis: 46%; border-radius: 16px; }
}


/* ============================================================
   Адаптив: тач, безопасные зоны, короткие экраны
   ============================================================ */
/* Область нажатия не меньше 44 px (Apple HIG 44, Material 48, WCAG 2.5.8 минимум 24). Рисунок
   остаётся прежним: расширяется только невидимая зона */
@media (pointer: coarse) {
  .nav { gap: 0; }
  .nav a { display: grid; align-items: center; justify-items: end; min-height: 44px; padding: 0 calc(6 * var(--u)); margin-right: calc(-6 * var(--u)); }
  .location { padding: 14px 4px; margin-top: -14px; }
  .loader__enter { min-height: 44px; min-width: 44px; }
}

/* Названия карточек на тач-экране: наведения нет, поэтому подпись всегда у ближней к зрителю */
@media (hover: none) {
  .card.is-front .card__title { opacity: 1; transform: rotate(-3deg); }
}

/* Узкий экран: строки бабла переносятся, локация сжимается между лого и навигацией */
@media (max-width: 480px) {
  .bubble p:first-of-type { white-space: normal; }
}
@media (max-aspect-ratio: 1/1) {
  .location { width: max-content; max-width: calc(100vw - 196px); white-space: normal; text-align: center; text-wrap: balance; line-height: 1.15; }
}

/* Низкие ландшафтные экраны (телефон набок): навигация плотнее, бабл about ниже неё */
@media (max-height: 520px) and (min-aspect-ratio: 1/1) {
  .about { top: calc(max(136 * var(--u), 126px)); }
}
@media (pointer: coarse) and (max-height: 520px) and (min-aspect-ratio: 1/1) {
  .nav a { min-height: 34px; }
}

/* Телефон: таблички-наклейки целиком в кадре, строки реплик не слипаются */
@media (max-aspect-ratio: 1/1) {
  .note__tag, .bubble__tag { left: 30px; top: -2px; width: calc(100 * var(--u)); height: calc(46 * var(--u)); font-size: calc(18.5 * var(--u)); }
  .note__text, .bubble__body { line-height: 1.22; }
  .bubble__body { padding-top: 38px; }
  .about__scroll { padding-top: 40px; }
  .note__body { padding-top: 24px; }
}

.location .nb { white-space: nowrap; }
/* About на высоком телефоне: сцена крупнее, поэтому персонаж увеличивается меньше (иначе шляпа упирается в локацию) */
@media (max-aspect-ratio: 1/1) { :root { --about-s: .1; } }
@media (max-aspect-ratio: 5/7) { :root { --about-s: .12; } }
@media (max-aspect-ratio: 9/16) { :root { --about-s: .04; } }
/* Телефон: даты опыта под должностью, чтобы название не сжималось в узкую колонку */
@media (max-aspect-ratio: 1/1) {
  .about__jobs li { grid-template-columns: auto 1fr; gap: var(--s1) var(--s2); }
  .about__jobs time { grid-column: 2; }
  .about__jobs time { opacity: .5; }
}

/* ============================================================
   Телефон: правки по скиллу responsive-adapt (десктоп не затронут)
   ============================================================ */
/* Узкий телефон: фото в About меньше, чтобы текст рядом не сжимался в колонку из 3 слов */
@media (max-width: 480px) {
  .about__photo { width: 30%; margin-left: var(--s2); }
}
/* Тач: ссылки на компании в опыте получают область нажатия 44 px, вид не меняется */
@media (pointer: coarse) {
  .about__jobs b a { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; margin-block: -12px; }
}

/* ============================================================
   Телефон и планшет, правки после аудита ui-ux-pro-max (десктоп с мышью не затронут)
   ============================================================ */
/* Кнопки листания проектов: на тач-экране и в узком вертикальном окне свайп не единственный способ */
.pager { display: none; }
@media (max-aspect-ratio: 1/1), (pointer: coarse) {
  .pager { display: block; position: absolute; inset: 0; pointer-events: none; z-index: 200; }
  .pager__btn {
    position: absolute;
    top: var(--car-mid, 45%);
    translate: 0 -50%;
    display: grid; place-items: center;
    width: max(44px, calc(36 * var(--uf))); height: max(44px, calc(36 * var(--uf)));
    padding: 0; border: 0; border-radius: 50%;
    background: var(--magenta); color: #fff;
    box-shadow: 0 0 0 calc(2 * var(--uf)) #fff;
    pointer-events: auto; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform .18s cubic-bezier(.3, 1.6, .5, 1);
  }
  .pager__btn--prev { left: max(10px, calc(14 * var(--uf) + var(--sal))); }
  .pager__btn--next { right: max(10px, calc(14 * var(--uf) + var(--sar))); }
  .pager__btn svg { width: 55%; height: 55%; }
  .pager__btn:active { transform: scale(.88); transition-duration: .06s; }
  .pager__btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
}
/* Серый вспомогательный текст темнее: 4,5:1 и выше на белом, как требует WCAG AA */
@media (max-aspect-ratio: 1/1), (pointer: coarse) {
  .about__jobs div > span, .about__jobs time { opacity: .72; }
  .about__scroll h3 small { opacity: .62; }
  .about__scroll li::marker { color: rgba(36, 37, 36, .62); }
}
/* Локация: читается на облаках и не меньше 14 px */
@media (max-aspect-ratio: 1/1) {
  .location { font-size: max(14px, calc(15 * var(--uf))); text-shadow: 0 1px 2px rgba(0, 0, 0, .55), 0 0 6px rgba(0, 0, 0, .35); }
}
@media (pointer: coarse) {
  .location { padding: 12px 2px; margin-top: -12px; text-shadow: 0 1px 2px rgba(0, 0, 0, .55), 0 0 6px rgba(0, 0, 0, .35); }
}
/* Сцена не должна уезжать вбок от фокуса или прокрутки к элементу: clip, в отличие от hidden, не даёт прокручивать даже программно */
@media (max-aspect-ratio: 1/1), (pointer: coarse) {
  .stage { overflow: clip; }
}
/* Кейс на телефоне занимает весь экран, и белый крестик сливается с белым листом: делаем его круглой розовой кнопкой с белой обводкой, как остальные */
@media (max-width: 700px), (max-aspect-ratio: 1/1) {
  .case__close { background: var(--magenta); border-radius: 50%; filter: none; box-shadow: 0 0 0 calc(2 * var(--uf)) #fff, 0 2px 8px rgba(0, 0, 0, .35); width: max(44px, calc(40 * var(--uf))); }
  .case__close svg { width: 52%; }
}

/* ============================================================
   МОБИЛЬНАЯ ВЕРСИЯ по макетам Figma (402 x 874): телефон в портрете, ширина до 600 px
   Размеры в px: на телефоне текст не меньше 16 px, кнопки не меньше 44 px. Десктоп и планшет
   этот блок не затрагивает. Нижняя панель: CV, локация, звук. Реплика на главной сверху,
   нижняя модалка (projects, contacts) и бабл about снизу над панелью
   ============================================================ */
@media (max-aspect-ratio: 1/1) and (max-width: 600px) {
  :root {
    --mx: 20px;
    --mb: max(calc(var(--sab) + 12px), 22px);   /* низ нижней панели */
    --bar-top: calc(var(--mb) + 48px);          /* верх нижней панели */
  }
  /* Шапка */
  .logo { left: calc(12px + var(--sal)); top: 24px; width: 60px; }
  .nav { top: 34px; right: calc(var(--mx) + var(--sar)); gap: 0; }
  .nav a { font-size: 24px; -webkit-text-stroke: 8px #fff; min-height: 44px; padding: 0 6px; margin-right: -6px; }

  /* Нижняя панель: два круга по 48 px и локация между ними */
  .cvbtn, .sound { width: 48px; height: 48px; min-height: 48px; bottom: var(--mb); }
  .cvbtn { left: calc(var(--mx) + var(--sal)); padding: 0; gap: 0; }
  .sound { right: calc(var(--mx) + var(--sar)); }
  .cvbtn span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .cvbtn svg { width: 24px; height: 24px; }
  .sound__icon { width: 26px; }
  .location {
    top: auto; bottom: calc(var(--mb) + 24px); margin: 0; padding: 6px 0;
    transform: translate(-50%, 50%);
    width: max-content; max-width: min(190px, calc(100vw - 168px));
    font-size: 14px; line-height: 1.2; text-align: center; text-wrap: initial;
  }

  /* Главная: реплика сверху, табличка повёрнута, мысли идут вниз к персонажу */
  .bubble {
    top: max(calc(.247 * var(--vh)), 214px); bottom: auto;
    left: calc(var(--mx) + var(--sal)); right: calc(var(--mx) + var(--sar));
    width: auto; transform: none; transform-origin: 50% 0;
  }
  .bubble__body { padding: 28px 22px 22px; border-radius: 22px; font: 500 16px / 1.25 var(--font-ui); transform-origin: 50% 0; }
  .bubble p:first-of-type { white-space: normal; }
  .bubble p + p { margin-top: 1.25em; }
  .bubble__tag { left: 0; top: -32px; width: 112px; height: 52px; border-radius: 10px; font-size: 16px; line-height: 1.02; transform: rotate(-10deg); }
  .bubble__dot--l { width: 32px; height: 32px; left: auto; right: 59px; top: calc(100% + 11px); }
  .bubble__dot--s { width: 17px; height: 17px; left: auto; right: 91px; top: calc(100% + 49px); }

  /* Нижняя модалка (projects, contacts): аватар и табличка торчат над карточкой */
  .note { left: calc(var(--mx) + var(--sal)); right: calc(var(--mx) + var(--sar)); width: auto; bottom: calc(var(--bar-top) + 20px); }
  .note__body { display: grid; align-items: center; min-height: 92px; padding: 22px; border-radius: 22px; text-align: center; transform-origin: 50% 100%; }
  .note__avatar { position: absolute; left: 80px; top: -61px; width: 80px; height: 80px; }
  .note__tag { left: 170px; top: -47px; width: 112px; height: 52px; border-radius: 10px; font-size: 16px; line-height: 1.02; transform: none; }
  .note__text { font: 500 16px / 1.4 var(--font-ui); }

  /* About: карточка 338 px высотой над панелью, мысли слева сверху, без таблички (как в макете) */
  .about { left: calc(var(--mx) + var(--sal)); right: calc(var(--mx) + var(--sar)); width: auto; top: auto; bottom: calc(var(--bar-top) + 20px); height: clamp(240px, calc(.387 * var(--vh)), 440px); }
  .about__body { border-radius: 22px; }
  .about .bubble__tag { display: none; }
  .about__dot { display: block; bottom: auto; }
  .about__dot--l { width: 32px; height: 32px; left: 16px; top: -45px; }
  .about__dot--s { width: 18px; height: 18px; left: 39px; top: -67px; }
  .about__scroll { padding: 22px 22px 28px; font-size: 16px; line-height: 1.4; }
  .about__scroll h2 { font-size: 28px; }
  .about__scroll h3 { font-size: 20px; }

  /* Contacts: три круга по 64 px дугой над антенной */
  .cbtn { --mo: 0px; --ct: calc(.303 * var(--vh)); width: 64px; height: 64px; left: calc(50% + var(--mo) - 32px); bottom: auto; top: var(--ct); }
  .cbtn--ig { --mo: calc(-1 * min(129px, 32vw)); }
  .cbtn--mail { --mo: min(129px, 32vw); }
  .cbtn--tg { --ct: calc(.2506 * var(--vh)); }
  .cbtn__icon { width: 34px; }
}

/* Телефон: карусель вертикальная, свайп вверх-вниз и тап по выглядывающей карточке заменяют стрелки */
@media (max-aspect-ratio: 1/1) and (max-width: 600px) {
  .pager { display: none; }
}

/* About: списки без логотипов (talks, contests) */
.about__jobs--plain li { grid-template-columns: 1fr; }
.about__jobs--plain div > span a { color: inherit; text-decoration: underline; text-underline-offset: calc(3 * var(--u)); }
@media (max-aspect-ratio: 1/1) and (max-width: 600px) {
  .about__jobs--plain div > span a { display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; }
}

/* About: tools по группам */
.about__toolset { margin: 0; }
.about__toolset > div { display: grid; grid-template-columns: calc(78 * var(--u)) 1fr; gap: var(--s2); padding: calc(var(--s1) * .7) 0; border-top: max(1px, calc(1 * var(--u))) solid rgba(36, 37, 36, .14); }
.about__toolset > div:last-child { border-bottom: max(1px, calc(1 * var(--u))) solid rgba(36, 37, 36, .14); }
.about__toolset dt { font-weight: 700; opacity: .6; }
.about__toolset dd { margin: 0; }
@media (max-aspect-ratio: 1/1) and (max-width: 600px) { .about__toolset > div { grid-template-columns: 64px 1fr; } .about__toolset dt { opacity: .72; } }
.about__also{opacity:.6;margin-top:var(--s2)}

/* About: фото с выступлений (миниатюра и просмотр) */
.about__jobs li:has(.about__shot) { grid-template-columns: 1fr auto; align-items: center; }
.about__shot { all: unset; box-sizing: border-box; cursor: pointer; width: calc(52 * var(--u)); height: calc(52 * var(--u)); border-radius: calc(10 * var(--u)); overflow: hidden; outline-offset: 2px; }
.about__shot img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.about__shot:hover img { transform: scale(1.08); }
.about__shot:focus-visible { outline: max(2px, calc(2 * var(--u))) solid var(--case-blue); }
.shot { border: 0; padding: 0; background: transparent; max-width: min(92vw, 880px); max-height: 92vh; overflow: visible; color: #fff; }
.shot::backdrop { background: rgba(10, 10, 30, .78); }
.shot__img { display: block; max-width: 100%; max-height: 72vh; border-radius: 14px; margin: 0 auto; box-shadow: 0 8px 40px rgba(0, 0, 0, .5); }
.shot__cap { margin: 12px 0 0; text-align: center; font: 500 16px/1.4 var(--font-ui); text-shadow: 0 1px 6px rgba(0, 0, 0, .7); }
.shot__close { position: absolute; top: -14px; right: -14px; width: 44px; height: 44px; border-radius: 50%; border: 2px solid #fff; background: var(--magenta, #ed00ff); color: #fff; font: 700 26px/1 sans-serif; cursor: pointer; display: grid; place-items: center; padding: 0 0 3px; }
.shot__close:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
@media (max-width: 600px) { .about__shot { width: 52px; height: 52px; } .shot__close { top: -10px; right: -6px; } }

/* Кейс: видимые подписи под картинками */
/* Подпись-пометка об авторстве: промо и другие артефакты, сделанные не мной */
.case__label {
  margin: 0;
  font: 600 calc(12 * var(--u)) / 1.3 var(--font-ui);
  opacity: .55;
}
.case__promo { margin: var(--s5) 0 0; }
.case__promo .reels { margin-top: var(--s4); }
.case__fig--cap { overflow: visible; background: none; }
.case__fig--cap > img { border-radius: calc(18 * var(--u)); height: auto; }
.case__cap { margin: var(--s3) 0 0; font: inherit; color: inherit; opacity: 1; max-width: 40em; text-wrap: pretty; }
/* Мерч: подпись держится за своей картинкой, а следующий предмет начинается дальше */
.case__sec .case__fig--cap + .case__fig--cap { margin-top: var(--s6); }
