<template>
  <q-page class="tech-surface">
    <!-- Collapsed topbar with translucent blur -->
    <header class="detail-topbar">
      <button class="topbar-btn" @click="$router.back()" aria-label="Retour">
        <span class="material-icons">arrow_back</span>
      </button>
      <div class="topbar-title">
        <div class="t-caption" style="color:var(--tg-700);font-weight:700">{{ job?.name || '…' }}</div>
        <div class="topbar-subject">{{ job?.subject || 'Job' }}</div>
      </div>
    </header>

    <!-- Loading state -->
    <div v-if="loading" class="loading-wrap">
      <div class="loading-spinner" />
    </div>

    <template v-if="job && !loading">
      <!-- Status hero strip -->
      <div class="status-hero">
        <span class="tg-chip" :class="statusChipClass">
          <span class="tg-chip-dot" />
          {{ statusLabel }}
        </span>
        <div v-if="job.priority === 'urgent' || job.priority === 'high'" style="margin-left:8px">
          <span class="tg-chip" :class="job.priority === 'urgent' ? 'is-stop' : 'is-work'">
            {{ job.priority === 'urgent' ? 'Urgent' : 'Haute priorité' }}
          </span>
        </div>
      </div>

      <div class="tg-page tg-page--content">

        <!-- Location + GPS -->
        <section v-if="locationAddress || job.customer_name" class="tg-card tg-card--wash section-card">
          <div class="section-head-inline t-micro">Client & adresse</div>
          <div v-if="job.customer_name" class="info-line">
            <span class="material-icons info-icon">person</span>
            <span class="t-body">{{ job.customer_name }}</span>
          </div>
          <div v-if="locationAddress" class="info-line">
            <span class="material-icons info-icon" style="color:var(--sig-stop)">place</span>
            <span class="t-body" style="flex:1">{{ locationAddress }}</span>
            <button class="tg-btn is-ghost is-compact" @click="openGps">
              <span class="material-icons" style="font-size:18px">navigation</span>
              GPS
            </button>
          </div>
          <div v-if="locationDetail?.contact_name" class="info-line" style="gap:8px">
            <span class="material-icons info-icon">support_agent</span>
            <span class="t-body-sm">
              {{ locationDetail.contact_name }}
              <span v-if="locationDetail.contact_phone"> · {{ locationDetail.contact_phone }}</span>
            </span>
          </div>
        </section>

        <!-- Job info (editable fields — kept compact) -->
        <section class="tg-card section-card">
          <div class="section-head-inline t-micro">Détails</div>

          <label class="field-wrap">
            <span class="field-label">Sujet</span>
            <input v-model="job.subject" class="field-input"
              @blur="saveField('subject', job.subject)" />
          </label>

          <div class="field-row-pair">
            <label class="field-wrap">
              <span class="field-label">Type</span>
              <select v-model="job.job_type" class="field-input"
                @change="saveField('job_type', job.job_type)">
                <option v-for="t in jobTypes" :key="t.value" :value="t.value">{{ t.label }}</option>
              </select>
            </label>
            <label class="field-wrap">
              <span class="field-label">Priorité</span>
              <select v-model="job.priority" class="field-input"
                @change="saveField('priority', job.priority)">
                <option v-for="p in priorities" :key="p.value" :value="p.value">{{ p.label }}</option>
              </select>
            </label>
          </div>

          <div class="field-row-pair">
            <label class="field-wrap">
              <span class="field-label">Heure</span>
              <input v-model="job.scheduled_time" type="time" class="field-input"
                @blur="saveField('scheduled_time', job.scheduled_time)" />
            </label>
            <label class="field-wrap">
              <span class="field-label">Durée (h)</span>
              <input v-model.number="job.duration_h" type="number" step="0.5" min="0.5" max="12" class="field-input"
                @blur="saveField('duration_h', job.duration_h)" />
            </label>
          </div>

          <label class="field-wrap">
            <span class="field-label">Notes</span>
            <textarea v-model="job.description" rows="3" class="field-input field-input--ta"
              @blur="saveField('description', job.description)" />
          </label>
        </section>

        <!-- Equipment -->
        <section class="tg-card section-card">
          <div class="section-head-row">
            <span class="t-micro">Équipements · {{ equipment.length }}</span>
            <button class="tg-btn is-text" @click="addEquipmentMenu = true">
              <span class="material-icons" style="font-size:18px">add</span> Ajouter
            </button>
          </div>

          <div v-if="loadingEquip" class="text-center" style="padding:24px">
            <div class="loading-spinner loading-spinner--sm" />
          </div>

          <div v-else-if="equipment.length" class="equip-list">
            <button v-for="eq in equipment" :key="eq.name" class="equip-row"
              @click="$router.push({ name: 'tech-device', params: { serial: eq.serial_number } })">
              <span class="material-icons equip-icon" :style="{ color: eqStatusColor(eq.status) }">
                {{ eqIcon(eq.equipment_type) }}
              </span>
              <div class="equip-text">
                <div class="t-body">{{ eq.equipment_type }} — {{ eq.brand }} {{ eq.model }}</div>
                <div class="t-caption mono">{{ eq.serial_number }}</div>
              </div>
              <span class="tg-chip" :class="eqStatusChip(eq.status)" style="margin-left:auto">
                {{ eq.status || '—' }}
              </span>
            </button>
          </div>

          <div v-else class="empty-inline t-caption">Aucun équipement lié</div>
        </section>
      </div>

      <!-- ── Floating CTA pill (always in thumb reach) ─────────────────────── -->
      <div class="tg-fab-cta">
        <button v-if="isScheduled"
          class="tg-btn is-primary is-block"
          @click="updateStatus('In Progress')" :disabled="saving">
          <span class="material-icons">directions_car</span>
          En route vers le client
        </button>
        <button v-else-if="isInProgress"
          class="tg-btn is-success is-block"
          @click="updateStatus('Completed')" :disabled="saving">
          <span class="material-icons">check_circle</span>
          Marquer comme terminée
        </button>
        <button v-else-if="isCompleted"
          class="tg-btn is-ghost is-block"
          @click="updateStatus('In Progress')" :disabled="saving">
          <span class="material-icons">replay</span>
          Rouvrir la tâche
        </button>

        <!-- Testing shortcut: jump straight to Completed -->
        <button v-if="canTerminateDirect"
          class="tg-btn is-outline is-compact is-block"
          style="margin-top:8px"
          @click="updateStatus('Completed')" :disabled="saving">
          <span class="material-icons" style="font-size:18px">fast_forward</span>
          Terminer directement (test)
        </button>
      </div>
    </template>

    <!-- Add-equipment bottom sheet -->
    <transition name="fade">
      <div v-if="addEquipmentMenu" class="tg-peek-backdrop is-open" @click="addEquipmentMenu = false" />
    </transition>
    <div class="tg-peek" :class="{ 'is-open': addEquipmentMenu }">
      <div class="tg-peek-handle" />
      <div style="padding: 4px 20px 20px">
        <div class="t-h2" style="margin-bottom:12px">Ajouter un équipement</div>
        <button class="equip-option" @click="addEquipmentMenu = false; goScan()">
          <span class="material-icons equip-option-icon" style="color:var(--tg-700)">qr_code_scanner</span>
          <div>
            <div class="t-body">Scanner un code-barres / QR</div>
            <div class="t-caption">Caméra + détection auto du SN ou MAC</div>
          </div>
        </button>
        <button class="equip-option" @click="addEquipmentMenu = false; searchEquipDialog = true">
          <span class="material-icons equip-option-icon" style="color:var(--sig-work)">search</span>
          <div>
            <div class="t-body">Rechercher un équipement existant</div>
            <div class="t-caption">Par numéro de série ou MAC</div>
          </div>
        </button>
        <button class="equip-option" @click="addEquipmentMenu = false; createEquipDialog = true">
          <span class="material-icons equip-option-icon" style="color:var(--sig-go)">add_circle</span>
          <div>
            <div class="t-body">Créer un nouvel équipement</div>
            <div class="t-caption">Saisir manuellement</div>
          </div>
        </button>
      </div>
    </div>

    <!-- Search existing equipment (basic dialog, stays Quasar for now) -->
    <q-dialog v-model="searchEquipDialog">
      <q-card style="min-width:340px;border-radius:20px">
        <q-card-section class="text-h6">Rechercher un équipement</q-card-section>
        <q-card-section>
          <q-input v-model="eqSearchText" label="Numéro de série ou MAC" outlined dense autofocus
            @keyup.enter="searchEquipment" debounce="400" @update:model-value="searchEquipment">
            <template v-slot:append><q-icon name="search" /></template>
          </q-input>
          <q-list v-if="eqSearchResults.length" bordered separator class="q-mt-sm" style="max-height:250px;overflow-y:auto">
            <q-item v-for="eq in eqSearchResults" :key="eq.name" clickable @click="linkEquipToJob(eq)">
              <q-item-section>
                <q-item-label>{{ eq.equipment_type }} — {{ eq.brand }} {{ eq.model }}</q-item-label>
                <q-item-label caption class="mono">SN: {{ eq.serial_number }}</q-item-label>
                <q-item-label caption v-if="eq.customer_name">Client: {{ eq.customer_name }}</q-item-label>
              </q-item-section>
              <q-item-section side><q-icon name="link" color="primary" /></q-item-section>
            </q-item>
          </q-list>
          <div v-if="eqSearchText && !eqSearchResults.length && !eqSearching" class="text-caption text-grey q-mt-sm text-center">
            Aucun résultat
          </div>
        </q-card-section>
        <q-card-actions align="right">
          <q-btn flat label="Fermer" v-close-popup />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <!-- Create new equipment -->
    <q-dialog v-model="createEquipDialog">
      <q-card style="min-width:340px;border-radius:20px">
        <q-card-section class="text-h6">Nouvel équipement</q-card-section>
        <q-card-section>
          <q-input v-model="newEquip.serial_number" label="Numéro de série" outlined dense class="q-mb-sm" autofocus />
          <q-select v-model="newEquip.equipment_type" :options="eqTypes" label="Type" outlined dense class="q-mb-sm" />
          <q-input v-model="newEquip.brand" label="Marque" outlined dense class="q-mb-sm" />
          <q-input v-model="newEquip.model" label="Modèle" outlined dense class="q-mb-sm" />
          <q-input v-model="newEquip.mac_address" label="MAC (optionnel)" outlined dense class="q-mb-sm" />
        </q-card-section>
        <q-card-actions align="right">
          <q-btn flat label="Annuler" v-close-popup />
          <q-btn color="primary" label="Créer & Lier" :loading="creatingEquip" @click="createAndLinkEquip" />
        </q-card-actions>
      </q-card>
    </q-dialog>
  </q-page>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Notify } from 'quasar'
