<template>
  <div class="wisdom-management">
    <div class="wisdom-backdrop" aria-hidden="true">
      <div class="wisdom-grid"></div>
      <div class="wisdom-orbit wisdom-orbit-a"></div>
      <div class="wisdom-orbit wisdom-orbit-b"></div>
      <div class="wisdom-scan"></div>
    </div>

    <aside v-if="leftPanels.length && !artifactActive" class="wisdom-side wisdom-side-left">
      <section v-for="panel in leftPanels" :key="panel.id" class="wisdom-side-panel" :class="`is-${panel.type}`">
        <header v-if="!panel.chart" class="wisdom-side-header">
          <div>
            <span>{{ panel.kicker }}</span>
            <strong>{{ panel.title }}</strong>
          </div>
          <em v-if="panel.badge">{{ panel.badge }}</em>
        </header>
        <div v-if="panel.items?.length" class="wisdom-side-metrics">
          <div v-for="item in panel.items" :key="`${panel.id}-${item.label}`" class="wisdom-side-metric">
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
            <em v-if="item.note">{{ item.note }}</em>
          </div>
        </div>
        <div v-if="panel.text" class="wisdom-side-text" v-html="renderMarkdown(panel.text)"></div>
        <div v-if="panel.actions?.length" class="wisdom-side-actions">
          <button
            v-for="action in panel.actions"
            :key="action.question"
            type="button"
            :disabled="loading"
            @click="sendMessage(action.question)"
          >
            {{ action.label }}
          </button>
        </div>
      </section>
    </aside>

    <aside v-if="rightPanels.length && !artifactActive" class="wisdom-side wisdom-side-right">
      <section v-for="panel in rightPanels" :key="panel.id" class="wisdom-side-panel" :class="`is-${panel.type}`">
        <header v-if="!panel.chart" class="wisdom-side-header">
          <div>
            <span>{{ panel.kicker }}</span>
            <strong>{{ panel.title }}</strong>
          </div>
          <em v-if="panel.badge">{{ panel.badge }}</em>
        </header>
        <smart-chart-renderer
          v-if="panel.chart"
          class="wisdom-side-chart"
          :chart="panel.chart"
        />
        <div v-if="panel.items?.length" class="wisdom-side-metrics">
          <div v-for="item in panel.items" :key="`${panel.id}-${item.label}`" class="wisdom-side-metric">
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
            <em v-if="item.note">{{ item.note }}</em>
          </div>
        </div>
        <div v-if="panel.text" class="wisdom-side-text" v-html="renderMarkdown(panel.text)"></div>
        <div v-if="panel.actions?.length" class="wisdom-side-actions">
          <button
            v-for="action in panel.actions"
            :key="action.question"
            type="button"
            :disabled="loading"
            @click="sendMessage(action.question)"
          >
            {{ action.label }}
          </button>
        </div>
      </section>
    </aside>

    <section v-if="artifactActive" class="wisdom-artifact-workspace">
      <header class="wisdom-artifact-header">
        <div class="wisdom-artifact-heading">
          <span class="wisdom-artifact-mark" aria-hidden="true"></span>
          <div>
            <small>专题分析</small>
            <strong>{{ artifact.title }}</strong>
          </div>
        </div>
        <div class="wisdom-artifact-tools">
          <span class="wisdom-artifact-status" :class="`is-${artifact.status}`">
            <i></i>{{ artifactStatusLabel }}
          </span>
          <button
            v-if="artifact.status === 'ready' || artifact.status === 'error'"
            type="button"
            :disabled="artifactGenerating || !lastArtifactPayload"
            title="重新生成当前界面"
            @click="retryArtifactGeneration"
          >
            重新生成
          </button>
        </div>
      </header>

      <div class="wisdom-artifact-body">
        <div v-if="artifactGenerating" class="wisdom-artifact-building">
          <div class="wisdom-artifact-building__intro">
            <span class="wisdom-artifact-building__spinner"></span>
            <div>
              <strong>{{ artifact.status === "collecting" ? "正在汇总业务数据" : "正在生成专题分析页面" }}</strong>
            </div>
          </div>
          <div class="wisdom-artifact-skeleton is-wide"></div>
          <div class="wisdom-artifact-skeleton-grid">
            <div class="wisdom-artifact-skeleton"></div>
            <div class="wisdom-artifact-skeleton"></div>
          </div>
          <div class="wisdom-artifact-skeleton is-chart"></div>
        </div>

        <iframe
          v-else-if="artifact.html"
          :key="artifact.renderKey"
          ref="artifactFrameRef"
          class="wisdom-artifact-frame"
          :srcdoc="artifact.html"
          sandbox="allow-scripts"
          referrerpolicy="no-referrer"
          title="专题分析页面"
          @load="handleArtifactFrameLoad"
        ></iframe>

        <div v-else class="wisdom-artifact-error">
          <strong>专题分析页面暂未生成</strong>
          <p>{{ artifact.error || "当前数据不足以形成专题分析页面。" }}</p>
          <button type="button" :disabled="!lastArtifactPayload" @click="retryArtifactGeneration">重新生成</button>
        </div>

      </div>
    </section>

    <main class="wisdom-chat" :class="{ 'has-artifact': artifactActive }">
      <div ref="dialogueRef" class="wisdom-dialogue" :class="{ 'is-empty': !messages.length }">
	        <section v-if="!messages.length" class="wisdom-empty-state">
	          <div class="wisdom-empty-mark">
	            <span></span>
	            <strong>AI</strong>
	          </div>
	          <h2>智慧辅助分析</h2>
	          <p>{{ welcomeText }}</p>
	        </section>

        <article
          v-for="message in messages"
          :key="message.id"
          class="wisdom-message"
          :class="`is-${message.role}`"
        >
          <div v-if="message.role === 'assistant'" class="wisdom-message-mark">
            <span>智</span>
          </div>
          <div class="wisdom-bubble">
            <template v-if="message.role === 'user'">
              {{ message.text }}
            </template>
            <template v-else>
              <div v-if="message.digesting" class="wisdom-digesting">
                <span></span><span></span><span></span>
                <em>{{ message.digestText || "正在汇总分析" }}</em>
              </div>
              <div v-if="message.visibleText" class="wisdom-answer" v-html="renderMarkdown(message.visibleText)"></div>
              <span v-if="message.streaming" class="wisdom-stream-caret"></span>
	              <div v-if="message.suggestions?.length && (message.allowFollowUp || (!message.digesting && !message.streaming))" class="wisdom-suggestion-list">
	                <button
	                  v-for="suggestion in message.suggestions"
	                  :key="suggestion.question"
	                  type="button"
	                  :disabled="loading"
	                  @click="sendMessage(suggestion.question)"
	                >
	                  {{ suggestion.label }}
	                </button>
	              </div>
            </template>
          </div>
        </article>
      </div>

      <form class="wisdom-input-bar" @submit.prevent="sendMessage()">
        <div class="wisdom-input-shell">
          <span class="wisdom-input-icon"></span>
          <input
            v-model="currentText"
            :disabled="loading"
            autocomplete="off"
            placeholder="请输入需要了解的业务事项"
            @keydown.enter.prevent="sendMessage()"
          />
          <button
            type="button"
            class="wisdom-voice-button"
            :class="{ 'is-listening': voiceListening }"
            :disabled="loading || !voiceSupported"
            :title="voiceSupported ? (voiceListening ? '停止语音输入' : '语音输入') : '当前浏览器不支持语音输入'"
            :aria-label="voiceSupported ? (voiceListening ? '停止语音输入' : '语音输入') : '当前浏览器不支持语音输入'"
            @click="toggleVoiceInput"
          >
            <span></span>
          </button>
          <button class="wisdom-submit-button" type="submit" :disabled="loading || !currentText.trim()">
            <span v-if="loading" class="wisdom-button-loading"></span>
            <span>{{ loading ? "分析中" : "发送" }}</span>
          </button>
        </div>
      </form>
    </main>
  </div>
