<template>
	<div class="docker-dashboard">
		<div v-if="isListLoading && !containerItems.length" class="loading-wrap">
			<t-loading text="加载 Docker 容器..." />
		</div>
		<template v-else-if="containerItems.length">
			<t-cell-group title="容器列表" theme="card">
				<div class="section list">
					<button
						v-for="item in containerItems"
						:key="item.id"
						type="button"
						:class="['chip', { active: item.id === selectedContainerId }]"
						@click="handleSelectContainer(item.id)"
					>
						<div class="top">
							<span class="name" v-text="Text.display(item.name)" />
							<span :class="['state', resolveStateClass(item.state)]" v-text="resolveStateText(item.state)" />
						</div>
						<div class="bottom">
							<span class="img" v-text="Text.display(item.image)" />
							<span class="note" v-text="resolveHealthText(item.healthStatus)" />
						</div>
					</button>
				</div>
			</t-cell-group>
			<div v-if="isStatusLoading && !statusView" class="loading-wrap">
				<t-loading text="加载容器状态..." />
			</div>
			<template v-else-if="statusView">
				<t-cell-group title="容器概览" theme="card">
					<t-cell title="名称" :note="Text.display(statusView?.name)" />
					<t-cell title="镜像" :note="Text.display(statusView?.image)" />
					<t-cell title="状态" :note="resolveStateText(statusView?.state)" />
					<t-cell title="状态详情" :note="Text.display(statusView?.status)" />
					<t-cell title="健康检查" :note="resolveHealthText(statusView?.healthStatus)" />
					<t-cell title="容器 ID" :note="Text.display(statusView?.id?.slice(0, 12))" />
					<t-cell title="镜像 ID" :note="Text.display(statusView?.imageId?.slice(0, 12))" />
					<t-cell title="创建时间" :note="Time.toPassedDateTime(statusView?.createdAt)" />
					<t-cell title="启动时间" :note="resolveDockerRawTime(statusView?.startedAt)" />
					<t-cell title="结束时间" :note="resolveDockerRawTime(statusView?.finishedAt)" />
					<t-cell title="采样时间" :note="Time.toPassedDateTime(statusView?.updatedAt)" />
				</t-cell-group>
				<t-cell-group class="section resource" title="资源使用" theme="card">
					<t-cell-info label="CPU 使用率" :value="Text.unit(statusView?.cpuPercent, '%')">
						<progress-group mode="heap" :progress="cpuProgressList" />
					</t-cell-info>
					<t-cell-info label="内存使用率" :value="memoryUsageText">
						<progress-group mode="heap" :progress="memoryProgressList" :note="Text.unit(statusView?.memoryPercent, '%')" />
					</t-cell-info>
					<t-cell title="进程数" :note="Text.display(statusView?.pids)" />
					<t-cell title="重启次数" :note="Text.display(statusView?.restartCount)" />
					<t-cell title="退出码" :note="Text.display(statusView?.exitCode)" />
					<t-cell title="OOM Kill" :note="Text.displayBool(statusView?.oomKilled, '是', '否')" />
				</t-cell-group>
				<t-cell-group class="section traffic" title="网络与块设备" theme="card">
					<t-cell title="网络接收" :note="IOSize.format(statusView?.networkRxBytes)" />
					<t-cell title="网络发送" :note="IOSize.format(statusView?.networkTxBytes)" />
					<t-cell title="块设备读取" :note="IOSize.format(statusView?.blockReadBytes)" />
					<t-cell title="块设备写入" :note="IOSize.format(statusView?.blockWriteBytes)" />
				</t-cell-group>
			</template>
			<t-empty v-else description="暂无容器状态数据" />
		</template>
		<t-empty v-else description="暂无 Docker 容器数据" />
		<t-cell-group class="section history" title="历史采样" theme="card">
			<t-tabs class="metric-tabs" :value="historyMetric" @change="handleHistoryMetricChange">
				<t-tab-panel v-for="item in historyMetricTabs" :key="item.value" :value="item.value" :label="item.label" />
			</t-tabs>
			<div v-if="isHistoryLoading && !historyItems.length" class="loading-wrap">
				<t-loading text="加载容器历史..." />
			</div>
			<template v-else-if="historyItems.length">
				<v-chart
					ref="chartRef"
					class="chart"
					:option="historyChartOption"
					:update-options="historyChartUpdateOptions"
					:autoresize="true"
				/>
				<div class="slider bg-white">
					<span class="label">较早</span>
					<t-slider
						class="control"
						:min="0"
						:max="Math.max(historyItems.length - historyVisibleCount, 0)"
						:step="1"
						:value="historySliderValue"
						@change="handleHistorySliderChange"
					/>
					<span class="label">最新</span>
				</div>
				<t-cell-group>
					<t-cell v-for="item in historySummary" :key="item.label" :title="item.label" :note="item.value" />
				</t-cell-group>
			</template>
			<t-empty v-else :description="selectedContainerId ? '暂无容器历史数据' : '请先选择容器'" />
		</t-cell-group>
	</div>
