<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { RouterLink } from 'vue-router'
import {
  fetchAgentDetail,
  updateAgentDocumentInjection,
  type AgentDetail,
  type AgentToolDetail,
} from '../api/agentCatalog'
import {
  fetchHealth,
  fetchManualJobs,
  fetchManualRun,
  fetchSchedulerStatus,
  runManualJob,
  type ManualJob,
  type ManualRun,
  type SchedulerStatus,
} from '../api/dashboard'
import { fetchDemandGrade } from '../api/demand'
import { fetchAgentOssLogs } from '../api/ossLog'
import { fetchVideoDiscoveryDemands } from '../api/videoDiscovery'
import type { DemandGradeItem } from '../types/demand'
import type { OssLogItem } from '../types/ossLog'
import type { VideoDiscoveryDemand } from '../types/videoDiscovery'

const health = ref<'loading' | 'online' | 'offline'>('loading')
const scheduler = ref<SchedulerStatus | null>(null)
const jobs = ref<ManualJob[]>([])
const demands = ref<DemandGradeItem[]>([])
const discoveryDemands = ref<VideoDiscoveryDemand[]>([])
const logs = ref<OssLogItem[]>([])
const loading = ref(true)
const notice = ref('')
const noticeType = ref<'success' | 'error'>('success')
const bizDt = ref(todayBizDt())
const runningJobId = ref<string | null>(null)
const activeRun = ref<ManualRun | null>(null)
let pollTimer = 0
let copiedTimer = 0

const pipeline = [
  {
    index: '01',
    title: '数据同步',
    description: '从 ODPS 同步全局分类树、策略需求池与视频点位。',
    color: 'blue',
  },
  {
    index: '02',
    title: '智能归类',
    description: 'Agent 将新需求词挂靠到稳定的全局内容分类骨架。',
    color: 'cyan',
  },
  {
    index: '03',
    title: '热度计算',
    description: '融合四项先验与 ROV / VOV 后验，形成树级热度。',
    color: 'violet',
  },
  {
    index: '04',
    title: '需求分级',
    description: '按业务价值与供给机会自动评估 S / A / B / C / D。',
    color: 'amber',
  },
  {
    index: '05',
    title: '寻找视频',
    description: '从目的点、关键点、灵感点拓展搜索意图并发现视频。',
    color: 'orange',
  },
  {
    index: '06',
    title: 'AIGC 写入记录',
    description: '以 dry-run 记录准备写入的数据与哈希，不调用真实下游。',
    color: 'green',
  },
]

const featureCards = [
  {
    to: '/demand-map',
    eyebrow: 'INTELLIGENCE MAP',
    title: '平台全局需求地图',
    description: '用矩形树图观察分类热度、优先级与需求分布，快速定位供给机会。',
    meta: '热度树 · 多维评分 · 需求下钻',
    symbol: '⌁',
    tone: 'indigo',
  },
  {
    to: '/demand-tree',
    eyebrow: 'CATEGORY SYSTEM',
    title: '全局分类树',
    description: '逐层展开内容分类骨架，核对节点路径、权重维度及关联需求。',
    meta: '层级浏览 · 自由展开 · HTML 导出',
    symbol: '⌘',
    tone: 'sky',
  },
  {
    to: '/video-discovery',
    eyebrow: 'CONTENT DISCOVERY',
    title: '需求汇总',
    description: '从需求等级进入命中视频，查看目的点、关键点和灵感点证据。',
    meta: '需求筛选 · 视频命中 · 点位追踪',
    symbol: '▷',
    tone: 'orange',
  },
  {
    to: '/demand-process',
    eyebrow: 'AGENT AUDIT',
    title: 'Agent 运行审计',
    description: '追溯模型输入、思考过程、工具调用和结构化运行结果。',
    meta: 'JSONL · HTML 可视化 · OSS 日志',
    symbol: '◎',
    tone: 'green',
  },
]

const agentSystem = [
  {
    step: '01',
    name: '分配 Agent',
    code: 'demand_belong_category_agent',
    subtitle: '语义归属与分类挂载',
    description: '理解需求词的真实语义，在全局内容分类树中逐层判断，找到最可信的归属位置。',
    input: '原始需求词',
    output: '分类节点',
    tone: 'blue',
    principles: ['真实分类树约束', '置信度优先', '语义路径下钻'],
    tools: ['分类树浏览', '归属结果写入'],
  },
  {
    step: '02',
    name: '分等级 Agent',
    code: 'demand_grade_agent',
    subtitle: '证据融合与优先级判断',
    description: '融合来源热度、树级环境与真实效果，为每个需求形成稳定、可解释的 S–D 级判断。',
    input: '分类需求',
    output: 'S / A / B / C / D',
    tone: 'violet',
    principles: ['后验效果优先', '全局与局部校正', '五档优先级决策'],
    tools: [
      '业务日期',
      '相关需求检索',
      '分类与权重',
      '类目路径',
      '局部热度',
      '词级后验',
      '分数分布',
      '分级结果写入',
    ],
  },
  {
    step: '03',
    name: '拓展 Agent',
    code: 'demand_video_expand_agent',
    subtitle: '视频点位与需求拓展',
    description: '从目的点、关键点和灵感点中识别相近意图，将高价值点位转化为可执行供给方向。',
    input: '高优需求 + 视频点位',
    output: '拓展需求',
    tone: 'orange',
    principles: ['目的点优先', '相近意图筛选', '来源视频可追溯'],
    tools: ['拓展结果批量写入'],
  },
]

type AgentSummary = (typeof agentSystem)[number]

const selectedAgentSummary = ref<AgentSummary | null>(null)
const agentDetail = ref<AgentDetail | null>(null)
const agentDetailLoading = ref(false)
const agentDetailError = ref<string | null>(null)
const agentDetailTab = ref<'prompt' | 'injection' | 'tools'>('prompt')
const promptCopied = ref(false)
const injectionDraft = ref('')
const injectionEnabled = ref(true)
const injectionSaving = ref(false)
const injectionSaveMessage = ref('')
const injectionSaveError = ref<string | null>(null)

const latestBizDt = computed(() => {
  const values = [...demands.value.map((item) => item.biz_dt), ...discoveryDemands.value.map((item) => item.biz_dt)]
    .filter(Boolean)
    .sort()
  return values.at(-1) ?? null
})

const gradeSummary = computed(() => {
  const counts: Record<string, number> = { S: 0, A: 0, B: 0, C: 0, D: 0 }
  for (const item of demands.value) {
    const grade = item.grade?.toUpperCase()
    if (grade in counts) counts[grade] += 1
  }
  return counts
})

const videoTotal = computed(() =>
  discoveryDemands.value.reduce((sum, item) => sum + item.video_count, 0),
)

const coveredDemandCount = computed(() =>
  discoveryDemands.value.filter((item) => item.video_count > 0).length,
)

const nextRun = computed(() => scheduler.value?.jobs[0]?.next_run_time ?? null)

