<center>
<img src="https://file.garden/Zw17vw8ctXTQw7PV/mewelcome.png" alt="[A pixel drawing of me, a white feminine individual with half pink, half green pigtails and glasses. I am saying WELCOME" width="300px">
</center>

I'm [Agnes the Alien](https://agnes.love/) (it/its), a 25 year old writer, artist, and hobbyist developer. This is my personal blog where I mainly write about mental health, trauma, PTSD, fandom, becoming a convert to Quakerism, fictosexuality, alterhumanity, and pretty much anything on my mind. I'm trying to develop a consistent blogging habit...

Subscribe to my blog via [email](/subscribe/) or [RSS feed](/feed/).

**Last 3 posts**
{{ posts|limit:3 }}

**Tag Cloud**
{{ tags }}


<aside class="tiny-notes">
recently played...

<br>
<iframe src="https://petracoding.github.io/neocities/widgets/lastfm?center=0&marquee=0&font-family=Times New Roman&font-size=14px&color=#9e5461&username=keegbovo&swapPositions=0&delimiter=by&underline=0" frameborder="0" title="Last.Fm Status" width="80px" height="40px"></iframe>
<hr>
**Blog Stats**
<div class="ws-widget">
  <div class="ws-grid" id="ws-grid">
    <p class="ws-loading">Fetching stats…</p>
  </div>
</div>



<script>
document.addEventListener('DOMContentLoaded', function () {
  const grid = document.getElementById('ws-grid')
  if (!grid) return

  function countWords(html) {
    const stripped = html
      .replace(/<pre[\s\S]*?<\/pre>/gi, ' ')
      .replace(/<code[\s\S]*?<\/code>/gi, ' ')
    const text = stripped.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim()
    return text ? text.split(' ').length : 0
  }

  function fmt(n) {
    return n.toLocaleString()
  }

  function createRow(label, value) {
    const row = document.createElement('div')
    row.className = 'ws-row'

    const labelEl = document.createElement('span')
    labelEl.className = 'ws-label'
    labelEl.textContent = label

    const valueEl = document.createElement('span')
    valueEl.className = 'ws-value'
    valueEl.textContent = value

    row.append(labelEl, valueEl)
    return row
  }

  function createLinkedRow(label, post) {
    const row = document.createElement('div')
    row.className = 'ws-row'

    const link = document.createElement('a')
    link.className = 'ws-label ws-link'
    link.textContent = `${label} →`
    link.title = post.title
    link.rel = 'noopener noreferrer'

    try {
      const url = new URL(post.url)
      link.href = (url.protocol === 'https:' || url.protocol === 'http:') ? url.href : '#'
    } catch {
      link.href = '#'
    }

    const valueEl = document.createElement('span')
    valueEl.className = 'ws-value'
    valueEl.textContent = `${fmt(post.words)} words`

    row.append(link, valueEl)
    return row
  }

  fetch('/feed/', { cache: 'no-store' })
    .then(function (res) { return res.text() })
    .then(function (text) {
      const xml = new DOMParser().parseFromString(text, 'application/xml')
      if (xml.querySelector('parsererror')) throw new Error('Invalid XML')

      const isAtom = xml.querySelector('entry') !== null
      const entries = Array.from(xml.querySelectorAll(isAtom ? 'entry' : 'item'))

      const posts = entries.map(function (el) {
        const content = isAtom
          ? (el.querySelector('content')?.textContent || '')
          : (el.getElementsByTagNameNS('http://purl.org/rss/1.0/modules/content/', 'encoded')[0]?.textContent
             || el.querySelector('description')?.textContent || '')
        const dateStr = isAtom
          ? el.querySelector('published')?.textContent
          : el.querySelector('pubDate')?.textContent
        const ts = dateStr ? new Date(dateStr).getTime() : NaN

        return {
          title: el.querySelector('title')?.textContent || 'Untitled',
          url: isAtom
            ? (el.querySelector("link[rel='alternate']")?.getAttribute('href')
               || el.querySelector('link')?.getAttribute('href') || '')
            : (el.querySelector('link')?.textContent || ''),
          words: countWords(content),
          ts,
        }
      }).filter(function (p) { return !isNaN(p.ts) })

      if (!posts.length) {
        grid.replaceChildren()
        const empty = document.createElement('p')
        empty.className = 'ws-empty'
        empty.textContent = 'No posts found.'
        grid.appendChild(empty)
        return
      }

      let totalWords = 0
      let shortest = null
      let longest = null

      for (const p of posts) {
        totalWords += p.words
        if (!shortest || p.words < shortest.words) shortest = p
        if (!longest || p.words > longest.words) longest = p
      }

      const avgWords = Math.round(totalWords / posts.length)

      grid.replaceChildren(
        createRow(' Total words', fmt(totalWords)),
        createRow(' Avg per post', fmt(avgWords)),
        createLinkedRow(' Longest', longest),
        createLinkedRow(' Shortest', shortest)
      )
    })
    .catch(function () {
      grid.replaceChildren()
      const error = document.createElement('p')
      error.className = 'ws-error'
      error.textContent = "Couldn't load feed."
      grid.appendChild(error)
    })
})
</script>
</aside>
