<template>
  <div class="app-layout">
    <!-- 左侧侧边栏 -->
    <aside class="sidebar">
      <div class="brand">
        <span class="icon">🩺</span>
        <h1>体检中心</h1>
      </div>
      <nav class="nav-menu">
        <button 
          class="nav-item" 
          :class="{ active: currentTab === 'overview' }"
          @click="currentTab = 'overview'"
        >
          <span class="nav-icon">📊</span> 静态概览
        </button>
        <button 
          class="nav-item" 
          :class="{ active: currentTab === 'bsod' }"
          @click="currentTab = 'bsod'"
        >
          <span class="nav-icon">☠️</span> 蓝屏分析
        </button>
      </nav>
      <div class="sidebar-footer">
        <span class="version">Pro v1.2</span>
      </div>
    </aside>

    <!-- 右侧主内容区 -->
    <main class="main-content">
      
      <!-- TAB 1: 概览 -->
      <div v-if="currentTab === 'overview'" class="tab-view overview-view">
        <div class="view-header">
          <h2>系统健康概览</h2>
          <div class="actions-row">
             <button @click="startScan" :disabled="loading" class="primary-btn" :class="{ 'scanning': loading }">
              <span v-if="loading" class="icon-spin">🔄</span>
              <span v-else>🔍 全面体检</span>
            </button>
            <div class="sub-actions">
              <button class="icon-btn" @click="triggerImport" :disabled="loading">📂 导入</button>
              <button class="icon-btn" @click="exportReport" :disabled="!isReportValid || loading">💾 导出</button>
            </div>
          </div>
        </div>

        <!-- 状态提示 -->
        <div v-if="errorMsg" class="message-box error">⚠️ {{ errorMsg }}</div>
        <div v-if="scanFinished" class="message-box success">✅ 扫描完成</div>

        <input type="file" ref="fileInput" @change="handleFileImport" accept=".json" style="display: none" />

        <!-- 卡片展示区 -->
        <div v-if="report.hardware" class="dashboard fade-in">
          <!-- 1. 硬件概览 (强制独占一行) -->
          <div class="card summary slide-up">
            <div class="card-header">
              <h3>🖥️ 硬件概览与资源占用</h3>
            </div>
            <div class="grid-container-summary">
              <div class="basic-info">
                <div class="info-item"><span class="label">CPU</span><span class="value text-ellipsis" :title="report.hardware.cpu_name">{{ report.hardware.cpu_name }}</span></div>
                <div class="info-item"><span class="label">System</span><span class="value text-ellipsis">{{ report.hardware.sys_vendor }} {{ report.hardware.sys_product }}</span></div>
                <div class="info-item"><span class="label">Mobo</span><span class="value text-ellipsis">{{ report.hardware.mobo_vendor }} {{ report.hardware.mobo_product }}</span></div>
                <div class="info-item"><span class="label">BIOS</span><span class="value text-ellipsis">{{ report.hardware.bios_version }}</span></div>
              </div>
              <div class="usage-bars">
                <div class="usage-item">
                  <div class="progress-label">
                    <span class="text-ellipsis">C盘 ({{ report.hardware.c_drive_used_gb }}/{{ report.hardware.c_drive_total_gb }}GB)</span>
                    <strong>{{ calculatePercent(report.hardware.c_drive_used_gb, report.hardware.c_drive_total_gb) }}%</strong>
                  </div>
                  <div class="progress-bar-large"><div class="fill" :style="getProgressStyle(report.hardware.c_drive_used_gb, report.hardware.c_drive_total_gb)"></div></div>
                </div>
                <div class="usage-item">
                  <div class="progress-label">
                    <span class="text-ellipsis">内存 ({{ report.hardware.memory_used_gb }}/{{ report.hardware.memory_total_gb }}GB)</span>
                    <strong>{{ calculatePercent(report.hardware.memory_used_gb, report.hardware.memory_total_gb) }}%</strong>
                  </div>
                  <div class="progress-bar-large"><div class="fill" :style="getProgressStyle(report.hardware.memory_used_gb, report.hardware.memory_total_gb)"></div></div>
                </div>
              </div>
            </div>
          </div>

          <!-- 2. 驱动状态 -->
          <div v-if="report.drivers" class="card slide-up" :class="{ danger: report.drivers.length > 0, success: report.drivers.length === 0 }">
            <div class="card-header">
              <h3>🔌 驱动状态</h3>
              <span class="badge" :class="report.drivers.length > 0 ? 'badge-red' : 'badge-green'">
                {{ report.drivers.length > 0 ? '异常' : '正常' }}
              </span>
            </div>
            <div v-if="report.drivers.length > 0" class="list-container">
              <div v-for="(drv, idx) in report.drivers" :key="idx" class="list-item error-item">
                <div class="item-header">
                  <strong class="text-ellipsis" :title="drv.device_name">{{ drv.device_name }}</strong>
                  <span class="code-tag">Code {{ drv.error_code }}</span>
                </div>
                <p class="description">{{ drv.description }}</p>
              </div>
            </div>
            <div v-else class="good-news">设备管理器无异常。</div>
          </div>

          <!-- 3. 电池健康 -->
          <div v-if="report.battery" class="card slide-up" :class="{ danger: report.battery.health_percentage < 60 }">
            <div class="card-header">
              <h3>🔋 电池健康</h3>
              <span class="badge badge-blue">{{ report.battery.health_percentage }}%</span>
            </div>
            <div class="content-box">
              <div class="progress-bar"><div class="fill" :style="{ width: report.battery.health_percentage + '%', background: getBatteryColor(report.battery.health_percentage) }"></div></div>
              <p class="description mt-2">{{ report.battery.explanation }}</p>
            </div>
          </div>

          <!-- 4. 硬盘健康 -->
          <div v-if="report.storage" class="card slide-up" :class="{ danger: hasStorageDanger }">
            <div class="card-header">
              <h3>💾 硬盘 S.M.A.R.T</h3>
            </div>
            <div class="list-container">
              <div v-for="(disk, index) in report.storage" :key="index" class="list-item">
                <div class="item-header">
                  <strong class="text-ellipsis" :title="disk.model">{{ disk.model }}</strong>
                  <span class="status-text" :class="disk.is_danger ? 'text-red' : 'text-green'">{{ disk.health_status }}</span>
                </div>
                <p class="description">{{ disk.human_explanation }}</p>
              </div>
            </div>
          </div>

          <!-- 5. 日志卡片 -->
          <div v-if="report.events" class="card slide-up" :class="{ danger: report.events.length > 0 }">
            <div class="card-header">
              <h3>⚡ 关键日志</h3>
            </div>
            <div v-if="report.events.length > 0" class="list-container">
              <div v-for="(evt, idx) in report.events" :key="idx" class="list-item warning-item">
                <div class="item-header">
                  <span class="event-id">ID: {{ evt.event_id }}</span>
                  <span class="event-source" :title="evt.source">{{ evt.source }}</span>
                  <span class="event-time">{{ formatTime(evt.time_generated) }}</span>
                </div>
                <p class="description highlight">{{ evt.analysis_hint }}</p>
                <p v-if="evt.message" class="description raw-message">{{ evt.message }}</p>
              </div>
            </div>
            <div v-else class="good-news">无致命错误日志。</div>
          </div>
        </div>
      </div>

      <!-- TAB 2: 蓝屏分析 -->
      <div v-if="currentTab === 'bsod'" class="tab-view bsod-view">
        <div class="view-header">
          <h2>蓝屏死机分析 (Minidump)</h2>
          <!-- 按钮组 -->
          <div class="actions-row">
            <button class="secondary-btn" @click="triggerBsodImport" :disabled="bsodAnalyzing">📂 导入文件</button>
            <button class="secondary-btn" @click="loadMinidumps" :disabled="bsodLoading">🔄 刷新列表</button>
          </div>
        </div>

        <!-- 隐藏的 BSOD 文件输入框 -->
        <input type="file" ref="bsodFileInput" @change="handleBsodFileImport" accept=".dmp" style="display: none" />

        <div class="bsod-layout">
          <div class="bsod-list-panel">
            <div v-if="bsodList.length === 0 && !bsodLoading" class="empty-state">
              未发现 Minidump 文件。<br>系统可能未启用转储或已被清理。
            </div>
            <div v-else class="file-list">
              <div 
                v-for="file in bsodList" 
                :key="file.path" 
                class="file-item"
                :class="{ active: selectedBsod?.path === file.path }"
                @click="analyzeBsod(file)"
              >
                <div class="file-icon">📄</div>
                <div class="file-info">
                  <div class="file-name">{{ file.filename }}</div>
                  <div class="file-meta">{{ file.created_time }} · {{ file.size_kb }}KB</div>
                </div>
              </div>
            </div>
          </div>

          <div class="bsod-detail-panel">
            <div v-if="bsodAnalyzing" class="analyzing-state">
              <div class="spinner"></div>
              <p>正在解析 Dump 文件，可能需要几秒钟...</p>
            </div>
            <div v-else-if="bsodResult" class="analysis-result fade-in">
              <div class="result-header">
                <h3>{{ bsodResult.crash_reason }}</h3>
                <span class="code-pill">{{ bsodResult.bug_check_code }}</span>
              </div>
              
              <div class="human-analysis card-section">
                <h4>🤖 智能分析</h4>
                <p class="human-text">{{ bsodResult.human_analysis }}</p>
                <div class="recommendation">
                  <strong>建议操作：</strong> {{ bsodResult.recommendation }}
                </div>
              </div>

              <div class="tech-details card-section">
                <h4>🔬 技术细节</h4>
                <div class="detail-grid">
                  <div class="d-item"><span class="d-label">崩溃地址</span>{{ bsodResult.crash_address }}</div>
                  <div class="d-item"><span class="d-label">相关线程</span>{{ bsodResult.crashing_thread || 'N/A' }}</div>
                </div>
              </div>
            </div>
            <div v-else class="empty-detail">
              👈 请从左侧选择一个蓝屏文件开始分析，<br>或点击上方“导入文件”分析外部文件
            </div>
          </div>
        </div>
      </div>

    </main>

    <!-- Toast 通知 -->
    <transition name="toast-slide">
      <div v-if="toast.show" class="toast-notification" :class="toast.type">
        <div class="toast-content">
          <span class="check-icon">{{ toast.type === 'error' ? '❌' : '✅' }}</span>
          <div class="toast-text"><h4>{{ toast.title }}</h4><p>{{ toast.message }}</p></div>
        </div>
        <div class="toast-progress"></div>
      </div>
    </transition>
  </div>
