<script setup lang="ts">
import { onMounted, onUnmounted, ref, computed, watch } from 'vue'
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import { ArrowLeft, Bot, Activity, RefreshCw } from '@lucide/vue'
import { apiFetch } from '../services/api'
import {
  applyAgentFileWrite,
  useAgentActivityQuery,
  useAgentDetailQuery,
  useAgentFileQuery,
  useAgentFilesQuery,
  useAgentSummaryQuery,
  type AgentActivityDto,
  type AgentFileDto,
  type AgentFileWriteDto,
} from '../api/agentDetail'
import { queryClient, queryKeys } from '../api/queryClient'
import ConfigTabs from '../components/config/ConfigTabs.vue'
import ConfigEditor from '../components/config/ConfigEditor.vue'
import AgentWorkspaceBrowser from '../components/config/AgentWorkspaceBrowser.vue'
import StandingOrdersEditor from '../components/config/StandingOrdersEditor.vue'
import { subscribeDomainEventState } from '../services/domainEvents'
import { createMutationRequestContext } from '../services/mutationContext'
import { useAuthStore } from '../stores/auth'
import AsyncStatePanel from '../components/mission-control/AsyncStatePanel.vue'

const route = useRoute()
const router = useRouter()
const auth = useAuthStore()

const activeTab = ref(0)
const liveConnected = ref(false)
const liveUnavailable = ref(false)
let activityReloadTimer: ReturnType<typeof setTimeout> | null = null
let unsubscribeDomainState: (() => void) | null = null

interface EditorState {
  content: string
  savedContent: string
  saving: boolean
  dirty: boolean
  saveStatus: 'idle' | 'saved' | 'error'
  saveMessage: string
  backupStatus: string
  reloadStatus: string
  reloadMessage: string
  contentHash: string
  verified: boolean
}

const editorState = ref<EditorState>({
  content: '',
  savedContent: '',
  saving: false,
  dirty: false,
  saveStatus: 'idle',
  saveMessage: '',
  backupStatus: 'not_applicable',
  reloadStatus: 'not_supported',
  reloadMessage: '',
  contentHash: '',
  verified: false,
})

const agentId = route.params.id as string
const canConfigure = computed(() => auth.user?.role === 'owner')
const agentQuery = useAgentDetailQuery(agentId)
const activityQuery = useAgentActivityQuery(agentId)
const summaryQuery = useAgentSummaryQuery(agentId)
const filesQuery = useAgentFilesQuery(agentId, canConfigure)
const agent = computed(() => agentQuery.data.value ?? null)
const activityItems = computed(() => activityQuery.data.value ?? [])
const summary = computed(() => summaryQuery.data.value ?? null)
const configFiles = computed(() => filesQuery.data.value?.files ?? [])
const loading = computed(() => agentQuery.isPending.value)
const activityLoading = computed(() => activityQuery.isFetching.value)
const summaryLoading = computed(() => summaryQuery.isFetching.value)

const currentFile = computed(() => {
  if (!configFiles.value.length) return null
  const activeFile = configFiles.value[activeTab.value]
  return activeFile || configFiles.value[0]
})

const activeTabFileName = computed(() => {
  return currentFile.value?.name || null
})
const requestedFileName = computed(() =>
  typeof route.query.file === 'string' ? route.query.file : '',
)
const fileQuery = useAgentFileQuery(
  agentId,
  computed(() => activeTabFileName.value ?? ''),
  canConfigure,
)
const configsLoading = computed(() =>
  canConfigure.value
  && (
    filesQuery.isPending.value
    || (Boolean(activeTabFileName.value) && fileQuery.isFetching.value)
  ),
)
const configsError = computed(() => {
  if (!canConfigure.value) {
    return 'Nur Owner dürfen sensible OpenClaw-Agentdateien lesen und bearbeiten.'
  }
  const cause = fileQuery.error.value ?? filesQuery.error.value
  return cause instanceof Error ? cause.message : ''
})
const initLoading = computed(() =>
  loading.value,
)

const fallbackName = computed(() => {
  return agentId.charAt(0).toUpperCase() + agentId.slice(1)
})

function formatFileSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
}

