<script setup lang="ts">
import {
  Activity,
  AlertTriangle,
  ArrowLeft,
  CheckCircle2,
  CircleStop,
  Clock3,
  GitBranch,
  Link2,
  Loader2,
  Play,
  Radio,
  RefreshCw,
  RotateCcw,
  ShieldCheck,
  Workflow,
  X,
} from '@lucide/vue'
import { computed, nextTick, ref } from 'vue'
import { RouterLink, useRoute, useRouter } from 'vue-router'
import {
  useOpenClawRunHistory,
  useOpenClawRunMutations,
} from '../api/openClawRuns'
import { useAuthStore } from '../stores/auth'
import { useOpenClawStore } from '../stores/openclaw'
import AsyncStatePanel from '../components/mission-control/AsyncStatePanel.vue'

type RunAction = 'stop' | 'retry' | 'resume'

const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const openClaw = useOpenClawStore()
const pendingAction = ref<RunAction | null>(null)
const actionReason = ref('')
const announcement = ref('')
const closeButton = ref<HTMLButtonElement | null>(null)
const actionReturnFocus = ref<HTMLElement | null>(null)
const runHero = ref<HTMLElement | null>(null)

const runId = computed(() => String(route.params.id ?? ''))
const historyQuery = useOpenClawRunHistory(runId)
const { actionMutation } = useOpenClawRunMutations()
const history = computed(() => historyQuery.data.value ?? null)
const run = computed(() => history.value?.run ?? null)
const detailLoading = computed(() => historyQuery.isFetching.value)
const detailError = computed(() => {
  const error = historyQuery.error.value
  return error instanceof Error ? error.message : ''
})
const actionBusy = computed(() => actionMutation.isPending.value)
const actionError = computed(() => {
  const error = actionMutation.error.value
  return error instanceof Error ? error.message : ''
})
const canOperate = computed(() => auth.user?.role === 'owner')

function formatDate(value: string | null): string {
  if (!value) return 'Not reported'
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return date.toLocaleString('de-DE', {
    day: '2-digit',
    month: 'short',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
  })
}

function statusTone(status: string): string {
  if (['running', 'completed', 'ready', 'connected'].includes(status)) return 'positive'
  if (['dispatching', 'stopping', 'blocked', 'reconnecting'].includes(status)) return 'warning'
  if (['failed', 'stopped', 'unsupported', 'disconnected'].includes(status)) return 'danger'
  return 'neutral'
}

function shortId(value: string | null): string {
  if (!value) return '—'
  return value.length <= 26 ? value : `${value.slice(0, 11)}…${value.slice(-9)}`
}

function gatewayHistoryJson(): string {
  if (history.value?.gatewayHistory === null || history.value?.gatewayHistory === undefined) return ''
  return JSON.stringify(history.value.gatewayHistory, null, 2)
}

async function refresh() {
  await historyQuery.refetch()
}

async function askAction(action: RunAction, event: MouseEvent) {
  actionReturnFocus.value = event.currentTarget instanceof HTMLElement
    ? event.currentTarget
    : null
  pendingAction.value = action
  actionReason.value = ''
  actionMutation.reset()
  await nextTick()
  closeButton.value?.focus()
}

async function closeAction() {
  if (actionBusy.value) return
  const returnFocus = actionReturnFocus.value
  actionReturnFocus.value = null
  pendingAction.value = null
  actionReason.value = ''
  actionMutation.reset()
  await nextTick()
  if (returnFocus?.isConnected &&
      !(returnFocus instanceof HTMLButtonElement && returnFocus.disabled)) {
    returnFocus.focus()
  } else {
    runHero.value?.focus()
  }
}

function actionTitle(): string {
  if (pendingAction.value === 'stop') return 'Stop this OpenClaw run?'
  if (pendingAction.value === 'retry') return 'Retry as a new correlated run?'
  return 'Resume this run?'
}

function actionDescription(): string {
  if (pendingAction.value === 'stop') {
    return 'Nexus records the stop request before sending the capability-gated abort to OpenClaw.'
  }
  if (pendingAction.value === 'retry') {
    return 'Nexus creates a new durable run linked through retriedFromRunId. The original history remains immutable.'
  }
  return run.value?.resumeCapabilityMessage ||
    'Resume is only available when the connected OpenClaw Gateway advertises a supported same-run resume contract.'
}

