@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,500;1,400;1,500&display=swap');
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;0,600;1,400;1,500;1,600&display=swap");

:root {
  --page-max: 1920px;
  --container: 648px;

  --space-32: 32px;
  --space-64: 64px;
  --space-128: 128px;

  --pad-page: var(--space-32);
  --gap: var(--space-32);

  --text: #1D173F;
  --muted: rgba(29, 23, 63, 0.55);
  --bg: #FFFFFF;

  /* для фейдеров (page-fades) — в rgb, чтобы удобно менять альфу */
  --fade-color: 255, 255, 255;

  --pill: #2E37FF;
  --img-stroke: #EAEAEA;
}

* { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: -0.03em;
  font-style: italic;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }

.page {
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
}

.breadcrumbs {
  position: fixed;
  top: var(--pad-page);
  left: var(--pad-page);
  z-index: 2000;

  font-size: 14px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--muted);
  font-style: normal;

  max-width: calc(100vw - (var(--pad-page) * 2));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.breadcrumbs a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.breadcrumbs a:hover { border-bottom-color: currentColor; }

.hero {
  padding-top: var(--space-128);
  padding-bottom: var(--space-128);
  display: grid;
  place-items: center;
  gap: var(--space-32);
}

.hero__title {
  width: 100%;
  max-width: var(--container); /* 648px */
}
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 0 var(--space-128);
}

/* ---------- ритм ---------- */

/*
  Унифицированный вертикальный ритм на флексах.
  Конструкция внутри .section:
  заголовок → (64) → текст → (32) → картинка+подпись → (64) → картинка+подпись → (128) → следующий заголовок
*/

.section {
  padding-top: var(--space-128);
  display: flex;
  flex-direction: column;
}
.section--first { padding-top: 0; }

.h2 {
  margin: 0;
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: -0.05em;
  font-style: italic;
  font-weight: 400;
  text-align: center;
  color: var(--muted);
}

/* базово: все абзацы с красной строкой */
.copy {
  margin: 0;
  text-indent: 2ch;
}

/* первый абзац после заголовка — без красной строки */
.h2 + .copy {
  margin-top: var(--space-64);
  text-indent: 0;
}

/* текстовый ритм */
.copy + .copy { margin-top: var(--space-32); }

/* текст → картинка */
.copy + .media { margin-top: var(--space-32); }

/* картинка → текст (когда в одной главе несколько медиаблоков, разделённых абзацами) */
.media + .copy { margin-top: var(--space-64); }

/* картинка → картинка */
.media + .media { margin-top: var(--space-64); }

/* картинка → следующий заголовок */
.media + .h2 { margin-top: var(--space-128); }

/* на всякий: если заголовок идёт после текста */
.copy + .h2 { margin-top: var(--space-128); }

/* ---------- media ---------- */

.media {
  margin: 0;
}

.media__frame {
  position: relative;
  background: #fff;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--img-stroke);
}

/* страховка: чтобы обводка не “терялась” при разных рендерах */
.media__frame img {
  outline: 1px solid var(--img-stroke);
  outline-offset: -1px;
}

.caption {
  margin-top: var(--space-32);
  font-style: normal;
  font-weight: 500;
  font-size: 16px;
  line-height: 1.1;
  letter-spacing: 0;
  color: var(--muted);
  text-align: center;
}

/*
  Подпись всегда внутри figure.
  Отступы между блоками управляются правилами выше (.media + ...).
*/

/* ---------- media grid (2×2 по 648×648) ---------- */

/*
  Фикс: жёстко фиксируем строки/колонки, чтобы контент не “раздувал” ряд,
  и нижний правый блок не уезжал вниз.
  Работает для контейнера 648px: сетка становится 1 колонкой на мобиле (ниже).
*/

.media_grid {
  display: grid;
  grid-template-columns: repeat(2, 648px);
  grid-template-rows: repeat(2, 648px);
  gap: var(--gap);
  justify-content: center;
}

/* каждая ячейка всегда ровно 648×648, контент не влияет на высоту ряда */
.media_grid > * {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* если внутри ячейки лежит <img> — пусть заполняет ячейку ровно */
.media_grid > * img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- triple group (1+2) ---------- */

.media--triple .media__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px; /* всегда 24px */
}

.media--triple .media__item { margin: 0; }

@media (min-width: 700px) {
  .media--triple .media__grid {
    grid-template-columns: 312px 312px;
    justify-content: center;
  }

  .media--triple .media__item:nth-child(1) { grid-column: 1; grid-row: 1 / span 2; }
  .media--triple .media__item:nth-child(2) { grid-column: 2; grid-row: 1; }
  .media--triple .media__item:nth-child(3) { grid-column: 2; grid-row: 2; }

  .media--triple .media__item:nth-child(1) img {
    width: 312px;
    height: 648px;
    object-fit: cover;
  }
  .media--triple .media__item:nth-child(2) img,
  .media--triple .media__item:nth-child(3) img {
    width: 312px;
    height: 312px;
    object-fit: cover;
  }
}