</template>

<script setup lang="ts">
import { Toast } from "tdesign-mobile-vue";
import { use } from "echarts/core";
import { SVGRenderer } from "echarts/renderers";
import { LineChart } from "echarts/charts";
import { GridComponent, LegendComponent, TooltipComponent } from "echarts/components";
import VChart from "vue-echarts";
import type { EChartsOption, SeriesOption } from "echarts";
import DockerAPI from "@/api/DockerAPI";
import type {
	DockerContainerHistoryPointView,
	DockerContainerStatusView,
	DockerContainerSummaryView
} from "@/types/Docker";
import { useSettingStore } from "@/store/settingStore";
import { IOSize, type LabelValue, Text, Time } from "timi-web";
import TCellInfo from "@/components/TCellInfo.vue";
import type { ProgressItem } from "@/components/ProgressGroup.vue";
import ProgressGroup from "@/components/ProgressGroup.vue";

type DockerHistoryMetric = "cpu" | "memory" | "network" | "block" | "pids";

use([
	SVGRenderer,
	LineChart,
	GridComponent,
	TooltipComponent,
	LegendComponent
]);

defineOptions({
	name: "DockerDashboard"
});

const settingStore = useSettingStore();

const isListLoading = ref(false);
const isStatusLoading = ref(false);
const isHistoryLoading = ref(false);

const containerItems = ref<DockerContainerSummaryView[]>([]);
const selectedContainerId = ref("");
const statusView = ref<DockerContainerStatusView | null>(null);
const historyPoints = ref<DockerContainerHistoryPointView[]>([]);

const chartRef = ref<InstanceType<typeof VChart> | null>(null);
const historyChartUpdateOptions = Object.freeze({
	notMerge: true
});

// ---------- 当前状态 ----------

const cpuProgressList = computed<ProgressItem[]>(() => {
	return [
		{
			color: "var(--td-brand-color)",
			value: normalizePercent(statusView.value?.cpuPercent)
		}
	];
});
const memoryUsageText = computed(() => {
	const usage = IOSize.format(statusView.value?.memoryUsageBytes || 0);
	const limitValue = statusView.value?.memoryLimitBytes || 0;
	const limit = limitValue < 1 ? "无限制" : IOSize.format(limitValue);
	return `${usage} / ${limit}`;
});
const memoryProgressList = computed<ProgressItem[]>(() => {
	const limit = statusView.value?.memoryLimitBytes || 0;
	const usage = statusView.value?.memoryUsageBytes || 0;
	const fallback = limit < 1 ? 0 : usage / limit;
	const percent = statusView.value?.memoryPercent;
	return [
		{
			color: "var(--td-warning-color)",
			value: normalizePercent(percent, fallback)
		}
	];
});

function normalizePercent(percent?: number | null, fallback = 0): number {
	const source = typeof percent === "number" ? percent / 100 : fallback;
	if (Number.isNaN(source) || !Number.isFinite(source)) {
		return 0;
	}
	return Math.min(Math.max(source, 0), 1);
}

