<template>
  <el-container class="layout command-layout">
    <el-header class="command-header">
      <div class="brand">
        <span class="brand-mark" aria-hidden="true">
          <i></i>
          <b></b>
          <em></em>
        </span>
        <strong>城市照明综合网管平台</strong>
      </div>

      <nav class="top-nav" aria-label="主导航">
        <button
          v-for="item in visibleNavItems"
          :key="item.label"
          class="nav-item"
          :class="{ active: isActive(item) }"
          type="button"
          @click="router.push(item.path)"
        >
          <el-icon><component :is="item.icon" /></el-icon>
          <span>{{ item.label }}</span>
        </button>
      </nav>

      <div class="header-tools">
        <!-- <button class="tool-button" type="button" title="搜索">
          <el-icon><Search /></el-icon>
        </button>
        <span class="divider"></span>
        <button class="tool-button has-badge" type="button" title="告警通知">
          <el-icon><Bell /></el-icon>
          <sup>12</sup>
        </button>
        <button class="tool-button" type="button" title="全屏">
          <el-icon><FullScreen /></el-icon>
        </button> -->
        <span class="date-time">{{ nowText }}</span>
        <button class="weather" type="button" :title="weatherTitle" @click="handleWeatherClick" @dblclick.stop.prevent="openWeatherLocationDialog">
          <i :class="weatherIconClass" aria-hidden="true"></i>
          <span>{{ weatherText }}</span>
        </button>
        <el-dropdown>
          <button class="user-button" type="button">
            <el-icon><User /></el-icon>
            <span>{{ authStore.user?.name ?? '用户' }}</span>
          </button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item @click="passwordDialogVisible = true">修改密码</el-dropdown-item>
              <el-dropdown-item @click="authStore.logout()">退出登录</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </el-header>

    <el-main class="main">
      <router-view />
    </el-main>

    <el-dialog v-model="passwordDialogVisible" title="修改密码" width="420px">
      <el-form :model="passwordForm" label-width="90px">
        <el-form-item label="原密码">
          <el-input v-model="passwordForm.oldPassword" type="password" show-password />
        </el-form-item>
        <el-form-item label="新密码">
          <el-input v-model="passwordForm.newPassword" type="password" show-password />
        </el-form-item>
        <el-form-item label="确认密码">
          <el-input v-model="passwordForm.confirmPassword" type="password" show-password />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="passwordDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="changingPassword" @click="changePassword">保存</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="weatherLocationDialogVisible" title="选择天气位置" width="480px">
      <el-form :model="weatherLocationForm" label-width="80px">
        <el-form-item label="地点">
          <el-input v-model.trim="weatherLocationForm.keyword" placeholder="输入城市、区县或详细地址" @keyup.enter="resolveWeatherLocation">
            <template #append>
              <el-button :loading="weatherLocationSaving" @click="resolveWeatherLocation">解析</el-button>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="位置名称">
          <el-input v-model.trim="weatherLocationForm.locationName" placeholder="用于悬浮提示展示" />
        </el-form-item>
        <el-form-item label="经纬度">
          <div class="weather-location-grid">
            <el-input v-model.trim="weatherLocationForm.longitude" placeholder="经度" />
            <el-input v-model.trim="weatherLocationForm.latitude" placeholder="纬度" />
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="clearStoredWeatherLocation">清除保存</el-button>
        <el-button :loading="weatherLocationSaving" @click="fillBrowserWeatherLocation">浏览器定位</el-button>
        <el-button @click="weatherLocationDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="weatherLocationSaving" @click="saveWeatherLocation">保存并刷新</el-button>
      </template>
    </el-dialog>
  </el-container>
</template>

<script setup lang="ts">
import { Bell, FullScreen, Monitor, Odometer, Search, Setting, Tools, User, Warning } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { authApi } from '../api/modules';
import { menuRoutes } from '../router';
import { useAuthStore } from '../stores/auth';
import { BEIJING_CENTER, getBrowserCoordinates, loadAmap } from '../utils/amap';