@media (max-width: 699px) {
  :root { --pad-page: 16px; }

  .container { padding: 0 var(--pad-page) var(--space-128); }
  .header { padding: var(--pad-page); }

  .hero { padding-top: 72px; padding-bottom: 72px; }

  .media--triple .media__grid { grid-template-columns: 1fr; }

  .media--triple .media__item img {
    width: 100%;
    height: auto;
    object-fit: contain;
  }

  /* на мобиле 2×2 по 648 не влезет — делаем 1 колонку, высота по контенту */
  .media_grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    justify-content: stretch;
  }

  .media_grid > * {
    height: auto;
    overflow: visible;
  }

  .media_grid > * img {
    width: 100%;
    height: auto;
    object-fit: contain;
  }
}

/* ==============================
   MOBILE FIX: keep TRIPLE as 1+2 (no vertical stacking)
   – works with current markup (img directly inside .media__item)
   – removes the "step" by letting right squares define row heights
   (place at the very end so it overrides earlier mobile rules)
   ============================== */

@media (max-width: 699px) {
  /* safe edge-to-edge wrapper, but keep inner padding like text */
  .media--triple {
    position: relative;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    width: 100vw;
  }

  .media--triple .media__grid {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: clamp(10px, 3vw, 16px) !important;

    padding-left: var(--pad-page);
    padding-right: var(--pad-page);
    box-sizing: border-box;
    align-items: stretch;
  }

  .media--triple .media__item { margin: 0; min-width: 0; overflow: hidden; }

  .media--triple .media__item:nth-child(1) { grid-column: 1; grid-row: 1 / span 2; }
  .media--triple .media__item:nth-child(2) { grid-column: 2; grid-row: 1; }
  .media--triple .media__item:nth-child(3) { grid-column: 2; grid-row: 2; }

  /* Right items are true squares and define row heights */
  .media--triple .media__item:nth-child(2),
  .media--triple .media__item:nth-child(3) {
    aspect-ratio: 1 / 1;
  }

  /* Images must fill their grid items (override earlier "contain") */
  .media--triple .media__item img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover !important;
    display: block;
  }
}

/* ---------- Projects page ---------- */

.container--projects {
  padding-bottom: var(--space-128);
}

.projects {
  padding-top: 128px;
  display: flex;
  flex-direction: column;
  gap: var(--space-128);
}

.project {
  display: block;
  text-decoration: none;
  color: inherit;
}

.project__meta {
  margin-top: var(--space-32);
  display: flex;
  justify-content: space-between;
  align-items: baseline;

  font-style: normal;
  font-size: 14px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--muted);
}

.project__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 70%;
}

.project__year {
  white-space: nowrap;
}

.project--small .project__media .media__frame img {
  width: 100%;
  height: auto;
  object-fit: contain;
}

/* ==============================
   NEWEST OVERLAYS
   GIF + TOP BADGE (FINAL)
   ============================== */

/* ===== TOKENS ===== */
.project{
  /* GIF */
  --newest-gif-h: 1000px;
  --newest-gif-scale: 0.9;
  --newest-gif-x: 0px;
  --newest-gif-y: -10px;
  --newest-gif-opacity: .8;
  --newest-gif-gray: 1;

  /* BADGE (TOP ONLY) */
  --newest-badge-h: 260px;      /* высота зоны */
  --newest-badge-scale: 0.4;
  --newest-badge-x: 0px;
  --newest-badge-y: 12px;       /* отступ ОТ ВЕРХА ЗОНЫ */
  --newest-badge-opacity: 1;
  --newest-badge-gray: 0;
}

/* изоляция */
.project--big{
  isolation: isolate;
}

/* media — якорь */
.project__media{
  position: relative;
}

/* ==============================
   GIF
   ============================== */

.project__newest-gifwrap{
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;

  height: var(--newest-gif-h);
  transform: translateY(-50%);

  z-index: 6;
  pointer-events: none;
}

.project__newest-gif{
  position: absolute;
  left: 50%;
  top: 50%;

  width: 100%;
  height: 100%;

  transform:
    translate(calc(-50% + var(--newest-gif-x)),
              calc(-50% + var(--newest-gif-y)))
    scale(var(--newest-gif-scale));
  transform-origin: 50% 50%;

  object-fit: contain;
  object-position: center;

  opacity: var(--newest-gif-opacity);
  mix-blend-mode: var(--newest-gif-blend);
  filter: grayscale(var(--newest-gif-gray)) blur(var(--newest-gif-blur));

  image-rendering: pixelated;
}

/* ==============================
   TOP BADGE (NO MAGIC)
   ============================== */

.project__newest-badgewrap{
  position: absolute;
  left: 0;
  right: 0;
  top: 0;                 /* ЖЁСТКО К ВЕРХУ MEDIA */

  height: var(--newest-badge-h);

  z-index: 7;
  pointer-events: none;
}

.project__newest-badge{
  position: absolute;
  left: 50%;
  top: 0;

  width: 100%;
  height: 100%;

  transform:
    translate(calc(-50% + var(--newest-badge-x)),
              var(--newest-badge-y))
    scale(var(--newest-badge-scale));
  transform-origin: 50% 0%;

  object-fit: contain;
  object-position: center;

  opacity: var(--newest-badge-opacity);
  mix-blend-mode: var(--newest-badge-blend);
  filter: grayscale(var(--newest-badge-gray));

  image-rendering: pixelated;
}

