/* ===================================================================
   PORTFOLIO DESIGN SYSTEM
   Premium dark-first theme with glassmorphism, gradients & micro-animations
   =================================================================== */

/* --- Шрифт --- */
/* Inter лежит на этом же сервере, а не грузится с fonts.googleapis.com.
   Раньше грузился оттуда, и это означало, что браузер каждого посетителя
   сам ходил на серверы Google, отдавая туда свой IP-адрес. Пока это было так,
   сноска в футере «сайт не собирает данные и ничего не передаёт за пределы
   РФ» была бы неправдой. Теперь внешних запросов у сайта нет вообще, и это
   видно в панели «Сеть» любого браузера.

   Один файл на подмножество вместо шести: это вариативная версия Inter,
   одна кривая покрывает все начертания от 300 до 800.

   Подмножества только latin и cyrillic. latin-ext (акцентированная латиница
   и валютные знаки, 85 КБ) выброшен намеренно: проверено поиском по исходникам,
   на сайте нет ни одного такого символа. Если появится (например Café), символ
   просто отрисуется системным шрифтом, ничего не сломается.

   Лицензия шрифта SIL OFL 1.1 разрешает размещение у себя, текст лежит рядом
   в public/fonts/OFL.txt. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* --- Reset & Base --- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  /* Dark theme (default) */
  --bg-primary: #071715;
  --bg-secondary: #0d2420;
  --bg-surface: rgba(9, 31, 28, 0.88);
  --bg-surface-hover: rgba(15, 47, 41, 0.96);
  --bg-glass: rgba(5, 24, 22, 0.74);

  --text-primary: #E2E8F0;
  --text-secondary: #94A3B8;
  /* 11.09.2026: было #64748B и давало 3.86:1 на фоне страницы при норме WCAG AA
     4.5:1 для обычного текста. Им набраны шесть мест мелким кеглем, от сноски о
     приватности до подписей на карточках проектов, то есть промахивался мимо
     нормы весь мелкий текст сайта сразу. Новое значение даёт 5.98 на фоне
     страницы и 4.68 на самом светлом фоне, который под ним бывает
     (--bg-surface-hover), и при этом остаётся заметно тусклее --text-secondary,
     так что три ступени текста по-прежнему различимы.
     Меняя это значение, пересчитайте коэффициент, а не подбирайте на глаз. */
  --text-muted: #8794A8;

  /* Названия приведены к цветам 11.09.2026: раньше оранжевый назывался
     indigo, а янтарный violet, оба имени остались от прежней палитры. */
  --accent-amber: #FF9D1E;
  --accent-gold: #FFC247;
  --accent-cyan: #20BFA9;
  --accent-emerald: #10B981;
  --accent-rose: #F43F5E;

  --gradient-primary: linear-gradient(135deg, #FF8A00, #FFC247);
  --gradient-hero: linear-gradient(100deg, rgba(4, 22, 20, 0.98) 10%, rgba(4, 22, 20, 0.82) 58%, rgba(4, 22, 20, 0.5) 100%);
  --gradient-accent: linear-gradient(135deg, #FF9D1E, #20BFA9);
  --gradient-card: linear-gradient(145deg, rgba(255, 157, 30, 0.09), rgba(32, 191, 169, 0.05));

  --border-color: rgba(255, 157, 30, 0.22);
  --border-subtle: rgba(148, 163, 184, 0.08);

  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.5);
  --shadow-glow: 0 0 34px rgba(255, 157, 30, 0.18);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;

  --transition-fast: 150ms ease;
  --transition-base: 300ms ease;
  --transition-slow: 500ms ease;

  --font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --nav-height: 72px;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--nav-height);
}

body {
  font-family: var(--font-family);
  background-color: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transition: background var(--transition-base), color var(--transition-base);
  min-width: 320px;
  overflow-x: hidden;
}

/* Фоновая картинка. Размер задаётся НЕ через inset: 0, а явной высотой в lvh.
   inset: 0 у fixed-элемента растягивает его на текущий layout viewport, а на
   телефоне тот меняется каждый раз, когда при скролле прячется и возвращается
   адресная строка браузера. Из-за `cover` картинка при этом перемасштабируется,
   и выглядит это как «в каждом разделе свой зум». lvh это большой viewport
   (адресная строка убрана), он от скролла не зависит, поэтому масштаб постоянен.
   100vh оставлен запасным значением для браузеров без поддержки lvh. */
body::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  z-index: -2;
  /* Фон нарисован в SVG прямо в проекте (см. комментарий внутри файла) и с
     02.10.2026 лежит в базе (site_media, id background.svg). Адрес в переменную
     кладёт content.jsx с отпечатком ?v=, а на статичных страницах статей её
     задаёт articles.css. До 26.07.2026 здесь лежала растровая картинка из
     интернета, чьё происхождение и права на неё установить было невозможно. */
  background: linear-gradient(rgba(4, 20, 18, 0.78), rgba(4, 20, 18, 0.92)), var(--site-bg-image) center / cover no-repeat;
}

#root { position: relative; z-index: 0; }

a {
  color: var(--accent-cyan);
  text-decoration: none;
  transition: color var(--transition-fast);
}

a:hover {
  color: var(--accent-amber);
}

h1,
h2,
h3,
h4 {
  line-height: 1.2;
  font-weight: 700;
}

/* --- Layout --- */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 100px 0;
  position: relative;
}

.section__title {
  font-size: 2.5rem;
  margin-bottom: 16px;
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.section__subtitle {
  font-size: 1.1rem;
  color: var(--text-secondary);
  max-width: 600px;
  margin-bottom: 48px;
}

/* --- Navbar --- */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--nav-height);
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border-subtle);
  z-index: 1000;
  transition: background var(--transition-base);
}

.navbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
}

/* Логотип стал <button> ради доступности с клавиатуры, поэтому здесь сброс
   собственного вида кнопки: без него браузер нарисовал бы серую рамку и залил
   фон, перекрыв градиентную заливку текста. */
.navbar__logo {
  padding: 0;
  border: 0;
  background: var(--gradient-primary);
  font-family: inherit;
  font-size: 1.3rem;
  font-weight: 800;
  cursor: pointer;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  letter-spacing: -0.5px;
}

.navbar__logo:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 4px;
  border-radius: 4px;
}

.navbar__links {
  display: flex;
  gap: 8px;
  list-style: none;
  align-items: center;
}

.navbar__link {
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-secondary);
  /* Именно перечисление свойств, а не `all`. `all` анимирует и outline, а он
     у этого элемента теперь рисует рамку фокуса: рамка проявлялась плавно из
     значений по умолчанию (3 px цветом текста) и нужной становилась только к концу
     перехода. Человек, быстро идущий табом, видел бы только смазанный след.
     Рамка фокуса обязана появляться мгновенно. */
  transition: color var(--transition-fast), background var(--transition-fast);
  cursor: pointer;
  background: none;
  border: none;
  font-family: var(--font-family);
}

.navbar__link:hover {
  color: var(--text-primary);
  background: var(--bg-surface);
}

.navbar__link--bulb::before,
.navbar__language-option--active::before {
  content: '';
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 6px;
  vertical-align: -2px;
  background: var(--site-bulb-image) center / 175% 175% no-repeat;
  opacity: 0.3;
  filter: brightness(0.45) saturate(0.65);
  transform: scale(0.82);
  transition: opacity var(--transition-fast), filter var(--transition-fast), transform var(--transition-fast);
}

.navbar__link--bulb:hover::before,
.navbar__link--bulb:focus-visible::before,
.navbar__language-option--active::before {
  opacity: 1;
  filter: brightness(1.2) saturate(1.2) drop-shadow(0 0 5px rgba(255, 174, 46, 0.9));
  transform: scale(1);
}