async function executeAction() {
  if (!pendingAction.value || !run.value) return
  const action = pendingAction.value
  try {
    if (action === 'stop') {
      await actionMutation.mutateAsync({
        id: run.value.id,
        action: 'stop',
        reason: actionReason.value,
      })
      announcement.value = 'Run stop request completed.'
      await refresh()
    } else if (action === 'resume') {
      await actionMutation.mutateAsync({
        id: run.value.id,
        action: 'resume',
        reason: actionReason.value,
      })
      announcement.value = 'Run resume request completed.'
      await refresh()
    } else {
      const result = await actionMutation.mutateAsync({
        id: run.value.id,
        action: 'retry',
        reason: actionReason.value,
      })
      const resultRun = result.resultRun
      announcement.value = 'A correlated retry run was created.'
      await closeAction()
      if (resultRun) await router.push(`/runs/${resultRun.id}`)
      return
    }
    await closeAction()
  } catch {
    // The store exposes the exact server message in the confirmation dialog.
  }
}

</script>

<template>
  <div class="run-detail nexus-page nexus-page--standard">
    <header class="run-detail-header nexus-page-header">
      <div class="run-title-block">
        <RouterLink class="back-link" to="/runs" aria-label="Back to Run Control">
          <ArrowLeft :size="15" aria-hidden="true" />
        </RouterLink>
        <div>
          <span class="eyebrow">DURABLE OPENCLAW RUN</span>
          <h1>{{ run?.title || 'Run detail' }}</h1>
          <p v-if="run">
            {{ run.agentId }} · <code>{{ shortId(run.id) }}</code>
          </p>
        </div>
      </div>
      <div class="run-detail-actions">
        <span :class="['sync-badge', openClaw.syncMode === 'live' ? 'positive' : 'warning']">
          <Radio :size="12" aria-hidden="true" />
          {{ openClaw.syncMode === 'live' ? 'Event stream live' : 'Polling fallback' }}
        </span>
        <button type="button" class="nexus-button" :disabled="detailLoading" @click="refresh">
          <RefreshCw :size="14" :class="{ spin: detailLoading }" />
          Refresh
        </button>
      </div>
    </header>

    <AsyncStatePanel
      v-if="detailLoading && !run"
      state="loading"
      title="Durable Run wird geladen"
      message="Nexus gleicht lokale Transitionen mit der OpenClaw-Historie ab."
    />

    <AsyncStatePanel
      v-else-if="detailError && !run"
      state="error"
      title="Run konnte nicht geladen werden"
      :message="detailError"
      action-label="Zur Run Control"
      @action="router.push('/runs')"
    />

    <template v-else-if="run">
      <section v-if="run.sequenceGapDetected" class="gap-warning" role="alert">
        <AlertTriangle :size="18" />
        <div>
          <strong>Gateway sequence gap detected</strong>
          <p>The event projection missed one or more frames. Nexus requested authoritative history; verify the timeline before taking another side effect.</p>
        </div>
        <button type="button" class="nexus-button" @click="refresh">Reconcile</button>
      </section>

      <section ref="runHero" class="run-hero glass-panel" tabindex="-1">
        <div class="run-state">
          <span :class="['state-icon', statusTone(run.status)]">
            <Workflow :size="20" aria-hidden="true" />
          </span>
          <div>
            <small>Lifecycle state</small>
            <strong>{{ run.status }}</strong>
            <span>Updated {{ formatDate(run.updatedAt) }}</span>
          </div>
        </div>
        <div class="hero-metrics">
          <div><small>OpenClaw run</small><strong>{{ shortId(run.openClawRunId) }}</strong></div>
          <div><small>Gateway sequence</small><strong>{{ run.lastGatewaySequence ?? 'Not reported' }}</strong></div>
          <div><small>Actor</small><strong>{{ run.actor }}</strong></div>
          <div><small>Correlation</small><strong>{{ shortId(run.correlationId) }}</strong></div>
        </div>
        <div class="hero-actions">
          <button
            type="button"
            class="nexus-button nexus-button--danger"
            :disabled="!canOperate || !run.canStop"
            @click="askAction('stop', $event)"
          ><CircleStop :size="14" /> Stop</button>
          <button
            type="button"
            class="nexus-button"
            :disabled="!canOperate || !run.canResume"
            :title="run.resumeCapabilityMessage || undefined"
            @click="askAction('resume', $event)"
          ><Play :size="14" /> Resume</button>
          <button
            type="button"
            class="nexus-button nexus-button--primary"
            :disabled="!canOperate || !run.canRetry"
            @click="askAction('retry', $event)"
          ><RotateCcw :size="14" /> Retry</button>
        </div>
        <p v-if="!run.canResume && run.resumeCapabilityMessage" class="capability-note">
          {{ run.resumeCapabilityMessage }}
        </p>
      </section>

      <div class="run-detail-grid">
        <main class="run-detail-main">
          <section class="detail-panel prompt-panel">
            <header><div><span class="eyebrow">REQUEST</span><h2>Agent objective</h2></div><ShieldCheck :size="17" /></header>
            <pre>{{ run.prompt }}</pre>
            <p v-if="run.lastError" class="run-error"><AlertTriangle :size="15" />{{ run.lastError }}</p>
          </section>

          <section class="detail-panel timeline-panel">
            <header>
              <div><span class="eyebrow">AUTHORITATIVE LEDGER</span><h2>Lifecycle history</h2></div>
              <span>{{ history?.transitions.length ?? 0 }} transitions</span>
            </header>
            <ol v-if="history?.transitions.length" class="run-timeline">
              <li v-for="transition in history.transitions" :key="transition.id">
                <span :class="['timeline-marker', statusTone(transition.toStatus)]" aria-hidden="true"></span>
                <div class="transition-main">
                  <div><strong>{{ transition.action }}</strong><time>{{ formatDate(transition.occurredAt) }}</time></div>
                  <p>{{ transition.message }}</p>
                  <span>{{ transition.fromStatus }} → {{ transition.toStatus }}</span>
                </div>
                <dl>
                  <div><dt>Actor</dt><dd>{{ transition.actor }}</dd></div>
                  <div><dt>Correlation</dt><dd>{{ shortId(transition.correlationId) }}</dd></div>
                  <div v-if="transition.gatewaySequence !== null"><dt>Sequence</dt><dd>{{ transition.gatewaySequence }}</dd></div>
                  <div v-if="transition.resultRunId"><dt>Result run</dt><dd><RouterLink :to="`/runs/${transition.resultRunId}`">{{ shortId(transition.resultRunId) }}</RouterLink></dd></div>
                </dl>
              </li>
            </ol>
            <div v-else class="detail-empty">No lifecycle transition has been recorded.</div>
          </section>

          <details v-if="history" class="detail-panel gateway-history">
            <summary>
              <span><Activity :size="15" /><strong>Gateway history</strong></span>
              <code>{{ history.gatewayHistoryState }}</code>
            </summary>
            <p v-if="history.message">{{ history.message }}</p>
            <pre v-if="gatewayHistoryJson()">{{ gatewayHistoryJson() }}</pre>
            <div v-else class="detail-empty">OpenClaw did not expose gateway history for this session.</div>
          </details>
        </main>

        <aside class="run-detail-aside">
          <section class="detail-panel correlation-panel">
            <header><div><span class="eyebrow">CORRELATION</span><h2>Linked objects</h2></div><Link2 :size="16" /></header>
            <dl>
              <div><dt>Run ID</dt><dd><code>{{ run.id }}</code></dd></div>
              <div><dt>Session</dt><dd><RouterLink :to="{ path: '/runs', query: { session: run.sessionKey } }">{{ shortId(run.sessionKey) }}</RouterLink></dd></div>
              <div><dt>Agent</dt><dd><RouterLink :to="`/agents/${encodeURIComponent(run.agentId)}`">{{ run.agentId }}</RouterLink></dd></div>
              <div><dt>Task</dt><dd><RouterLink v-if="run.taskId" :to="`/tasks/${run.taskId}`">{{ shortId(run.taskId) }}</RouterLink><span v-else>—</span></dd></div>
              <div><dt>Project</dt><dd><RouterLink v-if="run.projectId" :to="`/projects/${run.projectId}`">{{ shortId(run.projectId) }}</RouterLink><span v-else>—</span></dd></div>
              <div><dt>Retry source</dt><dd><RouterLink v-if="run.retriedFromRunId" :to="`/runs/${run.retriedFromRunId}`">{{ shortId(run.retriedFromRunId) }}</RouterLink><span v-else>—</span></dd></div>
            </dl>
          </section>

          <section class="detail-panel timing-panel">
            <header><div><span class="eyebrow">TIMING</span><h2>Recorded timestamps</h2></div><Clock3 :size="16" /></header>
            <dl>
              <div><dt>Created</dt><dd>{{ formatDate(run.createdAt) }}</dd></div>
              <div><dt>Started</dt><dd>{{ formatDate(run.startedAt) }}</dd></div>
              <div><dt>Updated</dt><dd>{{ formatDate(run.updatedAt) }}</dd></div>
              <div><dt>Finished</dt><dd>{{ formatDate(run.finishedAt) }}</dd></div>
            </dl>
          </section>

          <section class="detail-panel trust-panel">
            <GitBranch :size="17" />
            <div><strong>Mutation contract</strong><p>Each lifecycle action carries a fresh logical idempotency key, correlation ID, W3C trace context and JWT-derived actor.</p></div>
          </section>
        </aside>
      </div>
    </template>

    <p class="sr-only" aria-live="polite">{{ announcement }}</p>

    <Teleport to="body">
      <div v-if="pendingAction" class="run-action-overlay" @click.self="closeAction" @keydown.esc="closeAction">
        <section class="run-action-dialog" role="dialog" aria-modal="true" aria-labelledby="run-action-title">
          <header>
            <div><span class="eyebrow">OPERATOR CONFIRMATION</span><h2 id="run-action-title">{{ actionTitle() }}</h2></div>
            <button ref="closeButton" type="button" aria-label="Close confirmation" :disabled="actionBusy" @click="closeAction"><X :size="18" /></button>
          </header>
          <div>
            <p>{{ actionDescription() }}</p>
            <label>
              <span>Reason <small>optional</small></span>
              <textarea v-model="actionReason" rows="3" maxlength="1000" placeholder="Operational reason for the audit ledger"></textarea>
            </label>
            <p v-if="actionError" class="run-action-error" role="alert">{{ actionError }}</p>
            <footer>
              <button type="button" class="nexus-button" :disabled="actionBusy" @click="closeAction">Cancel</button>
              <button
                type="button"
                :class="['nexus-button', pendingAction === 'stop' ? 'nexus-button--danger' : 'nexus-button--primary']"
                :disabled="actionBusy"
                @click="executeAction"
              >
                <Loader2 v-if="actionBusy" :size="14" class="spin" />
                <CheckCircle2 v-else :size="14" />
                Confirm
              </button>
            </footer>
          </div>
        </section>
      </div>
    </Teleport>
  </div>
