<template>
	<div class="version-compare-wrap">
			<div class="compare-top">
				<div class="compare-top-col">
					<div class="compare-top-label">原版本：</div>
					<el-select v-model="oldVersionId" placeholder="请选择版本" class="compare-top-select" clearable>
						<el-option
							v-for="item in versionOptions"
							:key="item.value"
							:label="item.label"
							:value="item.value"
							:disabled="item.value === newVersionId"
						/>
					</el-select>
				</div>
				<div class="compare-top-col">
					<div class="compare-top-label">现版本：</div>
					<el-select v-model="newVersionId" placeholder="请选择版本" class="compare-top-select" clearable>
						<el-option
							v-for="item in versionOptions"
							:key="item.value"
							:label="item.label"
							:value="item.value"
							:disabled="item.value === oldVersionId"
						/>
					</el-select>
				</div>
			</div>

			<div class="compare-tools">
				<div class="compare-tools-tabs" ref="tabsWrapRef">
					<button
						v-for="(tab, index) in diffTabs"
						:key="tab.value"
						class="compare-tools-tab"
						:class="{ 'is-active': diffType === tab.value }"
						type="button"
						@click="handleDiffTabClick(tab.value)"
						:ref="el => setTabRef(el, index)"
					>
						<span class="label">{{ tab.label }}</span>
						<span
							class="count"
							v-if="diffCounts[tab.value] !== null && diffCounts[tab.value] !== undefined"
						>
							{{ diffCounts[tab.value] }}
						</span>
					</button>
					<span class="compare-tools-tabs-active" :style="activeBarStyle"></span>
				</div>

				<div class="compare-tools-actions">
					<el-checkbox v-model="onlyChinaRelated" label="只看涉华条款" size="large" />

					<div class="compare-tools-switches">
						<div class="compare-tools-switch">
							<el-switch v-model="termsHighlight" inline-prompt/>
							<span class="label">高亮实体</span>
						</div>
						<div class="compare-tools-switch">
							<el-switch v-model="termsShowOriginal" inline-prompt/>
							<span class="label">
								<img class="label-icon" :src="translateIcon" alt="" />
								显示原文
							</span>
						</div>
					</div>

					<div class="find-word-wrap">
						<div class="find-word-box" v-if="findWordBox">
							<div class="find-word-input">
								<el-input ref="findWordInputRef" v-model="findWordTxt" placeholder="查找条款内容" clearable
									@input="handleUpdateWord" />
							</div>
							<div class="find-word-limit">{{ findWordNum }}/{{ findWordMax }}</div>
							<div class="find-word-icon" @click="handleFindWord('last')">
								<el-icon><ArrowUp /></el-icon>
							</div>
							<div class="find-word-icon" @click="handleFindWord('next')">
								<el-icon><ArrowDown /></el-icon>
							</div>
							<div class="find-word-icon" @click="handleFindWord('close')">
								<el-icon><Close /></el-icon>
							</div>
						</div>
						<el-button type="primary" plain class="find-word-open-btn"
							@click="handleFindWord('open')">
							<el-icon class="find-word-open-icon"><Search /></el-icon>
							查找
						</el-button>
					</div>
				</div>
			</div>

			<div class="compare-columns" v-loading="isLoading" @click="handleEntityClick">
				<div class="compare-row" v-for="(pair, index) in comparePairs" :key="getPairKey(pair, index)">
					<div class="compare-cell">
						<template v-if="pair?.oldTerm">
							<div class="term-body">
								<div class="term-main">
									<div class="term-row term-row-cn">
										<div class="term-no-cn">第{{ pair.oldTerm.tkxh }}条.</div>
										<div class="term-content-cn" v-html="getTermContentHtml(pair.oldTerm, 'cn')"></div>
									</div>
									<div class="term-row term-row-en" v-if="termsShowOriginal">
										<div class="term-no-en">Sec.{{ pair.oldTerm.tkxh }}</div>
										<div class="term-content-en" v-html="getTermContentHtml(pair.oldTerm, 'en')"></div>
									</div>
								</div>
							</div>
						</template>
						<div v-else class="term-empty">—</div>
					</div>

					<div class="compare-cell">
						<template v-if="pair?.newTerm">
							<div class="term-body">
								<div class="term-main">
									<div class="term-row term-row-cn">
										<div class="term-no-cn">第{{ pair.newTerm.tkxh }}条.</div>
										<div class="term-content-cn" v-html="getTermContentHtml(pair.newTerm, 'cn')"></div>
									</div>
									<div class="term-row term-row-en" v-if="termsShowOriginal">
										<div class="term-no-en">Sec.{{ pair.newTerm.tkxh }}</div>
										<div class="term-content-en" v-html="getTermContentHtml(pair.newTerm, 'en')"></div>
									</div>
								</div>
							</div>
						</template>
						<div v-else class="term-empty">—</div>
					</div>
				</div>
			</div>

			<div class="compare-footer">
				<div class="compare-footer-text">{{ `共 ${total} 项` }}</div>
				<div class="compare-footer-right">
					<el-pagination
						background
						layout="prev, pager, next"
						:total="total"
						v-model:current-page="currentPage"
						v-model:page-size="pageSize"
						@current-change="handleCurrentChange"
					/>
				</div>
			</div>
		</div>