import { getDoc, listDocs, createDoc, updateDoc } from 'src/api/erp'
import { HUB_URL } from 'src/config/hub'

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

const jobName = computed(() => route.params.name)
const loading = ref(true)
const saving = ref(false)
const job = ref(null)
const locationDetail = ref(null)
const equipment = ref([])
const loadingEquip = ref(false)

// Add-equipment dialog state
const addEquipmentMenu = ref(false)
const searchEquipDialog = ref(false)
const createEquipDialog = ref(false)
const eqSearchText = ref('')
const eqSearchResults = ref([])
const eqSearching = ref(false)
const creatingEquip = ref(false)
const eqTypes = ['ONT', 'Modem', 'Routeur', 'Décodeur TV', 'VoIP', 'Amplificateur', 'Splitter', 'Câble', 'Autre']
const newEquip = ref({ serial_number: '', equipment_type: 'ONT', brand: '', model: '', mac_address: '' })

const jobTypes = [
  { label: 'Installation', value: 'Installation' },
  { label: 'Réparation', value: 'Repair' },
  { label: 'Maintenance', value: 'Maintenance' },
  { label: 'Inspection', value: 'Inspection' },
  { label: 'Livraison', value: 'Delivery' },
  { label: 'Autre', value: 'Other' },
]
// Priorité Dispatch Job — SOURCE UNIQUE (config/dispatch-priority).
import { DISPATCH_PRIORITIES as priorities } from 'src/config/dispatch-priority'

