<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { usePermissions } from 'src/composables/usePermissions'
import FlowCanvas from 'src/components/flow-editor/FlowCanvas.vue'

const { HUB_URL } = usePermissions()
const flows = ref(null)
const loading = ref(true)
const saving = ref(false)
const dirty = ref(false)
const selectedIntent = ref(null)
const editingStep = ref(null)
const showPrompt = ref(false)
const generatedPrompt = ref('')
const showJson = ref(false)
const showCanvas = ref(false)   // POC : vue canvas node-based (Vue Flow) au lieu de l'arbre

async function loadFlows () {
  loading.value = true
  try {
    const res = await fetch(`${HUB_URL}/agent/flows`)
    flows.value = await res.json()
    if (flows.value.intents?.length && !selectedIntent.value) {
      selectedIntent.value = flows.value.intents[0].id
    }
  } catch (e) { console.error('Load flows error:', e) }
  finally { loading.value = false }
}

async function saveFlows () {
  saving.value = true
  try {
    const res = await fetch(`${HUB_URL}/agent/flows`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(flows.value),
    })
    const data = await res.json()
    if (data.ok) { dirty.value = false; flows.value.version = data.version }
  } catch (e) { console.error('Save error:', e) }
  finally { saving.value = false }
}

async function viewPrompt () {
  const res = await fetch(`${HUB_URL}/agent/prompt`)
  const data = await res.json()
  generatedPrompt.value = data.prompt || ''
  showPrompt.value = true
}

const currentIntent = computed(() => flows.value?.intents?.find(i => i.id === selectedIntent.value))

// Step tree helpers
function stepsByParent (steps, parentId = null, branch = null) {
  return steps.filter(s => {
    if (parentId === null) return !s.parent
    return s.parent === parentId && (branch === null || s.branch === branch)
  })
}
function branchesOf (step) {
  if (!currentIntent.value) return []
  const steps = currentIntent.value.steps
  const children = steps.filter(s => s.parent === step.id)
  return [...new Set(children.map(c => c.branch))].filter(Boolean)
}

// Edit step
function openStepEditor (step) {
  editingStep.value = JSON.parse(JSON.stringify(step))
}
function saveStep () {
  if (!editingStep.value || !currentIntent.value) return
  const idx = currentIntent.value.steps.findIndex(s => s.id === editingStep.value.id)
  if (idx >= 0) currentIntent.value.steps[idx] = editingStep.value
  editingStep.value = null
  dirty.value = true
}
function deleteStep (stepId) {
  if (!currentIntent.value) return
  currentIntent.value.steps = currentIntent.value.steps.filter(s => s.id !== stepId && s.parent !== stepId)
  dirty.value = true
}

// Add step
function addStep (parentId = null, branch = null) {
  if (!currentIntent.value) return
  const id = 'step_' + Date.now().toString(36)
  const step = { id, type: 'respond', label: 'Nouvelle étape', message: '' }
  if (parentId) { step.parent = parentId; step.branch = branch || 'yes' }
  currentIntent.value.steps.push(step)
  dirty.value = true
  openStepEditor(step)
}

// ── Canvas Vue Flow → édite le MÊME modèle de steps (clic=éditer, lien=parent, glisser=position persistée _pos) ──
function canvasEdit (id) { const s = currentIntent.value?.steps.find(x => x.id === id); if (s) openStepEditor(s) }
function canvasConnect ({ source, target }) {
  if (!currentIntent.value || source === target) return
  const s = currentIntent.value.steps.find(x => x.id === target)
  const p = currentIntent.value.steps.find(x => x.id === source)
  if (!s || !p) return
  s.parent = source
  if ((p.type === 'condition' || p.type === 'switch') && !s.branch) s.branch = 'yes'
  dirty.value = true
}
function canvasMove ({ id, position }) { const s = currentIntent.value?.steps.find(x => x.id === id); if (s) { s._pos = { x: position.x, y: position.y }; dirty.value = true } }