</template>

<style scoped>
.run-detail {
  width: min(100%, 1180px);
  margin-inline: auto;
}

.run-detail-header,
.run-title-block,
.run-detail-actions,
.sync-badge,
.run-state,
.hero-actions,
.detail-panel > header,
.trust-panel {
  display: flex;
  align-items: center;
}

.run-title-block {
  align-items: flex-start;
  gap: 11px;
}

.back-link {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--accent-wash);
  color: var(--tx-2);
}

.back-link:hover {
  border-color: var(--line-3);
  color: var(--tx);
}

.run-title-block h1 {
  margin: 3px 0 2px;
}

.run-title-block p {
  margin: 0;
  color: var(--tx-3);
  font-size: 11px;
}

.run-title-block code,
.sync-badge,
.hero-metrics strong,
.run-timeline time,
.run-timeline span,
.run-timeline dl,
.correlation-panel dd,
.timing-panel dd,
.gateway-history code {
  font-family: var(--font-mono-v2);
}

.run-detail-actions {
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}

.sync-badge {
  gap: 6px;
  min-height: 32px;
  padding: 0 10px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--accent-wash);
  color: var(--tx-2);
  font-size: 9.5px;
  text-transform: uppercase;
}

.sync-badge.positive { color: var(--st-work); }
.sync-badge.warning { color: var(--st-queue); }