// ── Status helpers ─────────────────────────────────────────────────────────
const isScheduled   = computed(() => job.value && ['Scheduled', 'assigned', 'open', 'Open', 'Assigned'].includes(job.value.status))
const isInProgress  = computed(() => job.value && ['In Progress', 'in_progress'].includes(job.value.status))
const isCompleted   = computed(() => job.value?.status === 'Completed')
const canTerminateDirect = computed(() => // raccourci de TEST seulement (dev) — jamais en prod
  import.meta.env.DEV && job.value && !isInProgress.value && !isCompleted.value && job.value.status !== 'Cancelled'
)

const statusLabel = computed(() => {
  const map = {
    Scheduled: 'Planifié', assigned: 'Assigné', open: 'À faire', Open: 'À faire', Assigned: 'Assigné',
    'In Progress': 'En cours', in_progress: 'En cours',
    Completed: 'Terminé', Cancelled: 'Annulé', 'On Hold': 'En attente',
  }
  return map[job.value?.status] || job.value?.status || ''
})
const statusChipClass = computed(() => {
  const s = job.value?.status
  if (isCompleted.value) return 'is-go'
  if (isInProgress.value) return 'is-work'
  if (s === 'Cancelled') return 'is-wait'
  if (s === 'On Hold') return 'is-wait'
  return 'is-info'
})