// Add intent
function addIntent () {
  if (!flows.value) return
  const id = 'intent_' + Date.now().toString(36)
  flows.value.intents.push({ id, label: 'Nouveau flow', trigger: '', color: '#64748b', steps: [] })
  selectedIntent.value = id
  dirty.value = true
}
function deleteIntent (id) {
  if (!flows.value) return
  flows.value.intents = flows.value.intents.filter(i => i.id !== id)
  if (selectedIntent.value === id) selectedIntent.value = flows.value.intents[0]?.id || null
  dirty.value = true
}

// Persona edit
const editPersona = ref(false)

const stepTypeLabels = {
  tool: 'Appel outil', condition: 'Condition', switch: 'Switch', respond: 'Réponse',
  action: 'Action', goto: 'Aller à',
}
const severityColors = { info: '#3b82f6', warning: '#f59e0b', critical: '#ef4444' }

onMounted(loadFlows)
</script>

<template>
<q-page class="af-page">
  <div v-if="loading" class="af-loading">Chargement des flows...</div>
  <template v-else-if="flows">

    <!-- Header -->
    <div class="af-header">
      <div class="af-title">
        <span class="af-icon">&#x26A1;</span>
        <div>
          <h1>Agent AI — Flows</h1>
          <span class="af-subtitle">v{{ flows.version || 1 }} · {{ flows.intents?.length || 0 }} flows · {{ flows.updated_at ? new Date(flows.updated_at).toLocaleDateString('fr-CA') : '' }}</span>
        </div>
      </div>
      <div class="af-actions">
        <button class="af-btn af-btn-ghost" @click="viewPrompt">Voir prompt</button>
        <button class="af-btn af-btn-ghost" @click="showJson = !showJson">{{ showJson ? 'Visuel' : 'JSON' }}</button>
        <button class="af-btn af-btn-ghost" @click="showCanvas = !showCanvas">{{ showCanvas ? 'Arbre' : '🎨 Canvas' }}</button>
        <button class="af-btn af-btn-primary" :disabled="!dirty || saving" @click="saveFlows">
          {{ saving ? 'Sauvegarde...' : dirty ? 'Sauvegarder' : 'Sauvegardé' }}
        </button>
      </div>
    </div>

    <!-- Persona card -->
    <div class="af-persona" @click="editPersona = !editPersona">
      <div class="af-persona-hdr">
        <strong>{{ flows.persona?.name || 'Agent' }}</strong> — {{ flows.persona?.role || '' }}
      </div>
      <div v-if="editPersona" class="af-persona-edit" @click.stop>
        <label>Nom</label>
        <input v-model="flows.persona.name" @input="dirty = true" />
        <label>Rôle</label>
        <input v-model="flows.persona.role" @input="dirty = true" />
        <label>Ton</label>
        <input v-model="flows.persona.tone" @input="dirty = true" />
        <label>Règles</label>
        <div v-for="(r, i) in flows.persona.rules" :key="i" class="af-rule-row">
          <input v-model="flows.persona.rules[i]" @input="dirty = true" />
          <button class="af-btn-x" @click="flows.persona.rules.splice(i, 1); dirty = true">x</button>
        </div>
        <button class="af-btn af-btn-sm" @click="flows.persona.rules.push(''); dirty = true">+ Règle</button>
      </div>
      <div v-else class="af-persona-rules">
        <span v-for="r in flows.persona?.rules" :key="r" class="af-rule-chip">{{ r }}</span>
      </div>
    </div>

    <!-- JSON view -->
    <div v-if="showJson" class="af-json-wrap">
      <textarea class="af-json" :value="JSON.stringify(flows, null, 2)"
        @input="e => { try { flows = JSON.parse(e.target.value); dirty = true } catch {} }" />
    </div>

    <!-- Visual view -->
    <template v-else>
      <!-- Intent tabs -->
      <div class="af-tabs">
        <button v-for="intent in flows.intents" :key="intent.id"
          class="af-tab" :class="{ active: selectedIntent === intent.id }"
          :style="selectedIntent === intent.id ? `border-color:${intent.color};color:${intent.color}` : ''"
          @click="selectedIntent = intent.id">
          <span class="af-tab-dot" :style="`background:${intent.color}`"></span>
          {{ intent.label }}
        </button>
        <button class="af-tab af-tab-add" @click="addIntent">+</button>
      </div>

      <!-- Intent detail -->
      <div v-if="currentIntent" class="af-intent">
        <div class="af-intent-header">
          <input class="af-intent-label" v-model="currentIntent.label" @input="dirty = true" />
          <input class="af-intent-color" type="color" v-model="currentIntent.color" @input="dirty = true" />
          <button class="af-btn-x af-del-intent" @click="deleteIntent(currentIntent.id)" title="Supprimer ce flow">&#x1F5D1;</button>
        </div>
        <div class="af-trigger">
          <label>Déclencheur:</label>
          <input v-model="currentIntent.trigger" @input="dirty = true" placeholder="Quand ce flow se déclenche..." />
        </div>

        <!-- Canvas node-based (Vue Flow) — POC visuel n8n-like -->
        <FlowCanvas v-if="showCanvas" :steps="currentIntent.steps"
          @add="addStep()" @edit="canvasEdit" @delete="deleteStep" @connect="canvasConnect" @move="canvasMove" />
        <!-- Flow tree (vue arbre) -->
        <div v-else class="af-tree">
          <div class="af-tree-col">
            <template v-for="step in stepsByParent(currentIntent.steps, null)" :key="step.id">
              <FlowNode :step="step" :intent="currentIntent" :stepsByParent="stepsByParent" :branchesOf="branchesOf"
                @edit="openStepEditor" @delete="deleteStep" @add="addStep" :depth="0" />
            </template>
            <button class="af-add-root" @click="addStep()">+ Ajouter une étape</button>
          </div>
        </div>
      </div>
    </template>

    <!-- Step editor modal -->
    <div v-if="editingStep" class="af-overlay" @click.self="editingStep = null">
      <div class="af-modal">
        <div class="af-modal-hdr">
          <span>Modifier: {{ editingStep.label || editingStep.id }}</span>
          <button @click="editingStep = null">&#x2715;</button>
        </div>
        <div class="af-modal-body">
          <label>ID</label>
          <input v-model="editingStep.id" disabled class="af-input-disabled" />
          <label>Type</label>
          <select v-model="editingStep.type">
            <option v-for="(lbl, t) in stepTypeLabels" :key="t" :value="t">{{ lbl }}</option>
          </select>
          <label>Label</label>
          <input v-model="editingStep.label" />
          <template v-if="editingStep.type === 'tool'">
            <label>Outil</label>
            <input v-model="editingStep.tool" placeholder="get_equipment" />
            <label>Note</label>
            <input v-model="editingStep.note" />
          </template>
          <template v-if="editingStep.type === 'condition'">
            <label>Champ</label>
            <input v-model="editingStep.field" placeholder="device.online" />
            <div class="af-row">
              <div><label>Opérateur</label><select v-model="editingStep.op">
                <option value="==">==</option><option value="!=">!=</option>
                <option value="<">&lt;</option><option value=">">&gt;</option>
                <option value="<=">&lt;=</option><option value=">=">&gt;=</option>
              </select></div>
              <div><label>Valeur</label><input v-model="editingStep.value" /></div>
            </div>
          </template>
          <template v-if="editingStep.type === 'switch'">
            <label>Champ switch</label>
            <input v-model="editingStep.field" placeholder="onu.alarm_type" />
          </template>
          <template v-if="editingStep.type === 'respond'">
            <label>Message</label>
            <textarea v-model="editingStep.message" rows="4"></textarea>
            <label>Note interne</label>
            <input v-model="editingStep.note" />
          </template>
          <template v-if="editingStep.type === 'action'">
            <label>Action</label>
            <input v-model="editingStep.action" placeholder="create_dispatch_job" />
            <label>Paramètres (JSON)</label>
            <textarea :value="JSON.stringify(editingStep.params || {}, null, 2)"
              @input="e => { try { editingStep.params = JSON.parse(e.target.value) } catch {} }" rows="3"></textarea>
            <label>Message au client</label>
            <textarea v-model="editingStep.message" rows="2"></textarea>
          </template>
          <template v-if="editingStep.type === 'goto'">
            <label>Cible (intent ID)</label>
            <input v-model="editingStep.target" />
          </template>
          <label>Sévérité</label>
          <select v-model="editingStep.severity">
            <option value="">—</option>
            <option value="info">Info</option>
            <option value="warning">Warning</option>
            <option value="critical">Critical</option>
          </select>
          <template v-if="editingStep.parent">
            <label>Branche (parent condition)</label>
            <input v-model="editingStep.branch" placeholder="yes / no / dying_gasp / ..." />
          </template>
        </div>
        <div class="af-modal-ftr">
          <button class="af-btn af-btn-primary" @click="saveStep">Enregistrer</button>
          <button class="af-btn af-btn-ghost" @click="editingStep = null">Annuler</button>
        </div>
      </div>
    </div>

    <!-- Prompt preview modal -->
    <div v-if="showPrompt" class="af-overlay" @click.self="showPrompt = false">
      <div class="af-modal af-modal-wide">
        <div class="af-modal-hdr">
          <span>System Prompt généré</span>
          <button @click="showPrompt = false">&#x2715;</button>
        </div>
        <pre class="af-prompt-pre">{{ generatedPrompt }}</pre>
      </div>
    </div>

  </template>