/* ==============================
   MOBILE
   ============================== */

@media (max-width: 699px){
  .project{
    --newest-gif-h: 80vw;
    --newest-gif-scale: 1;
    --newest-gif-y: -5px;

    --newest-badge-h: 28vw;
    --newest-badge-scale: .5;
    --newest-badge-y: 15px;

    --newest-gif-opacity: .55;
  }
}

.projects__outro {
  padding-top: var(--space-128);
}

:root{
  --hero-min-h: 74px;
  --hero-top: 16px;
}

/* чтобы фиксированный тайтл не “прилипал” к краю и был над контентом */
.hero--sticky {
  position: relative;
}

.hero__title {
  display: block;
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;

  transform-origin: 50% 0%;
  will-change: transform;
}

/* фиксированное состояние (включается скриптом) */
.hero--sticky.is-fixed .hero__title {
  position: fixed;
  left: 50%;
  top: 128px; /* старт совпадает со скриптом */
  z-index: 2000;
  transform-origin: 50% 0%;
}

/* чтобы контент не залезал под фикс-тайтл */
body.has-sticky-hero .container {
  padding-top: calc(var(--space-128) + var(--hero-min-h));
}

:root{
  --fade-h: 90px; /* высота фейда */
}

/* слой поверх всего */
.page-fades::before,
.page-fades::after{
  content:"";
  position: fixed;
  left: 0;
  right: 0;
  height: var(--fade-h);
  pointer-events: none;
  z-index: 1200; /* выше контента и тайтла */
}

/* сверху: белый -> прозрачный вниз */
.page-fades::before{
  top: 0;
  background: linear-gradient(
    to bottom,
    rgba(var(--fade-color), 1) 0%,
    rgba(var(--fade-color), 0.96) 18%,
    rgba(var(--fade-color), 0.85) 36%,
    rgba(var(--fade-color), 0.6) 54%,
    rgba(var(--fade-color), 0.3) 72%,
    rgba(var(--fade-color), 0.12) 86%,
    rgba(var(--fade-color), 0) 100%
  );
}

/* снизу: белый -> прозрачный вверх */
.page-fades::after{
  bottom: 0;
  background: linear-gradient(
    to top,
    rgba(var(--fade-color), 1) 0%,
    rgba(var(--fade-color), 0.96) 18%,
    rgba(var(--fade-color), 0.85) 36%,
    rgba(var(--fade-color), 0.6) 54%,
    rgba(var(--fade-color), 0.3) 72%,
    rgba(var(--fade-color), 0.12) 86%,
    rgba(var(--fade-color), 0) 100%
  );
}

:root{
  --accent-blue: #4597F7;
  --hover-stroke: 4px;
}

/* 1) одна рамка вокруг всего медиаблока проекта */
.project__media{
  position: relative;
  outline: var(--hover-stroke) solid transparent;
  outline-offset: -1px;
  transition: outline-color 160ms ease;
}

.project:hover .project__media{
  outline-color: var(--accent-blue);
}

/* 2) подписи синие */
.project__name,
.project__year{
  transition: color 160ms ease;
}

.project:hover .project__name,
.project:hover .project__year{
  color: var(--accent-blue);
}

/* 3) чтобы в триплете не подсвечивались отдельные картинки */
.project:hover .project__media .media__frame{
  outline-color: transparent !important;
  box-shadow: inset 0 0 0 1px transparent !important;
}

.page{
  opacity: 1;
  transition: opacity 220ms ease;
}

/* ВАЖНО: чтобы не было «вспышки» на первом кадре,
   на состоянии is-entering отключаем transition полностью. */
body.is-entering .page{
  opacity: 0;
  transition: none !important;
}

body.is-leaving .page{
  opacity: 0;
}

 /* === TOP BUTTONS (твои SVG) === */
    .top-buttons {
      position: fixed;
      top: 15px;
      right: 15px;
      display: flex;
      gap: 8px;
      z-index: 1200;
      pointer-events: auto;
    }

    .top-buttons__btn {
      padding: 0;
      border: 0;
      background: transparent;
      cursor: pointer;
      user-select: none;
      -webkit-tap-highlight-color: transparent;
      line-height: 0;
    }

    .top-buttons__btn img {
      display: block;
      width: auto;
      height: 58px;
    }

    /* === ROPE OVERLAY === */
    #ropeCanvas {
      position: fixed;
      inset: 0;
      width: 100%;
      height: 100%;
      z-index: 999;
      background: transparent;
      pointer-events: auto;

      opacity: 0;
      visibility: hidden;
      transition: opacity 160ms linear, visibility 0s linear 160ms;
    }

    #ropeCanvas.is-on {
      opacity: 1;
      visibility: visible;
      transition: opacity 160ms linear, visibility 0s;
    }

    /* якорь скрыт */
    .rope-anchor-dot { display: none; }

    /* === DARK THEME (rope toggles this) === */
    body.light-off {
      --bg: #0D0B1E;
      --text: #F0EFFF;
      --muted: rgba(255, 255, 255, 0.55);
      --img-stroke: rgba(255, 255, 255, 0.16);
      --fade-color: 13, 11, 30;
}

/* ==============================
   SHOTGUN (global overlay)
   ============================== */