.gap-warning {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--status-queue-line);
  border-radius: var(--r);
  background: var(--status-queue-bg);
  color: var(--st-queue);
}

.gap-warning strong {
  color: var(--tx);
  font-size: 12px;
}

.gap-warning p {
  margin: 3px 0 0;
  color: var(--tx-2);
  font-size: 10.5px;
  line-height: 1.5;
}

.run-hero {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  padding: 16px;
}

.run-state {
  gap: 11px;
}

.state-icon {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: var(--grad-soft);
  color: var(--tx-2);
}

.state-icon.positive { color: var(--st-work); }
.state-icon.warning { color: var(--st-queue); }
.state-icon.danger { color: var(--st-block); }

.run-state small,
.run-state strong,
.run-state span {
  display: block;
}

.run-state small,
.hero-metrics small {
  color: var(--tx-3);
  font-size: 9px;
  text-transform: uppercase;
}

.run-state strong {
  margin-top: 2px;
  font-family: var(--font-display);
  font-size: 16px;
  text-transform: capitalize;
}

.run-state span {
  margin-top: 2px;
  color: var(--tx-3);
  font-size: 9px;
}

.hero-metrics {
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
}

.hero-metrics > div {
  min-width: 0;
  padding: 9px 10px;
  border-right: 1px solid var(--line);
}

