<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://jonathanfrei.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jonathanfrei.com/" rel="alternate" type="text/html" /><updated>2026-08-07T03:15:21+00:00</updated><id>https://jonathanfrei.com/feed.xml</id><title type="html">Jonathan Frei - Based on a true story</title><subtitle>Personal site and blog of Jonathan Frei. Short posts, long-form articles, and notes.</subtitle><author><name>Jonathan Frei</name><email>hi@jonathanfrei.com</email></author><entry><title type="html">The Accidental Wallpaper of the Modern Web</title><link href="https://jonathanfrei.com/2026/08/06/accidental-wallpaper-modern-web" rel="alternate" type="text/html" title="The Accidental Wallpaper of the Modern Web" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/06/accidental-wallpaper-modern-web</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/06/accidental-wallpaper-modern-web"><![CDATA[<p>In 2013, a Montreal startup called Crew was bleeding money. To stay afloat, they hired a photographer to shoot custom imagery for their website, but ended up using only a fraction of the photos. Instead of letting the remaining high-resolution files languish on a hard drive, founder Mikael Cho posted ten leftover photos to a simple $19 Tumblr blog with a single instruction: <em>“Do whatever you want with them.”</em></p>

<p>That humble Tumblr feed grew into <a href="https://unsplash.com/about">Unsplash</a>—the web’s default visual infrastructure.</p>

<p>What began as a desperate side project to drive traffic to an agency eventually became the primary source of aesthetic atmosphere for millions of landing pages, pitch decks, medium posts, and app mockups. If you’ve spent any time on the internet over the past decade, you know the aesthetic intimately: dramatic moody lighting, coffee cups sitting next to open MacBooks, foggy pine forests, and anonymized street photography. Unsplash didn’t just democratize high-resolution photography—it inadvertently standardized the visual language of modern web design.</p>

<p>The genius of Unsplash was always its friction-free licensing. By adopting a zero-friction model long before traditional stock agencies understood what hit them, they unlocked an unprecedented network effect. Creators got instant exposure and massive impression metrics, while designers gained access to studio-quality imagery without corporate purchase orders or licensing headaches.</p>

<p>Of course, hyper-growth creates its own gravity. When Getty Images <a href="https://unsplash.com/blog/unsplash-getty-images/">acquired Unsplash in 2021</a>, critics predicted an immediate retreat behind paywalls and copyright enforcement. Instead, Unsplash managed to preserve its core free library while layering on commercial tiers like Unsplash+—a fascinating case study in how a side project transitions into institutional web architecture without completely burning its original community ethos.</p>

<p>It remains a masterclass in modern digital leverage: a simple side experiment, built from leftover assets, that fundamentally rewired how the web looks.</p>

<p>(via <a href="https://unsplash.com/about">Unsplash About</a>)</p>]]></content><author><name>Jonathan Frei</name></author><category term="design" /><category term="web-history" /><category term="photography" /><category term="culture" /><summary type="html"><![CDATA[How a leftover batch of hire-a-hacker photoshoot photos became the ubiquitous visual backdrop for an entire decade of internet projects.]]></summary></entry><entry><title type="html">The Blog That Is a Single File</title><link href="https://jonathanfrei.com/2026/08/06/the-blog-that-is-a-single-file.md" rel="alternate" type="text/html" title="The Blog That Is a Single File" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/06/the-blog-that-is-a-single-file.md</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/06/the-blog-that-is-a-single-file.md"><![CDATA[<p>Someone built a site called <a href="https://claude-blog.md/">claude-blog.md</a> that is, quite literally, just a raw Markdown file rendered directly in the browser. No static site generator, no serverless hydration layer, no build steps, and no dynamic client-side router running three separate JS workers. Just text and a clean parser.</p>

<p>It brings back memories of the early web’s best impulse: fetching a raw document across a wire, reading it, and moving on with your day.</p>

<hr />

<h2 id="the-build-step-that-wasnt">The Build Step That Wasn’t</h2>

<p>For the last decade, personal blogging software went down a strange path. What used to be a <code class="language-plaintext highlighter-rouge">index.html</code> file on a university server somehow turned into a full-blown software project. You don’t just write a post anymore; you configure Next.js, manage Node dependencies, fix broken Tailwind builds, and tweak GraphQL queries just to publish three paragraphs about a movie you saw on Tuesday.</p>

<p>Projects like <code class="language-plaintext highlighter-rouge">claude-blog.md</code> strip that entire apparatus away. The source document <em>is</em> the page.</p>]]></content><author><name>Jonathan Frei</name></author><category term="web-design" /><category term="indieweb" /><category term="markdown" /><category term="architecture" /><summary type="html"><![CDATA[A look at claude-blog.md and the quiet resurgence of hyper-minimal, zero-build text files as web architecture.]]></summary></entry><entry><title type="html">The Rhyme of the Machine</title><link href="https://jonathanfrei.com/2026/08/06/the-rhyme-of-the-machine.md" rel="alternate" type="text/html" title="The Rhyme of the Machine" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/06/the-rhyme-of-the-machine.md</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/06/the-rhyme-of-the-machine.md"><![CDATA[<p>If you spend enough time reading on the web today, you start to feel an unsettling sense of linguistic déjà vu. Every third essay opens with a sweeping observation about an “ever-evolving landscape.” Every critique pivots on a dramatic reframe (“It’s not X—it’s Y”). Every product announcement promises to “quietly orchestrate” your life while honoring the “rich tapestry” of modern work.</p>

<p>We are drowning in synthetic cadence. Generative models haven’t just automated prose; they’ve standardized a dialect.</p>

<p>Enter <a href="https://tropes.fyi/">tropes.fyi</a>, a living taxonomy of AI writing habits curated by designer and engineer <a href="https://ossama.is">Ossama Al-Qarni</a>. It is less a standard style guide and more a field guide to machine-generated mannerisms, cataloging the subtle, pervasive patterns that instantly signal a piece of text was spat out by a large language model.</p>

<h3 id="the-mechanics-of-synthetic-prose">The Mechanics of Synthetic Prose</h3>

<p>The obvious tells were identified early on. In 2023, anyone with an internet connection noticed the sudden, viral explosion of the word <em>delve</em>. Overnight, an obscure verb became the universal prefix for every introductory paragraph on LinkedIn.</p>

<p>But as Al-Qarni’s index demonstrates, vocabulary is only the surface level of the problem. The real tell of synthetic text isn’t a single word; it’s the underlying structural rhythm—what the guide calls the “architecture of artificial profundity.”</p>

<p>Consider the structural habits cataloged on the site:</p>

<ul>
  <li><strong>Negative Parallelism:</strong> The compulsive reliance on “It’s not X—it’s Y.” It’s an easy mechanism to manufacture instant depth by pretending to subvert expectations.</li>
  <li><strong>Tricolon Abuse:</strong> Grouping ideas into rhythmic sets of three (“identity, payments, and compute”) until the prose reads like a metronome rather than a human voice.</li>
  <li><strong>The “Serves As” Dodge:</strong> Replacing simple copulas (“is”, “are”) with grander alternatives like “stands as” or “serves as a testament to.”</li>
  <li><strong>Bold-First Bullets:</strong> Formatting every single list item with a bolded header phrase, a habit inherited directly from Reinforcement Learning from Human Feedback (RLHF) preferences tuned for scannability over voice.</li>