</template>

<script setup>
import { ref, computed, onUnmounted, reactive, onMounted, watch } from 'vue';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';

// --- 状态管理 ---
const currentTab = ref('overview'); // 'overview' | 'bsod'

// 概览相关
const emptyReport = () => ({ hardware: null, storage: null, events: null, minidumps: null, drivers: null, battery: null });
const report = ref(emptyReport());
const loading = ref(false);
const errorMsg = ref('');
const scanFinished = ref(false);
const fileInput = ref(null);
let unlistenFns = [];

// BSOD 相关
const bsodList = ref([]);
const selectedBsod = ref(null);
const bsodResult = ref(null);
const bsodLoading = ref(false);
const bsodAnalyzing = ref(false);
const bsodFileInput = ref(null); // 新增 BSOD 文件输入引用

const toast = reactive({ show: false, title: '', message: '', type: 'success' });
let toastTimer = null;

const hasStorageDanger = computed(() => report.value?.storage?.some(d => d.is_danger) || false);
const isReportValid = computed(() => report.value && (report.value.hardware || report.value.storage));

// --- 辅助函数 (保留) ---
function calculatePercent(used, total) { return (!total || total === 0) ? 0 : Math.round((used / total) * 100); }
function getProgressStyle(used, total) {
  const percent = calculatePercent(used, total);
  let color = percent >= 90 ? '#ff4757' : (percent >= 75 ? '#ffa502' : '#2ed573');
  return { width: `${percent}%`, background: color };
}
function getBatteryColor(p) { return p < 50 ? '#ff4757' : (p < 80 ? '#ffa502' : '#2ed573'); }
function formatTime(t) { return !t ? "Unknown Time" : t.replace('T', ' ').substring(0, 19); }