.hero-metrics > div:last-child {
  border-right: 0;
}

.hero-metrics strong {
  display: block;
  margin-top: 4px;
  overflow: hidden;
  color: var(--tx);
  font-size: 9.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hero-actions {
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 7px;
}

.capability-note {
  grid-column: 1 / -1;
  margin: -4px 0 0;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--accent-wash);
  color: var(--tx-3);
  font-size: 10px;
}

.run-detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 310px;
  align-items: start;
  gap: 14px;
}

.run-detail-main,
.run-detail-aside {
  min-width: 0;
  display: grid;
  gap: 14px;
}

.run-detail-aside {
  position: sticky;
  top: 0;
}

.detail-panel {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--glass);
  box-shadow: var(--panel-shadow);
  backdrop-filter: blur(12px);
}

.detail-panel > header {
  justify-content: space-between;
  gap: 10px;
  min-height: 58px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  color: var(--a-mid);
}

.detail-panel h2 {
  margin: 3px 0 0;
  color: var(--tx);
  font-family: var(--font-display);
  font-size: 15px;
}

.prompt-panel > pre,
.gateway-history > pre {
  margin: 0;
  overflow: auto;
  color: var(--tx-2);
  font-family: var(--font-body);
  font-size: 11.5px;
  line-height: 1.65;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.prompt-panel > pre {
  min-height: 100px;
  padding: 16px;
}

.run-error {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 14px 14px;
  padding: 10px;
  border: 1px solid var(--status-block-line);
  border-radius: 9px;
  background: var(--status-block-bg);
  color: var(--st-block);
  font-size: 10.5px;
}

.timeline-panel > header > span {
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 9px;
}

.run-timeline {
  display: grid;
  margin: 0;
  padding: 8px 14px 14px;
  list-style: none;
}

.run-timeline li {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) minmax(190px, 230px);
  gap: 11px;
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}

.run-timeline li:last-child {
  border-bottom: 0;
}

.timeline-marker {
  width: 9px;
  height: 9px;
  margin-top: 4px;
  border-radius: 50%;
  background: var(--st-idle);
  box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 12%, transparent);
}

.timeline-marker.positive { color: var(--st-work); background: var(--st-work); }
.timeline-marker.warning { color: var(--st-queue); background: var(--st-queue); }
.timeline-marker.danger { color: var(--st-block); background: var(--st-block); }

.transition-main > div {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}

.transition-main strong {
  font-size: 11px;
}

.transition-main time {
  color: var(--tx-3);
  font-size: 8.5px;
}

.transition-main p {
  margin: 5px 0;
  color: var(--tx-2);
  font-size: 10.5px;
  line-height: 1.5;
}

.transition-main > span {
  color: var(--tx-3);
  font-size: 8.5px;
}

.run-timeline dl,
.correlation-panel dl,
.timing-panel dl {
  display: grid;
  gap: 6px;
  margin: 0;
}

.run-timeline dl div,
.correlation-panel dl div,
.timing-panel dl div {
  min-width: 0;
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr);
  gap: 7px;
}

.run-timeline dt,
.correlation-panel dt,
.timing-panel dt {
  color: var(--tx-3);
  font-size: 8.5px;
}