const authStore = useAuthStore();
const route = useRoute();
const router = useRouter();
const passwordDialogVisible = ref(false);
const changingPassword = ref(false);
const weatherLocationDialogVisible = ref(false);
const weatherLocationSaving = ref(false);
const nowText = ref('');
const passwordForm = reactive({ oldPassword: '', newPassword: '', confirmPassword: '' });
const weatherLocationForm = reactive({
  keyword: '',
  locationName: '',
  longitude: '',
  latitude: '',
});
let clockTimer: number | undefined;
let weatherTimer: number | undefined;
let weatherClickTimer: number | undefined;

const WEATHER_LOCATION_STORAGE_KEY = 'urbanLighting.weatherLocation';

interface WeatherState {
  status: 'locating' | 'loading' | 'ready' | 'error';
  temperature?: number;
  weatherCode?: number;
  updatedAt?: string;
  latitude?: number;
  longitude?: number;
  locationName?: string;
  errorText?: string;
}

interface WeatherLocationPreference {
  longitude: number;
  latitude: number;
  locationName: string;
}

const weather = ref<WeatherState>({ status: 'locating' });

const visibleNavItems = computed(() =>
  menuRoutes
    .filter((item) => {
      const permission = item.meta?.permission as string | undefined;
      return !permission || authStore.permissions.includes(permission);
    })
    .map((item) => ({
      label: String(item.meta?.title ?? ''),
      path: item.path,
      icon: routeIcon(item.path),
    })),
);

const weatherText = computed(() => {
  if (weather.value.status === 'locating') {
    return '定位中';
  }
  if (weather.value.status === 'loading') {
    return '天气获取中';
  }
  if (weather.value.status === 'error' || weather.value.temperature === undefined) {
    return weather.value.errorText ?? '天气获取失败';
  }
  return `${weatherCodeText(weather.value.weatherCode)} ${Math.round(weather.value.temperature)}°C`;
});

const weatherTitle = computed(() => {
  if (!weather.value.locationName && weather.value.longitude === undefined && weather.value.latitude === undefined) {
    return weatherText.value;
  }
  const longitude = weather.value.longitude?.toFixed(4) ?? '-';
  const latitude = weather.value.latitude?.toFixed(4) ?? '-';
  const locationName = weather.value.locationName ?? '当前位置';
  const updatedAt = weather.value.updatedAt ? `，更新时间：${weather.value.updatedAt}` : '';
  return `实时天气：${locationName}（${longitude}, ${latitude}），${weatherText.value}${updatedAt}`;
});

const weatherIconClass = computed(() => {
  const code = weather.value.weatherCode;
  if (weather.value.status === 'error') {
    return 'error';
  }
  if (code === undefined) {
    return 'loading';
  }
  if ([0, 1].includes(code)) {
    return 'sun';
  }
  if ([2, 3].includes(code)) {
    return 'cloud';
  }
  if ([45, 48].includes(code)) {
    return 'fog';
  }
  if ([95, 96, 99].includes(code)) {
    return 'storm';
  }
  if ((code >= 51 && code <= 67) || (code >= 80 && code <= 82)) {
    return 'rain';
  }
  if ((code >= 71 && code <= 77) || (code >= 85 && code <= 86)) {
    return 'snow';
  }
  return 'cloud';
});

function routeIcon(path: string) {
  if (path === '/dashboard') {
    return Odometer;
  }
  if (path === '/map' || path === '/lamps' || path === '/terminals') {
    return Monitor;
  }
  if (path === '/sync') {
    return Tools;
  }
  if (path === '/alarms') {
    return Warning;
  }
  if (path.startsWith('/system/users')) {
    return User;
  }
  return Setting;
}

function isActive(item: { path: string }) {
  return route.path === item.path || route.path.startsWith(`${item.path}/`);
}

function refreshClock() {
  const now = new Date();
  const date = now.toLocaleDateString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).replaceAll('/', '-');
  const time = now.toLocaleTimeString('zh-CN', { hour12: false });
  const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'][now.getDay()];
  nowText.value = `${date} ${time} ${week}`;
}