</template>

<script setup>
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"
import { buildSmartContextAnswer, buildSmartQuestionContext } from "@/services/smartContextBuilder"
import { buildLocalSmartArtifact, generateSmartArtifact } from "@/services/smartArtifactApi"
import { secureArtifactHtml } from "./artifactRuntime"

const SmartChartRenderer = defineAsyncComponent({
  loader: () => import("./components/SmartChartRenderer.vue"),
  loadingComponent: {
    template: '<div class="smart-chart-loading">正在绘制统计图表</div>',
  },
})

const props = defineProps({
  active: {
    type: Boolean,
    default: true,
  },
})
const currentText = ref("")
const messages = ref([])
const loading = ref(false)
const dialogueRef = ref(null)
const artifactFrameRef = ref(null)
const leftPanels = ref([])
const rightPanels = ref([])
const artifact = ref(createEmptyArtifact())
const artifactActive = computed(() => artifact.value.status !== "idle")
const artifactGenerating = computed(() => ["collecting", "generating"].includes(artifact.value.status))
const artifactStatusLabel = computed(() => {
  if (artifact.value.status === "collecting") return "汇总数据"
  if (artifact.value.status === "generating") return "生成页面"
  if (artifact.value.status === "ready") return "分析完成"
  if (artifact.value.status === "error") return "生成失败"
  if (artifact.value.status === "waiting") return "等待选择"
  return "待生成"
})
const voiceSupported = ref(false)
const voiceListening = ref(false)
const voiceError = ref("")
const welcomeText = "请输入需要了解的业务事项，系统将依据平台汇总数据形成要点分析和专题页面。"
const ARTIFACT_SOFT_TIMEOUT = 28000
let streamTimer = null
let speechRecognition = null
let artifactRequestSerial = 0
const lastArtifactPayload = ref(null)

onMounted(() => {
  initSpeechRecognition()
  window.addEventListener("message", handleArtifactMessage)
})

onBeforeUnmount(() => {
  stopStreaming()
  stopVoiceInput()
  artifactRequestSerial += 1
  window.removeEventListener("message", handleArtifactMessage)
})

watch(
  () => props.active,
  (active) => {
    if (active) return
    stopStreaming()
    stopVoiceInput()
    artifactRequestSerial += 1
    loading.value = false
    messages.value = messages.value.map((message) =>
      message.streaming ? { ...message, streaming: false, digesting: false } : message,
    )
  },
)

function createId() {
  return `${Date.now()}-${Math.random().toString(16).slice(2)}`
}

function createEmptyArtifact() {
  return {
    status: "idle",
    title: "动态分析",
    question: "",
    html: "",
    error: "",
    model: "",
    fallback: false,
    renderKey: 0,
  }
}

function prepareArtifact(question) {
  artifactRequestSerial += 1
  lastArtifactPayload.value = null
  artifact.value = {
    ...createEmptyArtifact(),
    status: "collecting",
    title: buildArtifactTitle(question),
    question,
  }
}

function buildArtifactTitle(question) {
  const normalized = String(question || "动态分析").replace(/[？?。！!]+$/g, "").trim()
  return normalized.length > 28 ? `${normalized.slice(0, 28)}...` : normalized || "动态分析"
}

async function launchArtifactGeneration(payload) {
  const normalizedPayload = {
    question: payload?.question || artifact.value.question,
    answer: payload?.answer || "",
    charts: Array.isArray(payload?.charts) ? payload.charts : [],
    datasets: Array.isArray(payload?.datasets) ? payload.datasets : [],
    context: payload?.context || null,
    pagePath: window.location.hash || window.location.pathname,
    pageName: "智慧管理",
  }
  lastArtifactPayload.value = normalizedPayload
  const requestId = ++artifactRequestSerial
  artifact.value = {
    ...artifact.value,
    status: "generating",
    title: buildArtifactTitle(normalizedPayload.question),
    question: normalizedPayload.question,
    html: "",
    error: "",
    model: "",
    fallback: false,
  }
  try {
    const result = await withArtifactSoftTimeout(generateSmartArtifact(normalizedPayload))
    if (requestId !== artifactRequestSerial) return { stale: true }
    const securedHtml = secureArtifactHtml(result.html)
    if (!securedHtml) throw new Error("生成页面未通过安全检查")
    artifact.value = {
      ...artifact.value,
      status: "ready",
      html: securedHtml,
      error: "",
      model: result.model || "DeepSeek",
      fallback: false,
      renderKey: Date.now(),
    }
    return { ok: true, result }
  } catch (error) {
    if (requestId !== artifactRequestSerial) return { stale: true }
    const errorMessage = getFriendlyErrorMessage(error, "专题分析页面生成暂时不可用，请稍后重试。")
    console.error("[智慧管理] DeepSeek HTML生成失败", error)
    const fallbackHtml = buildLocalArtifactHtml(normalizedPayload, errorMessage)
    if (fallbackHtml) {
      artifact.value = {
        ...artifact.value,
        status: "ready",
        html: fallbackHtml,
        error: errorMessage,
        model: "本地兜底",
        fallback: true,
        renderKey: Date.now(),
      }
      return { ok: false, fallback: true, message: errorMessage, error }
    }
    artifact.value = {
      ...artifact.value,
      status: "error",
      html: "",
      error: errorMessage,
      model: "",
      fallback: false,
      renderKey: Date.now(),
    }
    return { ok: false, message: errorMessage, error }
  }
}