const locationAddress = computed(() => {
  const loc = locationDetail.value
  if (!loc) return job.value?.service_location_name || ''
  return [loc.address_line, loc.city, loc.postal_code].filter(Boolean).join(', ')
})

// ── Equipment display helpers ──────────────────────────────────────────────
function eqIcon (type) {
  const map = { ONT: 'settings_input_hdmi', Modem: 'router', Routeur: 'wifi', 'Décodeur TV': 'tv', VoIP: 'phone' }
  return map[type] || 'memory'
}
function eqStatusColor (s) {
  if (s === 'Actif') return 'var(--sig-go)'
  if (s === 'Défectueux' || s === 'Perdu') return 'var(--sig-stop)'
  return 'var(--ink-400)'
}
function eqStatusChip (s) {
  if (s === 'Actif') return 'is-go'
  if (s === 'Défectueux' || s === 'Perdu') return 'is-stop'
  return 'is-wait'
}

// ── Load job + related data ────────────────────────────────────────────────
async function loadJob () {
  loading.value = true
  try {
    job.value = await getDoc('Dispatch Job', jobName.value)
    if (job.value.service_location) {
      getDoc('Service Location', job.value.service_location)
        .then(loc => { locationDetail.value = loc })
        .catch(() => {})
    }
    loadEquipment()
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur chargement job: ' + e.message })
  } finally {
    loading.value = false
  }
}

async function loadEquipment () {
  if (!job.value?.service_location && !job.value?.customer) return
  loadingEquip.value = true
  try {
    const filters = job.value.service_location
      ? { service_location: job.value.service_location }
      : { customer: job.value.customer }
    equipment.value = await listDocs('Service Equipment', {
      filters,
      fields: ['name', 'serial_number', 'equipment_type', 'brand', 'model', 'mac_address', 'status', 'customer_name'],
      limit: 50,
    })
  } catch { equipment.value = [] }
  finally { loadingEquip.value = false }
}

// ── Save / status ──────────────────────────────────────────────────────────
async function saveField (field, value) {
  if (!job.value?.name) return
  try { await updateDoc('Dispatch Job', job.value.name, { [field]: value }) }
  catch (e) { Notify.create({ type: 'negative', message: 'Erreur sauvegarde: ' + e.message }) }
}

/**
 * Status changes go through targo-hub /dispatch/job-status — that endpoint
 * is the single place where the chain-walk lives (unblocks depends_on
 * children on Completed, broadcasts SSE). Direct ERPNext PUTs would skip
 * both and the chain wouldn't advance.
 */