.navbar__language-switcher {
  display: inline-flex;
  align-items: center;
  padding: 3px;
  border: 1px solid var(--border-color);
  border-radius: 999px;
  background: rgba(5, 24, 22, 0.54);
}

.navbar__language-option {
  min-height: 32px;
  padding: 0 9px;
  border: 0;
  border-radius: 999px;
  color: var(--text-muted);
  background: transparent;
  font: 800 0.72rem var(--font-family);
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast), box-shadow var(--transition-fast);
}

.navbar__language-option::before {
  width: 12px;
  height: 12px;
  margin-right: 4px;
}

.navbar__language-option--active {
  color: #fff;
  background: var(--gradient-primary);
  box-shadow: 0 2px 10px rgba(255, 138, 0, 0.35);
}

.navbar__language-option:not(.navbar__language-option--active):hover {
  color: var(--text-primary);
  background: var(--bg-surface-hover);
}

.navbar__hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
}

.navbar__hamburger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--text-primary);
  border-radius: 2px;
  transition: all var(--transition-fast);
}

/* --- Hero --- */
.hero {
  /* svh, а не vh: на телефоне layout viewport меняется каждый раз, когда
     прячется и возвращается адресная строка, и первый экран из-за этого прыгал
     на ширинах от 481 до 768 px (ниже 480 высота и так переопределена на auto).
     Тот же приём уже применён к фоновой картинке, см. комментарий у body::before.
     Первая строка это запасное значение для браузеров без поддержки svh. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  background: var(--gradient-hero);
  position: relative;
  overflow: hidden;
  padding-top: var(--nav-height);
}

.hero::before {
  content: '';
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 157, 30, 0.12) 0%, transparent 70%);
  top: -100px;
  right: -200px;
  animation: float 8s ease-in-out infinite;
}

.hero::after {
  content: '';
  position: absolute;
  width: 400px;
  height: 400px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(6, 182, 212, 0.08) 0%, transparent 70%);
  bottom: -100px;
  left: -100px;
  animation: float 10s ease-in-out infinite reverse;
}

@keyframes float {

  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-30px);
  }
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 100px;
  background: rgba(255, 157, 30, 0.1);
  border: 1px solid rgba(255, 157, 30, 0.2);
  color: var(--accent-amber);
  font-size: 0.85rem;
  font-weight: 500;
  margin-bottom: 24px;
  animation: fadeInUp 0.8s ease both;
}

.hero__title {
  font-size: clamp(2.5rem, 6vw, 4.5rem);
  font-weight: 800;
  letter-spacing: -1.5px;
  margin-bottom: 16px;
  animation: fadeInUp 0.8s ease 0.1s both;
}

.hero__title-gradient {
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.hero__description {
  font-size: 1.2rem;
  color: var(--text-secondary);
  max-width: 560px;
  line-height: 1.7;
  margin-bottom: 36px;
  animation: fadeInUp 0.8s ease 0.2s both;
}

.hero__actions {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  animation: fadeInUp 0.8s ease 0.3s both;
}

.hero__stats {
  display: flex;
  gap: 48px;
  margin-top: 64px;
  animation: fadeInUp 0.8s ease 0.4s both;
}

.hero__stat-value {
  font-size: 2rem;
  font-weight: 800;
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.hero__stat-label {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-top: 4px;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(24px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 28px;
  border-radius: var(--radius-md);
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  border: none;
  font-family: var(--font-family);
  /* Именно перечисление свойств, а не `all`. `all` анимирует и outline, а он
     у этого элемента теперь рисует рамку фокуса: рамка проявлялась плавно из
     значений по умолчанию (3 px цветом текста) и нужной становилась только к концу
     перехода. Человек, быстро идущий табом, видел бы только смазанный след.
     Рамка фокуса обязана появляться мгновенно. */
  transition: background var(--transition-base), box-shadow var(--transition-base),
    transform var(--transition-base), color var(--transition-base),
    border-color var(--transition-base);
  text-decoration: none;
  /* Надпись и стрелка всегда в одну строку. Без этого «Открыть демо →» в узкой
     карточке переносил стрелку на вторую строку и кнопка становилась двухэтажной. */
  white-space: nowrap;
}

.btn--primary {
  background: var(--gradient-primary);
  color: #fff;
  box-shadow: 0 4px 16px rgba(255, 157, 30, 0.3);
}

.btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(255, 157, 30, 0.4);
  color: #fff;
}

.btn--secondary {
  background: var(--bg-surface);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
}

.btn--secondary:hover {
  background: var(--bg-surface-hover);
  transform: translateY(-2px);
}

.btn--sm {
  padding: 8px 18px;
  font-size: 0.85rem;
}

.btn--back {
  position: fixed;
  top: 20px;
  left: 20px;
  z-index: 1001;
  background: var(--bg-glass);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  color: var(--text-primary);
  padding: 10px 20px;
  border-radius: var(--radius-md);
  font-weight: 600;
  cursor: pointer;
  font-family: var(--font-family);
  /* Именно перечисление свойств, а не `all`. `all` анимирует и outline, а он
     у этого элемента теперь рисует рамку фокуса: рамка проявлялась плавно из
     значений по умолчанию (3 px цветом текста) и нужной становилась только к концу
     перехода. Человек, быстро идущий табом, видел бы только смазанный след.
     Рамка фокуса обязана появляться мгновенно. */
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.btn--back:hover {
  background: var(--bg-surface-hover);
}

/* --- Cards --- */
.card {
  background: var(--bg-surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 28px;
  transition: all var(--transition-base);
  position: relative;
  overflow: hidden;
}

.card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--gradient-card);
  opacity: 0;
  transition: opacity var(--transition-base);
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-glow);
  border-color: rgba(255, 157, 30, 0.25);
}

.card:hover::before {
  opacity: 1;
}

.card__content {
  position: relative;
  z-index: 1;
}

.card__icon {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  background: var(--gradient-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  margin-bottom: 16px;
  color: #fff;
}

.card__title {
  font-size: 1.15rem;
  font-weight: 700;
  margin-bottom: 8px;
}

.card__text {
  color: var(--text-secondary);
  font-size: 0.9rem;
  line-height: 1.6;
}

/* --- Skills --- */
.skills__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 24px;
}

.skill-card__items {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 16px;
}

.skill-item-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.skill-item-bullet {
  display: flex;
  /* flex-start, а не center. При center стрелка у длинного навыка, который
     переносится на две строки, вставала ровно между ними и переставала
     читаться как маркер списка. Маркер принадлежит первой строке. */
  align-items: flex-start;
  gap: 8px;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text-secondary);
  transition: color var(--transition-fast), transform var(--transition-fast);
}

.skill-item-bullet__icon {
  color: var(--accent-cyan);
  font-size: 1.1rem;
  /* Стрелка крупнее текста, и без этой поправки она сидит на пару
     пикселей выше строки, на которой должна стоять. */
  line-height: 1.35;
  flex: 0 0 auto;
  transition: transform var(--transition-fast), color var(--transition-fast);
}

.skill-item-bullet:hover {
  transform: translateX(6px);
  color: var(--text-primary);
}

.skill-item-bullet:hover .skill-item-bullet__icon {
  transform: scale(1.2);
  color: var(--accent-amber);
}

.hero__image-wrapper {
  position: relative;
  width: 380px;
  height: 380px;
  flex-shrink: 0;
  animation: fadeInUp 0.8s ease 0.4s both;
}

.hero__image-glow {
  position: absolute;
  inset: -20px;
  background: var(--gradient-primary);
  border-radius: 50%;
  opacity: 0.2;
  filter: blur(40px);
  animation: pulseGlow 4s ease-in-out infinite alternate;
}