function withArtifactSoftTimeout(promise) {
  return new Promise((resolve, reject) => {
    const timer = window.setTimeout(() => {
      const error = new Error("专题分析页面生成服务响应时间较长，已切换本地分析页面")
      error.code = "ARTIFACT_SOFT_TIMEOUT"
      reject(error)
    }, ARTIFACT_SOFT_TIMEOUT)

    promise.then(resolve, reject).finally(() => window.clearTimeout(timer))
  })
}

function buildLocalArtifactHtml(payload, reason) {
  try {
    const html = buildLocalSmartArtifact({ ...payload, reason })
    return secureArtifactHtml(html)
  } catch (error) {
    console.error("[智慧管理] 本地专题页面生成失败", error)
    return ""
  }
}

function retryArtifactGeneration() {
  if (!lastArtifactPayload.value || artifactGenerating.value) return
  launchArtifactGeneration(lastArtifactPayload.value)
}

function failArtifactPreparation(message) {
  artifactRequestSerial += 1
  artifact.value = {
    ...artifact.value,
    status: "error",
    html: "",
    error: message,
    fallback: false,
    renderKey: Date.now(),
  }
}

function handleArtifactFrameLoad() {
  if (artifact.value.status === "ready") return
  artifact.value = { ...artifact.value, status: "ready" }
}

function handleArtifactMessage(event) {
  if (event.source !== artifactFrameRef.value?.contentWindow || event.data?.source !== "smart-artifact") return
  if (event.data.type === "runtime-error") {
    artifact.value = {
      ...artifact.value,
      status: "error",
      html: "",
      error: event.data.message || "生成界面运行异常",
      fallback: false,
      renderKey: Date.now(),
    }
  }
}

function normalizeYakText(value) {
  return String(value || "")
    .replace(/耗牛/g, "牦牛")
    .replace(/犛牛/g, "牦牛")
}

function normalizeQuestionText(value) {
  return normalizeYakText(value).trim()
}

function initSpeechRecognition() {
  if (typeof window === "undefined") return
  const Recognition = window.SpeechRecognition || window.webkitSpeechRecognition
  voiceSupported.value = Boolean(Recognition)
  if (!Recognition) return

  speechRecognition = new Recognition()
  speechRecognition.lang = "zh-CN"
  speechRecognition.continuous = false
  speechRecognition.interimResults = true
  speechRecognition.maxAlternatives = 1

  speechRecognition.onstart = () => {
    voiceListening.value = true
    voiceError.value = ""
  }
  speechRecognition.onresult = (event) => {
    const results = Array.from(event.results || [])
    const transcript = results
      .map((result) => result?.[0]?.transcript || "")
      .join("")
      .trim()
    if (transcript) currentText.value = transcript
  }
  speechRecognition.onerror = (event) => {
    voiceListening.value = false
    voiceError.value = event?.error || "语音输入失败"
  }
  speechRecognition.onend = () => {
    voiceListening.value = false
  }
}

function toggleVoiceInput() {
  if (!speechRecognition || loading.value) return
  if (voiceListening.value) {
    stopVoiceInput()
    return
  }
  try {
    voiceError.value = ""
    speechRecognition.start()
  } catch (error) {
    voiceError.value = error?.message || "语音输入启动失败"
    voiceListening.value = false
  }
}

function stopVoiceInput() {
  if (!speechRecognition || !voiceListening.value) return
  try {
    speechRecognition.stop()
  } catch (error) {
    voiceError.value = error?.message || "语音输入已结束"
  } finally {
    voiceListening.value = false
  }
}

async function sendMessage(text = currentText.value) {
  const question = normalizeQuestionText(text)
  if (!question || loading.value) return
  stopVoiceInput()

  const userMessage = {
    id: createId(),
    role: "user",
    text: question,
  }
  const assistantMessage = {
    id: createId(),
    role: "assistant",
    steps: [],
    digesting: true,
    digestText: "生成中",
    visibleText: "",
    fullText: "",
    streaming: false,
    charts: [],
    insights: [],
    suggestions: [],
  }

  messages.value = [...messages.value, userMessage, assistantMessage]
  currentText.value = ""
  loading.value = true
  prepareArtifact(question)
  await scrollToBottom()

  await handleUnifiedQuestion(question, assistantMessage.id)
}

async function handleUnifiedQuestion(question, assistantId) {
  patchAssistant(assistantId, {
    digestText: "生成中",
  })

  try {
    const pagePath = window.location.hash || window.location.pathname
    const context = await buildSmartQuestionContext(question, { pagePath })
    const answer = buildSmartContextAnswer(context)
    const insights = context.insights?.length ? context.insights : buildChartInsights(context.charts || [])

    patchAssistant(assistantId, {
      digesting: true,
      digestText: "生成中",
      insights,
      suggestions: [],
      allowFollowUp: true,
    })
    updateDynamicPanels({
      question,
      answer,
      charts: context.charts || [],
      insights,
      suggestions: [],
    })
    finishAssistant(assistantId, buildArtifactPreparingMessage())
    launchArtifactGeneration({
      question,
      answer,
      charts: context.charts || [],
      datasets: context.datasets || [],
      context,
    })
  } catch (error) {
    const errorText = getFriendlyErrorMessage(error, "上下文数据整理失败，请稍后重试。")
    updateDynamicPanels({ question, answer: errorText, charts: [], insights: [], suggestions: [] })
    failArtifactPreparation(errorText)
    finishAssistant(assistantId, errorText)
  }
}