function weatherCodeText(code?: number) {
  if (code === undefined) {
    return '实时天气';
  }
  const labels: Record<number, string> = {
    0: '晴',
    1: '晴间多云',
    2: '多云',
    3: '阴',
    45: '雾',
    48: '雾凇',
    51: '毛毛雨',
    53: '毛毛雨',
    55: '毛毛雨',
    56: '冻雨',
    57: '冻雨',
    61: '小雨',
    63: '中雨',
    65: '大雨',
    66: '冻雨',
    67: '冻雨',
    71: '小雪',
    73: '中雪',
    75: '大雪',
    77: '雪粒',
    80: '阵雨',
    81: '阵雨',
    82: '强阵雨',
    85: '阵雪',
    86: '强阵雪',
    95: '雷雨',
    96: '雷雨冰雹',
    99: '雷雨冰雹',
  };
  return labels[code] ?? '实时天气';
}

function formatBeijingDateTime(value?: string) {
  if (value) {
    const beijingTime = value.match(/^(\d{4})-(\d{2})-(\d{2})[T\s](\d{2}):(\d{2})(?::(\d{2}))?/);
    if (beijingTime && !/[zZ]|[+-]\d{2}:?\d{2}$/.test(value)) {
      return `${beijingTime[1]}-${beijingTime[2]}-${beijingTime[3]} ${beijingTime[4]}:${beijingTime[5]}:${beijingTime[6] ?? '00'}`;
    }
    const date = new Date(value);
    if (!Number.isNaN(date.getTime())) {
      return formatDateInBeijing(date);
    }
  }
  return formatDateInBeijing(new Date());
}

function formatDateInBeijing(date: Date) {
  const parts = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  }).formatToParts(date);
  const getPart = (type: string) => parts.find((part) => part.type === type)?.value ?? '00';
  return `${getPart('year')}-${getPart('month')}-${getPart('day')} ${getPart('hour')}:${getPart('minute')}:${getPart('second')}`;
}

function refreshWeather() {
  if (weather.value.status === 'locating' || weather.value.status === 'loading') {
    return;
  }
  void loadWeather();
}

function handleWeatherClick() {
  if (weatherClickTimer) {
    window.clearTimeout(weatherClickTimer);
    weatherClickTimer = undefined;
    return;
  }
  weatherClickTimer = window.setTimeout(() => {
    weatherClickTimer = undefined;
    refreshWeather();
  }, 240);
}

function openWeatherLocationDialog() {
  if (weatherClickTimer) {
    window.clearTimeout(weatherClickTimer);
    weatherClickTimer = undefined;
  }
  const storedLocation = readStoredWeatherLocation();
  const longitude = storedLocation?.longitude ?? weather.value.longitude ?? BEIJING_CENTER[0];
  const latitude = storedLocation?.latitude ?? weather.value.latitude ?? BEIJING_CENTER[1];
  const locationName = storedLocation?.locationName ?? weather.value.locationName ?? '北京市';
  weatherLocationForm.keyword = locationName;
  weatherLocationForm.locationName = locationName;
  weatherLocationForm.longitude = String(longitude);
  weatherLocationForm.latitude = String(latitude);
  weatherLocationDialogVisible.value = true;
}

function readStoredWeatherLocation(): WeatherLocationPreference | null {
  try {
    const raw = window.localStorage.getItem(WEATHER_LOCATION_STORAGE_KEY);
    if (!raw) {
      return null;
    }
    const parsed = JSON.parse(raw) as Partial<WeatherLocationPreference>;
    const longitude = Number(parsed.longitude);
    const latitude = Number(parsed.latitude);
    if (!isValidLongitude(longitude) || !isValidLatitude(latitude)) {
      window.localStorage.removeItem(WEATHER_LOCATION_STORAGE_KEY);
      return null;
    }
    return {
      longitude,
      latitude,
      locationName: typeof parsed.locationName === 'string' && parsed.locationName.trim() ? parsed.locationName.trim() : '自定义位置',
    };
  } catch {
    return null;
  }
}