.hero__image {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  border: 4px solid var(--border-color);
  box-shadow: var(--shadow-lg);
  z-index: 2;
  transition: all var(--transition-base);
}

.hero__image:hover {
  transform: scale(1.05);
  border-color: var(--accent-amber);
}

@keyframes pulseGlow {
  from {
    opacity: 0.15;
    transform: scale(0.95);
  }

  to {
    opacity: 0.3;
    transform: scale(1.05);
  }
}

/* --- Карусель (проекты и автоматизация) --- */
/* Лента вместо сетки: карточек больше, чем помещается в ряд, поэтому ряд
   прокручивается горизонтально, а ширина карточки фиксирована — значит их видно
   ровно столько, сколько влезает по ширине экрана. */
.carousel {
  position: relative;
}

.carousel__rail {
  display: flex;
  /* Промежуток вынесен в переменную, потому что из него считается ширина
     карточки ленты. Задай его числом в двух местах, и они однажды разъедутся. */
  --rail-gap: 28px;
  gap: var(--rail-gap);
  overflow-x: auto;
  scroll-behavior: smooth;
  /* Прилипание намеренно только на телефоне (см. медиазапрос ниже). На широком
     экране последняя карточка часто выступает за край на десяток-другой
     пикселей, а её точка прилипания оказывается за пределом прокрутки: браузер
     возвращает ленту в начало, и она вообще перестаёт двигаться. */
  scroll-padding-left: 4px;
  /* место под тень и подъём карточки на hover, иначе overflow их обрежет */
  padding: 8px 4px 20px;
  margin: -8px -4px -20px;
  /* Системная полоса прокрутки убрана: под лентой уже есть точки, и они говорят
     ровно то же самое, только понятнее — показывают, сколько всего карточек и на
     какой мы сейчас. Две шкалы под одной лентой читались как две разные. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.carousel__rail::-webkit-scrollbar {
  display: none;
}

.carousel__rail:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 4px;
  border-radius: var(--radius-xl);
}

/* Затемнение у того края, за которым спрятано продолжение ленты. Вместе со
   стрелками и точками это третий сигнал «здесь есть ещё карточки». */
.carousel::before,
.carousel::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 34px;
  width: 56px;
  z-index: 2;
  pointer-events: none;
  opacity: 1;
  transition: opacity var(--transition-base);
}

.carousel::before {
  left: -4px;
  background: linear-gradient(90deg, var(--bg-primary), transparent);
}

.carousel::after {
  right: -4px;
  background: linear-gradient(270deg, var(--bg-primary), transparent);
}

.carousel[data-start='true']::before,
.carousel[data-end='true']::after {
  opacity: 0;
}

.carousel__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--text-primary);
  background: rgba(4, 16, 15, 0.86);
  border: 1px solid var(--border-color);
  border-radius: 50%;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  transition: opacity var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast);
}

.carousel__arrow:hover:not(:disabled) {
  background: var(--bg-surface-hover);
  border-color: rgba(255, 157, 30, 0.4);
}

.carousel__arrow:disabled {
  opacity: 0;
  pointer-events: none;
}

.carousel__arrow--prev {
  left: -14px;
}

.carousel__arrow--next {
  right: -14px;
}

.carousel__dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
}

.carousel__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--border-color);
  cursor: pointer;
  transition: background var(--transition-fast), width var(--transition-fast);
}

.carousel__dot:hover {
  background: var(--text-muted);
}

.carousel__dot--active {
  width: 26px;
  border-radius: 999px;
  background: var(--gradient-primary);
}

.project-card__highlights {
  list-style: none;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.project-card__highlights li {
  position: relative;
  padding-left: 18px;
  font-size: 0.85rem;
  color: var(--text-secondary);
  line-height: 1.45;
}

.project-card__highlights li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gradient-primary);
}

.project-card__stack {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 20px;
}

.project-card__tag {
  padding: 3px 9px;
  border-radius: var(--radius-sm);
  font-size: 0.74rem;
  font-weight: 500;
  color: var(--text-muted);
  border: 1px solid var(--border-subtle);
  background: rgba(148, 163, 184, 0.05);
}

/* Правовая сноска на карточке. Приглушена настолько, чтобы не спорить с
   описанием проекта, но остаётся читаемой: её задача — показать, что проект не
   выдаёт себя за чужой продукт, ещё до того как посетитель откроет демо.
   Полная версия лежит внутри самого демо, в диалоге «О программе». */
.project-card__legal {
  margin: -8px 0 18px;
  padding-top: 12px;
  border-top: 1px solid var(--border-subtle);
  color: var(--text-muted);
  font-size: 0.72rem;
  line-height: 1.5;
}

.project-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
}

.project-card__note {
  font-size: 0.78rem;
  color: var(--text-muted);
  min-width: 0;
}

/* «Вход по коду» у приложений с бэкендом: отдельной строкой над примечанием. */
.project-card__access {
  display: block;
  font-weight: 600;
  color: var(--text-secondary);
}

/* Кнопка не ужимается под длинную подпись слева: сжимается подпись. */
.project-card__footer .btn {
  flex-shrink: 0;
  /* Главная кнопка карточки: 44 px высоты, иначе на телефоне палец мажет.
     Замер 14.09.2026 при btn--sm: 38 px. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* --- Automation & AI sections --- */
/* Инструменты автоматизации тоже лента: их шесть, в один ряд они не помещаются
   и раньше уезжали вниз простынёй. Карточка уже проектной, потому что в ней
   только текст. */
.auto__carousel {
  margin-bottom: 48px;
}

.carousel__rail > .card {
  flex: 0 0 320px;
  max-width: 100%;
}

.auto__flow {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 32px;
  margin-top: 24px;
}

.auto__flow-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 16px;
}

.auto__flow-steps {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.auto__flow-step {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  background: rgba(255, 157, 30, 0.08);
  border: 1px solid rgba(255, 157, 30, 0.15);
  border-radius: var(--radius-md);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-primary);
}

.auto__flow-arrow {
  color: var(--accent-amber);
  font-size: 1.2rem;
}

.ai__comparison {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 48px;
}

.ai__type-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 32px;
  transition: all var(--transition-base);
}

.ai__type-card:hover {
  border-color: rgba(255, 157, 30, 0.3);
  box-shadow: var(--shadow-glow);
}

.ai__type-card--local {
  border-color: rgba(16, 185, 129, 0.2);
}

.ai__type-card--local:hover {
  border-color: rgba(16, 185, 129, 0.4);
  box-shadow: 0 0 30px rgba(16, 185, 129, 0.1);
}

.ai__type-icon {
  font-size: 2rem;
  margin-bottom: 16px;
}

.ai__type-title {
  font-size: 1.3rem;
  font-weight: 700;
  margin-bottom: 8px;
}

.ai__type-text {
  color: var(--text-secondary);
  font-size: 0.9rem;
  line-height: 1.6;
}

.ai__models {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 32px;
}

.ai__models-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 20px;
}

.ai__model-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ai__model-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: rgba(255, 157, 30, 0.05);
  border-radius: var(--radius-md);
  transition: background var(--transition-fast);
}

.ai__model-item:hover {
  background: rgba(255, 157, 30, 0.1);
}

.ai__model-name {
  font-weight: 600;
  font-size: 0.95rem;
  min-width: 140px;
}

.ai__model-desc {
  color: var(--text-secondary);
  font-size: 0.85rem;
}

/* --- Footer --- */
.footer {
  padding: 32px 0;
  border-top: 1px solid var(--border-subtle);
  text-align: center;
}