function resolveStateClass(state?: string | null): string {
	if (state === "running") {
		return "ok";
	}
	if (state === "exited" || state === "dead") {
		return "err";
	}
	return "wait";
}

function resolveStateText(state?: string | null): string {
	if (!state) {
		return "-";
	}
	const map: Record<string, string> = {
		created: "已创建",
		running: "运行中",
		restarting: "重启中",
		exited: "已退出",
		paused: "已暂停",
		dead: "已停止"
	};
	return map[state] || state;
}

function resolveHealthText(health?: string | null): string {
	if (!health) {
		return "未配置";
	}
	const map: Record<string, string> = {
		healthy: "健康",
		unhealthy: "异常",
		starting: "启动中"
	};
	return map[health] || health;
}

function resolveDockerRawTime(value?: string | null): string {
	if (!value || value.startsWith("0001-01-01")) {
		return "-";
	}
	const dateValue = Date.parse(value);
	if (Number.isNaN(dateValue)) {
		return value;
	}
	return Time.toPassedDateTime(dateValue);
}

// ---------- 历史采样 ----------

const historyMetric = ref<DockerHistoryMetric>("cpu");

const historyMetricTabs = computed(() => {
	const labelMap: Record<DockerHistoryMetric, string> = {
		cpu: "CPU",
		memory: "内存",
		network: "网络",
		block: "块设备",
		pids: "进程"
	};
	return (Object.keys(labelMap) as DockerHistoryMetric[]).map((item) => ({
		value: item,
		label: labelMap[item]
	}));
});

function handleHistoryMetricChange(value: string): void {
	const nextValue = value as DockerHistoryMetric;
	if (nextValue === "cpu" || nextValue === "memory" || nextValue === "network" || nextValue === "block" || nextValue === "pids") {
		historyMetric.value = nextValue;
	}
}

const historyItems = computed<DockerContainerHistoryPointView[]>(() => {
	return historyPoints.value.slice().sort((left, right) => left.at - right.at);
});
const historySummary = computed<LabelValue<string, any>[]>(() => {
	const lastPoint = historyItems.value[historyItems.value.length - 1];
	if (!lastPoint) {
		return [];
	}
	if (historyMetric.value === "cpu") {
		return [
			{ label: "CPU 使用率", value: Text.unit(lastPoint.cpuPercent, "%") }
		];
	}
	if (historyMetric.value === "memory") {
		return [
			{ label: "内存占用", value: IOSize.format(lastPoint.memoryUsageBytes || 0) },
			{ label: "内存使用率", value: Text.unit(lastPoint.memoryPercent, "%") }
		];
	}
	if (historyMetric.value === "network") {
		return [
			{ label: "累计接收", value: IOSize.format(lastPoint.networkRxBytes || 0) },
			{ label: "累计发送", value: IOSize.format(lastPoint.networkTxBytes || 0) }
		];
	}
	if (historyMetric.value === "block") {
		return [
			{ label: "累计读取", value: IOSize.format(lastPoint.blockReadBytes || 0) },
			{ label: "累计写入", value: IOSize.format(lastPoint.blockWriteBytes || 0) }
		];
	}
	return [
		{ label: "进程数", value: Text.display(lastPoint.pids) }
	];
});

const isHistorySliderTouched = ref(false);
const historySliderValue = ref(0);
const HISTORY_DEFAULT_VISIBLE_COUNT = 24;

const historyVisibleCount = computed(() => {
	if (historyItems.value.length < 1) {
		return 1;
	}
	return Math.min(HISTORY_DEFAULT_VISIBLE_COUNT, historyItems.value.length);
});
const historySliderMaxStart = computed(() => {
	return Math.max(historyItems.value.length - historyVisibleCount.value, 0);
});
const currentHistoryRange = computed(() => {
	const length = historyItems.value.length;
	if (length < 1) {
		return { startValue: 0, endValue: 0 };
	}
	const startValue = Math.min(Math.max(Math.floor(historySliderValue.value), 0), historySliderMaxStart.value);
	const endValue = Math.min(startValue + historyVisibleCount.value - 1, length - 1);
	return { startValue, endValue };
});
const visibleHistoryItems = computed<DockerContainerHistoryPointView[]>(() => {
	if (!historyItems.value.length) {
		return [];
	}
	return historyItems.value.slice(currentHistoryRange.value.startValue, currentHistoryRange.value.endValue + 1);
});