</template>

<script setup>
import { computed, nextTick, onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { getBillContentId, getBillVersionCompare, getBillVersionCompareStatistics } from "@/api/bill";
import { extractTextEntity } from "@/api/intelligent/index";
import { ArrowDown, ArrowUp, Close, Search } from "@element-plus/icons-vue";
import translateIcon from "./assert/icons/translate-icons.svg";

const route = useRoute();

const billId = computed(() => route.query.billId);

const versionOptions = ref([]);
const oldVersionId = ref("");
const newVersionId = ref("");

const diffType = ref("CHANGE");
const onlyChinaRelated = ref(false);
const keyword = ref("");

const termsHighlight = ref(true);
const termsShowOriginal = ref(true);

const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);

const diffTabs = [
	{ label: "变更", value: "CHANGE" },
	{ label: "新增", value: "ADD" },
	{ label: "删除", value: "DELETE" }
];
const diffCounts = ref({ CHANGE: 0, ADD: 0, DELETE: 0 });
const tabsWrapRef = ref(null);
const tabItemRefs = ref([]);
const activeBarStyle = ref({});

const findWordBox = ref(false);
const findWordInputRef = ref();
const findWordTxt = ref("");
const findWordKeyword = ref("");
const findWordNum = ref(0);
const findWordMax = ref(0);
const findWordTimer = ref(null);

const isLoading = ref(false);
const comparePairs = ref([]);

const compareRequestToken = ref(0);
const queryAbortController = ref(null);

const resetAbortController = () => {
	queryAbortController.value?.abort?.();
	queryAbortController.value = new AbortController();
	return queryAbortController.value;
};

const isAbortError = error => {
	return (
		error?.code === "ERR_CANCELED" ||
		error?.name === "CanceledError" ||
		error?.name === "AbortError" ||
		(typeof error?.message === "string" && /canceled|aborted/i.test(error.message))
	);
};

const handleLoadVersionOptions = async () => {
	if (!billId.value) {
		versionOptions.value = [];
		oldVersionId.value = "";
		newVersionId.value = "";
		return;
	}

	const res = await getBillContentId({ id: billId.value });
	const rawList = Array.isArray(res?.data) ? res.data : [];
	const seen = new Set();
	versionOptions.value = rawList
		.map(item => {
			return {
				label: item?.contentZh,
				value: item?.contentZh
			};
		})
		.filter(item => item.value)
		.filter(item => {
			if (seen.has(item.value)) return false;
			seen.add(item.value);
			return true;
		});

	if (!versionOptions.value.length) {
		oldVersionId.value = "";
		newVersionId.value = "";
		return;
	}

	if (versionOptions.value.length === 1) {
		oldVersionId.value = versionOptions.value[0].value;
		newVersionId.value = "";
		return;
	}

	oldVersionId.value = versionOptions.value[0].value;
	newVersionId.value = versionOptions.value[versionOptions.value.length - 1].value;
};