function formatModifiedAt(dateStr: string): string {
  const d = new Date(dateStr)
  return d.toLocaleDateString('de-DE', {
    year: 'numeric', month: 'short', day: 'numeric',
    hour: '2-digit', minute: '2-digit',
  })
}

const statusColor = (status: string): string => {
  switch (status) {
    case 'Online': return 'var(--st-work)'
    case 'Degraded': return 'var(--st-queue)'
    case 'Offline': return 'var(--st-block)'
    default: return 'var(--st-idle)'
  }
}

function formatLastSeen(dateStr?: string): string {
  if (!dateStr) return 'N/A'
  const d = new Date(dateStr)
  return d.toLocaleDateString('de-DE', {
    year: 'numeric', month: 'short', day: 'numeric',
    hour: '2-digit', minute: '2-digit',
  })
}

function formatActivityTime(item: AgentActivityDto): string {
  if (item.relativeTime) return item.relativeTime
  const d = new Date(item.at)
  return d.toLocaleDateString('de-DE', {
    month: 'short', day: 'numeric',
    hour: '2-digit', minute: '2-digit',
  })
}

function activityTypeLabel(type: string): string {
  if (type === 'thinking') return 'Thinking'
  if (type === 'handoff') return 'Handoff'
  if (type === 'task') return 'Task'
  return 'Activity'
}

function scheduleActivityReload() {
  if (activityReloadTimer) return
  activityReloadTimer = setTimeout(async () => {
    activityReloadTimer = null
    await Promise.allSettled([
      queryClient.invalidateQueries({ queryKey: queryKeys.agentActivity(agentId) }),
      queryClient.invalidateQueries({ queryKey: queryKeys.agentSummary(agentId) }),
    ])
  }, 250)
}

function retryAgent() {
  void agentQuery.refetch()
}

function retrySummary() {
  void summaryQuery.refetch()
}

function retryActivity() {
  void activityQuery.refetch()
}

function retryConfigs() {
  void filesQuery.refetch()
  if (activeTabFileName.value) void fileQuery.refetch()
}

function formatSummaryTimestamp(value?: string | null): string {
  if (!value) return 'No timestamp'
  const d = new Date(value)
  return d.toLocaleDateString('de-DE', {
    month: 'short', day: 'numeric',
    hour: '2-digit', minute: '2-digit',
  })
}

function summarySourceLabel(source: string): string {
  switch (source) {
    case 'nexus-activity': return 'Nexus activity'
    case 'gateway-session-history': return 'Gateway history'
    case 'derived-mixed': return 'Derived from mixed feed'
    case 'none': return 'No data'
    default: return source
  }
}

function onDomainEvent(event: Event) {
  const detail = (event as CustomEvent<{
    eventType?: string
    entity?: { type?: string }
    payload?: { agentIds?: unknown[] }
  }>).detail
  if (detail?.eventType !== 'activity.created' || detail.entity?.type !== 'activity') return
  const agentIds = Array.isArray(detail.payload?.agentIds)
    ? detail.payload.agentIds.map(id => String(id).toLowerCase())
    : []
  if (agentIds.includes(agentId.toLowerCase())) scheduleActivityReload()
}

function hydrateEditor(data: AgentFileDto) {
  if (editorState.value.dirty || editorState.value.saving) return
  editorState.value = {
    content: data.content ?? '',
    savedContent: data.content ?? '',
    saving: false,
    dirty: false,
    saveStatus: 'idle',
    saveMessage: data.missing ? 'Datei fehlt noch und wird beim ersten Speichern angelegt.' : '',
    backupStatus: 'not_applicable',
    reloadStatus: 'not_supported',
    reloadMessage: 'Nexus meldet erst nach erfolgreichem OpenClaw-Read-back „verifiziert“.',
    contentHash: data.contentHash,
    verified: false,
  }
}

function refreshActivity(): void {
  void Promise.allSettled([
    activityQuery.refetch(),
    summaryQuery.refetch(),
  ])
}

watch(
  () => fileQuery.data.value,
  data => {
    if (data) hydrateEditor(data)
  },
  { immediate: true },
)

watch(
  () => configFiles.value.length,
  length => {
    if (!length || activeTab.value >= length) activeTab.value = 0
  },
  { immediate: true },
)