function writeStoredWeatherLocation(location: WeatherLocationPreference) {
  window.localStorage.setItem(WEATHER_LOCATION_STORAGE_KEY, JSON.stringify(location));
}

function isValidLongitude(value: number) {
  return Number.isFinite(value) && value >= -180 && value <= 180;
}

function isValidLatitude(value: number) {
  return Number.isFinite(value) && value >= -90 && value <= 90;
}

function getWeatherLocationFromForm() {
  const longitude = Number(weatherLocationForm.longitude);
  const latitude = Number(weatherLocationForm.latitude);
  if (!isValidLongitude(longitude) || !isValidLatitude(latitude)) {
    ElMessage.warning('请输入有效的经纬度');
    return null;
  }
  return {
    longitude,
    latitude,
    locationName: weatherLocationForm.locationName.trim() || weatherLocationForm.keyword.trim() || '自定义位置',
  };
}

async function resolveWeatherLocation() {
  const keyword = weatherLocationForm.keyword.trim();
  if (!keyword) {
    ElMessage.warning('请输入地点名称');
    return;
  }
  weatherLocationSaving.value = true;
  try {
    const location = await geocodeAddress(keyword);
    weatherLocationForm.longitude = String(location.longitude);
    weatherLocationForm.latitude = String(location.latitude);
    weatherLocationForm.locationName = location.locationName;
  } catch {
    ElMessage.error('地点解析失败，请手动输入经纬度');
  } finally {
    weatherLocationSaving.value = false;
  }
}

async function fillBrowserWeatherLocation() {
  weatherLocationSaving.value = true;
  try {
    const [longitude, latitude] = await getBrowserCoordinates();
    const locationName = await reverseGeocode(longitude, latitude);
    weatherLocationForm.keyword = locationName;
    weatherLocationForm.locationName = locationName;
    weatherLocationForm.longitude = String(longitude);
    weatherLocationForm.latitude = String(latitude);
  } catch {
    ElMessage.warning('浏览器定位失败');
  } finally {
    weatherLocationSaving.value = false;
  }
}

async function saveWeatherLocation() {
  const formLocation = getWeatherLocationFromForm();
  if (!formLocation) {
    return;
  }
  weatherLocationSaving.value = true;
  try {
    const locationName = formLocation.locationName === '自定义位置'
      ? await reverseGeocode(formLocation.longitude, formLocation.latitude)
      : formLocation.locationName;
    writeStoredWeatherLocation({ ...formLocation, locationName });
    weatherLocationDialogVisible.value = false;
    ElMessage.success('天气位置已保存');
    void loadWeather();
  } catch {
    ElMessage.error('天气位置保存失败');
  } finally {
    weatherLocationSaving.value = false;
  }
}

function clearStoredWeatherLocation() {
  window.localStorage.removeItem(WEATHER_LOCATION_STORAGE_KEY);
  weatherLocationDialogVisible.value = false;
  ElMessage.success('已清除保存的天气位置');
  void loadWeather();
}

async function loadWeather() {
  weather.value = { status: 'locating' };
  let longitude = 0;
  let latitude = 0;
  let locationName = '';
  const storedLocation = readStoredWeatherLocation();

  if (storedLocation) {
    longitude = storedLocation.longitude;
    latitude = storedLocation.latitude;
    locationName = storedLocation.locationName;
  } else {
    try {
      [longitude, latitude] = await getBrowserCoordinates();
      locationName = await reverseGeocode(longitude, latitude);
    } catch {
      [longitude, latitude] = BEIJING_CENTER;
      locationName = '北京市';
    }
  }

  const params = new URLSearchParams({
    latitude: String(latitude),
    longitude: String(longitude),
    current: 'temperature_2m,weather_code',
    timezone: 'Asia/Shanghai',
  });

  weather.value = { status: 'loading', latitude, longitude, locationName };
  try {
    const response = await fetch(`https://api.open-meteo.com/v1/forecast?${params.toString()}`, { cache: 'no-store' });
    if (!response.ok) {
      throw new Error(`weather request failed: ${response.status}`);
    }
    const data = await response.json();
    const current = data.current ?? {};
    const temperature = Number(current.temperature_2m);
    const weatherCode = Number(current.weather_code);
    if (!Number.isFinite(temperature) || !Number.isFinite(weatherCode)) {
      throw new Error('weather response missing current data');
    }
    weather.value = {
      status: 'ready',
      temperature,
      weatherCode,
      updatedAt: formatBeijingDateTime(current.time),
      latitude,
      longitude,
      locationName,
    };
  } catch {
    weather.value = { status: 'error', errorText: '天气获取失败', latitude, longitude, locationName };
  }
}

