<script setup lang="ts">
import type {
  AgentListItem,
  KnowledgeBaseListItem,
  WorkflowListItem,
  WorkflowRunListItem,
} from '#/api/ai-platform/ai-platform';
import type { UserAnnouncement } from '#/api/core/announcement';
import type { Message } from '#/api/core/message';

import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';

import { Page } from '@vben/common-ui';
import {
  Bell,
  Bot,
  BookOpen,
  Calendar,
  CheckCircle2,
  ClipboardList,
  CloudSun,
  Cpu,
  Database,
  FileText,
  GitBranch,
  LayoutGrid,
  Mail,
  MessageSquare,
  Network,
  Play,
  Route,
  Send,
  Server,
  Settings,
  Shield,
  Users,
  Workflow,
} from '@vben/icons';
import { useUserStore } from '@vben/stores';

import { ElButton, ElEmpty, ElProgress, ElSkeleton, ElTag } from 'element-plus';

import {
  getAgentListApi,
  getAllWorkflowRunsApi,
  getKnowledgeBaseListApi,
  getWorkflowListApi,
} from '#/api/ai-platform/ai-platform';
import {
  getUnreadAnnouncementCountApi,
  getUserAnnouncementListApi,
} from '#/api/core/announcement';
import { getMessageListApi, getUnreadCountApi } from '#/api/core/message';
import {
  getServerHealthOverviewApi,
  getServerHealthRealtimeApi,
  type ServerHealthOverview,
  type ServerRealtimeStats,
} from '#/api/core/server-health';

defineOptions({ name: 'ControlCenter' });

const router = useRouter();
const userStore = useUserStore();

const loading = ref(false);
const loaded = ref(false);
const now = ref(new Date());
const timer = ref<number>();
const agents = ref<AgentListItem[]>([]);
const workflows = ref<WorkflowListItem[]>([]);
const knowledgeBases = ref<KnowledgeBaseListItem[]>([]);
const runs = ref<WorkflowRunListItem[]>([]);
const announcements = ref<UserAnnouncement[]>([]);
const messages = ref<Message[]>([]);
const serverOverview = ref<ServerHealthOverview>();
const realtimeStats = ref<ServerRealtimeStats>();

const stats = reactive({
  agentTotal: 0,
  announcementUnread: 0,
  knowledgeTotal: 0,
  messageUnread: 0,
  runTotal: 0,
  workflowTotal: 0,
});

const displayName = computed(() => {
  return (
    userStore.userInfo?.realName ||
    userStore.userInfo?.username ||
    '超级管理员'
  );
});

const greeting = computed(() => {
  const hour = now.value.getHours();
  if (hour < 6) return '凌晨好';
  if (hour < 12) return '上午好';
  if (hour < 18) return '下午好';
  return '晚上好';
});

const currentTime = computed(() =>
  now.value.toLocaleTimeString('zh-CN', { hour12: false }),
);

const currentDate = computed(() =>
  now.value.toLocaleDateString('zh-CN', {
    day: 'numeric',
    month: 'long',
    weekday: 'long',
    year: 'numeric',
  }),
);

const publishedAgents = computed(
  () => agents.value.filter((item) => item.status === 'published').length,
);

const publishedWorkflows = computed(
  () => workflows.value.filter((item) => item.status === 'published').length,
);

const completedRuns = computed(
  () =>
    runs.value.filter((item) =>
      ['completed', 'success'].includes(item.status),
    ).length,
);

const failedRuns = computed(
  () => runs.value.filter((item) => item.status === 'failed').length,
);

const tokenTotal = computed(() =>
  runs.value.reduce((sum, item) => sum + (item.total_tokens || 0), 0),
);

const successRate = computed(() => {
  if (!runs.value.length) return 0;
  return Math.round((completedRuns.value / runs.value.length) * 100);
});