const normalizeDiffType = value => {
	if (value === "ADD") return "ADD";
	if (value === "DELETE") return "DELETE";
	return "CHANGE";
};

const setTabRef = (el, index) => {
	if (el) tabItemRefs.value[index] = el;
};

const updateActiveBar = () => {
	const index = diffTabs.findIndex(tab => tab.value === diffType.value);
	const target = tabItemRefs.value[index];
	const wrap = tabsWrapRef.value;
	if (!target || !wrap) {
		activeBarStyle.value = {};
		return;
	}
	const wrapRect = wrap.getBoundingClientRect();
	const targetRect = target.getBoundingClientRect();
	activeBarStyle.value = {
		width: `${targetRect.width}px`,
		transform: `translateX(${targetRect.left - wrapRect.left}px)`
	};
};

const handleDiffTabClick = value => {
	if (diffType.value === value) return;
	diffType.value = value;
	nextTick(() => {
		updateActiveBar();
	});
};


const mapDiffTypeToStatus = value => {
	const diff = normalizeDiffType(value);
	if (diff === "ADD") return "add";
	if (diff === "DELETE") return "del";
	return "update";
};

const mapVersionCompareItemToPair = item => {
	const oldTerm = item?.originalClauseMainId
		? {
				id: item.originalClauseMainId,
				ywid: item.originalClauseMainId,
				tkxh: item?.originalClauseNumber ?? "",
				fynr: item?.originalContentZh ?? "",
				ywnr: item?.originalContent ?? ""
			}
		: null;
	const newTerm = item?.currentClauseMainId
		? {
				id: item.currentClauseMainId,
				ywid: item.currentClauseMainId,
				tkxh: item?.currentClauseNumber ?? "",
				fynr: item?.currentContentZh ?? "",
				ywnr: item?.currentContent ?? ""
			}
		: null;
	return { oldTerm, newTerm };
};

const getVersionCompareBaseParams = () => ({
	billId: billId.value,
	content: keyword.value,
	currentVersion: newVersionId.value,
	isCn: onlyChinaRelated.value ? "Y" : "N",
	originalVersion: oldVersionId.value
});

const fetchComparePage = async ({ diff, page, size, signal }) => {
	const params = {
		...getVersionCompareBaseParams(),
		currentPage: Math.max(1, Number(page) || 1),
		pageSize: Math.max(1, Number(size) || 10),
		status: mapDiffTypeToStatus(diff)
	};
	const res = await getBillVersionCompare(params, { signal });
	const data = res?.data?.data ?? res?.data ?? {};
	const raw = Array.isArray(data?.content) ? data.content : [];
	return {
		list: raw.map(mapVersionCompareItemToPair),
		total: Number(data?.totalElements ?? 0) || 0
	};
};

const getCountByChangeType = (statisticsList, changeTypeLabel) => {
	const list = Array.isArray(statisticsList) ? statisticsList : [];
	const target = list.find(item => String(item?.changeType ?? "") === changeTypeLabel);
	return Number(target?.count ?? 0) || 0;
};

const loadCompareStatistics = async (currentToken, signal) => {
	debugger
	const res = await getBillVersionCompareStatistics(getVersionCompareBaseParams(), { signal });
	if (currentToken !== compareRequestToken.value) return;
	const list = res.data
	diffCounts.value = {
		CHANGE: getCountByChangeType(list, "更新"),
		ADD: getCountByChangeType(list, "新增"),
		DELETE: getCountByChangeType(list, "删除")
	};
};

const loadComparePairs = async () => {
	if (!billId.value || !oldVersionId.value || !newVersionId.value) {
		queryAbortController.value?.abort?.();
		comparePairs.value = [];
		diffCounts.value = { CHANGE: 0, ADD: 0, DELETE: 0 };
		total.value = 0;
		return;
	}

	const controller = resetAbortController();
	const currentToken = ++compareRequestToken.value;
	isLoading.value = true;
	try {
		const [currentRes] = await Promise.all([
			fetchComparePage({
				diff: diffType.value,
				page: currentPage.value,
				size: pageSize.value,
				signal: controller.signal
			}),
			loadCompareStatistics(currentToken, controller.signal)
		]);
		if (currentToken !== compareRequestToken.value || controller.signal.aborted) return;
		comparePairs.value = currentRes.list;
		total.value = currentRes.total;
		await ensureEntitiesForPairs(comparePairs.value, controller.signal);
	} catch (error) {
		if (currentToken !== compareRequestToken.value || isAbortError(error)) return;
		comparePairs.value = [];
		diffCounts.value = { CHANGE: 0, ADD: 0, DELETE: 0 };
		total.value = 0;
	} finally {
		if (currentToken === compareRequestToken.value) {
			isLoading.value = false;
		}
	}
};