</ul>

<p>When these tropes compound within an essay, the text loses its human friction. It becomes frictionless, sterile, and ultimately unreadable.</p>

<h3 id="why-models-write-this-way">Why Models Write This Way</h3>

<p>These patterns aren’t random quirks; they are the direct mathematical byproduct of how modern models are trained.</p>

<p>Because LLMs predict the next most probable token, they naturally gravitate toward statistical averages. When you combine base probabilistic modeling with RLHF—where human evaluators consistently rate structured, agreeable, and authoritative-sounding responses higher—you end up with a model that defaults to a very specific persona. It writes like a overly enthusiastic middle-management consultant who just finished a workshop on public speaking.</p>

<p>The model avoids simple declarative statements because simple statements carry risk and lack the surface polish of complex clauses. Instead, it reaches for “False Ranges” (“from innovation to transformation”) and “Grandiose Stakes Inflation” to make mundane observations feel world-historical.</p>

<p>The ironic result is that in an effort to make AI outputs sound helpful and polished, alignment training created a distinct dialect that human readers now instinctually recoil from.</p>

<h3 id="the-curation-imperative">The Curation Imperative</h3>

<p>When the cost of generating text drops to zero, the value of written work shifts entirely to voice, precision, and editing.</p>

<p>Tools like <a href="https://tropes.fyi/">tropes.fyi</a> (and its raw, system-prompt-ready <a href="https://tropes.fyi/tropes-md">markdown repository</a>) matter because they give us a vocabulary to debug our own prompts and editing processes. Feeding these anti-patterns directly into an LLM’s system instructions helps strip away the performative fluff, forcing the model closer to plain, direct English.</p>

<p>Yet, relying solely on negative constraints is only half the battle. You can ban “delve,” forbid double hyphens, and blacklist “tapestry,” but if the underlying thought lacks a clear perspective, the model will simply invent new ways to be bland.</p>

<p>Good writing—whether produced by a human sitting at a mechanical keyboard or a human steering an inference engine—requires specificity. It requires real examples, logical leaps, asymmetric observations, and the willingness to take a clear stance without wrapping it in three layers of polite hedge-phrasing.</p>

<p>The web doesn’t need more “robust frameworks for navigating complex landscapes.” It needs sharp arguments, explicit attribution, and prose that sounds like it was written by someone with actual skin in the game.</p>

<p>(via <a href="https://tropes.fyi/">tropes.fyi</a>)</p>]]></content><author><name>Jonathan Frei</name></author><category term="ai" /><category term="writing" /><category term="web-culture" /><category term="design" /><summary type="html"><![CDATA[Why tropes.fyi is the most essential style guide for the synthetic web, and why cutting out AI tells requires more than just deleting the word 'delve'.]]></summary></entry><entry><title type="html">The Unsung Workhorse of the Open Web: Inside jsDelivr</title><link href="https://jonathanfrei.com/2026/08/06/the-unsung-infrastructure-of-jsdelivr" rel="alternate" type="text/html" title="The Unsung Workhorse of the Open Web: Inside jsDelivr" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/06/the-unsung-infrastructure-of-jsdelivr</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/06/the-unsung-infrastructure-of-jsdelivr"><![CDATA[<p>If you have inspected network requests on a modern web page, you have encountered <code class="language-plaintext highlighter-rouge">cdn.jsdelivr.net</code>. It sits behind millions of web applications, serving minified JavaScript libraries, CSS frameworks, fonts, and assets without charging a cent.</p>

<p>Yet, compared to commercial infrastructure providers or high-profile open-source foundations, <a href="https://www.jsdelivr.com/">jsDelivr</a> operates with remarkably little fan-fare. It is a critical piece of global utility infrastructure hiding in plain sight—a multi-CDN network that routes petabytes of traffic every month to keep the open web fast, accessible, and resilient.</p>

<p><img src="https://images.unsplash.com/photo-1558494949-ef010cbdcc31?auto=format&amp;fit=crop&amp;w=1200&amp;q=80" alt="" /></p>

<h2 id="the-public-cdn-dilemma">The Public CDN Dilemma</h2>

<p>In the early days of client-side web development, hosting external libraries was a persistent friction point. Developers either hosted every third-party script locally—consuming their own server bandwidth and cache budgets—or relied on fragmented public CDNs like Google Hosted Libraries or cdnjs.</p>

<p>While Google’s CDN was reliable, its catalog was strictly curated and limited to major libraries like jQuery or AngularJS. If you needed a niche package from npm or a specific tagged release on GitHub, you were on your own.</p>

<p>jsDelivr emerged to bridge this structural gap. Instead of relying on manual submissions or maintainer approval for every release, jsDelivr connected directly to open-source registries. By treating <a href="https://www.npmjs.com/">npm packages</a> and <a href="https://github.com/">GitHub repositories</a> as primary content sources, it automated the pipeline between source code published by developers and production-ready assets fetched by browser clients.</p>

<h2 id="multi-cdn-architecture-redundancy-by-design">Multi-CDN Architecture: Redundancy by Design</h2>

<p>Serving billions of requests daily requires infrastructure that goes well beyond a single cloud region or edge provider. A single CDN network, no matter how expansive, remains vulnerable to regional outages, fiber cuts, and routing anomalies.</p>

<p>jsDelivr addresses this by running a multi-CDN architecture. Rather than operating its own physical edge datacenters everywhere, it pools bandwidth and edge nodes from commercial enterprise CDNs, including Cloudflare, Fastly, Bunny CDN, and Gcore.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>              ┌──────────────────────┐
              │    User Request      │
              └──────────┬───────────┘
                         │
              ┌──────────▼───────────┐
              │  SmartDNS / Anycast  │
              └──────────┬───────────┘
                         │
 ┌───────────────────────┼───────────────────────┐
 │                       │                       │
┌────▼────────┐       ┌──────▼──────┐         ┌──────▼──────┐
│  Cloudflare │       │   Fastly    │         │  Bunny CDN  │
└────┬────────┘       └──────┬──────┘         └──────┬──────┘
│                       │                       │
└───────────────────────┼───────────────────────┘
│
┌──────────▼───────────┐
│ jsDelivr Origin &amp;    │
│ On-the-Fly Processing│
└──────────────────────┘

</code></pre></div></div>
<p>When a client browser requests a file from <code class="language-plaintext highlighter-rouge">cdn.jsdelivr.net</code>, an automated routing layer checks global health metrics and routes the request through the fastest, closest, and most reliable vendor network at that exact millisecond. If one CDN partner experiences degradation in Western Europe or South America, traffic shifts transparently to another provider without downtime or developer intervention.</p>

<p>This structural redundancy gives open-source projects access to performance levels typically reserved for enterprise engineering budgets.</p>

<h2 id="direct-integration-with-github-npm-and-wordpress">Direct Integration with GitHub, npm, and WordPress</h2>

<p>The true utility of jsDelivr lies in its predictable URL structure. It eliminates manual asset uploads entirely.</p>

<h3 id="1-the-npm-pipeline">1. The npm Pipeline</h3>
<p>Any package published to npm is instantly available via jsDelivr. Developers query the network using semantic versioning:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"[https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js](https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js)"</span><span class="nt">&gt;&lt;/script&gt;</span>

<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"[https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js](https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js)"</span><span class="nt">&gt;&lt;/script&gt;</span>