function buildArtifactPreparingMessage() {
  return [
    "专题分析页面正在生成，完成后会自动显示在右侧。",
    "你可以继续提出其他问题。",
  ].join("\n")
}

function formatNumber(value) {
  const number = Number(String(value).replace(/,/g, ""))
  if (!Number.isFinite(number)) return value || "--"
  return number.toLocaleString("zh-CN", { maximumFractionDigits: 2 })
}
function updateDynamicPanels({ question, answer, charts = [], insights = [], suggestions = [], aiPanels } = {}) {
  const aiLeft = aiPanels?.leftPanels || []
  const aiRight = aiPanels?.rightPanels || []
  if (aiLeft.length || aiRight.length) {
    leftPanels.value = aiLeft
    rightPanels.value = aiRight
    return
  }

  const fallbackPanels = buildFallbackPanels({ question, answer, charts, insights, suggestions })
  leftPanels.value = fallbackPanels.left
  rightPanels.value = fallbackPanels.right
}

function buildFallbackPanels({ question, answer, charts = [], insights = [], suggestions = [] } = {}) {
  const left = []
  const right = []
  const metricItems = (insights.length ? insights : buildChartInsights(charts)).map((item) => ({
    label: item.label,
    value: item.value,
    note: item.note,
  }))

  if (!charts.length && !metricItems.length) {
    return { left, right }
  }

  if (metricItems.length) {
    left.push({
      id: `summary-${createId()}`,
      type: "metrics",
      kicker: "数据要点",
      title: "数据摘要",
      badge: "实时",
      items: metricItems.slice(0, 4),
      actions: [],
    })
  }

  charts.slice(0, 2).forEach((chart, index) => {
    right.push({
      id: `chart-${chart.id || index}-${createId()}`,
      type: "chart",
      kicker: index === 0 ? "可视分析" : "关联图表",
      title: chart.title || `统计图表${index + 1}`,
      badge: chart.unit || "",
      chart,
      items: [],
      actions: [],
      text: "",
    })
  })

  return {
    left: left.slice(0, 2),
    right: right.slice(0, 2),
  }
}
function buildChartInsights(charts = []) {
  const insights = []
  charts.slice(0, 2).forEach((chart) => {
    const rows = (chart.rows || [])
      .map((row) => ({
        ...row,
        value: Number(row.value),
      }))
      .filter((row) => row.name && Number.isFinite(row.value))
    if (!rows.length) return

    const unit = chart.unit || rows.find((row) => row.unit)?.unit || ""
    const sorted = rows.slice().sort((a, b) => b.value - a.value)
    const total = rows.reduce((sum, row) => sum + row.value, 0)
    const average = total / rows.length
    const top = sorted[0]
    const bottom = sorted[sorted.length - 1]

    insights.push({
      label: "最高",
      value: `${top.name} ${formatNumber(top.value)}${unit}`,
      note: chart.title,
    })
    if (rows.length > 2) {
      insights.push({
        label: chart.type === "pie" ? "占比项" : "最低",
        value: `${bottom.name} ${formatNumber(bottom.value)}${unit}`,
        note: chart.type === "pie" ? "最小结构项" : "低值区域",
      })
    }
    insights.push({
      label: "合计",
      value: `${formatNumber(total)}${unit}`,
      note: rows.length > 1 ? `覆盖 ${rows.length} 项` : chart.title,
    })
    if (chart.type !== "pie" && rows.length > 1) {
      insights.push({
        label: "均值",
        value: `${formatNumber(average)}${unit}`,
        note: "按当前图表项计算",
      })
    }
  })
  return insights.slice(0, 4)
}

function patchAssistant(id, patch, shouldScroll = true) {
  messages.value = messages.value.map((message) => (message.id === id ? { ...message, ...patch } : message))
  if (shouldScroll) scrollToBottom()
}

function finishAssistant(id, text) {
  patchAssistant(id, {
    digesting: false,
  })
  streamAssistantText(id, text)
}

function getFriendlyErrorMessage(error, fallback) {
  const message = String(error?.message || "")
  if (error?.code === 401 || error?.code === "401" || error?.code === "HTTP_401" || /未登录|授权|Unauthorized|HTTP 401/i.test(message)) {
    return "当前登录状态已失效，请重新登录后查询。"
  }
  if (error?.code === "REQUEST_TIMEOUT" || /timeout|timed out|超时/i.test(message)) {
    return "服务响应时间较长，请稍后再试，或换一个更具体的问题。"
  }
  if (error?.code === "REQUEST_ABORTED" || /aborted|abort|signal/i.test(message)) {
    return "本次分析已中断，请重新提交。"
  }
  if (error?.code === "HTTP_404" || error?.status === 404 || /HTTP 404/i.test(message)) {
    return "专题分析页面生成服务暂不可用，请稍后重试。"
  }
  if (/Failed to fetch|NetworkError|Load failed|HTTP 50|HTTP 40/i.test(message)) {
    return fallback
  }
  return /[a-zA-Z]{4,}/.test(message) ? fallback : message || fallback
}

function streamAssistantText(id, text) {
  stopStreaming()
  const source = normalizeYakText(text)
  const chunkSize = source.length > 1200 ? 36 : source.length > 700 ? 24 : 14
  let index = 0
  patchAssistant(id, {
    fullText: source,
    visibleText: "",
    streaming: true,
    charts: [],
  })

  const tick = () => {
    index = Math.min(index + chunkSize, source.length)
    patchAssistant(id, {
      visibleText: source.slice(0, index),
      streaming: index < source.length,
    })

    if (index >= source.length) {
      streamTimer = null
      loading.value = false
      return
    }
    streamTimer = window.setTimeout(tick, 18)
  }

  streamTimer = window.setTimeout(tick, 0)
}

function stopStreaming() {
  if (streamTimer) {
    window.clearTimeout(streamTimer)
    streamTimer = null
  }
}