const collaborationItems = computed(() => [
  {
    color: 'blue',
    icon: Send,
    path: '/ai-platform/agent',
    title: '我发起的',
    value: stats.agentTotal,
  },
  {
    color: 'amber',
    icon: ClipboardList,
    path: '/ai-platform/workflow-runs',
    title: '我的待办',
    value: Math.max(stats.runTotal - completedRuns.value, 0),
  },
  {
    color: 'violet',
    icon: Workflow,
    path: '/ai-platform/workflow-runs',
    title: '我的在办',
    value: runs.value.length,
  },
  {
    color: 'cyan',
    icon: CheckCircle2,
    path: '/ai-platform/agent',
    title: '我的已办',
    value: publishedAgents.value,
  },
  {
    color: 'orange',
    icon: Bell,
    path: '/message/announcement-list',
    title: '抄送我的',
    value: stats.messageUnread + stats.announcementUnread,
  },
  {
    color: 'green',
    icon: Play,
    path: '/ai-platform/workflow',
    title: '发起流程',
    value: stats.workflowTotal,
  },
]);

const appEntries = [
  {
    color: 'blue',
    icon: Bot,
    path: '/ai-platform/agent',
    title: '智能体协作',
  },
  {
    color: 'cyan',
    icon: Workflow,
    path: '/ai-platform/workflow',
    title: '流程编排',
  },
  {
    color: 'amber',
    icon: BookOpen,
    path: '/ai-platform/knowledge',
    title: '知识库',
  },
  {
    color: 'violet',
    icon: MessageSquare,
    path: '/agent-chat/codex',
    title: 'Codex 协作',
  },
];

const quickLinks = [
  {
    icon: Settings,
    path: '/system-config',
    title: '系统配置',
  },
  {
    icon: Users,
    path: '/system/user',
    title: '用户管理',
  },
  {
    icon: Shield,
    path: '/system/role',
    title: '角色权限',
  },
  {
    icon: Route,
    path: '/system/menu',
    title: '菜单管理',
  },
  {
    icon: FileText,
    path: '/message/announcement',
    title: '公告管理',
  },
  {
    icon: Mail,
    path: '/message/announcement-list',
    title: '消息中心',
  },
  {
    icon: GitBranch,
    path: '/ai-platform/workflow-runs',
    title: '执行历史',
  },
  {
    icon: Database,
    path: '/system/new-permission',
    title: 'API 管理',
  },
];

const resourceCards = computed(() => [
  {
    icon: Bot,
    label: '智能体',
    tone: 'blue',
    value: stats.agentTotal,
  },
  {
    icon: Workflow,
    label: '流程',
    tone: 'cyan',
    value: stats.workflowTotal,
  },
  {
    icon: BookOpen,
    label: '知识库',
    tone: 'amber',
    value: stats.knowledgeTotal,
  },
  {
    icon: Play,
    label: '执行记录',
    tone: 'green',
    value: stats.runTotal,
  },
]);

const serverCards = computed(() => {
  const overview = serverOverview.value;
  const realtime = realtimeStats.value;
  const memory = realtime?.memory_details || overview?.memory_info.virtual;

  return [
    {
      desc: `${overview?.cpu_info.total_cores || '-'} 核心`,
      icon: Cpu,
      label: 'CPU',
      tone: 'blue',
      value: `${Math.round(realtime?.cpu_percent ?? overview?.cpu_info.cpu_percent ?? 0)}%`,
    },
    {
      desc:
        memory?.used && memory?.total
          ? `${formatBytes(memory.used)} / ${formatBytes(memory.total)}`
          : '等待采集',
      icon: Database,
      label: '内存',
      tone: 'green',
      value: `${Math.round(realtime?.memory_percent ?? overview?.memory_info.virtual.percent ?? 0)}%`,
    },
    {
      desc: `累计读写 ${formatBytes(overview?.disk_info.total_read_bytes)} / ${formatBytes(overview?.disk_info.total_write_bytes)}`,
      icon: Server,
      label: '磁盘读取',
      tone: 'amber',
      value: `${formatBytes(realtime?.disk_io.read_speed)}/s`,
    },
    {
      desc: `上传 ${formatBytes(realtime?.network_io.upload_speed)}/s`,
      icon: Network,
      label: '网络下载',
      tone: 'cyan',
      value: `${formatBytes(realtime?.network_io.download_speed)}/s`,
    },
  ];
});

function go(path: string) {
  router.push(path);
}

function formatTime(value?: string) {
  if (!value) return '-';
  return value.replace('T', ' ').slice(0, 16);
}

function formatBytes(value?: number) {
  if (!value || value <= 0) return '0 B';
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let size = value;
  let unitIndex = 0;
  while (size >= 1024 && unitIndex < units.length - 1) {
    size /= 1024;
    unitIndex += 1;
  }
  return `${size >= 10 || unitIndex === 0 ? size.toFixed(0) : size.toFixed(1)} ${units[unitIndex]}`;
}