body.shotgun-on{ cursor: crosshair; }

#holes-layer,
#imgholes-layer,
#fragments-layer{
  position: absolute;
  inset: 0;
  pointer-events: none;
}
#holes-layer{ z-index: 900; }
#imgholes-layer{ z-index: 910; }
#fragments-layer{ z-index: 920; }

.shotgun-hole{
  position: absolute;
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  opacity: .95;
  image-rendering: pixelated;
}

.shotgun-img-hole{
  position: absolute;
  background: var(--bg);
  border-radius: 2px;
  opacity: 1;
  will-change: transform, opacity;
}

.shotgun-frag{
  position: absolute;
  will-change: transform, opacity, filter;
  opacity: 1;
  border-radius: 1px;
  image-rendering: pixelated;
  pointer-events: none;
}

#shotgun-wrap{
  position: fixed;
  left: 50%;
  bottom: 0;
  /* по умолчанию дробаш спрятан ниже экрана */
  transform: translateX(-50%) translateY(260px);
  width: 740px;
  height: 740px;
  z-index: 2200; /* ниже хлебных крошек и верхних кнопок */
  pointer-events: none;
  will-change: transform;

  opacity: 0;
  filter: drop-shadow(0 12px 26px rgba(0,0,0,.22));
  transition:
    transform 520ms cubic-bezier(.18,.86,.2,1),
    opacity 260ms ease;
}

/* видимое состояние */
#shotgun-wrap.is-visible{
  transform: translateX(-50%) translateY(0);
  opacity: 1;
}

/* лёгкий «тяжёлый» баунс при появлении */
@keyframes shotgunBounce{
  0%   { transform: translateX(-50%) translateY(260px); }
  100% { transform: translateX(-50%) translateY(0); }
}

#shotgun-wrap.is-bounce{
  animation: shotgunBounce 560ms cubic-bezier(.2,.9,.2,1) both;
}

/* дымок из ствола */
.shotgun-smoke{
  position: absolute;
  left: 56%;
  top: 36%;
  width: 90px;
  height: 90px;
  border-radius: 999px;
  pointer-events: none;
  background: radial-gradient(circle at 35% 35%, rgba(255,255,255,.55), rgba(255,255,255,0) 62%);
  mix-blend-mode: screen;
  opacity: 0;
  transform: translate(-50%,-50%) scale(0.55);
  will-change: transform, opacity, filter;
}

@keyframes shotgunSmokePuff{
  0%   { opacity: 0; transform: translate(-50%,-50%) scale(0.35); filter: blur(0px); }
  12%  { opacity: .95; }
  100% { opacity: 0; transform: translate(-50%,-78%) scale(1.35); filter: blur(1.2px); }
}

.shotgun-smoke.is-on{
  animation: shotgunSmokePuff 560ms ease-out both;
}

#shotgun{
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  image-rendering: pixelated;
  user-select: none;
  -webkit-user-drag: none;
}

#flash{
  position: fixed;
  inset: 0;
  background: rgba(255,255,255,.07);
  opacity: 0;
  transition: opacity 140ms ease;
  pointer-events: none;
  z-index: 970;
}
#flash.on{ opacity: 1; }

.shotgun-reset{
  position: fixed;
  left: 50%;
  bottom: 15px;
  transform: translateX(-50%);
  z-index: 2200;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  line-height: 0;
}

.shotgun-reset img{
  display: block;
  height: 58px;
  width: auto;
}

/* плавная смена картинок (projects) */
.js-fade-img{ transition: opacity 600ms ease-in-out; opacity: 1; }
.js-fade-img.is-fading{ opacity: 0; }


body.shotgun-on a{ pointer-events: none; }
body.shotgun-on .top-buttons a, body.shotgun-on .breadcrumbs a, body.shotgun-on .shotgun-reset a{ pointer-events: auto; }


/* ==============================
   AFTER DEMOLISH UNDERLAY
   ============================== */

.media__frame > img.after-underlay{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
}

.media__frame > img.after-underlay + img{
  position: relative;
  z-index: 1;
}

/* (удалено) старый эксперимент с появлением дробаша через анимацию на #shotgun.
   теперь используется #shotgun-wrap.is-visible/.is-bounce */

#rope-tooltip {
  position: fixed;
  pointer-events: none;
  z-index: 1500;

  opacity: 0;
  transform: translate(-50%, -50%) scale(.96);
  transition: opacity 120ms ease, transform 120ms ease;
}

#rope-tooltip.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

#rope-tooltip img {
  display: block;
  width: 120px;
  height: auto;
}

/* ==============================
   CV (inline SVG, selectable)
   ============================== */

.cv-stage{
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 128px 32px 128px; /* сверху под крошки/кнопки, снизу под download */
  pointer-events: none;
}

.cv-wrap{
  width: min(980px, calc(100vw - 64px));
  height: calc(100vh - 256px);
  overflow: auto;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--img-stroke);
  pointer-events: auto;
  -webkit-overflow-scrolling: touch;
}

.cv-svg-host{
  padding: 32px;
  display: grid;
  place-items: center;
}

/* сам inline svg */
.cv-svg{
  display: block;
  width: 100%;
  height: auto;
  background: #fff;

  /* главное: текст выделяется */
  user-select: text;
  -webkit-user-select: text;
}