.footer__text {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* Сноска о данных. Мелкая и приглушённая, как и положено правовой сноске, но
   намеренно НЕ спрятана под раскрывающийся блок: смысл её в том, чтобы её было
   видно без единого клика.
   С 01.10.2026 (просьба Михаила) карточка во всю ширину контейнера, как блоки
   над ней, а не узкая полоса 860 px посередине. Сплошная строка в 1150 px
   нечитаема, поэтому текст на широком экране делится на две колонки (не уже
   22rem каждая); на планшете и телефоне колонка одна сама собой. */
.footer__privacy {
  margin: 0 0 28px;
  padding: 20px 24px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.footer__privacy-heading {
  margin-bottom: 8px;
  color: var(--text-secondary);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.footer__privacy-text {
  color: var(--text-muted);
  font-size: 0.78rem;
  line-height: 1.75;
  text-wrap: pretty;
  columns: 2 22rem;
  column-gap: 40px;
}

.footer__privacy-more {
  margin-top: 10px;
  font-size: 0.78rem;
}

/* --- Fade-in on scroll --- */
.fade-in {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.fade-in--visible {
  opacity: 1;
  transform: translateY(0);
}

/* --- Responsive --- */
@media (max-width: 768px) {
  .section {
    padding: 64px 0;
  }

  .section__title {
    font-size: 2rem;
  }

  .navbar__links {
    display: none;
  }

  /* Подложка меню НЕ полупрозрачная. Раньше здесь стоял --bg-glass с блюром:
     на телефоне сквозь него просвечивал контент страницы, и пункты меню
     читались плохо. Блюр к тому же не везде срабатывает поверх фиксированного
     фонового изображения. */
  .navbar__links--open {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: var(--nav-height);
    left: 0;
    right: 0;
    background: #061a18;
    border-bottom: 1px solid var(--border-color);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
    padding: 16px;
    gap: 4px;
  }

  /* Затемнение всей страницы под открытым меню. Живёт внутри .navbar, поэтому
     наследует её z-index 1000 и гарантированно лежит выше контента, но ниже
     самой панели меню. Клик по нему закрывает меню. */
  .navbar__scrim {
    position: fixed;
    top: var(--nav-height);
    left: 0;
    right: 0;
    /* Высота задана явно, а не парой top/bottom: <button> не растягивается по
       вертикали от противоположных смещений и остаётся нулевой высоты. */
    height: calc(100vh - var(--nav-height));
    height: calc(100lvh - var(--nav-height));
    background: rgba(2, 10, 9, 0.72);
    border: 0;
    padding: 0;
    animation: navScrimIn var(--transition-base) ease;
  }

  @keyframes navScrimIn {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  .navbar__links--open {
    position: absolute;
    z-index: 1;
  }

  .navbar__hamburger {
    display: flex;
  }

  .skills__grid {
    grid-template-columns: 1fr;
  }

  /* Стрелки остаются и на телефоне: без них не видно, что карточек больше одной.
     Просто меньше и прижаты к самым краям, чтобы не закрывать текст. */
  .carousel__arrow {
    width: 36px;
    height: 36px;
    font-size: 1.15rem;
  }

  .carousel__arrow--prev {
    left: -6px;
  }

  .carousel__arrow--next {
    right: -6px;
  }

  .carousel::before,
  .carousel::after {
    width: 28px;
  }

  /* Здесь карточка равна ширине ленты, поэтому точка прилипания каждой из них
     достижима, и листание пальцем честно останавливается на карточке.
     `.card` перечислен отдельно: у него своя ширина с большей специфичностью. */
  .carousel__rail > *,
  .carousel__rail > .card {
    flex-basis: 100%;
    scroll-snap-align: start;
  }

  .carousel__rail {
    --rail-gap: 20px;
    scroll-snap-type: x mandatory;
  }

  .ai__comparison {
    grid-template-columns: 1fr;
  }

  .auto__flow-steps {
    flex-direction: column;
  }

  .auto__flow-arrow {
    transform: rotate(90deg);
  }
}

@media (max-width: 480px) {
  .container {
    padding: 0 16px;
  }

  .card {
    padding: 20px;
  }
}

/* --- 2026 portfolio refresh: growth visual language, legal pages and mobile polish --- */
.hero {
  background: var(--gradient-hero);
}

.hero::before { background: radial-gradient(circle, rgba(255, 157, 30, 0.15) 0%, transparent 70%); }
.hero::after { background: radial-gradient(circle, rgba(32, 191, 169, 0.11) 0%, transparent 70%); }

.btn--primary { box-shadow: 0 4px 18px rgba(255, 138, 0, 0.3); }
.btn--primary:hover { box-shadow: 0 8px 26px rgba(255, 138, 0, 0.42); }

.btn--bulb::before {
  content: '';
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
  background: var(--site-bulb-image) center / 165% 165% no-repeat;
  opacity: 0.38;
  filter: brightness(0.48) saturate(0.7);
  transform: scale(0.88) rotate(-5deg);
  transition: opacity var(--transition-base), filter var(--transition-base), transform var(--transition-base);
}

.btn--bulb:hover::before,
.btn--bulb:focus-visible::before {
  opacity: 1;
  filter: brightness(1.18) saturate(1.25) drop-shadow(0 0 7px rgba(255, 174, 46, 0.95));
  transform: scale(1.08) rotate(0deg);
}

.btn--bulb:hover,
.btn--bulb:focus-visible {
  box-shadow: 0 8px 30px rgba(255, 138, 0, 0.34), 0 0 24px rgba(255, 194, 71, 0.16);
}

/* Стили галочки согласия (.consent-field) удалены вместе с остальной формой
   26.07.2026: чекбокса, который бы её собирал, на сайте нет. */

.footer__links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin-bottom: 12px;
  font-size: 0.8rem;
}

.legal-page { min-height: 100vh; padding: 86px 0 64px; }
.legal-page__container { max-width: 920px; }
.legal-page__back { position: static; display: inline-flex; margin-bottom: 20px; }
.legal-card {
  padding: clamp(24px, 5vw, 56px);
  background: var(--bg-surface);
  backdrop-filter: blur(18px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.legal-card__eyebrow { color: var(--accent-amber); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; font-size: .72rem; }
.legal-card h1 { margin: 8px 0; font-size: clamp(1.8rem, 4vw, 2.8rem); }
.legal-card__updated { color: var(--text-muted); font-size: .85rem; }
.legal-card__operator { margin: 24px 0 32px; padding: 16px; background: var(--gradient-card); border-left: 3px solid var(--accent-amber); border-radius: var(--radius-sm); }
.legal-card section + section { margin-top: 28px; }
.legal-card h2 { margin-bottom: 8px; font-size: 1.1rem; }
.legal-card section p { color: var(--text-secondary); }
.legal-card__cross { margin-top: 32px; padding-top: 20px; border-top: 1px solid var(--border-subtle); font-size: .9rem; }

@media (max-width: 992px) {
  .hero { background: linear-gradient(rgba(4, 22, 20, .82), rgba(4, 22, 20, .94)); }
}

@media (max-width: 768px) {
  .navbar__links--open { align-items: stretch; max-height: calc(100vh - var(--nav-height)); overflow-y: auto; }
  .navbar__links--open li { width: 100%; }
  .navbar__links--open .navbar__link { width: 100%; text-align: left; padding: 12px 16px; }
  .navbar__links--open .navbar__language-switcher { margin: 10px 8px 0; width: max-content; }
  .btn--back { top: 12px; left: 12px; max-width: calc(100vw - 24px); }
}

@media (max-width: 480px) {
  .section__subtitle { margin-bottom: 32px; }
  .carousel__rail, .skills__grid { min-width: 0; }
  .auto__flow, .ai__models, .ai__type-card { padding: 22px; }
  .ai__model-item { align-items: flex-start; flex-wrap: wrap; }
  .ai__model-name { min-width: 0; }
  .footer__privacy { padding: 16px 18px; }
  .legal-page { padding-top: 72px; }
  .legal-card { border-radius: var(--radius-lg); }
}


/* --- Опыт и результаты --- */
/* Хронология одной колонкой с вертикальной осью слева. Не сетка: порядок здесь
   несёт смысл, а две колонки его ломают — глаз перестаёт читать сверху вниз. */
.timeline {
  position: relative;
  list-style: none;
  margin: 0 0 40px;
  padding: 0 0 0 34px;
}

/* Сама ось. Растворяется к низу: последняя запись самая старая, и обрубленная
   линия под ней выглядела бы как недорисованная. */
.timeline::before {
  content: '';
  position: absolute;
  left: 7px;
  top: 10px;
  bottom: 10px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--accent-amber), rgba(255, 157, 30, 0.35) 45%, transparent);
}

.timeline__item {
  position: relative;
}

.timeline__item + .timeline__item {
  margin-top: 20px;
}

.timeline__marker {
  position: absolute;
  left: -34px;
  top: 26px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--bg-primary);
  border: 3px solid var(--accent-amber);
  box-shadow: 0 0 0 4px rgba(255, 157, 30, 0.12);
}

/* У текущего места работы точка залита и подсвечена: это единственная запись,
   которая продолжается, и видно это должно быть без чтения дат. */
.timeline__item:first-child .timeline__marker {
  background: var(--gradient-primary);
  box-shadow: 0 0 0 5px rgba(255, 157, 30, 0.16), 0 0 18px rgba(255, 157, 30, 0.5);
}

.timeline__card {
  background: var(--bg-surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 24px 26px;
  transition: transform var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base);
}

.timeline__card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-glow);
  border-color: rgba(255, 157, 30, 0.3);
}

.timeline__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.timeline__role {
  font-size: 1.2rem;
  font-weight: 700;
}

.timeline__company {
  margin-top: 2px;
  color: var(--accent-cyan);
  font-size: 0.92rem;
  font-weight: 600;
}

.timeline__period {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text-muted);
  font-size: 0.8rem;
  white-space: nowrap;
}