watch(
  [configFiles, requestedFileName],
  ([files, requested]) => {
    if (!requested || editorState.value.dirty) return
    const index = files.findIndex(file => file.name === requested)
    if (index >= 0) activeTab.value = index
  },
  { immediate: true },
)

async function switchTab(index: number) {
  if (activeTab.value === index) return
  if (editorState.value.dirty &&
      !window.confirm('Ungespeicherte Änderungen verwerfen und eine andere Datei öffnen?')) {
    return
  }
  activeTab.value = index
  const fileName = configFiles.value[index]?.name
  if (fileName && route.query.file !== fileName) {
    await router.replace({ query: { ...route.query, file: fileName } })
  }
}

function onContentChange(value: string) {
  editorState.value.content = value
  editorState.value.dirty = value !== editorState.value.savedContent
}

async function saveFile() {
  const fileName = activeTabFileName.value
  if (!fileName || !editorState.value.dirty) return

  editorState.value.saving = true
  editorState.value.saveStatus = 'idle'
  editorState.value.saveMessage = ''
  editorState.value.backupStatus = 'not_applicable'
  editorState.value.reloadStatus = 'not_supported'
  editorState.value.reloadMessage = ''
  editorState.value.verified = false

  try {
    const requestContext = createMutationRequestContext(
      'openclaw-agent-file-set',
      `${agentId}:${fileName}:${editorState.value.contentHash}`,
    )
    const response = await apiFetch(
      `/api/v1/openclaw/agents/${encodeURIComponent(agentId)}/files/${encodeURIComponent(fileName)}`,
      {
      method: 'PUT',
      headers: requestContext.headers,
      body: JSON.stringify({
        content: editorState.value.content,
        expectedHash: editorState.value.contentHash,
      }),
    })

    if (!response.ok) {
      const err = await response.json().catch(() => ({}))
      const problem = err as {
        detail?: string
        error?: string
        message?: string
        errors?: Record<string, string[]>
        currentHash?: string
      }
      const detail = problem.detail
        || problem.message
        || problem.error
        || Object.values(problem.errors ?? {}).flat().join(' ')
        || 'Failed to save file'
      if (response.status === 409 && problem.currentHash) {
        editorState.value.reloadMessage = 'OpenClaw enthält eine neuere Version. Lade die Datei neu, bevor du erneut speicherst.'
      }
      throw new Error(detail)
    }

    const result: AgentFileWriteDto = await response.json()
    editorState.value.content = result.file.content ?? editorState.value.content
    editorState.value.savedContent = editorState.value.content
    editorState.value.dirty = false
    editorState.value.saveStatus = 'saved'
    editorState.value.saveMessage = result.message
    editorState.value.backupStatus = 'not_applicable'
    editorState.value.reloadStatus = result.verified ? 'verified' : 'not_supported'
    editorState.value.reloadMessage = result.verified
      ? 'OpenClaw hat den gespeicherten Inhalt identisch zurückgegeben.'
      : 'Der Runtime-Reload wurde nicht bestätigt.'
    editorState.value.contentHash = result.file.contentHash
    editorState.value.verified = result.verified

    await applyAgentFileWrite(queryClient, agentId, result)

    setTimeout(() => {
      if (editorState.value.saveStatus === 'saved') {
        editorState.value.saveStatus = 'idle'
        editorState.value.saveMessage = ''
      }
    }, 2000)
  } catch (e) {
    editorState.value.saveStatus = 'error'
    editorState.value.saveMessage = e instanceof Error ? e.message : 'Failed to save file'
    editorState.value.backupStatus = 'not_applicable'
    editorState.value.reloadStatus = 'not_supported'
    editorState.value.verified = false
  } finally {
    editorState.value.saving = false
  }
}

onMounted(() => {
  window.addEventListener('nexus:domain-event', onDomainEvent)
  unsubscribeDomainState = subscribeDomainEventState(state => {
    liveConnected.value = state === 'open'
    liveUnavailable.value = state === 'unsupported' || state === 'error'
  })
})

function onBeforeUnload(event: BeforeUnloadEvent) {
  if (!editorState.value.dirty) return
  event.preventDefault()
  event.returnValue = ''
}

window.addEventListener('beforeunload', onBeforeUnload)