const nextRunLabel = computed(() => {
  if (!nextRun.value) return '未计划'
  const date = new Date(nextRun.value)
  if (Number.isNaN(date.getTime())) return nextRun.value
  return new Intl.DateTimeFormat('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date)
})

const displayJobs = computed(() => jobs.value.filter((job) => job.id !== 'run_supply_pipeline'))

const promptLines = computed(() => agentDetail.value?.system_prompt.split('\n') ?? [])
const injectionDirty = computed(() => {
  const saved = agentDetail.value?.document_injection
  if (!saved) return false
  return (
    injectionDraft.value !== saved.content ||
    injectionEnabled.value !== saved.enabled
  )
})

onMounted(() => {
  loadDashboard()
  window.addEventListener('keydown', handleDetailKeydown)
})
onBeforeUnmount(() => {
  window.clearTimeout(pollTimer)
  window.clearTimeout(copiedTimer)
  window.removeEventListener('keydown', handleDetailKeydown)
  document.body.style.overflow = ''
})

async function loadDashboard() {
  const [healthResult, schedulerResult, jobsResult, demandResult, discoveryResult, logsResult] =
    await Promise.allSettled([
      fetchHealth(),
      fetchSchedulerStatus(),
      fetchManualJobs(),
      fetchDemandGrade(),
      fetchVideoDiscoveryDemands(),
      fetchAgentOssLogs(),
    ])

  health.value =
    healthResult.status === 'fulfilled' && healthResult.value.status === 'ok'
      ? 'online'
      : 'offline'
  if (schedulerResult.status === 'fulfilled') scheduler.value = schedulerResult.value
  if (jobsResult.status === 'fulfilled') jobs.value = jobsResult.value.items ?? []
  if (demandResult.status === 'fulfilled') demands.value = demandResult.value.items ?? []
  if (discoveryResult.status === 'fulfilled') {
    discoveryDemands.value = discoveryResult.value.items ?? []
  }
  if (logsResult.status === 'fulfilled') logs.value = logsResult.value.items ?? []
  loading.value = false
}

function todayBizDt(): string {
  const parts = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(new Date())
  const value = Object.fromEntries(parts.map((part) => [part.type, part.value]))
  return `${value.year}${value.month}${value.day}`
}

function readableBizDt(value: string | null): string {
  if (!value || value.length !== 8) return value || '暂无数据'
  return `${value.slice(0, 4)}.${value.slice(4, 6)}.${value.slice(6)}`
}

function readableTime(value: string | null | undefined): string {
  if (!value) return '—'
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return new Intl.DateTimeFormat('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date)
}

function openLog(item: OssLogItem) {
  const url = item.oss_path?.trim()
  if (url) window.open(url, '_blank', 'noopener,noreferrer')
}

async function openAgentDetail(agent: AgentSummary) {
  selectedAgentSummary.value = agent
  agentDetail.value = null
  agentDetailError.value = null
  agentDetailLoading.value = true
  agentDetailTab.value = 'prompt'
  promptCopied.value = false
  injectionDraft.value = ''
  injectionEnabled.value = true
  injectionSaveMessage.value = ''
  injectionSaveError.value = null
  document.body.style.overflow = 'hidden'
  try {
    const detail = await fetchAgentDetail(agent.code)
    agentDetail.value = detail
    injectionDraft.value = detail.document_injection.content
    injectionEnabled.value = detail.document_injection.enabled
  } catch (error) {
    agentDetailError.value = error instanceof Error ? error.message : String(error)
  } finally {
    agentDetailLoading.value = false
  }
}

function closeAgentDetail() {
  selectedAgentSummary.value = null
  agentDetail.value = null
  agentDetailError.value = null
  document.body.style.overflow = ''
}

function handleDetailKeydown(event: KeyboardEvent) {
  if (event.key === 'Escape' && selectedAgentSummary.value) closeAgentDetail()
}

async function copySystemPrompt() {
  const prompt = agentDetail.value?.system_prompt
  if (!prompt) return
  await navigator.clipboard.writeText(prompt)
  promptCopied.value = true
  window.clearTimeout(copiedTimer)
  copiedTimer = window.setTimeout(() => {
    promptCopied.value = false
  }, 1600)
}

async function saveDocumentInjection() {
  if (!selectedAgentSummary.value || injectionSaving.value) return
  injectionSaving.value = true
  injectionSaveMessage.value = ''
  injectionSaveError.value = null
  try {
    const saved = await updateAgentDocumentInjection(
      selectedAgentSummary.value.code,
      {
        content: injectionDraft.value,
        enabled: injectionEnabled.value,
      },
    )
    if (agentDetail.value) agentDetail.value.document_injection = saved
    injectionSaveMessage.value = '文档注入已保存，将在下一次创建 Agent 时生效'
  } catch (error) {
    injectionSaveError.value = error instanceof Error ? error.message : String(error)
  } finally {
    injectionSaving.value = false
  }
}

function formatInjectionTime(value: string | null): string {
  if (!value) return '尚未保存'
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return new Intl.DateTimeFormat('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date)
}

function promptLineType(line: string): 'heading' | 'bullet' | 'step' | 'text' | 'space' {
  if (!line.trim()) return 'space'
  if (line.startsWith('## ')) return 'heading'
  if (/^\s*-\s/.test(line)) return 'bullet'
  if (/^\s*\d+\.\s/.test(line)) return 'step'
  return 'text'
}

function cleanPromptLine(line: string): string {
  return line
    .replace(/^##\s+/, '')
    .replace(/^\s*-\s+/, '')
    .replace(/^\s*\d+\.\s+/, '')
    .replaceAll('**', '')
}

function toolParameters(tool: AgentToolDetail) {
  return Object.entries(tool.parameters?.properties ?? {})
}

async function startJob(job: ManualJob) {
  if (runningJobId.value) return
  runningJobId.value = job.id
  notice.value = ''
  try {
    activeRun.value = await runManualJob(job.id, bizDt.value)
    noticeType.value = 'success'
    notice.value = `${job.name}已开始，运行编号 ${activeRun.value.run_id.slice(0, 8)}`
    pollRun(activeRun.value.run_id)
  } catch (error) {
    noticeType.value = 'error'
    notice.value = error instanceof Error ? error.message : String(error)
    runningJobId.value = null
  }
}

async function startPipeline() {
  const job = jobs.value.find((item) => item.id === 'run_supply_pipeline')
  if (job) await startJob(job)
}

function pollRun(runId: string) {
  window.clearTimeout(pollTimer)
  pollTimer = window.setTimeout(async () => {
    try {
      const run = await fetchManualRun(runId)
      activeRun.value = run
      if (['queued', 'running', 'retry_wait', 'cancelling', 'blocked_previous_run'].includes(run.status)) {
        pollRun(runId)
        return
      }
      runningJobId.value = null
      noticeType.value = run.status === 'succeeded' ? 'success' : 'error'
      const runName = run.job_name || '供给流水线'
      notice.value =
        run.status === 'succeeded'
          ? `${runName}执行完成`
          : `${runName}执行失败：${run.error_message || run.error || '请查看运行中心'}`
      await loadDashboard()
    } catch {
      runningJobId.value = null
    }
  }, 2500)
}
</script>

<template>
  <div class="overview">
    <section class="hero">
      <div class="hero-copy">
        <div class="hero-kicker">
          <span class="signal" :class="health" />
          SUPPLY INTELLIGENCE SYSTEM
          <span class="version">v0.1</span>
        </div>
        <h1>从需求信号到<br /><em>可执行内容供给</em></h1>
        <p>
          SupplyAgent 把分类、热度、分级、视频拓展、内容发现与 AIGC dry-run 记录连接成一条
          可追溯的智能流水线。
        </p>
        <div class="hero-actions">
          <RouterLink class="primary-action" to="/demand-map">
            打开需求地图 <span>↗</span>
          </RouterLink>
          <button
            class="secondary-action"
            type="button"
            :disabled="!jobs.length || Boolean(runningJobId)"
            @click="startPipeline"
          >
            <span v-if="runningJobId === 'run_supply_pipeline'" class="mini-spinner" />
            {{ runningJobId === 'run_supply_pipeline' ? '流水线运行中' : '运行今日流水线' }}
          </button>
        </div>
      </div>

      <div class="hero-visual" aria-label="供给流水线实时概览">
        <div class="orbit orbit-one" />
        <div class="orbit orbit-two" />
        <div class="core">
          <span class="core-ring" />
          <strong>SA</strong>
          <small>AGENT CORE</small>
        </div>
        <div class="float-card card-demand">
          <span class="float-icon indigo">D</span>
          <span><small>今日需求</small><strong>{{ demands.length || '—' }}</strong></span>
        </div>
        <div class="float-card card-grade">
          <span class="float-icon amber">S</span>
          <span><small>高优需求</small><strong>{{ gradeSummary.S + gradeSummary.A || '—' }}</strong></span>
        </div>
        <div class="float-card card-video">
          <span class="float-icon green">V</span>
          <span><small>命中视频</small><strong>{{ videoTotal || '—' }}</strong></span>
        </div>
        <span class="agent-label label-llm">LLM</span>
        <span class="agent-label label-tools">TOOLS</span>
        <span class="agent-label label-skills">SKILLS</span>
      </div>
    </section>

    <section class="metric-grid" aria-label="业务数据概览">
      <article class="metric-card">
        <span class="metric-label">数据业务日</span>
        <strong>{{ readableBizDt(latestBizDt) }}</strong>
        <small>{{ loading ? '正在读取数据' : '最新可用快照' }}</small>
      </article>
      <article class="metric-card">
        <span class="metric-label">需求分级</span>
        <strong>{{ demands.length || '—' }}</strong>
        <small><b class="grade-s">S {{ gradeSummary.S }}</b> · A {{ gradeSummary.A }} · B {{ gradeSummary.B }}</small>
      </article>
      <article class="metric-card">
        <span class="metric-label">视频供给覆盖</span>
        <strong>{{ coveredDemandCount || '—' }}</strong>
        <small>{{ videoTotal }} 个视频证据</small>
      </article>
      <article class="metric-card">
        <span class="metric-label">调度状态</span>
        <strong class="status-value">
          <span class="status-dot" :class="{ active: scheduler?.running }" />
          {{ scheduler?.running ? '运行中' : '未运行' }}
        </strong>
        <small>下次 {{ nextRunLabel }} · {{ scheduler?.timezone || 'Asia/Shanghai' }}</small>
      </article>
    </section>

    <section class="section-block">
      <div class="section-heading">
        <div>
          <span class="section-index">01 / CAPABILITIES</span>
          <h2>一个工作台，覆盖完整供给链路</h2>
        </div>
        <p>每个结果都能回到数据、模型判断和工具调用证据。</p>
      </div>
      <div class="feature-grid">
        <RouterLink
          v-for="feature in featureCards"
          :key="feature.to"
          :to="feature.to"
          class="feature-card"
          :class="feature.tone"
        >
          <div class="feature-top">
            <span class="feature-symbol">{{ feature.symbol }}</span>
            <span class="feature-arrow">↗</span>
          </div>
          <span class="feature-eyebrow">{{ feature.eyebrow }}</span>
          <h3>{{ feature.title }}</h3>
          <p>{{ feature.description }}</p>
          <small>{{ feature.meta }}</small>
        </RouterLink>
      </div>
    </section>

    <section class="section-block agent-system-section">
      <div class="section-heading agent-system-heading">
        <div>
          <span class="section-index">02 / MULTI-AGENT SYSTEM</span>
          <h2>三个 Agent，共同完成一次需求决策</h2>
        </div>
        <p>系统角色、判断原则与工具能力协同工作，让需求从语义信号逐步变成可执行方向。</p>
      </div>

      <div class="agent-system-canvas">
        <div class="system-signal system-signal-one" />
        <div class="system-signal system-signal-two" />
        <div class="system-entry">
          <span>INPUT</span>
          <strong>需求信号</strong>
        </div>

        <div class="agent-chain">
          <article
            v-for="(agent, index) in agentSystem"
            :key="agent.code"
            class="agent-card"
            :class="agent.tone"
          >
            <header class="agent-card-head">
              <div class="agent-identity">
                <span class="agent-index">{{ agent.step }}</span>
                <div>
                  <h3>{{ agent.name }}</h3>
                  <small>{{ agent.subtitle }}</small>
                </div>
              </div>
              <span class="agent-status"><i /> ACTIVE</span>
            </header>

            <div class="agent-core-visual">
              <span class="agent-core-orbit orbit-a" />
              <span class="agent-core-orbit orbit-b" />
              <strong>{{ agent.step }}</strong>
              <small>INTELLIGENCE</small>
            </div>

            <p class="agent-description">{{ agent.description }}</p>

            <div class="system-charter">
              <div class="mini-title">
                <span>SYSTEM</span>
                <small>核心判断原则</small>
              </div>
              <div class="principle-list">
                <span v-for="principle in agent.principles" :key="principle">
                  <i /> {{ principle }}
                </span>
              </div>
            </div>

            <div class="tool-suite">
              <div class="mini-title">
                <span>TOOLS</span>
                <small>{{ agent.tools.length }} 项能力</small>
              </div>
              <div class="tool-cloud">
                <span v-for="tool in agent.tools" :key="tool">{{ tool }}</span>
              </div>
            </div>

            <button class="agent-detail-trigger" type="button" @click="openAgentDetail(agent)">
              <span>
                <small>CONFIGURATION</small>
                查看 Prompt 与工具详情
              </span>
              <b>↗</b>
            </button>

            <footer class="agent-io">
              <span><small>输入</small>{{ agent.input }}</span>
              <i>→</i>
              <span><small>输出</small>{{ agent.output }}</span>
            </footer>

            <span v-if="index < agentSystem.length - 1" class="agent-flow-arrow">
              <i />
              <b>›</b>
            </span>
          </article>
        </div>

        <div class="system-exit">
          <span>OUTPUT</span>
          <strong>可执行供给方向</strong>
        </div>

        <div class="agent-foundation">
          <span class="foundation-label">SHARED FOUNDATION</span>
          <div>
            <span><i class="foundation-dot data" /> 真实业务数据</span>
            <span><i class="foundation-dot reason" /> 可解释判断</span>
            <span><i class="foundation-dot trace" /> 全链路可追溯</span>
          </div>
          <small>OpenRouter LLM · ReAct Loop · Structured Tools</small>
        </div>
      </div>
    </section>

    <section class="section-block pipeline-section">
      <div class="section-heading">
        <div>
          <span class="section-index">03 / PIPELINE</span>
          <h2>每日自动供给流水线</h2>
        </div>
        <div class="pipeline-meta">
          <span class="live-pill"><i /> 每日 15:00 自动执行</span>
          <span>6 个阶段串行推进</span>
        </div>
      </div>
      <div class="pipeline-track">
        <article v-for="(stage, index) in pipeline" :key="stage.index" class="stage">
          <div class="stage-marker" :class="stage.color">
            <span>{{ stage.index }}</span>
          </div>
          <div class="stage-copy">
            <h3>{{ stage.title }}</h3>
            <p>{{ stage.description }}</p>
          </div>
          <span v-if="index < pipeline.length - 1" class="stage-line" />
        </article>
      </div>
    </section>

    <section class="operations-grid">
      <div class="operation-card">
        <div class="card-heading">
          <div>
            <span class="section-index">04 / OPERATIONS</span>
            <h2>任务控制中心</h2>
          </div>
          <label class="date-control">
            <span>业务日</span>
            <input v-model="bizDt" type="text" inputmode="numeric" maxlength="8" aria-label="业务日" />
          </label>
        </div>

        <div v-if="notice" class="notice" :class="noticeType">{{ notice }}</div>

        <div class="job-list">
          <div v-for="job in displayJobs" :key="job.id" class="job-row">
            <span class="job-state" :class="{ active: runningJobId === job.id }" />
            <div class="job-copy">
              <strong>{{ job.name }}</strong>
              <small>{{ job.description }}</small>
            </div>
            <button
              type="button"
              :disabled="Boolean(runningJobId)"
              @click="startJob(job)"
            >
              {{ runningJobId === job.id ? '执行中' : '运行' }}
            </button>
          </div>
          <div v-if="!displayJobs.length" class="empty-row">
            {{ health === 'offline' ? '服务未连接，启动 API 后可控制任务' : '正在加载任务…' }}
          </div>
        </div>
      </div>

      <aside class="audit-card">
        <div class="card-heading">
          <div>
            <span class="section-index">05 / TRACEABILITY</span>
            <h2>最近 Agent 审计</h2>
          </div>
          <RouterLink to="/demand-process">全部日志 ↗</RouterLink>
        </div>
        <div class="audit-list">
          <button
            v-for="item in logs.slice(0, 5)"
            :key="item.id"
            type="button"
            class="audit-item"
            @click="openLog(item)"
          >
            <span class="audit-icon">AI</span>
            <span class="audit-copy">
              <strong>{{ item.log_name || '需求归类运行' }}</strong>
              <small>{{ readableTime(item.create_time) }}</small>
            </span>
            <span class="audit-arrow">›</span>
          </button>
          <div v-if="!logs.length" class="empty-audit">
            <span>◎</span>
            <strong>暂无可展示的运行日志</strong>
            <small>Agent 执行后将在这里显示完整审计记录</small>
          </div>
        </div>
      </aside>
    </section>

    <footer class="overview-footer">
      <span><b>SupplyAgent</b> · AI-native Content Supply Infrastructure</span>
      <span>OpenRouter LLM · Tools · Skills · ReAct · FastAPI</span>
    </footer>

    <Teleport to="body">
      <Transition name="agent-detail">
        <div
          v-if="selectedAgentSummary"
          class="agent-detail-overlay"
          role="dialog"
          aria-modal="true"
          :aria-label="`${selectedAgentSummary.name} 详情`"
          @mousedown.self="closeAgentDetail"
        >
          <section class="agent-detail-modal" :class="selectedAgentSummary.tone">
            <header class="detail-modal-header">
              <div class="detail-agent-identity">
                <span>{{ selectedAgentSummary.step }}</span>
                <div>
                  <small>AGENT CONFIGURATION</small>
                  <h2>{{ selectedAgentSummary.name }}</h2>
                  <code>{{ selectedAgentSummary.code }}</code>
                </div>
              </div>
              <button type="button" aria-label="关闭 Agent 详情" @click="closeAgentDetail">×</button>
            </header>

            <div class="detail-tabs" role="tablist" aria-label="Agent 详情类型">
              <button
                type="button"
                role="tab"
                :aria-selected="agentDetailTab === 'injection'"
                :class="{ active: agentDetailTab === 'injection' }"
                @click="agentDetailTab = 'injection'"
              >
                <span>DOCUMENT INJECTION</span>
                <small>
                  {{ agentDetail?.document_injection.content ? '已配置业务文档' : '添加业务文档' }}
                </small>
              </button>
              <button
                type="button"
                role="tab"
                :aria-selected="agentDetailTab === 'prompt'"
                :class="{ active: agentDetailTab === 'prompt' }"
                @click="agentDetailTab = 'prompt'"
              >
                <span>SYSTEM PROMPT</span>
                <small>完整系统指令</small>
              </button>
              <button
                type="button"
                role="tab"
                :aria-selected="agentDetailTab === 'tools'"
                :class="{ active: agentDetailTab === 'tools' }"
                @click="agentDetailTab = 'tools'"
              >
                <span>TOOLS</span>
                <small>{{ agentDetail?.tools.length ?? selectedAgentSummary.tools.length }} 个注册工具</small>
              </button>
            </div>

            <div v-if="agentDetailLoading" class="detail-state">
              <span class="detail-loader" />
              正在读取当前 Agent 配置…
            </div>

            <div v-else-if="agentDetailError" class="detail-state detail-error">
              <strong>详情加载失败</strong>
              <span>{{ agentDetailError }}</span>
              <button type="button" @click="openAgentDetail(selectedAgentSummary)">重新加载</button>
            </div>

            <div v-else-if="agentDetail" class="detail-content">
              <section v-show="agentDetailTab === 'prompt'" class="prompt-panel">
                <div class="detail-content-head">
                  <div>
                    <span>LIVE SYSTEM PROMPT</span>
                    <small>内容直接读取自当前 Agent 配置文件</small>
                  </div>
                  <button type="button" @click="copySystemPrompt">
                    {{ promptCopied ? '已复制 ✓' : '复制 Prompt' }}
                  </button>
                </div>

                <button
                  v-if="agentDetail.document_injection.content"
                  type="button"
                  class="prompt-injection-notice"
                  @click="agentDetailTab = 'injection'"
                >
                  <span :class="{ disabled: !agentDetail.document_injection.enabled }">
                    <i />
                    文档注入{{ agentDetail.document_injection.enabled ? '已启用' : '已停用' }}
                  </span>
                  <small>
                    {{ agentDetail.document_injection.content.length }} 字符 · 查看注入内容
                  </small>
                  <b>›</b>
                </button>

                <div class="prompt-document">
                  <template v-for="(line, index) in promptLines" :key="`${index}-${line}`">
                    <h3 v-if="promptLineType(line) === 'heading'">
                      <span>{{ String(index + 1).padStart(2, '0') }}</span>
                      {{ cleanPromptLine(line) }}
                    </h3>
                    <p v-else-if="promptLineType(line) === 'bullet'" class="prompt-bullet">
                      <i /> {{ cleanPromptLine(line) }}
                    </p>
                    <p v-else-if="promptLineType(line) === 'step'" class="prompt-step">
                      <b>{{ line.trim().match(/^\d+/)?.[0] }}</b>
                      {{ cleanPromptLine(line) }}
                    </p>
                    <p v-else-if="promptLineType(line) === 'text'" class="prompt-text">
                      {{ cleanPromptLine(line) }}
                    </p>
                    <div v-else class="prompt-space" />
                  </template>
                </div>
              </section>

              <section v-show="agentDetailTab === 'injection'" class="injection-panel">
                <div class="detail-content-head injection-content-head">
                  <div>
                    <span>WEB-MANAGED DOCUMENT</span>
                    <small>独立追加到基础 System Prompt，不修改原始 Prompt 文件</small>
                  </div>
                  <label class="injection-toggle">
                    <input v-model="injectionEnabled" type="checkbox" />
                    <span><i /></span>
                    {{ injectionEnabled ? '注入已启用' : '注入已停用' }}
                  </label>
                </div>

                <div class="injection-workspace">
                  <section class="injection-editor-card">
                    <header>
                      <div>
                        <span>编辑注入文档</span>
                        <small>适合补充业务知识、判断口径、术语说明和临时规则</small>
                      </div>
                      <code>MARKDOWN</code>
                    </header>
                    <textarea
                      v-model="injectionDraft"
                      maxlength="100000"
                      spellcheck="false"
                      placeholder="在这里输入需要追加给 Agent 的业务文档…&#10;&#10;例如：&#10;## 本周业务重点&#10;- 优先关注适老化内容&#10;- 对节日相关需求提高时效性判断"
                      aria-label="Agent 文档注入内容"
                    />
                    <footer>
                      <span>
                        {{ injectionDraft.length.toLocaleString() }} / 100,000 字符
                        · 更新于 {{ formatInjectionTime(agentDetail.document_injection.updated_at) }}
                      </span>
                      <button
                        type="button"
                        :disabled="injectionSaving || !injectionDirty"
                        @click="saveDocumentInjection"
                      >
                        <span v-if="injectionSaving" class="save-spinner" />
                        {{ injectionSaving ? '保存中' : injectionDirty ? '保存并应用' : '已保存' }}
                      </button>
                    </footer>
                  </section>

                  <aside class="injection-preview-card">
                    <header>
                      <div>
                        <span>实际注入预览</span>
                        <small>新建 Agent 时将追加到 System Prompt 末尾</small>
                      </div>
                      <span class="injection-state" :class="{ off: !injectionEnabled }">
                        <i /> {{ injectionEnabled ? 'ACTIVE' : 'PAUSED' }}
                      </span>
                    </header>
                    <div class="injection-preview-body" :class="{ empty: !injectionDraft.trim() }">
                      <template v-if="injectionDraft.trim()">
                        <span class="injection-heading">## Web 文档注入</span>
                        <p class="injection-preface">
                          以下内容由运营人员通过 SupplyAgent Web 工作台维护，用于补充业务知识与判断背景。
                        </p>
                        <pre>{{ injectionDraft }}</pre>
                      </template>
                      <template v-else>
                        <span class="empty-injection-icon">＋</span>
                        <strong>尚未添加注入文档</strong>
                        <small>左侧输入内容后，这里会实时展示实际注入效果</small>
                      </template>
                    </div>
                  </aside>
                </div>

                <div v-if="injectionSaveMessage || injectionSaveError" class="injection-message" :class="{ error: injectionSaveError }">
                  <i />
                  {{ injectionSaveError || injectionSaveMessage }}
                </div>
              </section>

              <section v-show="agentDetailTab === 'tools'" class="tools-panel">
                <div class="detail-content-head">
                  <div>
                    <span>REGISTERED TOOLSET</span>
                    <small>Agent 当前可调用的全部结构化工具</small>
                  </div>
                  <strong>{{ agentDetail.tools.length }} TOOLS</strong>
                </div>

                <div class="detail-tool-list">
                  <article
                    v-for="(tool, index) in agentDetail.tools"
                    :key="tool.name"
                    class="detail-tool-card"
                  >
                    <div class="detail-tool-index">{{ String(index + 1).padStart(2, '0') }}</div>
                    <div class="detail-tool-main">
                      <div class="detail-tool-title">
                        <code>{{ tool.name }}</code>
                        <span>FUNCTION</span>
                      </div>
                      <p>{{ tool.description || '暂无工具说明' }}</p>
                      <div v-if="toolParameters(tool).length" class="parameter-list">
                        <span
                          v-for="[name, schema] in toolParameters(tool)"
                          :key="name"
                          :class="{ required: tool.parameters.required?.includes(name) }"
                        >
                          {{ name }}
                          <small>{{ schema.type || 'string' }}</small>
                        </span>
                      </div>
                    </div>
                  </article>
                </div>
              </section>
            </div>
          </section>
        </div>
      </Transition>
    </Teleport>
  </div>
</template>

<style scoped>
.overview {
  --ink: #172033;
  --muted: #6c7484;
  --line: #e7e9ef;
  display: flex;
  flex-direction: column;
  gap: 26px;
  max-width: 1480px;
  margin: 0 auto;
  padding: 0 4px 30px;
  color: var(--ink);
}

.hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(420px, 0.94fr);
  min-height: 430px;
  overflow: hidden;
  border: 1px solid #e2e5ee;
  border-radius: 26px;
  background:
    linear-gradient(120deg, rgba(255, 255, 255, 0.98) 0 53%, rgba(246, 247, 252, 0.96) 53%),
    #fff;
  box-shadow: 0 20px 60px rgba(28, 35, 55, 0.07);
}

.hero::before {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(83, 96, 128, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(83, 96, 128, 0.045) 1px, transparent 1px);
  background-size: 36px 36px;
  mask-image: linear-gradient(to right, transparent 46%, black);
  content: '';
  pointer-events: none;
}

.hero-copy {
  position: relative;
  z-index: 1;
  align-self: center;
  padding: 58px 6vw 58px 58px;
}

.hero-kicker,
.section-index {
  color: #636b7f;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.18em;
}

.hero-kicker {
  display: flex;
  align-items: center;
  gap: 9px;
}

.signal {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #aab1bf;
  box-shadow: 0 0 0 4px rgba(170, 177, 191, 0.16);
}

.signal.online {
  background: #18a879;
  box-shadow: 0 0 0 4px rgba(24, 168, 121, 0.14);
}

.signal.offline {
  background: #e0605c;
  box-shadow: 0 0 0 4px rgba(224, 96, 92, 0.14);
}

.version {
  margin-left: 4px;
  padding: 3px 7px;
  border-radius: 999px;
  background: #eef0f6;
  color: #747c8d;
  font-size: 9px;
  letter-spacing: 0.08em;
}

.hero h1 {
  margin: 22px 0 18px;
  font-size: clamp(42px, 4.2vw, 66px);
  line-height: 1.05;
  letter-spacing: -0.055em;
}

.hero h1 em {
  color: #5b5bd6;
  font-family: 'STKaiti', 'Kaiti SC', serif;
  font-style: normal;
  font-weight: 500;
}

.hero-copy > p {
  max-width: 590px;
  margin: 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.85;
}

.hero-actions {
  display: flex;
  gap: 12px;
  margin-top: 30px;
}

.primary-action,
.secondary-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 46px;
  padding: 0 20px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  transition: transform 0.2s, box-shadow 0.2s, background 0.2s;
}

.primary-action {
  background: #1e2638;
  color: #fff;
  box-shadow: 0 10px 24px rgba(30, 38, 56, 0.18);
}

.secondary-action {
  border: 1px solid #d9dce4;
  background: #fff;
  color: #2d3445;
  cursor: pointer;
}

.primary-action:hover,
.secondary-action:not(:disabled):hover {
  transform: translateY(-2px);
}

.secondary-action:disabled {
  cursor: not-allowed;
  opacity: 0.58;
}

.hero-visual {
  position: relative;
  min-height: 430px;
}

.orbit {
  position: absolute;
  top: 50%;
  left: 50%;
  border: 1px dashed rgba(90, 91, 214, 0.24);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.orbit-one {
  width: 320px;
  height: 320px;
}

.orbit-two {
  width: 440px;
  height: 440px;
  border-color: rgba(90, 91, 214, 0.1);
}

.core {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  width: 146px;
  height: 146px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  border: 1px solid rgba(91, 91, 214, 0.2);
  border-radius: 42%;
  background: linear-gradient(145deg, #fff, #f0efff);
  box-shadow: 0 30px 70px rgba(91, 91, 214, 0.24);
  transform: translate(-50%, -50%) rotate(8deg);
}

.core::after {
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(91, 91, 214, 0.13);
  border-radius: 38%;
  content: '';
}

.core strong,
.core small {
  position: relative;
  z-index: 1;
  transform: rotate(-8deg);
}

.core strong {
  color: #5555d3;
  font-size: 46px;
  letter-spacing: -0.08em;
}

.core small {
  color: #8d91a6;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.17em;
}

.core-ring {
  position: absolute;
  width: 14px;
  height: 14px;
  top: -7px;
  right: 30px;
  border: 3px solid #fff;
  border-radius: 50%;
  background: #23b786;
}

.float-card {
  position: absolute;
  display: flex;
  min-width: 142px;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border: 1px solid rgba(221, 224, 233, 0.9);
  border-radius: 13px;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 15px 38px rgba(44, 50, 72, 0.1);
  backdrop-filter: blur(10px);
}

.float-card small,
.float-card strong {
  display: block;
}

.float-card small {
  color: #9399a8;
  font-size: 10px;
}

.float-card strong {
  margin-top: 1px;
  font-size: 20px;
}

.float-icon {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  border-radius: 9px;
  font-size: 12px;
  font-weight: 800;
}

.float-icon.indigo { background: #ececff; color: #5b5bd6; }
.float-icon.amber { background: #fff0d9; color: #c47718; }
.float-icon.green { background: #e2f7ef; color: #168762; }
.card-demand { top: 54px; left: 6%; }
.card-grade { top: 72px; right: 6%; }
.card-video { right: 5%; bottom: 48px; }

.agent-label {
  position: absolute;
  color: #858ca0;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.15em;
}

.label-llm { left: 16%; bottom: 80px; }
.label-tools { right: 18%; top: 46%; }
.label-skills { left: 32%; top: 20%; }

.metric-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.metric-card {
  min-height: 128px;
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 8px 30px rgba(38, 45, 66, 0.035);
}

.metric-card > span,
.metric-card > strong,
.metric-card > small {
  display: block;
}

.metric-label {
  margin-bottom: 8px;
  color: #878e9d;
  font-size: 11px;
}

.metric-card > strong {
  font-size: 27px;
  letter-spacing: -0.04em;
}

.metric-card > small {
  margin-top: 9px;
  color: #949aa7;
  font-size: 10px;
}

.metric-card small b {
  font-weight: 700;
}

.grade-s { color: #cb5b48; }
.status-value { display: flex !important; align-items: center; gap: 9px; }
.status-dot { width: 9px; height: 9px; border-radius: 50%; background: #c5cad3; }
.status-dot.active { background: #18a879; box-shadow: 0 0 0 5px rgba(24, 168, 121, 0.1); }

.section-block,
.operation-card,
.audit-card {
  padding: 28px;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.92);
}

.section-heading,
.card-heading {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}

.section-heading h2,
.card-heading h2 {
  margin: 6px 0 0;
  font-size: 24px;
  letter-spacing: -0.035em;
}

.section-heading > p,
.pipeline-meta {
  max-width: 420px;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-top: 24px;
}

.feature-card {
  position: relative;
  min-height: 260px;
  overflow: hidden;
  padding: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 16px;
  background: #fbfbfd;
  color: var(--ink);
  text-decoration: none;
  transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
}

.feature-card::after {
  position: absolute;
  right: -50px;
  bottom: -70px;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  background: var(--accent-soft);
  content: '';
  filter: blur(5px);
}

.feature-card:hover {
  transform: translateY(-4px);
  border-color: var(--accent);
  box-shadow: 0 18px 40px rgba(31, 39, 58, 0.08);
}

.feature-card.indigo { --accent: #6868d9; --accent-soft: #e8e8ff; }
.feature-card.sky { --accent: #3f91c8; --accent-soft: #ddf3ff; }
.feature-card.orange { --accent: #d17835; --accent-soft: #ffead7; }
.feature-card.green { --accent: #299575; --accent-soft: #dff5ed; }

.feature-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.feature-symbol {
  display: grid;
  width: 43px;
  height: 43px;
  place-items: center;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 22px;
  font-weight: 800;
}

.feature-arrow {
  color: #a2a8b4;
  font-size: 18px;
}

.feature-eyebrow {
  display: block;
  margin-top: 26px;
  color: var(--accent);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.15em;
}

.feature-card h3 {
  margin: 7px 0 10px;
  font-size: 18px;
}

.feature-card p {
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.75;
}

.feature-card > small {
  position: absolute;
  z-index: 1;
  bottom: 19px;
  left: 20px;
  color: #9298a6;
  font-size: 9px;
}

.agent-system-section {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(circle at 10% 0%, rgba(96, 102, 214, 0.09), transparent 28%),
    radial-gradient(circle at 95% 100%, rgba(213, 116, 64, 0.08), transparent 30%),
    #fbfbfd;
}

.agent-system-section::before {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(92, 99, 128, 0.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(92, 99, 128, 0.035) 1px, transparent 1px);
  background-size: 32px 32px;
  content: '';
  mask-image: linear-gradient(to bottom, black, transparent 58%);
  pointer-events: none;
}

.agent-system-heading {
  position: relative;
  z-index: 1;
}

.agent-system-canvas {
  position: relative;
  z-index: 1;
  overflow: hidden;
  margin-top: 26px;
  padding: 72px 20px 20px;
  border: 1px solid #dfe2e9;
  border-radius: 19px;
  background:
    linear-gradient(145deg, rgba(255, 255, 255, 0.82), rgba(241, 243, 249, 0.9)),
    #f4f5f9;
}

.system-signal {
  position: absolute;
  border: 1px solid rgba(98, 103, 205, 0.1);
  border-radius: 50%;
  pointer-events: none;
}

.system-signal-one {
  top: -180px;
  left: 32%;
  width: 460px;
  height: 460px;
}

.system-signal-two {
  right: -120px;
  bottom: -200px;
  width: 400px;
  height: 400px;
}

.system-entry,
.system-exit {
  position: absolute;
  top: 19px;
  display: flex;
  align-items: center;
  gap: 9px;
  color: #687082;
}

.system-entry {
  left: 23px;
}

.system-exit {
  right: 23px;
}

.system-entry span,
.system-exit span {
  padding: 4px 7px;
  border-radius: 5px;
  background: #e8eaf2;
  color: #7e8597;
  font-size: 7px;
  font-weight: 900;
  letter-spacing: 0.14em;
}

.system-entry strong,
.system-exit strong {
  font-size: 10px;
}

.agent-chain {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px;
}

.agent-card {
  --agent: #5377c9;
  --agent-soft: #eaf1ff;
  position: relative;
  display: flex;
  min-width: 0;
  min-height: 570px;
  padding: 20px;
  flex-direction: column;
  overflow: visible;
  border: 1px solid rgba(220, 224, 234, 0.96);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.94);
  box-shadow:
    0 20px 45px rgba(35, 42, 64, 0.065),
    inset 0 1px 0 #fff;
}

.agent-card::before {
  position: absolute;
  top: 0;
  right: 18px;
  left: 18px;
  height: 3px;
  border-radius: 0 0 6px 6px;
  background: linear-gradient(90deg, transparent, var(--agent), transparent);
  content: '';
}

.agent-card.blue {
  --agent: #4f78ce;
  --agent-soft: #eaf1ff;
}

.agent-card.violet {
  --agent: #7060cb;
  --agent-soft: #efecff;
}

.agent-card.orange {
  --agent: #cc7540;
  --agent-soft: #fff0e5;
}

.agent-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.agent-identity {
  display: flex;
  align-items: center;
  gap: 11px;
}

.agent-index {
  display: grid;
  width: 37px;
  height: 37px;
  flex-shrink: 0;
  place-items: center;
  border-radius: 10px;
  background: var(--agent-soft);
  color: var(--agent);
  font-size: 10px;
  font-weight: 900;
}

.agent-identity h3 {
  margin: 0;
  font-size: 15px;
  letter-spacing: -0.02em;
}

.agent-identity small {
  display: block;
  margin-top: 3px;
  color: #949aa8;
  font-size: 8px;
}

.agent-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  color: #9096a3;
  font-size: 7px;
  font-weight: 900;
  letter-spacing: 0.1em;
}

.agent-status i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #25ac7e;
  box-shadow: 0 0 0 3px rgba(37, 172, 126, 0.1);
}

.agent-core-visual {
  position: relative;
  display: flex;
  height: 126px;
  align-items: center;
  justify-content: center;
  margin: 18px 0 16px;
  flex-direction: column;
  overflow: hidden;
  border-radius: 13px;
  background:
    radial-gradient(circle at 50% 55%, var(--agent-soft), transparent 42%),
    linear-gradient(135deg, #fafbfe, #f4f5f9);
}

.agent-core-visual::before,
.agent-core-visual::after {
  position: absolute;
  border-radius: 50%;
  content: '';
}

.agent-core-visual::before {
  width: 72px;
  height: 72px;
  border: 1px solid var(--agent);
  opacity: 0.2;
}

.agent-core-visual::after {
  width: 48px;
  height: 48px;
  background: linear-gradient(145deg, #fff, var(--agent-soft));
  box-shadow: 0 10px 28px rgba(52, 59, 83, 0.11);
}

.agent-core-orbit {
  position: absolute;
  border: 1px dashed var(--agent);
  border-radius: 50%;
  opacity: 0.14;
}

.agent-core-orbit.orbit-a {
  width: 100px;
  height: 100px;
}

.agent-core-orbit.orbit-b {
  width: 150px;
  height: 58px;
  transform: rotate(-12deg);
}

.agent-core-visual strong,
.agent-core-visual small {
  position: relative;
  z-index: 1;
}

.agent-core-visual strong {
  color: var(--agent);
  font-size: 18px;
}

.agent-core-visual small {
  margin-top: 4px;
  color: #969dab;
  font-size: 5px;
  font-weight: 900;
  letter-spacing: 0.13em;
}

.agent-description {
  min-height: 56px;
  margin: 0 0 17px;
  color: #697183;
  font-size: 10px;
  line-height: 1.75;
}

.system-charter,
.tool-suite {
  padding-top: 14px;
  border-top: 1px solid #eceef3;
}

.tool-suite {
  margin-top: 15px;
}

.mini-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.mini-title > span {
  color: var(--agent);
  font-size: 7px;
  font-weight: 900;
  letter-spacing: 0.16em;
}

.mini-title > small {
  color: #a0a6b2;
  font-size: 7px;
}

.principle-list {
  display: flex;
  margin-top: 10px;
  gap: 7px;
  flex-direction: column;
}

.principle-list span {
  display: flex;
  align-items: center;
  gap: 7px;
  color: #555e70;
  font-size: 9px;
}

.principle-list i {
  width: 5px;
  height: 5px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--agent);
  box-shadow: 0 0 0 3px var(--agent-soft);
}

.tool-cloud {
  display: flex;
  align-content: flex-start;
  gap: 6px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.tool-cloud span {
  display: inline-flex;
  min-height: 23px;
  align-items: center;
  padding: 0 8px;
  border: 1px solid #e5e7ed;
  border-radius: 6px;
  background: #fafafd;
  color: #747c8d;
  font-size: 7px;
  white-space: nowrap;
}

.tool-cloud span::before {
  width: 3px;
  height: 3px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--agent);
  content: '';
  opacity: 0.75;
}

.agent-detail-trigger {
  display: flex;
  width: 100%;
  min-height: 43px;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 15px;
  padding: 7px 11px;
  border: 1px solid var(--agent-soft);
  border-radius: 9px;
  background: linear-gradient(90deg, var(--agent-soft), #fafafd);
  color: var(--agent);
  text-align: left;
  cursor: pointer;
  transition: transform 0.16s, border-color 0.16s, box-shadow 0.16s;
}

.agent-detail-trigger:hover {
  border-color: var(--agent);
  box-shadow: 0 8px 20px rgba(43, 51, 73, 0.07);
  transform: translateY(-1px);
}

.agent-detail-trigger span {
  font-size: 8px;
  font-weight: 800;
}

.agent-detail-trigger small {
  display: block;
  margin-bottom: 2px;
  color: #9ca2ae;
  font-size: 5px;
  font-weight: 900;
  letter-spacing: 0.14em;
}

.agent-detail-trigger b {
  font-size: 14px;
  font-weight: 500;
}

.agent-io {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 7px;
  margin-top: auto;
  padding-top: 17px;
}

.agent-io > span {
  display: flex;
  min-width: 0;
  min-height: 42px;
  align-items: flex-start;
  justify-content: center;
  padding: 8px;
  flex-direction: column;
  border-radius: 8px;
  background: #f5f6f9;
  color: #50596b;
  font-size: 8px;
  font-weight: 700;
}

.agent-io small {
  display: block;
  margin-bottom: 3px;
  color: #a0a6b2;
  font-size: 6px;
  font-weight: 800;
}

.agent-io > i {
  color: var(--agent);
  font-size: 12px;
  font-style: normal;
}

.agent-flow-arrow {
  position: absolute;
  z-index: 3;
  top: 49%;
  right: -29px;
  display: flex;
  width: 28px;
  align-items: center;
}

.agent-flow-arrow i {
  width: 20px;
  height: 1px;
  background: linear-gradient(90deg, var(--agent), #bbc0ca);
  opacity: 0.6;
}

.agent-flow-arrow b {
  color: #8a91a0;
  font-size: 16px;
  font-weight: 400;
}

.agent-foundation {
  position: relative;
  z-index: 1;
  display: grid;
  min-height: 56px;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 24px;
  margin-top: 18px;
  padding: 0 17px;
  border-radius: 11px;
  background: #242b3b;
  color: #fff;
}

.foundation-label {
  color: #9ca5b8;
  font-size: 7px;
  font-weight: 900;
  letter-spacing: 0.14em;
}

.agent-foundation > div {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 22px;
}

.agent-foundation > div span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: #d8dce5;
  font-size: 8px;
}

.foundation-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.foundation-dot.data { background: #5781dd; }
.foundation-dot.reason { background: #7d69d8; }
.foundation-dot.trace { background: #38ad83; }

.agent-foundation > small {
  color: #838c9f;
  font-size: 7px;
  letter-spacing: 0.04em;
}

.agent-detail-overlay {
  position: fixed;
  z-index: 100;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 28px;
  background: rgba(20, 25, 38, 0.62);
  backdrop-filter: blur(10px);
}

.agent-detail-modal {
  --detail-agent: #4f78ce;
  --detail-soft: #eaf1ff;
  display: flex;
  width: min(1080px, 100%);
  height: min(820px, calc(100vh - 56px));
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 22px;
  background: #f7f8fb;
  box-shadow: 0 40px 100px rgba(15, 20, 34, 0.34);
}

.agent-detail-modal.blue {
  --detail-agent: #4f78ce;
  --detail-soft: #eaf1ff;
}

.agent-detail-modal.violet {
  --detail-agent: #7060cb;
  --detail-soft: #efecff;
}

.agent-detail-modal.orange {
  --detail-agent: #cc7540;
  --detail-soft: #fff0e5;
}

.detail-modal-header {
  position: relative;
  display: flex;
  min-height: 104px;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  overflow: hidden;
  border-bottom: 1px solid #e3e6ed;
  background:
    radial-gradient(circle at 20% -50%, var(--detail-soft), transparent 48%),
    #fff;
}

.detail-modal-header::after {
  position: absolute;
  right: 90px;
  width: 260px;
  height: 260px;
  border: 1px solid var(--detail-agent);
  border-radius: 50%;
  content: '';
  opacity: 0.08;
}

.detail-agent-identity {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 16px;
}

.detail-agent-identity > span {
  display: grid;
  width: 54px;
  height: 54px;
  place-items: center;
  border: 1px solid var(--detail-agent);
  border-radius: 15px;
  background: var(--detail-soft);
  color: var(--detail-agent);
  font-size: 16px;
  font-weight: 900;
  box-shadow: 0 10px 25px rgba(41, 48, 68, 0.08);
}

.detail-agent-identity small {
  color: var(--detail-agent);
  font-size: 7px;
  font-weight: 900;
  letter-spacing: 0.15em;
}

.detail-agent-identity h2 {
  margin: 4px 0 3px;
  color: #242b3b;
  font-size: 21px;
  letter-spacing: -0.035em;
}

.detail-agent-identity code {
  color: #9299a8;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 8px;
}

.detail-modal-header > button {
  position: relative;
  z-index: 2;
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  padding: 0 0 3px;
  border: 1px solid #e0e3e9;
  border-radius: 10px;
  background: #fff;
  color: #828998;
  font-size: 22px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, transform 0.15s;
}

.detail-modal-header > button:hover {
  border-color: var(--detail-agent);
  color: var(--detail-agent);
  transform: rotate(4deg);
}

.detail-tabs {
  display: grid;
  min-height: 67px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding: 0 28px;
  border-bottom: 1px solid #e2e5ec;
  background: #fff;
}

.detail-tabs button {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 17px 0 0;
  flex-direction: column;
  border: 0;
  background: transparent;
  color: #969dab;
  cursor: pointer;
}

.detail-tabs button::after {
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  border-radius: 3px 3px 0 0;
  background: transparent;
  content: '';
}

.detail-tabs button.active {
  color: var(--detail-agent);
}

.detail-tabs button.active::after {
  background: var(--detail-agent);
}

.detail-tabs span {
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 0.12em;
}

.detail-tabs small {
  margin-top: 4px;
  color: #a5abb6;
  font-size: 8px;
}

.detail-content {
  min-height: 0;
  flex: 1;
  overflow: hidden;
}

.prompt-panel,
.injection-panel,
.tools-panel {
  display: flex;
  height: 100%;
  min-height: 0;
  flex-direction: column;
}

.injection-panel {
  position: relative;
}

.prompt-injection-notice {
  display: grid;
  min-height: 44px;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 13px;
  margin: 13px 28px 0;
  padding: 0 13px;
  border: 1px solid #e0e2ef;
  border-radius: 9px;
  background: linear-gradient(90deg, var(--detail-soft), #fafafd);
  color: #596173;
  text-align: left;
  cursor: pointer;
}

.prompt-injection-notice > span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--detail-agent);
  font-size: 8px;
  font-weight: 800;
}

.prompt-injection-notice > span.disabled {
  color: #959ba7;
}

.prompt-injection-notice > span i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px rgba(92, 99, 128, 0.08);
}

.prompt-injection-notice > small {
  color: #8e95a4;
  font-size: 8px;
}

.prompt-injection-notice > b {
  color: var(--detail-agent);
  font-size: 15px;
}

.detail-content-head {
  display: flex;
  min-height: 61px;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  flex-shrink: 0;
  border-bottom: 1px solid #e4e7ed;
  background: #f9fafe;
}

.detail-content-head > div > span {
  display: block;
  color: #5f6676;
  font-size: 8px;
  font-weight: 900;
  letter-spacing: 0.13em;
}

.detail-content-head > div > small {
  display: block;
  margin-top: 4px;
  color: #a1a7b3;
  font-size: 8px;
}

.detail-content-head > button {
  padding: 8px 12px;
  border: 1px solid #dce0e8;
  border-radius: 8px;
  background: #fff;
  color: #6e7585;
  font-size: 8px;
  font-weight: 800;
  cursor: pointer;
}

.detail-content-head > button:hover {
  border-color: var(--detail-agent);
  color: var(--detail-agent);
}

.detail-content-head > strong {
  color: var(--detail-agent);
  font-size: 9px;
  letter-spacing: 0.08em;
}

.injection-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: #6d7585;
  font-size: 8px;
  font-weight: 700;
  cursor: pointer;
}

.injection-toggle input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.injection-toggle > span {
  position: relative;
  width: 34px;
  height: 19px;
  border-radius: 999px;
  background: #c9ced8;
  transition: background 0.18s;
}

.injection-toggle > span i {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 5px rgba(24, 30, 44, 0.18);
  transition: transform 0.18s;
}

.injection-toggle input:checked + span {
  background: var(--detail-agent);
}

.injection-toggle input:checked + span i {
  transform: translateX(15px);
}

.injection-workspace {
  display: grid;
  min-height: 0;
  grid-template-columns: minmax(0, 1.08fr) minmax(330px, 0.92fr);
  gap: 14px;
  flex: 1;
  padding: 16px 20px 20px;
  overflow: hidden;
}

.injection-editor-card,
.injection-preview-card {
  display: flex;
  min-height: 0;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid #e0e3ea;
  border-radius: 13px;
  background: #fff;
  box-shadow: 0 10px 28px rgba(36, 43, 62, 0.035);
}

.injection-editor-card > header,
.injection-preview-card > header {
  display: flex;
  min-height: 61px;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 0 16px;
  flex-shrink: 0;
  border-bottom: 1px solid #e8eaf0;
  background: #fbfbfd;
}

.injection-editor-card header span,
.injection-preview-card header span {
  display: block;
  color: #4b5364;
  font-size: 10px;
  font-weight: 800;
}

.injection-editor-card header small,
.injection-preview-card header small {
  display: block;
  margin-top: 4px;
  color: #9ca2ae;
  font-size: 7px;
}

.injection-editor-card header code {
  padding: 5px 7px;
  border-radius: 5px;
  background: var(--detail-soft);
  color: var(--detail-agent);
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 6px;
  font-weight: 900;
  letter-spacing: 0.1em;
}

.injection-editor-card textarea {
  min-height: 0;
  flex: 1;
  resize: none;
  padding: 17px;
  border: 0;
  outline: none;
  background:
    linear-gradient(rgba(104, 111, 139, 0.035) 1px, transparent 1px),
    #fff;
  background-size: 100% 26px;
  color: #465064;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'PingFang SC', monospace;
  font-size: 10px;
  line-height: 26px;
}

.injection-editor-card textarea::placeholder {
  color: #afb4be;
}

.injection-editor-card > footer {
  display: flex;
  min-height: 57px;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 14px;
  flex-shrink: 0;
  border-top: 1px solid #e8eaf0;
  background: #fbfbfd;
}

.injection-editor-card > footer > span {
  color: #999fac;
  font-size: 7px;
}

.injection-editor-card > footer button {
  display: inline-flex;
  min-width: 88px;
  height: 32px;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 0 12px;
  border: 1px solid var(--detail-agent);
  border-radius: 7px;
  background: var(--detail-agent);
  color: #fff;
  font-size: 8px;
  font-weight: 800;
  cursor: pointer;
}

.injection-editor-card > footer button:disabled {
  border-color: #d8dce4;
  background: #eef0f4;
  color: #9aa1ae;
  cursor: default;
}

.save-spinner {
  width: 11px;
  height: 11px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.75s linear infinite;
}

.injection-state {
  display: inline-flex !important;
  align-items: center;
  gap: 6px;
  color: #23946e !important;
  font-size: 6px !important;
  letter-spacing: 0.1em;
}

.injection-state.off {
  color: #999fac !important;
}

.injection-state i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px rgba(35, 148, 110, 0.1);
}

.injection-preview-body {
  min-height: 0;
  flex: 1;
  overflow: auto;
  padding: 19px;
  background:
    radial-gradient(circle at 100% 0%, var(--detail-soft), transparent 38%),
    #fff;
}

.injection-preview-body.empty {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  text-align: center;
}

.injection-heading {
  display: block;
  color: var(--detail-agent);
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 10px;
  font-weight: 800;
}

.injection-preface {
  margin: 10px 0 16px;
  padding: 10px 12px;
  border-left: 2px solid var(--detail-agent);
  background: var(--detail-soft);
  color: #70788a;
  font-size: 8px;
  line-height: 1.65;
}

.injection-preview-body pre {
  margin: 0;
  color: #515b6e;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'PingFang SC', monospace;
  font-size: 9px;
  line-height: 1.75;
  white-space: pre-wrap;
  word-break: break-word;
}

.empty-injection-icon {
  display: grid;
  width: 42px;
  height: 42px;
  place-items: center;
  border-radius: 12px;
  background: var(--detail-soft);
  color: var(--detail-agent);
  font-size: 20px;
}

.injection-preview-body.empty strong {
  margin-top: 12px;
  color: #687082;
  font-size: 10px;
}

.injection-preview-body.empty small {
  max-width: 230px;
  margin-top: 5px;
  color: #a0a6b2;
  font-size: 7px;
  line-height: 1.6;
}

.injection-message {
  position: absolute;
  right: 30px;
  bottom: 25px;
  display: flex;
  min-height: 35px;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  border: 1px solid #bfe3d5;
  border-radius: 8px;
  background: #effaf6;
  color: #277a61;
  font-size: 8px;
  box-shadow: 0 9px 24px rgba(29, 68, 55, 0.1);
}

.injection-message.error {
  border-color: #efcbc8;
  background: #fff4f3;
  color: #aa514c;
}

.injection-message i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.prompt-document {
  min-height: 0;
  flex: 1;
  overflow: auto;
  padding: 26px 30px 50px;
  background:
    linear-gradient(90deg, transparent 59px, rgba(104, 111, 139, 0.07) 60px, transparent 61px),
    #fff;
}

.prompt-document h3 {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 30px 0 14px;
  color: #273044;
  font-size: 15px;
  letter-spacing: -0.02em;
}

.prompt-document h3:first-child {
  margin-top: 0;
}

.prompt-document h3 > span {
  display: grid;
  width: 31px;
  height: 24px;
  flex-shrink: 0;
  place-items: center;
  border-radius: 6px;
  background: var(--detail-soft);
  color: var(--detail-agent);
  font-size: 7px;
  font-weight: 900;
}

.prompt-document p {
  max-width: 920px;
  margin: 0 0 9px 46px;
  color: #5e6779;
  font-size: 10px;
  line-height: 1.8;
}

.prompt-bullet {
  position: relative;
}

.prompt-bullet > i {
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 8px 1px 0;
  border-radius: 50%;
  background: var(--detail-agent);
  box-shadow: 0 0 0 3px var(--detail-soft);
}

.prompt-step {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  align-items: start;
  gap: 8px;
}

.prompt-step > b {
  display: grid;
  width: 21px;
  height: 21px;
  place-items: center;
  border-radius: 6px;
  background: #eef0f5;
  color: #697184;
  font-size: 7px;
}

.prompt-space {
  height: 7px;
}

.detail-tool-list {
  display: grid;
  min-height: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  flex: 1;
  overflow: auto;
  padding: 20px 24px 40px;
  align-content: start;
}

.detail-tool-card {
  display: grid;
  min-height: 165px;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 13px;
  padding: 16px;
  border: 1px solid #e2e5eb;
  border-radius: 13px;
  background: #fff;
  box-shadow: 0 8px 25px rgba(36, 43, 62, 0.035);
}

.detail-tool-index {
  display: grid;
  width: 32px;
  height: 32px;
  place-items: center;
  border-radius: 9px;
  background: var(--detail-soft);
  color: var(--detail-agent);
  font-size: 8px;
  font-weight: 900;
}

.detail-tool-main {
  min-width: 0;
}

.detail-tool-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.detail-tool-title code {
  overflow: hidden;
  color: #3c4558;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 9px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-tool-title span {
  padding: 3px 5px;
  border-radius: 4px;
  background: #f0f2f6;
  color: #969dab;
  font-size: 5px;
  font-weight: 900;
  letter-spacing: 0.1em;
}

.detail-tool-main > p {
  display: -webkit-box;
  overflow: hidden;
  margin: 10px 0 12px;
  color: #747c8d;
  font-size: 9px;
  line-height: 1.65;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
}

.parameter-list {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
}

.parameter-list > span {
  display: inline-flex;
  min-height: 22px;
  align-items: center;
  gap: 5px;
  padding: 0 7px;
  border: 1px solid #e3e6ec;
  border-radius: 5px;
  background: #fafafd;
  color: #646d7f;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 7px;
}

.parameter-list > span.required {
  border-color: var(--detail-soft);
}

.parameter-list > span.required::before {
  color: var(--detail-agent);
  content: '*';
}

.parameter-list small {
  color: #a3a9b4;
  font-size: 6px;
}

.detail-state {
  display: flex;
  min-height: 0;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex: 1;
  color: #858c9c;
  font-size: 10px;
}

.detail-loader {
  width: 16px;
  height: 16px;
  border: 2px solid #dfe2ec;
  border-top-color: var(--detail-agent);
  border-radius: 50%;
  animation: spin 0.75s linear infinite;
}

.detail-state.detail-error {
  flex-direction: column;
  color: #a9534e;
}

.detail-error strong {
  font-size: 13px;
}

.detail-error button {
  margin-top: 6px;
  padding: 7px 12px;
  border: 1px solid #e0b5b2;
  border-radius: 7px;
  background: #fff;
  color: #a9534e;
  cursor: pointer;
}

.agent-detail-enter-active,
.agent-detail-leave-active {
  transition: opacity 0.2s ease;
}

.agent-detail-enter-active .agent-detail-modal,
.agent-detail-leave-active .agent-detail-modal {
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.agent-detail-enter-from,
.agent-detail-leave-to {
  opacity: 0;
}

.agent-detail-enter-from .agent-detail-modal,
.agent-detail-leave-to .agent-detail-modal {
  opacity: 0;
  transform: translateY(16px) scale(0.985);
}

.pipeline-section {
  overflow: hidden;
  background: #1d2434;
  color: #fff;
}

.pipeline-section .section-index { color: #858da0; }
.pipeline-section .section-heading > p,
.pipeline-meta { color: #9ca4b5; }
.pipeline-meta { display: flex; align-items: center; gap: 16px; }

.live-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 10px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
}

.live-pill i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #35c28f;
  box-shadow: 0 0 0 4px rgba(53, 194, 143, 0.12);
}

.pipeline-track {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0;
  margin-top: 32px;
}

.stage {
  position: relative;
  min-width: 0;
  padding-right: 24px;
}

.stage-marker {
  position: relative;
  z-index: 1;
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  border: 5px solid #1d2434;
  border-radius: 50%;
  font-size: 9px;
  font-weight: 800;
}

.stage-marker.blue { background: #5678e6; }
.stage-marker.cyan { background: #3f9ab0; }
.stage-marker.violet { background: #7a67d5; }
.stage-marker.amber { background: #ca8c3b; }
.stage-marker.orange { background: #d56842; }
.stage-marker.green { background: #309772; }

.stage-line {
  position: absolute;
  top: 17px;
  left: 34px;
  width: calc(100% - 20px);
  height: 1px;
  background: linear-gradient(90deg, #4f586d, #343c4e);
}

.stage-copy h3 {
  margin: 17px 0 8px;
  font-size: 14px;
}

.stage-copy p {
  margin: 0;
  color: #949daf;
  font-size: 10px;
  line-height: 1.65;
}

.operations-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(330px, 0.8fr);
  gap: 16px;
}

.card-heading {
  align-items: center;
}

.card-heading a {
  color: #666dda;
  font-size: 11px;
  font-weight: 700;
  text-decoration: none;
}

.date-control {
  display: flex;
  align-items: center;
  gap: 9px;
  color: #8a91a0;
  font-size: 10px;
}

.date-control input {
  width: 102px;
  height: 34px;
  padding: 0 10px;
  border: 1px solid #dfe2e9;
  border-radius: 8px;
  outline: none;
  color: #343b4b;
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.04em;
}

.date-control input:focus {
  border-color: #777ddd;
  box-shadow: 0 0 0 3px rgba(103, 109, 218, 0.1);
}

.notice {
  margin-top: 16px;
  padding: 10px 12px;
  border-radius: 9px;
  background: #eaf7f2;
  color: #287a61;
  font-size: 11px;
}

.notice.error {
  background: #fff0ef;
  color: #b64e49;
}

.job-list,
.audit-list {
  margin-top: 18px;
}

.job-row {
  display: grid;
  grid-template-columns: 9px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  min-height: 59px;
  border-top: 1px solid #eef0f4;
}

.job-state {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #c8cdd6;
}

.job-state.active {
  background: #5b5bd6;
  box-shadow: 0 0 0 4px rgba(91, 91, 214, 0.1);
}

.job-copy {
  min-width: 0;
}

.job-copy strong,
.job-copy small {
  display: block;
}

.job-copy strong {
  font-size: 12px;
}

.job-copy small {
  overflow: hidden;
  margin-top: 3px;
  color: #9298a6;
  font-size: 9px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.job-row button {
  padding: 6px 12px;
  border: 1px solid #dde0e7;
  border-radius: 7px;
  background: #fff;
  color: #555d6e;
  font-size: 10px;
  font-weight: 700;
  cursor: pointer;
}

.job-row button:hover:not(:disabled) {
  border-color: #6868d9;
  color: #5b5bd6;
}

.job-row button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.empty-row,
.empty-audit {
  display: flex;
  min-height: 160px;
  align-items: center;
  justify-content: center;
  color: #9ba1ae;
  font-size: 11px;
}

.audit-item {
  display: grid;
  width: 100%;
  grid-template-columns: 35px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-height: 59px;
  padding: 0;
  border: 0;
  border-top: 1px solid #eef0f4;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.audit-icon {
  display: grid;
  width: 32px;
  height: 32px;
  place-items: center;
  border-radius: 9px;
  background: #f0efff;
  color: #6262d2;
  font-size: 9px;
  font-weight: 800;
}

.audit-copy {
  min-width: 0;
}

.audit-copy strong,
.audit-copy small {
  display: block;
}

.audit-copy strong {
  overflow: hidden;
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.audit-copy small {
  margin-top: 3px;
  color: #9ca2af;
  font-size: 9px;
}

.audit-arrow {
  color: #aeb3bd;
  font-size: 20px;
}

.empty-audit {
  flex-direction: column;
  text-align: center;
}

.empty-audit > span {
  color: #777ddd;
  font-size: 24px;
}

.empty-audit strong {
  margin-top: 8px;
  color: #656d7c;
  font-size: 11px;
}

.empty-audit small {
  margin-top: 4px;
  color: #a0a6b1;
  font-size: 9px;
}

.overview-footer {
  display: flex;
  justify-content: space-between;
  padding: 4px 8px 0;
  color: #9aa0ad;
  font-size: 9px;
  letter-spacing: 0.05em;
}

.overview-footer b {
  color: #5a6171;
}

.mini-spinner {
  width: 12px;
  height: 12px;
  border: 2px solid rgba(48, 55, 72, 0.2);
  border-top-color: #303748;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

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

@media (max-width: 1120px) {
  .hero { grid-template-columns: 1fr 0.8fr; }
  .hero-copy { padding-left: 38px; }
  .feature-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .agent-chain { gap: 20px; }
  .agent-card { padding: 17px; }
  .agent-flow-arrow { right: -21px; width: 20px; }
  .agent-flow-arrow i { width: 13px; }
  .agent-foundation { gap: 14px; }
  .agent-foundation > div { gap: 13px; }
  .pipeline-track { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px 0; }
  .stage:nth-child(3) .stage-line { display: none; }
}

@media (max-width: 820px) {
  .hero { grid-template-columns: 1fr; }
  .hero-copy { padding: 42px 28px 20px; }
  .hero-visual { min-height: 350px; }
  .metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .agent-chain { grid-template-columns: 1fr; gap: 32px; }
  .agent-card { min-height: auto; }
  .agent-description { min-height: auto; }
  .agent-flow-arrow {
    top: auto;
    right: 50%;
    bottom: -29px;
    width: 28px;
    transform: translateX(50%) rotate(90deg);
  }
  .agent-foundation {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 16px;
    text-align: center;
  }
  .agent-foundation > div { flex-wrap: wrap; }
  .agent-foundation > small { line-height: 1.6; }
  .agent-detail-overlay { padding: 14px; }
  .agent-detail-modal {
    height: calc(100vh - 28px);
    border-radius: 17px;
  }
  .injection-workspace {
    grid-template-columns: 1fr;
    overflow: auto;
  }
  .injection-editor-card,
  .injection-preview-card {
    min-height: 430px;
  }
  .detail-tool-list { grid-template-columns: 1fr; }
  .operations-grid { grid-template-columns: 1fr; }
  .section-heading { align-items: flex-start; flex-direction: column; }
}

@media (max-width: 560px) {
  .overview { gap: 16px; }
  .hero { border-radius: 18px; }
  .hero h1 { font-size: 38px; }
  .hero-actions { align-items: stretch; flex-direction: column; }
  .metric-grid,
  .feature-grid { grid-template-columns: 1fr; }
  .section-block,
  .operation-card,
  .audit-card { padding: 20px; border-radius: 16px; }
  .agent-system-canvas { padding: 72px 11px 11px; }
  .system-entry { left: 14px; }
  .system-exit { right: 14px; }
  .system-entry strong,
  .system-exit strong { display: none; }
  .agent-card { padding: 16px; }
  .agent-foundation > div { align-items: flex-start; flex-direction: column; }
  .agent-detail-overlay { padding: 0; }
  .agent-detail-modal {
    width: 100%;
    height: 100vh;
    border: 0;
    border-radius: 0;
  }
  .detail-modal-header { min-height: 91px; padding: 0 17px; }
  .detail-agent-identity { gap: 11px; }
  .detail-agent-identity > span { width: 43px; height: 43px; border-radius: 12px; }
  .detail-agent-identity h2 { font-size: 18px; }
  .detail-agent-identity code {
    display: block;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .detail-tabs { padding: 0 17px; }
  .detail-tabs span { font-size: 7px; }
  .detail-tabs small { font-size: 6px; }
  .detail-content-head { padding: 0 17px; }
  .injection-content-head {
    align-items: flex-start;
    padding-top: 10px;
    padding-bottom: 10px;
    flex-direction: column;
  }
  .injection-workspace {
    gap: 10px;
    padding: 10px;
  }
  .injection-editor-card,
  .injection-preview-card { min-height: 410px; }
  .injection-editor-card > footer {
    align-items: flex-start;
    padding: 10px 12px;
    flex-direction: column;
  }
  .prompt-injection-notice { margin-right: 17px; margin-left: 17px; }
  .prompt-document {
    padding: 20px 17px 40px;
    background: #fff;
  }
  .prompt-document p { margin-left: 0; }
  .prompt-document h3 { gap: 9px; }
  .detail-tool-list { padding: 14px 12px 30px; }
  .detail-tool-card { grid-template-columns: 28px minmax(0, 1fr); padding: 13px; }
  .detail-tool-index { width: 27px; height: 27px; }
  .pipeline-track { grid-template-columns: 1fr; gap: 20px; }
  .stage { display: grid; grid-template-columns: 38px 1fr; gap: 12px; }
  .stage-copy h3 { margin-top: 0; }
  .stage-line { top: 35px; left: 17px; width: 1px; height: calc(100% + 20px); }
  .stage:nth-child(3) .stage-line { display: block; }
  .stage:last-child .stage-line { display: none; }
  .pipeline-meta { align-items: flex-start; flex-direction: column; }
  .card-heading { align-items: flex-start; flex-direction: column; }
  .overview-footer { gap: 8px; flex-direction: column; }
}

/* Readability and contrast */
.hero-kicker,
.section-index {
  color: #586273;
  font-size: 11px;
}

.version {
  color: #586273;
  font-size: 10px;
}

.hero-copy > p,
.section-heading > p,
.pipeline-meta {
  color: #4f596a;
  font-size: 14px;
}

.float-card small,
.agent-label {
  color: #5f6878;
  font-size: 11px;
}

.metric-label {
  color: #596273;
  font-size: 13px;
}

.metric-card > small {
  color: #5f6878;
  font-size: 12px;
}

.feature-eyebrow {
  font-size: 11px;
}

.feature-card p {
  color: #4f596a;
  font-size: 13px;
}

.feature-card > small {
  color: #596273;
  font-size: 11px;
}

.system-entry span,
.system-exit span {
  color: #4f596a;
  font-size: 10px;
}

.system-entry strong,
.system-exit strong {
  color: #30394a;
  font-size: 12px;
}

.agent-card {
  min-height: 690px;
  border-color: #d2d7e1;
  background: #fff;
}

.agent-index {
  font-size: 12px;
}

.agent-identity h3 {
  font-size: 18px;
}

.agent-identity small {
  color: #596273;
  font-size: 11px;
}

.agent-status {
  color: #596273;
  font-size: 10px;
}

.agent-core-visual small {
  color: #5f6878;
  font-size: 9px;
}

.agent-description {
  color: #465164;
  font-size: 13px;
}

.mini-title > span {
  font-size: 10px;
}

.mini-title > small {
  color: #5f6878;
  font-size: 11px;
}

.principle-list span {
  color: #384355;
  font-size: 12px;
}

.tool-cloud span {
  min-height: 28px;
  border-color: #d8dce5;
  background: #f6f7fa;
  color: #4f596a;
  font-size: 11px;
}

.agent-detail-trigger span {
  font-size: 12px;
}

.agent-detail-trigger small {
  color: #5f6878;
  font-size: 9px;
}

.agent-io > span {
  color: #30394a;
  font-size: 11px;
}

.agent-io small {
  color: #5f6878;
  font-size: 10px;
}

.foundation-label,
.agent-foundation > small {
  color: #c2c8d4;
  font-size: 10px;
}

.agent-foundation > div span {
  color: #f3f4f6;
  font-size: 11px;
}

.detail-agent-identity small {
  color: var(--detail-agent);
  font-size: 10px;
}

.detail-agent-identity code {
  color: #596273;
  font-size: 11px;
}

.detail-tabs span {
  font-size: 11px;
}

.detail-tabs small {
  color: #5f6878;
  font-size: 10px;
}

.detail-content-head > div > span {
  color: #374151;
  font-size: 11px;
}

.detail-content-head > div > small {
  color: #5f6878;
  font-size: 11px;
}

.detail-content-head > button,
.detail-content-head > strong {
  font-size: 11px;
}

.prompt-injection-notice > span,
.prompt-injection-notice > small {
  color: #465164;
  font-size: 11px;
}

.injection-toggle {
  color: #465164;
  font-size: 11px;
}

.injection-editor-card header span,
.injection-preview-card header span {
  color: #30394a;
  font-size: 13px;
}

.injection-editor-card header small,
.injection-preview-card header small {
  color: #5f6878;
  font-size: 11px;
}

.injection-editor-card header code,
.injection-state {
  font-size: 10px !important;
}

.injection-editor-card textarea {
  color: #30394a;
  font-size: 13px;
}

.injection-editor-card textarea::placeholder {
  color: #737d8e;
}

.injection-editor-card > footer > span,
.injection-editor-card > footer button {
  color: #4f596a;
  font-size: 11px;
}

.injection-editor-card > footer button:not(:disabled) {
  color: #fff;
}

.injection-preface,
.injection-preview-body pre {
  color: #3f4a5c;
  font-size: 12px;
}

.injection-preview-body.empty strong {
  color: #465164;
  font-size: 12px;
}

.injection-preview-body.empty small,
.injection-message {
  color: #4f596a;
  font-size: 11px;
}

.prompt-document h3 {
  font-size: 17px;
}

.prompt-document p {
  color: #3f4a5c;
  font-size: 13px;
}

.detail-tool-title code {
  color: #253044;
  font-size: 12px;
}

.detail-tool-title span {
  color: #596273;
  font-size: 9px;
}

.detail-tool-main > p {
  color: #465164;
  font-size: 12px;
}

.parameter-list > span {
  color: #374151;
  font-size: 10px;
}

.parameter-list small {
  color: #5f6878;
  font-size: 9px;
}

.detail-state {
  color: #4f596a;
  font-size: 13px;
}

.stage-copy h3 {
  font-size: 16px;
}

.stage-copy p {
  color: #c0c7d3;
  font-size: 12px;
}

.job-copy strong,
.audit-copy strong {
  font-size: 13px;
}

.job-copy small,
.audit-copy small,
.overview-footer {
  color: #5f6878;
  font-size: 11px;
}

.job-row button,
.date-control,
.date-control input {
  font-size: 12px;
}

@media (max-width: 820px) {
  .agent-card {
    min-height: auto;
  }
}

@media (max-width: 560px) {
  .detail-tabs span {
    font-size: 10px;
  }

  .detail-tabs small {
    font-size: 9px;
  }
}
</style>