</code></pre></div></div>

<h3 id="2-github-mirroring">2. GitHub Mirroring</h3>

<p>For code hosted directly on GitHub, assets can be served straight from release tags, specific commits, or branches:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"[https://cdn.jsdelivr.net/gh/user/repo@v1.0.0/dist/bundle.min.js](https://cdn.jsdelivr.net/gh/user/repo@v1.0.0/dist/bundle.min.js)"</span><span class="nt">&gt;&lt;/script&gt;</span>

</code></pre></div></div>

<h3 id="3-automatic-minification-and-combine-endpoints">3. Automatic Minification and Combine Endpoints</h3>

<p>To optimize bundle sizes, jsDelivr offers built-in on-the-fly minification and file concatenation. If an upstream package author forgets to supply a <code class="language-plaintext highlighter-rouge">.min.js</code> file, appending <code class="language-plaintext highlighter-rouge">.min</code> to the requested path triggers automated minification on jsDelivr’s origin infrastructure.</p>

<p>Similarly, developers can combine multiple scripts into a single HTTP request to reduce round-trip latency:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"[https://cdn.jsdelivr.net/g/lodash@4,jquery@3.6.0](https://cdn.jsdelivr.net/g/lodash@4,jquery@3.6.0)"</span><span class="nt">&gt;&lt;/script&gt;</span>

</code></pre></div></div>

<h2 id="security-and-integrity-in-open-ecosystems">Security and Integrity in Open Ecosystems</h2>

<p>Serving executable code directly from public registries presents obvious security considerations. Supply chain attacks—where malicious actors take over npm packages or inject compromised code—pose real risks to client-side applications.</p>

<p>jsDelivr mitigates these vectors through strict caching guarantees and integration with Subresource Integrity (SRI). Because versioned files on npm and GitHub tags are expected to be immutable, jsDelivr enforces aggressive edge caching. Once a specific version string is requested and cached, it remains fixed.</p>

<p><img src="https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?auto=format&amp;fit=crop&amp;w=1200&amp;q=80" alt="" /></p>

<p>For applications requiring strict security compliance, combining jsDelivr URLs with standard SRI hashes guarantees that browsers execute only code matching an exact cryptographic signature:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script 
  </span><span class="na">src=</span><span class="s">"[https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js](https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js)"</span> 
  <span class="na">integrity=</span><span class="s">"sha384-xyz..."</span> 
  <span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/script&gt;</span>

</code></pre></div></div>

<p>Additionally, the platform tracks abuse, implements malware scanning protocols across cached packages, and works alongside package registries to revoke access to compromised release artifacts promptly.</p>

<h2 id="the-economics-of-free-infrastructure">The Economics of Free Infrastructure</h2>

<p>Sustaining a global network that handles hundreds of billions of requests a month requires substantial financial resources. Commercial CDN equivalents cost thousands of dollars monthly for equivalent bandwidth volumes.</p>

<p>jsDelivr survives through a hybrid support model backed by corporate sponsorships and strategic technology partnerships. Companies like Cloudflare, Fastly, and Datadog donate bandwidth, edge compute, and monitoring systems because an efficient open-source ecosystem directly benefits their enterprise customer bases.</p>

<p>By operating as an independent entity focused entirely on performance metrics and developer experience, jsDelivr remains unencumbered by ad-tech tracking scripts, paywalls, or artificial rate limits for legitimate traffic.</p>

<h2 id="a-fundamental-pillar-of-web-development">A Fundamental Pillar of Web Development</h2>

<p>The web relies on open standards and shared resources. While frameworks and build tools continuously evolve, basic file distribution needs to work reliably everywhere, every time.</p>

<p>jsDelivr demonstrates what happens when engineering efficiency takes priority over commercial monetization. It transforms public version control repositories into a high-availability content delivery network, silently handling the plumbing of the web so developers can focus on building products.</p>]]></content><author><name>Jonathan Frei</name></author><category term="open-source" /><category term="web-dev" /><category term="infrastructure" /><category term="cdn" /><summary type="html"><![CDATA[How a free, open-source CDN quietly powers millions of websites by turning public GitHub repositories and npm packages into production-ready infrastructure.]]></summary></entry><entry><title type="html">When Will the First American Pope Come Home?</title><link href="https://jonathanfrei.com/2026/08/06/when-will-pope-leo-visit-the-united-states" rel="alternate" type="text/html" title="When Will the First American Pope Come Home?" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/06/when-will-pope-leo-visit-the-united-states</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/06/when-will-pope-leo-visit-the-united-states"><![CDATA[<p><img src="https://upload.wikimedia.org/wikipedia/commons/5/51/Pope_Leo_XIV_Waving.jpg" alt="Pope Leo XIV waves at the people gathered in St. Peter's Square in his first public appearance as pope" /></p>

<p>Pope Leo XIV has been on the road. <a href="https://www.vaticannews.va/en/pope.html">Turkey and Lebanon</a> last November. Algeria, Cameroon, Angola, and Equatorial Guinea in April. Spain in June. A deliberate stop on the migrant island of <a href="https://www.vaticannews.va/en/pope/news/2026-07/pope-leo-xiv-celebrates-mass-homily-lampedusa-4-july-2026.html">Lampedusa on the Fourth of July</a>. Peru is still expected later this year.</p>

<p>The one place he has not set foot is the United States.</p>

<p>This is not an accident. The <a href="https://www.usccb.org/news/2026/pope-has-no-plans-travel-us-2026-vatican-says">Vatican confirmed in February</a> that no American itinerary exists for 2026. The first pope born in Chicago, the first dual American-Peruvian citizen to wear the white cassock, has chosen to stay away from the country that produced him. The question is no longer whether he will come. It is when, and under what conditions the visit will finally make sense.</p>

<h2 id="the-calendar-and-the-optics">The Calendar and the Optics</h2>

<p>On July 29, after a peace concert at Castel Gandolfo, Leo sat for a brief interview with NBC. Asked whether Americans would see him soon, he answered with the careful precision that has become his public style.</p>

<p>“They will see me there. By coincidence, today we were looking at the calendar for the next couple of years. Nothing is set in stone yet, but I certainly hope to be there soon.”</p>

<p>(The full exchange is preserved in the <a href="https://www.vaticannews.va/en/pope/news/2026-07/pope-leo-xiv-interview-nbc-immigration-united-states.html">Vatican News summary of the NBC interview</a>.)</p>

<p>A couple of years from mid-2026 points to 2027 or early 2028. That window is already constrained. Vatican practice generally avoids major trips to a country during its election season. 2026 was a midterm year. 2028 is a presidential year. The cleaner slot is 2027, after the midterms settle and before the next presidential cycle heats up.</p>

<p>Leo has made the logic explicit in other ways. He has repeatedly described himself as “the pope who happens to be American,” not the American pope. The distinction is not semantic. A first-year homecoming would have framed his entire pontificate as a return to the United States. He refused the frame.</p>

<h2 id="why-the-delay-feels-calculated">Why the Delay Feels Calculated</h2>

<p><img src="https://pbs.twimg.com/media/HMX1FUXWAAAXTB8.jpg" alt="Pope Leo XIV at the cemetery for migrants who died at sea during his July 4, 2026 visit to Lampedusa" /></p>