watch(() => historyItems.value.length, (length) => {
	if (length < 1) {
		historySliderValue.value = 0;
		isHistorySliderTouched.value = false;
		return;
	}
	if (!isHistorySliderTouched.value) {
		historySliderValue.value = historySliderMaxStart.value;
		return;
	}
	historySliderValue.value = Math.min(historySliderValue.value, historySliderMaxStart.value);
});

function handleHistorySliderChange(value: number): void {
	historySliderValue.value = Math.min(Math.max(Math.floor(value), 0), historySliderMaxStart.value);
	isHistorySliderTouched.value = true;
}

// ---------- 图表 ----------

const isDarkTheme = ref(false);
let themeObserver: MutationObserver | null = null;

const historyChartOption = computed((): EChartsOption => {
	const axisColor = isDarkTheme.value ? "#9aa4b2" : "#7e8a9a";
	const lineColor = isDarkTheme.value ? "rgba(255, 255, 255, .12)" : "rgba(18, 42, 66, .08)";
	const legendColor = isDarkTheme.value ? "#d7dee8" : "#334155";

	const commonOption: EChartsOption = {
		tooltip: {
			trigger: "axis",
			confine: true,
			position: (point, _params, _dom, _rect, size) => {
				const gap = 6;
				const fingerGap = 24;
				const contentSize = size?.contentSize || [0, 0];
				const viewSize = size?.viewSize || [0, 0];
				const maxLeft = Math.max(viewSize[0] - contentSize[0] - gap, gap);
				const maxTop = Math.max(viewSize[1] - contentSize[1] - gap, gap);
				const clamp = (value: number, min: number, max: number): number => {
					return Math.min(Math.max(value, min), max);
				};
				const preferLeft = point[0] - contentSize[0] - gap;
				const preferRight = point[0] + gap;
				const left = point[0] < viewSize[0] / 2
					? clamp(preferRight, gap, maxLeft)
					: clamp(preferLeft, gap, maxLeft);
				const preferTop = point[1] - contentSize[1] - fingerGap;
				const preferBottom = point[1] + fingerGap;
				const top = preferTop >= gap
					? clamp(preferTop, gap, maxTop)
					: clamp(preferBottom, gap, maxTop);
				return [left, top];
			}
		},
		legend: {
			top: 10,
			textStyle: {
				color: legendColor
			}
		},
		grid: {
			top: 40,
			left: 8,
			right: 8,
			bottom: 8,
			containLabel: true
		},
		xAxis: {
			type: "category",
			boundaryGap: false,
			data: visibleHistoryItems.value.map((item) => item.at),
			axisLabel: {
				color: axisColor,
				formatter: val => Time.toShortTime(Number(val))
			},
			axisLine: {
				lineStyle: {
					color: lineColor
				}
			}
		}
	};

	if (!historyItems.value.length) {
		return commonOption;
	}

	if (historyMetric.value === "cpu") {
		return {
			...commonOption,
			tooltip: {
				...commonOption.tooltip,
				formatter: params => formatPercentTooltip(params, " %")
			},
			yAxis: {
				type: "value",
				min: 0,
				max: 100,
				axisLabel: {
					color: axisColor,
					formatter: "{value} %"
				},
				splitLine: {
					lineStyle: {
						color: lineColor
					}
				}
			},
			series: [
				resolveLineSeries("CPU", visibleHistoryItems.value.map((item) => item.cpuPercent || 0))
			]
		};
	}

	if (historyMetric.value === "memory") {
		return {
			...commonOption,
			tooltip: {
				...commonOption.tooltip,
				formatter: params => {
					const list = Array.isArray(params) ? params : [params];
					const title = `时间：${Time.toDateTime(Number(list[0]?.name))}`;
					const lines = list.map((item) => {
						const currentName = item.seriesName || "";
						if (currentName === "内存占用") {
							return `${item.marker}${currentName}: ${IOSize.format(Number(item.value))}`;
						}
						return `${item.marker}${currentName}: ${Text.unit(Number(item.value), " %")}`;
					});
					return [title, ...lines].join("<br />");
				}
			},
			yAxis: [
				{
					type: "value",
					axisLabel: {
						color: axisColor,
						formatter: (value: number) => IOSize.format(value)
					},
					splitLine: {
						lineStyle: {
							color: lineColor
						}
					}
				},
				{
					type: "value",
					min: 0,
					max: 100,
					axisLabel: {
						color: axisColor,
						formatter: "{value} %"
					},
					splitLine: {
						show: false
					}
				}
			],
			series: [
				resolveLineSeries("内存占用", visibleHistoryItems.value.map((item) => item.memoryUsageBytes || 0)),
				resolveLineSeries("内存使用率", visibleHistoryItems.value.map((item) => item.memoryPercent || 0), 1)
			]
		};
	}

	if (historyMetric.value === "network") {
		return {
			...commonOption,
			tooltip: {
				...commonOption.tooltip,
				formatter: params => formatSizeTooltip(params)
			},
			yAxis: {
				type: "value",
				axisLabel: {
					color: axisColor,
					formatter: (value: number) => IOSize.format(value)
				},
				splitLine: {
					lineStyle: {
						color: lineColor
					}
				}
			},
			series: [
				resolveLineSeries("接收", visibleHistoryItems.value.map((item) => item.networkRxBytes || 0)),
				resolveLineSeries("发送", visibleHistoryItems.value.map((item) => item.networkTxBytes || 0))
			]
		};
	}

	if (historyMetric.value === "block") {
		return {
			...commonOption,
			tooltip: {
				...commonOption.tooltip,
				formatter: params => formatSizeTooltip(params)
			},
			yAxis: {
				type: "value",
				axisLabel: {
					color: axisColor,
					formatter: (value: number) => IOSize.format(value)
				},
				splitLine: {
					lineStyle: {
						color: lineColor
					}
				}
			},
			series: [
				resolveLineSeries("读取", visibleHistoryItems.value.map((item) => item.blockReadBytes || 0)),
				resolveLineSeries("写入", visibleHistoryItems.value.map((item) => item.blockWriteBytes || 0))
			]
		};
	}

	return {
		...commonOption,
		tooltip: {
			...commonOption.tooltip,
			formatter: params => {
				const list = Array.isArray(params) ? params : [params];
				const title = `时间：${Time.toDateTime(Number(list[0]?.name))}`;
				const lines = list.map((item) => `${item.marker}${item.seriesName}: ${Text.display(Number(item.value))}`);
				return [title, ...lines].join("<br />");
			}
		},
		yAxis: {
			type: "value",
			minInterval: 1,
			axisLabel: {
				color: axisColor
			},
			splitLine: {
				lineStyle: {
					color: lineColor
				}
			}
		},
		series: [
			resolveLineSeries("进程数", visibleHistoryItems.value.map((item) => item.pids || 0))
		]
	};
});