// --- 概览：导出/导入 ---
async function exportReport() {
  if (!isReportValid.value) return;
  const fileName = `SystemDoctor_Report_${new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-")}.json`;
  const content = JSON.stringify(report.value, null, 2);
  if ('showSaveFilePicker' in window) {
    try {
      const handle = await window.showSaveFilePicker({ suggestedName: fileName, types: [{ description: 'JSON Report', accept: { 'application/json': ['.json'] }, }], });
      const writable = await handle.createWritable(); await writable.write(content); await writable.close();
      triggerToast('导出成功', '文件已保存到指定位置', 'success'); return;
    } catch (err) { if (err.name === 'AbortError') return; }
  }
  try {
    const blob = new Blob([content], { type: "application/json" }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url);
    triggerToast('导出成功', '已保存到默认下载目录', 'success');
  } catch (err) { triggerToast('导出失败', err.message, 'error'); }
}
function triggerImport() { fileInput.value.click(); }
function handleFileImport(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { const json = JSON.parse(e.target.result); if (json && (json.hardware || json.storage)) { report.value = json; scanFinished.value = false; triggerToast('导入成功', '已加载历史报告'); } else { triggerToast('导入失败', '文件格式错误', 'error'); } } catch (err) { triggerToast('解析失败', err.message, 'error'); } }; reader.readAsText(file); event.target.value = ''; }