<p>The political temperature is real. Leo has criticized the Trump administration’s immigration crackdowns and its involvement in the Iran conflict. The White House has returned fire. Vice President Vance once called Vatican positions on migration “troubling.” Trump himself has traded barbs. A papal visit under these conditions would force a White House meeting that neither side appears eager to stage-manage.</p>

<p>Yet the deeper reason is institutional. Leo spent more than a decade as a missionary and bishop in Peru. He holds Peruvian citizenship. His formative years as an Augustinian were not spent in the American hierarchy’s power centers. When he looks at the global Church, the United States is one large, wealthy, noisy province among many. Africa is where the numbers are growing. Latin America is where he already has pastoral roots. Europe still requires repair.</p>

<p>Francis never returned to Argentina. John Paul II returned to Poland early and often. Benedict visited Germany. Each choice revealed a different relationship to the place of origin. Leo’s choice so far is closer to Francis’s: the universal pastor does not begin by privileging the soil that produced him.</p>

<p>There is also a practical layer. The apostolic nunciature in Washington has been in transition. Organizing a full papal visit without a settled diplomatic channel is messy. The Vatican prefers clean logistics.</p>

<h2 id="what-a-visit-would-actually-look-like">What a Visit Would Actually Look Like</h2>

<p>When the trip finally happens, it will not be a simple hometown parade. Modern papal visits to the United States follow a recognizable pattern established since Paul VI’s 1965 day trip to New York and the United Nations. John Paul II made seven trips. Benedict came once, in 2008. Francis came in 2015 for Washington, New York, and Philadelphia. (See the <a href="https://en.wikipedia.org/wiki/List_of_papal_visits_to_the_United_States">full historical list</a>.)</p>

<p>Leo will almost certainly include the United Nations. He will almost certainly visit Chicago. The rest of the itinerary will be shaped by the American bishops and by the issues he has already chosen to emphasize: migration, peace, and the dignity of the person in an age of artificial intelligence and economic inequality.</p>

<p>The risk is that any American visit becomes another chapter in the ongoing culture-war narrative. Leo appears determined to deny that narrative oxygen for as long as possible. By arriving later, after he has already established his voice in Africa, the Mediterranean, and Latin America, he arrives as the pope who has already spoken, not the American who is finally coming home.</p>

<h2 id="the-speculative-window">The Speculative Window</h2>

<p>The most plausible window is the second half of 2027. By then the midterms will be over. The political temperature may have cooled or at least shifted. Leo will have completed his first major Latin American journey and solidified the pattern of his travel. A 2027 visit would still fall inside the “couple of years” he mentioned in the NBC interview.</p>

<p>A 2028 trip is less likely unless the presidential election produces a configuration that lowers the political stakes. A post-2028 visit remains possible if the current tensions harden into something more structural. Some Vatican observers have floated the idea that Leo may simply wait out the Trump presidency. That reading feels too conspiratorial. Leo has already shown he is willing to speak plainly about American policy without needing to plant his feet on American soil.</p>

<p>The more interesting possibility is that the delay itself is the message. An American pope who does not rush home is performing a kind of detachment that the global Church has rarely seen from its leaders. The United States is used to being the center of attention. Leo is teaching it, gently and publicly, that it is not.</p>

<p>Whether that lesson sticks will depend on what he does when he finally lands. Until then, the absence is doing more work than most presence ever manages.</p>]]></content><author><name>Jonathan Frei</name></author><category term="pope leo xiv" /><category term="vatican" /><summary type="html"><![CDATA[Pope Leo XIV has spent his first fifteen months circling the globe while carefully avoiding the country of his birth. The reasons are more interesting than simple politics.]]></summary></entry><entry><title type="html">Embed examples</title><link href="https://jonathanfrei.com/2026/08/05/embed-examples" rel="alternate" type="text/html" title="Embed examples" /><published>2026-08-05T16:00:00+00:00</published><updated>2026-08-05T16:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/05/embed-examples</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/05/embed-examples"><![CDATA[<p>Paste a supported URL on its own line in a Markdown file and the build turns it into a responsive embed.</p>

<h2 id="youtube">YouTube</h2>

<div class="embed embed-video" data-embed="video" style="--embed-ratio: 56.25%;">
  <div class="embed-video__inner">
    <iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" title="YouTube video" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" loading="lazy"></iframe>
  </div>
</div>

<h2 id="vimeo">Vimeo</h2>

<div class="embed embed-video" data-embed="video" style="--embed-ratio: 56.25%;">
  <div class="embed-video__inner">
    <iframe src="https://player.vimeo.com/video/148751763" title="Vimeo video" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe>
  </div>
</div>

<h2 id="x-twitter">X (Twitter)</h2>

<div class="embed embed-twitter" data-embed="twitter">
  <blockquote class="twitter-tweet" data-dnt="true">
    <a href="https://twitter.com/i/status/20">View post on X</a>
  </blockquote>
</div>

<h2 id="instagram">Instagram</h2>

<div class="embed embed-instagram" data-embed="instagram">
  <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/p/DbmBkWoATTD/" data-instgrm-version="14" style="width:100%; max-width:540px; margin:0 auto;">
    <a href="https://www.instagram.com/p/DbmBkWoATTD/">View post on Instagram</a>
  </blockquote>
</div>

<p><em>AI Video</em></p>

<div class="embed embed-instagram" data-embed="instagram">
  <blockquote class="instagram-media" data-instgrm-permalink="https://www.instagram.com/reel/Da8pIhYxeV9/" data-instgrm-version="14" style="width:100%; max-width:540px; margin:0 auto;">
    <a href="https://www.instagram.com/reel/Da8pIhYxeV9/">View post on Instagram</a>
  </blockquote>
</div>

<h2 id="notes">Notes</h2>

<ul>
  <li>The URL must sit alone on a line (blank lines above/below).</li>
  <li>Inline links in paragraphs are left alone.</li>
  <li>Disable for a page with front matter: <code class="language-plaintext highlighter-rouge">url_embeds: false</code>.</li>
  <li>Supported: YouTube, Vimeo, X/Twitter, Instagram, TikTok, Spotify, CodePen.</li>
</ul>]]></content><author><name>Jonathan Frei</name></author><category term="meta" /><category term="embeds" /><summary type="html"><![CDATA[Paste a supported URL on its own line in a Markdown file and the build turns it into a responsive embed.]]></summary></entry><entry><title type="html">When Canadian Wildfires Reach Florida: The Hidden Impact on Tourism</title><link href="https://jonathanfrei.com/tourism/2026/08/05/wildfires-florida" rel="alternate" type="text/html" title="When Canadian Wildfires Reach Florida: The Hidden Impact on Tourism" /><published>2026-08-05T14:36:00+00:00</published><updated>2026-08-05T14:36:00+00:00</updated><id>https://jonathanfrei.com/tourism/2026/08/05/wildfires-florida</id><content type="html" xml:base="https://jonathanfrei.com/tourism/2026/08/05/wildfires-florida"><![CDATA[<p>Every year, millions of visitors choose Florida for its beaches, outdoor attractions, golf courses, and sunshine. But increasingly, events happening more than a thousand miles away are shaping the visitor experience in the Sunshine State.</p>

<p>One of the most surprising examples is the growing influence of Canadian wildfires.</p>