.timeline__now {
  padding: 2px 9px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.14);
  border: 1px solid rgba(16, 185, 129, 0.3);
  color: var(--accent-emerald);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.timeline__summary {
  color: var(--text-secondary);
  font-size: 0.9rem;
  line-height: 1.6;
  margin-bottom: 20px;
}

/* Результаты в ряд, по одному на колонку. auto-fit с minmax, потому что у разных
   мест работы их разное число: три, три, два и один. Жёсткая сетка оставила бы
   у последней записи две пустые ячейки. */
.timeline__results {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--border-subtle);
}

.result__figure {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}

/* Тот же приём, что у счётчиков в первом экране: цифра залита градиентом.
   В режиме высокой контрастности возвращается обычный цвет, см. блок ниже. */
.result__value {
  font-size: 1.45rem;
  font-weight: 800;
  line-height: 1.1;
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.result__unit {
  color: var(--text-muted);
  font-size: 0.76rem;
}

.result__text {
  color: var(--text-secondary);
  font-size: 0.83rem;
  line-height: 1.5;
}

/* Образование, курс и язык. Это справка, а не результат, поэтому без карточек:
   строка значков, которая не спорит с хронологией выше. */
.credentials {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
}

.credentials__item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 16px;
  border: 1px solid var(--border-subtle);
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.05);
  color: var(--text-secondary);
  font-size: 0.82rem;
}

.credentials__icon {
  font-size: 1rem;
  line-height: 1;
}

/* Значок в списке возможностей секции ИИ: раньше размер задавался инлайном
   в разметке, теперь живёт здесь вместе с остальными стилями списка. */
.ai__model-icon {
  font-size: 1.3rem;
  line-height: 1;
}

@media (max-width: 768px) {
  .timeline {
    padding-left: 26px;
  }

  .timeline__marker {
    left: -26px;
    width: 13px;
    height: 13px;
    top: 22px;
  }

  .timeline::before {
    left: 6px;
  }

  .timeline__card {
    padding: 20px;
  }

  /* Дата на своей строке: на узком экране она вставала впритык к должности. */
  .timeline__head {
    flex-direction: column;
    gap: 8px;
  }

  .timeline__period {
    white-space: normal;
  }
}

@media (max-width: 480px) {
  .timeline__results {
    grid-template-columns: 1fr;
    gap: 14px;
  }

  .credentials__item {
    width: 100%;
  }
}

/* ===================================================================
   ДОСТУПНОСТЬ
   Блок стоит последним намеренно: это правила-страховки, и они должны
   выигрывать у всего, что объявлено выше.
   =================================================================== */

/* Видимый фокус для всего, по чему можно пройти табом.
   До 11.09.2026 рамка фокуса была ровно у двух элементов: логотипа в навбаре и
   самой ленты карусели. У всех кнопок, пунктов меню, стрелок и точек карусели,
   ссылок футера и переключателя языка её не было, и человек, идущий по сайту с
   клавиатуры, просто не видел, где находится. У .btn--bulb при фокусе менялась
   подсветка лампочки, но это не рамка и заменой ей не было.

   Именно :focus-visible, а не :focus: браузер сам решает, что фокус пришёл с
   клавиатуры, и после обычного клика мышью рамка не загорается. */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Круглым элементам круглая рамка: прямоугольник вокруг точки или стрелки
   читается как сбой вёрстки, а не как подсказка. */
.carousel__arrow:focus-visible,
.carousel__dot:focus-visible,
.navbar__language-option:focus-visible {
  border-radius: 999px;
}

.carousel__rail:focus-visible {
  border-radius: var(--radius-xl);
  outline-offset: 4px;
}

/* Меньше движения.
   До 11.09.2026 этого блока не было вообще, и системная настройка игнорировалась:
   постоянно крутились два пятна в первом экране, свечение под фотографией и
   появление блоков, плюс вся прокрутка была плавной.

   Важное место — .fade-in. Он прячет блок через opacity: 0, и если просто
   отключить переход, содержимое осталось бы невидимым навсегда. Поэтому здесь он
   принудительно показан, а в useReveal.js та же настройка проверяется ещё раз и
   наблюдатель не заводится. Две страховки на одну вещь тут уместны: цена ошибки
   это пустая страница. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  html,
  .carousel__rail {
    scroll-behavior: auto;
  }

  .fade-in {
    opacity: 1;
    transform: none;
  }

  /* Подъёмы карточек и кнопок при наведении тоже движение. Цвет и тень
     остаются: по ним и без сдвига понятно, что элемент отвечает. */
  .card:hover,
  .tile:hover,
  .btn--primary:hover,
  .btn--secondary:hover,
  .hero__image:hover,
  .skill-item-bullet:hover,
  .timeline__card:hover {
    transform: none;
  }
}

/* Режим принудительных цветов (высокая контрастность Windows).
   Заголовки сайта залиты градиентом через -webkit-text-fill-color: transparent.
   В этом режиме система не даёт нарисовать градиент, а прозрачный текст так
   прозрачным и остаётся: заголовки пропадают со страницы целиком. */
@media (forced-colors: active) {
  .section__title,
  .hero__title-gradient,
  .hero__stat-value,
  .navbar__logo,
  .result__value {
    -webkit-text-fill-color: currentColor;
    background: none;
    color: CanvasText;
  }

  .card,
  .tile__card,
  .home-nav,
  .contact-form__card,
  .timeline__card,
  .ai__type-card {
    border: 1px solid CanvasText;
  }

  a:focus-visible,
  button:focus-visible,
  [tabindex]:focus-visible {
    outline-color: Highlight;
  }
}