function renderMarkdown(value) {
  const lines = escapeHtml(value).split(/\r?\n/)
  const html = []
  let listItems = []
  let ordered = false

  const flushList = () => {
    if (!listItems.length) return
    html.push(`<${ordered ? "ol" : "ul"}>${listItems.map((item) => `<li>${renderInline(item)}</li>`).join("")}</${ordered ? "ol" : "ul"}>`)
    listItems = []
    ordered = false
  }

  lines.forEach((line) => {
    const trimmed = line.trim()
    if (!trimmed) {
      flushList()
      return
    }

    const heading = trimmed.match(/^#{1,4}\s+(.+)$/) || trimmed.match(/^\*\*(.+)\*\*$/)
    if (heading) {
      flushList()
      html.push(`<h3>${renderInline(heading[1])}</h3>`)
      return
    }

    const orderedMatch = trimmed.match(/^\d+[.)、]\s+(.+)$/)
    const unorderedMatch = trimmed.match(/^[-*]\s+(.+)$/)
    if (orderedMatch || unorderedMatch) {
      const nextOrdered = Boolean(orderedMatch)
      if (listItems.length && ordered !== nextOrdered) flushList()
      ordered = nextOrdered
      listItems.push(orderedMatch ? orderedMatch[1] : unorderedMatch[1])
      return
    }

    flushList()
    html.push(`<p>${renderInline(trimmed)}</p>`)
  })

  flushList()
  return html.join("")
}

function renderInline(value) {
  return value.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
}

function escapeHtml(value) {
  return String(value || "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;")
}

async function scrollToBottom() {
  await nextTick()
  window.requestAnimationFrame(() => {
    if (dialogueRef.value) {
      dialogueRef.value.scrollTop = dialogueRef.value.scrollHeight
    }
  })
}

</script>