/* чтобы внутри SVG не “глушились” клики по ссылкам */
.cv-svg a{
  pointer-events: auto;
  cursor: pointer;
}

/* если внутри SVG текстам зачем-то отключили pointer-events — вернём */
.cv-svg text{
  pointer-events: auto;
}

/* fallback */
.cv-fallback{
  margin: 0;
  padding: 18px 20px 22px;
  font-style: normal;
  font-size: 14px;
  line-height: 1.25;
  color: var(--muted);
  text-align: center;
}

.cv-fallback a{
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}

.cv-fallback__sep{
  display: inline-block;
  margin: 0 8px;
}

/* ==============================
   Bottom download button (если ещё нет)
   ============================== */

.bottom-buttons{
  position: fixed;
  left: 50%;
  bottom: 15px;
  transform: translateX(-50%);
  z-index: 1300; /* выше фейдера (1200) */
  pointer-events: auto;
}

.bottom-buttons__btn{
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  line-height: 0;
  display: inline-block;
}

.bottom-buttons__btn img{
  display: block;
  width: auto;
  height: 58px;
}

/* CV SVG typography fix */
.cv-svg,
.cv-svg text,
.cv-svg tspan{
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
  font-weight: 500;        /* Medium */
  font-style: normal;      /* как в макете */
  line-height: 1.3;        /* 130% */
  letter-spacing: 0;
}

/* ==============================
   MOBILE LAYOUT: controls like mock
   - Back: top-left
   - Theme: top-right
   - CV: bottom-left
   - Shotgun: bottom-right
   ============================== */

.back-btn{
  position: fixed;
  top: 15px;
  left: 15px;
  z-index: 1201; /* above fades (1200), same layer as top-buttons */
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  line-height: 0;
}

.back-btn img{
  display: block;
  width: auto;
  height: 58px; /* matches top buttons */
}

/* keep breadcrumbs hidden (button replaces it) */
.breadcrumbs{ display: none !important; }

@media (max-width: 699px){
  /* reserve space for bottom controls so content doesn't hide behind them */
  .container--projects{
    padding-bottom: calc(var(--space-128) + 86px + env(safe-area-inset-bottom, 0px));
  }

  /* turn the 3-button row into independent fixed buttons */
  .top-buttons{
    inset: 0;
    right: 0;
    top: 0;
    width: 100%;
    height: 100%;
    gap: 0;
    display: block;
    pointer-events: none; /* individual buttons re-enable */
  }

  .top-buttons__btn{
    position: fixed;
    pointer-events: auto;
  }

  /* Theme: top-right */
  #btnTheme{
    top: 15px;
    right: 15px;
    left: auto;
    bottom: auto;
  }

  /* CV: bottom-left */
  #btnCv{
    bottom: calc(15px + env(safe-area-inset-bottom, 0px));
    left: 15px;
    top: auto;
    right: auto;
  }

  /* Shotgun: bottom-right */
  #btnShotgun{
    bottom: calc(15px + env(safe-area-inset-bottom, 0px));
    right: 15px;
    top: auto;
    left: auto;
  }

  /* Back button slightly lower if the sticky hero overlaps; keep it aligned */
  .back-btn{
    top: 15px;
    left: 15px;
  }

  /* reduce title overlap with buttons */
  .hero{
    padding-top: 64px;
  }

  /* shotgun overlay: make sure gun fits phones */
  #shotgun-wrap{
    width: 520px;
    height: 520px;
    transform: translateX(-50%) translateY(220px);
  }
  #shotgun-wrap.is-visible{
    transform: translateX(-50%) translateY(0);
  }

  /* ==============================
     MOBILE: чтобы не раздувало страницу
     (НЕ ТРОГАЕМ z-index, только убираем расширение)
     ============================== */

  /* фрагменты/партиклы именно они чаще всего уводят width за 100vw */
  #fragments-layer { display: none !important; }
  .shotgun-frag { display: none !important; }
}

/* ==============================
   FINAL OVERRIDES
   - Controls above page-fades gradients
   - Breadcrumbs removed
   ============================== */

/* Gradients should sit above content, but below UI controls */
.page-fades::before,
.page-fades::after{
  z-index: 1100;
}

/* UI controls always above fades */
.top-buttons{ z-index: 1300; }
.back-btn{ z-index: 1301; }

/* Breadcrumbs are disabled */
.breadcrumbs{ display:none !important; }

/* ==============================
   MOBILE: buttons above shotgun overlay
   ============================== */
@media (max-width: 699px){
  .top-buttons{ z-index: 3001 !important; }
  .back-btn{ z-index: 3002 !important; }
  #shotgun-wrap{ z-index: 2900 !important; }
  .shotgun-reset{ z-index: 2900 !important; }
}

@media (max-width: 699px) {
  .hero__title{
    padding: 16px;
    box-sizing: border-box;
  }
}

@media (max-width: 699px){
  /* для триплетов: рамку рисуем по внутреннему блоку с паддингом,
     а не по full-bleed контейнеру */
  .project__media{
    outline: none;
  }

  .project__media .media--triple .media__grid{
    outline: var(--hover-stroke) solid transparent;
    outline-offset: -1px;
    transition: outline-color 160ms ease;
  }

  .project:hover .project__media .media--triple .media__grid{
    outline-color: var(--accent-blue);
  }

  .projects {
    padding-top: 64px;
  }
}