const handleCurrentChange = page => {
	currentPage.value = Number(page) || 1;
};

const getPairKey = (pair, index) => {
	const oldKey = pair?.oldTerm?.ywid ?? pair?.oldTerm?.id ?? pair?.oldTerm?.tkxh ?? "";
	const newKey = pair?.newTerm?.ywid ?? pair?.newTerm?.id ?? pair?.newTerm?.tkxh ?? "";
	return `${oldKey || "old"}__${newKey || "new"}__${index}`;
};

const escapeHtml = value => {
	const str = String(value ?? "");
	return str
		.replace(/&/g, "&amp;")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;")
		.replace(/"/g, "&quot;")
		.replace(/'/g, "&#39;");
};

const escapeRegExp = text => {
	return String(text || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};

const getSearchRanges = (text, searchTerm) => {
	const rawText = String(text ?? "");
	const term = String(searchTerm ?? "").trim();
	if (!rawText || !term) return [];

	const ranges = [];
	const reg = new RegExp(escapeRegExp(term), "g");
	let match;
	while ((match = reg.exec(rawText)) !== null) {
		ranges.push({ start: match.index, end: match.index + match[0].length });
		if (match[0].length === 0) reg.lastIndex += 1;
	}
	return ranges;
};

const normalizeEntities = entities => {
	const list = Array.isArray(entities) ? entities : [];
	return list
		.map(item => {
			return {
				text_span: String(item?.text_span ?? "").trim(),
				type: String(item?.type ?? "").trim()
			};
		})
		.filter(item => item.text_span);
};

const getEntityRanges = (text, entities) => {
	const ranges = [];
	const rawText = String(text ?? "");
	if (!rawText) return ranges;

	const list = normalizeEntities(entities).sort((a, b) => b.text_span.length - a.text_span.length);
	for (const ent of list) {
		let startIndex = 0;
		while (startIndex < rawText.length) {
			const idx = rawText.indexOf(ent.text_span, startIndex);
			if (idx === -1) break;
			ranges.push({ start: idx, end: idx + ent.text_span.length, ent });
			startIndex = idx + ent.text_span.length;
		}
	}
	ranges.sort((a, b) => a.start - b.start || b.end - a.end);

	const merged = [];
	let lastEnd = 0;
	for (const r of ranges) {
		if (r.start < lastEnd) continue;
		merged.push(r);
		lastEnd = r.end;
	}
	return merged;
};

const buildHighlightedHtml = (text, entities, enableHighlight, searchTerm) => {
	const rawText = String(text ?? "");
	if (!rawText) return "";

	const safeText = escapeHtml(rawText).replace(/\n/g, "<br />");
	const term = String(searchTerm ?? "").trim();
	const enableSearch = Boolean(term);
	if (!enableHighlight && !enableSearch) return safeText;

	const ranges = getEntityRanges(rawText, entities);
	const searchRanges = enableSearch ? getSearchRanges(rawText, term) : [];
	if (!ranges.length && !searchRanges.length) return safeText;

	const merged = [];
	for (const r of ranges) {
		merged.push({ start: r.start, end: r.end, type: "entity", ent: r.ent });
	}
	for (const r of searchRanges) {
		const overlapsEntity = ranges.some(er => r.start < er.end && r.end > er.start);
		if (overlapsEntity) continue;
		merged.push({ start: r.start, end: r.end, type: "search" });
	}
	merged.sort((a, b) => a.start - b.start || b.end - a.end);

	let html = "";
	let cursor = 0;
	for (const r of merged) {
		if (cursor < r.start) {
			html += escapeHtml(rawText.slice(cursor, r.start));
		}
		const spanText = rawText.slice(r.start, r.end);
		if (r.type === "entity") {
			const type = escapeHtml(r.ent?.type ?? "");
			const text = escapeHtml(spanText);
			html += `<span class="term-entity" data-entity-type="${type}" data-entity-text="${text}">${text}</span>`;
		} else {
			html += `<span class="term-find-highlight">${escapeHtml(spanText)}</span>`;
		}
		cursor = r.end;
	}
	if (cursor < rawText.length) {
		html += escapeHtml(rawText.slice(cursor));
	}
	return html.replace(/\n/g, "<br />");
};

const handleEntityClick = event => {
	const el = event?.target?.closest?.("span.term-entity");
	if (!el) return;

	const q = String(el.getAttribute("data-entity-text") ?? "").trim();
	if (!q) return;

	const url = `https://www.bing.com/search?q=${encodeURIComponent(q)}`;
	window.open(url, "_blank", "noopener");
};

const termEntityCache = ref(new Map());
const entityRequestToken = ref(0);

const getTermEntityKey = (term, lang) => {
	const baseKey = term?.ywid ?? term?.id ?? term?.tkxh ?? "";
	return `${baseKey}__${lang}`;
};

const ensureEntitiesForPairs = async (pairs, signal = queryAbortController.value?.signal) => {
	if (!termsHighlight.value) return;
	if (signal?.aborted) return;

	const list = Array.isArray(pairs) ? pairs : [];
	if (!list.length) return;

	const currentToken = ++entityRequestToken.value;
	const tasks = [];
	const maxTasks = 40;

	for (const pair of list) {
		const terms = [pair?.oldTerm, pair?.newTerm].filter(Boolean);
		for (const term of terms) {
			const cnKey = getTermEntityKey(term, "cn");
			const enKey = getTermEntityKey(term, "en");
			if (!termEntityCache.value.has(cnKey) && String(term?.fynr ?? "").trim()) {
				tasks.push({ key: cnKey, text: term.fynr });
			}
			if (!termEntityCache.value.has(enKey) && String(term?.ywnr ?? "").trim()) {
				tasks.push({ key: enKey, text: term.ywnr });
			}
			if (tasks.length >= maxTasks) break;
		}
		if (tasks.length >= maxTasks) break;
	}

	if (!tasks.length) return;

	try {
		const results = await Promise.all(
			tasks.map(async item => {
				if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
				const res = await extractTextEntity(item.text, { signal });
				const entities = normalizeEntities(res?.result ?? res?.data?.result ?? res?.data ?? res);
				return { key: item.key, entities };
			})
		);

		if (currentToken !== entityRequestToken.value || signal?.aborted) return;
		for (const r of results) {
			termEntityCache.value.set(r.key, r.entities);
		}
	} catch (error) {
		if (currentToken !== entityRequestToken.value || isAbortError(error)) return;
	}
};

const getTermContentHtml = (term, lang) => {
	const raw = lang === "en" ? term?.ywnr : term?.fynr;
	const key = getTermEntityKey(term, lang);
	const entities = termEntityCache.value.get(key) || [];
	return buildHighlightedHtml(raw, entities, termsHighlight.value, findWordKeyword.value);
};

const countOccurrences = (text, searchTerm) => {
	const rawText = String(text ?? "");
	const term = String(searchTerm ?? "").trim();
	if (!rawText || !term) return 0;
	const reg = new RegExp(escapeRegExp(term), "g");
	const matches = rawText.match(reg);
	return matches ? matches.length : 0;
};

const updateActiveFindHighlight = () => {
	const spans = document.querySelectorAll("span.term-find-highlight");
	spans.forEach((span, index) => {
		if (index + 1 === findWordNum.value) {
			span.classList.add("is-active");
			span.scrollIntoView({ block: "center" });
		} else {
			span.classList.remove("is-active");
		}
	});
};

const doUpdateFindWord = async () => {
	findWordNum.value = 0;
	findWordMax.value = 0;
	const term = String(findWordTxt.value || "").trim();
	findWordKeyword.value = term;

	if (!term) {
		await nextTick();
		return;
	}

	const list = Array.isArray(comparePairs.value) ? comparePairs.value : [];
	for (const pair of list) {
		const terms = [pair?.oldTerm, pair?.newTerm].filter(Boolean);
		for (const t of terms) {
			findWordMax.value += countOccurrences(t?.fynr, term);
			if (termsShowOriginal.value) {
				findWordMax.value += countOccurrences(t?.ywnr, term);
			}
		}
	}

	if (findWordMax.value > 0) {
		await nextTick();
		findWordNum.value = 1;
		updateActiveFindHighlight();
	}
};

const handleUpdateWord = () => {
	if (findWordTimer.value) {
		clearTimeout(findWordTimer.value);
		findWordTimer.value = null;
	}
	findWordTimer.value = setTimeout(() => {
		doUpdateFindWord();
	}, 300);
};

const handleFindWord = event => {
	switch (event) {
		case "open":
			findWordBox.value = true;
			nextTick(() => {
				findWordInputRef.value?.focus?.();
			});
			break;
		case "last":
			if (findWordMax.value > 1) {
				findWordNum.value = findWordNum.value === 1 ? findWordMax.value : findWordNum.value - 1;
				updateActiveFindHighlight();
			}
			break;
		case "next":
			if (findWordMax.value > 1) {
				findWordNum.value = findWordNum.value === findWordMax.value ? 1 : findWordNum.value + 1;
				updateActiveFindHighlight();
			}
			break;
		case "close":
			findWordBox.value = false;
			findWordTxt.value = "";
			findWordKeyword.value = "";
			findWordNum.value = 0;
			findWordMax.value = 0;
			break;
	}
};

watch(
	[billId, oldVersionId, newVersionId, diffType, onlyChinaRelated, keyword, currentPage, pageSize],
	() => {
		loadComparePairs();
	},
	{ immediate: true }
);

watch(diffType, () => {
	currentPage.value = 1;
	nextTick(() => {
		updateActiveBar();
	});
});

watch([oldVersionId, newVersionId, onlyChinaRelated, keyword], () => {
	currentPage.value = 1;
});

watch(termsHighlight, () => {
	ensureEntitiesForPairs(comparePairs.value);
});

watch(
	[comparePairs, termsShowOriginal],
	() => {
		if (!findWordBox.value) return;
		doUpdateFindWord();
	},
	{ deep: true }
);

onMounted(async () => {
	await handleLoadVersionOptions();
	nextTick(() => {
		updateActiveBar();
	});
});
</script>

<style lang="scss" scoped>
.version-compare-wrap {
	display: flex;
	flex-direction: column;
	row-gap: 16px;
	width: 100%;
	height: 848px;
	overflow: hidden;
	background: #ffffff;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
	padding: 16px 75px;
	box-sizing: border-box;
}

.compare-top {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 37px;
	margin-top: 0;
}

.compare-top-col {
	display: flex;
	align-items: center;
	gap: 22px;
	background: transparent;
	border-radius: 0;
	padding: 0;
	box-shadow: none;
}

.compare-top-label {
	font-size: 16px;
	font-weight: 400;
	color: var(--text-primary-65-color);
	white-space: nowrap;
}

.compare-top-select {
	flex: 1;

	:deep(.el-select__wrapper) {
		background-color: rgb(246, 250, 255);
		box-shadow: 0 0 0 1px var(--color-primary-35) inset;
	}

	:deep(.el-select__wrapper.is-hovering) {
		box-shadow: 0 0 0 1px var(--color-primary-35) inset;
	}

	:deep(.el-select__wrapper.is-focused) {
		box-shadow: 0 0 0 1px var(--color-primary-35) inset;
	}

	:deep(.el-select__selected-item),
	:deep(.el-select__placeholder),
	:deep(.el-select__input),
	:deep(.el-select__caret),
	:deep(.el-select__suffix),
	:deep(.el-select__icon) {
		color: var(--color-primary-100);
	}
}

.compare-tools {
	height: 66px;
	border-bottom: 1px solid var(--border-black-5);
	border-top: 1px solid var(--border-black-5);
	background: transparent;
	display: flex;
	align-items: center;
	gap: 24px;
	flex-wrap: nowrap;
	white-space: nowrap;
}

.compare-tools-tabs {
	flex: 0 0 auto;
	position: relative;
	display: flex;
	align-items: center;
	gap: 28px;
	height: 100%;
}

.compare-tools-tab {
	background: transparent;
	border: none;
	padding: 0;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	font-size: 16px;
	font-weight: 400;
	color: var(--text-primary-65-color);
	position: relative;

	&.is-active {
		color: var(--color-primary-100);
	}

	&:focus-visible {
		outline: 2px solid rgba(66, 133, 244, 0.5);
		outline-offset: 4px;
		border-radius: 6px;
	}

	.label {
		line-height: 1;
	}

	.count {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-width: 22px;
		height: 22px;
		padding: 0 6px;
		border-radius: 999px;
		background: var(--color-primary-100);
		color: var(--bg-white-100);
		font-size: 12px;
		font-weight: 600;
	}
}

.compare-tools-tabs-active {
	position: absolute;
	left: 0;
	bottom: -1px;
	height: 2px;
	background: var(--color-primary-100);
	border-radius: 2px;
	transition: transform 0.2s ease, width 0.2s ease;
}

.compare-tools-actions {
	display: flex;
	align-items: center;
	gap: 24px;
	flex-wrap: wrap;
	margin-left: auto;
	justify-content: flex-end;
	font-size: 16px;
	font-weight: 400;
	color: var(--text-primary-65-color);

	:deep(.el-checkbox__label) {
		font-size: 16px;
		font-weight: 400;
		color: var(--text-primary-65-color);
	}
}

.compare-tools-switches {
	display: flex;
	align-items: center;
	gap: 16px;
}

.compare-tools-switch {
	display: inline-flex;
	align-items: center;
	gap: 8px;

	.label {
		display: inline-flex;
		align-items: center;
		gap: 6px;
		font-size: 16px;
		font-weight: 400;
		color: var(--text-primary-65-color);
	}
}

.label-icon {
	width: 16px;
	height: 16px;
}

.compare-tools-search {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.find-word-box {
	width: 430px;
	height: 60px;
	border: 1px solid rgba(230, 231, 232, 1);
	background-color: #ffffff;
	border-radius: 6px;
	display: flex;
	align-items: center;
	position: absolute;
	right: 0;
	top: -68px;
	box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);

	.find-word-input {
		flex: 1;
		min-width: 0;
		padding-left: 8px;
	}

	.find-word-limit {
		border-right: solid 1px rgba(230, 231, 232, 1);
		color: #5f656c;
		padding: 0 16px 0 8px;
		white-space: nowrap;
	}

	.find-word-icon {
		padding: 6px 10px;
		margin: 0 2px;
		cursor: pointer;
		display: inline-flex;
		align-items: center;
	}
}

.find-word-wrap {
	position: relative;
	display: inline-flex;
	align-items: center;
}

.find-word-open-btn {
	height: 32px;
	background-color: var(--bg-white-100);
	border-color: var(--bg-black-10);
	color: var(--text-primary-80-color);

	&:hover {
		background-color: var(--bg-black-5);
		border-color: var(--bg-black-10);
		color: var(--text-primary-80-color);
	}

	&:active {
		background-color: var(--bg-black-10);
		border-color: var(--bg-black-10);
		color: var(--text-primary-80-color);
	}
}

.find-word-open-icon {
	margin-right: 4px;
}

:deep(span.term-find-highlight) {
	background-color: #ffff00;
}

:deep(span.term-find-highlight.is-active) {
	background-color: #ff9632;
}

.compare-columns {
	margin-top: 16px;
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overflow-x: hidden;
	display: flex;
	flex-direction: column;
}

.compare-row {
	width: 100%;
	display: grid;
	grid-template-columns: 1fr 1fr;
}

.compare-cell {
	width: 100%;
	box-sizing: border-box;
	border-radius: 2px;
	background: var(--bg-white-100);
	display: flex;
	align-items: flex-start;
	position: relative;
	padding: 16px;
}

.compare-row:nth-child(2n-1) .compare-cell {
	background: var(--bg-black-2);
}

.compare-footer {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 12px 0 0;
}

.compare-footer-text {
	font-size: 14px;
	color: var(--text-primary-65-color);
	white-space: nowrap;
}

.compare-footer-right {
	display: flex;
	justify-content: flex-end;
	flex: 1;
	min-width: 0;
}

.term-empty {
	width: 100%;
	min-height: 48px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: rgba(132, 136, 142, 1);
}

.term-body {
	display: flex;
	column-gap: 18px;
	flex: 1;
	min-width: 0;
	width: 100%;
}

.term-main {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	row-gap: 6px;
}

.term-row {
	display: flex;
	align-items: flex-start;
	column-gap: 18px;
}

.term-no-cn {
	font-size: 16px;
	font-weight: 700;
	line-height: 24px;
	color: var(--color-primary-100);
	white-space: nowrap;
	width: 90px;
	text-align: center;
	flex: 0 0 90px;
}

.term-no-en {
	font-size: 14px;
	font-weight: 400;
	line-height: 24px;
	color: var(--color-primary-100);
	white-space: nowrap;
	width: 90px;
	text-align: center;
	flex: 0 0 90px;
}

.term-content-cn {
	flex: 1;
	font-size: 16px;
	font-weight: 700;
	line-height: 24px;
	color: var(--text-primary-80-color);

	:deep(.term-entity) {
		display: inline-flex;
		align-items: center;
		gap: 4px;
		padding: 0 6px 0 4px;
		background: var(--color-primary-10);
		cursor: pointer;
		transition: background-color 0.15s ease, transform 0.15s ease;
	}

	:deep(.term-entity:hover) {
		background: var(--color-primary-35);
		transform: translateY(-1px);
	}

	:deep(.term-entity::before) {
		content: "";
		display: inline-block;
		width: 14px;
		height: 14px;
		flex: 0 0 14px;
		background-color: var(--color-primary-100);
		mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M448 768c176.736 0 320-143.264 320-320S624.736 128 448 128 128 271.264 128 448s143.264 320 320 320zm0 64C236.288 832 64 659.712 64 448S236.288 64 448 64s384 172.288 384 384-172.288 384-384 384z'/%3E%3Cpath d='M832 832a32 32 0 0 1-22.624-9.376l-160-160a32 32 0 0 1 45.248-45.248l160 160A32 32 0 0 1 832 832z'/%3E%3C/svg%3E");
		mask-repeat: no-repeat;
		mask-position: center;
		mask-size: contain;
	}
}

.term-content-en {
	flex: 1;
	font-size: 14px;
	font-weight: 400;
	line-height: 24px;
	color: var(--text-primary-65-color);

	:deep(.term-entity) {
		display: inline-flex;
		align-items: center;
		gap: 4px;
		padding: 0 6px 0 4px;
		background: var(--color-primary-10);
		cursor: pointer;
		transition: background-color 0.15s ease, transform 0.15s ease;
	}

	:deep(.term-entity:hover) {
		background: var(--color-primary-35);
		transform: translateY(-1px);
	}

	:deep(.term-entity::before) {
		content: "";
		display: inline-block;
		width: 14px;
		height: 14px;
		flex: 0 0 14px;
		background-color: var(--color-primary-100);
		mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M448 768c176.736 0 320-143.264 320-320S624.736 128 448 128 128 271.264 128 448s143.264 320 320 320zm0 64C236.288 832 64 659.712 64 448S236.288 64 448 64s384 172.288 384 384-172.288 384-384 384z'/%3E%3Cpath d='M832 832a32 32 0 0 1-22.624-9.376l-160-160a32 32 0 0 1 45.248-45.248l160 160A32 32 0 0 1 832 832z'/%3E%3C/svg%3E");
		mask-repeat: no-repeat;
		mask-position: center;
		mask-size: contain;
	}
}

@media (max-width: 1680px) {

	.compare-row,
	.compare-top {
		grid-template-columns: 1fr;
	}

	.compare-tools-actions {
		width: 100%;
	}

	.compare-tools-search {
		width: 100%;
	}

	.find-word-box {
		width: 100%;
	}
}
</style>