function formatPercentTooltip(params: unknown, unit: string): string {
	const list = Array.isArray(params) ? params : [params];
	const title = `时间：${Time.toDateTime(Number((list[0] as { name?: string }).name || 0))}`;
	const lines = list.map((item) => {
		const current = item as { marker?: string; seriesName?: string; value?: number };
		return `${current.marker || ""}${current.seriesName || ""}: ${Text.unit(Number(current.value || 0), unit)}`;
	});
	return [title, ...lines].join("<br />");
}

function formatSizeTooltip(params: unknown): string {
	const list = Array.isArray(params) ? params : [params];
	const title = `时间：${Time.toDateTime(Number((list[0] as { name?: string }).name || 0))}`;
	const lines = list.map((item) => {
		const current = item as { marker?: string; seriesName?: string; value?: number };
		return `${current.marker || ""}${current.seriesName || ""}: ${IOSize.format(Number(current.value || 0))}`;
	});
	return [title, ...lines].join("<br />");
}

function resolveLineSeries(name: string, data: Array<number | null>, yAxisIndex?: number): SeriesOption {
	const series: SeriesOption = {
		type: "line",
		name,
		showSymbol: false,
		smooth: true,
		lineStyle: {
			width: 2
		},
		areaStyle: {
			opacity: .18
		},
		data
	};

	if (typeof yAxisIndex === "number") {
		series.yAxisIndex = yAxisIndex;
	}

	return series;
}