async function startScan() {
  report.value = emptyReport(); errorMsg.value = ''; scanFinished.value = false; loading.value = true;
  if (unlistenFns.length > 0) { for (const fn of unlistenFns) fn(); unlistenFns = []; }
  try {
    unlistenFns.push(
      await listen('report-hardware', (e) => report.value.hardware = e.payload),
      await listen('report-storage', (e) => report.value.storage = e.payload),
      await listen('report-drivers', (e) => report.value.drivers = e.payload),
      await listen('report-minidumps', (e) => report.value.minidumps = e.payload),
      await listen('report-battery', (e) => report.value.battery = e.payload),
      await listen('report-events', (e) => report.value.events = e.payload),
      await listen('diagnosis-finished', () => { loading.value = false; scanFinished.value = true; triggerToast('扫描完成', '体检已结束', 'success'); })
    );
    await invoke('run_diagnosis');
  } catch (e) { loading.value = false; errorMsg.value = e; }
}

// --- BSOD 功能 ---
async function loadMinidumps() { bsodLoading.value = true; try { bsodList.value = await invoke('list_minidumps'); } catch (e) { triggerToast('加载失败', e, 'error'); } finally { bsodLoading.value = false; } }

async function analyzeBsod(file) { if (bsodAnalyzing.value) return; selectedBsod.value = file; bsodResult.value = null; bsodAnalyzing.value = true; try { bsodResult.value = await invoke('analyze_minidump', { filepath: file.path }); } catch (e) { triggerToast('分析失败', e, 'error'); } finally { bsodAnalyzing.value = false; } }