async function geocodeAddress(keyword: string) {
  const AMap = await loadAmap();
  await withTimeout(
    new Promise<void>((resolve, reject) => {
      AMap.plugin('AMap.Geocoder', () => {
        if (AMap.Geocoder) {
          resolve();
          return;
        }
        reject(new Error('AMap.Geocoder unavailable'));
      });
    }),
    4000,
  );
  const geocoder = new AMap.Geocoder();
  const result = await withTimeout(
    new Promise<any>((resolve, reject) => {
      geocoder.getLocation(keyword, (status: string, response: any) => {
        const geocode = response?.geocodes?.[0];
        if (status === 'complete' && geocode?.location) {
          resolve(geocode);
          return;
        }
        reject(new Error('geocode failed'));
      });
    }),
    5000,
  );
  const longitude = Number(result.location.lng);
  const latitude = Number(result.location.lat);
  if (!isValidLongitude(longitude) || !isValidLatitude(latitude)) {
    throw new Error('invalid geocode result');
  }
  return {
    longitude,
    latitude,
    locationName: result.formattedAddress || keyword,
  };
}

async function reverseGeocode(longitude: number, latitude: number) {
  try {
    const AMap = await loadAmap();
    await withTimeout(
      new Promise<void>((resolve, reject) => {
        AMap.plugin('AMap.Geocoder', () => {
          if (AMap.Geocoder) {
            resolve();
            return;
          }
          reject(new Error('AMap.Geocoder unavailable'));
        });
      }),
      4000,
    );
    const geocoder = new AMap.Geocoder();
    const result = await withTimeout(
      new Promise<any>((resolve, reject) => {
        geocoder.getAddress([longitude, latitude], (status: string, response: any) => {
          if (status === 'complete' && response?.regeocode) {
            resolve(response.regeocode);
            return;
          }
          reject(new Error('reverse geocode failed'));
        });
      }),
      5000,
    );
    const component = result.addressComponent ?? {};
    return [component.province, component.city, component.district].filter(Boolean).join('') || result.formattedAddress || '当前位置';
  } catch {
    return '当前位置';
  }
}

function withTimeout<T>(promise: Promise<T>, milliseconds: number) {
  return new Promise<T>((resolve, reject) => {
    const timer = window.setTimeout(() => reject(new Error('request timeout')), milliseconds);
    promise
      .then((value) => {
        window.clearTimeout(timer);
        resolve(value);
      })
      .catch((error) => {
        window.clearTimeout(timer);
        reject(error);
      });
  });
}

async function changePassword() {
  if (passwordForm.newPassword !== passwordForm.confirmPassword) {
    ElMessage.warning('两次输入的新密码不一致');
    return;
  }
  changingPassword.value = true;
  try {
    await authApi.changePassword({
      oldPassword: passwordForm.oldPassword,
      newPassword: passwordForm.newPassword,
    });
    ElMessage.success('密码修改成功，请重新登录');
    passwordDialogVisible.value = false;
    passwordForm.oldPassword = '';
    passwordForm.newPassword = '';
    passwordForm.confirmPassword = '';
    authStore.logout();
  } finally {
    changingPassword.value = false;
  }
}

onMounted(() => {
  refreshClock();
  void loadWeather();
  clockTimer = window.setInterval(refreshClock, 1000);
  weatherTimer = window.setInterval(() => void loadWeather(), 10 * 60 * 1000);
});