// ---------- 加载与自动刷新 ----------

let listTimer: number | null = null;
let statusTimer: number | null = null;
let historyTimer: number | null = null;

watch(() => settingStore.dashboard.server, restartAutoRefresh, { deep: true });

onMounted(() => {
	updateThemeState();
	restartAutoRefresh();
	themeObserver = new MutationObserver(() => {
		updateThemeState();
	});
	themeObserver.observe(document.documentElement, {
		attributes: true,
		attributeFilter: ["class"]
	});
});

onUnmounted(() => {
	clearAutoRefreshTimer();
	if (themeObserver) {
		themeObserver.disconnect();
		themeObserver = null;
	}
});

function updateThemeState(): void {
	isDarkTheme.value = document.documentElement.classList.contains("theme-dark");
}

function syncSelectedContainer(): void {
	if (!containerItems.value.length) {
		selectedContainerId.value = "";
		statusView.value = null;
		historyPoints.value = [];
		return;
	}
	const currentExists = containerItems.value.some((item) => item.id === selectedContainerId.value);
	if (!currentExists) {
		selectedContainerId.value = containerItems.value[0].id;
	}
}

function resetHistorySlider(): void {
	historySliderValue.value = 0;
	isHistorySliderTouched.value = false;
}

async function refreshContainers(): Promise<void> {
	if (isListLoading.value) {
		return;
	}
	isListLoading.value = true;
	try {
		const list = await DockerAPI.getContainers();
		containerItems.value = list.slice().sort((left, right) => left.name.localeCompare(right.name));
		syncSelectedContainer();
	} catch (error) {
		Toast({
			theme: "error",
			message: error instanceof Error ? error.message : "请求失败，请稍后重试"
		});
	} finally {
		isListLoading.value = false;
	}
}

async function refreshContainerStatus(): Promise<void> {
	if (!selectedContainerId.value) {
		statusView.value = null;
		return;
	}
	if (isStatusLoading.value) {
		return;
	}
	isStatusLoading.value = true;
	try {
		statusView.value = await DockerAPI.getContainerStatus(selectedContainerId.value);
	} catch (error) {
		Toast({
			theme: "error",
			message: error instanceof Error ? error.message : "请求失败，请稍后重试"
		});
	} finally {
		isStatusLoading.value = false;
	}
}

async function refreshContainerHistory(): Promise<void> {
	if (!selectedContainerId.value) {
		historyPoints.value = [];
		return;
	}
	if (isHistoryLoading.value) {
		return;
	}
	isHistoryLoading.value = true;
	try {
		const historyView = await DockerAPI.getContainerHistory(selectedContainerId.value, {
			window: "2h"
		});
		historyPoints.value = historyView?.points || [];
	} catch (error) {
		Toast({
			theme: "error",
			message: error instanceof Error ? error.message : "请求失败，请稍后重试"
		});
	} finally {
		isHistoryLoading.value = false;
	}
}

async function refreshSnapshot(): Promise<void> {
	await refreshContainers();
	await refreshContainerStatus();
}

async function refreshDashboard(): Promise<void> {
	await refreshSnapshot();
	await refreshContainerHistory();
}