/* --- Размер зоны нажатия на телефоне --- */
/* Замерено на ширине 360 px: гамбургер был 32x24, стрелки карусели 36x36, точки
   9 px по высоте. Всё это пальцем ловится с третьего раза. Минимум для касания
   44x44, и здесь он добирается отступами, а не увеличением самих значков:
   рисунок остаётся прежним, растёт только область, которая ловит палец. */
.navbar__hamburger {
  /* Сами три полоски занимают 24x16, поэтому до 44 добираем 14 px сверху и
     снизу, 10 px по бокам. Отрицательный внешний отступ компенсирует внутренний:
     без него кнопка раздвинула бы шапку и логотип уехал бы влево. */
  padding: 14px 10px;
  margin: -14px -10px;
}

@media (max-width: 768px) {
  .carousel__arrow {
    width: 44px;
    height: 44px;
    font-size: 1.25rem;
  }

  /* Точка остаётся маленьким кружком, но ловит палец на всю высоту строки:
     ::before растягивает невидимую область поверх самой точки.

     Ширина 26 px, а не 44. Сорок четыре здесь сделали бы хуже, а не лучше:
     точки стоят в 26 px друг от друга, и сорокачетырёхпиксельные области налезали бы
     одна на другую: палец у границы попадал бы в соседнюю точку. 26x44 без
     наложений честнее и перекрывает минимум WCAG 2.5.8 (24x24). Основные способы
     листать на телефоне всё равно другие: жест и стрелки по 44 px. */
  .carousel__dot {
    position: relative;
    width: 11px;
    height: 11px;
  }

  .carousel__dot--active {
    width: 28px;
  }

  .carousel__dot::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 26px;
    height: 44px;
  }

  .carousel__dots {
    /* 15 px зазора плюс 11 px точки дают 26 px между центрами, ровно под
       ширину области нажатия выше: области соприкасаются, но не налезают. */
    gap: 15px;
    margin-top: 10px;
  }
}

/* Третья, тихая ступень кнопки.
   В первом экране три кнопки одного веса спорили между собой и не помещались в
   колонку шириной 600 px: «Скачать резюме» переносилось на вторую строку и это
   читалось как случайный перенос, а не как замысел. Главное действие на сайте
   одно, связаться; резюме это запасной путь, и вес у него должен быть меньше.
   Тихая кнопка на отдельной строке выглядит намеренно. */
.btn--quiet {
  padding-left: 0;
  padding-right: 0;
  background: none;
  border: none;
  color: var(--text-secondary);
  box-shadow: none;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--border-color);
}

.btn--quiet:hover {
  background: none;
  box-shadow: none;
  color: var(--text-primary);
  text-decoration-color: var(--accent-amber);
  transform: none;
}

/* Лампочка у тихой кнопки мельче: она здесь не зовёт, а помечает. */
.btn--quiet.btn--bulb::before {
  width: 22px;
  height: 22px;
  flex-basis: 22px;
}

/* Ссылка занимает всю строку, чтобы два ряда читались как «два действия, потом
   ещё одно», а не как строка, в которую что-то не влезло. */
.hero__actions .btn--quiet {
  flex-basis: 100%;
  justify-content: flex-start;
  margin-top: -2px;
}

@media (max-width: 992px) {
  .hero__actions .btn--quiet {
    justify-content: center;
  }
}

/* --- Страницы вместо одной длинной (с 01.10.2026) --- */
/* Шапка фиксированная. На главной первый экран сам учитывает её высоту, а
   остальные страницы начинаются сразу с секции, у которой на телефоне отступ
   64 px при шапке в 72 px: без этого заголовок блока уезжал бы под шапку. Сами
   блоки не тронуты, отступ даёт обёртка страницы. */
.page-offset {
  padding-top: var(--nav-height);
}

/* Страница навыков: три секции подряд (навыки, автоматизация, ИИ). У каждой отступ
   100 px сверху и снизу, между соседями выходило 200 px (128 на телефоне).
   Сверху у следующей секции отступа нет, снизу у предыдущей 56 px (40 на телефоне).
   Опыт и проекты секцию имеют одну, остальные страницы это не задевает. */
.page-offset .section + .section {
  padding-top: 0;
}

.page-offset .section:has(+ .section) {
  padding-bottom: 56px;
}

@media (max-width: 768px) {
  .page-offset .section:has(+ .section) {
    padding-bottom: 40px;
  }
}

/* Пункты меню и логотип стали ссылками вместо кнопок. Кнопке браузер сам
   ставит inline-block и line-height: normal, ссылке это надо дать явно: иначе
   пункт вырос бы по высоте (у body line-height 1.6), а в открытом меню на
   телефоне не растянулся бы на всю ширину. Размеры сверены замером со старой
   шапкой: 33 px высоты пункта на ПК, 41 px в меню телефона, логотип 32x25. */
a.navbar__link {
  display: inline-block;
  line-height: normal;
}

a.navbar__logo {
  display: block;
  line-height: normal;
}

/* Текущая страница выглядит так же, как пункт под курсором: светлый текст,
   подложка и зажжённая лампочка. aria-current ставит NavLink (и сборщик
   статических страниц статей), отдельного класса не заводим. */
.navbar__link[aria-current] {
  color: var(--text-primary);
  background: var(--bg-surface);
}

.navbar__link--bulb[aria-current]::before {
  opacity: 1;
  filter: brightness(1.2) saturate(1.2) drop-shadow(0 0 5px rgba(255, 174, 46, 0.9));
  transform: scale(1);
}

/* Пункты меню теперь длиннее («Мои проекты», «My experience»). Подпись не
   переносится внутри пункта: перенос делал пункт вдвое выше и ломал шапку. От
   769 до 1000 px (ниже уже бургер) пункты плотнее, чтобы все пять вместе с
   переключателем языка помещались в одну строку. */
.navbar__link {
  white-space: nowrap;
}

@media (min-width: 769px) and (max-width: 1000px) {
  .navbar__links {
    gap: 4px;
  }

  .navbar__link {
    padding: 8px 9px;
    font-size: 0.86rem;
  }

  .navbar__link--bulb::before {
    width: 12px;
    height: 12px;
    margin-right: 4px;
  }

  .navbar__language-switcher {
    margin-left: 4px;
  }
}

/* Зона нажатия в шапке на телефоне. Замер старой шапки: пункт меню 41 px в
   высоту, логотип 32x25, RU/EN 50x32, всё меньше 44. Добираем невидимым
   ::after поверх элемента, как у точек карусели: рисунок и расстояния между
   пунктами остаются прежними, растёт только область, которая ловит палец.
   Пункты стоят через 4 px, поэтому их области по 2 px вверх и вниз смыкаются,
   но не налезают одна на другую. */
@media (max-width: 768px) {
  .navbar__logo,
  .navbar__link,
  .navbar__language-option {
    position: relative;
  }

  .navbar__logo::after,
  .navbar__link::after,
  .navbar__language-option::after {
    content: '';
    position: absolute;
  }

  .navbar__logo::after { inset: -10px -6px; }
  .navbar__link::after { inset: -2px 0; }
  .navbar__language-option::after { inset: -6px 0; }
}

/* ===================================================================
   Содержимое из базы, главная одним экраном, форма, плитки (02.10.2026)
   =================================================================== */

/* --- Экран ожидания и отказа (ContentProvider) --- */
.boot {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px;
  text-align: center;
  color: var(--text-secondary);
  background: var(--bg-primary);
}