<p>In recent years, massive wildfires across Canada have produced smoke plumes large enough to travel across much of North America. In May 2025, satellite imagery showed smoke from Canadian wildfires spreading through the Midwest and reaching northern Florida, prompting air quality concerns far from the fires themselves. According to reporting from <a href="https://www.wgcu.org/section/waterquality/2025-05-31/canadian-wildfire-smoke-pours-across-u-s-into-north-florida">WGCU Public Media</a>, NOAA imagery captured a broad swath of smoke reaching into the state as wildfire activity intensified across several Canadian provinces. 【1-7dcd8c】</p>

<p>For Florida’s tourism industry, the implications extend beyond a hazy skyline.</p>

<h2 id="air-quality-matters-to-travelers">Air Quality Matters to Travelers</h2>

<p>Florida’s appeal is built around outdoor experiences. Visitors come for beach vacations, theme parks, boating, fishing, nature preserves, and sporting events. Even modest reductions in air quality can affect those activities, particularly for travelers with asthma, heart conditions, or other respiratory concerns.</p>

<p>The Florida Department of Environmental Protection notes that wildfire smoke can significantly affect air quality and public health, especially for sensitive populations. The agency encourages residents and visitors to monitor air quality conditions when smoke events occur and take protective measures when necessary. 【2-5cad93】【3-7fc3fa】</p>

<p>For a family planning a beach day, a smoky horizon or air quality advisory may not cancel a trip outright, but it can influence how visitors perceive the destination and how much time they spend outdoors.</p>

<h2 id="perception-can-be-as-important-as-reality">Perception Can Be as Important as Reality</h2>

<p>Tourism is driven not only by actual conditions but also by traveler perception.</p>

<p>Smoke events often generate dramatic satellite images, weather alerts, and news coverage. Even when air quality impacts are temporary or localized, widespread media attention can create uncertainty among prospective visitors.</p>

<p>A June 2025 report highlighted that smoke from Canadian wildfires was expected to drift into Florida alongside a large Saharan dust event. Meteorologists noted that residents could observe haze and reduced visibility, with the most noticeable impacts occurring across parts of Central Florida. While the conditions were not expected to reach the severity seen in northern states, the event demonstrated how distant environmental events can influence Florida’s atmosphere and visitor experience. <a href="https://bluewaterhealthyliving.com/news/national-news/florida/wall-of-dust-see-impacts-of-saharan-dust-smoke-from-canadian-wildfires-in-florida/">(USA Today reporting)</a> 【4-56c090】</p>

<h2 id="economic-ripple-effects">Economic Ripple Effects</h2>

<p>Tourism is one of Florida’s largest economic drivers, supporting hotels, restaurants, attractions, transportation providers, and local businesses.</p>

<p>While there is currently limited evidence that Canadian wildfire smoke alone has caused significant tourism declines in Florida, travel industry researchers increasingly recognize that climate-related disruptions can influence destination selection, visitor satisfaction, and travel behavior.</p>

<p>The broader economic impacts of Canada’s wildfire seasons have become substantial. Export Development Canada reported that the record-setting 2023 wildfire season burned approximately 17.6 million hectares, with subsequent seasons continuing to produce major disruptions across industries and communities. These increasingly severe fire seasons are creating cross-border consequences that extend well beyond Canada itself. 【5-a587a0】</p>

<p>For Florida businesses dependent on outdoor recreation and seasonal travelers, maintaining confidence in the visitor experience becomes increasingly important as smoke events become more frequent.</p>

<h2 id="climate-connectivity">Climate Connectivity</h2>

<p>Perhaps the most important lesson is that tourism destinations are no longer isolated from distant environmental events.</p>

<p>Smoke generated in Manitoba, Saskatchewan, Alberta, or Ontario can eventually affect skies viewed by tourists in Florida. The atmosphere does not recognize political borders, and the effects of extreme weather increasingly span entire continents.</p>

<p>The U.S. Environmental Protection Agency has acknowledged the growing impact of cross-border wildfire smoke on American communities, emphasizing the need for monitoring, transparency, and public access to air quality information during major fire events. 【6-ad086f】</p>

<p>For Florida’s tourism industry, this means resilience is no longer just about preparing for hurricanes. It also involves understanding how distant climate events influence air quality, traveler expectations, and outdoor experiences.</p>

<p>As wildfire seasons become longer and more intense across North America, the connection between Canada’s forests and Florida’s beaches may become one of the defining stories of tourism in a changing climate.</p>

<h2 id="further-reading">Further Reading</h2>

<ul>
  <li><a href="https://www.wgcu.org/section/waterquality/2025-05-31/canadian-wildfire-smoke-pours-across-u-s-into-north-florida">WGCU: Canadian wildfire smoke reaches Florida</a></li>
  <li><a href="https://floridadep.gov/air/air-director/content/wildfire-smoke-and-air-quality">Florida DEP: Wildfire Smoke and Air Quality</a></li>
  <li><a href="https://fire.airnow.gov/">EPA AirNow Fire and Smoke Map</a></li>
  <li><a href="https://bluewaterhealthyliving.com/news/national-news/florida/wall-of-dust-see-impacts-of-saharan-dust-smoke-from-canadian-wildfires-in-florida/">USA Today report on Canadian wildfire smoke and Florida haze</a></li>
  <li><a href="https://www.edc.ca/en/article/2025-wildfires-impact-canadian-trade.html">Export Development Canada: Economic impacts of Canadian wildfires</a></li>
</ul>]]></content><author><name>Jonathan Frei</name></author><category term="tourism" /><category term="florida" /><category term="tourism" /><category term="wildfires" /><category term="canada" /><category term="climate" /><category term="travel" /><summary type="html"><![CDATA[Every year, millions of visitors choose Florida for its beaches, outdoor attractions, golf courses, and sunshine. But increasingly, events happening more than a thousand miles away are shaping the visitor experience in the Sunshine State.]]></summary></entry><entry><title type="html">SpaceX’s First Earnings Report: A High-Stakes Test of Belief</title><link href="https://jonathanfrei.com/markets/2026/08/05/SpaceX-Earnings" rel="alternate" type="text/html" title="SpaceX’s First Earnings Report: A High-Stakes Test of Belief" /><published>2026-08-05T14:30:00+00:00</published><updated>2026-08-05T14:30:00+00:00</updated><id>https://jonathanfrei.com/markets/2026/08/05/SpaceX-Earnings</id><content type="html" xml:base="https://jonathanfrei.com/markets/2026/08/05/SpaceX-Earnings"><![CDATA[<p>SpaceX has spent years operating in a world of private funding rounds, long-term bets, and founder-driven narratives. This week, it enters a different arena.</p>

<p>The company is set to release its first quarterly earnings report as a public company following its June IPO, and Wall Street is watching closely. Not just because of the numbers, but because of the extraordinary divide between believers and skeptics.</p>

<p>At roughly $120 per share, SpaceX is trading well below its post-IPO highs near $225. Yet the company remains one of the most closely watched stocks in the market, sitting at the intersection of space exploration, telecommunications, artificial intelligence, and defense technology.</p>

<p>What makes this earnings report especially fascinating is the scale of the bets being placed against it.</p>

<p>According to market commentary circulating on X, approximately 95% of shares available for lending have been borrowed by short sellers, with short interest reportedly reaching 34% of the public float. In dollar terms, that’s an estimated $24.6 billion wager that the stock will move lower.</p>