/* ==============================
   VISUALS (infinite world)
   — scoped, чтобы не ломать остальные страницы
   — тема: по умолчанию светлая (как весь сайт), dark включается body.light-off (rope)
   ============================== */

body.visuals{
  overflow: hidden;
}

body.visuals #viewport{
  position: fixed;
  inset: 0;
  overflow: hidden;
  cursor: grab;
  user-select: none;
  touch-action: none;
  perspective: 900px;
  perspective-origin: 50% 50%;
}

body.visuals #viewport.is-dragging{ cursor: grabbing; }

body.visuals #tiles{
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  will-change: transform;
  transform-style: preserve-3d;
}

body.visuals .tile{
  position: absolute;
  left: 0;
  top: 0;
  width: var(--world-w, 6000px);
  height: var(--world-h, 4000px);
  will-change: transform;
  transform-style: preserve-3d;
}

/* Токены для визуалса (светлая тема) */
body.visuals{
  --world-w: 6000px;
  --world-h: 4000px;

  --shadow-rgb: 0, 0, 0;
  --shadow-ambient-rgb: 0, 0, 0;
  --shadow-ambient-a: 0;

  --dust-rgb: 0, 0, 0;
  --dust-glow-rgb: 0, 0, 0;
  --dust-glow-a: 0;
}

/* Токены для визуалса (тёмная тема — rope ставит body.light-off) */
body.visuals.light-off{
  --shadow-rgb: 0, 0, 0;
  --shadow-ambient-rgb: 255, 255, 255;
  --shadow-ambient-a: 0.08;

  --dust-rgb: 255, 255, 255;
  --dust-glow-rgb: 255, 255, 255;
  --dust-glow-a: 0.12;
}

/* Ноды */
body.visuals .node{
  position: absolute;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
  overflow: visible;
  transform-style: preserve-3d;
  /* ВАЖНО: не используем contain: paint — он клипует тени/3D */
}

/* Карточка — это “объём”: тень, свет, затемнение снизу, блик */
body.visuals .node .card{
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  border-radius: 14px;

  --shadow-a: 0;
  --shadow-x: 0px;
  --shadow-y: 24px;
  --shadow-b: 54px;

  --lt: 0;   /* light top */
  --db: 0;   /* dark bottom */

  --glare: 0;
  --glare-x: 50%;
  --glare-y: 25%;

  filter:
    drop-shadow(var(--shadow-x) var(--shadow-y) var(--shadow-b) rgba(var(--shadow-rgb), var(--shadow-a)))
    drop-shadow(0 0 26px rgba(var(--shadow-ambient-rgb), var(--shadow-ambient-a)));
}

body.visuals .node img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 14px;
}

/* Свет сверху */
body.visuals .node .card::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 14px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,0.62), rgba(255,255,255,0) 58%);
  opacity: calc(0.10 + (var(--lt) * 0.65));
  mix-blend-mode: soft-light;
}

/* Затемнение снизу при “продавливании” */
body.visuals .node .card::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 14px;
  pointer-events: none;
  background: linear-gradient(0deg, rgba(0,0,0,0.85), rgba(0,0,0,0) 62%);
  opacity: calc(0.10 + (var(--db) * 0.75));
  mix-blend-mode: multiply;
}

/* Блик (отдельным слоем, чтобы не спорил с затемнением) */
body.visuals .node .pcard__glare{
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  border-radius: inherit;
  opacity: calc(var(--glare-opacity) * .42);
  mix-blend-mode: soft-light;
  background:
    radial-gradient(
      circle at var(--pointer-x) var(--pointer-y),
      rgba(255,255,255,.30) 0%,
      rgba(255,255,255,.14) 10%,
      rgba(255,255,255,.05) 18%,
      rgba(255,255,255,0) 34%
    );
  will-change: opacity, background, transform;
}

/* safety: newest overlay always has a positioning context */
.project--newest .project__media{ position: relative; }


/* ==============================
   IMAGE VIEWER
   ============================== */

.media__frame,
.media_grid > *,
.image-viewer__surface,
.image-viewer__img{
  background:#fff;
}

.caption{
  background: transparent;
}

.media__frame img,
.media_grid img,
.media img{
  cursor: zoom-in;
  -webkit-user-drag: none;
  user-select: none;
}

.image-viewer{
  position: fixed;
  inset: 0;
  z-index: 1600;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 180ms ease, visibility 0s linear 180ms;
}

.image-viewer.is-open{
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 180ms ease, visibility 0s;
}

.image-viewer__backdrop{
  position: absolute;
  inset: 0;
  background: rgba(8, 8, 10, 0.72);
}

.image-viewer__viewport{
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 96px 32px 32px;
  overflow: hidden;
  cursor: zoom-in;
}

.image-viewer__viewport.is-zoomed{
  cursor: grab;
}

.image-viewer__viewport.is-dragging{
  cursor: grabbing;
}

.image-viewer__surface{
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  max-width: min(1400px, calc(100vw - 64px));
  max-height: calc(100vh - 128px);
  background: #fff;
  overflow: visible;
}