.boot__dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--gradient-primary);
  animation: bootPulse 1.1s ease-in-out infinite alternate;
}

@keyframes bootPulse {
  from { opacity: 0.35; transform: scale(0.8); }
  to { opacity: 1; transform: scale(1.1); }
}

.boot__label {
  font-size: 0.82rem;
  letter-spacing: 0.05em;
}

.boot__title {
  color: var(--text-primary);
  font-size: clamp(1.4rem, 4vw, 2rem);
}

.boot__text {
  max-width: 520px;
  line-height: 1.6;
}

.boot__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 8px;
}

.boot__actions .btn {
  min-height: 44px;
}

/* --- Главная: фото и цифры | окно «Разделы» | должность и описание ---
   Размеры через clamp() и vh: на 1366x768 и на 1920x1080 главная должна
   укладываться в один экран без прокрутки. Шапка фиксирована, поэтому её высота
   (72 px) вычтена в отступе сверху. Ниже 1200 px раскладка перестраивается, и
   страница прокручивается как обычно. */
/* Фон-градиент лежит на обёртке всей главной, а не на первом экране: форма и
   подвал ниже должны сидеть на нём же, иначе на стыке видна полоса. */
.home {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--gradient-hero);
  overflow: hidden;
}

.home__main {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

/* Пятна света живут на обёртке, а не на первом экране: так их не режет нижний край
   .hero, и на стыке с формой нет полосы. Те же пятна и та же анимация. */
.hero--home::before,
.hero--home::after {
  display: none;
}

.home {
  position: relative;
}

.home::before {
  content: '';
  pointer-events: none;
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 157, 30, 0.15) 0%, transparent 70%);
  top: -100px;
  right: -200px;
  animation: float 8s ease-in-out infinite;
}

.home::after {
  content: '';
  pointer-events: none;
  position: absolute;
  width: 400px;
  height: 400px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(32, 191, 169, 0.11) 0%, transparent 70%);
  bottom: -100px;
  left: -100px;
  animation: float 10s ease-in-out infinite reverse;
}

.hero.hero--home {
  flex: 1 1 auto;
  min-height: 0;
  background: none;
  padding: calc(var(--nav-height) + clamp(8px, 2vh, 24px)) 0 clamp(8px, 2vh, 22px);
}

.hero--home > .container {
  width: 100%;
}

.home-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(220px, 320px) minmax(260px, 340px) minmax(0, 1fr);
  align-items: center;
  gap: clamp(20px, 3vw, 44px);
}

.home-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(10px, 2.2vh, 22px);
}

.hero--home .hero__image-wrapper {
  /* 02.10.2026, второй заход: блок связи стал ниже на 90 px, фото подросло с 35vh до 39vh. */
  width: min(340px, 39vh);
  height: min(340px, 39vh);
}

.hero--home .hero__stats {
  width: 100%;
  margin-top: 0;
  gap: 12px;
  justify-content: space-between;
  text-align: center;
}

.hero--home .hero__stats > div {
  flex: 1 1 0;
  min-width: 0;
}

.hero--home .hero__stat-value {
  font-size: clamp(1.25rem, 3vh, 1.8rem);
}

.hero--home .hero__stat-label {
  font-size: 0.72rem;
  line-height: 1.3;
}

.hero--home .hero__text {
  text-align: left;
}

.hero--home .hero__badge {
  margin-bottom: clamp(10px, 2vh, 20px);
}

.hero--home .hero__title {
  font-size: clamp(1.9rem, 5.7vh, 3.5rem);
  letter-spacing: -1px;
  margin-bottom: clamp(8px, 1.6vh, 14px);
}

.hero--home .hero__description {
  max-width: none;
  font-size: clamp(0.92rem, 1.9vh, 1.05rem);
  line-height: 1.6;
  margin-bottom: clamp(8px, 1.6vh, 16px);
}

.hero--home .hero__actions .btn--quiet {
  min-height: 44px;
}

/* Окно «Разделы»: карточка со стеклом и рамкой, как остальные карточки сайта. */
.home-nav {
  padding: clamp(14px, 2.4vh, 22px);
  background: var(--bg-surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  animation: fadeInUp 0.8s ease 0.3s both;
}

.home-nav__title {
  margin-bottom: 12px;
  color: var(--text-secondary);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.home-nav__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.home-nav__link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: clamp(46px, 7vh, 56px);
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: rgba(255, 157, 30, 0.06);
  color: var(--text-primary);
  font-size: 1.05rem;
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}

.home-nav__link:hover,
.home-nav__link:focus-visible {
  color: var(--text-primary);
  background: rgba(255, 157, 30, 0.14);
  border-color: rgba(255, 157, 30, 0.35);
  transform: translateX(3px);
}

.home-nav__icon {
  flex: 0 0 auto;
  font-size: 1.35rem;
  line-height: 1;
}

.home-nav__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.home-nav__meta {
  margin-left: auto;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(255, 157, 30, 0.12);
  color: var(--accent-gold);
  font-size: 0.82rem;
  font-weight: 700;
}

/* --- Блок связи: три кнопки (формы с полями нет, см. ContactForm.jsx) --- */
.contact-form {
  position: relative;
  z-index: 1;
  padding-bottom: clamp(8px, 1.8vh, 20px);
}

.contact-form__card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 24px;
  padding: clamp(12px, 2vh, 18px) 20px;
  background: var(--bg-surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.contact-form__head {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.contact-form__title {
  font-size: 1.15rem;
}

.contact-form__note {
  color: var(--text-secondary);
  font-size: 0.88rem;
  line-height: 1.4;
}

.contact-form__actions {
  display: flex;
  gap: 8px;
}

.contact-form__actions .btn {
  min-height: 44px;
  padding: 10px 18px;
  font-size: 0.9rem;
}

.contact-form__actions .btn--bulb::before {
  width: 22px;
  height: 22px;
  flex-basis: 22px;
}

/* --- Подвал главной в одну строку --- */
.footer--compact {
  position: relative;
  z-index: 1;
  padding: 12px 0 14px;
}

.footer__line {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px 22px;
  font-size: 0.8rem;
}

.footer__line a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.footer__note {
  color: var(--text-muted);
}

/* --- Главная от 768 до 1199 px: фото и текст рядом, разделы рядом четырьмя --- */
@media (max-width: 1199px) {
  .home-grid {
    grid-template-columns: minmax(200px, 280px) minmax(0, 1fr);
    grid-template-areas:
      "left text"
      "nav nav";
    gap: 28px 36px;
  }

  .home-left { grid-area: left; }
  .hero--home .hero__text { grid-area: text; }
  .home-nav { grid-area: nav; }

  .hero--home .hero__image-wrapper {
    width: 240px;
    height: 240px;
  }

  .hero--home .hero__title {
    font-size: clamp(2rem, 4.6vw, 3rem);
  }

  .home-nav__list {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

}

/* --- Главная на телефоне: фото и имя, разделы 2x2, описание, цифры, форма ---
   Обёртки колонок растворяются (display: contents), и их дети встают в один
   столбец в нужном порядке. */
@media (max-width: 767px) {
  .hero.hero--home {
    padding: calc(var(--nav-height) + 20px) 0 28px;
  }

  .home-grid {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
    text-align: center;
  }

  .home-left,
  .hero--home .hero__text,
  .hero--home .hero__intro,
  .hero--home .hero__body {
    display: contents;
  }

  .hero--home .hero__image-wrapper { order: 1; align-self: center; width: 190px; height: 190px; }
  .hero--home .hero__badge { order: 2; align-self: center; margin-bottom: 0; }
  .hero--home .hero__title { order: 3; text-align: center; font-size: 2.1rem; margin-bottom: 0; }
  .home-nav { order: 4; }
  .hero--home .hero__description { order: 5; font-size: 1rem; margin-bottom: 0; }
  .hero--home .hero__actions { order: 6; justify-content: center; }
  .hero--home .hero__stats { order: 7; flex-wrap: nowrap; }

  .hero--home .hero__actions .btn--quiet {
    flex-basis: auto;
    justify-content: center;
    padding-left: 12px;
    padding-right: 12px;
  }

  .home-nav__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: 1fr;
  }

  .home-nav__link {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 4px;
    min-height: 84px;
    padding: 12px 14px;
    white-space: normal;
  }

  .home-nav__meta {
    margin-left: 0;
  }

  .footer__line a {
    min-height: 44px;
    padding: 0 8px;
  }

  .contact-form__card {
    flex-direction: column;
    align-items: stretch;
  }

  .contact-form__actions {
    flex-wrap: wrap;
  }

  /* Три кнопки в одну строку: без лампочки и с узкими полями они помещаются и
     на экране 360 px, а не оставляют одну кнопку на второй строке. */
  .contact-form__actions .btn {
    flex: 1 1 0;
    justify-content: center;
    padding: 10px 8px;
  }

  .contact-form__actions .btn--bulb::before {
    display: none;
  }
}

/* --- Проекты плиткой --- */
/* Шапка страницы проектов: слева заголовок, справа окно «Вход по коду».
   На телефоне окно идёт под подзаголовком во всю ширину. */
.projects-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 380px);
  align-items: start;
  gap: 16px 32px;
  margin-bottom: 36px;
}

.projects-head .section__subtitle {
  margin-bottom: 0;
}

.lock-card {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 16px 18px;
  background: var(--bg-surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.lock-card__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: rgba(255, 157, 30, 0.1);
  font-size: 1.2rem;
}

.lock-card__body {
  min-width: 0;
}

.lock-card__title {
  margin-bottom: 4px;
  font-size: 1rem;
  font-weight: 700;
}

.lock-card__text {
  color: var(--text-secondary);
  font-size: 0.86rem;
  line-height: 1.5;
}

@media (max-width: 860px) {
  .projects-head {
    grid-template-columns: minmax(0, 1fr);
    margin-bottom: 28px;
  }
}

.tiles {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 200px;
  grid-auto-flow: dense;
  gap: 16px;
}

.tile-item {
  position: relative;
  min-width: 0;
}

.tile-item--s { grid-column: span 1; grid-row: span 1; }
.tile-item--m { grid-column: span 2; grid-row: span 1; }
.tile-item--l { grid-column: span 2; grid-row: span 2; }

/* Плитка под курсором поднимается над соседями, чтобы раскрытая карточка
   ложилась поверх них. */
.tile-item:hover,
.tile-item:focus-within {
  z-index: 30;
}

.tile {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  color: var(--text-primary);
  border-radius: var(--radius-xl);
}

.tile:hover {
  color: var(--text-primary);
}

.tile__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  background: radial-gradient(circle at 30% 40%, rgba(32, 191, 169, 0.18), transparent 60%), #04100f;
  transition: filter var(--transition-base), border-color var(--transition-base), box-shadow var(--transition-base);
}

.tile__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tile__shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(4, 16, 15, 0.88) 0%, rgba(4, 16, 15, 0) 52%);
}

