/* kiosk.css — интерфейсный слой V5 для тач-стола (чат «UX / киоск»).
   Подключается ПОСЛЕ style.css и правит его там, где требуется стол.

   Три вещи разом:
   1) Масштаб. `html { font-size: clamp(...) }` + rem вместо px. На ноутбуке
      корень 14 px (всё как раньше), на столе 3840 px — 19,2 px, и весь
      интерфейс растёт пропорционально. Жёстких брейкпоинтов вроде
      `@media (min-width:3000px)` нет: между 1440 и 3840 масштаб плавный.
   2) Тач. Ни одной цели меньше 48 px (15 мм на 55″), ни одного текста
      меньше 14 px на столе (0,75rem × 19,2 = 14,4 px), никакого hover-пути.
   3) Киоск. Служебные элементы скрыты, пока нет ?admin=1; приглашение,
      справка, подложка карточки — здесь же.

   Размеры стола: 55″ 4K = 3840×2160 при DPR 1, шаг пикселя 0,317 мм.
   Класс: KEEP (спринт «Выставка», поток K).
   ------------------------------------------------------------------ */

:root {
  /* Базовый ритм: 1rem = 14 px на ноутбуке, 19,2 px на 4K-столе */
  --ux-tap: 3.43rem;          /* 48 px @14 → 66 px @19,2 (≈21 мм на 55″) */
  --ux-tap-min: 48px;         /* абсолютный пол независимо от масштаба */
  --ux-text-min: 0.75rem;     /* 10,5 px @14 → 14,4 px на столе */
  --ux-gap: 0.85rem;
  --ux-radius: 0.85rem;

  /* Ширины боковых панелей: ими же позиционируются кромочные вкладки */
  --ux-panel-left-w: clamp(360px, 22vw, 640px);
  --ux-panel-right-w: clamp(340px, 19vw, 560px);
  --ux-panel-inset: 1.1rem;

  /* Цвета: --muted поднят до 6,06:1 на фоне #0c0d1a (аудит A2 §15) */
  --ux-bg: #0c0d1a;
  --ux-text: #e1e2ed;
  --ux-muted: #8b8fa8;
  --ux-accent: #a78bfa;
  --ux-border: rgba(124, 58, 237, .28);
}

html {
  /* .5vw: 1440 px → 7,2 (пол 14) · 2560 → 12,8 (пол 14) · 3840 → 19,2 · LED 5616 → 22 */
  font-size: clamp(14px, 0.5vw, 22px);
}

/* ── Жесты браузера ────────────────────────────────────────────────
   Ничего из этого в V5 не было: пинч на панели зумил страницу,
   long-press выделял текст и открывал контекстное меню. */
html, body {
  /* pan-x pan-y, а не none: пинч-зум страницы запрещён, но боковые панели
     остаются прокручиваемыми пальцем (рецепт аудита A2 §16 п. 3).
     Канвасу base3d.js ставит touch-action:none сам. */
  touch-action: pan-x pan-y;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
/* Панели скроллятся пальцем по вертикали — и только они */
.panel, .bundle-panel-body, .card, .help-modal-body, #card-body {
  touch-action: pan-y;
  overscroll-behavior: contain;
}
/* Текст, который посетитель может захотеть выделить (в служебном режиме) */
[data-selectable] { -webkit-user-select: text; user-select: text; }

/* ── Служебные элементы: скрыты, пока нет ?admin=1 ─────────────────
   Ничего не удалено — вернуть можно адресом ...?admin=1 */
body:not(.is-admin) [data-admin] { display: none !important; }

#admin-badge {
  /* Слева внизу: по центру стоит плавающая кнопка «Сбросить вид» */
  position: fixed; left: 1.1rem; bottom: 0.7rem;
  z-index: 60; padding: 0.3rem 0.9rem; border-radius: 999px;
  background: rgba(245, 158, 11, .16); border: 1px solid rgba(245, 158, 11, .5);
  color: #fbbf24; font-size: var(--ux-text-min); letter-spacing: .06em;
  pointer-events: none;
}

/* ── Шапка ─────────────────────────────────────────────────────────
   Была 52 px фиксировано (16 мм на столе), шрифты 12–13 px. */
body:not(.display-mode) .hdr {
  height: auto; min-height: 3.6rem; padding: 0.4rem 1.4rem;
}
body:not(.display-mode) .hdr-left .logo { font-size: 1rem; }
body:not(.display-mode) .hdr-left .version { font-size: var(--ux-text-min); }
body:not(.display-mode) .hdr-nav { gap: 0.6rem; }

body:not(.display-mode) .nav-link,
body:not(.display-mode) .nav-btn {
  min-height: var(--ux-tap); min-width: var(--ux-tap);
  padding: 0 1rem; font-size: 0.95rem; border-radius: 0.6rem;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
}
/* Hover на столе не существует — оставляем только состояние нажатия */
body.kiosk .nav-link:hover, body.kiosk .nav-btn:hover { background: none; }
body.kiosk .nav-btn:active, body.kiosk .nav-link:active { background: rgba(124, 58, 237, .28); }

.nav-btn-icon { font-size: 1.15rem; line-height: 1; }
.nav-btn-label { font-size: 0.95rem; }

/* ── Путь «Все области › … » — он же кнопка «в начало» ─────────────
   Была пилюля 16 px без padding: 5 мм на столе, промахнуться легко. */
body:not(.display-mode) .breadcrumb {
  gap: 0.5rem; padding: 0.35rem 0.5rem;
  font-size: 1rem;
}
body:not(.display-mode) .breadcrumb .bc-root,
body:not(.display-mode) .breadcrumb .bc-current,
body:not(.display-mode) .breadcrumb .back-btn {
  min-height: var(--ux-tap); display: inline-flex; align-items: center;
  padding: 0 0.95rem; font-size: 1rem; border-radius: 999px;
}
body:not(.display-mode) .breadcrumb .bc-root.bc-root-link {
  background: rgba(124, 58, 237, .18); border: 1px solid var(--ux-border);
  color: #fff; font-weight: 600;
}
body:not(.display-mode) .breadcrumb .bc-root.bc-root-link:active { background: rgba(124, 58, 237, .34); }
body:not(.display-mode) .breadcrumb .bc-sep { font-size: 1.1rem; opacity: .55; }

/* ── Боковые панели ────────────────────────────────────────────────
   360/380 px на 3840 — 9,5 % ширины; текст 11–12 px. */
body:not(.display-mode) .panel-left  { width: var(--ux-panel-left-w); left: var(--ux-panel-inset); }
body:not(.display-mode) .panel-right { width: var(--ux-panel-right-w); right: var(--ux-panel-inset); }

/* Правая колонка: вид карты → список статей → связи (служебное).
   Три fixed-панели наезжали друг на друга, как только менялась высота
   любой из них; одна flex-колонка снимает вопрос раз и навсегда. */
body:not(.display-mode) .right-rail {
  position: fixed; right: var(--ux-panel-inset); top: 4.6rem; bottom: var(--ux-panel-inset);
  width: var(--ux-panel-right-w);
  display: flex; flex-direction: column; gap: 0.7rem;
  z-index: 22; pointer-events: none;
}
body:not(.display-mode) .right-rail > .panel,
body:not(.display-mode) .right-rail > .bundle-panel {
  position: static; width: 100%; right: auto; bottom: auto; top: auto;
  max-height: none; pointer-events: auto; box-sizing: border-box;
}
body:not(.display-mode) .right-rail > .panel-view,
body:not(.display-mode) .right-rail > .bundle-panel { flex: 0 0 auto; }
body:not(.display-mode) .right-rail > .panel-articles {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
}
body:not(.display-mode) .right-rail > .bundle-panel { max-height: 42vh; overflow-y: auto; }
/* Колонка не нужна на LED и не должна занимать место, когда пуста */
body.display-mode .right-rail { display: none !important; }
body:not(.display-mode) .panel {
  top: 4.6rem; border-radius: var(--ux-radius); padding: 1.1rem 1.2rem;
  max-height: calc(100vh - 7.5rem);
  /* width должен включать padding — иначе столбцы в ?admin=1 наезжают */
  box-sizing: border-box;
}
body:not(.display-mode) .panel-content { font-size: 0.95rem; line-height: 1.6; }
body:not(.display-mode) .panel-title { font-size: var(--ux-text-min); letter-spacing: .1em; }
/* Полоса прокрутки под палец */
body:not(.display-mode) .panel-left::-webkit-scrollbar,
body:not(.display-mode) .panel-right::-webkit-scrollbar { width: 0.6rem; }

/* ── Карточки уровня (левая панель) ────────────────────────────────*/
body:not(.display-mode) .cp-title { font-size: 1.4rem; }
body:not(.display-mode) .cp-subtitle { font-size: 0.85rem; }
body:not(.display-mode) .cp-stat { font-size: 1.6rem; }
body:not(.display-mode) .cp-stat-label { font-size: var(--ux-text-min); }
body:not(.display-mode) .cp-section { font-size: 0.85rem; margin: 1.4rem 0 0.7rem; }
body:not(.display-mode) .cp-card { padding: 0.95rem 1rem; border-radius: 0.7rem; margin-bottom: 0.7rem; }
body:not(.display-mode) .cp-card-name { font-size: 1.05rem; }
body:not(.display-mode) .cp-card-count { font-size: 0.9rem; }
body:not(.display-mode) .cp-card-stats { font-size: 0.85rem; }
body:not(.display-mode) .cp-card-top { font-size: 0.85rem; line-height: 1.55; }
/* Оговорка к плитке остатка. Строка в той же строке плиток (`.cp-stats-row`
   переносится), поэтому она видна рядом с числом, а не под всей карточкой, и
   не в свёртке. Не цель касания: читается без тапа и без наведения. */
