<script setup lang="ts">
import { computed, ref, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores/app'
import ControllerIndicator from '@/components/ControllerIndicator.vue'
import { rpcClient } from '@/api/rpc-client'

const { t } = useI18n()
const store = useAppStore()

// Server name
const serverName = computed(() => store.serverName)
const editingServerName = ref(false)
const serverNameDraft = ref('')
const serverNameInput = ref<HTMLInputElement | null>(null)

function startEditServerName() {
  serverNameDraft.value = serverName.value
  editingServerName.value = true
  nextTick(() => serverNameInput.value?.select())
}

async function saveServerName() {
  const name = serverNameDraft.value.trim()
  if (!name || name === serverName.value) {
    editingServerName.value = false
    return
  }
  try {
    await rpcClient.call({ method: 'server.set-name', params: { name } })
    store.updateServerName(name)
  } catch (e) {
    if (import.meta.env.DEV) console.error('Failed to rename server:', e)
  }
  editingServerName.value = false
}

// Version & release notes
const version = computed(() => store.serverInfo?.version || '0.0.0')
const showReleaseNotes = ref(false)

// Identity
const serverTorAddressFromStore = computed(() => store.serverInfo?.['tor-address'] || null)
const torAddressFromRpc = ref<string | null>(null)
const serverTorAddress = computed(() => serverTorAddressFromStore.value || torAddressFromRpc.value)
const userDid = computed(() => {
  try {
    return localStorage.getItem('neode_did') || null
  } catch {
    return null
  }
})

const copiedOnion = ref(false)
const copiedDid = ref(false)
let copiedTimer: ReturnType<typeof setTimeout> | null = null

async function copyOnionAddress() {
  const addr = serverTorAddress.value
  if (!addr) return
  try {
    await navigator.clipboard.writeText(addr)
  } catch {
    const ta = document.createElement('textarea')
    ta.value = addr
    ta.style.position = 'fixed'
    ta.style.opacity = '0'
    document.body.appendChild(ta)
    ta.select()
    document.execCommand('copy')
    document.body.removeChild(ta)
  }
  copiedOnion.value = true
  if (copiedTimer) clearTimeout(copiedTimer)
  copiedTimer = setTimeout(() => { copiedOnion.value = false }, 2000)
}

async function copyDid() {
  if (!userDid.value) return
  try {
    await navigator.clipboard.writeText(userDid.value)
  } catch {
    const ta = document.createElement('textarea')
    ta.value = userDid.value
    ta.style.position = 'fixed'
    ta.style.opacity = '0'
    document.body.appendChild(ta)
    ta.select()
    document.execCommand('copy')
    document.body.removeChild(ta)
  }
  copiedDid.value = true
  setTimeout(() => { copiedDid.value = false }, 2000)
}

// Load Tor address on mount if not in store
async function init() {
  if (!serverTorAddressFromStore.value) {
    try {
      const res = await rpcClient.getTorAddress()
      torAddressFromRpc.value = res.tor_address ?? null
    } catch (e) {
      if (import.meta.env.DEV) console.warn('Tor address may not be available yet', e)
    }
  }
}
init()
</script>

<template>
  <!-- Controller indicator - Mobile only -->
  <div class="md:hidden mb-4">
    <ControllerIndicator />
  </div>

  <!-- Info Grid -->
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
    <!-- Server Name Card (editable) — container: Enter to edit, Enter to save, Escape to exit -->
    <div data-controller-container tabindex="0" class="bg-black/20 rounded-xl px-5 py-4 border border-white/10 transition-all hover:-translate-y-1">
      <div class="flex items-center gap-3 mb-2">
        <svg class="w-5 h-5 text-white/70" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
        </svg>
        <p class="text-xs font-semibold text-white/60 uppercase tracking-wide">{{ t('settings.serverName') }}</p>
      </div>
      <div v-if="editingServerName" class="flex items-center gap-2">
        <input
          ref="serverNameInput"
          v-model="serverNameDraft"
          type="text"
          maxlength="64"
          class="flex-1 px-3 py-1.5 bg-white/10 border border-white/20 rounded-lg text-white text-lg font-semibold focus:outline-none focus:border-white/40 transition-colors"
          @keydown.enter="saveServerName"
          @keydown.escape="editingServerName = false"
        />
        <button
          class="px-3 py-1.5 bg-white/10 border border-white/20 rounded-lg text-white/70 hover:text-white hover:bg-white/15 transition-colors text-sm"
          @click="saveServerName"
        >Save</button>
        <button
          class="px-3 py-1.5 text-white/50 hover:text-white/70 transition-colors text-sm"
          @click="editingServerName = false"
        >Cancel</button>
      </div>
      <div v-else class="flex items-center gap-2 group cursor-pointer" @click="startEditServerName">
        <p class="text-lg font-semibold text-white/95">{{ serverName }}</p>
        <svg class="w-4 h-4 text-white/30 group-hover:text-white/60 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
        </svg>
      </div>
    </div>

    <!-- Version Card -->
    <div class="bg-black/20 rounded-xl px-5 py-4 border border-white/10">
      <div class="flex items-center gap-3 mb-2">
        <svg class="w-5 h-5 text-white/70" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
        </svg>
        <p class="text-xs font-semibold text-white/60 uppercase tracking-wide">{{ t('common.version') }}</p>
      </div>
      <div class="flex items-center justify-between">
        <p class="text-lg font-semibold text-white/95">{{ version }}</p>
        <button
          @click="showReleaseNotes = true"
          class="glass-button px-3 py-1.5 text-xs"
        >What's New</button>
      </div>
    </div>

    <!-- Release Notes Modal -->
    <Teleport to="body">
      <Transition name="modal">
        <div v-if="showReleaseNotes" class="fixed inset-0 z-[3000] flex items-center justify-center p-4" @click="showReleaseNotes = false">
          <div class="absolute inset-0 bg-black/60 backdrop-blur-sm"></div>
          <div @click.stop class="glass-card p-6 max-w-lg w-full relative z-10 flex flex-col" style="max-height: 85vh">
            <div class="flex items-start justify-between gap-4 mb-5 shrink-0">
              <h3 class="text-xl font-semibold text-white">What's New</h3>
              <button @click="showReleaseNotes = false" class="p-2 rounded-lg hover:bg-white/10 text-white/70 hover:text-white transition-colors" aria-label="Close">
                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>
              </button>
            </div>
            <div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
              <!-- v1.7.21-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.21-alpha</span>
                  <span class="text-xs text-white/40">Apr 21, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>FIPS bootstrap no longer depends on a single public anchor. You can now add your own anchors — other archipelago nodes or a VPS you control — and the node will dial every one of them to join the mesh on startup. If one anchor is down, the next one seeds the routing layer instead, so a flaky public anchor no longer strands a fresh install.</p>
                  <p>Anchors persist across restarts and are re-applied every five minutes, so a daemon that got temporarily isolated reconnects on its own without anyone having to SSH in. Each anchor carries an operator-editable label so you can remember which is which.</p>
                  <p>No behavior change if you don't configure any — the upstream daemon's own defaults keep working as before. This purely adds an operator-controlled list on top.</p>
                </div>
              </div>
              <!-- v1.7.20-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.20-alpha</span>
                  <span class="text-xs text-white/40">Apr 21, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Fixed a critical bug where nodes on the automatic daily-update schedule could end up offline after their nightly update. The scheduler was killing the service a moment too early, before the built-in restart handler had a chance to bring the new version back up — leaving the node dead until someone SSH'd in and started it manually. The scheduler now hands off cleanly to the same restart path the 'Install Update' button uses, so auto-applied updates come back online on their own.</p>
                  <p>Applies to any node configured for 'Check &amp; Apply Daily' — no change required on your end, the fix ships with this update.</p>
                </div>
              </div>
              <!-- v1.7.19-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.19-alpha</span>
                  <span class="text-xs text-white/40">Apr 21, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Your node no longer offers a version you've already passed as an "available update". If you sideload or skip a release, any stored pointer to an earlier version is dropped on next restart, and the System Update page offers only the genuinely newer release — no more seeing an older version listed as something to install.</p>
                  <p>Version comparison is now numeric, not alphabetic. 1.7.10 correctly outranks 1.7.9 (earlier naive string-order would have got this backwards once the patch number hits double digits), so update prompts and "up to date" checks stay accurate past the nines.</p>
                  <p>A stale manifest from a slow cache or proxy can no longer downgrade your node. If the manifest reports a version equal to or behind what's running, your node treats that as "up to date" rather than offering the older version as an update.</p>
                </div>
              </div>
              <!-- v1.7.18-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.18-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Nodes discovered through a trusted peer now land as Trusted instead of Observer. When your federated peer shares its own peer list with you, those nodes get the same trust level as a direct invite — the link they came through is already one you vetted, so you no longer need to promote them by hand before they can be used normally.</p>
                  <p>The update flow now writes clearer logs at every step. Start of download, cancel, and apply each emit a one-line entry to the system journal with the staging path and the affected files, so if a download misbehaves on your node it's easy to see exactly where it got to.</p>
                </div>
              </div>
              <!-- v1.7.17-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.17-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>When a download gets stuck, you can now cancel it. A new Cancel Download button sits next to the progress bar — it stops the transfer, clears the partial file, and returns you to a clean state so you can retry. No more staring at a frozen bar with no way to recover.</p>
                  <p>Downloads that stall for 30 seconds or more now say so. The progress bar turns amber and shows 'Download appears stuck — try Cancel and start again' instead of just sitting silently at whatever percent it reached.</p>
                  <p>Canceling is fast. It no longer has to wait out the retry timer — the download bails within half a second, so you're not stuck watching a stuck screen while you wait to unstick it.</p>
                </div>
              </div>
              <!-- v1.7.16-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.16-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Federation is now bidirectional and instant. When someone joins using your invite code, their node appears on your Federation page automatically — no need for the inviter to click Sync or wait for the next poll. Names and node details populate within seconds of the handshake finishing.</p>
                  <p>New nodes can no longer federate with themselves. Accepting an invite that points back at the local node (by DID, public key, or onion address) is rejected up front, so self-peering no longer clutters the node list with a duplicate card.</p>
                  <p>Transitive discovery: if nodes A and B are already federated and node C joins A, all three nodes now learn about each other. The new peer is pulled in as an Observer entry on existing federation members, so you can promote to Trusted with one click instead of trading a second invite code.</p>
                  <p>The Federation page auto-refreshes every five seconds while it's open. Status changes, new peers, and incoming join requests surface on their own — clicking Sync remains available for an on-demand pull.</p>
                </div>
              </div>
              <!-- v1.7.15-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.15-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Updates survive network hiccups. Downloads now resume from exactly where a dropped connection left off, and retry up to 6 times with increasing gaps between attempts, instead of restarting from byte zero or giving up.</p>
                  <p>The download progress bar now shows real progress. Instead of a fake number that creeps to 95% and freezes, you see the actual bytes arriving, and it continues to update correctly even if you navigate away and come back.</p>
                  <p>Update check itself retries on slow responses. If git.tx1138.com is momentarily overloaded, the node tries three times with a five-second wait between attempts before concluding you're up to date.</p>
                </div>
              </div>
              <!-- v1.7.14-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.14-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Installing an update now shows a full-screen progress overlay with the Archipelago logo, a status message, and an animated bar. The page reloads itself automatically once the new version is up — no manual refresh. If something stalls, a 'Reload now' button appears after a few minutes.</p>
                  <p>Download progress no longer looks frozen near the end. The bar pauses at 95% with a 'Finishing download — verifying checksum…' message and spinner while the last bytes arrive and are hashed.</p>
                  <p>FIPS Reconnect now genuinely tries to fix the anchor. It runs a proper recovery sequence (stop → start → wait for the bootstrap window → check peers) and tells you the likely reason it's still unreachable — corrupt identity key, seed not unlocked, network blocking UDP, or the anchor server being down — instead of a generic 'try again'.</p>
                  <p>Healed a latent FIPS identity bug: the public-key file was being written in text form (an 'npub1…' string) on some nodes, which the daemon couldn't parse and silently authenticated with a garbage key. The Reconnect button now rewrites the file in the correct binary format and re-installs the config before restarting — nodes stuck with no peers for 'no reason' should come back online.</p>
                  <p>AIUI (Claude sidebar) is back. The installer now ships AIUI in the frontend bundle and preserves it across future updates — it was being wiped on every OTA because it lived outside the Vue build.</p>
                  <p>Installing a big app (IndeedHub, Bitcoin, Penpot) no longer gives up early and shows 'didn't work' while the download is still running in the background. The client waits up to 45 minutes for the install pipeline to finish.</p>
                  <p>'Rollback to Previous' is now labelled 'Rollback Available' — clearer that it's a choice you have, not a status you're stuck with.</p>
                </div>
              </div>
              <!-- v1.7.13-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.13-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>App catalog now loads reliably. Before, the Marketplace / Discover page couldn't fetch the catalog of apps because the upstream host wasn't sending the right CORS headers and the node's security policy didn't allow the fallback URL either. The node now fetches the catalog server-side and serves it same-origin to the browser — no more blank app lists.</p>
                </div>
              </div>
              <!-- v1.7.12-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.12-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Nothing new — version bump so freshly-installed nodes (from the 1.7.11 ISO) have something to OTA down, confirming the end-to-end update pipeline out of the box.</p>
                </div>
              </div>
              <!-- v1.7.11-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.11-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>OTA proof release — first version where Install Update should run clean from the UI with no manual steps. Click it and watch the sidebar flip to 1.7.11-alpha on its own.</p>
                </div>
              </div>
              <!-- v1.7.10-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.10-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Install Update actually applies now. The installer had to write into system folders that the backend service was sandboxed out of — every earlier 'Failed to apply update' was a layer of that onion. Fixed by running the file swaps in a separate system context.</p>
                  <p>FIPS status on the Home and Server pages now reflects whether the public anchor is reachable. You'll see 'Active · N peers' (green) when healthy or 'No anchor' (orange) when the network is blocking the bootstrap — same signal as the full FIPS card.</p>
                  <p>Pasting an https://… URL into the profile picture or banner now previews correctly. Before, if the URL failed to load, the UI would silently blank out instead of showing your initial as a placeholder.</p>
                  <p>Uploaded profile pictures under 64 KB are now embedded directly in your Nostr profile (as a data URL), so any Nostr client can see them — not just ones routing over Tor. Larger uploads keep the onion URL for now, with a hint to paste a public URL for wider visibility.</p>
                </div>
              </div>
              <!-- v1.7.9-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.9-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>OTA verification release — nothing new to see. Click Install Update, grab a coffee, and watch the sidebar flip to 1.7.9-alpha on its own. If this one works end to end, the pipeline is solid and future updates will flow the same way.</p>
                </div>
              </div>
              <!-- v1.7.8-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.8-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Install Update finally works end-to-end over the air. The installer was trying to overwrite the running backend binary with a tool that fails on in-use files (ETXTBSY) — swapped it for an atomic rename, which the kernel allows on a live executable. Every previous 'Failed to apply update' attempt was this one root cause.</p>
                </div>
              </div>
              <!-- v1.7.7-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.7-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Over-the-air update test — no feature changes, just a version bump so your node can walk through the whole update flow end-to-end using the new robust installer. Safe to apply; nothing to do afterwards.</p>
                </div>
              </div>
              <!-- v1.7.6-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.6-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Install Update is now more robust. Each install gets its own uniquely-named staging folder and then moves files into place — the previous version had a small cleanup step that could hit a transient filesystem hiccup and bail out halfway. You'll also still see a rollback folder after a successful install.</p>
                  <p>Dev-box OTA: nodes that build archipelago from source can now opt into the standard Download → Install flow instead of Pull &amp; Rebuild, by setting ARCHIPELAGO_UPDATE_URL in the service environment. Useful when the dev machine has a checked-out repo but you want to test the regular update path.</p>
                </div>
              </div>
              <!-- v1.7.5-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.5-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Over-the-air update test — no feature changes, just a fresh version number so your node can walk through the whole update flow end-to-end: check, download, install, auto-restart. Safe to apply; nothing to do afterwards.</p>
                </div>
              </div>
              <!-- v1.7.4-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.4-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Install Update actually installs now. Before, the final step extracted the new UI into the wrong folder and bailed with 'Failed to apply update' — your node ended up backing up cleanly but never swapping in the new files. Fixed.</p>
                  <p>Download progress no longer overshoots 100%. You'll see the bar climb smoothly to 95% and then jump to 100% when the download actually finishes.</p>
                </div>
              </div>
              <!-- v1.7.3-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.3-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>The version number in the sidebar now always matches the actual running version — no more lying to you about being on an older release after an update.</p>
                  <p>FIPS Mesh card on the server page: cleaner layout on desktop (no more awkward gaps), and a one-click Reconnect button when the public anchor is unreachable — it restarts the FIPS daemon so it can re-bootstrap from the anchor.</p>
                  <p>Profile pictures now show correctly in the identity list and editor. Before, uploaded images silently failed to render because the URL was only reachable over Tor; the UI now rewrites them to a local path while keeping the external URL for other Nostr clients.</p>
                  <p>Identity rows now show your Display Name first (from your Nostr profile) with the internal identity name beside it in parentheses, so you see the name other people will see — not just the one you picked when creating it.</p>
                </div>
              </div>
              <!-- v1.7.2-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.2-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Install Update now actually installs. Before, the button would back up your current version then fail with 'Failed to apply update' because the installer couldn't write into system folders.</p>
                  <p>The button's also been renamed to 'Install Update' (previously 'Apply Update') and the node restarts itself a moment after you click it — no more manual restart step.</p>
                  <p>Your existing identities now show the generated avatar instead of just their initials — same look as freshly created ones.</p>
                  <p>Everything from 1.7.0-alpha and 1.7.1-alpha carries over (default avatars on creation, one-click Save publishes to Nostr relays, public blob URLs for profile pictures, 30-minute download window, VPN peer restore on reboot, reconciler-only-repairs, filebrowser fix).</p>
                </div>
              </div>
              <!-- v1.7.1-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.1-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Over-the-air update test — same features as 1.7.0, just a fresh version number so your node can try the new download-and-apply flow end-to-end. Safe to apply; nothing to do afterwards.</p>
                </div>
              </div>
              <!-- v1.7.0-alpha -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.0-alpha</span>
                  <span class="text-xs text-white/40">Apr 20, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Every identity now gets a personal avatar the moment it's created. Your main node identity gets a distinctive hexagonal-network icon; other identities get a colourful generated pattern unique to each one.</p>
                  <p>Profile editor: upload a profile picture and a banner, then tap Save — your Nostr profile now goes out to the relays in one step. No more 'Save' vs 'Save &amp; Publish' confusion.</p>
                  <p>Profile pictures and banners you upload are now reachable by other Nostr clients across the network — not just your own browser. Anyone who sees your profile on a relay can load the image.</p>
                  <p>Update downloads on slow connections no longer cut out right at the end. The client waits up to 30 minutes for each component instead of giving up after 15 seconds.</p>
                  <p>When you move a node to a new version without going through Check for Updates (for example via a reinstall or manual copy), it now reports the new version correctly instead of endlessly saying 'update available'.</p>
                  <p>Your VPN peers come back automatically after a reboot. No more rescanning QR codes on your phone or laptop.</p>
                  <p>Fresh installs stay lean — only File Browser is included out of the box. Other apps wait in the Marketplace until you pick them.</p>
                  <p>File Browser stops rebooting itself every few hours — the housekeeper now leaves it alone once it's healthy.</p>
                  <p>One-click 'Pull &amp; Rebuild' button works for nodes that update from source (the development path), not just the standard download path.</p>
                  <p>The download progress number is now clean (like 45.23%) instead of 45.270894%.</p>
                </div>
              </div>
              <!-- v1.3.5 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.3.5</span>
                  <span class="text-xs text-white/40">Apr 11, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <p>Migrated container registry to git.tx1138.com</p>
                </div>
              </div>
              <!-- v1.3.4 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.3.4</span>
                  <span class="text-xs text-white/40">Apr 7, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">NostrVPN — Built-in Mesh VPN</h4>
                    <p>NostrVPN is now a native system service. Peer discovery via Nostr relays, WireGuard tunnels. Auto-configured with your node's identity during onboarding — no setup required.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">New Marketplace Apps</h4>
                    <p>FIPS (encrypted mesh network) and Routstr (decentralized AI inference with Cashu payments) available as installable apps. Status UIs included for headless apps.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">ISO Boot Fix</h4>
                    <p>Fixed backend service crash on fresh ISO installs caused by overly restrictive systemd security settings. Fresh installs now boot cleanly.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">Bootstrap from Trusted Node</h4>
                    <p>New installs auto-connect to a trusted Bitcoin node via Tor during initial sync. ElectrumX, LND, and BTCPay work immediately while your local chain catches up.</p>
                  </div>
                </div>
              </div>
              <!-- v1.3.0 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.3.0</span>
                  <span class="text-xs text-white/40">Mar 19, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Full Security Audit</h4>
                    <p>33 security findings from a comprehensive penetration test — all fixed. Backend now only accessible through nginx. Path traversal, SSRF, and XSS vulnerabilities eliminated. Federation requires cryptographic signatures. Session tokens rotate after 2FA. Destructive operations now require password confirmation.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">Container Reliability</h4>
                    <p>Memory limits on every container prevent one app from crashing the whole system. Crashed apps now show a red "crashed" badge with a restart button instead of disappearing. Smart health status shows "starting up", "healthy", or "unhealthy" in real time. Apps you stop stay stopped — no more auto-restart fighting.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">Wallet on Home</h4>
                    <p>The Home dashboard now shows your Bitcoin wallet with on-chain, Lightning, and ecash balances. Send, receive, and view transaction history right from the home screen. New Transactions modal shows your full history with confirmations.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">LND Connect Fixed</h4>
                    <p>Connect Your Wallet (Zeus, Zap, BlueWallet) now works over both local network and Tor. QR codes generate correctly with REST API access.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">UI Polish</h4>
                    <p>Mesh view redesigned. New glass button styles throughout. Restart button on running apps. Improved app status badges. Cleaner navigation on the Apps page.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.9 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.9</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Security Hardening Complete</h4>
                    <p>All 12 pentest findings fixed. CSRF tokens now survive restarts. Password hashing upgraded to Argon2id. Bitcoin RPC gets a unique random password on every install. Federation messages require ed25519 signatures.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">7 Bugs Squashed</h4>
                    <p>Random logouts fixed (P0). Uninstall dialog is now a proper full-screen modal with an "Uninstalling..." overlay. App cards no longer flicker between Start/Launch during container scans. ElectrumX index estimate corrected.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">Bitcoin Sync on Dashboard</h4>
                    <p>Homepage System card now shows Bitcoin Core sync progress, block height, and green/orange status indicator when Bitcoin is running.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.8 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.8</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Pentest Remediation (9/12)</h4>
                    <p>Fixed 9 of 12 security findings: session auth on LND connect info, DEV_MODE removed from production, ed25519 signature verification on node messages, path traversal protection, NIP-07 origin validation, AIUI session checks, strict onion validation.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">UI Polish Batch</h4>
                    <p>Fedimint renamed to "Fedimint Guardian". Tab-launch icons. Marketplace sorts installed apps to end. Mesh mobile layout fixed. On-Chain first in receive modals. Federation shows names instead of DIDs. Cleaner iframe error screens.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.7 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.7</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Marketplace & Credentials</h4>
                    <p>29 containers running rootless. Marketplace app aliases working. Credential injection for inter-container authentication.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.4-6 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.4-6</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Rootless Podman Migration</h4>
                    <p>Migrated all containers from root to rootless Podman. UID namespace mapping, volume ownership fixes, sysctl tuning. Bitcoin RPC verified, all web services confirmed healthy. 29 containers up and running.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.2-3 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.2-3</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Systemd Hardening Restored</h4>
                    <p>Full systemd security sandbox restored now that containers run rootless. NoNewPrivileges, restricted namespaces, and system call filtering re-enabled. Session persistence and boot sequence fixes.</p>
                  </div>
                </div>
              </div>
              <!-- alpha.1 -->
              <div>
                <div class="flex items-center gap-2 mb-3">
                  <span class="text-xs font-mono px-2 py-0.5 rounded bg-white/10 text-white/60">v1.2.0-alpha.1</span>
                  <span class="text-xs text-white/40">Mar 18, 2026</span>
                </div>
                <div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
                  <div>
                    <h4 class="text-white font-medium mb-1">Mesh Radio & Container Stability</h4>
                    <p>LoRa mesh radio auto-detects USB port changes with a new Connect button. Fixed container crash loops — all apps start cleanly and stay stable. Apps starting up show progress instead of re-appearing in the store. Tor routing enabled by default for Bitcoin and Lightning.</p>
                  </div>
                  <div>
                    <h4 class="text-white font-medium mb-1">Off-Grid Bitcoin</h4>
                    <p>Receive Bitcoin block headers over mesh radio. Dead man's switch broadcasts location to trusted contacts if you go silent. GPS sharing is opt-in only.</p>
                  </div>
                </div>
              </div>
            </div>
            <button @click="showReleaseNotes = false" class="glass-button w-full mt-4 py-2 text-sm shrink-0">Close</button>
          </div>
        </div>
      </Transition>
    </Teleport>

    <!-- Session Card -->
    <div class="bg-black/20 rounded-xl px-5 py-4 border border-white/10 md:col-span-2">
      <div class="flex items-center gap-3 mb-2">
        <svg class="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
        </svg>
        <p class="text-xs font-semibold text-white/60 uppercase tracking-wide">{{ t('settings.sessionStatus') }}</p>
      </div>
      <p class="text-base font-medium text-white/90">{{ t('settings.loggedIn') }}</p>
    </div>

    <!-- Identity Card: DID + Tor Address -->
    <div v-if="userDid || serverTorAddress" class="bg-black/20 rounded-xl px-5 py-4 border border-white/10 md:col-span-2 space-y-4">
      <div v-if="userDid">
        <div class="flex items-center justify-between gap-2 mb-2">
          <div class="flex items-center gap-3 min-w-0">
            <svg class="w-5 h-5 text-amber-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
            </svg>
            <p class="text-xs font-semibold text-white/60 uppercase tracking-wide">{{ t('settings.yourDid') }}</p>
          </div>
          <button
            @click="copyDid"
            class="shrink-0 px-3 py-1.5 rounded-lg glass-button glass-button-sm text-xs font-medium text-white/90 hover:text-white transition-colors flex items-center gap-1.5"
          >
            <svg v-if="!copiedDid" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
            </svg>
            <span v-else class="text-green-400 text-xs">{{ t('common.copied') }}</span>
            <span v-if="!copiedDid">{{ t('common.copy') }}</span>
          </button>
        </div>
        <p class="text-sm font-mono text-white/90 break-all" :title="userDid">{{ userDid }}</p>
        <p class="text-xs text-white/50 mt-1">{{ t('settings.didHelper') }}</p>
      </div>
      <div v-if="serverTorAddress" :class="userDid ? 'pt-4 border-t border-white/10' : ''">
        <div class="flex items-center gap-3 mb-2">
          <svg class="w-5 h-5 text-amber-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
          </svg>
          <p class="text-xs font-semibold text-white/60 uppercase tracking-wide">{{ t('settings.onionAddress') }}</p>
        </div>
        <p class="text-sm font-mono text-amber-400/90 break-all mb-1" :title="serverTorAddress">{{ serverTorAddress }}</p>
        <p class="text-xs text-white/50 mb-3">{{ t('settings.onionHelper') }}</p>
        <button
          @click="copyOnionAddress"
          class="w-full min-h-[44px] rounded-lg glass-button text-sm font-medium text-white/90 hover:text-white transition-colors flex items-center justify-center gap-2"
        >
          <svg v-if="!copiedOnion" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
          </svg>
          <span v-if="!copiedOnion">{{ t('common.copy') }}</span>
          <span v-else class="text-green-400">{{ t('common.copied') }}</span>
        </button>
      </div>
    </div>
  </div>
</template>