async function updateStatus (status) {
  saving.value = true
  try {
    const res = await fetch(`${HUB_URL}/dispatch/job-status`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ job: job.value.name, status }),
    })
    if (!res.ok) throw new Error(`Status update failed (${res.status})`)
    const result = await res.json()
    job.value.status = status
    const msg = status === 'Completed'
      ? (result.unblocked?.length
          ? `Tâche terminée — ${result.unblocked.length} prochaine${result.unblocked.length > 1 ? 's' : ''} débloquée${result.unblocked.length > 1 ? 's' : ''}`
          : 'Tâche terminée ✓')
      : status === 'In Progress' ? 'En route ! 🚗'
      : status === 'Scheduled' ? 'Tâche rouverte' : status
    Notify.create({ type: 'positive', message: msg, icon: status === 'Completed' ? 'check_circle' : 'directions_car' })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
  } finally { saving.value = false }
}

// ── GPS & misc ─────────────────────────────────────────────────────────────
function openGps () {
  const loc = locationDetail.value
  if (loc?.latitude && loc?.longitude) {
    window.open(`https://www.google.com/maps/dir/?api=1&destination=${loc.latitude},${loc.longitude}`, '_blank')
    return
  }
  const addr = loc
    ? [loc.address_line, loc.city, loc.postal_code].filter(Boolean).join(', ')
    : (job.value?.service_location_name || '')
  window.open(`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(addr)}`, '_blank')
}

function goScan () {
  router.push({
    name: 'tech-scan',
    query: {
      job: job.value.name,
      customer: job.value.customer,
      customer_name: job.value.customer_name,
      location: job.value.service_location,
      location_name: job.value.service_location_name,
    },
  })
}

// ── Equipment search / create / link ───────────────────────────────────────
async function searchEquipment () {
  const text = eqSearchText.value?.trim()
  if (!text || text.length < 2) { eqSearchResults.value = []; return }
  eqSearching.value = true
  try {
    let results = await listDocs('Service Equipment', {
      filters: { serial_number: ['like', `%${text}%`] },
      fields: ['name', 'serial_number', 'equipment_type', 'brand', 'model', 'mac_address', 'customer_name', 'status'],
      limit: 10,
    })
    if (!results.length) {
      results = await listDocs('Service Equipment', {
        filters: { mac_address: ['like', `%${text}%`] },
        fields: ['name', 'serial_number', 'equipment_type', 'brand', 'model', 'mac_address', 'customer_name', 'status'],
        limit: 10,
      })
    }
    eqSearchResults.value = results
  } catch { eqSearchResults.value = [] }
  finally { eqSearching.value = false }
}

async function linkEquipToJob (eq) {
  try {
    const updates = {}
    if (job.value.customer) updates.customer = job.value.customer
    if (job.value.service_location) updates.service_location = job.value.service_location
    await updateDoc('Service Equipment', eq.name, updates)
    equipment.value.push(eq)
    searchEquipDialog.value = false
    eqSearchText.value = ''
    eqSearchResults.value = []
    Notify.create({ type: 'positive', message: `${eq.equipment_type} lié au job`, icon: 'link' })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
  }
}

async function createAndLinkEquip () {
  if (!newEquip.value.serial_number?.trim()) {
    Notify.create({ type: 'warning', message: 'Numéro de série requis' })
    return
  }
  creatingEquip.value = true
  try {
    const data = {
      ...newEquip.value,
      status: 'Actif',
      customer: job.value.customer || '',
      service_location: job.value.service_location || '',
    }
    const doc = await createDoc('Service Equipment', data)
    equipment.value.push(doc)
    Notify.create({ type: 'positive', message: 'Équipement créé et lié', icon: 'check_circle' })
    createEquipDialog.value = false
    newEquip.value = { serial_number: '', equipment_type: 'ONT', brand: '', model: '', mac_address: '' }
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
  } finally {
    creatingEquip.value = false
  }
}

onMounted(loadJob)
</script>

<style lang="scss" scoped>
// Floating FAB is 52px tall + 16px margin + 88px tab-island clearance.
// Reserve additional bottom room on this page so scroll reaches the final
// card without it being hidden under the CTA pill.
.tech-surface.q-page { padding-bottom: 188px !important; }