<style lang="scss">
.wisdom-management {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  color: #dffaff;
  background:
    radial-gradient(circle at 50% 45%, rgba(37, 161, 133, 0.28), rgba(3, 16, 28, 0.18) 35%, rgba(2, 8, 18, 0.86) 72%),
    linear-gradient(180deg, #041324, #030914);
  pointer-events: auto;
}

.wisdom-backdrop {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.wisdom-grid {
  position: absolute;
  left: 430px;
  right: 430px;
  top: 128px;
  bottom: 8px;
  opacity: 0.18;
  background-image:
    linear-gradient(rgba(48, 220, 255, 0.14) 1px, transparent 1px),
    linear-gradient(90deg, rgba(48, 220, 255, 0.14) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(circle at center, #000 42%, transparent 78%);
}

.wisdom-orbit {
  position: absolute;
  left: 50%;
  top: 50%;
  border: 1px solid rgba(48, 220, 255, 0.18);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: inset 0 0 70px rgba(48, 220, 255, 0.06), 0 0 70px rgba(32, 232, 188, 0.08);
}

.wisdom-orbit-a {
  width: 760px;
  height: 760px;
  animation: wisdomOrbitSpin 24s linear infinite;
}

.wisdom-orbit-b {
  width: 980px;
  height: 260px;
  border-color: rgba(250, 211, 107, 0.16);
  transform: translate(-50%, -48%) rotate(-9deg);
  animation: wisdomPulse 6s ease-in-out infinite;
}

.wisdom-scan {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 620px;
  height: 620px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: conic-gradient(from 0deg, transparent, rgba(48, 220, 255, 0.2), transparent 24%);
  opacity: 0.2;
  animation: wisdomScanSpin 8s linear infinite;
}

.wisdom-artifact-workspace {
  position: absolute;
  left: 590px;
  right: 36px;
  top: 112px;
  bottom: 18px;
  z-index: 6;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(48, 220, 255, 0.3);
  background: rgba(3, 17, 28, 0.96);
  box-shadow: inset 0 0 40px rgba(48, 220, 255, 0.05), 0 18px 42px rgba(0, 0, 0, 0.28);
}

.wisdom-artifact-header {
  flex: 0 0 62px;
  min-width: 0;
  padding: 0 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 1px solid rgba(48, 220, 255, 0.18);
  background: linear-gradient(90deg, rgba(8, 48, 61, 0.92), rgba(5, 25, 37, 0.82));
}

.wisdom-artifact-heading,
.wisdom-artifact-tools {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
}

.wisdom-artifact-mark {
  position: relative;
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(48, 220, 255, 0.68);
  background: rgba(48, 220, 255, 0.08);
}

.wisdom-artifact-mark::before,
.wisdom-artifact-mark::after {
  content: "";
  position: absolute;
  background: #30dcff;
  box-shadow: 0 0 10px rgba(48, 220, 255, 0.6);
}

.wisdom-artifact-mark::before {
  left: 6px;
  right: 6px;
  top: 8px;
  height: 2px;
}

.wisdom-artifact-mark::after {
  left: 6px;
  right: 10px;
  top: 16px;
  height: 2px;
}

.wisdom-artifact-heading small,
.wisdom-artifact-heading strong {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wisdom-artifact-heading small {
  margin-bottom: 3px;
  color: rgba(48, 220, 255, 0.68);
  font-size: 11px;
}

.wisdom-artifact-heading strong {
  max-width: 720px;
  color: #fff;
  font-size: 17px;
}

.wisdom-artifact-status {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: rgba(223, 250, 255, 0.68);
  font-size: 12px;
}

.wisdom-artifact-status i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #ffd76c;
  box-shadow: 0 0 10px rgba(255, 215, 108, 0.6);
}

.wisdom-artifact-status.is-ready i {
  background: #27f0c0;
  box-shadow: 0 0 10px rgba(39, 240, 192, 0.6);
}

.wisdom-artifact-status.is-error i {
  background: #ff956e;
  box-shadow: 0 0 10px rgba(255, 149, 110, 0.56);
}

.wisdom-artifact-tools button,
.wisdom-artifact-error button {
  height: 30px;
  padding: 0 12px;
  border: 1px solid rgba(48, 220, 255, 0.32);
  background: rgba(7, 43, 56, 0.78);
  color: #dffaff;
  font-size: 12px;
  cursor: pointer;
}

.wisdom-artifact-tools button:hover:not(:disabled),
.wisdom-artifact-error button:hover:not(:disabled) {
  border-color: rgba(255, 215, 108, 0.62);
  color: #fff;
}

.wisdom-artifact-tools button:disabled,
.wisdom-artifact-error button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.wisdom-artifact-body {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.wisdom-artifact-frame {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  background: #06131d;
}

.wisdom-artifact-building {
  height: 100%;
  overflow: hidden;
  padding: 28px;
  background:
    linear-gradient(rgba(48, 220, 255, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(48, 220, 255, 0.04) 1px, transparent 1px),
    #06131d;
  background-size: 36px 36px;
}

.wisdom-artifact-building__intro {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 24px;
}

.wisdom-artifact-building__intro strong,
.wisdom-artifact-building__intro p {
  display: block;
  margin: 0;
}

.wisdom-artifact-building__intro strong {
  color: #fff;
  font-size: 18px;
}

.wisdom-artifact-building__intro p {
  margin-top: 4px;
  color: rgba(223, 250, 255, 0.5);
  font-size: 12px;
}

.wisdom-artifact-building__spinner {
  width: 30px;
  height: 30px;
  border: 2px solid rgba(48, 220, 255, 0.18);
  border-top-color: #30dcff;
  border-radius: 50%;
  animation: wisdomSpin 0.9s linear infinite;
}

.wisdom-artifact-skeleton {
  position: relative;
  height: 190px;
  overflow: hidden;
  border: 1px solid rgba(48, 220, 255, 0.12);
  background: rgba(8, 35, 47, 0.66);
}

.wisdom-artifact-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(99, 239, 226, 0.1), transparent);
  animation: wisdomArtifactShimmer 1.6s ease-in-out infinite;
}

.wisdom-artifact-skeleton.is-wide {
  height: 96px;
}

.wisdom-artifact-skeleton.is-chart {
  height: 260px;
  margin-top: 14px;
}

.wisdom-artifact-skeleton-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-top: 14px;
}

.wisdom-artifact-error {
  height: 100%;
  display: grid;
  place-content: center;
  justify-items: center;
  padding: 32px;
  text-align: center;
  background: #06131d;
}

.wisdom-artifact-error strong {
  color: #fff;
  font-size: 20px;
}

.wisdom-artifact-error p {
  max-width: 520px;
  margin: 10px 0 18px;
  color: rgba(223, 250, 255, 0.62);
  font-size: 13px;
  line-height: 1.7;
}

.wisdom-side {
  position: absolute;
  top: 112px;
  bottom: 18px;
  z-index: 5;
  width: clamp(390px, 21vw, 460px);
  overflow-y: auto;
  display: grid;
  align-content: start;
  gap: 16px;
  padding: 6px 0 10px;
  box-sizing: border-box;
  scrollbar-width: none;
}

.wisdom-side::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.wisdom-side-left {
  left: clamp(24px, 2.4vw, 52px);
}

.wisdom-side-right {
  right: clamp(24px, 2.4vw, 52px);
}

.wisdom-side-panel {
  min-height: 0;
  border: 1px solid rgba(48, 220, 255, 0.22);
  background:
    linear-gradient(135deg, rgba(6, 37, 50, 0.9), rgba(4, 19, 32, 0.86)),
    radial-gradient(circle at 18% 0%, rgba(39, 240, 192, 0.12), transparent 34%);
  box-shadow: inset 0 0 24px rgba(48, 220, 255, 0.07), 0 14px 28px rgba(0, 0, 0, 0.22);
  padding: 15px;
  box-sizing: border-box;
}

.wisdom-side-panel.is-chart {
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}

.wisdom-side-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.wisdom-side-header span {
  display: block;
  margin-bottom: 5px;
  color: rgba(48, 220, 255, 0.72);
  font-size: 12px;
}

.wisdom-side-header strong {
  display: block;
  max-width: 220px;
  color: #fff;
  font-size: 17px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wisdom-side-header em {
  flex: 0 0 auto;
  padding: 3px 8px;
  border: 1px solid rgba(255, 215, 108, 0.32);
  color: #ffd76c;
  font-size: 12px;
  font-style: normal;
  background: rgba(255, 215, 108, 0.08);
}

.wisdom-side-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
}

.wisdom-side-metric {
  min-width: 0;
  padding: 10px;
  border: 1px solid rgba(48, 220, 255, 0.16);
  background: rgba(3, 22, 35, 0.58);
  box-sizing: border-box;
}

.wisdom-side-metric span,
.wisdom-side-metric em {
  display: block;
  color: rgba(223, 250, 255, 0.55);
  font-size: 12px;
  font-style: normal;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wisdom-side-metric strong {
  display: block;
  margin: 4px 0;
  color: #ffd76c;
  font-family: "D-DIN", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wisdom-side-text {
  color: rgba(237, 253, 255, 0.88);
  font-size: 13px;
  line-height: 1.7;
}

.wisdom-side-text h3 {
  margin: 0 0 8px;
  color: #fff;
  font-size: 15px;
}

.wisdom-side-text p {
  margin: 7px 0;
}

.wisdom-side-text ul,
.wisdom-side-text ol {
  margin: 8px 0 8px 18px;
  padding: 0;
}

.wisdom-side-text strong {
  color: #ffd76c;
}

.wisdom-side-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.wisdom-side-text + .wisdom-side-actions,
.wisdom-side-metrics + .wisdom-side-actions {
  margin-top: 12px;
}

.wisdom-side-actions button {
  height: 30px;
  min-width: 84px;
  padding: 0 10px;
  border: 1px solid rgba(48, 220, 255, 0.28);
  background: linear-gradient(135deg, rgba(8, 48, 62, 0.76), rgba(6, 28, 43, 0.76));
  color: rgba(255, 215, 108, 0.9);
  font-size: 12px;
  cursor: pointer;
}

.wisdom-side-actions button:hover:not(:disabled) {
  border-color: rgba(255, 215, 108, 0.62);
  color: #fff;
}

.wisdom-side-chart.smart-chart-card {
  width: 100%;
  height: 348px;
  margin-top: 0;
}

.wisdom-side-chart .smart-chart-header {
  height: 58px;
  padding: 10px 13px 0;
}

.wisdom-side-chart .smart-chart-header strong {
  font-size: 15px;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wisdom-side-chart .smart-chart-header span,
.wisdom-side-chart .smart-chart-header em {
  font-size: 11px;
}

.wisdom-side-chart .smart-chart {
  height: 264px;
}

.wisdom-avatar-ring,
.wisdom-empty-mark span {
  position: absolute;
  inset: 0;
  border: 1px solid rgba(48, 220, 255, 0.62);
  border-radius: 50%;
  animation: wisdomSpin 7s linear infinite;
}

.wisdom-avatar-ring::before,
.wisdom-empty-mark span::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ffd76c;
  box-shadow: 0 0 14px rgba(255, 215, 108, 0.8);
}

.wisdom-chat {
  position: absolute;
  left: 50%;
  top: 112px;
  bottom: 18px;
  z-index: 4;
  width: clamp(720px, calc(100% - 1040px), 900px);
  display: flex;
  flex-direction: column;
  min-width: 0;
  transform: translateX(-50%);
}

.wisdom-chat.has-artifact {
  left: 34px;
  right: auto;
  width: 520px;
  transform: none;
}

.wisdom-chat.has-artifact .wisdom-bubble {
  max-width: calc(100% - 46px);
}

.wisdom-dialogue {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 8px 18px;
  scrollbar-width: thin;
  scrollbar-color: rgba(48, 220, 255, 0.5) rgba(3, 18, 30, 0.3);
}

.wisdom-dialogue.is-empty {
  display: grid;
  place-items: center;
}

.wisdom-empty-state {
  position: relative;
  width: 560px;
  min-height: 280px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.wisdom-empty-mark {
  position: relative;
  width: 126px;
  height: 126px;
  display: grid;
  place-items: center;
}

.wisdom-empty-mark strong {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #071520;
  font-family: "D-DIN", Arial, sans-serif;
  font-size: 34px;
  background: radial-gradient(circle at 32% 24%, #fff, #9cf8e9 48%, #2bd4cb 100%);
  box-shadow: 0 0 42px rgba(78, 243, 222, 0.38);
}

.wisdom-empty-state h2 {
  margin: 18px 0 10px;
  color: #fff;
  font-size: 28px;
  letter-spacing: 0;
}

.wisdom-empty-state p {
  margin: 0;
  max-width: 420px;
  color: rgba(223, 250, 255, 0.82);
  font-size: 15px;
  line-height: 1.8;
}

.wisdom-suggestion-list button {
  height: 34px;
  border: 1px solid rgba(48, 220, 255, 0.28);
  background: linear-gradient(135deg, rgba(8, 48, 62, 0.78), rgba(6, 28, 43, 0.78));
  color: rgba(223, 250, 255, 0.86);
  font-size: 13px;
  cursor: pointer;
  box-shadow: inset 0 0 16px rgba(48, 220, 255, 0.06);
}

.wisdom-suggestion-list button:hover:not(:disabled) {
  border-color: rgba(255, 215, 108, 0.62);
  color: #fff;
  background: linear-gradient(135deg, rgba(48, 220, 255, 0.18), rgba(255, 215, 108, 0.12));
}

.wisdom-message {
  display: flex;
  margin: 14px 0;
  gap: 10px;
}

.wisdom-message.is-user {
  justify-content: flex-end;
}

.wisdom-message-mark {
  flex: 0 0 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #06151f;
  font-weight: 800;
  background: linear-gradient(135deg, #dffaff, #4cf0de);
  box-shadow: 0 0 22px rgba(78, 243, 222, 0.36);
}

.wisdom-bubble {
  max-width: min(680px, calc(100% - 48px));
  box-sizing: border-box;
  border: 1px solid rgba(48, 220, 255, 0.18);
  background: rgba(4, 22, 34, 0.92);
  box-shadow: inset 0 0 24px rgba(48, 220, 255, 0.06), 0 14px 34px rgba(0, 0, 0, 0.34);
  color: rgba(237, 253, 255, 0.92);
  font-size: 14px;
  line-height: 1.7;
  padding: 13px 15px;
}

.smart-chart-loading {
  width: min(620px, 100%);
  height: 292px;
  margin-top: 12px;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  border: 1px solid rgba(48, 220, 255, 0.22);
  background: rgba(4, 22, 34, 0.72);
  color: rgba(255, 215, 108, 0.86);
  font-size: 13px;
  box-shadow: inset 0 0 24px rgba(48, 220, 255, 0.06);
}

.wisdom-suggestion-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

.wisdom-suggestion-list button {
  width: auto;
  min-width: 86px;
  padding: 0 12px;
  color: rgba(255, 215, 108, 0.9);
}

.wisdom-message.is-user .wisdom-bubble {
  max-width: min(560px, 76%);
  border-color: rgba(255, 215, 108, 0.26);
  background: linear-gradient(135deg, rgba(50, 115, 106, 0.9), rgba(13, 54, 65, 0.86));
}

.wisdom-steps {
  display: grid;
  gap: 8px;
  margin-bottom: 10px;
}

.wisdom-step {
  display: flex;
  align-items: center;
  gap: 8px;
  color: rgba(223, 250, 255, 0.64);
  font-size: 13px;
}

.wisdom-step span {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid rgba(48, 220, 255, 0.7);
  position: relative;
}

.wisdom-step span::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 2px;
  width: 4px;
  height: 7px;
  border-right: 2px solid #30dcff;
  border-bottom: 2px solid #30dcff;
  transform: rotate(40deg);
}

.wisdom-digesting {
  display: flex;
  align-items: center;
  gap: 8px;
  color: rgba(255, 215, 108, 0.88);
}

.wisdom-digesting span,
.wisdom-button-loading {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ffd76c;
  animation: wisdomBounce 1s ease-in-out infinite;
}

.wisdom-digesting span:nth-child(2) {
  animation-delay: 0.14s;
}

.wisdom-digesting span:nth-child(3) {
  animation-delay: 0.28s;
}

.wisdom-digesting em {
  font-style: normal;
}

.wisdom-answer {
  color: rgba(237, 253, 255, 0.94);
}

.wisdom-answer h3 {
  margin: 12px 0 8px;
  color: #fff;
  font-size: 17px;
}

.wisdom-answer p {
  margin: 8px 0;
}

.wisdom-answer ul,
.wisdom-answer ol {
  margin: 8px 0 8px 20px;
  padding: 0;
}

.wisdom-answer li {
  margin: 4px 0;
}

.wisdom-answer strong {
  color: #ffd76c;
}

.wisdom-stream-caret {
  display: inline-block;
  width: 8px;
  height: 18px;
  margin-left: 4px;
  vertical-align: middle;
  background: #30dcff;
  animation: wisdomBlink 0.8s steps(2, start) infinite;
}

.wisdom-input-bar {
  flex: 0 0 64px;
  padding: 8px 8px 0;
  box-sizing: border-box;
}

.wisdom-input-shell {
  height: 50px;
  border: 1px solid rgba(48, 220, 255, 0.34);
  background: linear-gradient(135deg, rgba(8, 42, 55, 0.92), rgba(3, 18, 31, 0.92));
  box-shadow: inset 0 0 24px rgba(48, 220, 255, 0.08), 0 0 30px rgba(48, 220, 255, 0.1);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 8px 0 16px;
  box-sizing: border-box;
}

.wisdom-input-shell:focus-within {
  border-color: rgba(126, 251, 246, 0.78);
  box-shadow:
    inset 0 0 24px rgba(48, 220, 255, 0.1),
    0 0 0 2px rgba(126, 251, 246, 0.12),
    0 0 30px rgba(48, 220, 255, 0.14);
}

.wisdom-input-icon {
  width: 16px;
  height: 16px;
  border: 2px solid #30dcff;
  border-radius: 50%;
  position: relative;
  flex: 0 0 auto;
}

.wisdom-input-icon::after {
  content: "";
  position: absolute;
  right: -7px;
  bottom: -5px;
  width: 8px;
  height: 2px;
  border-radius: 2px;
  background: #30dcff;
  transform: rotate(45deg);
}

.wisdom-input-shell input {
  min-width: 0;
  flex: 1;
  border: 0;
  outline: 0;
  background: transparent;
  color: #fff;
  font-size: 15px;
}

.wisdom-input-shell input::placeholder {
  color: rgba(223, 250, 255, 0.62);
}

.wisdom-submit-button {
  width: 92px;
  height: 36px;
  border: 1px solid rgba(255, 215, 108, 0.46);
  background: linear-gradient(135deg, rgba(255, 215, 108, 0.26), rgba(48, 220, 255, 0.12));
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
}

.wisdom-voice-button {
  position: relative;
  flex: 0 0 auto;
  width: 38px;
  height: 36px;
  border: 1px solid rgba(48, 220, 255, 0.32);
  background: rgba(6, 35, 49, 0.76);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.wisdom-voice-button span {
  position: relative;
  width: 10px;
  height: 17px;
  border: 2px solid #30dcff;
  border-radius: 8px;
  box-sizing: border-box;
}

.wisdom-voice-button span::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -8px;
  width: 14px;
  height: 8px;
  border: 2px solid #30dcff;
  border-top: 0;
  border-radius: 0 0 10px 10px;
  transform: translateX(-50%);
}

.wisdom-voice-button span::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -12px;
  width: 12px;
  height: 2px;
  border-radius: 2px;
  background: #30dcff;
  transform: translateX(-50%);
}

.wisdom-voice-button.is-listening {
  border-color: rgba(255, 215, 108, 0.62);
  background: rgba(255, 215, 108, 0.14);
  box-shadow: 0 0 18px rgba(255, 215, 108, 0.22);
}

.wisdom-voice-button.is-listening span,
.wisdom-voice-button.is-listening span::before {
  border-color: #ffd76c;
}

.wisdom-voice-button.is-listening span::after {
  background: #ffd76c;
}

.wisdom-submit-button:disabled,
.wisdom-voice-button:disabled {
  cursor: not-allowed;
  opacity: 0.62;
}

.wisdom-submit-button:focus-visible,
.wisdom-voice-button:focus-visible,
.wisdom-suggestion-list button:focus-visible {
  outline: 2px solid #7efbf6;
  outline-offset: 2px;
}

.wisdom-button-loading {
  width: 12px;
  height: 12px;
  border: 2px solid rgba(255, 255, 255, 0.34);
  border-top-color: #fff;
  background: transparent;
  animation: wisdomSpin 0.8s linear infinite;
}

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

@keyframes wisdomOrbitSpin {
  to {
    transform: translate(-50%, -50%) rotate(360deg);
  }
}

@keyframes wisdomScanSpin {
  to {
    transform: translate(-50%, -50%) rotate(360deg);
  }
}

@keyframes wisdomPulse {
  0%,
  100% {
    opacity: 0.36;
  }
  50% {
    opacity: 0.72;
  }
}

@keyframes wisdomBounce {
  0%,
  100% {
    transform: translateY(0);
    opacity: 0.42;
  }
  50% {
    transform: translateY(-5px);
    opacity: 1;
  }
}

@keyframes wisdomBlink {
  50% {
    opacity: 0;
  }
}

@keyframes wisdomArtifactShimmer {
  100% {
    transform: translateX(100%);
  }
}

@media (max-width: 1480px) {
  .wisdom-artifact-workspace {
    left: 430px;
    right: 20px;
  }

  .wisdom-chat.has-artifact {
    left: 20px;
    right: auto;
    width: 390px;
  }

  .wisdom-artifact-heading strong {
    max-width: 520px;
  }

  .wisdom-side {
    top: 112px;
    bottom: 16px;
    width: 318px;
  }

  .wisdom-side-left {
    left: 20px;
  }

  .wisdom-side-right {
    right: 20px;
  }

  .wisdom-side-chart.smart-chart-card {
    height: 320px;
  }

  .wisdom-side-chart .smart-chart {
    height: 236px;
  }

  .wisdom-chat {
    width: clamp(560px, calc(100% - 760px), 760px);
  }
}

@media (max-width: 1280px) {
  .wisdom-side {
    display: none;
  }

  .wisdom-chat {
    width: min(860px, calc(100% - 80px));
  }

  .wisdom-artifact-workspace {
    left: 374px;
    right: 16px;
  }

  .wisdom-chat.has-artifact {
    left: 16px;
    right: auto;
    width: 342px;
  }

  .wisdom-artifact-heading strong {
    max-width: 360px;
  }

  .wisdom-artifact-tools {
    gap: 8px;
  }

  .wisdom-artifact-status {
    display: none;
  }
}
</style>
