/* ============================================================
 * Карта связей — стили для /ai-library/map/
 * ============================================================ */

.map-page { padding-block: 1.25rem 2rem; }

/* Карта в общем контейнере (как остальной контент).
   Высота — чтобы вписывалась в стандартный монитор 1080p без скроллинга. */
.map-canvas-wrap {
	position: relative;
	margin-block: 0 1.25rem;
	background: radial-gradient(ellipse at 30% 20%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 60%),
	            radial-gradient(ellipse at 70% 80%, color-mix(in srgb, var(--accent-end) 6%, transparent), transparent 60%),
	            var(--bg-elev-1);
	border: 1px solid var(--border);
	border-radius: var(--r-lg);
	overflow: hidden;
	height: clamp( 420px, calc( 100vh - 200px ), 820px );
}

.map-canvas {
	width: 100%; height: 100%;
	cursor: grab;
	display: block;
	outline: none;
	touch-action: none; /* отдаём управление D3 для pinch/pan на мобильных */
	/* GPU-acceleration: SVG-root рендерится как отдельный слой */
	will-change: transform;
}
/* Линии не должны блокировать hover на узлах */
.nsl-link { pointer-events: none; }
.map-canvas:active { cursor: grabbing; }
.map-canvas:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.map-canvas-wrap:fullscreen,
.map-canvas-wrap:-webkit-full-screen {
	border-radius: 0;
	height: 100vh;
}
.map-canvas-wrap:fullscreen .map-canvas,
.map-canvas-wrap:-webkit-full-screen .map-canvas { height: 100vh; }

/* ─── узлы ─── */
.nsl-node { cursor: pointer; transition: opacity 180ms var(--ease); }
.nsl-node__circle {
	stroke: rgba(255,255,255,0.22);
	stroke-width: 1.25;
	transition: stroke 180ms var(--ease), stroke-width 180ms var(--ease);
}
/* Активный узел — обводка контрастного цвета + чуть толще, без feGaussianBlur.
   На mobile GPU фильтры с blur'ом давали серьёзный фриз; обводка справляется. */
.nsl-node:hover .nsl-node__circle,
.nsl-node.is-active .nsl-node__circle {
	stroke: var(--text);
	stroke-width: 3;
}
.nsl-node.is-dim { opacity: 0.18; }

.nsl-node__label {
	fill: var(--text);
	font-family: var(--font-sans);
	font-size: 13px;
	font-weight: 600;
	letter-spacing: -0.01em;
	pointer-events: none;
	user-select: none;
	paint-order: stroke;
	/* Обводка текста цветом фона — читаемость поверх рёбер.
	   2.5px хватает; раньше 3px давал лишний рендеринг. */
	stroke: var(--bg-elev-1);
	stroke-width: 2.5px;
}

/* ─── рёбра ─── */
/* Тонкие линии, без drop-shadow — на 43 узлах было ~80 «теней» одновременно,
   GPU перерисовывал их каждый кадр. Без shadow граф читается чище. */
.nsl-link {
	stroke: var(--text-muted);
	stroke-linecap: round;
	stroke-width: 1.1;
	transition: stroke-opacity 180ms var(--ease), stroke 180ms var(--ease), stroke-width 180ms var(--ease);
}
/* Прямые связи (term_related) — тонкие, но яркие, фиолетовые */
.nsl-link--related {
	stroke: var(--accent);
	stroke-opacity: 0.85;
	stroke-width: 1.5;
}
/* Связи по категории — тонкий пунктир */
.nsl-link--category {
	stroke: color-mix( in srgb, var(--accent) 55%, var(--text-muted) );
	stroke-opacity: 0.55;
	stroke-width: 1;
	stroke-dasharray: 4 5;
}
.nsl-link.is-dim     { stroke-opacity: 0.1; }
/* Подсветка ребра когда соседний узел активен — увеличенная stroke-width, без glow */
.nsl-link.is-active {
	stroke: var(--accent-bright);
	stroke-opacity: 1;
	stroke-width: 2.4;
}

/* ─── tooltip ─── */
.map-tooltip {
	position: absolute;
	pointer-events: none;
	background: var(--bg-elev-2);
	border: 1px solid var(--border-strong);
	border-radius: var(--r-md);
	padding: .85rem 1rem;
	max-width: 280px;
	box-shadow: var(--shadow-md);
	opacity: 0;
	transform: translateY(4px);
	transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
	z-index: var(--z-floating);
}
.map-tooltip.is-visible { opacity: 1; transform: translateY(0); }
.map-tooltip__kicker {
	font-size: 10px;
	color: var(--accent-bright);
	letter-spacing: .12em;
	text-transform: uppercase;
	margin: 0 0 .25rem;
	font-weight: 600;
}
.map-tooltip__title {
	font-size: var(--fs-lg);
	font-weight: 600;
	letter-spacing: -0.01em;
	margin: 0 0 .35rem;
	color: var(--text);
}
.map-tooltip__deck {
	font-size: var(--fs-sm);
	color: var(--text-muted);
	line-height: 1.4;
	margin: 0;
}