onBeforeRouteLeave(() => {
  if (!editorState.value.dirty) return true
  return window.confirm('Ungespeicherte Agent-Konfiguration verwerfen und die Seite verlassen?')
})

onUnmounted(() => {
  window.removeEventListener('nexus:domain-event', onDomainEvent)
  unsubscribeDomainState?.()
  unsubscribeDomainState = null
  if (activityReloadTimer) clearTimeout(activityReloadTimer)
  window.removeEventListener('beforeunload', onBeforeUnload)
})
</script>

<template>
  <div class="detail-page nexus-page">
    <button type="button" class="back-link" @click="router.push('/agents')">
      <ArrowLeft :size="14" />
      Zurück zu Agents
    </button>

    <AsyncStatePanel
      v-if="initLoading && !agent"
      state="loading"
      title="Agent wird geladen"
    />

    <AsyncStatePanel
      v-else-if="agentQuery.error.value && !agent"
      state="error"
      title="Agent nicht verfügbar"
      :problem="agentQuery.error.value"
      @action="retryAgent"
    />

    <template v-else>
      <AsyncStatePanel
        v-if="agentQuery.error.value && agent"
        state="stale"
        title="Agentdaten möglicherweise veraltet"
        :problem="agentQuery.error.value"
        action-label="Aktualisieren"
        compact
        @action="retryAgent"
      />
      <!-- Agent header -->
      <div class="agent-header">
        <div class="agent-avatar" :class="agentId">
          <Bot :size="24" />
        </div>
        <div class="agent-header-info">
          <span class="eyebrow">{{ agent?.role?.toUpperCase() || 'AGENT' }}</span>
          <h1>{{ agent?.name || fallbackName }}</h1>
          <div v-if="agent" class="agent-status-row">
            <span :style="{ background: statusColor(agent.status) }" class="status-dot"></span>
            <span class="status-label">{{ agent.status }}</span>
            <span class="status-sep">·</span>
            <span class="status-label mono">{{ agent.model || 'N/A' }}</span>
            <span v-if="agent.lastSeen" class="status-sep">·</span>
            <span v-if="agent.lastSeen" class="status-label">
              <Activity :size="11" />
              {{ formatLastSeen(agent.lastSeen) }}
            </span>
          </div>
        </div>
      </div>

      <section class="thinking-section">
        <header class="section-head">
          <div>
            <span class="eyebrow">AUTHORITATIVE ACTIVITY</span>
            <h2>Agent events <span :class="['live-dot', { on: liveConnected }]"></span></h2>
            <p class="section-note">
              Nexus activity streams live. Gateway session history remains read-only fallback and refreshes when related Nexus events arrive or on manual reload.
            </p>
          </div>
          <button
            type="button"
            class="icon-button"
            aria-label="Agent activity and summary refresh"
            :disabled="activityLoading || summaryLoading"
            @click="refreshActivity"
          >
            <RefreshCw :size="14" :class="{ spin: activityLoading }" />
          </button>
        </header>

        <AsyncStatePanel
          v-if="summaryLoading && !summary"
          state="loading"
          title="Zusammenfassungen werden geladen"
          compact
        />

        <AsyncStatePanel
          v-else-if="summaryQuery.error.value && !summary"
          state="error"
          title="Zusammenfassungen nicht verfügbar"
          :problem="summaryQuery.error.value"
          compact
          @action="retrySummary"
        />

        <div v-else-if="summary" class="summary-row">
          <div class="summary-card">
            <span>Now</span>
            <p>{{ summary.now.text }}</p>
            <small>{{ summarySourceLabel(summary.now.source) }} · {{ formatSummaryTimestamp(summary.now.timestamp) }}</small>
          </div>
          <div class="summary-card">
            <span>Today</span>
            <p>{{ summary.today.text }}</p>
            <small>{{ summarySourceLabel(summary.today.source) }} · {{ formatSummaryTimestamp(summary.today.timestamp) }}</small>
          </div>
        </div>

        <AsyncStatePanel
          v-else
          state="empty"
          title="Keine Zusammenfassung"
          message="OpenClaw hat für diesen Agenten noch keine bestätigte Zusammenfassung geliefert."
          compact
        />

        <AsyncStatePanel
          v-if="summaryQuery.error.value && summary"
          state="stale"
          title="Zusammenfassung möglicherweise veraltet"
          :problem="summaryQuery.error.value"
          action-label="Aktualisieren"
          compact
          @action="retrySummary"
        />

        <AsyncStatePanel
          v-if="liveUnavailable"
          state="stale"
          title="Live-Stream wird neu verbunden"
          message="Die letzte bestätigte Aktivität bleibt sichtbar."
          action-label="Manuell aktualisieren"
          compact
          @action="refreshActivity"
        />

        <AsyncStatePanel
          v-if="activityLoading && !activityItems.length"
          state="loading"
          title="Aktivität wird geladen"
          compact
        />

        <AsyncStatePanel
          v-else-if="activityQuery.error.value && !activityItems.length"
          state="error"
          title="Aktivität nicht verfügbar"
          :problem="activityQuery.error.value"
          compact
          @action="retryActivity"
        />

        <template v-else-if="activityItems.length">
          <AsyncStatePanel
            v-if="activityQuery.error.value"
            state="stale"
            title="Aktivitätsliste möglicherweise veraltet"
            :problem="activityQuery.error.value"
            action-label="Aktualisieren"
            compact
            @action="retryActivity"
          />
          <div class="thinking-list">
            <article
              v-for="item in activityItems"
              :key="`${item.source}-${item.id ?? item.at}-${item.message}`"
              class="thinking-item"
            >
              <div class="thinking-meta">
                <span class="type-pill">{{ activityTypeLabel(item.type) }}</span>
                <span>{{ formatActivityTime(item) }}</span>
              </div>
              <p>{{ item.message }}</p>
            </article>
          </div>
        </template>

        <AsyncStatePanel
          v-else
          state="empty"
          title="Keine aktuelle Aktivität"
          message="Für diesen Agenten liegen noch keine bestätigten Events vor."
          compact
        />
      </section>

      <!-- Config section -->
      <div class="config-section">
        <AsyncStatePanel
          v-if="configsLoading && !configFiles.length"
          state="loading"
          title="Agent-Dateien werden geladen"
          compact
        />

        <AsyncStatePanel
          v-else-if="configsError && !configFiles.length"
          state="error"
          title="Agent-Dateien nicht verfügbar"
          :message="configsError"
          :problem="fileQuery.error.value ?? filesQuery.error.value"
          :action-label="canConfigure ? 'Aktualisieren' : ''"
          compact
          @action="retryConfigs"
        />

        <template v-else>
          <AsyncStatePanel
            v-if="configsError"
            state="stale"
            title="Agent-Dateiliste möglicherweise veraltet"
            :message="configsError"
            :problem="fileQuery.error.value ?? filesQuery.error.value"
            action-label="Aktualisieren"
            compact
            @action="retryConfigs"
          />
          <ConfigTabs
            :tabs="configFiles.map(file => file.name)"
            :active-tab="activeTab"
            @switch-tab="switchTab"
          />

          <ConfigEditor
            :file-name="activeTabFileName"
            :file-size="currentFile?.size != null ? formatFileSize(Number(currentFile.size)) : 'Noch nicht angelegt'"
            :file-modified="currentFile?.updatedAt ? formatModifiedAt(currentFile.updatedAt) : 'Keine Änderung gemeldet'"
            :content="editorState.content"
            :dirty="editorState.dirty"
            :saving="editorState.saving"
            :save-status="editorState.saveStatus"
            :save-message="editorState.saveMessage"
            :backup-status="editorState.backupStatus"
            :reload-status="editorState.reloadStatus"
            :reload-message="editorState.reloadMessage"
            :content-hash="editorState.contentHash"
            :verified="editorState.verified"
            :read-only="!canConfigure"
            @update-content="onContentChange"
            @save="saveFile"
          />
          <StandingOrdersEditor
            v-if="activeTabFileName === 'AGENTS.md'"
            :content="editorState.content"
            :read-only="!canConfigure"
            @apply="onContentChange"
          />
          <AgentWorkspaceBrowser v-if="canConfigure" :agent-id="agentId" />
        </template>
      </div>
    </template>
  </div>