// [新增] BSOD 导入功能
function triggerBsodImport() { bsodFileInput.value.click(); }
function handleBsodFileImport(event) {
  const file = event.target.files[0];
  if (!file) return;
  
  // 更新 UI 状态，模拟选中了一个“外部文件”
  selectedBsod.value = { path: 'external', filename: file.name, created_time: 'Imported', size_kb: Math.round(file.size / 1024) };
  bsodResult.value = null;
  bsodAnalyzing.value = true;

  const reader = new FileReader();
  reader.onload = async (e) => {
    try {
      // 将 ArrayBuffer 转换为 Uint8Array (Rust Vec<u8>)
      const arrayBuffer = e.target.result;
      const bytes = new Uint8Array(arrayBuffer);
      const byteArray = Array.from(bytes); // 转换为普通数组以便序列化传输

      const result = await invoke('analyze_minidump_bytes', { fileContent: byteArray });
      bsodResult.value = result;
      triggerToast('分析成功', '已完成外部文件解析', 'success');
    } catch (err) {
      triggerToast('分析失败', err, 'error');
    } finally {
      bsodAnalyzing.value = false;
    }
  };
  reader.readAsArrayBuffer(file);
  event.target.value = '';
}

watch(currentTab, (newVal) => { if (newVal === 'bsod' && bsodList.value.length === 0) loadMinidumps(); });

function triggerToast(title, message, type = 'success') { toast.title = title; toast.message = message; toast.type = type; toast.show = true; if (toastTimer) clearTimeout(toastTimer); toastTimer = setTimeout(() => { toast.show = false; }, 3000); }
onUnmounted(() => { for (const fn of unlistenFns) fn(); if (toastTimer) clearTimeout(toastTimer); });
</script>