function getStatusType(status: string) {
  if (['completed', 'published', 'success'].includes(status)) return 'success';
  if (status === 'failed') return 'danger';
  if (status === 'draft') return 'info';
  return 'primary';
}

async function loadDashboard() {
  loading.value = true;
  now.value = new Date();

  try {
    const [
      agentRes,
      workflowRes,
      knowledgeRes,
      runRes,
      announcementRes,
      announcementUnreadRes,
      messageRes,
      messageUnreadRes,
      serverOverviewRes,
      realtimeStatsRes,
    ] = await Promise.all([
      getAgentListApi({ page: 1, pageSize: 6 }),
      getWorkflowListApi({ page: 1, pageSize: 6 }),
      getKnowledgeBaseListApi({ page: 1, pageSize: 6 }),
      getAllWorkflowRunsApi({ page: 1, pageSize: 6 }),
      getUserAnnouncementListApi({ page: 1, pageSize: 5 }),
      getUnreadAnnouncementCountApi(),
      getMessageListApi({ page: 1, pageSize: 5 }),
      getUnreadCountApi(),
      getServerHealthOverviewApi().catch(() => undefined),
      getServerHealthRealtimeApi().catch(() => undefined),
    ]);

    agents.value = agentRes.items || [];
    workflows.value = workflowRes.items || [];
    knowledgeBases.value = knowledgeRes.items || [];
    runs.value = runRes.items || [];
    announcements.value = announcementRes.items || [];
    messages.value = messageRes.items || [];
    serverOverview.value = serverOverviewRes;
    realtimeStats.value = realtimeStatsRes;

    stats.agentTotal = agentRes.total || agents.value.length;
    stats.workflowTotal = workflowRes.total || workflows.value.length;
    stats.knowledgeTotal = knowledgeRes.total || knowledgeBases.value.length;
    stats.runTotal = runRes.total || runs.value.length;
    stats.announcementUnread = announcementUnreadRes.count || 0;
    stats.messageUnread = messageUnreadRes.total || 0;
    loaded.value = true;
  } finally {
    loading.value = false;
  }
}

onMounted(() => {
  loadDashboard();
  timer.value = window.setInterval(() => {
    now.value = new Date();
  }, 1000);
});

onBeforeUnmount(() => {
  if (timer.value) window.clearInterval(timer.value);
});
</script>