function restartAutoRefresh(): void {
	void refreshDashboard();
	clearAutoRefreshTimer();

	const snapshotIntervalMs = Math.max(settingStore.dashboard.server.snapshotRefreshSeconds, 1) * 1000;
	const historyIntervalMs = Math.max(settingStore.dashboard.server.historyRefreshSeconds, 1) * 1000;

	listTimer = window.setInterval(() => {
		void refreshContainers();
	}, snapshotIntervalMs);

	statusTimer = window.setInterval(() => {
		void refreshContainerStatus();
	}, snapshotIntervalMs);

	historyTimer = window.setInterval(() => {
		void refreshContainerHistory();
	}, historyIntervalMs);
}

function clearAutoRefreshTimer(): void {
	if (listTimer !== null) {
		window.clearInterval(listTimer);
		listTimer = null;
	}
	if (statusTimer !== null) {
		window.clearInterval(statusTimer);
		statusTimer = null;
	}
	if (historyTimer !== null) {
		window.clearInterval(historyTimer);
		historyTimer = null;
	}
}

async function handleSelectContainer(containerId: string): Promise<void> {
	if (containerId === selectedContainerId.value) {
		return;
	}
	selectedContainerId.value = containerId;
	statusView.value = null;
	historyPoints.value = [];
	resetHistorySlider();
	await refreshContainerStatus();
	await refreshContainerHistory();
}
</script>

<style scoped lang="less">
.docker-dashboard {
	gap: 1rem;
	display: flex;
	flex-direction: column;

	.section {

		&.list {
			gap: .6rem;
			display: grid;
			grid-template-columns: repeat(2, minmax(0, 1fr));

			.chip {
				gap: .45rem;
				border: 0;
				display: flex;
				cursor: pointer;
				padding: .6rem;
				text-align: left;
				border-radius: .75rem;
				flex-direction: column;
				background: var(--app-bg-soft, #f6f7f9);

				&.active {
					background: color-mix(in srgb, var(--td-brand-color) 12%, var(--app-bg-soft, #f6f7f9));
					box-shadow: 0 0 0 1px color-mix(in srgb, var(--td-brand-color) 45%, transparent);
				}

				.top,
				.bottom {
					gap: .45rem;
					display: flex;
					align-items: center;
					justify-content: space-between;
				}

				.name {
					flex: 1;
					color: var(--app-text);
					font-size: .85rem;
					font-weight: 700;
					overflow: hidden;
					white-space: nowrap;
					text-overflow: ellipsis;
				}

				.img,
				.note {
					color: var(--app-sub);
					font-size: .72rem;
				}

				.img {
					flex: 1;
					overflow: hidden;
					white-space: nowrap;
					text-overflow: ellipsis;
				}

				.state {
					flex: none;
					padding: .1rem .4rem;
					border-radius: .5rem;

					&.ok {
						color: #047857;
						background: rgba(16, 185, 129, .15);
					}

					&.err {
						color: #b42318;
						background: rgba(250, 76, 76, .14);
					}

					&.wait {
						color: #8a5b00;
						background: rgba(245, 158, 11, .18);
					}
				}
			}
		}

		&.history {

			.metric-tabs {
				width: 100%;
				--td-tab-track-width: 4rem;
			}

			.chart {
				width: 100%;
				height: 16rem;
				background: #FFF;
			}

			.slider {
				gap: .5rem;
				display: flex;
				padding: .5rem 2rem;
				align-items: center;

				.label {
					flex: none;
					font-size: .75rem;
					color: var(--app-sub);
				}

				.control {
					flex: 1;
				}
			}
		}
	}

	.loading-wrap {
		display: flex;
		min-height: 4rem;
		align-items: center;
		justify-content: center;
	}
}

:global(.theme-dark) .docker-dashboard .section.list .chip {
	background: rgba(255, 255, 255, .06);

	&.active {
		background: color-mix(in srgb, var(--td-brand-color) 20%, rgba(255, 255, 255, .06));
	}

	.state {

		&.ok {
			color: #86efac;
		}

		&.err {
			color: #fda4af;
		}

		&.wait {
			color: #fcd34d;
		}
	}
}
</style>