</template>

<style scoped>
.detail-page {
  max-width: 960px;
  margin: 0 auto;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--panel);
  color: var(--tx-3);
  font-size: 10.5px;
  cursor: pointer;
  margin-bottom: 20px;
  transition: border-color 0.15s, color 0.15s;
}
.back-link:hover {
  border-color: var(--line-3);
  color: var(--tx);
}

.status-message {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 48px;
  color: var(--tx-3);
  font-size: 12px;
}
.status-message.error {
  color: var(--st-block);
}
.status-message.compact {
  padding: 20px;
}
.spin {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

.agent-header {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
}
.agent-avatar {
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: color-mix(in srgb, var(--a-mid) 10%, transparent);
  color: var(--a-mid);
  flex-shrink: 0;
}
.agent-avatar.iris { background: color-mix(in srgb, var(--a-mid) 15%, transparent); color: var(--a-mid); }
.agent-avatar.programmer { background: color-mix(in srgb, var(--a-blue) 15%, transparent); color: var(--a-blue); }
.agent-avatar.architekt { background: color-mix(in srgb, var(--a-blue) 15%, transparent); color: var(--a-blue); }
.agent-avatar.reviewer { background: color-mix(in srgb, var(--st-review) 15%, transparent); color: var(--st-review); }
.agent-avatar.researcher { background: color-mix(in srgb, var(--a-mid) 15%, transparent); color: var(--a-mid); }
.agent-avatar.executor { background: color-mix(in srgb, var(--st-think) 15%, transparent); color: var(--st-think); }

.agent-header-info {
  flex: 1;
}
.agent-header-info .eyebrow {
  display: block;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--a-mid);
  text-transform: uppercase;
  margin-bottom: 2px;
}
.agent-header-info h1 {
  margin: 0 0 4px;
  font-size: 20px;
  font-weight: 600;
  color: var(--tx);
}
.agent-status-row {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
}
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.status-label {
  font-size: 11px;
  color: var(--tx-3);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.status-label.muted { color: var(--tx-3); }
.status-label.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; }
.status-sep { color: var(--line-3); font-size: 11px; }