.tile__badge,
.tile__lock {
  position: absolute;
  top: 12px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(4, 16, 15, 0.78);
  border: 1px solid var(--border-color);
  backdrop-filter: blur(4px);
}

.tile__badge {
  left: 12px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent-gold);
}

.tile__lock {
  right: 12px;
  font-size: 0.8rem;
  line-height: 1.4;
}

.tile__label {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 14px;
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.25;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7);
}

.tile-item--l .tile__label {
  font-size: 1.3rem;
}

.tile:hover .tile__media,
.tile:focus-visible .tile__media {
  border-color: rgba(255, 157, 30, 0.55);
  box-shadow: var(--shadow-glow);
}

/* Остальные плитки гаснут, пока открыта одна. */
.tiles:has(.tile:hover) .tile-item:not(:hover) .tile__media,
.tiles:has(.tile:focus-visible) .tile-item:not(:focus-within) .tile__media {
  filter: grayscale(0.9) brightness(0.38);
}

.tile__caption {
  display: none;
}

/* Раскрытая карточка. Положение по горизонтали и вертикали задаёт
   ProjectTiles.jsx (left и top в пикселях от плитки): рядом с краем окна она
   растёт в сторону, где есть место. Пока скрыта, не ловит мышь. */
.tile__card {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 20;
  display: block;
  width: max(100%, 420px);
  max-width: min(480px, calc(100vw - 24px));
  /* Минус шапка (72 px) и по 12 px запаса сверху и снизу. Полосы прокрутки у
     карточки нет: тексты в базе короткие (описание около 160 знаков, три пункта),
     и карточка влезает в окно 1280x650. Не влезла бы, лишнее обрезалось бы,
     поэтому тест e2e сверяет scrollHeight и clientHeight у всех восьми. */
  max-height: calc(100vh - var(--nav-height) - 24px);
  overflow: hidden;
  padding: 18px 20px;
  background: #061a18;
  border: 1px solid rgba(255, 157, 30, 0.35);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg), var(--shadow-glow);
  visibility: hidden;
  opacity: 0;
  transform: translateY(6px) scale(0.98);
  transform-origin: top left;
  pointer-events: none;
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility 0s linear var(--transition-fast);
}

.tile:hover .tile__card,
.tile:focus-visible .tile__card {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition-delay: 0s;
}

.tile__card-title {
  display: block;
  margin-bottom: 6px;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.25;
}

.tile__card-desc {
  display: block;
  margin-bottom: 10px;
  color: var(--text-secondary);
  font-size: 0.86rem;
  line-height: 1.5;
}

.tile__card .project-card__highlights {
  margin-bottom: 12px;
  gap: 5px;
}

.tile__card .project-card__highlights li {
  font-size: 0.82rem;
  line-height: 1.4;
}

.tile__card .project-card__stack {
  margin-bottom: 12px;
}

.tile__card .project-card__legal {
  margin: -2px 0 12px;
  padding-top: 8px;
}

/* --- Проекты на телефоне и планшете без мыши: одна колонка строк со значком --- */
/* Устройства без мыши и узкие окна (до 700 px карточке негде раскрыться).
   Строка: значок слева, справа название с замком и описание в две строки.
   Размеры s/m/l здесь не работают: все строки одинаковые, порядок по sort. */
.tile__icon {
  display: none;
}

@media (hover: none), (max-width: 700px) {
  .tiles {
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: auto;
    gap: 10px;
  }

  .tile-item--l,
  .tile-item--m,
  .tile-item--s { grid-column: auto; grid-row: auto; }

  .tile {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: 76px;
    height: auto;
    padding: 12px 14px;
    background: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
  }

  .tile:active {
    background: var(--bg-surface-hover);
  }

  .tile__media,
  .tile__shade,
  .tile__label,
  .tile__card {
    display: none;
  }

  .tile__icon {
    display: grid;
    flex: none;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-md);
    background: rgba(255, 157, 30, 0.08);
    border: 1px solid var(--border-subtle);
  }

  .tile__icon img {
    display: block;
    width: 36px;
    height: 36px;
  }

  .tile__caption {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }

  .tile__caption-title {
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1.25;
  }

  .tile__caption-lock {
    margin-left: 6px;
    font-size: 0.8rem;
  }

  .tile__caption-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    color: var(--text-secondary);
    font-size: 0.8rem;
    line-height: 1.45;
  }
}