onBeforeUnmount(() => {
  if (clockTimer) {
    window.clearInterval(clockTimer);
  }
  if (weatherTimer) {
    window.clearInterval(weatherTimer);
  }
  if (weatherClickTimer) {
    window.clearTimeout(weatherClickTimer);
  }
});
</script>

<style scoped>
.layout {
  min-height: 100vh;
  overflow: hidden;
  background:
    radial-gradient(circle at 21% 12%, rgba(0, 141, 255, 0.24), transparent 25%),
    radial-gradient(circle at 78% 8%, rgba(37, 99, 235, 0.18), transparent 26%),
    linear-gradient(180deg, #05152d 0%, #031126 46%, #020916 100%);
}

.command-header {
  --header-height: 58px;
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr) auto;
  align-items: center;
  height: var(--header-height);
  padding: 0 18px;
  border-bottom: 1px solid rgba(26, 137, 255, 0.36);
  background:
    linear-gradient(180deg, rgba(2, 19, 46, 0.96), rgba(3, 14, 35, 0.86)),
    linear-gradient(90deg, rgba(33, 150, 243, 0.16), transparent 45%, rgba(33, 150, 243, 0.12));
  box-shadow: 0 10px 36px rgba(0, 12, 35, 0.42), inset 0 -1px rgba(255, 255, 255, 0.08);
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  color: #f8fbff;
}

.brand strong {
  overflow: hidden;
  font-size: 22px;
  font-weight: 800;
  letter-spacing: 0;
  text-overflow: ellipsis;
  text-shadow: 0 0 16px rgba(65, 170, 255, 0.48);
  white-space: nowrap;
}

.brand-mark {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: flex-end;
  width: 40px;
  height: 40px;
  padding: 4px 5px;
  color: #39d7ff;
  border-bottom: 2px solid currentColor;
  filter: drop-shadow(0 0 10px rgba(35, 162, 255, 0.72));
}

.brand-mark i,
.brand-mark b,
.brand-mark em {
  display: block;
  width: 6px;
  margin-right: 3px;
  border: 1px solid currentColor;
  background: linear-gradient(180deg, rgba(86, 196, 255, 0.95), rgba(15, 87, 208, 0.36));
  box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.28);
}

.brand-mark i {
  height: 19px;
}

.brand-mark b {
  height: 28px;
}

.brand-mark em {
  height: 35px;
  margin-right: 0;
}

.top-nav {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  height: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.top-nav::-webkit-scrollbar {
  display: none;
}

.nav-item,
.tool-button,
.user-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  color: #b9c9de;
  background: transparent;
  cursor: pointer;
  transition: color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

.nav-item {
  position: relative;
  flex: 0 0 auto;
  gap: 8px;
  height: 42px;
  padding: 0 18px;
  font-size: 15px;
  font-weight: 700;
  white-space: nowrap;
}

.nav-item::after {
  position: absolute;
  right: 12px;
  bottom: 0;
  left: 12px;
  height: 2px;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, #2dd4ff, transparent);
  opacity: 0;
  content: "";
}

.nav-item:hover,
.nav-item.active {
  color: #fff;
  background: linear-gradient(180deg, rgba(20, 86, 179, 0.72), rgba(5, 32, 82, 0.26));
  box-shadow: inset 0 0 18px rgba(38, 145, 255, 0.26), 0 0 18px rgba(17, 104, 255, 0.12);
}

.nav-item.active::after {
  opacity: 1;
}

.nav-item .el-icon {
  font-size: 18px;
}

.header-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-self: end;
  color: #d7e6f8;
}

.tool-button {
  position: relative;
  width: 30px;
  height: 30px;
  border-radius: 4px;
  font-size: 18px;
}

.tool-button:hover,
.user-button:hover {
  color: #fff;
  background: rgba(28, 129, 255, 0.18);
}

.tool-button sup {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  color: #fff;
  background: #ff4d40;
  font-size: 11px;
  line-height: 17px;
}

.divider {
  width: 1px;
  height: 24px;
  background: rgba(148, 184, 220, 0.28);
}