</q-page>
</template>

<!-- Recursive FlowNode component -->
<script>
import { defineComponent, h } from 'vue'
const severityColors = { info: '#3b82f6', warning: '#f59e0b', critical: '#ef4444' }
const typeIcons = { tool: '\u2699', condition: '\u2753', switch: '\u2194', respond: '\uD83D\uDCAC', action: '\u26A1', goto: '\u27A1' }

const FlowNode = defineComponent({
  name: 'FlowNode',
  props: ['step', 'intent', 'stepsByParent', 'branchesOf', 'depth'],
  emits: ['edit', 'delete', 'add'],
  setup (props, { emit }) {
    return () => {
      const s = props.step
      const branches = props.branchesOf(s)
      const sevColor = s.severity ? severityColors[s.severity] : null
      const icon = typeIcons[s.type] || '\u25CB'

      const children = []

      // Render branch children
      if (s.type === 'condition') {
        for (const br of ['yes', 'no']) {
          const brSteps = props.stepsByParent(props.intent.steps, s.id, br)
          if (brSteps.length || true) {
            children.push(h('div', { class: 'af-branch', key: br }, [
              h('div', { class: `af-branch-label af-branch-${br}` }, br === 'yes' ? 'Oui' : 'Non'),
              ...brSteps.map(cs => h(FlowNode, { step: cs, intent: props.intent, stepsByParent: props.stepsByParent, branchesOf: props.branchesOf, depth: props.depth + 1, onEdit: (st) => emit('edit', st), onDelete: (id) => emit('delete', id), onAdd: (p, b) => emit('add', p, b) })),
              h('button', { class: 'af-add-child', onClick: () => emit('add', s.id, br) }, '+'),
            ]))
          }
        }
      } else if (s.type === 'switch') {
        const allBranches = [...new Set(props.intent.steps.filter(c => c.parent === s.id).map(c => c.branch))].filter(Boolean)
        for (const br of allBranches) {
          const brSteps = props.stepsByParent(props.intent.steps, s.id, br)
          children.push(h('div', { class: 'af-branch', key: br }, [
            h('div', { class: 'af-branch-label af-branch-case' }, br),
            ...brSteps.map(cs => h(FlowNode, { step: cs, intent: props.intent, stepsByParent: props.stepsByParent, branchesOf: props.branchesOf, depth: props.depth + 1, onEdit: (st) => emit('edit', st), onDelete: (id) => emit('delete', id), onAdd: (p, b) => emit('add', p, b) })),
          ]))
        }
        children.push(h('button', { class: 'af-add-child', onClick: () => { const br = prompt('Nom de la branche (ex: dying_gasp)'); if (br) emit('add', s.id, br) } }, '+ branche'))
      }

      return h('div', { class: 'af-node-wrap' }, [
        h('div', {
          class: ['af-node', `af-node-${s.type}`],
          style: sevColor ? `border-left: 3px solid ${sevColor}` : '',
          onClick: () => emit('edit', s),
        }, [
          h('div', { class: 'af-node-head' }, [
            h('span', { class: 'af-node-icon' }, icon),
            h('span', { class: 'af-node-label' }, s.label || s.id),
            h('span', { class: 'af-node-type' }, s.type),
            h('button', { class: 'af-node-del', onClick: (e) => { e.stopPropagation(); emit('delete', s.id) } }, '\u2715'),
          ]),
          s.tool ? h('div', { class: 'af-node-detail' }, `\u2699 ${s.tool}`) : null,
          s.message ? h('div', { class: 'af-node-msg' }, s.message.length > 80 ? s.message.slice(0, 80) + '...' : s.message) : null,
          s.action ? h('div', { class: 'af-node-detail af-node-action-detail' }, `\u26A1 ${s.action}`) : null,
          s.note ? h('div', { class: 'af-node-note' }, s.note) : null,
        ]),
        children.length ? h('div', { class: 'af-children' }, children) : null,
      ])
    }
  },
})
export { FlowNode }
</script>