/* ─── hint справа снизу ─── */
.map-hint {
	position: absolute;
	right: 1rem; bottom: 1rem;
	display: flex; gap: 1.25rem;
	font-size: var(--fs-xs);
	color: var(--text-muted);
	letter-spacing: .04em;
	pointer-events: none;
	/* Плотный фон без backdrop-filter — на мобильных blur'ы дают перерисовку всего слоя */
	background: color-mix( in srgb, var(--bg) 92%, transparent );
	padding: .5rem .75rem;
	border-radius: var(--r-sm);
	border: 1px solid var(--border);
}
.map-hint__item { display: inline-flex; align-items: center; gap: .35rem; }
.map-hint__item::before {
	content: '';
	width: 4px; height: 4px;
	border-radius: 50%;
	background: var(--accent);
	margin-right: .15rem;
}

/* ─── кнопки управления (zoom) ─── */
.map-controls {
	position: absolute;
	top: 1rem; right: 1rem;
	display: flex; flex-direction: column; gap: .25rem;
	/* Плотный фон без backdrop-filter (см. .map-hint) */
	background: color-mix( in srgb, var(--bg) 94%, transparent );
	border: 1px solid var(--border);
	border-radius: var(--r-md);
	padding: .25rem;
	box-shadow: var(--shadow-sm);
}
.map-controls__btn {
	width: 32px; height: 32px;
	display: inline-flex; align-items: center; justify-content: center;
	color: var(--text-muted);
	border-radius: var(--r-sm);
	transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.map-controls__btn:hover { color: var(--text); background: var(--bg-elev-2); }
.map-controls__btn:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}
.map-controls__btn:active { background: var(--accent-tint); color: var(--accent-bright); }

/* ─── легенда (одновременно — фильтры) ─── */
.map-legend {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem .75rem;
	padding-block: 1rem;
	font-size: var(--fs-sm);
	color: var(--text-muted);
}
/* Каждая «строчка легенды» — кнопка-toggle. По умолчанию выглядит как
   обычная подпись с цветным кружком; при is-active — фон акцентом,
   при is-dim (есть другие активные, но этот не выбран) — приглушённая. */
.map-legend__item {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .4rem .75rem;
	background: transparent;
	color: inherit;
	font: inherit;
	border: 1px solid var(--border);
	border-radius: var(--r-pill);
	cursor: pointer;
	transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.map-legend__item:hover {
	color: var(--text);
	border-color: var(--border-strong);
	background: var(--bg-elev-1);
}
.map-legend__item:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}
.map-legend__item.is-active {
	color: var(--text);
	background: var(--bg-elev-2);
	border-color: var(--accent);
}
.map-legend__item.is-dim { opacity: 0.45; }
.map-legend__item.is-dim:hover { opacity: 0.85; }
.map-legend__dot {
	display: inline-block;
	width: 10px; height: 10px;
	border-radius: 50%;
	flex-shrink: 0;
}
.map-legend__label { white-space: nowrap; }

/* Фильтрация на самом SVG — узлы и линии исчезают (display:none через
   visibility, чтобы не пересчитывать layout). */
.nsl-node.is-filtered-out,
.nsl-link.is-filtered-out { display: none; }

.map-error {
	color: var(--text-muted);
	text-align: center;
	padding-block: 4rem;
}

/* ─── анимация появления (GPU-acc, БЕЗ конфликта с D3 transform) ───
   D3 ставит `transform: translate(x,y)` на каждом tick.
   CSS-анимации НЕ должны трогать `transform`, иначе узлы «застывают» в одной точке.
   Используем только opacity. */
.nsl-root { animation: nslFadeIn 400ms var(--ease) both; }
@keyframes nslFadeIn {
	from { opacity: 0; }
	to   { opacity: 1; }
}
/* Staggered появление узлов — opacity-only */
.nsl-node {
	animation: nslNodeIn 400ms var(--ease) both;
	animation-delay: var(--enter-delay, 0ms);
}
@keyframes nslNodeIn {
	from { opacity: 0; }
	to   { opacity: 1; }
}
/* Активный узел «дышит» — пульсация stroke-width, без filter.
   Когда курсор уходит — класс is-active снимается, анимация прерывается. */
.nsl-node.is-active .nsl-node__circle {
	animation: nslPulse 1.8s ease-in-out infinite;
}
@keyframes nslPulse {
	0%, 100% { stroke-width: 2.5; }
	50%      { stroke-width: 4; }
}

/* Mobile: ещё больше упрощаем — пульсация и hover-анимация выключены,
   force-simulation тяжелее на слабых GPU. */
@media (max-width: 720px) {
	.map-canvas-wrap { height: 60vh; }
	.map-hint { display: none; }
	.nsl-node__label { font-size: 11px; }
	.nsl-node.is-active .nsl-node__circle { animation: none; }
	.nsl-link { stroke-width: 0.9; }
	.nsl-link--related { stroke-width: 1.2; }
	.nsl-link--category { stroke-width: 0.8; }
	.nsl-link.is-active { stroke-width: 1.8; }
}

/* prefers-reduced-motion: всё статично */
@media (prefers-reduced-motion: reduce) {
	.nsl-root,
	.nsl-node { animation: none; }
	.nsl-node.is-active .nsl-node__circle { animation: none; }
	.nsl-node,
	.nsl-node__circle,
	.nsl-link { transition: none; }
}