.date-time {
  color: #d8e7f9;
  font-family: "DIN Alternate", "Roboto Mono", monospace;
  font-size: 14px;
  white-space: nowrap;
}

.weather {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 88px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #e6f4ff;
  cursor: pointer;
  font: inherit;
  font-size: 14px;
  white-space: nowrap;
}

.weather:focus-visible {
  outline: 1px solid rgba(53, 215, 255, 0.86);
  outline-offset: 4px;
}

.weather i {
  position: relative;
  flex: 0 0 auto;
  width: 22px;
  height: 14px;
}

.weather i::before,
.weather i::after {
  position: absolute;
  content: "";
}

.weather i.sun::before {
  inset: 1px 5px;
  border-radius: 50%;
  background: #ffd45a;
  box-shadow: 0 0 12px rgba(255, 212, 90, 0.88);
}

.weather i.sun::after {
  inset: -2px 2px;
  border: 1px dashed rgba(255, 212, 90, 0.85);
  border-radius: 50%;
}

.weather i.cloud::before,
.weather i.rain::before,
.weather i.snow::before,
.weather i.storm::before,
.weather i.fog::before {
  right: 0;
  bottom: 2px;
  left: 2px;
  height: 10px;
  border-radius: 999px;
  background: #f7fbff;
  box-shadow: -7px 1px 0 -3px #f7fbff, 7px 1px 0 -2px #f7fbff, 0 0 10px rgba(156, 218, 255, 0.58);
}

.weather i.rain::after {
  right: 3px;
  bottom: -3px;
  width: 2px;
  height: 8px;
  border-radius: 999px;
  background: #35d7ff;
  box-shadow: -7px -1px 0 #35d7ff, -14px 0 0 #35d7ff;
  transform: rotate(18deg);
}

.weather i.snow::after {
  right: 4px;
  bottom: -4px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #dff7ff;
  box-shadow: -8px -1px 0 #dff7ff, -15px 1px 0 #dff7ff;
}

.weather i.storm::after {
  right: 5px;
  bottom: -6px;
  width: 8px;
  height: 12px;
  clip-path: polygon(44% 0, 100% 0, 58% 45%, 100% 45%, 22% 100%, 42% 54%, 0 54%);
  background: #ffd45a;
}

.weather i.fog::after {
  right: 1px;
  bottom: -2px;
  left: 0;
  height: 2px;
  border-radius: 999px;
  background: #bfe6ff;
  box-shadow: 0 5px 0 rgba(191, 230, 255, 0.85);
}

.weather i.loading::before,
.weather i.error::before {
  inset: 1px 5px;
  border: 2px solid rgba(180, 213, 248, 0.45);
  border-top-color: #35d7ff;
  border-radius: 50%;
}

.weather i.loading::before {
  animation: weather-spin 1s linear infinite;
}

.weather i.error::before {
  border-color: #ff6b4a;
}

.weather span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.weather-location-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  width: 100%;
}

@keyframes weather-spin {
  to {
    transform: rotate(360deg);
  }
}

.user-button {
  gap: 6px;
  height: 32px;
  max-width: 120px;
  padding: 0 10px;
  border: 1px solid rgba(72, 164, 255, 0.22);
  border-radius: 4px;
  font-size: 13px;
}

.user-button span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.main {
  height: calc(100vh - 58px);
  padding: 0;
  overflow: auto;
}

@media (max-width: 1280px) {
  .command-header {
    grid-template-columns: 260px minmax(0, 1fr) auto;
    padding: 0 12px;
  }

  .nav-item {
    padding: 0 11px;
    font-size: 14px;
  }

  .date-time,
  .weather {
    display: none;
  }
}

@media (max-width: 860px) {
  .command-header {
    grid-template-columns: 1fr auto;
    height: auto;
    min-height: 58px;
    row-gap: 8px;
    padding: 10px 12px;
  }

  .top-nav {
    grid-column: 1 / -1;
    order: 3;
    overflow-x: auto;
    padding-bottom: 4px;
  }

  .main {
    height: calc(100vh - 112px);
  }

  .brand strong {
    font-size: 18px;
  }
}
</style>