<style>
.af-page { padding: 20px 24px; max-width: 1200px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
.af-loading { padding: 40px; text-align: center; color: #94a3b8; }
.af-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
.af-title { display: flex; align-items: center; gap: 12px; }
.af-title h1 { font-size: 22px; font-weight: 700; margin: 0; }
.af-icon { font-size: 28px; }
.af-subtitle { font-size: 13px; color: #64748b; }
.af-actions { display: flex; gap: 8px; }
.af-btn { padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; cursor: pointer; border: 1px solid #e2e8f0; background: #fff; transition: all .15s; }
.af-btn:hover { background: #f8fafc; }
.af-btn-primary { background: #6366f1; color: #fff; border-color: #6366f1; }
.af-btn-primary:hover { background: #4f46e5; }
.af-btn-primary:disabled { opacity: .5; cursor: default; }
.af-btn-ghost { background: transparent; border-color: #cbd5e1; }
.af-btn-sm { padding: 3px 10px; font-size: 12px; }
.af-btn-x { background: none; border: none; cursor: pointer; color: #94a3b8; font-size: 14px; padding: 2px 6px; }
.af-btn-x:hover { color: #ef4444; }

.af-persona { border: 1px solid #e2e8f0; border-radius: 10px; padding: 14px 18px; margin-bottom: 18px; cursor: pointer; background: #fafbfc; }
.af-persona:hover { border-color: #cbd5e1; }
.af-persona-hdr { font-size: 14px; margin-bottom: 6px; }
.af-persona-rules { display: flex; flex-wrap: wrap; gap: 6px; }
.af-rule-chip { font-size: 11px; background: #f1f5f9; padding: 3px 10px; border-radius: 12px; color: #475569; }
.af-persona-edit { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.af-persona-edit label { font-size: 11px; color: #64748b; font-weight: 600; text-transform: uppercase; }
.af-persona-edit input { padding: 6px 10px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 13px; }
.af-rule-row { display: flex; gap: 6px; align-items: center; }
.af-rule-row input { flex: 1; }

.af-tabs { display: flex; gap: 4px; margin-bottom: 16px; flex-wrap: wrap; }
.af-tab { padding: 7px 16px; border: 2px solid transparent; border-bottom-color: #e2e8f0; border-radius: 8px 8px 0 0; font-size: 13px; font-weight: 600; cursor: pointer; background: #f8fafc; color: #64748b; display: flex; align-items: center; gap: 6px; transition: all .15s; }
.af-tab:hover { background: #f1f5f9; }
.af-tab.active { background: #fff; border-color: currentColor; border-bottom-color: #fff; }
.af-tab-dot { width: 8px; height: 8px; border-radius: 50%; }
.af-tab-add { border: 2px dashed #cbd5e1; color: #94a3b8; }

.af-intent { border: 1px solid #e2e8f0; border-radius: 10px; padding: 18px; background: #fff; }
.af-intent-header { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.af-intent-label { font-size: 18px; font-weight: 700; border: none; outline: none; flex: 1; background: transparent; }
.af-intent-color { width: 28px; height: 28px; border: none; cursor: pointer; border-radius: 6px; }
.af-del-intent { font-size: 16px; }
.af-trigger { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }
.af-trigger label { font-size: 12px; font-weight: 600; color: #64748b; white-space: nowrap; }
.af-trigger input { flex: 1; padding: 6px 10px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 13px; }

.af-tree { }
.af-tree-col { display: flex; flex-direction: column; gap: 4px; }
.af-node-wrap { margin-left: 0; }
.af-children { margin-left: 24px; padding-left: 16px; border-left: 2px solid #e2e8f0; display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.af-branch { margin-top: 4px; }
.af-branch-label { font-size: 11px; font-weight: 700; text-transform: uppercase; padding: 2px 8px; border-radius: 4px; display: inline-block; margin-bottom: 4px; }
.af-branch-yes { background: #dcfce7; color: #166534; }
.af-branch-no { background: #fee2e2; color: #991b1b; }
.af-branch-case { background: #e0e7ff; color: #3730a3; }

.af-node { padding: 10px 14px; border: 1px solid #e2e8f0; border-radius: 8px; cursor: pointer; background: #fff; transition: all .15s; }
.af-node:hover { border-color: #6366f1; box-shadow: 0 1px 4px rgba(99,102,241,.12); }
.af-node-tool { background: #fefce8; border-color: #fde68a; }
.af-node-condition { background: #eff6ff; border-color: #bfdbfe; }
.af-node-switch { background: #f0fdf4; border-color: #bbf7d0; }
.af-node-respond { background: #faf5ff; border-color: #e9d5ff; }
.af-node-action { background: #fff1f2; border-color: #fecdd3; }
.af-node-goto { background: #f0f9ff; border-color: #bae6fd; }

.af-node-head { display: flex; align-items: center; gap: 8px; }
.af-node-icon { font-size: 16px; }
.af-node-label { font-size: 13px; font-weight: 600; flex: 1; }
.af-node-type { font-size: 10px; color: #94a3b8; text-transform: uppercase; font-weight: 600; }
.af-node-del { background: none; border: none; cursor: pointer; color: #cbd5e1; font-size: 12px; padding: 0 4px; }
.af-node-del:hover { color: #ef4444; }
.af-node-detail { font-size: 12px; color: #64748b; margin-top: 4px; }
.af-node-action-detail { color: #dc2626; }
.af-node-msg { font-size: 12px; color: #475569; margin-top: 4px; font-style: italic; white-space: pre-line; }
.af-node-note { font-size: 11px; color: #94a3b8; margin-top: 3px; padding: 2px 6px; background: #f8fafc; border-radius: 3px; }

.af-add-root, .af-add-child { padding: 6px 14px; border: 2px dashed #cbd5e1; border-radius: 8px; color: #94a3b8; font-size: 12px; cursor: pointer; background: transparent; margin-top: 6px; }
.af-add-root:hover, .af-add-child:hover { border-color: #6366f1; color: #6366f1; }

.af-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.4); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.af-modal { background: #fff; border-radius: 12px; width: 480px; max-width: 90vw; max-height: 85vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0,0,0,.15); }
.af-modal-wide { width: 700px; }
.af-modal-hdr { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid #e2e8f0; font-weight: 600; }
.af-modal-hdr button { background: none; border: none; font-size: 18px; cursor: pointer; color: #64748b; }
.af-modal-body { padding: 18px; display: flex; flex-direction: column; gap: 8px; }
.af-modal-body label { font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; margin-top: 4px; }
.af-modal-body input, .af-modal-body select, .af-modal-body textarea { padding: 7px 10px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 13px; font-family: inherit; }
.af-modal-body textarea { resize: vertical; }
.af-input-disabled { background: #f8fafc; color: #94a3b8; }
.af-row { display: flex; gap: 10px; }
.af-row > div { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.af-modal-ftr { padding: 12px 18px; border-top: 1px solid #e2e8f0; display: flex; gap: 8px; justify-content: flex-end; }

.af-prompt-pre { padding: 18px; font-size: 12px; line-height: 1.6; white-space: pre-wrap; max-height: 60vh; overflow-y: auto; background: #f8fafc; margin: 0; font-family: 'SF Mono', monospace; }

.af-json-wrap { margin-top: 12px; }
.af-json { width: 100%; min-height: 500px; padding: 14px; font-family: 'SF Mono', monospace; font-size: 12px; line-height: 1.5; border: 1px solid #e2e8f0; border-radius: 10px; resize: vertical; }
</style>