.run-timeline dd,
.correlation-panel dd,
.timing-panel dd {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  color: var(--tx-2);
  font-size: 8.5px;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.run-timeline a,
.correlation-panel a {
  color: var(--a-mid);
}

.correlation-panel dl,
.timing-panel dl {
  padding: 12px 14px;
}

.correlation-panel dl div,
.timing-panel dl div {
  padding: 4px 0;
}

.gateway-history > summary {
  min-height: 52px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  cursor: pointer;
}

.gateway-history > summary span {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--a-mid);
}

.gateway-history > summary strong {
  color: var(--tx);
  font-family: var(--font-display);
  font-size: 13px;
}

.gateway-history > summary code {
  color: var(--tx-3);
  font-size: 9px;
}

.gateway-history > p {
  margin: 0;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
  color: var(--tx-2);
  font-size: 10px;
}

.gateway-history > pre {
  max-height: 360px;
  padding: 14px;
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--space-0) 46%, transparent);
  font-family: var(--font-mono-v2);
  font-size: 9.5px;
}

.detail-empty {
  padding: 24px 14px;
  color: var(--tx-3);
  font-size: 10.5px;
  text-align: center;
}

.trust-panel {
  align-items: flex-start;
  gap: 10px;
  padding: 13px;
  color: var(--a-mid);
}

.trust-panel strong {
  color: var(--tx);
  font-size: 11px;
}

.trust-panel p {
  margin: 4px 0 0;
  color: var(--tx-3);
  font-size: 9.5px;
  line-height: 1.5;
}

.run-action-overlay {
  position: fixed;
  inset: 0;
  z-index: 750;
  display: grid;
  place-items: center;
  padding: 20px;
  background: color-mix(in srgb, var(--space-0) 80%, transparent);
  backdrop-filter: blur(14px);
}

.run-action-dialog {
  width: min(520px, 100%);
  overflow: hidden;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: color-mix(in srgb, var(--space-1) 97%, transparent);
  box-shadow: var(--panel-shadow), var(--glow-purple);
}

.run-action-dialog > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 15px 17px;
  border-bottom: 1px solid var(--line);
}

.run-action-dialog h2 {
  margin: 3px 0 0;
  font-family: var(--font-display);
  font-size: 17px;
}

.run-action-dialog header button {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: transparent;
  color: var(--tx-2);
  cursor: pointer;
}

.run-action-dialog > div {
  display: grid;
  gap: 12px;
  padding: 16px;
}

.run-action-dialog p {
  margin: 0;
  color: var(--tx-2);
  font-size: 10.5px;
  line-height: 1.55;
}

.run-action-dialog label {
  display: grid;
  gap: 6px;
}

.run-action-dialog label span {
  color: var(--tx-2);
  font-family: var(--font-mono-v2);
  font-size: 9px;
  text-transform: uppercase;
}

.run-action-dialog label small {
  color: var(--tx-3);
}

.run-action-dialog textarea {
  width: 100%;
  min-height: 82px;
  resize: vertical;
  padding: 10px;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  background: var(--field-surface);
  color: var(--tx);
  font-family: var(--font-body);
  font-size: 11px;
}

.run-action-dialog textarea:focus {
  outline: none;
  border-color: var(--line-3);
  box-shadow: var(--focus-ring);
}

.run-action-dialog footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.run-action-error {
  padding: 9px;
  border: 1px solid var(--status-block-line);
  border-radius: 9px;
  background: var(--status-block-bg);
  color: var(--st-block) !important;
}

.spin {
  animation: run-detail-spin 1s linear infinite;
}

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 1024px) {
  .run-hero {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero-actions {
    justify-content: flex-start;
  }

  .capability-note {
    grid-column: auto;
  }

  .run-detail-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .run-detail-aside {
    position: static;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .trust-panel {
    grid-column: 1 / -1;
  }
}

@media (max-width: 767px) {
  .run-detail-header,
  .gap-warning {
    align-items: stretch;
    grid-template-columns: minmax(0, 1fr);
  }

  .run-detail-header {
    flex-direction: column;
  }

  .run-detail-actions {
    justify-content: flex-start;
  }

  .hero-metrics,
  .run-detail-aside {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero-metrics > div {
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .hero-metrics > div:last-child {
    border-bottom: 0;
  }

  .run-timeline li {
    grid-template-columns: 12px minmax(0, 1fr);
  }

  .run-timeline dl {
    grid-column: 2;
  }
}

@media (prefers-reduced-motion: reduce) {
  .spin {
    animation: none;
  }
}
</style>