.image-viewer__img{
  display: block;
  max-width: min(1400px, calc(100vw - 64px));
  max-height: calc(100vh - 128px);
  width: auto;
  height: auto;
  object-fit: contain;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0,0,0,.06);
  user-select: none;
  -webkit-user-drag: none;
  transform-origin: center center;
  transition: transform 90ms ease;
  will-change: transform;
}

.image-viewer__viewport.is-dragging .image-viewer__img{
  transition: none;
}

body.viewer-open{
  overflow: hidden;
}

body.viewer-open #ropeCanvas{
  pointer-events: none !important;
}

body.viewer-open .top-buttons{
  z-index: 1200;
}

body.viewer-open .back-btn{
  z-index: 1700 !important;
  pointer-events: auto !important;
}

@media (max-width: 699px){
  .image-viewer__viewport{
    padding: 88px 16px 16px;
  }

  .image-viewer__surface,
  .image-viewer__img{
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 104px);
  }
}



/* ==============================
   POKEMON-LIKE ARTIFACT CARDS
   ============================== */
body.visuals .node .card{display:none !important;}
body.visuals .node .pcard{
  --pointer-x: 50%;
  --pointer-y: 50%;
  --background-x: 50%;
  --background-y: 50%;
  --pointer-from-center: 0;
  --pointer-from-top: .5;
  --pointer-from-left: .5;
  --card-opacity: 0;
  --glare-opacity: 0;
  --art-shadow: drop-shadow(0 12px 22px rgba(0,0,0,.10)) drop-shadow(0 2px 8px rgba(0,0,0,.05));
  --art-glow: drop-shadow(0 0 0 rgba(255,255,255,0));
  position: relative;
  width: 100%;
  height: 100%;
  pointer-events: auto;
  z-index: 2;
  transform: translate3d(0px,0px,0.01px);
  transform-style: preserve-3d;
  will-change: transform, visibility, z-index;
}
body.visuals .node .pcard *{outline:none !important;}
body.visuals .node .pcard.water{ --card-glow-rgb: 60, 226, 255; }
body.visuals .node .pcard.fire{ --card-glow-rgb: 255, 120, 92; }
body.visuals .node .pcard.grass{ --card-glow-rgb: 148, 240, 114; }
body.visuals .node .pcard.lightning{ --card-glow-rgb: 255, 221, 89; }
body.visuals .node .pcard.psychic{ --card-glow-rgb: 190, 105, 255; }
body.visuals .node .pcard.interacting{ z-index: 999999; }
body.visuals .node .pcard__translater,
body.visuals .node .pcard__rotator{
  width: 100%; height: 100%; display:block; perspective:600px; transform-style:preserve-3d; transform-origin:center; will-change: transform, filter;
}
body.visuals .node .pcard__translater{position:relative; transform: translate3d(0px,0px,0.01px) scale(1);}
body.visuals .node .pcard__rotator{
  position: relative;
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  overflow: visible;
  border-radius: 0;
  background: transparent !important;
  box-shadow: none !important;
  transition: transform .08s ease-out, filter .18s ease-out;
}
body.visuals .node .pcard.active .pcard__rotator,
body.visuals .node .pcard.interacting .pcard__rotator{
  filter: drop-shadow(0 0 12px rgba(var(--card-glow-rgb, 60, 226, 255), .035));
}
body.visuals .node .pcard__front,
body.visuals .node .pcard__front *{backface-visibility:hidden; transform-style:preserve-3d;}
body.visuals .node .pcard__front{
  position: relative;
  width: 100%;
  height: 100%;
  overflow: visible;
  isolation: isolate;
  transform: translate3d(0px,0px,0.01px);
  background: transparent !important;
}
body.visuals .node .pcard__img,
body.visuals .node .pcard__shine,
body.visuals .node .pcard__glare{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
}
body.visuals .node .pcard__img{
  display:block;
  object-fit:contain;
  object-position:center;
  border-radius:0 !important;
  background: transparent !important;
  transform: translate3d(0px,0px,0.01px);
  filter: var(--art-shadow) var(--art-glow);
}
body.visuals .node .pcard.mask-ready .pcard__shine,
body.visuals .node .pcard.mask-ready .pcard__glare,
body.visuals .node .pcard.mask-ready .pcard__shine::before,
body.visuals .node .pcard.mask-ready .pcard__shine::after,
body.visuals .node .pcard.mask-ready .pcard__glare::after{
  -webkit-mask-repeat:no-repeat;
  mask-repeat:no-repeat;
  -webkit-mask-position:center center;
  mask-position:center center;
  -webkit-mask-size:contain;
  mask-size:contain;
  -webkit-mask-mode:alpha;
  mask-mode:alpha;
}
body.visuals .node .pcard__shine,
body.visuals .node .pcard__shine::before,
body.visuals .node .pcard__shine::after,
body.visuals .node .pcard__glare,
body.visuals .node .pcard__glare::after{
  pointer-events:none;
  will-change: transform, opacity, background-image, background-size, background-position, filter;
  content:"";
}
body.visuals .node .pcard__shine{
  z-index:3;
  transform: translateZ(1px);
  background-image:
    url('./assets/pokemon-card/img/cosmos-bottom-trans.png'),
    repeating-linear-gradient(82deg, hsl(53, 65%, 60%) 0%, hsl(93, 56%, 50%) 8%, hsl(176, 54%, 49%) 16%, hsl(228, 59%, 55%) 24%, hsl(283, 60%, 55%) 32%, hsl(326, 59%, 51%) 40%, hsl(326, 59%, 51%) 48%, hsl(283, 60%, 55%) 56%, hsl(228, 59%, 55%) 64%, hsl(176, 54%, 49%) 72%, hsl(93, 56%, 50%) 80%, hsl(53, 65%, 60%) 88%),
    radial-gradient(circle farthest-corner at var(--pointer-x) var(--pointer-y), rgba(173,255,252,.22) 0%, rgba(121,156,255,.08) 24%, rgba(0,0,0,0) 58%);
  background-blend-mode: soft-light, normal, normal;
  background-position: var(--cosmosbg, center center), calc(18% + (var(--pointer-from-left) * 64%)) calc(18% + (var(--pointer-from-top) * 64%)), center center;
  background-size: cover, 220% 420%, cover;
  filter: brightness(.84) contrast(1.08) saturate(.78);
  mix-blend-mode: soft-light;
  opacity: calc(var(--card-opacity) * .34);
}
body.visuals .node .pcard__shine::before,
body.visuals .node .pcard__shine::after,
body.visuals .node .pcard__glare::after{
  position:absolute;
  inset:0;
}
body.visuals .node .pcard__shine::before{
  background-image: url('./assets/pokemon-card/img/cosmos-middle-trans.png'), repeating-linear-gradient(82deg, hsl(53, 65%, 60%) 0%, hsl(93, 56%, 50%) 8%, hsl(176, 54%, 49%) 16%, hsl(228, 59%, 55%) 24%, hsl(283, 60%, 55%) 32%, hsl(326, 59%, 51%) 40%, hsl(326, 59%, 51%) 48%, hsl(283, 60%, 55%) 56%, hsl(228, 59%, 55%) 64%, hsl(176, 54%, 49%) 72%, hsl(93, 56%, 50%) 80%, hsl(53, 65%, 60%) 88%);
  background-blend-mode: soft-light, normal;
  background-position: var(--cosmosbg, center center), calc(22% + (var(--pointer-from-left) * 56%)) calc(22% + (var(--pointer-from-top) * 56%));
  background-size: cover, 240% 500%;
  filter: brightness(.92) contrast(1.12) saturate(.74);
  mix-blend-mode: soft-light;
  opacity: .28;
}
body.visuals .node .pcard__shine::after{
  background-image: url('./assets/pokemon-card/img/glitter.png'), radial-gradient(circle at var(--pointer-x) var(--pointer-y), rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 30%);
  background-blend-mode: screen, normal;
  background-position: calc(50% + (var(--pointer-from-left) - .5) * 10%) calc(50% + (var(--pointer-from-top) - .5) * 10%), center center;
  background-size: 120% 120%, cover;
  filter: brightness(.88) contrast(1.04);
  mix-blend-mode: soft-light;
  opacity: .22;
}
body.visuals .node .pcard__glare{
  z-index:4;
  transform: translateZ(1.4px);
  background-image: radial-gradient(circle farthest-corner at var(--pointer-x) var(--pointer-y), rgba(255,255,255,.34) 0%, rgba(255,255,255,.18) 9%, rgba(185,234,255,.06) 18%, rgba(0,0,0,0) 34%);
  filter: brightness(.94) contrast(1.02) saturate(.94);
  mix-blend-mode: soft-light;
  opacity: calc(var(--glare-opacity) * .34);
}
body.visuals .node .pcard__glare::after{
  background-image: radial-gradient(circle farthest-corner at var(--pointer-x) var(--pointer-y), rgba(255,255,255,.18) 0%, rgba(180,140,255,.05) 16%, rgba(0,0,0,0) 42%);
  mix-blend-mode: soft-light;
  opacity: .24;
}

body.visuals .node .pcard.active,
body.visuals .node .pcard.interacting{
  z-index: 999999;
}

body.visuals .node .pcard.active .pcard__rotator,
body.visuals .node .pcard.interacting .pcard__rotator{
  filter: drop-shadow(0 0 18px rgba(var(--card-glow-rgb, 60, 226, 255), .08));
}

body.visuals .node .pcard.active .pcard__shine,
body.visuals .node .pcard.interacting .pcard__shine{
  opacity: calc(var(--card-opacity) * .95);
}

body.visuals .node .pcard.active .pcard__glare,
body.visuals .node .pcard.interacting .pcard__glare{
  opacity: var(--glare-opacity);
}

@media (max-width: 699px) {
  body.visuals #viewport{
    perspective: none;
  }

  body.visuals #tiles,
  body.visuals .tile,
  body.visuals .node{
    will-change: auto !important;
    transform-style: flat !important;
  }

  body.visuals .node .pcard,
  body.visuals .node .pcard__translater,
  body.visuals .node .pcard__rotator{
    will-change: auto !important;
    filter: none !important;
  }

  body.visuals .node .pcard__shine,
  body.visuals .node .pcard__glare,
  body.visuals #dust{
    display: none !important;
  }
}