--- layout: layouts/base.njk withBlogSidebar: true ---
{# Support both camelCase (Indiekit Eleventy preset) and underscore (legacy) property names #} {% set bookmarkedUrl = bookmarkOf or bookmark_of %} {% set likedUrl = likeOf or like_of %} {% set replyTo = inReplyTo or in_reply_to %} {% set repostedUrl = repostOf or repost_of %} {% if title %}

{{ title }}

{% else %}
{% if replyTo %}↩ Reply{% elif likedUrl %}♥ Like{% elif repostedUrl %}♻ Repost{% elif bookmarkedUrl %}🔖 Bookmark{% else %}✎ Note{% endif %}
{% endif %}
{% if category %} {# Handle both string and array categories #} {% if category is string %} {{ category }} {% else %} {% for cat in category %} {{ cat }} {% endfor %} {% endif %} {% endif %}
{# Bridgy syndication content - controls what gets posted to social networks #} {# For interaction types (bookmarks, likes, replies, reposts), include the target URL #} {% set bridgySummary = description or summary or (content | ogDescription(280)) %} {% set interactionUrl = bookmarkedUrl or likedUrl or replyTo or repostedUrl %} {% if bridgySummary or interactionUrl %} {% endif %} {# Render photo(s) from frontmatter for photo posts - use eleventy:ignore to skip image transform #} {% if photo %} {% endif %} {% set isInteraction = replyTo or likedUrl or repostedUrl or bookmarkedUrl %} {% set hasContent = content and content | striptags | trim %}
{{ content | safe }}
{# Rich reply context with h-cite microformat #} {% include "components/reply-context.njk" %} {# AI usage disclosure — always shown, collapsed by default, placed after reply context #} {% set aiTextLevel = aiTextLevel or ai_text_level or "0" %} {% set aiCodeLevel = aiCodeLevel or ai_code_level %} {% set aiTools = aiTools or ai_tools %} {% set aiDescription = aiDescription or ai_description %}
AI: Text {% if aiTextLevel === "0" %}None{% elif aiTextLevel === "1" %}Editorial{% elif aiTextLevel === "2" %}Co-drafted{% elif aiTextLevel === "3" %}AI-generated{% endif %}{% if aiCodeLevel %} ¡ Code {% if aiCodeLevel === "0" %}Human{% elif aiCodeLevel === "1" %}AI-assisted{% elif aiCodeLevel === "2" %}AI-generated{% endif %}{% endif %}{% if aiTools %} ¡ {{ aiTools }}{% endif %} {% if aiDescription %}

{{ aiDescription }}

{% endif %}

Learn more about AI usage on this site

{# Pending syndication targets (for services like IndieNews that require u-syndication before webmention) #} {% if mpSyndicateTo %} {% endif %} {# Syndication Footer - shows where this post was also published #} {# Separate self-hosted AP URLs from external syndication targets #} {% set externalSyndication = [] %} {% set selfHostedApUrl = "" %} {% if syndication %} {% for url in syndication %} {% if url.indexOf(site.url) == 0 %} {% set selfHostedApUrl = url %} {% else %} {% set externalSyndication = (externalSyndication.push(url), externalSyndication) %} {% endif %} {% endfor %} {% endif %} {% if externalSyndication.length or selfHostedApUrl %} {% endif %} {# Author h-card for IndieWeb authorship #} {# Pagefind filter metadata — hidden elements for search filtering #} {# JSON-LD Structured Data for SEO #} {# Handle photo as potentially an array #} {% set postImage = photo %} {% if postImage %} {# If photo is an array, use first element (check if first element looks like a URL) #} {% if postImage[0] and (postImage[0] | length) > 10 %} {% set postImage = postImage[0] %} {% endif %} {% endif %} {% if not postImage or postImage == "" %} {% set postImage = image or (content | extractFirstImage) %} {% endif %} {% set postDesc = description | default(content | ogDescription(160)) %} {# Lightbox overlay for article images #}
{# Comments section #} {% include "components/comments.njk" %} {# Webmentions display - likes, reposts, replies #} {% include "components/webmentions.njk" %} {# Post Navigation - Previous/Next #} {% include "components/post-navigation.njk" %}