// Topbar (translucent, blur, sticky)
.detail-topbar {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center;
  padding: calc(env(safe-area-inset-top) + 8px) 12px 8px;
  background: var(--surface-over);
  backdrop-filter: saturate(180%) blur(22px);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  border-bottom: 1px solid rgba(15,23,42,0.05);
}
.topbar-btn {
  width: 40px; height: 40px;
  border: 0; background: transparent;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--ink-700);
  -webkit-tap-highlight-color: transparent;
  &:active { background: var(--tg-50); }
}
.topbar-title {
  flex: 1; min-width: 0; text-align: center;
  padding: 0 4px;
}
.topbar-subject {
  font: 700 0.9375rem/1.25 system-ui;
  color: var(--ink-900);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-menu {
  position: fixed; inset: 0;
  z-index: 50;
  background: rgba(15,23,42,0.2);
  backdrop-filter: blur(2px);
  display: flex; align-items: flex-start; justify-content: flex-end;
  padding: 60px 8px 0;
}
.topbar-menu-card {
  background: var(--surface-elev);
  border-radius: var(--r-md);
  box-shadow: var(--elev-3);
  padding: 4px;
  min-width: 220px;
}
.topbar-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 10px 14px;
  border: 0; background: transparent;
  border-radius: var(--r-sm);
  font: var(--t-body-sm);
  text-align: left; cursor: pointer;
  &:active { background: var(--tg-50); }
  .material-icons { font-size: 18px; color: var(--ink-500); }
}

// Status hero strip
.status-hero {
  display: flex; align-items: center;
  padding: 14px 18px;
  background: var(--surface-wash);
}

// Section card spacing
.section-card {
  margin-bottom: 14px;
}
.section-head-inline {
  margin-bottom: 10px;
}
.section-head-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}

// Inline info lines (for location card)
.info-line {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0;
  &:not(:last-child) { border-bottom: 1px solid rgba(15,23,42,0.05); }
  .info-icon { font-size: 18px; color: var(--ink-500); }
}

// Form fields — custom, no Quasar chrome
.field-wrap {
  display: block; margin-bottom: 12px;
  &:last-child { margin-bottom: 0; }
}
.field-label {
  display: block;
  font: var(--t-caption);
  color: var(--ink-500);
  margin-bottom: 4px;
}
.field-input {
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border: 1.5px solid var(--ink-300);
  border-radius: var(--r-sm);
  background: var(--surface-elev);
  font: var(--t-body);
  color: var(--ink-900);
  outline: none;
  transition: border 160ms, box-shadow 160ms;
  &:focus {
    border-color: var(--tg-500);
    box-shadow: 0 0 0 4px rgba(92,89,168,0.12);
  }
}
.field-input--ta {
  min-height: 80px; resize: vertical;
  font: var(--t-body-sm);
}
.field-row-pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  margin-bottom: 12px;
}

// Equipment list
.equip-list {
  display: flex; flex-direction: column; gap: 8px;
}
.equip-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  border: 0;
  background: var(--surface-wash);
  border-radius: var(--r-md);
  cursor: pointer;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: background 160ms;
  &:active { background: var(--tg-100); }
}
.equip-icon { font-size: 22px; flex-shrink: 0; }
.equip-text { flex: 1; min-width: 0; }
.mono { font-family: 'SF Mono', 'Menlo', 'Fira Code', monospace; font-size: 0.85em; }

.equip-option {
  display: flex; align-items: center; gap: 14px;
  width: 100%; padding: 14px;
  border: 0; background: transparent;
  border-radius: var(--r-md);
  text-align: left; cursor: pointer;
  margin-bottom: 4px;
  -webkit-tap-highlight-color: transparent;
  &:active { background: var(--tg-50); }
}
.equip-option-icon { font-size: 28px; flex-shrink: 0; }

.empty-inline {
  text-align: center; padding: 16px;
  color: var(--ink-500);
}

// Loading
.loading-wrap {
  display: flex; align-items: center; justify-content: center;
  padding: 80px 0;
}
.loading-spinner {
  width: 40px; height: 40px;
  border: 3px solid var(--tg-100);
  border-top-color: var(--tg-500);
  border-radius: 50%;
  animation: lspin 0.8s linear infinite;
  &--sm { width: 24px; height: 24px; border-width: 2px; }
}
@keyframes lspin { to { transform: rotate(360deg); } }

.fade-enter-active, .fade-leave-active { transition: opacity 200ms; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>