<template>
  <Page content-class="control-center-page" :show-margin="false">
    <div class="workbench">
      <section class="top-grid">
        <div class="welcome-card panel">
          <div class="avatar-badge">AI</div>
          <div class="welcome-copy">
            <h2>{{ greeting }}，{{ displayName }}，欢迎回来</h2>
            <p>这里汇总智能体、流程编排、公告消息和服务器状态，方便快速进入协作工作。</p>
          </div>
          <div class="time-box">
            <strong>{{ currentTime }}</strong>
            <span>{{ currentDate }}</span>
          </div>
        </div>

        <div class="status-card panel">
          <div class="panel-title compact">
            <CloudSun :size="17" />
            <span>今日状态</span>
          </div>
          <div class="status-body">
            <strong>{{ successRate }}%</strong>
            <span>最近流程完成率</span>
          </div>
        </div>
      </section>

      <section class="main-grid">
        <div class="left-stack">
          <div class="panel collaboration-panel">
            <div class="panel-title">
              <LayoutGrid :size="17" />
              <span>协作中心</span>
              <ElButton link type="primary" @click="go('/ai-platform/workflow')">
                更多
              </ElButton>
            </div>
            <div class="collaboration-grid">
              <button
                v-for="item in collaborationItems"
                :key="item.title"
                class="round-entry"
                type="button"
                @click="go(item.path)"
              >
                <span class="round-icon" :class="item.color">
                  <component :is="item.icon" :size="21" />
                </span>
                <strong>{{ item.title }}</strong>
                <small>{{ item.value }}</small>
              </button>
            </div>
          </div>

          <div class="panel app-panel">
            <div class="panel-title">
              <Bot :size="17" />
              <span>我的应用</span>
            </div>
            <div class="app-grid">
              <button
                v-for="entry in appEntries"
                :key="entry.path"
                class="app-entry"
                type="button"
                @click="go(entry.path)"
              >
                <span class="square-icon" :class="entry.color">
                  <component :is="entry.icon" :size="22" />
                </span>
                <span>{{ entry.title }}</span>
              </button>
            </div>
          </div>
        </div>

        <div class="panel feed-panel">
          <div class="panel-title">
            <FileText :size="17" />
            <span>最新公告</span>
          </div>
          <ElSkeleton v-if="loading && !loaded" :rows="4" animated />
          <div v-else-if="announcements.length" class="feed-list">
            <button
              v-for="item in announcements"
              :key="item.id"
              class="feed-item"
              type="button"
              @click="go('/message/announcement-list')"
            >
              <strong>{{ item.title }}</strong>
              <span>{{ item.summary || item.publisher_name || '系统公告' }}</span>
            </button>
          </div>
          <ElEmpty v-else description="暂无公告" />
        </div>

        <div class="panel feed-panel">
          <div class="panel-title">
            <Bell :size="17" />
            <span>消息通知</span>
          </div>
          <ElSkeleton v-if="loading && !loaded" :rows="4" animated />
          <div v-else-if="messages.length" class="feed-list">
            <button
              v-for="item in messages"
              :key="item.id"
              class="feed-item"
              type="button"
              @click="go('/message/announcement-list')"
            >
              <strong>{{ item.title }}</strong>
              <span>{{ formatTime(item.created_at) }} · {{ item.msg_type }}</span>
            </button>
          </div>
          <ElEmpty v-else description="暂无消息" />
        </div>
      </section>

      <section class="server-panel panel">
        <div class="panel-title">
          <Server :size="17" />
          <span>服务器信息</span>
          <small>
            {{
              serverOverview
                ? `${serverOverview.basic_info.hostname} (${serverOverview.basic_info.ip_address}) · 运行 ${serverOverview.boot_time.uptime_formatted}`
                : '等待服务器采集数据'
            }}
          </small>
        </div>
        <div class="resource-grid">
          <div
            v-for="item in serverCards"
            :key="item.label"
            class="resource-card"
          >
            <span class="resource-icon" :class="item.tone">
              <component :is="item.icon" :size="18" />
            </span>
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
            <small>{{ item.desc }}</small>
          </div>
        </div>
      </section>

      <section class="bottom-grid">
        <div class="panel runs-panel">
          <div class="panel-title">
            <GitBranch :size="17" />
            <span>最近执行</span>
            <ElButton
              link
              type="primary"
              @click="go('/ai-platform/workflow-runs')"
            >
              执行历史
            </ElButton>
          </div>
          <ElSkeleton v-if="loading && !loaded" :rows="5" animated />
          <div v-else-if="runs.length" class="run-list">
            <button
              v-for="run in runs"
              :key="run.id"
              class="run-row"
              type="button"
              @click="go('/ai-platform/workflow-runs')"
            >
              <span>
                <strong>{{ run.workflow_name }}</strong>
                <small>
                  {{ run.total_steps }} 步 · {{ run.total_tokens }} tokens ·
                  {{ formatTime(run.started_at) }}
                </small>
              </span>
              <ElTag :type="getStatusType(run.status)" size="small">
                {{ run.status }}
              </ElTag>
            </button>
          </div>
          <ElEmpty v-else description="暂无执行记录" />
        </div>

        <div class="panel quick-panel">
          <div class="panel-title">
            <Network :size="17" />
            <span>快捷入口</span>
          </div>
          <div class="quick-grid">
            <button
              v-for="link in quickLinks"
              :key="link.path"
              class="quick-link"
              type="button"
              @click="go(link.path)"
            >
              <component :is="link.icon" :size="19" />
              <span>{{ link.title }}</span>
            </button>
          </div>
        </div>

        <div class="panel health-panel">
          <div class="panel-title">
            <Cpu :size="17" />
            <span>运行概览</span>
          </div>
          <div class="health-list">
            <div class="runtime-summary">
              <div
                v-for="item in resourceCards"
                :key="item.label"
                class="runtime-chip"
              >
                <component :is="item.icon" :size="16" />
                <span>{{ item.label }}</span>
                <strong>{{ item.value }}</strong>
              </div>
            </div>
            <div>
              <span>智能体发布率</span>
              <strong>{{ publishedAgents }} / {{ stats.agentTotal }}</strong>
              <ElProgress
                :percentage="
                  stats.agentTotal
                    ? Math.round((publishedAgents / stats.agentTotal) * 100)
                    : 0
                "
                :show-text="false"
              />
            </div>
            <div>
              <span>流程发布率</span>
              <strong>{{ publishedWorkflows }} / {{ stats.workflowTotal }}</strong>
              <ElProgress
                :percentage="
                  stats.workflowTotal
                    ? Math.round((publishedWorkflows / stats.workflowTotal) * 100)
                    : 0
                "
                :show-text="false"
              />
            </div>
            <div class="token-row">
              <Calendar :size="17" />
              <span>最近执行消耗 {{ tokenTotal }} tokens</span>
            </div>
          </div>
        </div>
      </section>
    </div>
  </Page>