<p>That’s an unusually large bearish position for a company still in the earliest days of public trading.</p>

<h2 id="the-unlock-that-changes-everything">The Unlock That Changes Everything</h2>

<p>If earnings weren’t enough, another major catalyst arrives almost immediately afterward.</p>

<p>Around 911.5 million shares held by employees and early investors are scheduled to become eligible for trading. That figure is larger than the 638.9 million shares issued during the IPO itself.</p>

<p>The result is a dramatic increase in available supply.</p>

<p>Before the unlock, only a small fraction of SpaceX’s total shares actively traded on public markets. Afterward, the company’s free float is expected to more than double, significantly changing the stock’s trading dynamics.</p>

<p>Share lockup expirations are always closely watched because they introduce a simple but powerful question:</p>

<p>Will insiders hold, or will they sell?</p>

<p>The answer is rarely as straightforward as headlines suggest. Employees may sell for diversification, tax planning, or personal financial reasons rather than signaling a lack of confidence. Still, markets often react strongly to the possibility of increased selling pressure.</p>

<h2 id="what-investors-actually-want-to-hear">What Investors Actually Want to Hear</h2>

<p>While the headlines focus on short sellers and lockups, the long-term story remains centered on execution.</p>

<p>Three topics seem likely to dominate investor attention:</p>

<h3 id="starlink-growth">Starlink Growth</h3>

<p>Starlink has evolved from an ambitious side project into one of SpaceX’s most important commercial businesses.</p>

<p>Investors will want updates on subscriber growth, revenue expansion, enterprise adoption, and profitability. The satellite internet network increasingly represents the recurring revenue engine that helps fund SpaceX’s broader ambitions.</p>

<p>For many analysts, Starlink’s progress may matter more than any single launch milestone.</p>

<h3 id="starship-progress">Starship Progress</h3>

<p>The future valuation of SpaceX still depends heavily on Starship.</p>

<p>The company’s next-generation launch system is central to plans involving lunar missions, Mars exploration, satellite deployment, and potentially entirely new business models that don’t yet exist.</p>

<p>Every update on testing, regulatory approvals, launch schedules, and technical progress will be scrutinized.</p>

<h3 id="ai-and-data-opportunities">AI and Data Opportunities</h3>

<p>Another emerging area is the intersection between Starlink’s global infrastructure and the rapidly growing demand for AI-related connectivity and compute capacity.</p>

<p>Investors are increasingly interested in whether SpaceX can participate in the broader AI ecosystem through partnerships, communications infrastructure, or future services built on its satellite network.</p>

<p>Even modest commentary from management could become a significant talking point.</p>

<h2 id="a-battle-between-narrative-and-numbers">A Battle Between Narrative and Numbers</h2>

<p>What’s striking about SpaceX’s current position is that both bulls and bears have compelling arguments.</p>

<p>The bullish case is straightforward:</p>

<ul>
  <li>A dominant launch business.</li>
  <li>The world’s largest satellite internet constellation.</li>
  <li>Powerful technological advantages.</li>
  <li>One of the strongest brands in modern engineering.</li>
</ul>

<p>The bearish case is equally clear:</p>

<ul>
  <li>A lofty valuation.</li>
  <li>Significant execution risks.</li>
  <li>Uncertainty around future profitability.</li>
  <li>Potential selling pressure from newly unlocked shares.</li>
</ul>

<p>This creates the kind of setup markets love: high expectations, strong emotions, and a catalyst capable of reshaping sentiment overnight.</p>

<h2 id="why-this-earnings-report-matters">Why This Earnings Report Matters</h2>

<p>First earnings reports are never just about financial statements.</p>

<p>They are moments when a company transitions from story to measurement.</p>

<p>Investors already know SpaceX can launch rockets. They know Starlink has customers. They know Elon Musk can command global attention.</p>

<p>What public shareholders now want is something more durable: evidence that the economics can support the ambition.</p>

<p>The coming days will provide the first real glimpse into how public markets value one of the most ambitious companies of the modern era.</p>

<p>And with nearly a billion additional shares about to enter the market, it’s difficult to imagine a more consequential opening chapter for SpaceX’s life as a public company.</p>

<p><em>(Based on market discussion and commentary circulating on X as of August 5, 2026. Investors should review official company filings and earnings materials when available.)</em></p>]]></content><author><name>Jonathan Frei</name></author><category term="markets" /><category term="spacex" /><category term="stocks" /><category term="investing" /><category term="starlink" /><category term="starship" /><category term="ipo" /><category term="markets" /><summary type="html"><![CDATA[SpaceX has spent years operating in a world of private funding rounds, long-term bets, and founder-driven narratives. This week, it enters a different arena.]]></summary></entry><entry><title type="html">Easy URL embeds in Markdown</title><link href="https://jonathanfrei.com/2026/08/05/embeds" rel="alternate" type="text/html" title="Easy URL embeds in Markdown" /><published>2026-08-05T00:00:00+00:00</published><updated>2026-08-05T00:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/05/embeds</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/05/embeds"><![CDATA[<p>You can handle multiple platforms embeds—like <strong>YouTube, X (Twitter), Instagram, Vimeo, and Spotify</strong>—with a single client-side JavaScript approach or a Ruby plugin hook.</p>

<p>Because platforms like X and Instagram use full interactive widgets rather than simple <code class="language-plaintext highlighter-rouge">&lt;iframe&gt;</code> elements, using <strong>JavaScript</strong> is usually the most reliable solution.</p>

<hr />

<h2 id="the-universal-javascript--css-solution">The Universal JavaScript + CSS Solution</h2>

<p>This script checks paragraphs in your content for standalone URLs from supported platforms and swaps them out with their corresponding responsive embed HTML or platform scripts.</p>

<h3 id="1-add-css-for-iframe-embeds-youtube-spotify-vimeo">1. Add CSS for <code class="language-plaintext highlighter-rouge">&lt;iframe&gt;</code> embeds (YouTube, Spotify, Vimeo)</h3>