.cp-noise-note:empty { display: none; }
.cp-noise-note {
  flex: 1 0 100%; margin: 0.2rem 0 0; padding: 0.55rem 0.7rem;
  border-left: 3px solid rgba(148, 163, 184, .5);
  background: rgba(148, 163, 184, .08); border-radius: 0.35rem;
  font-size: 0.85rem; line-height: 1.5; color: #c7cbd8;
}
.cp-noise-note b { color: #e2e6f0; font-weight: 600; }
body:not(.display-mode) .cp-card-top em { font-size: var(--ux-text-min); }
body:not(.display-mode) .cp-item { font-size: 0.9rem; min-height: 2.4rem; }
body:not(.display-mode) .cp-item-count { font-size: 0.9rem; }
/* Пилюли подтем внутри мета-карточки: были 18 px = 5,7 мм */
body:not(.display-mode) .cp-pill {
  min-height: var(--ux-tap); display: inline-flex; align-items: center;
  padding: 0 0.85rem; font-size: 0.85rem; border-radius: 999px;
}
body.kiosk .cp-card:hover { transform: none; box-shadow: none; }
body.kiosk .cp-card:active { transform: scale(.985); border-color: var(--ux-accent); }
body.kiosk .cp-pill:hover { background: rgba(124, 58, 237, .12); color: #c8cad8; }
body.kiosk .cp-pill:active { background: rgba(124, 58, 237, .34); color: #fff; }
/* Служебная строка «подтема N» */
.cp-dev { opacity: .6; }

/* Подписи годов на спарклайнах: #6b6f8a даёт 3,1:1 на фоне карточки.
   CSS-правило перебивает атрибут fill="..." из main.js. */
.cp-sparkline text { fill: var(--ux-muted); }

/* ── Сегменты и переключатели ──────────────────────────────────────*/
body:not(.display-mode) .seg-btn {
  min-height: var(--ux-tap); padding: 0 0.9rem; font-size: 0.9rem;
}
body:not(.display-mode) .layout-opt { padding: 0.5rem 0.4rem; min-height: var(--ux-tap); }
body:not(.display-mode) .layout-opt span { font-size: 0.9rem; }
body:not(.display-mode) .layout-opt small { font-size: var(--ux-text-min); }
body:not(.display-mode) .layout-opt input[type=radio],
body:not(.display-mode) .layout-opt input[type=checkbox] { width: 1.4rem; height: 1.4rem; }
/* Ползунки: дорожка 3 px и бегунок 12 px = 4 мм — пальцем не взять */
body:not(.display-mode) .viz-row input[type=range] { height: 2.4rem; }
body:not(.display-mode) .viz-row input[type=range]::-webkit-slider-thumb {
  width: 2.4rem; height: 2.4rem; border-radius: 50%;
}
body:not(.display-mode) .viz-label, body:not(.display-mode) .viz-val { font-size: 0.85rem; }
body:not(.display-mode) .section-title { font-size: var(--ux-text-min); }
body:not(.display-mode) .coord-legend {
  font-size: 0.85rem; line-height: 1.55; color: var(--ux-muted);
  margin-top: 0.6rem;
}
/* Служебные блоки внутри видимой панели «Вид карты» */
body:not(.is-admin) .research-block { display: none !important; }

/* ── Плавающие кнопки ──────────────────────────────────────────────*/
body:not(.display-mode) .floating-btn {
  min-height: var(--ux-tap); padding: 0 1.2rem; border-radius: 999px; gap: 0.5rem;
}
body:not(.display-mode) .floating-btn-icon { font-size: 1.2rem; }
body:not(.display-mode) .floating-btn-label { font-size: 0.95rem; }
body.kiosk .floating-btn:hover { transform: translateX(-50%); }
body.kiosk .floating-btn:active { transform: translateX(-50%) scale(.96); }

body:not(.display-mode) .bundle-panel-header { min-height: var(--ux-tap); }
body:not(.display-mode) .bundle-power { width: 2.6rem; height: 2.6rem; font-size: 1.1rem; }
body:not(.display-mode) .bundle-panel-title { font-size: 0.9rem; }

/* ── Подписи в 3D ──────────────────────────────────────────────────
   base3d.js ставит их инлайном 14/11 px (4,4 мм на столе). Инлайн бьётся
   только !important — постоянное решение (em в движке) в CONTRACTS. */
body:not(.display-mode) #scene > div > div { font-size: 1.05rem !important; }
body:not(.display-mode) #scene > div > div span { font-size: 0.85rem !important; }
/* Кликабельная подпись = тач-цель: раньше «толстая зона» была 6×10 px */
.cluster-label-clickable { padding: 0.9rem 1.2rem; margin: -0.9rem -1.2rem; }
body.kiosk .cluster-label-clickable:active { transform: translate(-50%, -50%) scale(1.09); }

/* ── Правая панель: список статей на столе (профиль single) ────────
   В dual этот список живёт на LED; на одиночном столе он нужен здесь,
   иначе половина 3840 px пустует, а посетитель ищет статьи только тыком
   по звёздам. Стили .dp-* существуют только под body.display-mode —
   здесь их «настольный» вариант. */
body:not(.display-mode) .panel-articles { display: block; }
/* В dual список показывает LED — на столе он лишний */
body.profile-dual:not(.display-mode) .panel-articles { display: none; }

body:not(.display-mode) .dp-article-card {
  background: rgba(21, 22, 37, .62);
  border: 1px solid rgba(47, 49, 70, .7);
  border-radius: 0.7rem;
  padding: 0.8rem 0.9rem;
  margin-bottom: 0.6rem;
  min-height: var(--ux-tap);
  cursor: pointer;
  transition: border-color .15s, transform .12s;
}
body.kiosk .dp-article-card:active {
  border-color: var(--ux-accent);
  transform: scale(.99);
}
body:not(.display-mode) .dp-article-title {
  font-size: 0.95rem; font-weight: 600; color: #fff;
  line-height: 1.4; margin-bottom: 0.3rem;
}
body:not(.display-mode) .dp-article-meta {
  font-size: 0.8rem; color: var(--ux-muted);
  display: flex; gap: 0.35rem; flex-wrap: wrap; margin-bottom: 0.2rem;
}
body:not(.display-mode) .dp-article-meta span:not(:last-child)::after {
  content: "·"; margin-left: 0.35rem; color: #3a3d55;
}
body:not(.display-mode) .dp-article-cited { font-size: 0.8rem; color: var(--ux-accent); font-weight: 600; }
body:not(.display-mode) .dp-empty { font-size: 0.9rem; color: var(--ux-muted); text-align: center; padding: 2rem 0.8rem; font-style: italic; }

/* Служебный режим: в колонку добавляется панель связей и блок точки вращения.
   Отдельных правил про наложение не нужно — колонка расставляет всё сама.
   На узком экране список статей уступает место рабочим контролам. */
@media (max-width: 1500px) {
  body.is-admin:not(.display-mode) .right-rail > .panel-articles { display: none; }
}

/* ── Карточка статьи ───────────────────────────────────────────────*/
.card-backdrop {
  position: fixed; inset: 0; z-index: 88; background: rgba(4, 4, 12, .55);
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
body.card-open .card-backdrop { opacity: 1; pointer-events: auto; }

/* ── Созвездия авторов: карточка автора одна ────────────────────────
   Тап по узлу открывал СРАЗУ ДВЕ карточки одного и того же автора:
   закреплённую справа (`#story-pin`, 620 px, созвездия не касается) и
   центральную модалку `#card`. Модалка ложилась ровно на созвездие —
   замер на 3840×2160: карточка [1434, 656, 971×848], узлы
   [1378, 851, 968×578], пересечение 912×578 px, — а её подложка
   (`inset: 0`, `pointer-events: auto`) съедала следующее касание, и
   событие тапа по сцене не рождалось вовсе. Посетитель не мог выбрать
   соседнего автора, пока не найдёт крестик: у стола это тупик.
   В этом режиме другой карточки в `#card` быть не может — тап в линзе
   перехватывается целиком (`main.js`, ветка `lens === 'coauthor'`), и
   внутрь попадает только автор. */
body.ux-lens-authors #card { display: none !important; }
body.ux-lens-authors .card-backdrop { opacity: 0 !important; pointer-events: none !important; }
body:not(.display-mode) .card {
  width: clamp(420px, 34vw, 900px); max-height: 78vh;
  padding: 1.6rem 1.8rem; border-radius: var(--ux-radius); z-index: 89;
}
body:not(.display-mode) .card-close {
  width: var(--ux-tap); height: var(--ux-tap); min-width: var(--ux-tap-min);
  min-height: var(--ux-tap-min); font-size: 1.6rem; border-radius: 0.6rem;
  display: grid; place-items: center; top: 0.7rem; right: 0.7rem;
}
body:not(.display-mode) .am-title { font-size: 1.25rem; line-height: 1.35; }
body:not(.display-mode) .am-row { font-size: 0.9rem; padding: 0.45rem 0; }
body:not(.display-mode) .am-key { font-size: var(--ux-text-min); }
body:not(.display-mode) .am-section-label { font-size: var(--ux-text-min); }
body:not(.display-mode) .am-abstract { font-size: 0.95rem; line-height: 1.65; }
body:not(.display-mode) .am-affiliations, body:not(.display-mode) .am-aff-item { font-size: 0.85rem; }
body:not(.display-mode) .am-badge { font-size: var(--ux-text-min); padding: 0.25rem 0.7rem; }

/* ── Плашка-пояснение (короткая, сама гаснет) ──────────────────────
   Не перехватывает касания: посетитель может продолжать крутить карту,
   пока она висит. Сверху по центру — под путём, над картой. */
.ux-toast {
  position: fixed; left: 50%; top: 6.4rem; transform: translate(-50%, -0.6rem);
  z-index: 95; max-width: min(46rem, 60vw);
  padding: 0.9rem 1.4rem; border-radius: 1.1rem;
  background: rgba(18, 19, 38, .95); border: 1px solid var(--ux-border);
  box-shadow: 0 0.8rem 2.4rem rgba(0, 0, 0, .5);
  color: var(--ux-text); font-size: 0.95rem; line-height: 1.45;
  text-align: center; opacity: 0; pointer-events: none;
  transition: opacity .25s, transform .25s;
}
.ux-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.ux-toast-title { color: #fff; font-weight: 600; }
.ux-toast-title::after { content: " — "; color: var(--ux-muted); font-weight: 400; }
body.attract-on .ux-toast { display: none; }

/* ── «Связи цитирования»: три ручки на столе (решение заказчика 20.09) ──
   Панель была целиком служебной; теперь на витрине видны связи вкл/выкл,
   плотность и прозрачность, остальное помечено data-admin в разметке.
   Ползунок прозрачности был 46 px — ниже порога тач-цели; поднят до 48.
   Замер 20.09 на 3840×2160: кнопка связей 50 px, метки плотности 85 px,
   тексты от 14,4 px. */
body:not(.display-mode) #bundle-panel input[type="range"] {
  height: max(48px, 2.5rem);
}
/* Висящая плашка — только легенда режима координат (решение заказчика 20.09).
   Сама плашка остаётся прозрачной для касаний (`pointer-events: none` выше):
   касание ест ТОЛЬКО кнопка, иначе плашка съедала бы тапы по карте. */
.ux-toast-close {
  display: block; margin: 0.8rem auto 0;
  min-height: max(48px, var(--ux-tap)); min-width: max(48px, 10rem);
  padding: 0 1.4rem; border-radius: 0.8rem;
  border: 1px solid var(--ux-border); background: rgba(255, 255, 255, .1);
  color: var(--ux-text); font: inherit; font-size: 0.95rem; font-weight: 600;
  pointer-events: auto; cursor: pointer;
}
.ux-toast-close:active { background: rgba(255, 255, 255, .18); }

/* ── «Загружаем область…» ──────────────────────────────────────────
   Между тапом по области и первым кадром нового уровня проходит до
   нескольких секунд (visual_l1_0.json — 12 МБ). Плашка отвечает на один
   вопрос: касание засчитано. Касаний не перехватывает — карту можно крутить
   дальше; появляется с задержкой, чтобы не мигать на кешированных уровнях. */
.ux-level-loading {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 90; display: flex; align-items: center; gap: 1rem;
  padding: 1.1rem 1.6rem; border-radius: 1.2rem;
  background: rgba(18, 19, 38, .95); border: 1px solid var(--ux-border);
  box-shadow: 0 0.8rem 2.4rem rgba(0, 0, 0, .5);
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .2s;
}
.ux-level-loading.is-on { opacity: 1; visibility: visible; }
.ux-level-loading-spin {
  width: 1.8rem; height: 1.8rem; flex: none; border-radius: 50%;
  border: 3px solid rgba(124, 58, 237, .25); border-top-color: #a78bfa;
  animation: ux-level-spin 0.9s linear infinite;
}
.ux-level-loading-text { display: flex; flex-direction: column; gap: 0.15rem; }
.ux-level-loading-title { color: var(--ux-text); font-size: 1rem; font-weight: 500; }
.ux-level-loading-name { color: #fff; font-size: 1.25rem; font-weight: 700; }
@keyframes ux-level-spin { to { transform: rotate(360deg); } }
body.attract-on .ux-level-loading { display: none; }

@media (prefers-reduced-motion: reduce) {
  .ux-level-loading { transition: none; }
  .ux-level-loading-spin { animation: none; border-top-color: rgba(124, 58, 237, .25); background: #a78bfa; }
}

/* ── «Всё вне выбранной темы — серым» — тумблер в «Виде карты» ─────
   Вся строка — одна тач-цель (≥ 48 px), подпись словом рядом с дорожкой.
   Положение рисует aria-checked из Engine.state.view.focusDim (focus-dim.js). */
.ux-switch {
  display: flex; align-items: center; gap: 0.8rem; width: 100%;
  min-height: var(--ux-tap); margin-top: 0.6rem; padding: 0.4rem 0.6rem;
  background: none; border: 1px solid var(--ux-border); border-radius: 0.9rem;
  color: var(--ux-text); font: inherit; font-size: 1rem; text-align: left;
  cursor: pointer;
}
.ux-switch:active { background: rgba(124, 58, 237, .18); }
.ux-switch-track {
  flex: none; position: relative; width: 3.2rem; height: 1.8rem; border-radius: 999px;
  background: rgba(255, 255, 255, .14); transition: background .15s;
}
.ux-switch-knob {
  position: absolute; top: 0.2rem; left: 0.2rem; width: 1.4rem; height: 1.4rem;
  border-radius: 50%; background: #fff; transition: transform .15s;
}
.ux-switch[aria-checked="true"] .ux-switch-track { background: var(--ux-accent); }
.ux-switch[aria-checked="true"] .ux-switch-knob { transform: translateX(1.4rem); }
.ux-switch-label { flex: 1; line-height: 1.3; }
@media (prefers-reduced-motion: reduce) { .ux-switch-track, .ux-switch-knob { transition: none; } }

/* ── «Коснитесь ещё раз, чтобы войти» ─────────────────────────────
   Первое касание по названию выделяет, второе входит (1.56.0). Без подсказки
   первое касание выглядит как отказ. Стоит под выделенной подписью и едет за
   ней (enter-hint.js); касаний не ест — второе касание идёт в подпись. */
.ux-enter-hint {
  position: fixed; left: 0; top: 0; z-index: 85;
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  max-width: 28rem; padding: 0.7rem 1.2rem; border-radius: 1rem;
  background: rgba(18, 19, 38, .92); border: 1px solid var(--ux-border);
  box-shadow: 0 0.6rem 2rem rgba(0, 0, 0, .5);
  text-align: center; pointer-events: none;
  opacity: 0; visibility: hidden; transition: opacity .15s;
}
.ux-enter-hint.is-on { opacity: 1; visibility: visible; }
.ux-enter-hint-name { color: #fff; font-size: 1.15rem; font-weight: 700; }
.ux-enter-hint-text { color: var(--ux-text); font-size: 1rem; }
body.attract-on .ux-enter-hint { display: none; }
@media (prefers-reduced-motion: reduce) { .ux-enter-hint { transition: none; } }

/* ── Подсказка-призрак: «два пальца» ───────────────────────────────
   Жест панорамирования есть с самого начала, но ничем не обозначен.
   Показываем один раз на уровень и убираем. */
.pan-hint {
  position: fixed; left: 50%; bottom: 8.5rem; transform: translateX(-50%);
  z-index: 60; display: flex; flex-direction: column; align-items: center; gap: 0.7rem;
  opacity: 0; pointer-events: none; transition: opacity .5s;
}
.pan-hint.is-on { opacity: 1; }
.pan-hint-stage { position: relative; width: 9rem; height: 3rem; }
.pan-hint-finger {
  position: absolute; top: 50%; width: 2.1rem; height: 2.1rem; margin-top: -1.05rem;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, rgba(255,255,255,.95) 0%, rgba(167,139,250,.85) 55%, rgba(124,58,237,.25) 100%);
  box-shadow: 0 0 1.4rem rgba(167, 139, 250, .55);
}
.pan-hint-finger-a { left: 0.4rem;  animation: ux-pan-a 2.8s ease-in-out infinite; }
.pan-hint-finger-b { right: 0.4rem; animation: ux-pan-b 2.8s ease-in-out infinite; }
.pan-hint-text {
  padding: 0.5rem 1.1rem; border-radius: 999px;
  background: rgba(18, 19, 38, .92); border: 1px solid var(--ux-border);
  color: var(--ux-text); font-size: 0.95rem; white-space: nowrap;
}
@keyframes ux-pan-a {
  0%, 100% { transform: translateX(0); }
  35%      { transform: translateX(2.4rem); }
  70%      { transform: translateX(1.2rem); }
}
@keyframes ux-pan-b {
  0%, 100% { transform: translateX(0); }
  35%      { transform: translateX(-2.4rem); }
  70%      { transform: translateX(-1.2rem); }
}
@media (prefers-reduced-motion: reduce) {
  .pan-hint-finger { animation: none !important; }
}
body.attract-on .pan-hint, body.card-open .pan-hint { display: none; }

/* ── Загрузка и ошибка ─────────────────────────────────────────────*/
#loading {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: var(--ux-bg); color: var(--ux-text); z-index: 200;
}
.loading-box { text-align: center; max-width: 34rem; padding: 2rem; }
.loading-title { font-size: 1.3rem; font-weight: 600; margin-top: 1.2rem; }
.loading-hint { font-size: 0.95rem; color: var(--ux-muted); margin-top: 0.5rem; }
.loading-tech { font-size: var(--ux-text-min); color: #6b6f8a; margin-top: 1.2rem; font-family: monospace; }
.loading-spinner {
  width: 2.6rem; height: 2.6rem; margin: 0 auto; border-radius: 50%;
  border: 3px solid rgba(124, 58, 237, .22); border-top-color: var(--ux-accent);
  animation: ux-spin 0.9s linear infinite;
}
#loading.is-error .loading-title { color: #fca5a5; }
.loading-retry {
  margin-top: 1.4rem; min-height: var(--ux-tap); padding: 0 1.6rem;
  font: inherit; font-size: 1rem; color: #fff; cursor: pointer;
  background: rgba(124, 58, 237, .28); border: 1px solid var(--ux-border);
  border-radius: 999px;
}
.loading-retry:active { background: rgba(124, 58, 237, .5); }
@keyframes ux-spin { to { transform: rotate(360deg); } }

/* ── Справка ───────────────────────────────────────────────────────
   Структура из V4 (что вижу / что могу / чего нет) + «откуда числа». */
.help-modal {
  position: fixed; inset: 0; z-index: 9998; display: none;
  align-items: center; justify-content: center;
}
.help-modal.is-on { display: flex; }
.help-modal-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .72); backdrop-filter: blur(6px); }
.help-modal-body {
  position: relative; z-index: 1; width: min(52rem, 92vw); max-height: 86vh;
  background: rgba(18, 19, 38, .985); border: 1px solid var(--ux-border);
  border-radius: 1.2rem; padding: 2rem 2.2rem 1.4rem; overflow-y: auto;
  box-shadow: 0 1.5rem 5rem rgba(0, 0, 0, .65);
}
.help-modal-close {
  position: absolute; top: 0.9rem; right: 1rem; background: none; border: none;
  color: var(--ux-muted); font-size: 1.8rem; cursor: pointer;
  width: var(--ux-tap); height: var(--ux-tap);
  min-width: var(--ux-tap-min); min-height: var(--ux-tap-min);
  display: grid; place-items: center; border-radius: 0.6rem;
}
.help-modal-close:active { color: #fff; background: rgba(124, 58, 237, .2); }
.help-modal-done {
  display: block; width: 100%; margin-top: 1.4rem; min-height: var(--ux-tap);
  font: inherit; font-size: 1rem; color: #fff; cursor: pointer;
  background: rgba(124, 58, 237, .26); border: 1px solid var(--ux-border);
  border-radius: 999px;
}
.help-modal-done:active { background: rgba(124, 58, 237, .48); }
.help-title { font-size: 1.5rem; font-weight: 600; color: #fff; margin-bottom: 0.35rem; padding-right: 3.5rem; }
.help-level { font-size: 0.85rem; color: var(--ux-accent); text-transform: uppercase; letter-spacing: .08em; margin-bottom: 1.4rem; }
.help-section { margin-bottom: 1.4rem; }
.help-section-title { font-size: 0.85rem; font-weight: 600; color: var(--ux-accent); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 0.5rem; }
.help-list { list-style: none; padding: 0; margin: 0; }
.help-list li {
  font-size: 1rem; color: var(--ux-text); line-height: 1.6;
  padding: 0.35rem 0 0.35rem 1.7rem; position: relative;
}
.help-list li::before { content: "•"; position: absolute; left: 0.35rem; color: var(--ux-accent); }
.help-list li.help-yes::before { content: "✓"; color: #34d399; font-weight: 600; }
.help-list li.help-no::before  { content: "×"; color: #f87171; font-weight: 600; }
.help-list li.help-hand::before { content: "✋"; color: var(--ux-accent); font-size: .9em; }
.help-list li.help-tap::before { content: "☞"; color: var(--ux-accent); }
.help-list li.help-num::before { content: "№"; color: #7c8496; font-weight: 600; font-size: .85em; }
.help-list li b { color: #fff; font-weight: 600; }
.help-list li i { font-style: italic; color: var(--ux-muted); }

/* ── Приглашение (attract) ─────────────────────────────────────────
   Полупрозрачное: галактика продолжает жить за текстом. */
.attract {
  position: fixed; inset: 0; z-index: 9997; display: none;
  align-items: center; justify-content: center; text-align: center;
  background: radial-gradient(ellipse at 50% 45%, rgba(9, 10, 22, .82) 0%, rgba(8, 9, 20, .9) 55%, rgba(6, 6, 14, .97) 100%);
  animation: ux-fade-in .6s ease both;
}
.attract.is-on { display: flex; }
.attract-inner { max-width: min(78rem, 86vw); padding: 3rem; }
.attract-title {
  font-size: clamp(2rem, 3.4vw, 4.4rem); font-weight: 700; color: #fff;
  letter-spacing: .01em; line-height: 1.15;
  text-shadow: 0 0 2.4rem rgba(124, 58, 237, .55);
}
.attract-lead {
  font-size: clamp(1rem, 1.1vw, 1.6rem); color: #c8cad8; line-height: 1.6;
  margin: 1.4rem auto 2.2rem; max-width: 46rem;
}
.attract-steps {
  list-style: none; margin: 0 auto 2.6rem; padding: 0;
  display: flex; gap: 1.6rem; justify-content: center; flex-wrap: wrap;
}
.attract-step {
  flex: 1 1 16rem; max-width: 20rem; text-align: left;
  font-size: 1.05rem; color: #d4d6e4; line-height: 1.5;
  padding: 1.1rem 1.2rem; border-radius: var(--ux-radius);
  background: rgba(124, 58, 237, .09); border: 1px solid var(--ux-border);
}
.attract-step-n {
  display: inline-grid; place-items: center; width: 2rem; height: 2rem;
  margin-right: 0.7rem; border-radius: 50%; font-size: 0.95rem; font-weight: 700;
  color: #fff; background: rgba(124, 58, 237, .55);
}
.attract-cta {
  display: inline-flex; align-items: center; gap: 1rem;
  font-size: clamp(1.4rem, 1.9vw, 2.6rem); font-weight: 600; color: #fff;
  padding: 1rem 2.4rem; border-radius: 999px;
  background: rgba(124, 58, 237, .2); border: 2px solid rgba(167, 139, 250, .55);
  animation: ux-pulse 2.6s ease-in-out infinite;
}
.attract-hand {
  width: 1.6em; height: 1.6em; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #fff 0%, #a78bfa 55%, rgba(124, 58, 237, 0) 72%);
  box-shadow: 0 0 0 0 rgba(167, 139, 250, .55);
  animation: ux-tap-ring 2.6s ease-out infinite;
}
.attract-gesture { margin-top: 1.8rem; font-size: 1rem; color: var(--ux-muted); }
/* Пока висит приглашение — интерфейс и подписи галактик не мешают тексту.
   #scene > div — слой DOM-подписей из base3d.js; канвас остаётся видимым. */
body.attract-on #scene > div { opacity: 0; transition: opacity .6s; }
/* Пока висит приглашение — интерфейс не мешает картинке */
body.attract-on .hdr,
body.attract-on .panel,
body.attract-on .breadcrumb,
body.attract-on .floating-btn,
body.attract-on .bundle-panel { opacity: 0; pointer-events: none; transition: opacity .5s; }

/* На LED приглашение зовёт к столу, а не к экрану */
.attract-display .attract-title { font-size: clamp(2.6rem, 3vw, 5rem); }
.attract-display .attract-steps { display: none; }

@keyframes ux-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ux-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(167, 139, 250, .28); }
  50%      { transform: scale(1.035); box-shadow: 0 0 2.6rem .6rem rgba(167, 139, 250, .12); }
}
@keyframes ux-tap-ring {
  0%   { box-shadow: 0 0 0 0 rgba(167, 139, 250, .55); }
  70%  { box-shadow: 0 0 0 1.4em rgba(167, 139, 250, 0); }
  100% { box-shadow: 0 0 0 0 rgba(167, 139, 250, 0); }
}

/* Уважаем системную настройку «меньше движения» */
@media (prefers-reduced-motion: reduce) {
  .attract, .attract-cta, .attract-hand, .loading-spinner { animation: none !important; }
}

/* ── Профиль single: контент второго экрана живёт на столе ─────────
   В single кнопка «Дисплей» не нужна даже в служебном режиме. */
body.profile-single #btn-display { display: none !important; }

/* ══ Раздел «Что интересного» ══════════════════════════════════════
   Аналитика V4, переложенная в тач. Правила приёмки (06.09):
   тултипов нет — только закреплённые карточки; легенда — фильтр;
   вместо точечных диаграмм полосы и списки; матрица заменена на
   «выбери тему → два списка»; долгого нажатия нет; один сюжет —
   один экран — одна мысль.
   ------------------------------------------------------------------ */

.nav-btn-accent {
  border-color: rgba(167, 139, 250, .55) !important;
  background: rgba(124, 58, 237, .16);
  color: #fff;
}
body.kiosk .nav-btn-accent:active { background: rgba(124, 58, 237, .38); }

/* ── Список сюжетов ────────────────────────────────────────────────*/
.story-picker {
  position: fixed; inset: 0; z-index: 9996; display: none;
  align-items: center; justify-content: center;
}
.story-picker.is-on { display: flex; }
.story-picker-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .74); backdrop-filter: blur(6px); }
.story-picker-body {
  position: relative; z-index: 1; width: min(70rem, 92vw); max-height: 88vh; overflow-y: auto;
  padding: 2.2rem 2.4rem; border-radius: 1.2rem;
  background: rgba(18, 19, 38, .985); border: 1px solid var(--ux-border);
  box-shadow: 0 1.5rem 5rem rgba(0, 0, 0, .65);
}
.story-picker-close {
  position: absolute; top: 0.9rem; right: 1rem; background: none; border: none;
  color: var(--ux-muted); font-size: 1.8rem; cursor: pointer;
  width: var(--ux-tap); height: var(--ux-tap);
  min-width: var(--ux-tap-min); min-height: var(--ux-tap-min);
  display: grid; place-items: center; border-radius: 0.6rem;
}
.story-picker-close:active { color: #fff; background: rgba(124, 58, 237, .2); }
.story-picker-title { font-size: 1.6rem; font-weight: 600; color: #fff; padding-right: 3.5rem; }
.story-picker-lead { font-size: 1rem; color: var(--ux-muted); line-height: 1.55; margin: 0.5rem 0 1.6rem; max-width: 46rem; }
.story-picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); gap: 1rem; }
.story-card {
  display: flex; flex-direction: column; gap: 0.5rem; text-align: left;
  min-height: 9rem; padding: 1.2rem 1.3rem; cursor: pointer;
  border-radius: 0.9rem; border: 1px solid rgba(47, 49, 70, .8);
  background: rgba(21, 22, 37, .7); color: inherit; font: inherit;
}
body.kiosk .story-card:active { border-color: var(--ux-accent); transform: scale(.99); }
.story-card-title { font-size: 1.15rem; font-weight: 600; color: #fff; }
.story-card-thought { font-size: 0.9rem; color: var(--ux-muted); line-height: 1.5; }
.story-card-badge { margin-top: auto; font-size: 0.8rem; color: var(--ux-accent); }

/* ── Лист сюжета: слева, карта остаётся видимой ────────────────────*/
.story-sheet {
  position: fixed; left: 1.1rem; top: 4.6rem; bottom: 1.1rem; z-index: 92;
  width: clamp(560px, 32vw, 1180px);
  display: none; flex-direction: column;
  border-radius: var(--ux-radius); border: 1px solid var(--ux-border);
  background: rgba(14, 15, 30, .97); box-shadow: 0 1rem 4rem rgba(0, 0, 0, .6);
  box-sizing: border-box; touch-action: pan-y; overscroll-behavior: contain;
}
.story-sheet.is-on { display: flex; }
/* Пока открыт сюжет, левая панель уровня не нужна: один экран — одна мысль */
body.story-open .panel-left { display: none; }
.story-sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.8rem 1rem 0.8rem 1.2rem; border-bottom: 1px solid rgba(47, 49, 70, .7);
}
.story-back {
  min-height: var(--ux-tap); padding: 0 1.2rem; cursor: pointer;
  font: inherit; font-size: 1rem; color: #fff; border-radius: 999px;
  background: rgba(124, 58, 237, .2); border: 1px solid var(--ux-border);
}
.story-back:active { background: rgba(124, 58, 237, .42); }
.story-close {
  width: var(--ux-tap); height: var(--ux-tap);
  min-width: var(--ux-tap-min); min-height: var(--ux-tap-min);
  background: none; border: none; color: var(--ux-muted); font-size: 1.8rem;
  cursor: pointer; border-radius: 0.6rem; display: grid; place-items: center;
}
.story-close:active { color: #fff; background: rgba(124, 58, 237, .2); }
.story-sheet-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 1.4rem 1.5rem 2rem; }
.story-title { font-size: 1.5rem; font-weight: 600; color: #fff; }
.story-thought { font-size: 1rem; color: #c8cad8; line-height: 1.6; margin: 0.5rem 0 1.4rem; max-width: 44rem; }

/* ── Фильтр-легенда (правило 2) ────────────────────────────────────*/
.story-filter { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.9rem; }
.story-chip {
  display: inline-flex; align-items: center; gap: 0.5rem;
  min-height: var(--ux-tap); padding: 0 1rem; cursor: pointer;
  font: inherit; font-size: 0.9rem; color: #c8cad8; border-radius: 999px;
  background: rgba(124, 58, 237, .1); border: 1px solid rgba(47, 49, 70, .8);
}
.story-chip.is-on { background: rgba(124, 58, 237, .34); color: #fff; border-color: var(--ux-accent); }
.story-chip-dot { width: 0.75rem; height: 0.75rem; border-radius: 50%; flex: 0 0 auto; }
.story-count { font-size: 0.85rem; color: var(--ux-muted); margin-bottom: 0.6rem; }
.story-hint { font-size: 0.85rem; color: var(--ux-muted); margin-bottom: 0.8rem; font-style: italic; }

/* ── Ранжированный список (вместо точечной диаграммы, правило 3) ───*/
.story-list { display: flex; flex-direction: column; gap: 0.6rem; }
.story-row {
  display: flex; flex-direction: column; gap: 0.35rem; text-align: left;
  padding: 0.9rem 1rem; cursor: pointer; font: inherit; color: inherit;
  border-radius: 0.7rem; border: 1px solid rgba(47, 49, 70, .7);
  background: rgba(21, 22, 37, .6); min-height: var(--ux-tap);
}
body.kiosk .story-row:active { border-color: var(--ux-accent); transform: scale(.995); }
.story-row-title { font-size: 0.98rem; font-weight: 600; color: #fff; line-height: 1.4; }
.story-row-meta { font-size: 0.82rem; color: var(--ux-muted); }
.story-row-measure { display: flex; align-items: center; gap: 0.7rem; margin-top: 0.2rem; }
.story-row-value { font-size: 0.85rem; color: #c8cad8; white-space: nowrap; }
.story-row-value b { color: #fff; font-size: 1rem; }
.story-bar { flex: 1 1 auto; height: 0.65rem; border-radius: 999px; background: rgba(255, 255, 255, .07); overflow: hidden; }
.story-bar-fill { display: block; height: 100%; border-radius: 999px; }
/* Пара полос «наблюдаемое / ожидаемое» в одной шкале («Что вспыхнуло»,
   «Разрывы»).
   Своей ширины у полосы нет — внутри только заливка в процентах, — поэтому
   при базисе auto она схлопывается в ноль, как только справа оказывается
   длинный текст: в узкой карточке темы так пропали обе. Отсюда явный базис,
   нижний предел и перенос строки: мера обязана быть видимой, а не
   «помещаться». Замер на 3840×2160, а не расчёт. */
.story-pair { flex: 1 1 8rem; min-width: 8rem; display: flex; flex-direction: column; gap: 0.22rem; }
.story-pair-row { display: flex; width: 100%; }
.bu-year .ru-row-measure, .story-rel-measure { flex-wrap: wrap; row-gap: 0.3rem; }
/* Дорожка под парой занимает всю строку, а текст отношения переносится под неё.
   Иначе ширину дорожки задаёт соседний текст, и у строк одного списка она
   разная: замер на 3840×2160 дал 239,9 px против 243,8 px — полосы разных
   соседей переставали быть сравнимыми, хотя шкала у них общая. */
.bu-year .ru-row-measure .story-pair, .story-rel-measure .story-pair { flex-basis: 100%; }

/* Разбивка цитирований моста одной полосой: три части складываются в cited_by.
   Ширина задана явно по той же причине, что и у пары полос выше. */
.br-split {
  display: flex; width: 100%; min-width: 8rem; height: 0.9rem;
  border-radius: 999px; overflow: hidden; margin: 0.7rem 0 0.5rem;
  background: rgba(255, 255, 255, .07);
}
.br-split-seg { display: block; height: 100%; }
.br-legend { display: flex; flex-wrap: wrap; gap: 0.3rem 1.1rem; font-size: 0.85rem; color: var(--ux-muted); }
.br-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.br-legend-item b { color: #fff; }
.story-row-numbers { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.6rem; font-size: 0.85rem; color: var(--ux-muted); }
.story-row-numbers b { color: #fff; font-size: 1rem; }
.story-arrow { color: var(--ux-accent); }
.story-row-woke { margin-left: auto; color: var(--ux-accent); }
.story-years { width: 100%; height: 3.4rem; margin: 0.25rem 0; }
.story-years text { fill: var(--ux-muted); font-family: inherit; }

/* ── Два списка вместо матрицы (правило 4) ─────────────────────────*/
.story-themes { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.2rem; }
.story-theme {
  display: inline-flex; align-items: center; gap: 0.5rem;
  min-height: var(--ux-tap); padding: 0 0.95rem; cursor: pointer;
  font: inherit; font-size: 0.88rem; color: #c8cad8; border-radius: 999px;
  background: rgba(124, 58, 237, .09); border: 1px solid rgba(47, 49, 70, .8);
}
.story-theme.is-on { background: rgba(124, 58, 237, .34); color: #fff; border-color: var(--ux-accent); }
.story-theme-n { color: var(--ux-muted); font-size: 0.8rem; }
.story-theme-head { padding: 0.6rem 0 0.6rem 0.9rem; margin-bottom: 1rem; }
.story-theme-title { font-size: 1.25rem; font-weight: 600; color: #fff; }
.story-theme-sub { font-size: 0.85rem; color: var(--ux-muted); margin-top: 0.2rem; }
.story-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 1.2rem; }
.story-col-title {
  font-size: 0.85rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; margin-bottom: 0.7rem;
}
.story-col-more { color: #34d399; }
.story-col-less { color: #f59e0b; }
.story-rel-list { display: flex; flex-direction: column; gap: 0.6rem; }
.story-rel {
  padding: 0.85rem 0.95rem; border-radius: 0.7rem;
  border: 1px solid rgba(47, 49, 70, .7); background: rgba(21, 22, 37, .6);
}
.story-rel-head { display: flex; align-items: center; gap: 0.5rem; }
.story-rel-name { font-size: 0.95rem; font-weight: 600; color: #fff; line-height: 1.35; }
.story-rel-measure { display: flex; align-items: center; gap: 0.7rem; margin: 0.45rem 0 0.3rem; font-size: 0.85rem; color: #c8cad8; }
.story-rel-nums { font-size: 0.82rem; color: var(--ux-muted); }
.story-empty-soft { font-size: 0.9rem; color: var(--ux-muted); line-height: 1.55; font-style: italic; padding: 0.6rem 0; }
.story-empty { font-size: 1rem; color: var(--ux-muted); padding: 2rem 0; text-align: center; }

/* ── Кнопки внутри сюжета ──────────────────────────────────────────*/
.story-map-btn, .story-open-article {
  margin-top: 0.6rem; min-height: var(--ux-tap); padding: 0 1.1rem; cursor: pointer;
  font: inherit; font-size: 0.88rem; color: #fff; border-radius: 999px;
  background: rgba(124, 58, 237, .2); border: 1px solid var(--ux-border);
}
.story-map-btn:active, .story-open-article:active { background: rgba(124, 58, 237, .45); }
.story-open-article { width: 100%; margin-top: 1.2rem; font-size: 1rem; }

/* ── Закреплённая карточка (замена тултипу, правило 1) ─────────────*/
.story-pin {
  position: fixed; right: 1.1rem; top: 4.6rem; z-index: 94;
  width: clamp(340px, 24vw, 620px); max-height: calc(100vh - 7.5rem);
  display: none; box-sizing: border-box;
  border-radius: var(--ux-radius); border: 1px solid var(--ux-border);
  background: rgba(14, 15, 30, .98); box-shadow: 0 1rem 4rem rgba(0, 0, 0, .6);
  touch-action: pan-y; overscroll-behavior: contain;
}
.story-pin.is-on { display: block; }
/* Пока карточка закреплена, правая колонка уступает ей место */
body.story-open .right-rail { display: none; }
.story-pin-close {
  position: absolute; top: 0.6rem; right: 0.7rem; z-index: 1;
  width: var(--ux-tap); height: var(--ux-tap);
  min-width: var(--ux-tap-min); min-height: var(--ux-tap-min);
  background: rgba(14, 15, 30, .9); border: none; color: var(--ux-muted);
  font-size: 1.7rem; cursor: pointer; border-radius: 0.6rem;
  display: grid; place-items: center;
}
.story-pin-close:active { color: #fff; background: rgba(124, 58, 237, .25); }
.story-pin-body { max-height: calc(100vh - 7.5rem); overflow-y: auto; padding: 1.3rem 1.4rem 1.6rem; }
.story-pin-title { font-size: 1.1rem; font-weight: 600; color: #fff; line-height: 1.4; padding-right: 3rem; }
.story-pin-meta { font-size: 0.85rem; color: var(--ux-muted); margin-top: 0.35rem; }
.story-pin-lead { font-size: 0.95rem; color: #c8cad8; line-height: 1.55; margin-top: 0.8rem; }
.story-pin-lead b { color: #fff; }
.story-pin-section {
  font-size: 0.82rem; font-weight: 600; color: var(--ux-accent);
  text-transform: uppercase; letter-spacing: .06em; margin: 1.2rem 0 0.6rem;
}
.story-src-list { display: flex; flex-direction: column; gap: 0.55rem; }
.story-src { padding: 0.7rem 0.8rem; border-radius: 0.6rem; background: rgba(21, 22, 37, .7); border: 1px solid rgba(47, 49, 70, .7); }
.story-src-name { display: block; font-size: 0.92rem; color: #fff; line-height: 1.35; }
.story-src-measure { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.4rem; font-size: 0.85rem; color: #c8cad8; }

/* ── «Как это посчитано» — определения дословно из данных ──────────*/
.story-method {
  margin-top: 1.6rem; padding: 0.9rem 1rem; border-radius: 0.7rem;
  background: rgba(124, 58, 237, .07); border: 1px solid rgba(47, 49, 70, .7);
}
.story-method > summary {
  cursor: pointer; list-style: none; min-height: var(--ux-tap); display: flex; align-items: center;
  font-size: 0.88rem; font-weight: 600; color: var(--ux-accent);
  text-transform: uppercase; letter-spacing: .06em;
}
.story-method > summary::-webkit-details-marker { display: none; }
.story-method > summary::after { content: " ▾"; margin-left: 0.4rem; }
.story-method[open] > summary::after { content: " ▴"; }
.story-method p, .story-method li { font-size: 0.85rem; color: var(--ux-muted); line-height: 1.6; }
.story-method p { margin: 0.6rem 0 0; }
.story-method ul { margin: 0.4rem 0 0; padding-left: 1.2rem; }
.story-method-title { color: #c8cad8; font-weight: 600; margin-top: 0.9rem !important; }

/* Приглашение и сюжеты не показываются одновременно */
body.attract-on .story-sheet, body.attract-on .story-picker, body.attract-on .story-pin { display: none !important; }
.story-cov { color: #6b6f8a; }

/* Пояснение вместо переключателя подписей в режиме «По цитированиям» */
body:not(.display-mode) .labels-note {
  font-size: 0.85rem; line-height: 1.55; color: var(--ux-muted); margin: 0.5rem 0 0;
}

/* ══ Досье темы на карточке уровня (M3) ════════════════════════════
   Каждое число рядом с покрытием; определения — в «Как это посчитано»
   дословно из defs файла. Кольца — индикация, не цель касания.
   ------------------------------------------------------------------ */
.dsr-wrap { margin: 1.2rem 0 0.4rem; }
.dsr-summary {
  font-size: 0.95rem; line-height: 1.6; color: #c8cad8;
  padding: 0.9rem 1rem; border-radius: 0.7rem;
  background: rgba(124, 58, 237, .08); border: 1px solid rgba(47, 49, 70, .7);
}
.dsr-section {
  font-size: 0.82rem; font-weight: 600; color: var(--ux-accent);
  text-transform: uppercase; letter-spacing: .06em; margin: 1.3rem 0 0.6rem;
}
.dsr-note { font-size: 0.82rem; color: var(--ux-muted); line-height: 1.5; margin-top: 0.5rem; }
.dsr-cov { font-size: 0.8rem; color: #6b7089; line-height: 1.5; margin-top: 0.5rem; }
.dsr-dim { color: var(--ux-muted); }

/* Термины */
.dsr-terms { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.dsr-term {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.8rem; border-radius: 999px; font-size: 0.85rem;
  color: #d4d6e4; background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(47, 49, 70, .8);
}
.dsr-term-mesh { border-color: rgba(167, 139, 250, .45); }
.dsr-term-n { color: var(--ux-muted); font-size: 0.78rem; }

/* Возраст */
.dsr-age { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.dsr-age-main { display: flex; flex-direction: column; line-height: 1.1; }
.dsr-age-main b { font-size: 2rem; color: #fff; font-weight: 600; }
.dsr-age-main span { font-size: 0.78rem; color: var(--ux-muted); text-transform: uppercase; letter-spacing: .06em; }
.dsr-age-side { flex: 1 1 12rem; font-size: 0.88rem; color: #c8cad8; line-height: 1.7; }
.dsr-age-side b { color: #fff; }

/* ── Полоса возраста темы ───────────────────────────────────────────
   Коробка — межквартильный размах, засечка — медиана, тонкая линия —
   от самой ранней статьи до самой поздней. Ось общая для всех тем, её
   концы подписаны: без подписей полоса показывала бы форму, но не место.
   Хвост тусклый и тонкий намеренно — от 1951 года до первого квартиля
   лежат единицы статей, и равный по яркости хвост читался бы как
   «тема идёт с пятидесятых». Ничего не зависит от наведения: на столе
   его нет, и все три числа стоят рядом словами. */
/* Пометка «тема на границе различимости». Стоит первой в досье, до всех
   чисел темы: прочитанная после вывода, она не работает. Вид тот же, что у
   пометки «не по теме» — оба говорят о свойстве темы, а не о её числах, и
   посетителю полезно узнавать их одним взглядом. Наведения не требует. */
.dsr-stability {
  margin: 0 0 0.9rem; padding: 0.7rem 0.85rem;
  border-left: 3px solid rgba(245, 158, 11, .55);
  background: rgba(245, 158, 11, .08); border-radius: 0.4rem;
  font-size: 0.88rem; line-height: 1.5; color: #e8d9b8;
}

.dsr-agebar { margin: 0.7rem 0 0.2rem; }
.dsr-agebar-track {
  position: relative; height: 0.9rem; border-radius: 0.45rem;
  background: rgba(255,255,255,.06);
}
.dsr-agebar-tail {
  position: absolute; top: 50%; transform: translateY(-50%);
  height: 2px; background: rgba(255,255,255,.28); border-radius: 1px;
}
.dsr-agebar-box {
  position: absolute; top: 0; bottom: 0; min-width: 3px;
  background: var(--ux-accent, #7c8cff); border-radius: 0.45rem; opacity: .75;
}
.dsr-agebar-med {
  position: absolute; top: -0.15rem; bottom: -0.15rem; width: 3px;
  margin-left: -1.5px; background: #fff; border-radius: 2px;
}
.dsr-agebar-scale {
  display: flex; justify-content: space-between;
  font-size: 0.8rem; color: var(--ux-muted); margin-top: 0.25rem;
}

/* Кольца потоков */
.dsr-rings { display: flex; gap: 0.9rem; justify-content: space-between; }
.dsr-ring { flex: 1 1 0; text-align: center; min-width: 0; }
/* Кольцо и число в нём — одна коробка: доля центрируется абсолютно,
   иначе при другом масштабе шрифта отрицательные отступы разъезжаются. */
.dsr-ring-figure { position: relative; width: 100%; max-width: 6.5rem; margin: 0 auto 0.5rem; }
.dsr-ring-figure svg { width: 100%; height: auto; display: block; }
.dsr-ring-value {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 1.05rem; font-weight: 600; color: #fff;
}
.dsr-ring-caption { font-size: 0.82rem; color: #c8cad8; line-height: 1.35; }
.dsr-ring-sub { font-size: 0.78rem; color: var(--ux-muted); margin-top: 0.15rem; }
.dsr-inflow { font-size: 0.88rem; color: #c8cad8; margin-top: 0.9rem; line-height: 1.6; }
.dsr-inflow span { color: var(--ux-muted); margin-right: 0.4rem; }
.dsr-inflow b { color: #fff; }

/* Журналы: сокращение на столе, полное имя по касанию */
.dsr-journals { display: flex; flex-direction: column; gap: 0.4rem; }
.dsr-journal {
  display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
  min-height: var(--ux-tap); padding: 0.5rem 0.85rem; cursor: pointer;
  font: inherit; text-align: left; color: #d4d6e4; border-radius: 0.6rem;
  background: rgba(255, 255, 255, .04); border: 1px solid rgba(47, 49, 70, .7);
}
body.kiosk .dsr-journal:active { border-color: var(--ux-accent); }
.dsr-journal.is-expanded { border-color: rgba(167, 139, 250, .5); }
.dsr-journal-name { font-size: 0.88rem; line-height: 1.4; }
.dsr-journal-n { font-size: 0.85rem; color: var(--ux-muted); flex: 0 0 auto; }

/* «Как это посчитано» — тот же вид, что в сюжетах */
.dsr-how {
  margin-top: 1.2rem; padding: 0.8rem 0.9rem; border-radius: 0.7rem;
  background: rgba(124, 58, 237, .06); border: 1px solid rgba(47, 49, 70, .7);
}
.dsr-how > summary {
  cursor: pointer; list-style: none; min-height: var(--ux-tap); display: flex; align-items: center;
  font-size: 0.85rem; font-weight: 600; color: var(--ux-accent);
  text-transform: uppercase; letter-spacing: .06em;
}
.dsr-how > summary::-webkit-details-marker { display: none; }
.dsr-how > summary::after { content: " ▾"; margin-left: 0.4rem; }
.dsr-how[open] > summary::after { content: " ▴"; }
.dsr-how p { font-size: 0.82rem; color: var(--ux-muted); line-height: 1.6; margin: 0.6rem 0 0; }
.dsr-how p b { color: #c8cad8; }

/* На LED досье не рисуем: там своя раскладка карточек */
body.display-mode .dsr-wrap { display: none; }

/* Похожие статьи внутри карточки (CONTRACTS v1.5.0 §5) */
.am-similar { display: flex; flex-direction: column; gap: 0.45rem; }
.am-similar-item {
  text-align: left; font: inherit; font-size: 0.9rem; line-height: 1.45;
  color: #d4d6e4; cursor: pointer; min-height: var(--ux-tap);
  padding: 0.6rem 0.85rem; border-radius: 0.6rem;
  background: rgba(255, 255, 255, .04); border: 1px solid rgba(47, 49, 70, .7);
}
body.kiosk .am-similar-item:active { border-color: var(--ux-accent); color: #fff; }

/* Остаток кластеризации (−1) — не тема: приглушён и всегда с оговоркой
   (CONTRACTS v1.6.0 §4.3). «Mainstream» в данных посетитель прочитал бы
   как «главное направление», то есть ровно наоборот смыслу. */
.story-noise-note {
  margin-top: 0.5rem; font-size: 0.8rem; line-height: 1.5;
  color: #7c8496; font-style: italic;
}
.story-src-noise, .story-rel-noise { border-style: dashed; opacity: .88; }
.story-theme-noise { border-style: dashed; color: var(--ux-muted); }
.story-theme-noise.is-on { color: #fff; }

/* ══ Река времени (сюжет «Как росла область», он же слайдер M4) ══════
   Полоса во всю ширину внизу: палец попадает в неё не глядя. Бегунок
   рисуется по дробному курсору, подпись — по целому году, иначе он
   дёргается ступенями по 6 лет в секунду.
   ------------------------------------------------------------------ */
.river {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 93;
  padding: 0.6rem 1.1rem 0.5rem;
  background: linear-gradient(to top, rgba(8, 9, 20, .97) 60%, rgba(8, 9, 20, .82));
  border-top: 1px solid rgba(124, 58, 237, .28);
  touch-action: none;   /* скраб пальцем, а не прокрутка страницы */
}
.river-plot {
  position: relative; height: 7.5rem; cursor: pointer;
  border-radius: 0.5rem; overflow: hidden;
  background: rgba(255, 255, 255, .03);
}
.river-svg { width: 100%; height: 100%; display: block; }
.river-cursor {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: #fff; box-shadow: 0 0 0.8rem rgba(255, 255, 255, .55);
  pointer-events: none;
}
.river-cursor-year {
  position: absolute; top: 0.3rem; left: 50%; transform: translateX(-50%);
  padding: 0.2rem 0.6rem; border-radius: 999px; white-space: nowrap;
  background: rgba(12, 13, 26, .92); border: 1px solid rgba(255, 255, 255, .3);
  color: #fff; font-size: 0.95rem; font-weight: 600;
}
.river-axis { position: relative; height: 1.4rem; margin-top: 0.3rem; }
.river-tick {
  position: absolute; transform: translateX(-50%);
  font-size: var(--ux-text-min); color: var(--ux-muted);
}
/* Плавающая кнопка не должна нырять под реку */
body.river-open .floating-btn { bottom: 11.5rem; }
body.river-open .story-sheet { bottom: 11rem; }
body.river-open #admin-badge { bottom: 11.5rem; }
body.display-mode .river { display: none; }

.river-counter { font-size: 1.15rem; color: #c8cad8; line-height: 1.5; }
.river-counter b { color: #fff; font-size: 1.5rem; }
.river-controls { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 0.9rem 0; }
.river-play, .river-reset {
  min-height: var(--ux-tap); padding: 0 1.3rem; cursor: pointer;
  font: inherit; font-size: 1rem; color: #fff; border-radius: 999px;
  background: rgba(124, 58, 237, .24); border: 1px solid var(--ux-border);
}
.river-play.is-playing { background: rgba(167, 139, 250, .42); }
.river-play:active, .river-reset:active { background: rgba(124, 58, 237, .5); }
.river-legend { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 0.9rem; }
.river-legend-item {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: 0.85rem; color: #c8cad8;
}

/* Близость у похожих статей: число обязательно, потому что порога нет —
   пять соседей находятся всегда, даже у одинокой статьи (решение 11.09). */
.am-similar-item { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; }
.am-similar-title { flex: 1 1 auto; }
.am-similar-score {
  flex: 0 0 auto; font-size: 0.8rem; color: var(--ux-accent);
  padding: 0.2rem 0.6rem; border-radius: 999px;
  background: rgba(124, 58, 237, .16); white-space: nowrap;
}
.am-similar-warn {
  margin-top: 0.6rem; font-size: 0.82rem; line-height: 1.5;
  color: #fbbf24; font-style: italic;
}
.am-similar-how {
  margin-top: 0.6rem; padding: 0.6rem 0.8rem; border-radius: 0.6rem;
  background: rgba(124, 58, 237, .06); border: 1px solid rgba(47, 49, 70, .7);
}
.am-similar-how > summary {
  cursor: pointer; list-style: none; min-height: var(--ux-tap); display: flex; align-items: center;
  font-size: 0.82rem; font-weight: 600; color: var(--ux-accent);
  text-transform: uppercase; letter-spacing: .06em;
}
.am-similar-how > summary::-webkit-details-marker { display: none; }
.am-similar-how > summary::after { content: " ▾"; margin-left: 0.4rem; }
.am-similar-how[open] > summary::after { content: " ▴"; }
.am-similar-how p { font-size: 0.82rem; color: var(--ux-muted); line-height: 1.6; margin: 0.5rem 0 0; }

/* Молодая тема в «Разговорах» и оговорка про смысл терминов в досье:
   не примечание мелким шрифтом, а строка, которую видно до чтения списка. */
.story-young {
  margin-bottom: 0.8rem; padding: 0.7rem 0.85rem; border-radius: 0.6rem;
  font-size: 0.85rem; line-height: 1.55; color: #d4d6e4;
  background: rgba(245, 158, 11, .1); border: 1px solid rgba(245, 158, 11, .35);
}
.dsr-warn {
  margin-top: 0.6rem; font-size: 0.82rem; line-height: 1.55;
  color: #d4d6e4; padding: 0.6rem 0.75rem; border-radius: 0.5rem;
  background: rgba(245, 158, 11, .09); border: 1px solid rgba(245, 158, 11, .3);
}

/* Третье число на карточке моста: сумма двух показанных — половина реальной.
   Не примечание, а предупреждение — иначе посетитель сложит и поверит. */
.story-pin-warn {
  margin-top: 0.7rem; padding: 0.7rem 0.85rem; border-radius: 0.6rem;
  font-size: 0.85rem; line-height: 1.55; color: #d4d6e4;
  background: rgba(245, 158, 11, .1); border: 1px solid rgba(245, 158, 11, .35);
}
.story-pin-warn b { color: #fff; }

/* Плашка «не по теме»: слово, а не символ — глиф потребовал бы легенды,
   которую посетитель у стола не откроет (решение 11.09, принято «Наукой»). */
.off-topic-badge {
  display: inline-flex; align-items: center; margin-left: 0.5rem;
  padding: 0.15rem 0.55rem; border-radius: 999px; white-space: nowrap;
  font-size: 0.75rem; color: #fbbf24;
  background: rgba(245, 158, 11, .14); border: 1px dashed rgba(245, 158, 11, .5);
}
.dsr-offtopic {
  margin: 0.8rem 0; padding: 0.8rem 0.9rem; border-radius: 0.6rem;
  font-size: 0.88rem; line-height: 1.6; color: #d4d6e4;
  background: rgba(245, 158, 11, .09); border: 1px solid rgba(245, 158, 11, .3);
}

/* ══ Сюжет «Российские работы» ══════════════════════════════════════
   Оговорка про PubMed и РИНЦ стоит ПЕРВОЙ и крупнее числа: посетитель
   в России прочитает долю как утверждение о российской науке, а это
   неправда (docs/UI_TEXT_REVIEW.md §4.1). */
.ru-warning {
  margin-bottom: 1.2rem; padding: 1rem 1.1rem; border-radius: 0.7rem;
  font-size: 0.95rem; line-height: 1.6; color: #f1f2f7;
  background: rgba(245, 158, 11, .13); border-left: 4px solid #f59e0b;
}
.ru-total { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.6rem; }
.ru-total b { font-size: 2.4rem; font-weight: 600; color: #fff; line-height: 1.1; }
.ru-total-share { font-size: 0.95rem; color: var(--ux-muted); }
.ru-map-btn {
  margin-top: 1rem; min-height: var(--ux-tap); padding: 0 1.3rem; cursor: pointer;
  font: inherit; font-size: 1rem; color: #fff; border-radius: 999px;
  background: rgba(124, 58, 237, .24); border: 1px solid var(--ux-border);
}
.ru-map-btn.is-on { background: rgba(167, 139, 250, .45); }
.ru-map-btn:active { background: rgba(124, 58, 237, .5); }
.ru-signs, .ru-rows { display: flex; flex-direction: column; gap: 0.5rem; }
.ru-sign, .ru-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.9rem;
  font-size: 0.9rem; color: #c8cad8;
}
.ru-sign-name, .ru-row-name { flex: 0 0 42%; display: flex; align-items: center; gap: 0.45rem; }
.ru-sign-measure, .ru-row-measure { flex: 1 1 auto; display: flex; align-items: center; gap: 0.6rem; }
.ru-sign-measure b, .ru-row-measure b { color: #fff; min-width: 3.5rem; text-align: right; }
.ru-row-share { color: var(--ux-muted); font-size: 0.82rem; min-width: 3rem; }

/* Линза соавторства: карточка автора и список групп */
.ca-main { font-size: 0.95rem; color: #fff; line-height: 1.45; }
/* Размер группы — строкой с подписью, а не числом через точку рядом с
   именем: голое «50» читается как «в группе пятьдесят человек». */
.ca-sub { font-size: 0.85rem; color: var(--ux-muted); margin-top: 0.15rem; }
/* Объём и признак отбора рядом с заголовком списка — тем же тоном, что
   подпись: это оговорка к списку, а не его часть. */
.am-section-scope { font-size: 0.82rem; color: var(--ux-muted); font-weight: 400; }
.ca-sub b { color: #fff; font-weight: 600; }

/* Оговорка про группы в карточке автора (модалка движка). Видна всегда и
   рядом со строками, о которых говорит: карточку открывают мимо сюжета, а
   по адресу ?lens=coauthor — и вовсе без него. Не сворачивается: на столе
   нет наведения, а «подробнее» посетитель не нажмёт. */
.am-caveat {
  margin-top: 0.9rem; padding: 0.7rem 0.85rem;
  border-left: 3px solid rgba(167, 139, 250, .55);
  background: rgba(167, 139, 250, .08); border-radius: 0.4rem;
  font-size: 0.85rem; line-height: 1.5; color: #c8cad8;
}
.ca-mates { display: flex; flex-direction: column; gap: 0.45rem; }
.ca-mate {
  display: flex; flex-direction: column; gap: 0.35rem; text-align: left;
  min-height: var(--ux-tap); padding: 0.55rem 0.8rem; cursor: pointer;
  font: inherit; color: inherit; border-radius: 0.6rem;
  background: rgba(255, 255, 255, .04); border: 1px solid rgba(47, 49, 70, .7);
}
body.kiosk .ca-mate:active { border-color: var(--ux-accent); }
.ca-mate-name { font-size: 0.9rem; color: #fff; }
.ca-mate-measure { display: flex; align-items: center; gap: 0.6rem; font-size: 0.82rem; color: var(--ux-muted); }
.ca-mate-measure b { color: #c8cad8; white-space: nowrap; }

/* ── Сюжет «Что вспыхнуло» ─────────────────────────────────────────*/
/* Пометка «предварительно» — СЛОВОМ, как и «не по теме»: значок потребовал бы
   легенды, а её у стола никто не открывает. Под строкой стоит объяснение,
   потому что само слово не говорит, чем такой всплеск отличается. */
.bu-flag {
  display: inline-flex; align-items: center; margin-left: 0.5rem;
  padding: 0.15rem 0.55rem; border-radius: 999px; white-space: nowrap;
  font-size: 0.75rem; font-weight: 400; color: #fbbf24;
  background: rgba(245, 158, 11, .14); border: 1px dashed rgba(245, 158, 11, .5);
}
.bu-run .story-row-meta { font-size: 0.9rem; color: #c8cad8; }
.bu-about { font-size: 0.9rem; line-height: 1.6; color: #c8cad8; }
/* Год, с которого пришли в карточку, — чтобы строка не потерялась в списке */
.ru-row.is-on .ru-row-name { color: #fff; font-weight: 600; }

/* ── Выдвижные панели с кромочными вкладками (профиль single, шаг 2) ─
   Панели открыты по умолчанию: свёрнутый интерфейс у стола без
   сопровождающего значит «не увидят вовсе». Вкладка убирает лишнее,
   а не прячет главное. */
body.ux-edge-tabs:not(.display-mode) .panel-left,
body.ux-edge-tabs:not(.display-mode) .right-rail {
  transition: transform .22s ease;
  will-change: transform;
}
body.ux-left-hidden:not(.display-mode) .panel-left {
  transform: translateX(calc(-100% - var(--ux-panel-inset) - 1rem));
}
body.ux-right-hidden:not(.display-mode) .right-rail {
  transform: translateX(calc(100% + var(--ux-panel-inset) + 1rem));
}

.ux-edge-tab {
  position: fixed; top: 50%; z-index: 24;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.5rem; padding: 1.1rem 0.4rem;
  min-width: var(--ux-tap); min-height: 9rem;
  font: inherit; font-size: 0.9rem; color: var(--ux-text); cursor: pointer;
  background: rgba(14, 15, 30, .92); border: 1px solid var(--ux-border);
  backdrop-filter: blur(10px);
  /* Едет transform, а не left: на 3840×2160 поверх работающей сцены
     анимация left пересчитывала бы раскладку каждый кадр. */
  transform: translate(0, -50%);
  transition: transform .22s ease;
}
/* Имя вкладки читается сверху вниз — иначе кромка шириной в палец
   не вмещает слово, а слово здесь обязательно: стрелка говорит только
   направление, но не что за ней. */
.ux-edge-tab-name {
  writing-mode: vertical-rl; letter-spacing: .06em; white-space: nowrap;
}
.ux-edge-tab-arrow { font-size: 1.15rem; color: var(--ux-accent); line-height: 1; }
body.kiosk .ux-edge-tab:active { background: rgba(124, 58, 237, .34); }

.ux-edge-tab-left {
  left: calc(var(--ux-panel-inset) + var(--ux-panel-left-w));
  border-left: none; border-radius: 0 var(--ux-radius) var(--ux-radius) 0;
}
.ux-edge-tab-right {
  right: calc(var(--ux-panel-inset) + var(--ux-panel-right-w));
  border-right: none; border-radius: var(--ux-radius) 0 0 var(--ux-radius);
}
body.ux-left-hidden .ux-edge-tab-left {
  transform: translate(calc(-1 * (var(--ux-panel-inset) + var(--ux-panel-left-w))), -50%);
}
body.ux-right-hidden .ux-edge-tab-right {
  transform: translate(calc(var(--ux-panel-inset) + var(--ux-panel-right-w)), -50%);
}

/* Пока открыт сюжет, левой панели нет — не должно быть и её вкладки */
body.story-open .ux-edge-tab-left { display: none; }
/* На LED вкладок не бывает: там нет касаний */
body.display-mode .ux-edge-tab { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  body.ux-edge-tabs:not(.display-mode) .panel-left,
  body.ux-edge-tabs:not(.display-mode) .right-rail,
  .ux-edge-tab { transition: none; }
}
/* Доля «не по теме» — в той же плашке, а не отдельной строкой: посетитель
   читает её вместе с объяснением, а не как самостоятельное сообщение. */
.dsr-offtopic-scope { color: #fbbf24; }

/* ── Пара чисел в сюжете «Работы, связанные с Россией» ─────────────
   Число выделено только типографикой: текст «Науки» дословный, и разбивать
   абзац на «цифру и подпись» значило бы его переписать. */
.ru-pair p { font-size: 0.95rem; line-height: 1.65; color: #d4d6e4; margin: 0 0 0.9rem; }
.ru-pair-n { font-size: 1.5rem; color: #fff; margin-right: 0.15rem; }
/* Заключительный абзац — не украшение, а условие показа пары: он снимает
   чтение «одно точное, другое приблизительное». */
.ru-pair-both {
  padding: 0.8rem 0.9rem; border-radius: 0.6rem; margin-bottom: 0 !important;
  background: rgba(124, 58, 237, .1); border: 1px solid var(--ux-border);
}