</template>

<style scoped>
.control-center-page {
  background: hsl(var(--background));
  border-radius: 0;
}

.workbench {
  display: grid;
  gap: 12px;
  padding: 10px 12px;
}

.panel {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: 8px;
  box-shadow: 0 1px 2px rgb(15 23 42 / 4%);
}

.top-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: minmax(0, 9fr) minmax(260px, 3fr);
}

.welcome-card {
  align-items: center;
  display: flex;
  gap: 18px;
  min-height: 122px;
  padding: 22px 28px;
}

.avatar-badge {
  align-items: center;
  background: rgb(16 185 129);
  border-radius: 999px;
  color: rgb(248 250 252);
  display: flex;
  flex-shrink: 0;
  font-size: 18px;
  font-weight: 700;
  height: 50px;
  justify-content: center;
  width: 50px;
}

.welcome-copy {
  flex: 1;
  min-width: 0;
}

.welcome-copy h2 {
  color: hsl(var(--foreground));
  font-size: 20px;
  font-weight: 700;
  line-height: 1.35;
  margin: 0 0 6px;
}

.welcome-copy p,
.time-box span,
.panel-title small,
.feed-item span,
.run-row small,
.resource-card small,
.health-list span,
.token-row {
  color: hsl(var(--muted-foreground));
}

.welcome-copy p {
  margin: 0;
}

.time-box {
  display: grid;
  gap: 6px;
  justify-items: end;
}

.time-box strong {
  font-size: 24px;
  line-height: 1;
}

.status-card {
  display: grid;
  gap: 12px;
  min-height: 122px;
  padding: 18px;
}

.status-body {
  align-items: center;
  display: grid;
  justify-items: center;
}

.status-body strong {
  color: hsl(var(--primary));
  font-size: 26px;
  line-height: 1;
}

.main-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: minmax(0, 6fr) minmax(260px, 3fr) minmax(260px, 3fr);
}

.left-stack {
  display: grid;
  gap: 12px;
}

.panel-title {
  align-items: center;
  display: flex;
  gap: 8px;
  min-height: 42px;
  padding: 14px 16px 8px;
}

.panel-title.compact {
  padding: 0;
}

.panel-title > span {
  flex: 1;
  font-weight: 650;
}

.collaboration-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  padding: 22px 28px 26px;
}

.round-entry,
.app-entry,
.quick-link,
.run-row,
.feed-item {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  text-align: left;
}

.round-entry {
  align-items: center;
  display: grid;
  gap: 8px;
  justify-items: center;
  min-width: 0;
}

.round-entry strong {
  color: hsl(var(--muted-foreground));
  font-size: 13px;
  font-weight: 500;
}

.round-entry small {
  color: hsl(var(--foreground));
  font-weight: 650;
}

.round-icon,
.square-icon,
.resource-icon {
  align-items: center;
  display: flex;
  justify-content: center;
}

.round-icon {
  border-radius: 999px;
  color: rgb(248 250 252);
  height: 44px;
  width: 44px;
}

.square-icon {
  border-radius: 10px;
  color: rgb(248 250 252);
  height: 38px;
  width: 38px;
}

.blue {
  background: rgb(59 130 246);
}

.amber {
  background: rgb(245 158 11);
}

.violet {
  background: rgb(139 92 246);
}

.cyan {
  background: rgb(14 165 233);
}

.orange {
  background: rgb(249 115 22);
}

.green {
  background: rgb(16 185 129);
}

.app-grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  min-height: 116px;
  padding: 20px 28px 24px;
}

.app-entry {
  align-items: center;
  display: grid;
  gap: 10px;
  justify-items: center;
}