.thinking-section {
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  margin-bottom: 16px;
  overflow: hidden;
}
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}
.section-head .eyebrow {
  display: block;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--a-mid);
}
.section-head h2 {
  margin: 2px 0 0;
  color: var(--tx);
  font-size: 13px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.section-note {
  margin: 6px 0 0;
  color: var(--tx-3);
  font-size: 10px;
  line-height: 1.45;
  max-width: 560px;
}
.live-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--tx-3);
}
.live-dot.on {
  background: var(--st-work);
}
.icon-button {
  width: 30px;
  height: 30px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: color-mix(in srgb, var(--tx) 3%, transparent);
  color: var(--tx-2);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.icon-button:disabled {
  opacity: .65;
  cursor: default;
}
.thinking-list {
  display: grid;
}
.summary-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: color-mix(in srgb, var(--tx) 5%, transparent);
  border-bottom: 1px solid var(--line);
}
.summary-row > div {
  background: var(--panel);
  padding: 12px 16px;
}
.summary-card small {
  display: block;
  margin-top: 7px;
  color: var(--tx-3);
  font-size: 9.5px;
  line-height: 1.4;
}
.summary-row span {
  display: block;
  color: var(--tx-3);
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  margin-bottom: 5px;
}
.summary-row p {
  margin: 0;
  color: var(--tx);
  font-size: 11px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.thinking-item {
  padding: 12px 16px;
  border-bottom: 1px solid color-mix(in srgb, var(--tx) 5%, transparent);
}
.thinking-item:last-child {
  border-bottom: 0;
}
.thinking-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  color: var(--tx-3);
  font-size: 10px;
}
.type-pill {
  padding: 2px 6px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 24%, transparent);
  color: var(--tx-2);
  background: color-mix(in srgb, var(--a-mid) 8%, transparent);
  font-size: 9px;
}
.thinking-item p {
  margin: 0;
  color: var(--tx);
  font-size: 11px;
  line-height: 1.55;
  overflow-wrap: anywhere;
}
.summary-inline-error {
  border-bottom: 1px solid var(--line);
}

@media (max-width: 640px) {
  .detail-page {
    max-width: 100%;
  }
  .summary-row {
    grid-template-columns: 1fr;
  }
}
</style>