<style>
body { margin: 0; padding: 0; background-color: #f4f6f9; overflow: hidden; }
</style>

<style scoped>
.app-layout { display: flex; height: 100vh; width: 100vw; overflow: hidden; background-color: #f4f6f9; }
.sidebar { width: 240px; background: #2c3e50; color: white; display: flex; flex-direction: column; padding: 20px 0; box-shadow: 2px 0 10px rgba(0,0,0,0.1); z-index: 10; }
.brand { padding: 0 20px 30px; display: flex; align-items: center; gap: 12px; }
.brand .icon { font-size: 1.8rem; } .brand h1 { font-size: 1.2rem; margin: 0; font-weight: 700; color: white; }
.nav-menu { flex: 1; display: flex; flex-direction: column; gap: 5px; padding: 0 10px; }
.nav-item { background: transparent; border: none; color: #bdc3c7; padding: 12px 15px; font-size: 1rem; cursor: pointer; text-align: left; border-radius: 8px; transition: all 0.2s; display: flex; align-items: center; gap: 12px; }
.nav-item:hover { background: rgba(255,255,255,0.1); color: white; }
.nav-item.active { background: #2ecc71; color: white; font-weight: 600; box-shadow: 0 4px 10px rgba(46, 204, 113, 0.3); }
.nav-icon { font-size: 1.2rem; }
.sidebar-footer { padding: 0 20px; text-align: center; color: #7f8c8d; font-size: 0.8rem; }
.main-content { flex: 1; overflow-y: auto; padding: 30px 40px; position: relative; }

.view-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; }
.view-header h2 { margin: 0; font-size: 1.8rem; color: #2c3e50; }
.actions-row { display: flex; align-items: center; gap: 15px; }
.sub-actions { display: flex; gap: 10px; }

.dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 20px; }
.card { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.03); border: 1px solid #eaecf0; border-top: 3px solid #2ecc71; }
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #f0f2f5; }
.card-header h3 { margin: 0; font-size: 1.1rem; font-weight: 600; }

.item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; gap: 12px; }
.progress-label { display: flex; justify-content: space-between; font-size: 0.85rem; color: #636e72; gap: 10px; }
.text-ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.item-header strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1; }
.status-text, .code-tag, .badge { flex-shrink: 0; white-space: nowrap; }
.event-id { font-weight: bold; color: #2c3e50; background: #e2e8f0; padding: 1px 5px; border-radius: 3px; font-size: 0.75rem; flex-shrink: 0; }
.event-source { font-size: 0.75rem; color: #7f8c8d; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 0 5px; text-align: left; }
.event-time { font-size: 0.75rem; color: #95a5a6; flex-shrink: 0; white-space: nowrap; }
.badge { font-size: 0.75rem; padding: 3px 10px; border-radius: 12px; color: white; font-weight: 600; letter-spacing: 0.5px; white-space: nowrap; flex-shrink: 0; }

.grid-container-summary { display: grid; grid-template-columns: 1fr 1.5fr; gap: 25px; }
@media (max-width: 900px) { .grid-container-summary { grid-template-columns: 1fr; } }
.basic-info, .usage-bars { display: flex; flex-direction: column; gap: 12px; }
.usage-bars { padding-top: 5px; }
.usage-item { display: flex; flex-direction: column; gap: 6px; }
.info-item { display: flex; flex-direction: column; }
.label { font-size: 0.75rem; color: #95a5a6; margin-bottom: 2px; text-transform: uppercase; font-weight: 600; }
.value { font-size: 1rem; font-weight: 500; color: #2c3e50; }
.progress-bar-large { width: 100%; height: 16px; background: #f1f3f5; border-radius: 8px; overflow: hidden; }
.fill { height: 100%; transition: width 0.6s ease; }
.list-container { display: flex; flex-direction: column; gap: 10px; }
.list-item { background: #f8f9fa; padding: 10px 14px; border-radius: 6px; border: 1px solid #edf2f7; }
.list-item.error-item { background: #fff5f5; border-color: #fed7d7; }
.list-item.warning-item { background: #fffaf0; border-color: #fce588; }
.description { margin: 0; color: #636e72; font-size: 0.9rem; line-height: 1.4; }
.description.highlight { color: #d35400; font-weight: 500; }
.description.raw-message { margin-top: 6px; font-size: 0.8rem; color: #7f8c8d; font-family: Consolas, monospace; background: #fff; padding: 4px 8px; border-radius: 4px; border: 1px solid #eee; word-break: break-all; }
.text-green { color: #27ae60; } .text-red { color: #c0392b; }
.badge-red { background-color: #ff4757; } .badge-green { background-color: #2ed573; } .badge-blue { background-color: #3498db; } .badge-gray { background-color: #95a5a6; }
.code-tag { background: #ff4757; color: white; padding: 1px 5px; border-radius: 3px; font-size: 0.75rem; font-weight: bold; }
.good-news { color: #27ae60; font-weight: 600; background: #eafaf1; padding: 12px; border-radius: 6px; border: 1px solid #d4efdf; text-align: center; font-size: 0.9rem; }
.tip { margin-top: 12px; font-size: 0.85rem; color: #d35400; background: #fff3e0; padding: 10px; border-radius: 6px; border: 1px solid #ffe0b2; }
.progress-wrapper { margin-bottom: 12px; }
.progress-bar { width: 100%; height: 8px; background: #f1f3f5; border-radius: 4px; overflow: hidden; }
.content-box { padding: 5px 0; } .main-text { font-weight: 500; color: #2c3e50; margin-bottom: 8px; }
.card.danger { border-top-color: #ff4757; }

.card.summary { border-top-color: #3498db; grid-column: 1 / -1; }

.primary-btn { background: #2ecc71; color: white; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; font-weight: 600; display: flex; align-items: center; gap: 8px; transition: 0.2s; }
.primary-btn:hover:not(:disabled) { background: #27ae60; } .primary-btn:disabled { background: #bdc3c7; cursor: not-allowed; }
.secondary-btn { background: white; border: 1px solid #dcdfe6; color: #606266; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 0.9rem; }
.secondary-btn:hover:not(:disabled) { border-color: #2ecc71; color: #2ecc71; }
.icon-btn { background: transparent; border: none; cursor: pointer; padding: 8px; color: #7f8c8d; font-weight: 600; }
.icon-btn:hover:not(:disabled) { color: #2ecc71; background: #eafaf1; border-radius: 6px; }
.toast-notification { position: fixed; top: 20px; right: 20px; background: white; border-left: 5px solid #2ecc71; padding: 15px 20px; border-radius: 8px; box-shadow: 0 5px 20px rgba(0,0,0,0.15); z-index: 100; min-width: 250px; }
.toast-notification.error { border-left-color: #ff4757; }
.toast-content { display: flex; gap: 12px; } .toast-text h4 { margin: 0 0 4px; font-size: 1rem; } .toast-text p { margin: 0; color: #7f8c8d; font-size: 0.85rem; }
.toast-slide-enter-active, .toast-slide-leave-active { transition: all 0.3s; } .toast-slide-enter-from, .toast-slide-leave-to { transform: translateX(100%); opacity: 0; }
@keyframes spin { 100% { transform: rotate(360deg); } }
.fade-in { animation: fadeIn 0.4s ease-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.slide-up { animation: slideUp 0.4s ease-out forwards; } @keyframes slideUp { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
.bsod-layout { display: grid; grid-template-columns: 300px 1fr; gap: 20px; height: calc(100vh - 120px); }
.bsod-list-panel { background: white; border-radius: 10px; border: 1px solid #eaecf0; overflow-y: auto; }
.bsod-detail-panel { background: white; border-radius: 10px; border: 1px solid #eaecf0; padding: 25px; overflow-y: auto; position: relative; }
.file-item { padding: 15px; border-bottom: 1px solid #f0f2f5; cursor: pointer; display: flex; gap: 12px; transition: background 0.2s; }
.file-item:hover { background: #f8f9fa; } .file-item.active { background: #eafaf1; border-left: 4px solid #2ecc71; }
.file-icon { font-size: 1.5rem; } .file-name { font-weight: 600; font-size: 0.9rem; color: #2c3e50; margin-bottom: 4px; } .file-meta { font-size: 0.8rem; color: #95a5a6; }
.empty-state { padding: 40px; text-align: center; color: #95a5a6; font-size: 0.9rem; line-height: 1.6; }
.analyzing-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #7f8c8d; }
.spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #2ecc71; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 15px; }
.empty-detail { display: flex; align-items: center; justify-content: center; height: 100%; color: #95a5a6; font-size: 1.1rem; }
.result-header { border-bottom: 1px solid #eee; padding-bottom: 15px; margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; }
.result-header h3 { margin: 0; color: #c0392b; font-size: 1.4rem; } .code-pill { background: #2c3e50; color: white; padding: 4px 10px; border-radius: 4px; font-family: monospace; font-weight: bold; }
.card-section { margin-bottom: 25px; } .card-section h4 { margin: 0 0 10px 0; font-size: 1rem; color: #7f8c8d; text-transform: uppercase; letter-spacing: 0.5px; border-left: 3px solid #2ecc71; padding-left: 10px; }
.human-text { font-size: 1.1rem; color: #2c3e50; line-height: 1.6; margin-bottom: 10px; }
.recommendation { background: #eafaf1; color: #27ae60; padding: 15px; border-radius: 8px; font-weight: 500; }
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; } .d-item { background: #f8f9fa; padding: 10px; border-radius: 6px; display: flex; flex-direction: column; } .d-label { font-size: 0.75rem; color: #95a5a6; margin-bottom: 4px; }
.message-box { padding: 10px 15px; border-radius: 6px; margin-bottom: 15px; font-size: 0.9rem; font-weight: 500; }
.message-box.success { background-color: #eafaf1; color: #27ae60; border: 1px solid #d4efdf; }
.message-box.error { background-color: #ffeaea; color: #c0392b; border: 1px solid #ffcccc; }
</style>