.app-entry span:last-child {
  color: hsl(var(--muted-foreground));
  font-size: 13px;
}

.feed-panel {
  min-height: 370px;
}

.feed-list,
.run-list,
.health-list {
  display: grid;
  gap: 10px;
  padding: 8px 16px 16px;
}

.feed-item {
  border-bottom: 1px solid hsl(var(--border));
  display: grid;
  gap: 5px;
  min-height: 56px;
  padding: 8px 0;
}

.feed-item:last-child {
  border-bottom: 0;
}

.feed-item strong,
.run-row strong {
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.server-panel {
  min-height: 164px;
}

.resource-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  padding: 14px 16px 20px;
}

.resource-card {
  background: hsl(var(--muted) / 45%);
  border-radius: 8px;
  display: grid;
  gap: 8px;
  min-height: 106px;
  padding: 14px 16px;
}

.resource-icon {
  border-radius: 8px;
  color: hsl(var(--primary));
  height: 28px;
  width: 28px;
}

.resource-icon.blue {
  background: rgb(219 234 254);
  color: rgb(37 99 235);
}

.resource-icon.cyan {
  background: rgb(204 251 241);
  color: rgb(13 148 136);
}

.resource-icon.amber {
  background: rgb(254 243 199);
  color: rgb(180 83 9);
}

.resource-icon.green {
  background: rgb(220 252 231);
  color: rgb(22 163 74);
}

.resource-card > span:not(.resource-icon) {
  color: hsl(var(--muted-foreground));
}

.resource-card strong {
  font-size: 22px;
  line-height: 1;
}

.bottom-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: minmax(0, 5fr) minmax(320px, 4fr) minmax(260px, 3fr);
}

.runs-panel,
.quick-panel,
.health-panel {
  min-height: 230px;
}

.run-row {
  align-items: center;
  border: 1px solid hsl(var(--border));
  border-radius: 8px;
  display: flex;
  gap: 12px;
  justify-content: space-between;
  min-height: 58px;
  padding: 10px 12px;
}

.run-row > span {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.quick-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  padding: 14px 16px 18px;
}

.quick-link {
  align-items: center;
  border: 1px solid hsl(var(--border));
  border-radius: 8px;
  display: grid;
  gap: 8px;
  justify-items: center;
  min-height: 72px;
  padding: 10px;
}

.quick-link svg {
  color: hsl(var(--primary));
}

.quick-link span {
  color: hsl(var(--muted-foreground));
  font-size: 13px;
}

.health-list > div {
  display: grid;
  gap: 8px;
}

.health-list strong {
  font-size: 16px;
}

.runtime-summary {
  display: grid;
  gap: 8px !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.runtime-chip {
  align-items: center;
  background: hsl(var(--muted) / 45%);
  border-radius: 8px;
  display: grid !important;
  gap: 5px !important;
  grid-template-columns: auto 1fr auto;
  min-height: 42px;
  padding: 8px 10px;
}

.runtime-chip svg {
  color: hsl(var(--primary));
}

.runtime-chip span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.token-row {
  align-items: center;
  display: flex !important;
  gap: 8px !important;
  margin-top: 4px;
}

.round-entry:hover .round-icon,
.app-entry:hover .square-icon,
.quick-link:hover,
.run-row:hover,
.feed-item:hover {
  box-shadow: 0 8px 24px rgb(15 23 42 / 8%);
  transform: translateY(-1px);
}

.round-entry .round-icon,
.app-entry .square-icon,
.quick-link,
.run-row,
.feed-item {
  transition:
    box-shadow 0.18s ease,
    transform 0.18s ease,
    border-color 0.18s ease;
}

@media (max-width: 1280px) {
  .main-grid,
  .bottom-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .left-stack {
    grid-column: 1 / -1;
  }
}

@media (max-width: 960px) {
  .top-grid,
  .main-grid,
  .bottom-grid {
    grid-template-columns: 1fr;
  }

  .collaboration-grid,
  .app-grid,
  .resource-grid,
  .quick-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .welcome-card {
    align-items: flex-start;
    flex-direction: column;
    padding: 18px;
  }

  .time-box {
    justify-items: start;
  }

  .collaboration-grid,
  .app-grid,
  .resource-grid,
  .quick-grid {
    grid-template-columns: 1fr;
  }
}
</style>