<p>Add this to your CSS file (e.g., <code class="language-plaintext highlighter-rouge">assets/css/style.scss</code>):</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/* Responsive container for video/audio standard iframes */</span>
<span class="nc">.responsive-embed-container</span> <span class="p">{</span>
  <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
  <span class="nl">padding-bottom</span><span class="p">:</span> <span class="m">56.25%</span><span class="p">;</span> <span class="c">/* 16:9 Aspect Ratio */</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">overflow</span><span class="p">:</span> <span class="nb">hidden</span><span class="p">;</span>
  <span class="nl">max-width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">margin</span><span class="p">:</span> <span class="m">1.5rem</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.responsive-embed-container</span> <span class="nt">iframe</span> <span class="p">{</span>
  <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
  <span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">left</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">border</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="c">/* Center social widgets like X &amp; Instagram */</span>
<span class="nc">.social-embed-container</span> <span class="p">{</span>
  <span class="nl">display</span><span class="p">:</span> <span class="nb">flex</span><span class="p">;</span>
  <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
  <span class="nl">margin</span><span class="p">:</span> <span class="m">1.5rem</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<hr />

<h3 id="2-add-the-javascript-parser">2. Add the JavaScript Parser</h3>

<p>Add this script before <code class="language-plaintext highlighter-rouge">&lt;/body&gt;</code> (e.g., in <code class="language-plaintext highlighter-rouge">_includes/footer.html</code> or <code class="language-plaintext highlighter-rouge">_layouts/post.html</code>).</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">async</span> <span class="na">src=</span><span class="s">"https://platform.twitter.com/widgets.js"</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">async</span> <span class="na">src=</span><span class="s">"https://www.instagram.com/embed.js"</span><span class="nt">&gt;&lt;/script&gt;</span>

<span class="nt">&lt;script&gt;</span>
<span class="nb">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">"</span><span class="s2">DOMContentLoaded</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="dl">"</span><span class="s2">.post-content</span><span class="dl">"</span><span class="p">)</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="dl">"</span><span class="s2">main</span><span class="dl">"</span><span class="p">);</span>
  <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">content</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>

  <span class="kd">const</span> <span class="nx">paragraphs</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nf">querySelectorAll</span><span class="p">(</span><span class="dl">"</span><span class="s2">p</span><span class="dl">"</span><span class="p">);</span>

  <span class="nx">paragraphs</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">p</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">innerText</span><span class="p">.</span><span class="nf">trim</span><span class="p">();</span>
    
    <span class="c1">// Ensure the paragraph contains ONLY a URL</span>
    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/^https</span><span class="se">?</span><span class="sr">:</span><span class="se">\/\/[^\s]</span><span class="sr">+$/</span><span class="p">))</span> <span class="k">return</span><span class="p">;</span>

    <span class="kd">let</span> <span class="nx">embedHTML</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>

    <span class="c1">// 1. YouTube</span>
    <span class="kd">const</span> <span class="nx">ytMatch</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/</span><span class="se">(?:</span><span class="sr">youtube</span><span class="se">\.</span><span class="sr">com</span><span class="se">\/(?:</span><span class="sr">watch</span><span class="se">\?</span><span class="sr">v=|embed</span><span class="se">\/)</span><span class="sr">|youtu</span><span class="se">\.</span><span class="sr">be</span><span class="se">\/)([</span><span class="sr">a-zA-Z0-9_-</span><span class="se">]{11})</span><span class="sr">/</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">ytMatch</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">embedHTML</span> <span class="o">=</span> <span class="s2">`
        &lt;div class="responsive-embed-container"&gt;
          &lt;iframe src="https://www.youtube-nocookie.com/embed/</span><span class="p">${</span><span class="nx">ytMatch</span><span class="p">[</span><span class="mi">1</span><span class="p">]}</span><span class="s2">" allowfullscreen&gt;&lt;/iframe&gt;
        &lt;/div&gt;`</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 2. X (Twitter)</span>
    <span class="kd">const</span> <span class="nx">xMatch</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/</span><span class="se">(?:</span><span class="sr">twitter</span><span class="se">\.</span><span class="sr">com|x</span><span class="se">\.</span><span class="sr">com</span><span class="se">)\/([</span><span class="sr">a-zA-Z0-9_</span><span class="se">]</span><span class="sr">+</span><span class="se">)\/</span><span class="sr">status</span><span class="se">\/([</span><span class="sr">0-9</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">/</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">xMatch</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">embedHTML</span> <span class="o">=</span> <span class="s2">`
        &lt;div class="social-embed-container"&gt;
          &lt;blockquote class="twitter-tweet"&gt;&lt;a href="</span><span class="p">${</span><span class="nx">url</span><span class="p">}</span><span class="s2">"&gt;&lt;/a&gt;&lt;/blockquote&gt;
        &lt;/div&gt;`</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 3. Instagram</span>
    <span class="kd">const</span> <span class="nx">igMatch</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/</span><span class="se">(?:</span><span class="sr">instagram</span><span class="se">\.</span><span class="sr">com</span><span class="se">)\/(?:</span><span class="sr">p|reel</span><span class="se">)\/([</span><span class="sr">a-zA-Z0-9_-</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">/</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">igMatch</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">embedHTML</span> <span class="o">=</span> <span class="s2">`
        &lt;div class="social-embed-container"&gt;
          &lt;blockquote class="instagram-media" data-instgrm-permalink="</span><span class="p">${</span><span class="nx">url</span><span class="p">}</span><span class="s2">"&gt;&lt;/blockquote
        &lt;/div&gt;`</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 4. Vimeo</span>
    <span class="kd">const</span> <span class="nx">vimeoMatch</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/vimeo</span><span class="se">\.</span><span class="sr">com</span><span class="se">\/([</span><span class="sr">0-9</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">/</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">vimeoMatch</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">embedHTML</span> <span class="o">=</span> <span class="s2">`
        &lt;div class="responsive-embed-container"&gt;
          &lt;iframe src="https://player.vimeo.com/video/</span><span class="p">${</span><span class="nx">vimeoMatch</span><span class="p">[</span><span class="mi">1</span><span class="p">]}</span><span class="s2">" allowfullscreen&gt;&lt;/iframe&gt;
        &lt;/div&gt;`</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 5. Spotify (Tracks, Albums, Playlists)</span>
    <span class="kd">const</span> <span class="nx">spotifyMatch</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="sr">/open</span><span class="se">\.</span><span class="sr">spotify</span><span class="se">\.</span><span class="sr">com</span><span class="se">\/(</span><span class="sr">track|album|playlist|episode</span><span class="se">)\/([</span><span class="sr">a-zA-Z0-9</span><span class="se">]</span><span class="sr">+</span><span class="se">)</span><span class="sr">/</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">spotifyMatch</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">embedHTML</span> <span class="o">=</span> <span class="s2">`
        &lt;div style="margin: 1.5rem 0;"&gt;
          &lt;iframe src="https://open.spotify.com/embed/</span><span class="p">${</span><span class="nx">spotifyMatch</span><span class="p">[</span><span class="mi">1</span><span class="p">]}</span><span class="s2">/</span><span class="p">${</span><span class="nx">spotifyMatch</span><span class="p">[</span><span class="mi">2</span><span class="p">]}</span><span class="s2">" 
                  width="100%" height="152" frameborder="0" allow="encrypted-media"&gt;&lt;/iframe&gt;
        &lt;/div&gt;`</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// If a match was found, replace the </span><span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span> <span class="nx">tag</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">embedHTML</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">p</span><span class="p">.</span><span class="nx">outerHTML</span> <span class="o">=</span> <span class="nx">embedHTML</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">});</span>

  <span class="c1">// Re-trigger social widgets rendering if necessary</span>
  <span class="k">if </span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">twttr</span> <span class="o">&amp;&amp;</span> <span class="nb">window</span><span class="p">.</span><span class="nx">twttr</span><span class="p">.</span><span class="nx">widgets</span><span class="p">)</span> <span class="nb">window</span><span class="p">.</span><span class="nx">twttr</span><span class="p">.</span><span class="nx">widgets</span><span class="p">.</span><span class="nf">load</span><span class="p">();</span>
  <span class="k">if </span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">instgrm</span> <span class="o">&amp;&amp;</span> <span class="nb">window</span><span class="p">.</span><span class="nx">instgrm</span><span class="p">.</span><span class="nx">Embeds</span><span class="p">)</span> <span class="nb">window</span><span class="p">.</span><span class="nx">instgrm</span><span class="p">.</span><span class="nx">Embeds</span><span class="p">.</span><span class="nf">process</span><span class="p">();</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>

</code></pre></div></div>

<hr />

<h2 id="how-it-works-in-markdown">How it works in Markdown</h2>

<p>Just drop raw URLs on their own lines:</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Here is a YouTube video:

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed embed-video"</span> <span class="na">data-embed=</span><span class="s">"video"</span> <span class="na">style=</span><span class="s">"--embed-ratio: 56.25%;"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed-video__inner"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;iframe</span> <span class="na">src=</span><span class="s">"https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"</span> <span class="na">title=</span><span class="s">"YouTube video"</span> <span class="na">frameborder=</span><span class="s">"0"</span> <span class="na">allow=</span><span class="s">"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"</span> <span class="na">allowfullscreen</span> <span class="na">loading=</span><span class="s">"lazy"</span><span class="nt">&gt;&lt;/iframe&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="sb">


</span>Check out this post on X:

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed embed-twitter"</span> <span class="na">data-embed=</span><span class="s">"twitter"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;blockquote</span> <span class="na">class=</span><span class="s">"twitter-tweet"</span> <span class="na">data-dnt=</span><span class="s">"true"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://twitter.com/i/status/1683528642000000000"</span><span class="nt">&gt;</span>View post on X<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/blockquote&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="sb">


</span>Or this Spotify track:

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed embed-spotify"</span> <span class="na">data-embed=</span><span class="s">"spotify"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;iframe</span> <span class="na">style=</span><span class="s">"border-radius:12px"</span> <span class="na">src=</span><span class="s">"https://open.spotify.com/embed/track/4cOdK2wGLETKBW3PvgPWqT"</span> <span class="na">width=</span><span class="s">"100%"</span> <span class="na">height=</span><span class="s">"152"</span> <span class="na">frameborder=</span><span class="s">"0"</span> <span class="na">allowfullscreen</span> <span class="na">allow=</span><span class="s">"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"</span> <span class="na">loading=</span><span class="s">"lazy"</span><span class="nt">&gt;&lt;/iframe&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="sb">


</span></code></pre></div></div>]]></content><author><name>Jonathan Frei</name></author><category term="meta" /><category term="site" /><summary type="html"><![CDATA[You can handle multiple platforms embeds—like YouTube, X (Twitter), Instagram, Vimeo, and Spotify—with a single client-side JavaScript approach or a Ruby plugin hook.]]></summary></entry><entry><title type="html">The Fire Next Time: Why Our Forest Policy Is Just Arson</title><link href="https://jonathanfrei.com/2026/08/04/test-post" rel="alternate" type="text/html" title="The Fire Next Time: Why Our Forest Policy Is Just Arson" /><published>2026-08-04T22:00:00+00:00</published><updated>2026-08-04T22:00:00+00:00</updated><id>https://jonathanfrei.com/2026/08/04/test-post</id><content type="html" xml:base="https://jonathanfrei.com/2026/08/04/test-post"><![CDATA[<p>When three separate wildfires blew up across Spokane County this August, burning through thousands of hectares and sending 60,000 people packing, local officials pulled out the standard script: record heat, shifting winds, bad luck. You can read the play-by-play in <a href="https://www.spokesman.com/stories/2026/aug/02/wildfire-leaves-northwest-spokane-in-a-war-zone/"><em>The Spokesman-Review</em></a> or check <a href="https://thebusinessjournal.com/washington-wildfires-spokane-homes-destroyed/"><em>The Business Journal</em></a> for the staggering price tag on destroyed homes.</p>

<p>Weather provides the spark, but fuel builds the bomb. And when you spend a century letting dead timber and overgrown brush stack up until a forest looks like a game of Jenga played with matches, calling the outcome a “natural disaster” is just bad accounting. It’s organizational negligence. And when that negligence guarantees a town burns down every August, it’s just slow-motion arson with better paperwork.</p>

<hr />

<h2 id="the-interest-always-comes-due">The Interest Always Comes Due</h2>

<p>Forests in the American West need fire the way lawns need rain. For centuries, low-intensity burns cleared out the underbrush, opened up the canopy, and kept the ecosystem grounded. Indigenous communities ran this playbook for generations, keeping fuel loads low and forest floors clean.</p>

<p>Then the 20th century rolled around, and forestry management decided fire was an enemy to be eliminated. Every plume of smoke became a five-alarm emergency. But here’s the thing about fire: you don’t actually get to ban it. You just defer it. By putting out every minor blaze for a hundred years without doing the unsexy work of controlled burns or mechanical clearing, we didn’t save the forest. We just compounded the interest on a massive ecological debt.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Suppression + Bureaucratic Paralysis = Forest Floor Packed with Matches
Packed Forest + Summer Heat = Megafire
</code></pre></div></div>

<p>When fuel loads get this high, the spark itself is almost an afterthought. A lightning strike, a stray spark from a passing freight train, a discarded cigarette—it doesn’t matter. The forest isn’t burning because of the spark; it’s burning because it was loaded with gunpowder and left out in the sun.</p>

<hr />

<h2 id="bureaucracys-favorite-game-doing-nothing">Bureaucracy’s Favorite Game: Doing Nothing</h2>

<p>Nobody in state forestry lacks a brain or a degree in ecology. They know exactly how bad the problem is. The friction isn’t ignorance; it’s how government incentives work over a pint.</p>

<ul>
  <li><strong>Risk Asymmetry:</strong> If a forestry manager signs off on a controlled burn and smoke drifts onto a highway or burns three acres of private land, their career is effectively over. But if they do absolutely nothing and let the forest turn into a giant Tinder box that incinerates a neighborhood ten years later? That’s an “act of God.” No one gets fired for an act of God.</li>
  <li><strong>The Lawsuit Loop:</strong> Want to clear out dead trees or dig fuel breaks? Prepare for five years of environmental litigation. In a weird irony, the legal tools designed to protect pristine forests now lock them into structural decay, preserving the fuel until it inevitably explodes.</li>
  <li><strong>Budget Logic:</strong> Emergency fire suppression gets a blank check once homes start melting. Proactive thinning and controlled burning? That comes out of tight, discretionary budgets that get slashed the second tax revenues dip.</li>
</ul>

<p>We’ll happily drop millions a day on water bombers to fight the blaze, but we won’t spend ten grand on a drip torch to prevent it.</p>

<hr />

<h2 id="reckless-indifference">Reckless Indifference</h2>

<p>If you pour gasoline on your neighbor’s porch and throw a match, that’s arson. But if you watch gas leak onto the porch for twenty years, know with 100% mathematical certainty that it’s going to catch fire, block anyone who tries to clean it up, and then act surprised when the house blows up—what do we call that?</p>

<p>In the legal world, there’s a phrase for it: reckless endangerment.</p>

<p>The fires gutting eastern Washington aren’t random tragedies or unexpected bad luck. They are the predictable output of a bureaucratic system designed to dodge short-term friction at the expense of long-term survival. Until we start treating decades of artificial fuel buildup as an active threat rather than a cozy backdrop, we’re going to keep watching communities burn—and pretending nobody saw it coming.</p>]]></content><author><name>Jonathan Frei</name></author><category term="ai-author" /><category term="wildfires" /><category term="forest-management" /><category term="washington-state" /><category term="policy" /><summary type="html"><![CDATA[When dry timber turns an entire county into a tinderbox, calling the resulting inferno a 'natural disaster' is just bad accounting. It's institutional arson.]]></summary></entry></feed>