<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://amirhs1.github.io/eyvan/feed.xml" rel="self" type="application/atom+xml" /><link href="https://amirhs1.github.io/eyvan/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-10-28T22:08:48+00:00</updated><id>https://amirhs1.github.io/eyvan/feed.xml</id><title type="html">Your Name</title><subtitle>A clean, modern portfolio site for projects, writing, and professional information.</subtitle><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><entry><title type="html">Setting Up Eyvan</title><link href="https://amirhs1.github.io/eyvan/projects/setting-up-eyvan/" rel="alternate" type="text/html" title="Setting Up Eyvan" /><published>2026-06-16T00:00:00+00:00</published><updated>2026-06-16T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/setting-up-eyvan</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/setting-up-eyvan/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools as a practical setup guide shipped with the Eyvan template. Follow it after cloning the repository and running <code class="language-plaintext highlighter-rouge">bundle install</code> for the first time.</p>
</blockquote>

<p>Eyvan ships with demo content — placeholder names, example posts, and sample images — so you can see the template running immediately. This guide walks you through replacing all of it with your own content, in the order that matters. None of this requires touching the templates or SCSS.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<blockquote>
  <p><strong>Tip:</strong> This guide covers content setup only. When you are ready to change the brand color, fonts, or spacing, see the companion post <em>Theming Eyvan</em>, which explains Eyvan’s design tokens and a no-code color workflow built on Material Theme Builder.</p>
</blockquote>

<p>The rule of thumb: everything about <em>who you are</em> lives in <code class="language-plaintext highlighter-rouge">_data/</code>. Everything about <em>how Jekyll behaves</em> and <em>which site-wide assets are shared across templates</em> lives in <code class="language-plaintext highlighter-rouge">_config.yml</code>. Your <em>posts</em> live in <code class="language-plaintext highlighter-rouge">_posts/</code>. Your <em>images, fonts, and icons</em> live in <code class="language-plaintext highlighter-rouge">assets/</code>.</p>

<h2 id="step-1--the-two-required-changes">Step 1 — The two required changes</h2>

<p>Before anything else, open <code class="language-plaintext highlighter-rouge">_config.yml</code> and fix these two fields. Until you do, your deployed site will advertise incorrect URLs in canonical tags, Open Graph previews, and the sitemap.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://your-username.github.io"</span>
<span class="na">baseurl</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/your-repository-name"</span>
</code></pre></div></div>

<p>If you are deploying to a <strong>user or organization site</strong> (a repo named <code class="language-plaintext highlighter-rouge">your-username.github.io</code>), set <code class="language-plaintext highlighter-rouge">baseurl</code> to an empty string:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://your-username.github.io"</span>
<span class="na">baseurl</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
</code></pre></div></div>

<p>If you are using a <strong>custom domain</strong>, set <code class="language-plaintext highlighter-rouge">url</code> to the domain and keep <code class="language-plaintext highlighter-rouge">baseurl</code> empty:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://yourdomain.com"</span>
<span class="na">baseurl</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
</code></pre></div></div>

<p>That is all you need to change for a first deploy. Everything else below is about personalizing the content.</p>

<h2 id="step-2--site-identity-in-_configyml">Step 2 — Site identity in <code class="language-plaintext highlighter-rouge">_config.yml</code></h2>

<p>Open <code class="language-plaintext highlighter-rouge">_config.yml</code> and update the fields under the <em>Site metadata</em> section:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Your</span><span class="nv"> </span><span class="s">Name</span><span class="nv"> </span><span class="s">or</span><span class="nv"> </span><span class="s">Site</span><span class="nv"> </span><span class="s">Title"</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">One</span><span class="nv"> </span><span class="s">sentence</span><span class="nv"> </span><span class="s">that</span><span class="nv"> </span><span class="s">describes</span><span class="nv"> </span><span class="s">your</span><span class="nv"> </span><span class="s">site</span><span class="nv"> </span><span class="s">—</span><span class="nv"> </span><span class="s">used</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">search</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">social</span><span class="nv"> </span><span class="s">previews."</span>
<span class="na">author</span><span class="pi">:</span>
  <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Your</span><span class="nv"> </span><span class="s">Name"</span>
  <span class="na">email</span><span class="pi">:</span> <span class="s2">"</span><span class="s">hello@example.com"</span>
  <span class="na">uri</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://example.com"</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">title</code> and <code class="language-plaintext highlighter-rouge">description</code> values appear in the browser tab title, SEO metadata, feeds, and social previews. The nested <code class="language-plaintext highlighter-rouge">author</code> block is kept in <code class="language-plaintext highlighter-rouge">_config.yml</code> because <code class="language-plaintext highlighter-rouge">jekyll-feed</code> reads <code class="language-plaintext highlighter-rouge">site.author</code> from there. The visible theme identity still comes from <code class="language-plaintext highlighter-rouge">_data/author.yml</code>, so keep the two places aligned when you customize the template.</p>

<p>The same file also stores a few site-wide assets and links:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">default_og_image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/og-default.webp"</span>
<span class="na">logo</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/logo.svg"</span>
<span class="na">cv_url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/files/resume.pdf"</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">default_og_image</code> is the fallback social preview image for pages that do not set their own <code class="language-plaintext highlighter-rouge">image</code>. <code class="language-plaintext highlighter-rouge">logo</code> is global brand chrome used by the shared brand include, so it belongs with site-level metadata rather than the homepage hero. <code class="language-plaintext highlighter-rouge">cv_url</code> is also global because the social-links include can render the CV action in the header, mobile menu, and footer. If you also want the homepage hero button to download the same file, set the matching CTA link in <code class="language-plaintext highlighter-rouge">_data/hero.yml</code>.</p>

<h3 id="enabling-analytics">Enabling analytics</h3>

<p>If you want Google Analytics, paste your Measurement ID (the string that starts with <code class="language-plaintext highlighter-rouge">G-</code>) into this field:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">google_analytics</span><span class="pi">:</span> <span class="s2">"</span><span class="s">G-XXXXXXXXXX"</span>
</code></pre></div></div>

<p>Leave it blank (or remove it) to disable analytics entirely. No tracking request is made when the field is empty.</p>

<h3 id="reading-time">Reading time</h3>

<p>Reading time is estimated automatically from the word count of each post. Two global knobs control it:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">read_time</span><span class="pi">:</span> <span class="kc">true</span>           <span class="c1"># show or hide reading time on posts</span>
<span class="na">words_per_minute</span><span class="pi">:</span> <span class="m">238</span>     <span class="c1"># reading speed used for the estimate</span>
</code></pre></div></div>

<p>Set <code class="language-plaintext highlighter-rouge">read_time: false</code> to hide the reading-time display site-wide.</p>

<h2 id="step-3--your-profile-in-_dataauthoryml">Step 3 — Your profile in <code class="language-plaintext highlighter-rouge">_data/author.yml</code></h2>

<p>This file drives your name, role, biography, avatar, and contact information wherever they appear — the homepage hero, post metadata, and the about page.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Your</span><span class="nv"> </span><span class="s">Full</span><span class="nv"> </span><span class="s">Name"</span>
<span class="na">role</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Your</span><span class="nv"> </span><span class="s">Title</span><span class="nv"> </span><span class="s">or</span><span class="nv"> </span><span class="s">Role"</span>
<span class="na">location</span><span class="pi">:</span> <span class="s2">"</span><span class="s">City,</span><span class="nv"> </span><span class="s">Region,</span><span class="nv"> </span><span class="s">Country"</span>

<span class="na">avatar</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/avatar.webp"</span>

<span class="na">bio</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">A short paragraph about yourself. This appears in the homepage hero</span>
  <span class="s">and any author block the template renders. Markdown is not supported here —</span>
  <span class="s">keep it to plain text.</span>

<span class="na">email</span><span class="pi">:</span> <span class="s2">"</span><span class="s">you@example.com"</span>
</code></pre></div></div>

<p>Replace <code class="language-plaintext highlighter-rouge">assets/images/avatar.webp</code> with your own portrait (see <a href="#step-7--replacing-visual-assets">Step 7</a>). The <code class="language-plaintext highlighter-rouge">bio</code> field supports the YAML block scalar (<code class="language-plaintext highlighter-rouge">&gt;-</code>) so you can write longer text without escaping quotes.</p>

<h2 id="step-4--homepage-hero-in-_dataheroyml">Step 4 — Homepage hero in <code class="language-plaintext highlighter-rouge">_data/hero.yml</code></h2>

<p>The hero section at the top of the homepage is driven entirely by this file. Open it and replace the placeholder text:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">eyebrow</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Portfolio"</span>               <span class="c1"># small label above the headline (optional)</span>
<span class="na">title_lead</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Hi</span><span class="nv"> </span><span class="s">there,</span><span class="nv"> </span><span class="s">I</span><span class="nv"> </span><span class="s">am"</span>
<span class="na">description_html</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">&lt;p&gt;&lt;strong&gt;Your Professional Title&lt;/strong&gt; based in</span>
  <span class="s">&lt;strong&gt;City, Region, Country&lt;/strong&gt;. Write 1–2 sentences here describing</span>
  <span class="s">your practice, research, or portfolio focus.&lt;/p&gt;</span>

<span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/hero-placeholder.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">photograph</span><span class="nv"> </span><span class="s">or</span><span class="nv"> </span><span class="s">illustration</span><span class="nv"> </span><span class="s">representing</span><span class="nv"> </span><span class="s">you</span><span class="nv"> </span><span class="s">or</span><span class="nv"> </span><span class="s">your</span><span class="nv"> </span><span class="s">work"</span>

<span class="na">cta_button_primary_text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Download</span><span class="nv"> </span><span class="s">my</span><span class="nv"> </span><span class="s">resume"</span>
<span class="na">cta_button_primary_link</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/files/resume.pdf"</span>
<span class="na">cta_button_secondary_text</span><span class="pi">:</span> <span class="s2">"</span><span class="s">See</span><span class="nv"> </span><span class="s">my</span><span class="nv"> </span><span class="s">work"</span>
<span class="na">cta_button_secondary_link</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/projects/"</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">eyebrow</code> is optional — delete it or leave it blank if you do not want the small label. The author name in the headline still comes from <code class="language-plaintext highlighter-rouge">_data/author.yml</code>; <code class="language-plaintext highlighter-rouge">title_lead</code> only controls the words before the name. The CTA fields define the two buttons in the hero.</p>

<h2 id="step-5--navigation-in-_datanavigationyml">Step 5 — Navigation in <code class="language-plaintext highlighter-rouge">_data/navigation.yml</code></h2>

<p>This file controls the links in the site header and mobile menu. The default ships with four entries:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">main</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Home"</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/"</span>
    <span class="na">external</span><span class="pi">:</span> <span class="kc">false</span>

  <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">About"</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/about/"</span>
    <span class="na">external</span><span class="pi">:</span> <span class="kc">false</span>

  <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Projects"</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/projects/"</span>
    <span class="na">external</span><span class="pi">:</span> <span class="kc">false</span>

  <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Contact"</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/contact/"</span>
    <span class="na">external</span><span class="pi">:</span> <span class="kc">false</span>
</code></pre></div></div>

<p>Edit the <code class="language-plaintext highlighter-rouge">title</code> and <code class="language-plaintext highlighter-rouge">url</code> for each entry. Keep internal URLs baseurl-safe by writing them as site-relative paths such as <code class="language-plaintext highlighter-rouge">/projects/</code>; the navigation include applies <code class="language-plaintext highlighter-rouge">relative_url</code> for you.</p>

<p><code class="language-plaintext highlighter-rouge">external</code> is only needed when a navigation item should open in a new tab. The include also treats absolute URLs and PDF links as new-tab links automatically, but keeping <code class="language-plaintext highlighter-rouge">external: true</code> on intentional off-site links makes the data file easier to read.</p>

<p>Development-only navigation is kept separately in
<code class="language-plaintext highlighter-rouge">_data/test-navigation.yml</code>. When <code class="language-plaintext highlighter-rouge">dev_only: true</code> is set in <code class="language-plaintext highlighter-rouge">_config.yml</code>, the
navigation include appends its Tests entry to the public links above. Keep that
file separate so production navigation remains focused and the demo site does
not expose development-only surfaces.</p>

<h2 id="step-6--social-and-share-links">Step 6 — Social and share links</h2>

<h3 id="_datasocial-linksyml"><code class="language-plaintext highlighter-rouge">_data/social-links.yml</code></h3>

<p>Each key in this file adds an icon link to the social bar in the site header, mobile menu, footer, and about page. The shipped demo includes every platform supported by the current include. To remove a platform, comment out or delete its key. To update a platform, replace the placeholder URL:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">github</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://github.com/your-username"</span>
<span class="na">linkedin</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.linkedin.com/in/your-profile"</span>
<span class="na">x</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://x.com/your-handle"</span>
<span class="na">youtube</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.youtube.com/@your-channel"</span>
<span class="na">instagram</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.instagram.com/your-handle"</span>
<span class="na">scholar</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://scholar.google.com/citations?user=your-id"</span>
<span class="na">orcid</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://orcid.org/0000-0000-0000-0000"</span>
<span class="na">medium</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://medium.com/@your-handle"</span>
</code></pre></div></div>

<p>Supported social-link keys out of the box are <code class="language-plaintext highlighter-rouge">github</code>, <code class="language-plaintext highlighter-rouge">linkedin</code>, <code class="language-plaintext highlighter-rouge">instagram</code>, <code class="language-plaintext highlighter-rouge">youtube</code>, <code class="language-plaintext highlighter-rouge">x</code>, <code class="language-plaintext highlighter-rouge">scholar</code>, <code class="language-plaintext highlighter-rouge">orcid</code>, and <code class="language-plaintext highlighter-rouge">medium</code>. The CV action is separate and comes from <code class="language-plaintext highlighter-rouge">cv_url</code> in <code class="language-plaintext highlighter-rouge">_config.yml</code>.</p>

<h3 id="_datashareyml"><code class="language-plaintext highlighter-rouge">_data/share.yml</code></h3>

<p>Controls which actions appear in the share bar on posts. The shipped demo renders X, LinkedIn, Pinterest, email, print, and native share actions. Pinterest is skipped automatically on posts without an <code class="language-plaintext highlighter-rouge">image</code>, because it needs an image URL to build a useful pin.</p>

<p>Remove entries for platforms you do not want to offer. If you add a new share platform, add a matching branch in <code class="language-plaintext highlighter-rouge">_includes/post-share.html</code> so the include knows how to build that platform’s share URL.</p>

<h2 id="step-7--replacing-visual-assets">Step 7 — Replacing visual assets</h2>

<p>All visual assets live under <code class="language-plaintext highlighter-rouge">assets/</code>. Replace them at the same paths and Eyvan’s templates will automatically use your new files.</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Asset</th>
      <th style="text-align: left">Path</th>
      <th style="text-align: left">Recommended size</th>
      <th style="text-align: left">Used for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Avatar</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/images/avatar.webp</code></td>
      <td style="text-align: left">300 × 300 px</td>
      <td style="text-align: left">Hero, post meta</td>
    </tr>
    <tr>
      <td style="text-align: left">Hero image</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/images/hero-placeholder.webp</code></td>
      <td style="text-align: left">800 × 800 px or similar</td>
      <td style="text-align: left">Homepage hero</td>
    </tr>
    <tr>
      <td style="text-align: left">Logo</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/images/logo.svg</code></td>
      <td style="text-align: left">Preserve or update the SVG <code class="language-plaintext highlighter-rouge">viewBox</code></td>
      <td style="text-align: left">Header logo mark</td>
    </tr>
    <tr>
      <td style="text-align: left">OG fallback</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/images/og-default.webp</code></td>
      <td style="text-align: left">1200 × 630 px</td>
      <td style="text-align: left">Social previews on posts without a cover</td>
    </tr>
    <tr>
      <td style="text-align: left">Favicon</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/favicon/favicon.ico</code> + PNG variants</td>
      <td style="text-align: left">Per standard sizes</td>
      <td style="text-align: left">Browser tab, bookmarks</td>
    </tr>
  </tbody>
</table>

<p>Use <strong>WebP</strong> for photos and illustrations to keep file sizes small. For the OG image, a 1200 × 630 px WebP at quality 80 is the recommended target — it is the size Facebook, X, and LinkedIn expect.</p>

<p>The logo is an SVG rather than a raster image. When replacing it, keep a
<code class="language-plaintext highlighter-rouge">viewBox</code> that tightly contains the new artwork so the header can scale the
mark responsively without clipping or relying on fixed pixel dimensions.</p>

<h3 id="creating-and-installing-your-favicon">Creating and installing your favicon</h3>

<p>A favicon is the small icon browsers show in tabs, bookmarks, history, and
some home-screen shortcuts. You can create a complete favicon package with
<a href="https://favicon.io/">favicon.io</a>:</p>

<ol>
  <li>Choose <strong>PNG → ICO</strong>, <strong>Text → ICO</strong>, or <strong>Emoji → ICO</strong> and generate your
favicon.</li>
  <li>Download and extract the generated package.</li>
  <li>Replace the matching files in <code class="language-plaintext highlighter-rouge">assets/favicon/</code>:
<code class="language-plaintext highlighter-rouge">favicon.ico</code>, <code class="language-plaintext highlighter-rouge">favicon-16x16.png</code>, <code class="language-plaintext highlighter-rouge">favicon-32x32.png</code>,
<code class="language-plaintext highlighter-rouge">apple-touch-icon.png</code>, <code class="language-plaintext highlighter-rouge">android-chrome-192x192.png</code>, and
<code class="language-plaintext highlighter-rouge">android-chrome-512x512.png</code>.</li>
  <li>Also replace the root-level <code class="language-plaintext highlighter-rouge">favicon.ico</code>. Eyvan keeps this compatibility
copy for browsers and tools that request <code class="language-plaintext highlighter-rouge">/favicon.ico</code> directly.</li>
</ol>

<p>Keep the existing filenames so <code class="language-plaintext highlighter-rouge">_includes/head.html</code> can continue loading the
icons without template changes. You do not need to paste favicon.io’s HTML
snippet into the site because Eyvan already includes the required <code class="language-plaintext highlighter-rouge">&lt;link&gt;</code>
elements.</p>

<p>Open <code class="language-plaintext highlighter-rouge">assets/favicon/site.webmanifest</code> after copying the package and update the
site identity and install-screen colors:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Your Website Name"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"short_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Your Site"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"icons"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"src"</span><span class="p">:</span><span class="w"> </span><span class="s2">"android-chrome-192x192.png"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"sizes"</span><span class="p">:</span><span class="w"> </span><span class="s2">"192x192"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"image/png"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"src"</span><span class="p">:</span><span class="w"> </span><span class="s2">"android-chrome-512x512.png"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"sizes"</span><span class="p">:</span><span class="w"> </span><span class="s2">"512x512"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"image/png"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">],</span><span class="w">
  </span><span class="nl">"theme_color"</span><span class="p">:</span><span class="w"> </span><span class="s2">"#4f46e5"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"background_color"</span><span class="p">:</span><span class="w"> </span><span class="s2">"#ffffff"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"display"</span><span class="p">:</span><span class="w"> </span><span class="s2">"standalone"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">name</code> is the full website name, while <code class="language-plaintext highlighter-rouge">short_name</code> is the compact label used
when space is limited. <code class="language-plaintext highlighter-rouge">theme_color</code> controls supported browser or installed-app
interface colors, and <code class="language-plaintext highlighter-rouge">background_color</code> is used behind the app while it
launches. These values do not recolor the pixels inside the favicon images; to
change the favicon artwork or its colors, regenerate the images on favicon.io
and replace the files.</p>

<p>Keep the icon <code class="language-plaintext highlighter-rouge">src</code> values relative as shown above. Do not add a leading <code class="language-plaintext highlighter-rouge">/</code>,
because root-relative paths break when the template is published under its
default <code class="language-plaintext highlighter-rouge">/eyvan</code> base URL.</p>

<h3 id="understanding-and-replacing-the-open-graph-image">Understanding and replacing the Open Graph image</h3>

<p>An Open Graph (OG) image is the preview image shown when a page is shared on
services such as Facebook, LinkedIn, Discord, and Slack. Eyvan also uses the
same resolved image for its Twitter/X card metadata. A clear 1200 × 630 px
image works well across these platforms.</p>

<p><code class="language-plaintext highlighter-rouge">assets/images/og-default.webp</code> is the fallback Open Graph image used when a page or post does not define its own <code class="language-plaintext highlighter-rouge">image</code>. Replace it with a 1200 × 630 px image that includes your name, site title, or a recognizable visual identity. Then confirm <code class="language-plaintext highlighter-rouge">_config.yml</code> still points to it:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">default_og_image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/og-default.webp"</span>
</code></pre></div></div>

<p>If <code class="language-plaintext highlighter-rouge">assets/images/og-default.webp</code> is missing, add your image at that path or
store it elsewhere under <code class="language-plaintext highlighter-rouge">assets/images/</code> and update <code class="language-plaintext highlighter-rouge">default_og_image</code>. Keep
the path relative and omit a leading <code class="language-plaintext highlighter-rouge">/</code> so Jekyll can generate a baseurl-safe
absolute URL for social platforms.</p>

<p>Individual pages and posts can override the fallback with a purpose-built
social image:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">og_image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/your-social-preview.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Describe</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">social</span><span class="nv"> </span><span class="s">preview</span><span class="nv"> </span><span class="s">image"</span>
</code></pre></div></div>

<p>If <code class="language-plaintext highlighter-rouge">og_image</code> is absent, Eyvan next uses the regular <code class="language-plaintext highlighter-rouge">image</code> front matter value:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/your-post-cover.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Describe</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">image</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">screen</span><span class="nv"> </span><span class="s">readers"</span>
<span class="na">image_width</span><span class="pi">:</span> <span class="m">1200</span>
<span class="na">image_height</span><span class="pi">:</span> <span class="m">630</span>
</code></pre></div></div>

<p>Use the cover’s exact pixel dimensions for <code class="language-plaintext highlighter-rouge">image_width</code> and <code class="language-plaintext highlighter-rouge">image_height</code>.
Providing both values lets the browser reserve the correct space before the
image loads; omit both when you do not know them.</p>

<p>The resolution order is <code class="language-plaintext highlighter-rouge">og_image</code>, then <code class="language-plaintext highlighter-rouge">image</code>, then
<code class="language-plaintext highlighter-rouge">site.default_og_image</code>. This lets you use one image as a visible post cover
and a different 1200 × 630 px image for social sharing when needed.</p>

<p>If you already have images in JPEG or PNG, you can convert them with <a href="https://developers.google.com/speed/webp/docs/cwebp"><code class="language-plaintext highlighter-rouge">cwebp</code></a>, which is part of the <code class="language-plaintext highlighter-rouge">webp</code> package:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cwebp <span class="nt">-q</span> 80 <span class="nt">-resize</span> 300 0 your-avatar.jpg <span class="nt">-o</span> assets/images/avatar.webp
</code></pre></div></div>

<p>If you prefer a browser-based tool, <a href="https://squoosh.app/">Squoosh</a> is a practical option for previewing compression settings before downloading the converted image.</p>

<p>Eyvan ships demo media in modern web formats because they usually reduce transfer size without changing the authoring workflow:</p>

<ul>
  <li><strong>WebP</strong> works well for site images because it supports lossy and lossless compression, transparency, and broad browser support.</li>
  <li><strong>Opus</strong> works well for self-hosted audio because it gives strong quality at small file sizes and is a good general-purpose web audio codec.</li>
  <li><strong>WebM</strong> works well for self-hosted video because it is an open web container designed for efficient browser playback, commonly paired with VP9 or AV1 video and Opus audio.</li>
</ul>

<p>Keep original source files outside the published site if you need them for editing later. The optimized files in <code class="language-plaintext highlighter-rouge">assets/</code> should be the web-ready versions visitors download.</p>

<h2 id="step-8--replacing-demo-posts">Step 8 — Replacing demo posts</h2>

<p>The <code class="language-plaintext highlighter-rouge">_posts/</code> directory ships with demo content written to showcase the template. Replace it with your own writing before publishing.</p>

<p>The simplest workflow:</p>

<ol>
  <li>Delete the demo posts you do not want (or move them out of <code class="language-plaintext highlighter-rouge">_posts/</code>).</li>
  <li>Create a new file following the naming pattern: <code class="language-plaintext highlighter-rouge">_posts/YYYY-MM-DD-your-post-slug.md</code>.</li>
  <li>Add front matter at the top (see the <em>Front Matter Field Reference</em> post for all options).</li>
  <li>Write your content below the closing <code class="language-plaintext highlighter-rouge">---</code>.</li>
</ol>

<p>A minimal post looks like this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">My</span><span class="nv"> </span><span class="s">First</span><span class="nv"> </span><span class="s">Post"</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">short</span><span class="nv"> </span><span class="s">description</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">cards</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">search</span><span class="nv"> </span><span class="s">previews."</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">writing</span><span class="pi">]</span>
<span class="nn">---</span>

<span class="s">Your content starts here.</span>
</code></pre></div></div>

<p>For cover images, add:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/your-image.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Describe</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">image</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">screen</span><span class="nv"> </span><span class="s">readers"</span>
<span class="na">image_width</span><span class="pi">:</span> <span class="m">1200</span>
<span class="na">image_height</span><span class="pi">:</span> <span class="m">630</span>
<span class="na">image_srcset</span><span class="pi">:</span> <span class="pi">|</span>
  <span class="s">assets/images/posts/your-image-640.webp | 640w</span>
  <span class="s">assets/images/posts/your-image-960.webp | 960w</span>
  <span class="s">assets/images/posts/your-image.webp | 1200w</span>
<span class="na">image_sizes</span><span class="pi">:</span> <span class="s2">"</span><span class="s">(min-width:</span><span class="nv"> </span><span class="s">72rem)</span><span class="nv"> </span><span class="s">60rem,</span><span class="nv"> </span><span class="s">100vw"</span>
</code></pre></div></div>

<p>Responsive variants remain optional. When a post or page includes unusually
large imagery, generate a small set of alternate widths ahead of time and list
them in <code class="language-plaintext highlighter-rouge">image_srcset</code>. One practical no-bundler workflow is:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cwebp <span class="nt">-q</span> 80 <span class="nt">-resize</span> 640 0 your-image.png <span class="nt">-o</span> assets/images/posts/your-image-640.webp
cwebp <span class="nt">-q</span> 80 <span class="nt">-resize</span> 960 0 your-image.png <span class="nt">-o</span> assets/images/posts/your-image-960.webp
cwebp <span class="nt">-q</span> 82 your-image.png <span class="nt">-o</span> assets/images/posts/your-image.webp
</code></pre></div></div>

<p>Use exact source dimensions for <code class="language-plaintext highlighter-rouge">image_width</code> and <code class="language-plaintext highlighter-rouge">image_height</code>, and keep the
largest variant as the plain <code class="language-plaintext highlighter-rouge">image</code> path so older browsers still receive a
complete fallback.</p>

<p>If a post has a lot of headings, enable the sidebar table of contents:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<h2 id="step-9--footer-in-_datafooteryml">Step 9 — Footer in <code class="language-plaintext highlighter-rouge">_data/footer.yml</code></h2>

<p>The footer text — copyright notice, tagline, or links — is driven by this file. The default is a simple copyright line:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">copyright</span><span class="pi">:</span> <span class="s2">"</span><span class="s">©</span><span class="nv"> </span><span class="s">2025</span><span class="nv"> </span><span class="s">Your</span><span class="nv"> </span><span class="s">Name.</span><span class="nv"> </span><span class="s">All</span><span class="nv"> </span><span class="s">rights</span><span class="nv"> </span><span class="s">reserved."</span>
</code></pre></div></div>

<p>You can also add secondary links here, such as a privacy policy or a terms page. See the comments in the file for the supported fields.</p>

<h2 id="next--making-it-look-like-yours">Next — making it look like yours</h2>

<p>Everything above is content: the words, links, images, and posts that make the
site <em>yours</em>. None of it requires touching SCSS, and on the shipped palette and
type system it is enough for a polished first deploy.</p>

<p>When you want to change the <em>look</em> — the brand color, the fonts, or the
spacing rhythm — that lives in the design tokens under <code class="language-plaintext highlighter-rouge">_sass/0-settings/</code>. It
is a separate, slightly more technical task, so it has its own walkthrough:
<em>Theming Eyvan</em>. Start there once your content is in place. It covers a no-code
brand-color workflow built on Material Theme Builder, plus where the fonts and
spacing scale live.</p>

<h2 id="quick-checklist">Quick checklist</h2>

<p>Run through this before your first deploy:</p>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">url</code> and <code class="language-plaintext highlighter-rouge">baseurl</code> updated in <code class="language-plaintext highlighter-rouge">_config.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Site <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">description</code>, and <code class="language-plaintext highlighter-rouge">author</code> set in <code class="language-plaintext highlighter-rouge">_config.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Your name, role, bio, and avatar path set in <code class="language-plaintext highlighter-rouge">_data/author.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Hero headline and description updated in <code class="language-plaintext highlighter-rouge">_data/hero.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Navigation links updated in <code class="language-plaintext highlighter-rouge">_data/navigation.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Social links updated in <code class="language-plaintext highlighter-rouge">_data/social-links.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Share actions reviewed in <code class="language-plaintext highlighter-rouge">_data/share.yml</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">assets/images/avatar.webp</code> replaced with your own portrait</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">assets/images/hero-placeholder.webp</code> replaced or left as-is</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">assets/images/og-default.webp</code> replaced with your own fallback social preview</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Demo posts removed or replaced with your own content</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">bundle exec jekyll build</code> runs without errors</li>
</ul>

<p>After deploy, verify that your canonical URL and Open Graph previews show your domain, not the demo site URL. Use <a href="https://www.opengraph.xyz/">opengraph.xyz</a> or a similar tool to preview how your pages appear when shared on social platforms.</p>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>The post’s cover image was generated with AI tools for illustrative purposes by the author using the contents of this post as the generation prompt. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="meta" /><category term="jekyll" /><category term="setup" /><category term="documentation" /><summary type="html"><![CDATA[Step-by-step guide to replacing the demo content and making Eyvan your own — from config and data files to assets and posts.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/customizing_eyvan.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/customizing_eyvan.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Theming Eyvan</title><link href="https://amirhs1.github.io/eyvan/projects/theming-eyvan/" rel="alternate" type="text/html" title="Theming Eyvan" /><published>2026-06-15T00:00:00+00:00</published><updated>2026-06-15T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/theming-eyvan</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/theming-eyvan/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools as a theming guide shipped with the Eyvan template. It is the companion to <em>Setting Up Eyvan</em> — do your content setup there first, then return here when you want to change how the site looks.</p>
</blockquote>

<blockquote>
  <p><strong>Template note:</strong> This post intentionally omits the <code class="language-plaintext highlighter-rouge">image</code> front matter
field to demonstrate that Eyvan posts do not need a visible cover image. Its
social metadata falls back to <code class="language-plaintext highlighter-rouge">site.default_og_image</code>, while the post header
and archive card use the image-free presentation.</p>
</blockquote>

<p><em>Setting Up Eyvan</em> covered everything about <em>who you are</em> — names, links, images, and posts. None of it touched SCSS. This guide covers the other half: how the site <em>looks</em>. The brand color, the fonts, and the spacing rhythm all live in design tokens under <code class="language-plaintext highlighter-rouge">_sass/0-settings/</code>, and you can change them without editing a single layout, include, or component.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<p>This post assumes you are comfortable editing SCSS files and re-running the build. If you only want a different brand color, you can stop after the Material Theme Builder section — that is the most common change and the least code.</p>

<h2 id="how-eyvans-color-system-is-organized">How Eyvan’s color system is organized</h2>

<p>Eyvan’s palette follows the <a href="https://m3.material.io/styles/color/system/overview">Material 3</a> color model: a small set of named <em>roles</em> (primary, secondary, tertiary, surface, and so on) rather than a loose bag of hex values. Each role has an accessible “on” pair, and the same role names exist in both light and dark themes.</p>

<p>The system has two layers, and they exist for a specific reason:</p>

<ul>
  <li><strong>The brand accent — one value, one source of truth.</strong> The single color that links, buttons, tags, and focus rings use is defined in <code class="language-plaintext highlighter-rouge">_data/theme.yml</code> as <code class="language-plaintext highlighter-rouge">primary_light</code> and <code class="language-plaintext highlighter-rouge">primary_dark</code>. This is the layer you touch for a quick re-brand.</li>
  <li><strong>The full palette — everything else.</strong> Secondary and tertiary accents, every surface tone, and the 16 syntax-highlighting tokens live directly in <code class="language-plaintext highlighter-rouge">_sass/0-settings/_light-mode.scss</code> and <code class="language-plaintext highlighter-rouge">_sass/0-settings/_dark-mode.scss</code>, one file per theme.</li>
</ul>

<p>The brand accent is pulled out into <code class="language-plaintext highlighter-rouge">_data/theme.yml</code> because two different pipelines have to agree on it: <code class="language-plaintext highlighter-rouge">assets/css/main.scss</code> injects it into the Sass so the CSS <code class="language-plaintext highlighter-rouge">--color-primary</code> token gets its value, and <code class="language-plaintext highlighter-rouge">_includes/head.html</code> renders it into the <code class="language-plaintext highlighter-rouge">&lt;meta name="theme-color"&gt;</code> tag so the browser chrome matches. Keeping it in one data file means those two can never drift.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># _data/theme.yml — the brand accent, and nothing else</span>
<span class="na">primary_light</span><span class="pi">:</span> <span class="s2">"</span><span class="s">#7E4D7C"</span>   <span class="c1"># aubergine glaze — light-mode brand</span>
<span class="na">primary_dark</span><span class="pi">:</span>  <span class="s2">"</span><span class="s">#EFB4E9"</span>   <span class="c1"># lifted aubergine (orchid) — dark-mode brand</span>
</code></pre></div></div>

<h2 id="change-your-brand-color-with-material-theme-builder">Change your brand color with Material Theme Builder</h2>

<p>The fastest way to get a coherent, accessible palette is to let Google’s
<a href="https://material-foundation.github.io/material-theme-builder/">Material Theme Builder</a>
generate one from a single seed color. It is the same tool Eyvan’s shipped
palette came from (seed <code class="language-plaintext highlighter-rouge">#4B3049</code>, “Aubergine glaze”).</p>

<ol>
  <li><strong>Open Material Theme Builder</strong> and choose a <strong>source/seed color</strong> — your
brand color, a color pulled from your logo, or anything you like. The builder
generates a full light and dark scheme from that one seed.</li>
  <li><strong>Read the <code class="language-plaintext highlighter-rouge">Primary</code> role</strong> in the generated <strong>light</strong> scheme and again in the
<strong>dark</strong> scheme. These are the only two values you need for a basic re-brand.
(Material Theme Builder usually darkens the seed for light mode and lightens
it for dark mode so each stays legible against its background — that is why
light and dark get different hexes.)</li>
  <li>
    <p><strong>Paste them into <code class="language-plaintext highlighter-rouge">_data/theme.yml</code>:</strong></p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">primary_light</span><span class="pi">:</span> <span class="s2">"</span><span class="s">#XXXXXX"</span>   <span class="c1"># the Primary role from the light scheme</span>
<span class="na">primary_dark</span><span class="pi">:</span>  <span class="s2">"</span><span class="s">#YYYYYY"</span>   <span class="c1"># the Primary role from the dark scheme</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Run the site and look.</strong> <code class="language-plaintext highlighter-rouge">bundle exec jekyll serve</code>, then open the local
URL. Links, buttons, tags, focus outlines, and the browser theme-color all
pick up the new accent.</li>
</ol>

<p>That is the whole no-code path. For most sites, changing these two values is the
entire re-brand.</p>

<blockquote>
  <p><strong>Tip:</strong> Pick a seed with enough depth that Material Theme Builder can derive a
readable light-mode primary. Very pale seeds tend to produce a light-mode
primary that fails contrast against white — the build’s color-contract check
(below) will flag it before it ships.</p>
</blockquote>

<h2 id="keep-the-brand-colors-copies-in-sync">Keep the brand color’s copies in sync</h2>

<p>There is one rule to know. For build-time safety, the brand hex is mirrored in a
few checked-in places, and a CI guard (<code class="language-plaintext highlighter-rouge">scripts/check-color-contract.rb</code>) fails
the build if they disagree. When you change the accent, update <strong>all</strong> of them:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Location</th>
      <th style="text-align: left">What to change</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_data/theme.yml</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">primary_light</code> / <code class="language-plaintext highlighter-rouge">primary_dark</code> — the source of truth</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/0-settings/_light-mode.scss</code></td>
      <td style="text-align: left">the <code class="language-plaintext highlighter-rouge">$primary: … !default;</code> fallback (match <code class="language-plaintext highlighter-rouge">primary_light</code>)</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/0-settings/_dark-mode.scss</code></td>
      <td style="text-align: left">the <code class="language-plaintext highlighter-rouge">$primary: … !default;</code> fallback (match <code class="language-plaintext highlighter-rouge">primary_dark</code>)</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">assets/js/theme-toggle.js</code></td>
      <td style="text-align: left">the two hardcoded color fallbacks (match each mode)</td>
    </tr>
  </tbody>
</table>

<p>The <code class="language-plaintext highlighter-rouge">!default</code> fallbacks let the Sass compile on its own if the data injection
is ever bypassed; the JavaScript fallbacks cover the moment before the
<code class="language-plaintext highlighter-rouge">&lt;meta theme-color&gt;</code> value is read. They are belt-and-suspenders, but the guard
treats them as load-bearing, so keep them equal to <code class="language-plaintext highlighter-rouge">_data/theme.yml</code>.</p>

<p>You can run the same check locally before pushing — it is plain Ruby, with no
Jekyll build or Node toolchain required:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby scripts/check-color-contract.rb
</code></pre></div></div>

<p>It prints <code class="language-plaintext highlighter-rouge">Color contract policy passed</code> when the copies agree and every key
text, UI, and syntax color pair still meets WCAG 2.1 AA contrast.</p>

<h2 id="going-further-the-full-palette">Going further: the full palette</h2>

<p>If you want to move beyond the single accent — change the secondary or tertiary
colors, retune the surface tones, or restyle the code blocks — edit the two mode
files directly:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">_sass/0-settings/_light-mode.scss</code></li>
  <li><code class="language-plaintext highlighter-rouge">_sass/0-settings/_dark-mode.scss</code></li>
</ul>

<p>Because Eyvan uses the Material 3 role <strong>names</strong> (<code class="language-plaintext highlighter-rouge">$primary</code>, <code class="language-plaintext highlighter-rouge">$secondary</code>,
<code class="language-plaintext highlighter-rouge">$tertiary</code>, <code class="language-plaintext highlighter-rouge">$surface</code>, <code class="language-plaintext highlighter-rouge">$on-surface</code>, and so on), a full re-theme is mostly a
copy-paste job: export the complete scheme from Material Theme Builder and map
each role into the matching variable in each file. The 16 <code class="language-plaintext highlighter-rouge">base0*</code> variables at
the bottom of each file are the Base16 syntax-highlighting palette for code
blocks.</p>

<blockquote>
  <p><strong>Warning:</strong> Every text/background pair in the shipped palette meets WCAG 2.1
AA, and <code class="language-plaintext highlighter-rouge">scripts/check-color-contract.rb</code> enforces that on every PR. If you
hand-pick colors instead of using a generated accessible scheme, run the check
locally and fix any contrast failures before you push.</p>
</blockquote>

<h2 id="using-the-palette-in-your-own-components">Using the palette in your own components</h2>

<p>The section above is about <em>changing</em> the colors. This one is about <em>using</em>
them: you are adding a component of your own and you want it to work in both
themes without hardcoding a hex.</p>

<p>The mode files are the source, but components never read them directly.
<code class="language-plaintext highlighter-rouge">_sass/3-base/_base.scss</code> compiles both modes into CSS custom properties on
<code class="language-plaintext highlighter-rouge">:root</code> and swaps the whole set when the theme changes. Read a token with
<code class="language-plaintext highlighter-rouge">var()</code> and your component follows light and dark for free:</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.c-callout</span> <span class="p">{</span>
  <span class="nl">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-info-container</span><span class="p">);</span>
  <span class="nl">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-on-info-container</span><span class="p">);</span>
  <span class="na">border-inline-start</span><span class="p">:</span> <span class="m">4px</span> <span class="nb">solid</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-info</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Eyvan’s own components use roughly half the palette. The rest is emitted on
purpose: it completes the Material 3 role set, so a full re-theme has a home
for every role the Theme Builder exports, and so you have accessible,
theme-aware choices ready for the things the template does not ship.</p>

<h3 id="the-four-role-pattern">The four-role pattern</h3>

<p>Most of the palette arrives in groups of four. Learning the shape is worth more
than memorizing the names, because it repeats for every family:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Role</th>
      <th>Use for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X</code></td>
      <td>A filled, high-emphasis surface: a solid button, a status dot</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">on-X</code></td>
      <td>Text and icons placed <strong>on</strong> <code class="language-plaintext highlighter-rouge">X</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">X-container</code></td>
      <td>A soft, low-emphasis fill: a callout background, a chip</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">on-X-container</code></td>
      <td>Text and icons placed <strong>on</strong> <code class="language-plaintext highlighter-rouge">X-container</code></td>
    </tr>
  </tbody>
</table>

<p>Each role becomes a custom property with the <code class="language-plaintext highlighter-rouge">--color-</code> prefix, so the
<code class="language-plaintext highlighter-rouge">warning</code> family gives you <code class="language-plaintext highlighter-rouge">--color-warning</code>, <code class="language-plaintext highlighter-rouge">--color-on-warning</code>,
<code class="language-plaintext highlighter-rouge">--color-warning-container</code>, and <code class="language-plaintext highlighter-rouge">--color-on-warning-container</code>.</p>

<blockquote>
  <p><strong>Warning:</strong> Pair them only as shown — <code class="language-plaintext highlighter-rouge">on-X</code> on <code class="language-plaintext highlighter-rouge">X</code>, and <code class="language-plaintext highlighter-rouge">on-X-container</code> on
<code class="language-plaintext highlighter-rouge">X-container</code>. Those are the pairs that ship at WCAG AA or better and that
<code class="language-plaintext highlighter-rouge">scripts/check-color-contract.rb</code> verifies on every PR. Crossing the groups,
such as <code class="language-plaintext highlighter-rouge">on-X</code> on <code class="language-plaintext highlighter-rouge">X-container</code>, is the one combination nothing guarantees.</p>
</blockquote>

<p>Seven families follow the pattern:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Family</th>
      <th>Use for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">primary</code></td>
      <td>The brand accent: links, buttons, tags, focus rings</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">secondary</code></td>
      <td>An independent accent, never a tonal step of primary</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">tertiary</code></td>
      <td>A second independent accent, for charts or categories</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">error</code></td>
      <td>Destructive actions and validation failures</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">warning</code></td>
      <td>Cautions that do not block</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">info</code></td>
      <td>Neutral notices</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">success</code></td>
      <td>Confirmations and passing states</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">error</code>, <code class="language-plaintext highlighter-rouge">warning</code>, <code class="language-plaintext highlighter-rouge">info</code>, and <code class="language-plaintext highlighter-rouge">success</code> form a complete status system that
Eyvan does not currently render anywhere. It is there for you to build on.</p>

<h3 id="surfaces-text-and-borders">Surfaces, text, and borders</h3>

<p>Backgrounds come as a ladder, from the plain canvas up to the surface used
behind overlays:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Token</th>
      <th>Use for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface</code></td>
      <td>The page canvas</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-container-lowest</code></td>
      <td>The flattest step; the code canvas in dark mode</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-container-low</code></td>
      <td>Resting surfaces: cards, footer, TOC, code blocks</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-container</code></td>
      <td>A middle step between resting and elevated</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-container-high</code></td>
      <td>Elevated surfaces: raised cards, menus, entry meta</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-container-highest</code></td>
      <td>Overlay surfaces: modal panels, full-screen TOCs</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-dim</code></td>
      <td>The dim end of the ladder</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-bright</code></td>
      <td>The bright end of the ladder</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-surface-variant</code></td>
      <td>A tinted alternative to the plain canvas</td>
    </tr>
  </tbody>
</table>

<p>The text and border roles that sit on those surfaces:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Token</th>
      <th>Use for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-on-surface</code></td>
      <td>Primary body text and the default foreground</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-on-surface-variant</code></td>
      <td>Secondary and muted text</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-outline-variant</code></td>
      <td>Default borders and dividers</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--color-outline</code></td>
      <td>A stronger boundary when the subtle one is too faint</td>
    </tr>
  </tbody>
</table>

<p>For a high-contrast inversion — a tooltip or a snackbar, neither of which Eyvan
ships — use the inverse trio together: <code class="language-plaintext highlighter-rouge">--color-inverse-surface</code> as the
background, <code class="language-plaintext highlighter-rouge">--color-inverse-on-surface</code> as its text, and
<code class="language-plaintext highlighter-rouge">--color-inverse-primary</code> for an accent inside it.</p>

<h3 id="two-things-not-to-reach-for">Two things not to reach for</h3>

<p><code class="language-plaintext highlighter-rouge">--color-background</code> and <code class="language-plaintext highlighter-rouge">--color-on-background</code> are aliases. They hold exactly
the same values as <code class="language-plaintext highlighter-rouge">--color-surface</code> and <code class="language-plaintext highlighter-rouge">--color-on-surface</code> in both modes.
Material 3 keeps them for backward compatibility and Eyvan emits them for role
completeness. Prefer the <code class="language-plaintext highlighter-rouge">surface</code> pair.</p>

<p>The Base16 palette has sixteen slots, but Rouge only emits classes for eleven of
them. <code class="language-plaintext highlighter-rouge">base02</code>, <code class="language-plaintext highlighter-rouge">base04</code>, <code class="language-plaintext highlighter-rouge">base06</code>, <code class="language-plaintext highlighter-rouge">base07</code>, and <code class="language-plaintext highlighter-rouge">base0f</code> are defined so the
palette stays complete and a Base16 scheme can be dropped in whole, but no code
block currently renders them. Retune them when you swap syntax themes; do not
expect them to change anything otherwise.</p>

<blockquote>
  <p><strong>Note:</strong> To see which tokens the template already uses, search the styles for
<code class="language-plaintext highlighter-rouge">var(--color-</code>. <code class="language-plaintext highlighter-rouge">scripts/check-color-contract.rb</code> guarantees the other
direction: every token used in the styles, and every token named in this
guide, is one the base layer actually emits — so this list cannot quietly go
out of date.</p>
</blockquote>

<h2 id="typography">Typography</h2>

<p>Font families are set in <code class="language-plaintext highlighter-rouge">_sass/0-settings/_typography.scss</code>. Eyvan ships three:</p>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Variable</th>
      <th style="text-align: left">Font</th>
      <th style="text-align: left">Used for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">$font-family-display</code></td>
      <td style="text-align: left">Barlow Condensed</td>
      <td style="text-align: left">Display and UI text — headings, nav, buttons</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">$font-family-body</code></td>
      <td style="text-align: left">Gelasio</td>
      <td style="text-align: left">Long-form reading — the prose body</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">$font-family-mono</code></td>
      <td style="text-align: left">JetBrains Mono</td>
      <td style="text-align: left">Code blocks and inline code</td>
    </tr>
  </tbody>
</table>

<p>The fonts are <strong>self-hosted</strong>, not loaded from a CDN. The <code class="language-plaintext highlighter-rouge">@font-face</code>
declarations live in <code class="language-plaintext highlighter-rouge">_sass/2-generic/_fonts.scss</code>, and the <code class="language-plaintext highlighter-rouge">.woff2</code> files
themselves are in <code class="language-plaintext highlighter-rouge">assets/fonts/</code>. To swap a font:</p>

<ol>
  <li>Add the new <code class="language-plaintext highlighter-rouge">.woff2</code> files to <code class="language-plaintext highlighter-rouge">assets/fonts/</code>.</li>
  <li>Add matching <code class="language-plaintext highlighter-rouge">@font-face</code> blocks in <code class="language-plaintext highlighter-rouge">_sass/2-generic/_fonts.scss</code>.</li>
  <li>Point the relevant <code class="language-plaintext highlighter-rouge">$font-family-*</code> variable at the new family name.</li>
</ol>

<p>Keep new fonts self-hosted under <code class="language-plaintext highlighter-rouge">assets/</code>. Eyvan deliberately avoids external
font CDNs, so adding a <code class="language-plaintext highlighter-rouge">&lt;link&gt;</code> to Google Fonts would break that principle (and
add a third-party request to every page).</p>

<p>The same file also exposes the type scale and line-height, so you can adjust
sizing and rhythm without renaming any fonts.</p>

<h2 id="spacing-radius-and-shadows">Spacing, radius, and shadows</h2>

<p>Two more token files round out the visual system:</p>

<ul>
  <li><strong>Spacing</strong> — <code class="language-plaintext highlighter-rouge">_sass/0-settings/_spacing.scss</code> defines the spacing scale,
<code class="language-plaintext highlighter-rouge">$space-0</code> through <code class="language-plaintext highlighter-rouge">$space-9</code> (a 4px base unit growing to 96px). Components
reference these tokens, so changing one value re-spaces the whole site
consistently.</li>
  <li><strong>Radius and shadows</strong> — <code class="language-plaintext highlighter-rouge">_sass/0-settings/_config.scss</code> holds the global
border-radius and shadow tokens. Note the shipped radius is <code class="language-plaintext highlighter-rouge">0px</code>: Eyvan’s
squared corners are a deliberate design choice. Raise <code class="language-plaintext highlighter-rouge">$global-radius</code> (and the
button/border variants) if you prefer rounded corners.</li>
</ul>

<h2 id="previewing-and-shipping-changes">Previewing and shipping changes</h2>

<p>After any token change, run the site and watch the live reload:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>jekyll serve
</code></pre></div></div>

<p>SCSS edits recompile automatically, so color, type, and spacing changes appear
without a full restart. Before you push, run the color-contract check
(<code class="language-plaintext highlighter-rouge">ruby scripts/check-color-contract.rb</code>) so a sync or contrast problem fails
fast on your machine instead of in CI.</p>

<p>With that, you have changed how Eyvan looks without touching a single layout,
include, or component — exactly as the token architecture intends.</p>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>The design-token architecture and ITCSS layer layout are described in detail in the <em>Design Philosophy and Architecture of Eyvan</em> post. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="meta" /><category term="jekyll" /><category term="design" /><category term="css" /><category term="documentation" /><summary type="html"><![CDATA[How to re-skin Eyvan — a no-code brand-color workflow built on Material Theme Builder, plus where the fonts and spacing scale live.]]></summary></entry><entry><title type="html">Design Philosophy and Architecture of Eyvan</title><link href="https://amirhs1.github.io/eyvan/projects/eyvan-design-and-architecture/" rel="alternate" type="text/html" title="Design Philosophy and Architecture of Eyvan" /><published>2026-06-12T00:00:00+00:00</published><updated>2026-06-12T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/eyvan-design-and-architecture</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/eyvan-design-and-architecture/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools for the sole purpose of demonstrating the rich typographic and mathematical capabilities of the Eyvan template.</p>
</blockquote>

<p>A good portfolio template should feel almost invisible to the reader. It should frame the work, make writing comfortable to read, and give the site owner enough structure to keep growing without turning every new page into a design project. That is the central idea behind <strong>Eyvan</strong>: a visually restrained, content-first Jekyll template for portfolios, research notes, technical writing, and project archives.</p>

<p>The name comes from the architectural idea of an <em>eyvan</em><sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup>: an open, vaulted threshold that sits between inside and outside (<a class="c-prose-xref c-prose-xref--cref" href="#fig-eyvan-ameri-house">fig-eyvan-ameri-house</a>).</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-1" id="fig-eyvan-ameri-house" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/khane-amerian-eyvan.webp" alt="The five-bay panjdari of the main eyvan at the Āmeri House in Kashan, Iran, its vaulted ceiling filled with tiered muqarnas." loading="lazy" width="1200" height="900" srcset="/eyvan/assets/images/posts/khane-amerian-eyvan-640.webp 640w, /eyvan/assets/images/posts/khane-amerian-eyvan-960.webp 960w, /eyvan/assets/images/posts/khane-amerian-eyvan.webp 1200w" sizes="(min-width: 68rem) 48rem, (min-width: 48rem) 80vw, 100vw" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      The <em>panjdari</em> of the main eyvan — the open, vaulted balcony — of the Āmeri House in Kashan, Iran. Photograph by Matthias Blume, 18 November 2005, via <a href="https://commons.wikimedia.org/wiki/File:Khane_Amerian_iwan.jpg">Wikimedia Commons</a>, licensed under <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA 3.0</a>.

    </figcaption>
  
</figure>

<p>That metaphor fits the template well. A portfolio is also a threshold. It is not only a private archive, and it is not only a public résumé. It is a framed space where writing, projects, identity, and navigation meet.</p>

<p>This post explains how the template is organized, why the architecture is deliberately structured, and how the design system supports content-heavy posts without depending on a JavaScript framework.</p>

<h2 id="design-philosophy">Design philosophy</h2>

<h3 id="content-first-decoration-second">Content first, decoration second</h3>

<p>The template is designed around one simple rule: the content should always win. Headings, body text, figures, tables, code blocks, and project cards are the main interface. Decorative effects are allowed only when they improve orientation, hierarchy, or clarity.</p>

<p>That is why the visual language is restrained. The layout uses generous spacing, readable line lengths, clear section rhythm, and a focused but comprehensive set of reusable components. Instead of using heavy animations or complex page transitions, the design relies on structure: containers, grids, cards, captions, and navigation landmarks.</p>

<p>The goal is not to make every page look identical. The goal is to make every page feel like it belongs to the same system.</p>

<h3 id="minimal-visual-design-does-not-mean-an-empty-feature-set">Minimal visual design does not mean an empty feature set</h3>

<p>Minimal design is sometimes confused with removing everything. In Eyvan, minimal refers to the visual language: the interface avoids unnecessary decoration and keeps attention on the content. The template itself is intentionally capable. It includes a real header, social links, a theme toggle, project cards, post metadata, table of contents support, responsive media, captions, tags, sharing controls, cross-references, and related posts. Each piece has a specific job.</p>

<p>The design avoids over-styling Markdown output. A table should look like a table. A figure should look like a figure. A code block should be easy to scan. The template adds enough visual treatment to make these elements professional, but not so much that the styling competes with the content.</p>

<h3 id="no-javascript-framework">No JavaScript framework</h3>

<p>The site does not need React, Vue, Svelte, or a frontend build pipeline. Jekyll already provides the core content model: layouts, includes, data files, Markdown rendering, Sass compilation, and static output. For a portfolio site, that is usually enough.</p>

<p>This keeps the mental model small:</p>

<ol>
  <li>Write content in Markdown.</li>
  <li>Add metadata in front matter.</li>
  <li>Compose pages with Liquid layouts and includes.</li>
  <li>Style the system with SCSS.</li>
  <li>Build and deploy a static site.</li>
</ol>

<p>That simplicity matters because the best portfolio architecture is the one you will actually maintain.</p>

<h2 id="technology-stack">Technology stack</h2>

<p>The stack is deliberately conservative. Each tool solves a specific problem and avoids unnecessary moving parts.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-stack" data-ref-type="table">
    Core technologies used by Eyvan.

  </div>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Tool</th>
      <th style="text-align: left">Role</th>
      <th style="text-align: left">Why it belongs</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Jekyll</td>
      <td style="text-align: left">Static site generator</td>
      <td style="text-align: left">Converts Markdown, layouts, includes, Sass, and data files into a deployable static site.</td>
    </tr>
    <tr>
      <td style="text-align: left">Liquid</td>
      <td style="text-align: left">Template language</td>
      <td style="text-align: left">Handles reusable includes, conditional rendering, loops, and page metadata.</td>
    </tr>
    <tr>
      <td style="text-align: left">kramdown with GFM</td>
      <td style="text-align: left">Markdown engine</td>
      <td style="text-align: left">Supports GitHub-flavored Markdown patterns, automatic heading IDs, tables, footnotes, and math output.</td>
    </tr>
    <tr>
      <td style="text-align: left">MathJax</td>
      <td style="text-align: left">Math renderer</td>
      <td style="text-align: left">Enables LaTeX-style inline and display math on pages that opt in with <code class="language-plaintext highlighter-rouge">math: true</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">jekyll/tagging</code></td>
      <td style="text-align: left">Tag archive generation</td>
      <td style="text-align: left">Creates browsable topic pages for posts and projects.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">jekyll-sitemap</code></td>
      <td style="text-align: left">SEO support</td>
      <td style="text-align: left">Generates a sitemap for search engines.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">jekyll-feed</code></td>
      <td style="text-align: left">Syndication</td>
      <td style="text-align: left">Generates an Atom/RSS feed at <code class="language-plaintext highlighter-rouge">/feed.xml</code> and a discovery link in every page head.</td>
    </tr>
    <tr>
      <td style="text-align: left">SCSS</td>
      <td style="text-align: left">Styling language</td>
      <td style="text-align: left">Provides variables, mixins, partial organization, and compiled CSS.</td>
    </tr>
    <tr>
      <td style="text-align: left">GitHub Actions</td>
      <td style="text-align: left">Build pipeline</td>
      <td style="text-align: left">Builds the site with plugins that GitHub Pages does not process by default.</td>
    </tr>
  </tbody>
</table>

<p class="c-prose-table">The most important architectural choice is that the stack is <strong>Jekyll-first</strong>. Features are built with layouts, includes, front matter, and SCSS before reaching for custom JavaScript. JavaScript is used only where it improves behavior: theme initialization, mobile navigation, table of contents interaction, social sharing, back-to-top scrolling, cross-references, and conditional third-party loading.</p>

<p>The front matter and config are the control panel. For example, posts use the <code class="language-plaintext highlighter-rouge">post</code> layout by default, sharing is enabled by default, and read time is controlled globally:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># _config.yml</span>
<span class="na">markdown</span><span class="pi">:</span> <span class="s">kramdown</span>

<span class="na">kramdown</span><span class="pi">:</span>
  <span class="na">auto_ids</span><span class="pi">:</span> <span class="kc">true</span>
  <span class="na">input</span><span class="pi">:</span> <span class="s">GFM</span>
  <span class="na">math_engine</span><span class="pi">:</span> <span class="s">mathjax</span>

<span class="na">plugins</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">jekyll-sitemap</span>
  <span class="pi">-</span> <span class="s">jekyll/tagging</span>
  <span class="pi">-</span> <span class="s">jekyll-feed</span>

<span class="na">defaults</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">scope</span><span class="pi">:</span>
      <span class="na">type</span><span class="pi">:</span> <span class="s">posts</span>
    <span class="na">values</span><span class="pi">:</span>
      <span class="na">layout</span><span class="pi">:</span> <span class="s">post</span>
      <span class="na">share</span><span class="pi">:</span> <span class="kc">true</span>

<span class="na">sass</span><span class="pi">:</span>
  <span class="na">sass_dir</span><span class="pi">:</span> <span class="s">_sass</span>
  <span class="na">style</span><span class="pi">:</span> <span class="s">compressed</span>

<span class="na">words_per_minute</span><span class="pi">:</span> <span class="m">238</span>
<span class="na">read_time</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<h2 id="css-architecture">CSS architecture</h2>

<p>The stylesheet architecture follows <strong>ITCSS</strong>: Inverted Triangle CSS. The idea is to organize styles from the most abstract and widely shared rules to the most specific utilities and overrides. This makes the cascade easier to reason about because low-level decisions appear early and component-specific decisions appear later.</p>

<p>In this template, the Sass source is organized as ITCSS layer directories. The compiled stylesheet is assembled from <code class="language-plaintext highlighter-rouge">assets/css/main.scss</code>, which imports partials from these directories in layer order:</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-itcss" data-ref-type="table">
    ITCSS layers and their responsibilities.

  </div>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Layer</th>
      <th style="text-align: left">Directory/import group</th>
      <th style="text-align: left">Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Settings</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/0-settings/</code></td>
      <td style="text-align: left">Design tokens: colors, spacing, typography, breakpoints, and configuration values.</td>
    </tr>
    <tr>
      <td style="text-align: left">Tools</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/1-tools/</code></td>
      <td style="text-align: left">Mixins and helpers used by later layers.</td>
    </tr>
    <tr>
      <td style="text-align: left">Generic</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/2-generic/</code></td>
      <td style="text-align: left">Resets, box sizing, global normalization, and low-specificity baseline rules.</td>
    </tr>
    <tr>
      <td style="text-align: left">Base</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/3-base/</code></td>
      <td style="text-align: left">Default element styling for HTML, body, headings, links, media, tables, lists, and syntax highlighting.</td>
    </tr>
    <tr>
      <td style="text-align: left">Objects</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/4-objects/</code></td>
      <td style="text-align: left">Reusable layout patterns such as containers, grids, hero structure, site header layout, site footer layout, and prose measure.</td>
    </tr>
    <tr>
      <td style="text-align: left">Components</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/5-components/</code></td>
      <td style="text-align: left">Specific UI components such as buttons, nav, cards, hero, post layout, TOC, media figures, and theme toggle.</td>
    </tr>
    <tr>
      <td style="text-align: left">Layouts</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/6-layouts/</code></td>
      <td style="text-align: left">Page-level composition for the homepage, projects page, tag pages, and default shell spacing.</td>
    </tr>
    <tr>
      <td style="text-align: left">Trumps</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_sass/7-trumps/</code></td>
      <td style="text-align: left">Utilities, state helpers, print rules, and high-priority overrides.</td>
    </tr>
  </tbody>
</table>

<p class="c-prose-table">This structure separates <strong>what something is</strong> from <strong>where it sits</strong>. For example, <code class="language-plaintext highlighter-rouge">.c-button</code> controls button appearance, while <code class="language-plaintext highlighter-rouge">.l-projects__tags-list</code> controls the spacing of tag links on the projects page. That distinction prevents component styles from becoming tangled with page-specific layout rules.</p>

<h3 id="bem-naming-style">BEM naming style</h3>

<p>The class naming follows a practical BEM pattern with prefixes:</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.c-post-card</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.c-post-card__title</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.c-post-card__meta</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.c-post-card--featured</span> <span class="p">{</span>
<span class="p">}</span>

<span class="nc">.o-grid</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.o-grid__item</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.o-grid__item--span-6</span> <span class="p">{</span>
<span class="p">}</span>

<span class="nc">.l-projects</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.l-projects__archive</span> <span class="p">{</span>
<span class="p">}</span>

<span class="nc">.u-visually-hidden</span> <span class="p">{</span>
<span class="p">}</span>
<span class="nc">.is-active</span> <span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The prefix communicates the layer at a glance:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">c-</code> means component</li>
  <li><code class="language-plaintext highlighter-rouge">o-</code> means layout object</li>
  <li><code class="language-plaintext highlighter-rouge">l-</code> means page layout</li>
  <li><code class="language-plaintext highlighter-rouge">u-</code> means utility</li>
  <li><code class="language-plaintext highlighter-rouge">is-</code> means state</li>
</ul>

<p>This keeps templates readable. When you see <code class="language-plaintext highlighter-rouge">o-grid</code>, you know it handles layout. When you see <code class="language-plaintext highlighter-rouge">c-post-card</code>, you know it is a styled component. When you see <code class="language-plaintext highlighter-rouge">l-homepage</code>, you know it is page-specific composition.</p>

<h2 id="layout-system">Layout system</h2>

<h3 id="the-container">The container</h3>

<p>The <code class="language-plaintext highlighter-rouge">.o-container</code> object controls horizontal page width. It gives pages a consistent outer frame so that the header, hero, project archive, post cover image, and footer align visually.</p>

<p>A typical page starts like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-container"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"l-projects"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- page content --&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>The container is intentionally boring. That is a strength. It creates a stable page boundary without mixing in card styles, text styles, or page-specific spacing.</p>

<h3 id="the-grid">The grid</h3>

<p>The <code class="language-plaintext highlighter-rouge">.o-grid</code> object provides a 12-column responsive grid. Items span all 12 columns by default, then use modifiers such as <code class="language-plaintext highlighter-rouge">o-grid__item--span-tablet-6</code> or <code class="language-plaintext highlighter-rouge">o-grid__item--span-desktop-6</code> for wider screens.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-grid"</span><span class="nt">&gt;</span>
  {% for post in site.posts limit:6 %}
  <span class="nt">&lt;div</span>
    <span class="na">class=</span><span class="s">"o-grid__item o-grid__item--span-12 o-grid__item--span-tablet-6 o-grid__item--span-desktop-6"</span>
  <span class="nt">&gt;</span>
    {% include post-card.html post=post %}
  <span class="nt">&lt;/div&gt;</span>
  {% endfor %}
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>The result is a reusable grid system that works for project cards, homepage sections, and broad layout composition.</p>

<h3 id="the-prose-measure">The prose measure</h3>

<p>Long-form reading depends on line length. If text is too wide, the reader loses their place. If text is too narrow, the rhythm becomes choppy. The <code class="language-plaintext highlighter-rouge">.o-prose</code> object solves that by constraining the measure of article content.</p>

<p>The post layout applies:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-prose o-prose--measure-wide"</span><span class="nt">&gt;</span>
  <span class="c">&lt;!-- rendered Markdown content --&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>This allows code blocks, tables, figures, paragraphs, lists, and headings to share a consistent reading rhythm.</p>

<h3 id="the-3-column-post-layout">The 3-column post layout</h3>

<p>The post layout uses a three-column desktop structure:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>left gutter | prose column | table of contents
</code></pre></div></div>

<p>The left gutter is intentionally empty. It balances the right-side table of contents so the prose remains visually centered. On smaller screens, the layout collapses into a single column and the table of contents becomes a mobile/tablet toolbar and panel.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-post-layout"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span>
    <span class="na">class=</span><span class="s">"c-post-layout__col c-post-layout__col--left"</span>
    <span class="na">aria-hidden=</span><span class="s">"true"</span>
  <span class="nt">&gt;&lt;/div&gt;</span>

  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-post-layout__col c-post-layout__col--main"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-post-layout__prose"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-prose o-prose--measure-wide"</span><span class="nt">&gt;</span>{{ content }}<span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/div&gt;</span>

  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-post-layout__col c-post-layout__col--right"</span><span class="nt">&gt;</span>
    {% include post-toc-desktop.html %}
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>This is one of the template’s most important design decisions. It supports long articles without making the page feel crowded. The reader gets a focused article column, while the TOC remains available for orientation.</p>

<h2 id="component-inventory">Component inventory</h2>

<p>The template is built from small components that can be reused across layouts. The table below lists the major <code class="language-plaintext highlighter-rouge">c-*</code> components and their purpose.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-components" data-ref-type="table">
    Major reusable components in Eyvan and where they appear.

  </div>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Component</th>
      <th style="text-align: left">Purpose</th>
      <th style="text-align: left">Typical location</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-brand</code></td>
      <td style="text-align: left">Logo, name, and role link used as the site identity.</td>
      <td style="text-align: left">Header, footer, mobile menu</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-site-header</code></td>
      <td style="text-align: left">Global header shell for brand, navigation, theme toggle, and actions.</td>
      <td style="text-align: left">Default layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-nav</code></td>
      <td style="text-align: left">Primary navigation list with desktop and mobile modifiers.</td>
      <td style="text-align: left">Header, mobile menu</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-mobile-menu</code></td>
      <td style="text-align: left">Responsive expanded navigation for smaller screens.</td>
      <td style="text-align: left">Header include</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-theme-toggle</code></td>
      <td style="text-align: left">Light/dark theme control.</td>
      <td style="text-align: left">Header, mobile menu</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-button</code></td>
      <td style="text-align: left">Shared button and tag-link styling.</td>
      <td style="text-align: left">Hero, tags, CTAs, archive links</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-hero</code></td>
      <td style="text-align: left">Homepage introduction with text, CTA links, and image.</td>
      <td style="text-align: left">Homepage</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-section-heading</code></td>
      <td style="text-align: left">Reusable heading block for major page sections.</td>
      <td style="text-align: left">Homepage, projects, tag pages</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-post-card</code></td>
      <td style="text-align: left">Card preview for posts and projects.</td>
      <td style="text-align: left">Homepage, projects archive, related posts</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-post</code></td>
      <td style="text-align: left">Main article shell for long-form posts.</td>
      <td style="text-align: left">Post layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-post-cover</code></td>
      <td style="text-align: left">Optional cover image area above the article header.</td>
      <td style="text-align: left">Post layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-post-layout</code></td>
      <td style="text-align: left">Three-column article composition with left gutter, prose, and TOC.</td>
      <td style="text-align: left">Post layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-toc</code></td>
      <td style="text-align: left">Desktop table of contents navigation.</td>
      <td style="text-align: left">Post layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-mobile-toc</code></td>
      <td style="text-align: left">Mobile/tablet table of contents panel.</td>
      <td style="text-align: left">Post layout</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-prose-figure</code></td>
      <td style="text-align: left">Responsive single images, multi-image figure grids, audio, and video with captions.</td>
      <td style="text-align: left">Markdown posts via includes</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-prose-table</code></td>
      <td style="text-align: left">Styled Markdown or HTML tables inside long-form content.</td>
      <td style="text-align: left">Markdown posts</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">c-site-footer</code></td>
      <td style="text-align: left">Minimal footer with brand, metadata, and social links.</td>
      <td style="text-align: left">Default layout</td>
    </tr>
  </tbody>
</table>

<p class="c-prose-table">This inventory is useful because it creates a shared vocabulary. Instead of thinking “the thing that appears below the hero,” you can think “section heading plus grid plus post cards.” That makes changes easier to scope.</p>

<h2 id="feature-flags">Feature flags</h2>

<p>Many post features are controlled by front matter. This keeps content files explicit and avoids loading unnecessary features on every page.</p>

<h3 id="enable-math">Enable math</h3>

<p>Use <code class="language-plaintext highlighter-rouge">math: true</code> only when a post contains LaTeX-style math. For example, the template can render a simple performance ratio such as $R = \frac{content}{chrome}$ when MathJax is enabled.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">math</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>The useful part is conditional loading: a non-math essay does not need MathJax, so it should not pay for MathJax.</p>

<h3 id="enable-the-table-of-contents">Enable the table of contents</h3>

<p>Use <code class="language-plaintext highlighter-rouge">toc: true</code> for long posts with many headings. The post TOC wrappers currently scan <code class="language-plaintext highlighter-rouge">##</code> and <code class="language-plaintext highlighter-rouge">###</code> headings.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>A post like this one is a good stress test because it contains many second- and third-level headings. The desktop TOC improves scanning, and the mobile TOC keeps the same navigation available without permanently occupying screen space.</p>

<h3 id="disable-sharing">Disable sharing</h3>

<p>Sharing is enabled by default for posts, but you can turn it off when a page should feel private, internal, or reference-like.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">share</span><span class="pi">:</span> <span class="kc">false</span>
</code></pre></div></div>

<p>This is a good example of a feature flag that supports tone. Not every page needs the same interface.</p>

<h3 id="control-read-time-globally">Control read time globally</h3>

<p>Read time is controlled globally through <code class="language-plaintext highlighter-rouge">_config.yml</code>. The current metadata include does not read a per-post <code class="language-plaintext highlighter-rouge">read_time</code> front matter value.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">read_time</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">words_per_minute</span><span class="pi">:</span> <span class="m">238</span>
</code></pre></div></div>

<p>The global configuration uses a words-per-minute value, which keeps the estimate predictable across the site. To support per-post read-time overrides, the metadata include would need to be changed.</p>

<h3 id="enable-cross-references">Enable cross-references</h3>

<p>Use <code class="language-plaintext highlighter-rouge">crossrefs: true</code> when a post uses <code class="language-plaintext highlighter-rouge">{% include ref.html %}</code> to point to numbered figures, tables, videos, or audio blocks.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">ref.html</code> include creates the link, and <code class="language-plaintext highlighter-rouge">assets/js/crossref.js</code> resolves the displayed text to values such as “Figure 1” or “Table 2.”</p>

<h2 id="build-and-performance">Build and performance</h2>

<p>Static sites are fast by default, but performance still depends on restraint. This template uses several small decisions that add up.</p>

<h3 id="compressed-sass-output">Compressed Sass output</h3>

<p>The Sass configuration outputs compressed CSS:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">sass</span><span class="pi">:</span>
  <span class="na">sass_dir</span><span class="pi">:</span> <span class="s">_sass</span>
  <span class="na">style</span><span class="pi">:</span> <span class="s">compressed</span>
</code></pre></div></div>

<p>That keeps the final CSS smaller while preserving readable source SCSS in the repository.</p>

<h3 id="image-loading-priorities">Image loading priorities</h3>

<p>Post cover images, prose media, and most post-card covers use <code class="language-plaintext highlighter-rouge">loading="lazy"</code>,
which allows the browser to delay loading images until they are needed.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;img</span>
  <span class="na">class=</span><span class="s">"c-post-cover__image"</span>
  <span class="na">loading=</span><span class="s">"lazy"</span>
  <span class="na">src=</span><span class="s">"{{ page.image | relative_url }}"</span>
  <span class="na">alt=</span><span class="s">"{{ page.image_alt | default: page.title | escape }}"</span>
<span class="nt">/&gt;</span>
</code></pre></div></div>

<p>The homepage gives eager loading and high fetch priority to two likely
above-the-fold images: the hero image and the first post-card cover. Remaining
homepage cards, project and tag archives, related posts, and long-form media
stay lazy-loaded. This keeps the likely Largest Contentful Paint candidates
responsive without eagerly fetching the entire archive.</p>

<h3 id="pinned-mathjax-cdn-integration">Pinned MathJax CDN Integration</h3>

<p>MathJax is loaded from an exact, integrity-protected CDN release and only when
the page opts in:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% if page.math %}
<span class="nt">&lt;script&gt;</span>
  <span class="nb">window</span><span class="p">.</span><span class="nx">MathJax</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">loader</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">load</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">[tex]/braket</span><span class="dl">"</span><span class="p">],</span>
    <span class="p">},</span>
    <span class="na">tex</span><span class="p">:</span> <span class="p">{</span>
      <span class="na">inlineMath</span><span class="p">:</span> <span class="p">[</span>
        <span class="p">[</span><span class="dl">"</span><span class="s2">$</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">$</span><span class="dl">"</span><span class="p">],</span>
        <span class="p">[</span><span class="dl">"</span><span class="se">\\</span><span class="s2">(</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="se">\\</span><span class="s2">)</span><span class="dl">"</span><span class="p">],</span>
      <span class="p">],</span>
      <span class="na">displayMath</span><span class="p">:</span> <span class="p">[</span>
        <span class="p">[</span><span class="dl">"</span><span class="s2">$$</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">$$</span><span class="dl">"</span><span class="p">],</span>
        <span class="p">[</span><span class="dl">"</span><span class="se">\\</span><span class="s2">[</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="se">\\</span><span class="s2">]</span><span class="dl">"</span><span class="p">],</span>
      <span class="p">],</span>
      <span class="na">processEscapes</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
      <span class="na">packages</span><span class="p">:</span> <span class="p">{</span><span class="dl">"</span><span class="s2">[+]</span><span class="dl">"</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">braket</span><span class="dl">"</span><span class="p">]},</span>
    <span class="p">},</span>
  <span class="p">};</span>
<span class="nt">&lt;/script&gt;</span>

<span class="nt">&lt;script
  </span><span class="na">id=</span><span class="s">"MathJax-script"</span>
  <span class="na">defer</span>
  <span class="na">src=</span><span class="s">"https://cdn.jsdelivr.net/npm/mathjax@4.1.2/tex-chtml.js"</span>
  <span class="na">integrity=</span><span class="s">"sha384-zAhQQhdaMeHsMProNntGGg6nOUVcfuF9F22C3d1qJ9NZAVzCplXk1X85D2O5iufn"</span>
  <span class="na">crossorigin=</span><span class="s">"anonymous"</span>
  <span class="na">referrerpolicy=</span><span class="s">"no-referrer"</span>
<span class="nt">&gt;&lt;/script&gt;</span>
{% endif %}
</code></pre></div></div>

<p>This keeps the repository lightweight while avoiding mutable production code.
The integrity hash protects the entry bundle; exact version pinning also keeps
dynamically requested MathJax components on the reviewed release. Some posts
need equations; many do not.</p>

<h3 id="conditional-integrations">Conditional integrations</h3>

<p>The head include centralizes SEO, canonical links, feed discovery, Open Graph metadata, Twitter card metadata, favicons, theme-color handling, stylesheet loading, and optional analytics. Analytics loads only when a measurement ID exists, which keeps local development and early templates clean.</p>

<h2 id="extension-points">Extension points</h2>

<p>A good template should be easy to extend without rewriting its architecture. In Eyvan, the safest extension points are layouts, includes, data files, and SCSS components.</p>

<h3 id="add-a-new-layout">Add a new layout</h3>

<p>Create a new file in <code class="language-plaintext highlighter-rouge">_layouts</code>, then compose existing objects and components.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: default
---

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-container"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"l-notes"</span><span class="nt">&gt;</span>
    {% include section-heading.html id="notes-title" heading_level="h1"
    title=page.title description=page.description %}

    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"o-prose o-prose--measure-wide"</span><span class="nt">&gt;</span>{{ content }}<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>Then add layout-specific spacing in the layouts layer:</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* --- ################################################ --- */</span>
<span class="cm">/* --- Sub-file: _notes.scss --- */</span>

<span class="k">@use</span> <span class="s2">"../0-settings/spacing"</span> <span class="nt">as</span> <span class="nt">settings-spacing</span><span class="p">;</span>

<span class="nc">.l-notes</span> <span class="p">{</span>
  <span class="nl">display</span><span class="p">:</span> <span class="nb">grid</span><span class="p">;</span>
  <span class="nl">gap</span><span class="p">:</span> <span class="n">settings-spacing</span><span class="o">.</span><span class="nv">$space-6</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="add-a-new-component">Add a new component</h3>

<p>For a new component, start with a focused include and one component block. Do not put page layout into the component unless the component truly owns that layout.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-callout c-callout--{{ include.type | default: 'note' }}"</span><span class="nt">&gt;</span>
  {% if include.title %}
  <span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"c-callout__title"</span><span class="nt">&gt;</span>{{ include.title }}<span class="nt">&lt;/p&gt;</span>
  {% endif %}

  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"c-callout__body"</span><span class="nt">&gt;</span>{{ include.content | markdownify }}<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* --- ################################################ --- */</span>
<span class="cm">/* --- Sub-file: _callout.scss --- */</span>

<span class="k">@use</span> <span class="s2">"../0-settings/config"</span> <span class="nt">as</span> <span class="nt">settings-config</span><span class="p">;</span>
<span class="k">@use</span> <span class="s2">"../0-settings/spacing"</span> <span class="nt">as</span> <span class="nt">settings-spacing</span><span class="p">;</span>
<span class="k">@use</span> <span class="s2">"../0-settings/typography"</span> <span class="nt">as</span> <span class="nt">settings-type</span><span class="p">;</span>

<span class="nc">.c-callout</span> <span class="p">{</span>
  <span class="nl">padding</span><span class="p">:</span> <span class="n">settings-spacing</span><span class="o">.</span><span class="nv">$space-4</span><span class="p">;</span>
  <span class="nl">border</span><span class="p">:</span> <span class="n">settings-config</span><span class="o">.</span><span class="nv">$global-border-width</span> <span class="nb">solid</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-outline-variant</span><span class="p">);</span>
  <span class="nl">border-radius</span><span class="p">:</span> <span class="n">settings-config</span><span class="o">.</span><span class="nv">$global-radius</span><span class="p">;</span>
  <span class="nl">background-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-surface-container-high</span><span class="p">);</span>
  <span class="nl">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-on-surface</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.c-callout__title</span> <span class="p">{</span>
  <span class="na">margin-block</span><span class="p">:</span> <span class="m">0</span> <span class="n">settings-spacing</span><span class="o">.</span><span class="nv">$space-2</span><span class="p">;</span>
  <span class="nl">font-weight</span><span class="p">:</span> <span class="n">settings-type</span><span class="o">.</span><span class="nv">$font-weight-bold</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Note the split: geometry and type come from Sass tokens through <code class="language-plaintext highlighter-rouge">@use</code>, while
color comes from CSS custom properties. That is deliberate — geometry is fixed
at build time, but color has to change with the theme at runtime. <em>Theming
Eyvan</em> covers the full palette and which role to reach for.</p>

<h3 id="add-a-new-include">Add a new include</h3>

<p>Includes should do one job. For example, the figure include renders image figures; the audio include renders audio; the video include renders video. This is better than one enormous media include with too many modes.</p>

<p>A good include has:</p>

<ol>
  <li>A short purpose comment.</li>
  <li>Clear required parameters.</li>
  <li>Safe defaults.</li>
  <li>Accessible output.</li>
  <li>BEM classes that match the component layer.</li>
</ol>

<h3 id="add-new-data-driven-navigation">Add new data-driven navigation</h3>

<p>Navigation is data-driven, so adding links should happen in the navigation data file rather than hard-coding links into the header. The navigation include handles internal URLs, external links, active states, and development-only items.</p>

<p>That keeps the header focused on composition and the navigation focused on rendering links.</p>

<h2 id="why-this-architecture-works">Why this architecture works</h2>

<p>The architecture works because it divides responsibility clearly.</p>

<p>Jekyll owns content generation. Liquid owns composition. Front matter owns page-level decisions. <code class="language-plaintext highlighter-rouge">_config.yml</code> owns site-level defaults. SCSS owns visual systems. ITCSS controls the cascade. BEM keeps classes understandable. Small includes keep markup reusable. The post layout gives long-form writing a stable reading experience.</p>

<p>Most importantly, the template does not try to become an application. It remains a static portfolio system. That restraint is what makes it maintainable.</p>

<p>For a personal portfolio, the hardest problem is rarely technical complexity. The harder problem is consistency over time: adding new posts, updating projects, changing navigation, improving design, and keeping the site coherent as it grows. Eyvan solves that by providing a deliberately structured architecture with clear extension points.</p>

<p>The result is a site that feels calm, readable, and professional: content framed, not boxed; structure visible, but unobtrusive.</p>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>For more on the architectural term, see the <a href="https://www.iranicaonline.org/articles/ayvan-palace/">“Ayvān” entry in <em>Encyclopædia Iranica</em></a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="meta" /><category term="design" /><category term="jekyll" /><category term="css" /><category term="architecture" /><summary type="html"><![CDATA[A behind-the-scenes look at the design decisions, CSS architecture, layout system, and feature set of this template.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/khane-amerian-eyvan.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/khane-amerian-eyvan.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Front Matter Field Reference</title><link href="https://amirhs1.github.io/eyvan/projects/eyvan-front-matter-guide/" rel="alternate" type="text/html" title="Front Matter Field Reference" /><published>2026-06-10T00:00:00+00:00</published><updated>2026-06-10T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/eyvan-front-matter-guide</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/eyvan-front-matter-guide/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools for the sole purpose of demonstrating the rich typographic and mathematical capabilities of the Eyvan template.</p>
</blockquote>

<p>Front matter is the small YAML block at the top of a Jekyll page or post. It sits between two lines of three dashes and tells Jekyll how to process the file before it becomes HTML. In this template, front matter controls the page layout, post header, metadata, table of contents, social previews, MathJax loading, cover images, tags, cross-reference numbering, and sharing behavior.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<p>Think of front matter as configuration for one content file. <code class="language-plaintext highlighter-rouge">_config.yml</code> defines global site settings, layout defaults, plugin behavior, and build settings. Front matter defines the exceptions and content-specific values for an individual post or page. When Jekyll builds the site, it reads the YAML first, stores those values on the <code class="language-plaintext highlighter-rouge">page</code> object, and then makes them available to Liquid templates such as <code class="language-plaintext highlighter-rouge">_layouts/post.html</code>, <code class="language-plaintext highlighter-rouge">_includes/head.html</code>, <code class="language-plaintext highlighter-rouge">_includes/math.html</code>, and the post card or metadata includes.</p>

<p>This post is a practical reference for the front matter fields supported by this template. It is written for future posts, documentation pages, project write-ups, and long-form technical notes. The goal is simple: you should be able to open a blank Markdown file, add the right fields, and know exactly what each key changes on the rendered page.</p>

<blockquote>
  <p><strong>Note:</strong> This guide focuses on fields that are used by the current template. Jekyll itself supports many more patterns, but adding fields that no layout or include reads will not change the page unless you also update the template.</p>
</blockquote>

<h2 id="front-matter-basics">Front matter basics</h2>

<p>A post begins with a YAML block like this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Front</span><span class="nv"> </span><span class="s">Matter</span><span class="nv"> </span><span class="s">Field</span><span class="nv"> </span><span class="s">Reference"</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Every</span><span class="nv"> </span><span class="s">supported</span><span class="nv"> </span><span class="s">key,</span><span class="nv"> </span><span class="s">what</span><span class="nv"> </span><span class="s">it</span><span class="nv"> </span><span class="s">does,</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">when</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">it"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">documentation</span><span class="pi">,</span> <span class="nv">jekyll</span><span class="pi">,</span> <span class="nv">reference</span><span class="pi">,</span> <span class="nv">technical-writing</span><span class="pi">]</span>
<span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">complete</span><span class="nv"> </span><span class="s">reference</span><span class="nv"> </span><span class="s">guide</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">all</span><span class="nv"> </span><span class="s">supported</span><span class="nv"> </span><span class="s">front</span><span class="nv"> </span><span class="s">matter</span><span class="nv"> </span><span class="s">fields</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">Jekyll</span><span class="nv"> </span><span class="s">template."</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>Everything between the opening and closing <code class="language-plaintext highlighter-rouge">---</code> is parsed as YAML. Everything after the closing <code class="language-plaintext highlighter-rouge">---</code> is the body of the post. The body can use Markdown, HTML, Liquid includes, fenced code blocks, tables, blockquotes, footnotes, and any other syntax supported by the site’s Markdown engine.</p>

<p>In this template, posts live in <code class="language-plaintext highlighter-rouge">_posts/</code> and usually follow the filename pattern:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>YYYY-MM-DD-post-slug.md
</code></pre></div></div>

<p>For this article, the file is saved as:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>_posts/2026-06-10-eyvan-front-matter-guide.md
</code></pre></div></div>

<p>Because <code class="language-plaintext highlighter-rouge">_config.yml</code> sets defaults for posts, you usually do not need to write <code class="language-plaintext highlighter-rouge">layout: post</code> manually. Jekyll applies it automatically to files in the posts collection. You can still write it explicitly if you want the file to be self-documenting.</p>

<h2 id="how-jekyll-processes-front-matter">How Jekyll processes front matter</h2>

<p>Jekyll processes a post in a predictable order.</p>

<ol>
  <li>It reads the YAML front matter.</li>
  <li>It merges any matching defaults from <code class="language-plaintext highlighter-rouge">_config.yml</code>.</li>
  <li>It renders Liquid variables and includes.</li>
  <li>It converts Markdown to HTML with kramdown.</li>
  <li>It wraps the result in the selected layout.</li>
  <li>It writes the final HTML into the generated site.</li>
</ol>

<p>That order matters. For example, when a post sets <code class="language-plaintext highlighter-rouge">math: true</code>, the post body is rendered as usual, but the global layout also includes the MathJax loader because <code class="language-plaintext highlighter-rouge">_includes/math.html</code> checks <code class="language-plaintext highlighter-rouge">page.math</code>. When a post sets <code class="language-plaintext highlighter-rouge">image</code>, the post layout uses it as a cover image, and the head include can reuse the same value for Open Graph and Twitter preview metadata. When a post sets <code class="language-plaintext highlighter-rouge">toc: true</code>, the post layout exposes mobile and desktop table-of-contents areas that can be populated by the TOC include. When a post sets <code class="language-plaintext highlighter-rouge">crossrefs: true</code>, the base layout loads the script that turns <code class="language-plaintext highlighter-rouge">ref.html</code> links into numbered figure and table references.</p>

<blockquote>
  <p><strong>Tip:</strong> Treat front matter as a post-level API. The Markdown body should hold the content; front matter should describe how the template should present that content.</p>
</blockquote>

<h2 id="layout-fields">Layout fields</h2>

<p>Layout fields determine which template wraps the content and how the page is positioned inside the site.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-layout-fields" data-ref-type="table">
    Layout-related front matter fields.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Field</th>
      <th style="text-align: left">Type</th>
      <th style="text-align: left">Default</th>
      <th style="text-align: left">Used by</th>
      <th style="text-align: left">What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">layout</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">post</code> for posts, <code class="language-plaintext highlighter-rouge">default</code> globally</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_layouts/*.html</code></td>
      <td style="text-align: left">Selects the layout that wraps the page content.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">permalink</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">Site permalink pattern</td>
      <td style="text-align: left">Jekyll routing</td>
      <td style="text-align: left">Overrides the generated URL for a specific page or post.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post, page, head, cards</td>
      <td style="text-align: left">Main page title and browser/social title.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">subtitle</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post and page headers</td>
      <td style="text-align: left">Optional supporting text below the title.</td>
    </tr>
  </tbody>
</table>

<p>For normal posts, the most important layout field is <code class="language-plaintext highlighter-rouge">title</code>. The post layout renders it as the main <code class="language-plaintext highlighter-rouge">h1</code>, while the head include uses it for the document title and social metadata. <code class="language-plaintext highlighter-rouge">subtitle</code> is optional, but it is useful for documentation posts because it clarifies scope without making the title too long.</p>

<p>Use <code class="language-plaintext highlighter-rouge">layout</code> only when you want to override the default. For example, a static About page uses <code class="language-plaintext highlighter-rouge">layout: page</code>, while the homepage uses <code class="language-plaintext highlighter-rouge">layout: homepage</code>. A post can rely on the default <code class="language-plaintext highlighter-rouge">post</code> layout unless you are testing another layout.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">layout</span><span class="pi">:</span> <span class="s">post</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Building</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">Token-Bucket</span><span class="nv"> </span><span class="s">Rate</span><span class="nv"> </span><span class="s">Limiter"</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Design,</span><span class="nv"> </span><span class="s">implementation,</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">benchmarks</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">Python</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">Go"</span>
<span class="nn">---</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Warning:</strong> Do not use <code class="language-plaintext highlighter-rouge">layout: default</code> for long-form posts. The default layout only provides the site shell. The <code class="language-plaintext highlighter-rouge">post</code> layout adds the post header, tags, metadata row, optional cover image, TOC placement, post navigation, and related posts.</p>
</blockquote>

<h2 id="search-engine-optimization-seo-and-social-preview-fields">Search Engine Optimization (SEO) and social preview fields</h2>

<p>Search Engine Optimization (SEO) fields help the page appear correctly in search engines, feeds, and social previews. The template centralizes this behavior in the head include, so most pages only need a good <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">description</code>, and optional <code class="language-plaintext highlighter-rouge">image</code>.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-seo-fields" data-ref-type="table">
    SEO and social preview front matter fields.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Field</th>
      <th style="text-align: left">Type</th>
      <th style="text-align: left">Default</th>
      <th style="text-align: left">Used by</th>
      <th style="text-align: left">What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">Site title fallback</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">&lt;title&gt;</code>, Open Graph, Twitter</td>
      <td style="text-align: left">Defines the page title.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">site.description</code></td>
      <td style="text-align: left">Meta description, Open Graph, Twitter</td>
      <td style="text-align: left">Short summary for search and previews.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">og_image</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Open Graph, Twitter</td>
      <td style="text-align: left">Overrides the social preview image without adding a visible post cover or card image.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">site.default_og_image</code> or placeholder for social previews; none for the post cover</td>
      <td style="text-align: left">Post cover, post cards, Open Graph, Twitter</td>
      <td style="text-align: left">Provides the preferred social preview image and renders a post cover when set.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_alt</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">page.title</code></td>
      <td style="text-align: left">Post/page image alt text</td>
      <td style="text-align: left">Provides accessible text for the cover image.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_width</code></td>
      <td style="text-align: left">integer</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post cover, page image, post cards, post navigation</td>
      <td style="text-align: left">Adds the image’s intrinsic pixel width so browsers can reserve layout space.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_height</code></td>
      <td style="text-align: left">integer</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post cover, page image, post cards, post navigation</td>
      <td style="text-align: left">Adds the image’s intrinsic pixel height so browsers can reserve layout space.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_srcset</code></td>
      <td style="text-align: left">string block</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post cover, page image, post cards, post navigation</td>
      <td style="text-align: left">Declares optional responsive image candidates as newline-delimited <code class="language-plaintext highlighter-rouge">path | width</code> rows.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_sizes</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post cover, page image, post cards, post navigation</td>
      <td style="text-align: left">Declares the optional <code class="language-plaintext highlighter-rouge">sizes</code> hint paired with <code class="language-plaintext highlighter-rouge">image_srcset</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_position</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">CSS default</td>
      <td style="text-align: left">Post cover</td>
      <td style="text-align: left">Sets the cover image <code class="language-plaintext highlighter-rouge">object-position</code>, such as <code class="language-plaintext highlighter-rouge">center top</code> or <code class="language-plaintext highlighter-rouge">50% 35%</code>.</td>
    </tr>
  </tbody>
</table>

<p>A strong <code class="language-plaintext highlighter-rouge">description</code> should be specific, concise, and readable outside the page context. Aim for one sentence. Avoid keyword lists. Good descriptions explain what the reader will learn.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">complete</span><span class="nv"> </span><span class="s">reference</span><span class="nv"> </span><span class="s">guide</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">all</span><span class="nv"> </span><span class="s">supported</span><span class="nv"> </span><span class="s">front</span><span class="nv"> </span><span class="s">matter</span><span class="nv"> </span><span class="s">fields</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">Jekyll</span><span class="nv"> </span><span class="s">template."</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">image</code> field has several roles. In the post layout, it renders a full-width cover image above the article header. In post cards, it becomes the card image. In the head include, it becomes the social preview image. That makes it powerful, but it also means you should use it intentionally. If you want a header-only documentation post, omit <code class="language-plaintext highlighter-rouge">image</code> and let the head include fall back to <code class="language-plaintext highlighter-rouge">site.default_og_image</code> for social previews.</p>

<p>Use <code class="language-plaintext highlighter-rouge">og_image</code> when a page needs a purpose-built social preview without a
visible cover or when its social artwork should differ from its cover. Social
metadata resolves images in this order: <code class="language-plaintext highlighter-rouge">og_image</code>, then <code class="language-plaintext highlighter-rouge">image</code>, then
<code class="language-plaintext highlighter-rouge">site.default_og_image</code>. The <code class="language-plaintext highlighter-rouge">og_image</code> value does not render in the post header
or archive card.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">og_image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/social-preview.webp"</span>
</code></pre></div></div>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/token-bucket-diagram.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Token</span><span class="nv"> </span><span class="s">bucket</span><span class="nv"> </span><span class="s">rate</span><span class="nv"> </span><span class="s">limiter</span><span class="nv"> </span><span class="s">system</span><span class="nv"> </span><span class="s">diagram"</span>
<span class="na">image_width</span><span class="pi">:</span> <span class="m">1200</span>
<span class="na">image_height</span><span class="pi">:</span> <span class="m">630</span>
<span class="na">image_srcset</span><span class="pi">:</span> <span class="pi">|</span>
  <span class="s">assets/images/posts/token-bucket-diagram-640.webp | 640w</span>
  <span class="s">assets/images/posts/token-bucket-diagram-960.webp | 960w</span>
  <span class="s">assets/images/posts/token-bucket-diagram.webp | 1200w</span>
<span class="na">image_sizes</span><span class="pi">:</span> <span class="s2">"</span><span class="s">(min-width:</span><span class="nv"> </span><span class="s">72rem)</span><span class="nv"> </span><span class="s">60rem,</span><span class="nv"> </span><span class="s">100vw"</span>
<span class="na">image_position</span><span class="pi">:</span> <span class="s2">"</span><span class="s">center</span><span class="nv"> </span><span class="s">center"</span>
</code></pre></div></div>

<p>When you know the cover’s real pixel dimensions, add both <code class="language-plaintext highlighter-rouge">image_width</code> and
<code class="language-plaintext highlighter-rouge">image_height</code>. The browser uses the resulting intrinsic aspect ratio to
reserve space before the image downloads. Do not estimate these values, and
omit both fields when the dimensions are unknown.</p>

<p><code class="language-plaintext highlighter-rouge">image_srcset</code> is optional. When you pre-generate alternate widths, write one
candidate per line using <code class="language-plaintext highlighter-rouge">path | descriptor</code>, and pair it with <code class="language-plaintext highlighter-rouge">image_sizes</code>
when you want the browser to choose among width-based variants intelligently.
Each path is passed through <code class="language-plaintext highlighter-rouge">relative_url</code>, so the final output stays
baseurl-safe.</p>

<p>The <code class="language-plaintext highlighter-rouge">image_alt</code> field should describe the meaningful content of the image, not repeat the file name or stuff keywords into the page. Good alt text is useful for screen-reader users, slow connections, broken image states, and anyone who needs the image content expressed in words. For decorative images, the template currently falls back to the page title, so it is better to write a short meaningful description whenever <code class="language-plaintext highlighter-rouge">image</code> is set.</p>

<p>A good <code class="language-plaintext highlighter-rouge">image_alt</code> usually answers: what is shown, what matters about it, and why it is relevant to the page. Keep it concise. Do not start with phrases like “image of” or “picture of” unless the medium itself matters.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/front-matter-cover.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">An</span><span class="nv"> </span><span class="s">Eyvan-style</span><span class="nv"> </span><span class="s">arch</span><span class="nv"> </span><span class="s">framing</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">code</span><span class="nv"> </span><span class="s">editor</span><span class="nv"> </span><span class="s">with</span><span class="nv"> </span><span class="s">Jekyll</span><span class="nv"> </span><span class="s">front</span><span class="nv"> </span><span class="s">matter</span><span class="nv"> </span><span class="s">keys"</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Tip:</strong> If the cover image contains important text, include the text or its meaning in <code class="language-plaintext highlighter-rouge">image_alt</code>. If the image is only decorative, consider whether the post needs a cover image at all.</p>
</blockquote>

<h2 id="display-fields">Display fields</h2>

<p>Display fields control what appears in the post header and archive cards. They do not usually change the body content, but they strongly affect navigation and scanning.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-display-fields" data-ref-type="table">
    Display and metadata front matter fields.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Field</th>
      <th style="text-align: left">Type</th>
      <th style="text-align: left">Default</th>
      <th style="text-align: left">Used by</th>
      <th style="text-align: left">What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">tags</code></td>
      <td style="text-align: left">array</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Post header, project archive, tag pages</td>
      <td style="text-align: left">Groups posts and creates tag navigation.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">author</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">template-dependent</td>
      <td style="text-align: left">Entry metadata</td>
      <td style="text-align: left">Displays one author when metadata includes it.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">authors</code></td>
      <td style="text-align: left">array</td>
      <td style="text-align: left">template-dependent</td>
      <td style="text-align: left">Entry metadata</td>
      <td style="text-align: left">Displays multiple authors when supported.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">avatar</code></td>
      <td style="text-align: left">string</td>
      <td style="text-align: left">none</td>
      <td style="text-align: left">Entry metadata</td>
      <td style="text-align: left">Optional author image in post metadata.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">date</code></td>
      <td style="text-align: left">date</td>
      <td style="text-align: left">Filename date for posts</td>
      <td style="text-align: left">Entry metadata, ordering</td>
      <td style="text-align: left">Controls publication date and post sorting.</td>
    </tr>
  </tbody>
</table>

<p>Tags are especially important in this template because the Projects page groups content around posts, cards, and tag archives. Use a small, consistent set of tags. For example, prefer <code class="language-plaintext highlighter-rouge">technical-writing</code> everywhere instead of mixing <code class="language-plaintext highlighter-rouge">technical-writing</code>, <code class="language-plaintext highlighter-rouge">tech-writing</code>, and <code class="language-plaintext highlighter-rouge">docs</code>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">documentation</span><span class="pi">,</span> <span class="nv">jekyll</span><span class="pi">,</span> <span class="nv">reference</span><span class="pi">,</span> <span class="nv">technical-writing</span><span class="pi">]</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">author</code> when a post has one explicit byline that differs from the site-wide default author. This is useful for guest posts, edited notes, or a portfolio template demo where you want to show how attribution works.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">author</span><span class="pi">:</span> <span class="s2">"</span><span class="s">John</span><span class="nv"> </span><span class="s">Michael</span><span class="nv"> </span><span class="s">Doe"</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">avatar</code> when the metadata row should show an author image. The post layout passes <code class="language-plaintext highlighter-rouge">show_avatar=true</code> to the entry metadata include, so an avatar can appear where the metadata include supports it. Store avatar images in a predictable location, such as <code class="language-plaintext highlighter-rouge">assets/images/authors/</code>, and keep them small and square.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">author</span><span class="pi">:</span> <span class="s2">"</span><span class="s">John</span><span class="nv"> </span><span class="s">Michael</span><span class="nv"> </span><span class="s">Doe"</span>
<span class="na">avatar</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/authors/john_doe.webp"</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">authors</code> when a post has multiple credited contributors. Keep names short and consistent, because they may appear in compact metadata areas such as post headers or cards depending on the include implementation.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">authors</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s2">"</span><span class="s">John</span><span class="nv"> </span><span class="s">Michael</span><span class="nv"> </span><span class="s">Doe"</span>
  <span class="pi">-</span> <span class="s2">"</span><span class="s">Jane</span><span class="nv"> </span><span class="s">Mary</span><span class="nv"> </span><span class="s">Smith"</span>
</code></pre></div></div>

<p>For ordinary personal portfolio posts, you can usually omit <code class="language-plaintext highlighter-rouge">author</code>, <code class="language-plaintext highlighter-rouge">authors</code>, and <code class="language-plaintext highlighter-rouge">avatar</code> and let the template use the site-wide author data. Add them only when the post needs custom attribution.</p>

<p>The post date usually comes from the filename. A file named <code class="language-plaintext highlighter-rouge">2026-04-01-my-first-post.md</code> automatically has the date April 1, 2026. You can still set <code class="language-plaintext highlighter-rouge">date</code> manually if you need a specific time, but the filename is cleaner for most posts.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">date</span><span class="pi">:</span> <span class="s">2026-04-01 09:00:00 -0500</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Tip:</strong> Keep tags lowercase and hyphenated. They become part of tag archive URLs, so <code class="language-plaintext highlighter-rouge">technical-writing</code> is more predictable than <code class="language-plaintext highlighter-rouge">Technical Writing</code>.</p>
</blockquote>

<h2 id="feature-fields">Feature fields</h2>

<p>Feature fields are boolean switches. They turn optional behavior on or off for a single page.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-feature-fields" data-ref-type="table">
    Feature-toggle front matter fields.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Field</th>
      <th style="text-align: left">Type</th>
      <th style="text-align: left">Default</th>
      <th style="text-align: left">Used by</th>
      <th style="text-align: left">What it does</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">toc</code></td>
      <td style="text-align: left">boolean</td>
      <td style="text-align: left">none/false</td>
      <td style="text-align: left">Post TOC includes</td>
      <td style="text-align: left">Enables the table of contents experience for long posts.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">math</code></td>
      <td style="text-align: left">boolean</td>
      <td style="text-align: left">false</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_includes/math.html</code></td>
      <td style="text-align: left">Loads MathJax only on pages that need LaTeX math.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">crossrefs</code></td>
      <td style="text-align: left">boolean</td>
      <td style="text-align: left">false</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">_includes/scripts.html</code></td>
      <td style="text-align: left">Loads the script that resolves <code class="language-plaintext highlighter-rouge">ref.html</code> links to numbered table and figure references.</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">share</code></td>
      <td style="text-align: left">boolean</td>
      <td style="text-align: left">true for posts</td>
      <td style="text-align: left">Post header</td>
      <td style="text-align: left">Shows or hides the share controls.</td>
    </tr>
  </tbody>
</table>

<p>Use <code class="language-plaintext highlighter-rouge">toc: true</code> for long posts with several <code class="language-plaintext highlighter-rouge">##</code> and <code class="language-plaintext highlighter-rouge">###</code> headings. The post layout includes mobile and desktop TOC wrappers, and the current TOC includes only second- and third-level headings. This is especially useful for documentation, architecture notes, and tutorials.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">math: true</code> only when the post contains LaTeX-style math. The MathJax
include is guarded by <code class="language-plaintext highlighter-rouge">page.math</code>, so leaving it off avoids loading the
third-party runtime unnecessarily. Eyvan loads an exact, integrity-protected
MathJax CDN release rather than a rolling major-version URL.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">math</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">crossrefs: true</code> when the post uses <code class="language-plaintext highlighter-rouge">{% include ref.html %}</code> to point to numbered figures, videos, audio blocks, or tables. This is a page-level switch: it loads the script that resolves reference links from raw ids into labels such as “Figure 1” or “Table 2.” It does not control whether an individual figure, table, video, or audio block is counted.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">share: false</code> when sharing controls would be distracting or unnecessary. For example, a private test post, internal reference page, or draft-style note might not need them.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">share</span><span class="pi">:</span> <span class="kc">false</span>
</code></pre></div></div>

<p>Reading time is currently controlled globally in <code class="language-plaintext highlighter-rouge">_config.yml</code>, not by individual post front matter. The metadata include checks <code class="language-plaintext highlighter-rouge">site.read_time</code> and <code class="language-plaintext highlighter-rouge">site.words_per_minute</code>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">read_time</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">words_per_minute</span><span class="pi">:</span> <span class="m">238</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Tip:</strong> Reading time is an estimate, not a promise. It is most useful when the post is primarily prose. For media-heavy posts, use the introduction to set expectations instead.</p>
</blockquote>

<blockquote>
  <p><strong>Warning:</strong> Do not enable <code class="language-plaintext highlighter-rouge">math: true</code> globally unless almost every page uses math. Conditional loading is better for performance and keeps simple posts simple.</p>
</blockquote>

<h2 id="supported-fields-by-content-type">Supported fields by content type</h2>

<p>Different content types need different front matter. A short page, a long documentation post, and a visual project should not all use the same fields.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-content-types" data-ref-type="table">
    Recommended fields by content type.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Content type</th>
      <th style="text-align: left">Recommended fields</th>
      <th style="text-align: left">Usually omit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Short static page</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">layout</code>, <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">permalink</code>, <code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">toc</code>, <code class="language-plaintext highlighter-rouge">math</code>, <code class="language-plaintext highlighter-rouge">image</code></td>
    </tr>
    <tr>
      <td style="text-align: left">Documentation post</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">subtitle</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">toc</code>, <code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image</code> unless visual</td>
    </tr>
    <tr>
      <td style="text-align: left">Math-heavy post</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">math</code>, <code class="language-plaintext highlighter-rouge">toc</code>, <code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image</code> if not needed</td>
    </tr>
    <tr>
      <td style="text-align: left">Cross-referenced post</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">toc</code>, <code class="language-plaintext highlighter-rouge">crossrefs</code>, <code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">math</code> unless needed</td>
    </tr>
    <tr>
      <td style="text-align: left">Visual project</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">subtitle</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">image</code>, <code class="language-plaintext highlighter-rouge">image_alt</code>, <code class="language-plaintext highlighter-rouge">description</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">math</code></td>
    </tr>
    <tr>
      <td style="text-align: left">Private/dev test</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">share: false</code></td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image</code>, <code class="language-plaintext highlighter-rouge">math</code></td>
    </tr>
  </tbody>
</table>

<p>The best front matter is not the longest. It is the smallest set of fields that accurately describes the content and activates the features the post needs.</p>

<h2 id="creating-your-first-post">Creating your first post</h2>

<p>Follow this process when adding a new post to the template.</p>

<ol>
  <li>
    <p>Create a new Markdown file in <code class="language-plaintext highlighter-rouge">_posts/</code>.</p>

    <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>_posts/2026-04-01-my-first-post.md
</code></pre></div>    </div>
  </li>
  <li>
    <p>Add the required front matter.</p>

    <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Front</span><span class="nv"> </span><span class="s">Matter</span><span class="nv"> </span><span class="s">Field</span><span class="nv"> </span><span class="s">Reference"</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Every</span><span class="nv"> </span><span class="s">supported</span><span class="nv"> </span><span class="s">key,</span><span class="nv"> </span><span class="s">what</span><span class="nv"> </span><span class="s">it</span><span class="nv"> </span><span class="s">does,</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">when</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">it"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">documentation</span><span class="pi">,</span> <span class="nv">jekyll</span><span class="pi">,</span> <span class="nv">reference</span><span class="pi">,</span> <span class="nv">technical-writing</span><span class="pi">]</span>
<span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">complete</span><span class="nv"> </span><span class="s">reference</span><span class="nv"> </span><span class="s">guide</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">all</span><span class="nv"> </span><span class="s">supported</span><span class="nv"> </span><span class="s">front</span><span class="nv"> </span><span class="s">matter</span><span class="nv"> </span><span class="s">fields</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">Jekyll</span><span class="nv"> </span><span class="s">template."</span>
<span class="nn">---</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Write a clear opening paragraph before the first heading.</p>

    <p>This gives readers context immediately and keeps the post card description from doing all the explanatory work.</p>
  </li>
  <li>
    <p>Add headings in a logical order.</p>

    <p>Use <code class="language-plaintext highlighter-rouge">##</code> for major sections and <code class="language-plaintext highlighter-rouge">###</code> for subsections. A table of contents is only helpful when the heading structure is clean.</p>
  </li>
  <li>
    <p>Add tables, code blocks, or callouts where they help the reader.</p>

    <p>Use tables for reference material, fenced code blocks for examples, and blockquotes for notes or warnings.</p>
  </li>
  <li>
    <p>Run the site locally.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>jekyll serve
</code></pre></div>    </div>
  </li>
  <li>
    <p>Check the generated page on desktop and mobile.</p>

    <p>Confirm that the title, subtitle, tags, metadata, TOC, and body spacing all look correct.</p>
  </li>
  <li>
    <p>Commit and push the post.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add _posts/2026-04-01-my-first-post.md
git commit <span class="nt">-m</span> <span class="s2">"Add front matter reference guide"</span>
git push origin main
</code></pre></div>    </div>

    <p>If your default branch is not <code class="language-plaintext highlighter-rouge">main</code>, replace <code class="language-plaintext highlighter-rouge">main</code> with your actual branch name.</p>
  </li>
</ol>

<h2 id="minimal-vs-full-front-matter">Minimal vs full front matter</h2>

<p>Use the minimal version for ordinary posts. Use the full version when you need every major feature.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-minimal-full-front" data-ref-type="table">
    Minimal vs full front matter.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Minimal front matter</th>
      <th style="text-align: left">Full front matter</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Good for short posts, notes, and simple project updates.</td>
      <td style="text-align: left">Good for polished long-form posts with custom metadata and feature toggles.</td>
    </tr>
  </tbody>
</table>

<p>Minimal:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">Short</span><span class="nv"> </span><span class="s">Project</span><span class="nv"> </span><span class="s">Note"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">projects</span><span class="pi">,</span> <span class="nv">notes</span><span class="pi">]</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">short</span><span class="nv"> </span><span class="s">update</span><span class="nv"> </span><span class="s">about</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">recent</span><span class="nv"> </span><span class="s">project."</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>Full:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">layout</span><span class="pi">:</span> <span class="s">post</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Design</span><span class="nv"> </span><span class="s">Philosophy</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">Architecture</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">Eyvan"</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s2">"</span><span class="s">How</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">template</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">structured</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">why</span><span class="nv"> </span><span class="s">it</span><span class="nv"> </span><span class="s">was</span><span class="nv"> </span><span class="s">built</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">way"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">meta</span><span class="pi">,</span> <span class="nv">design</span><span class="pi">,</span> <span class="nv">jekyll</span><span class="pi">,</span> <span class="nv">css</span><span class="pi">,</span> <span class="nv">architecture</span><span class="pi">]</span>
<span class="na">date</span><span class="pi">:</span> <span class="s">2026-06-12 09:00:00 -0500</span>
<span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">math</span><span class="pi">:</span> <span class="kc">false</span>
<span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">share</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">image</span><span class="pi">:</span> <span class="s2">"</span><span class="s">assets/images/posts/khane-amerian-eyvan.webp"</span>
<span class="na">image_alt</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Muqarnas-adorned</span><span class="nv"> </span><span class="s">eyvan</span><span class="nv"> </span><span class="s">courtyard</span><span class="nv"> </span><span class="s">facade</span><span class="nv"> </span><span class="s">at</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">historic</span><span class="nv"> </span><span class="s">Ameri</span><span class="nv"> </span><span class="s">House</span><span class="nv"> </span><span class="s">in</span><span class="nv"> </span><span class="s">Kashan,</span><span class="nv"> </span><span class="s">Iran"</span>
<span class="na">image_position</span><span class="pi">:</span> <span class="s2">"</span><span class="s">center</span><span class="nv"> </span><span class="s">center"</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">A</span><span class="nv"> </span><span class="s">behind-the-scenes</span><span class="nv"> </span><span class="s">look</span><span class="nv"> </span><span class="s">at</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">design</span><span class="nv"> </span><span class="s">decisions,</span><span class="nv"> </span><span class="s">CSS</span><span class="nv"> </span><span class="s">architecture,</span><span class="nv"> </span><span class="s">layout</span><span class="nv"> </span><span class="s">system,</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">feature</span><span class="nv"> </span><span class="s">set</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">template."</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>The minimal version relies on defaults. The full version is more explicit. Both are valid, but the minimal version is easier to maintain when the defaults already match your intent.</p>

<h2 id="markdown-examples">Markdown examples</h2>

<p>Use inline code when referring to field names such as <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">subtitle</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">toc</code>, and <code class="language-plaintext highlighter-rouge">description</code>. Use fenced YAML blocks when showing complete front matter examples. This keeps the writing scannable and makes the post useful as a reference.</p>

<p>Eyvan also includes reusable Liquid snippets for rich Markdown content. Prefer these includes over hand-written HTML because they keep captions, numbering, cross-references, layout classes, and accessibility behavior centralized.</p>

<h3 id="tables-with-captions">Tables with captions</h3>

<p>Use <code class="language-plaintext highlighter-rouge">table-caption.html</code> immediately before a Markdown table when the table needs a visible caption and an anchorable <code class="language-plaintext highlighter-rouge">id</code>.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>table-caption.html<span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"A short caption for the table."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"tbl-example"</span><span class="w">
</span><span class="cp">%}</span>

| Field | Purpose |
| :--- | :--- |
| `title` | Main title |
| `description` | SEO summary |
{: .c-prose-table }
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">caption</code> value is the human-readable table title. The <code class="language-plaintext highlighter-rouge">id</code> value is the stable anchor used for links and cross-references.</p>

<blockquote>
  <p><strong>Important:</strong> Put <code class="language-plaintext highlighter-rouge">{: .c-prose-table }</code> directly after the final table row with no empty line between them. In kramdown, that attribute line attaches the <code class="language-plaintext highlighter-rouge">c-prose-table</code> class to the table. If you leave a blank line, the table may render without the template’s table styling.</p>
</blockquote>

<h3 id="image-figures">Image figures</h3>

<p>Use <code class="language-plaintext highlighter-rouge">figure.html</code> for images that belong to the article body. This is better than plain Markdown image syntax when you need a caption, figure numbering, a cross-reference target, or consistent responsive media styling.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>figure.html<span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"assets/images/posts/token-bucket-diagram.webp"</span><span class="w">
   </span><span class="na">alt</span><span class="o">=</span><span class="s2">"Token bucket rate limiter system diagram"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"A reusable image figure with an optional numbered caption."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-example"</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>Common options include <code class="language-plaintext highlighter-rouge">src</code>, <code class="language-plaintext highlighter-rouge">alt</code>, <code class="language-plaintext highlighter-rouge">caption</code>, and <code class="language-plaintext highlighter-rouge">id</code>. Use <code class="language-plaintext highlighter-rouge">alt</code> for accessibility and <code class="language-plaintext highlighter-rouge">caption</code> for visible explanatory text. Use a stable <code class="language-plaintext highlighter-rouge">id</code> such as <code class="language-plaintext highlighter-rouge">fig-rate-limiter-diagram</code> if you want to link to the figure later.</p>

<p>If the include supports figure numbering, you can usually disable numbering for decorative or supporting images with <code class="language-plaintext highlighter-rouge">numbered="false"</code>.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>figure.html<span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"assets/images/posts/front-matter-cover.webp"</span><span class="w">
   </span><span class="na">alt</span><span class="o">=</span><span class="s2">"Eyvan arch framing a code editor with front matter keys"</span><span class="w">
   </span><span class="na">numbered</span><span class="o">=</span><span class="s2">"false"</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Important:</strong> Images, videos, and audio blocks are numbered as figures by default. Use <code class="language-plaintext highlighter-rouge">numbered="false"</code> only when a captioned media item is decorative, supporting, or otherwise not meant to be counted or referenced. Do not use <code class="language-plaintext highlighter-rouge">ref.html</code> to reference an item marked <code class="language-plaintext highlighter-rouge">numbered="false"</code>, because that item is intentionally excluded from the numbering system.</p>
</blockquote>

<h3 id="multi-image-figure-grids">Multi-image figure grids</h3>

<p>Use the <code class="language-plaintext highlighter-rouge">images</code> parameter instead of <code class="language-plaintext highlighter-rouge">src</code> when one caption and one figure number should cover two or more related images side by side — for example, a before/after pair or a set of photos from the same scene. Each image is one line inside <code class="language-plaintext highlighter-rouge">images</code>, and the lines are separated by pipes (<code class="language-plaintext highlighter-rouge">|</code>) into up to five segments:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>path | alt text | WxH | srcset row | sizes
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Segment</th>
      <th style="text-align: left">Required</th>
      <th style="text-align: left">Purpose</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">path</code></td>
      <td style="text-align: left">Yes</td>
      <td style="text-align: left">Image source, same as <code class="language-plaintext highlighter-rouge">src</code> for a single image</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">alt</code></td>
      <td style="text-align: left">Yes</td>
      <td style="text-align: left">Per-image alt text — each image in the grid needs its own</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">WxH</code></td>
      <td style="text-align: left">No</td>
      <td style="text-align: left">Intrinsic pixel dimensions (e.g. <code class="language-plaintext highlighter-rouge">900x600</code>), used the same way as <code class="language-plaintext highlighter-rouge">width</code>/<code class="language-plaintext highlighter-rouge">height</code> on a single image to reserve layout space and prevent shift</td>
    </tr>
    <tr>
      <td style="text-align: left">srcset row</td>
      <td style="text-align: left">No</td>
      <td style="text-align: left">One responsive candidate for that image, in <code class="language-plaintext highlighter-rouge">path \| descriptor</code> form, same convention as <code class="language-plaintext highlighter-rouge">responsive_srcset</code></td>
    </tr>
    <tr>
      <td style="text-align: left">sizes</td>
      <td style="text-align: left">No</td>
      <td style="text-align: left">A <code class="language-plaintext highlighter-rouge">sizes</code> attribute for that image’s srcset</td>
    </tr>
  </tbody>
</table>

<p>Only <code class="language-plaintext highlighter-rouge">path</code> and <code class="language-plaintext highlighter-rouge">alt</code> are required per image — the dimension, srcset, and sizes segments can be omitted on any line where you don’t have that information yet.</p>

<p>A two-image grid with full captions and <code class="language-plaintext highlighter-rouge">cols</code> set to control the grid width:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>figure.html<span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-grid-example"</span><span class="w">
   </span><span class="na">cols</span><span class="o">=</span><span class="s2">"2"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"Shared caption describing both images together."</span><span class="w">
   </span><span class="na">images</span><span class="o">=</span><span class="s2">"
     assets/images/posts/example-a.webp | First image alt text  | 900x600
     assets/images/posts/example-b.webp | Second image alt text | 900x600
   "</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">cols="2"</code>, <code class="language-plaintext highlighter-rouge">"3"</code>, or <code class="language-plaintext highlighter-rouge">"4"</code> controls how many columns the grid uses on wide viewports; on narrow viewports the images stack to a single column regardless of <code class="language-plaintext highlighter-rouge">cols</code>. The <code class="language-plaintext highlighter-rouge">caption</code> and <code class="language-plaintext highlighter-rouge">id</code> behave exactly as they do for a single image — one shared caption and one figure number for the whole grid, not one per image.</p>

<h3 id="video-figures">Video figures</h3>

<p>Use <code class="language-plaintext highlighter-rouge">video.html</code> for self-hosted videos or third-party embeds. Videos share the same figure counter, so they can be referenced like other figures when they have an <code class="language-plaintext highlighter-rouge">id</code> and numbered caption.</p>

<p>Self-hosted video:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>video.html<span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"assets/videos/posts/geysir-iceland-2023-erupting-geyser-strokkur.webm"</span><span class="w">
   </span><span class="na">poster</span><span class="o">=</span><span class="s2">"assets/images/posts/geysir-iceland-2023-erupting-geyser-strokkur.webp"</span><span class="w">
   </span><span class="na">ratio</span><span class="o">=</span><span class="s2">"16-9"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"A short demonstration of the project interaction."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-demo-video"</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>Multiple self-hosted formats:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>video.html<span class="w">
   </span><span class="na">ratio</span><span class="o">=</span><span class="s2">"16-9"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"The same video provided in WebM and MP4 formats."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-demo-video-formats"</span><span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"
     assets/videos/posts/demo.webm | video/webm
     assets/videos/posts/demo.mp4  | video/mp4
   "</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>The multiple-format paths above are placeholders. Replace them with actual files in your repository.</p>

<p>Third-party embed:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>video.html<span class="w">
   </span><span class="na">embed</span><span class="o">=</span><span class="s2">"https://www.youtube.com/embed/VIDEO_ID"</span><span class="w">
   </span><span class="na">provider</span><span class="o">=</span><span class="s2">"youtube"</span><span class="w">
   </span><span class="na">ratio</span><span class="o">=</span><span class="s2">"16-9"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"An embedded walkthrough video."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-walkthrough-video"</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>Useful options include <code class="language-plaintext highlighter-rouge">src</code>, <code class="language-plaintext highlighter-rouge">embed</code>, <code class="language-plaintext highlighter-rouge">provider</code>, <code class="language-plaintext highlighter-rouge">poster</code>, <code class="language-plaintext highlighter-rouge">captions</code>, <code class="language-plaintext highlighter-rouge">captions_lang</code>, <code class="language-plaintext highlighter-rouge">captions_label</code>, <code class="language-plaintext highlighter-rouge">ratio</code>, <code class="language-plaintext highlighter-rouge">caption</code>, <code class="language-plaintext highlighter-rouge">id</code>, <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">loading</code>, <code class="language-plaintext highlighter-rouge">preload</code>, and <code class="language-plaintext highlighter-rouge">numbered="false"</code>. Use <code class="language-plaintext highlighter-rouge">ratio="16-9"</code> for most videos, <code class="language-plaintext highlighter-rouge">ratio="4-3"</code> for older recordings, <code class="language-plaintext highlighter-rouge">ratio="1-1"</code> for square media, and <code class="language-plaintext highlighter-rouge">ratio="cinema"</code> for wide cinematic embeds.</p>

<h3 id="audio-figures">Audio figures</h3>

<p>Use <code class="language-plaintext highlighter-rouge">audio.html</code> for podcast clips, sound examples, interviews, narration, or any post where audio is part of the content. The exact options should match your local include, but the recommended pattern is similar to video: provide a source, a caption, and an <code class="language-plaintext highlighter-rouge">id</code> when the audio should be referenceable.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>audio.html<span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"assets/audios/posts/ocean-waves-on-pebbly-beach-iceland-loop.opus"</span><span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"A short audio example used in the analysis."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-audio-example"</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>If the include supports multiple formats, prefer providing both MP3 and Ogg/WebM audio for broader browser support.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>audio.html<span class="w">
   </span><span class="na">caption</span><span class="o">=</span><span class="s2">"The same audio clip provided in multiple formats."</span><span class="w">
   </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-audio-formats"</span><span class="w">
   </span><span class="na">src</span><span class="o">=</span><span class="s2">"
     assets/audios/posts/example.ogg | audio/ogg
     assets/audios/posts/example.mp3 | audio/mpeg
   "</span><span class="w">
</span><span class="cp">%}</span>
</code></pre></div></div>

<p>The multiple-format paths above are placeholders. Replace them with actual files in your repository.</p>

<p>Use captions for context, not transcripts. If the audio contains spoken content, link to or include a transcript in the post body for accessibility.</p>

<h3 id="cross-references">Cross-references</h3>

<p>Use <code class="language-plaintext highlighter-rouge">ref.html</code> when you want to link to a numbered table, figure, video, or audio item from the body text. The <code class="language-plaintext highlighter-rouge">id</code> must match the target include or caption id, and the page must set <code class="language-plaintext highlighter-rouge">crossrefs: true</code> so the numbering script loads.</p>

<p><code class="language-plaintext highlighter-rouge">crossrefs: true</code> and <code class="language-plaintext highlighter-rouge">numbered="false"</code> control different layers of the system. <code class="language-plaintext highlighter-rouge">crossrefs: true</code> enables reference resolution for the whole page. <code class="language-plaintext highlighter-rouge">numbered="false"</code> removes one specific figure, video, audio block, or table caption from the numbering system.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>See <span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>ref.html<span class="w"> </span><span class="na">id</span><span class="o">=</span><span class="s2">"tbl-feature-fields"</span><span class="w"> </span><span class="na">cref</span><span class="o">=</span><span class="s2">"true"</span><span class="w"> </span><span class="cp">%}</span> for the feature toggles.
</code></pre></div></div>

<p>With <code class="language-plaintext highlighter-rouge">cref="true"</code>, the reference is displayed with a label such as “Table” or “Figure” when the cross-reference script resolves it. Without <code class="language-plaintext highlighter-rouge">cref</code>, it behaves more like a bare number reference.</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Figure <span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>ref.html<span class="w"> </span><span class="na">id</span><span class="o">=</span><span class="s2">"fig-example"</span><span class="w"> </span><span class="cp">%}</span> shows the reusable media pattern.
</code></pre></div></div>

<h3 id="math-rendering">Math rendering</h3>

<p>For math-heavy posts, use normal Markdown plus LaTeX delimiters, and enable MathJax in front matter with <code class="language-plaintext highlighter-rouge">math: true</code>.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">math</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div>

<p>Inline math can use <code class="language-plaintext highlighter-rouge">$...$</code>, while display math can use <code class="language-plaintext highlighter-rouge">$$...$$</code>.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The token refill rate is $r$ tokens per second.

$$
B(t) = <span class="se">\m</span>in(C, B_0 + rt)
$$
</code></pre></div></div>

<p>Only enable <code class="language-plaintext highlighter-rouge">math: true</code> on pages that need math so simple posts do not load MathJax unnecessarily.</p>

<blockquote>
  <p><strong>Tip:</strong> If you are writing a post that explains Liquid includes, wrap example include tags in <code class="language-plaintext highlighter-rouge">and</code> so Jekyll displays the example instead of executing it.</p>
</blockquote>

<h2 id="troubleshooting">Troubleshooting</h2>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-troubleshooting" data-ref-type="table">
    Common front matter problems and fixes.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Problem</th>
      <th style="text-align: left">Likely cause</th>
      <th style="text-align: left">Fix</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">The page renders without the post layout</td>
      <td style="text-align: left">Missing front matter or wrong collection</td>
      <td style="text-align: left">Ensure the file starts with <code class="language-plaintext highlighter-rouge">---</code> and lives in <code class="language-plaintext highlighter-rouge">_posts/</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left">The title does not appear correctly</td>
      <td style="text-align: left">Missing or malformed <code class="language-plaintext highlighter-rouge">title</code></td>
      <td style="text-align: left">Use a quoted string: <code class="language-plaintext highlighter-rouge">title: "My Post Title"</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left">Tags do not appear</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">tags</code> is not an array</td>
      <td style="text-align: left">Use <code class="language-plaintext highlighter-rouge">tags: [jekyll, documentation]</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left">TOC does not show</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">toc</code> missing, false, or headings are outside the supported levels</td>
      <td style="text-align: left">Add <code class="language-plaintext highlighter-rouge">toc: true</code> and use clear <code class="language-plaintext highlighter-rouge">##</code> / <code class="language-plaintext highlighter-rouge">###</code> headings.</td>
    </tr>
    <tr>
      <td style="text-align: left">Math does not render</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">math: true</code> is missing</td>
      <td style="text-align: left">Add <code class="language-plaintext highlighter-rouge">math: true</code> to the post front matter.</td>
    </tr>
    <tr>
      <td style="text-align: left">Cross-reference text stays as an id</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">crossrefs: true</code> is missing</td>
      <td style="text-align: left">Add <code class="language-plaintext highlighter-rouge">crossrefs: true</code> when using <code class="language-plaintext highlighter-rouge">ref.html</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left">Social preview image is wrong</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">og_image</code> / <code class="language-plaintext highlighter-rouge">image</code> missing or path incorrect</td>
      <td style="text-align: left">Add a valid relative path or configure <code class="language-plaintext highlighter-rouge">default_og_image</code>.</td>
    </tr>
    <tr>
      <td style="text-align: left">Cover image alt text is generic</td>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">image_alt</code> missing</td>
      <td style="text-align: left">Add descriptive <code class="language-plaintext highlighter-rouge">image_alt</code> text.</td>
    </tr>
    <tr>
      <td style="text-align: left">YAML build error</td>
      <td style="text-align: left">Bad indentation, colon, or unquoted special character</td>
      <td style="text-align: left">Quote strings that contain punctuation and keep arrays valid.</td>
    </tr>
  </tbody>
</table>

<p>YAML is strict about indentation and punctuation. A colon inside an unquoted string can break parsing. When in doubt, quote the value.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Front</span><span class="nv"> </span><span class="s">Matter</span><span class="nv"> </span><span class="s">Field</span><span class="nv"> </span><span class="s">Reference:</span><span class="nv"> </span><span class="s">A</span><span class="nv"> </span><span class="s">Practical</span><span class="nv"> </span><span class="s">Guide"</span>
</code></pre></div></div>

<p>Arrays can be written inline:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">documentation</span><span class="pi">,</span> <span class="nv">jekyll</span><span class="pi">,</span> <span class="nv">reference</span><span class="pi">]</span>
</code></pre></div></div>

<p>Or as a block:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">tags</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">documentation</span>
  <span class="pi">-</span> <span class="s">jekyll</span>
  <span class="pi">-</span> <span class="s">reference</span>
</code></pre></div></div>

<p>Both work. Inline arrays are compact and good for short tag lists. Block arrays are easier to read when the list grows.</p>

<h2 id="recommended-front-matter-pattern">Recommended front matter pattern</h2>

<p>For most long-form posts in this template, start with this pattern:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Clear,</span><span class="nv"> </span><span class="s">Specific</span><span class="nv"> </span><span class="s">Title"</span>
<span class="na">subtitle</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Optional</span><span class="nv"> </span><span class="s">sentence</span><span class="nv"> </span><span class="s">that</span><span class="nv"> </span><span class="s">explains</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">angle"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">primary-topic</span><span class="pi">,</span> <span class="nv">secondary-topic</span><span class="pi">,</span> <span class="nv">format</span><span class="pi">]</span>
<span class="na">toc</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">crossrefs</span><span class="pi">:</span> <span class="kc">true</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">One</span><span class="nv"> </span><span class="s">concise</span><span class="nv"> </span><span class="s">sentence</span><span class="nv"> </span><span class="s">explaining</span><span class="nv"> </span><span class="s">what</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">reader</span><span class="nv"> </span><span class="s">will</span><span class="nv"> </span><span class="s">learn."</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>Add <code class="language-plaintext highlighter-rouge">image</code> and <code class="language-plaintext highlighter-rouge">image_alt</code> when the post needs a visible cover. Use
<code class="language-plaintext highlighter-rouge">og_image</code> when it needs separate social artwork or a social preview without a
cover. Add the exact <code class="language-plaintext highlighter-rouge">image_width</code> and <code class="language-plaintext highlighter-rouge">image_height</code> together when known, and
add <code class="language-plaintext highlighter-rouge">image_position</code> when the cover needs custom cropping. Add <code class="language-plaintext highlighter-rouge">math: true</code> only
when the post contains math. Add <code class="language-plaintext highlighter-rouge">crossrefs: true</code> only when the post uses
<code class="language-plaintext highlighter-rouge">ref.html</code>. Add <code class="language-plaintext highlighter-rouge">share: false</code> only when you intentionally want to suppress the
share controls.</p>

<p>This approach keeps the content clean, the build predictable, and the template easy to maintain. The front matter stays small, but each key has a real job: <code class="language-plaintext highlighter-rouge">title</code> identifies the post, <code class="language-plaintext highlighter-rouge">subtitle</code> frames it, <code class="language-plaintext highlighter-rouge">tags</code> connect it to the archive, <code class="language-plaintext highlighter-rouge">toc</code> improves navigation, and <code class="language-plaintext highlighter-rouge">description</code> supports search and previews.</p>

<p>Front matter is not just metadata. In this Jekyll template, it is the control panel for each page. Used consistently, it lets you publish documentation, project write-ups, visual essays, and technical tutorials without changing the layout code every time.</p>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>The diagram (the post’s cover image) was generated with AI tools for illustrative purposes by the author using the contents of this post as the generation prompt. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="documentation" /><category term="jekyll" /><category term="reference" /><category term="technical-writing" /><summary type="html"><![CDATA[A complete reference guide for all supported front matter fields in this Jekyll template.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/front-matter-cover.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/front-matter-cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Visualizing 30 Years of Climate Trends</title><link href="https://amirhs1.github.io/eyvan/projects/climate-data-analysis/" rel="alternate" type="text/html" title="Visualizing 30 Years of Climate Trends" /><published>2026-03-07T00:00:00+00:00</published><updated>2026-03-07T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/climate-data-analysis</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/climate-data-analysis/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post and its associated synthetic, NOAA-inspired climate dataset were generated with AI tools to demonstrate Eyvan’s typography, mathematical notation, table captions, cross-references, and embedded charts. The values are plausible but should not be treated as a reproducible NOAA analysis unless they are replaced with a documented data pipeline and source files.</p>
</blockquote>

<blockquote>
  <p><strong>Template note:</strong> The interactive charts and <code class="language-plaintext highlighter-rouge">demo-climate-charts.js</code> are
demonstration content, not a core Eyvan dependency. Template users who do
not keep this post can remove the demo script with it.</p>
</blockquote>

<h2 id="introduction--methodology">Introduction &amp; Methodology</h2>

<p>The study of climate change benefits from clear analytical frameworks, especially when long-term trends need to be communicated through tables, figures, and statistical summaries. This demo post uses climate-style data to show how the Eyvan template handles mathematical notation, styled Markdown tables, numbered captions, cross-references, and embedded JavaScript charts.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<p>The dataset below spans exactly 30 years, from 1996 through 2025. It is a synthetic, NOAA-inspired demonstration dataset rather than a directly downloaded observational record. The values are structured to resemble a regional mid-latitude climate summary, with yearly maximum temperature, minimum temperature, temperature anomaly, precipitation total, and precipitation-status fields.</p>

<h3 id="data-harmonization-and-processing">Data Harmonization and Processing</h3>

<p>Real climate datasets often require careful preprocessing before analysis. Station moves, changing instruments, missing values, observation-time differences, and urbanization effects can all influence raw measurements. A production-quality analysis should document the data source, processing scripts, quality-control decisions, and uncertainty assumptions.</p>

<p>For this template demonstration, the preprocessing steps are presented as representative examples rather than as operations actually performed on raw NOAA files:</p>

<ol>
  <li><strong>Time-of-observation adjustment:</strong> A real workflow may standardize daily readings to reduce artifacts introduced by morning or afternoon station resets.</li>
  <li><strong>Homogenization:</strong> A real workflow may compare neighboring stations to identify artificial step changes caused by station relocation or equipment changes.</li>
  <li><strong>Missing-value handling:</strong> A real workflow may flag, remove, or estimate missing observations depending on the amount of missingness and the research question.</li>
</ol>

<p>The synthetic dataset is grouped into three distinct decadal epochs: Epoch I (1996–2005), Epoch II (2006–2015), and Epoch III (2016–2025). Segmenting the 30-year span into ten-year blocks helps demonstrate how tables and charts can communicate changes in central tendency and variability.</p>

<h2 id="statistical-formulas">Statistical Formulas</h2>

<p>To establish a mathematical foundation for our observations, we employ standard descriptive statistics. When evaluating climate parameters over multi-decade intervals, tracking the shift in the central tendency alone is insufficient; we must also quantify the dispersion and volatility of these systems.</p>

<p>The arithmetic mean ($\bar{x}$) represents the foundational baseline for decadal averages, calculated as:</p>

\[\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i\]

<p>Where $x_i$ denotes an individual annual or seasonal temperature/precipitation metric, and $n$ represents the total number of observed periods within that specific decade ($n = 10$ for annual aggregations within an epoch).</p>

<p>To measure the overall volatility and spread of temperatures within each epoch, we compute the sample standard deviation ($s$):</p>

\[s = \sqrt{\frac{1}{n-1}\sum_{i=1}^{n} (x_i - \bar{x})^2}\]

<p>A rising standard deviation over successive epochs would indicate increasing variability within the measured series. In this synthetic example, it is used to demonstrate how a post can discuss dispersion alongside changes in the mean.</p>

<h2 id="decadal-summary-statistics">Decadal Summary Statistics</h2>

<p>Applying these formulas to the synthetic dataset yields a distinct trajectory. The table below presents aggregate summary metrics for surface temperatures across the three designated decades. Here, mean temperature corresponds to $\bar{x}$, standard deviation corresponds to $s$, and heat days count average annual days above $35$°C.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-decadal-summary" data-ref-type="table">
    Synthetic decadal summary statistics for surface temperatures and extreme heat days.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Epoch</th>
      <th style="text-align: left">Time Period</th>
      <th style="text-align: left">Mean Temp (°C)</th>
      <th style="text-align: left">Median Temp (°C)</th>
      <th style="text-align: left">Std Dev (°C)</th>
      <th style="text-align: left">Heat Days &gt;35°C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Epoch I</strong></td>
      <td style="text-align: left">1996–2005</td>
      <td style="text-align: left">14.21</td>
      <td style="text-align: left">14.15</td>
      <td style="text-align: left">0.62</td>
      <td style="text-align: left">12.4</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Epoch II</strong></td>
      <td style="text-align: left">2006–2015</td>
      <td style="text-align: left">14.68</td>
      <td style="text-align: left">14.52</td>
      <td style="text-align: left">0.78</td>
      <td style="text-align: left">18.1</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Epoch III</strong></td>
      <td style="text-align: left">2016–2025</td>
      <td style="text-align: left">15.14</td>
      <td style="text-align: left">15.11</td>
      <td style="text-align: left">0.94</td>
      <td style="text-align: left">24.5</td>
    </tr>
  </tbody>
</table>

<h3 id="analysis-of-decadal-summaries">Analysis of Decadal Summaries</h3>

<p>The table reveals a clear upward shift in the synthetic central tendency metrics. The arithmetic mean ($\bar{x}$) rises by $0.47$°C between Epoch I and Epoch II, followed by an additional increase of $0.46$°C moving into Epoch III. This yields a net increase of $+0.93$°C over the 30-year demo period.</p>

<p>Concurrently, the sample standard deviation ($s$) expands from $0.62$°C to $0.94$°C. In a real observational study, that change would require uncertainty analysis before being interpreted as a robust increase in climate variability. In this demo dataset, it illustrates how Eyvan can present both central tendency and dispersion. The final column also demonstrates how derived metrics can be summarized: average annual heat days above $35$°C increase from $12.4$ days per year in Epoch I to $24.5$ days per year in Epoch III.</p>

<h2 id="comprehensive-annual-climate-record">Comprehensive Annual Climate Record</h2>

<p>To observe how these multi-decadal shifts appear on an annual basis, we can inspect the unaggregated demo series. The following multi-column table presents yearly temperature and precipitation values, including a synthetic temperature anomaly field modeled as if it were relative to a long-term baseline.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-annual-climate-record" data-ref-type="table">
    Synthetic annual temperature anomalies, precipitation totals, and climate variations from 1996 to 2025.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Year</th>
      <th style="text-align: left">Mean Max (°C)</th>
      <th style="text-align: left">Mean Min (°C)</th>
      <th style="text-align: left">Temp Anomaly (°C)</th>
      <th style="text-align: left">Annual Precip (mm)</th>
      <th style="text-align: left">Precip Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">1996</td>
      <td style="text-align: left">19.4</td>
      <td style="text-align: left">8.8</td>
      <td style="text-align: left">-0.12</td>
      <td style="text-align: left">845</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">1997</td>
      <td style="text-align: left">19.6</td>
      <td style="text-align: left">9.1</td>
      <td style="text-align: left">+0.05</td>
      <td style="text-align: left">892</td>
      <td style="text-align: left">Above Average</td>
    </tr>
    <tr>
      <td style="text-align: left">1998</td>
      <td style="text-align: left">20.1</td>
      <td style="text-align: left">9.7</td>
      <td style="text-align: left">+0.41</td>
      <td style="text-align: left">780</td>
      <td style="text-align: left">Below Average</td>
    </tr>
    <tr>
      <td style="text-align: left">1999</td>
      <td style="text-align: left">19.5</td>
      <td style="text-align: left">8.9</td>
      <td style="text-align: left">-0.03</td>
      <td style="text-align: left">830</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2000</td>
      <td style="text-align: left">19.3</td>
      <td style="text-align: left">8.7</td>
      <td style="text-align: left">-0.15</td>
      <td style="text-align: left">865</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2001</td>
      <td style="text-align: left">19.8</td>
      <td style="text-align: left">9.2</td>
      <td style="text-align: left">+0.18</td>
      <td style="text-align: left">812</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2002</td>
      <td style="text-align: left">19.9</td>
      <td style="text-align: left">9.4</td>
      <td style="text-align: left">+0.22</td>
      <td style="text-align: left">795</td>
      <td style="text-align: left">Below Average</td>
    </tr>
    <tr>
      <td style="text-align: left">2003</td>
      <td style="text-align: left">20.2</td>
      <td style="text-align: left">9.6</td>
      <td style="text-align: left">+0.39</td>
      <td style="text-align: left">850</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2004</td>
      <td style="text-align: left">19.5</td>
      <td style="text-align: left">8.9</td>
      <td style="text-align: left">-0.01</td>
      <td style="text-align: left">910</td>
      <td style="text-align: left">Above Average</td>
    </tr>
    <tr>
      <td style="text-align: left">2005</td>
      <td style="text-align: left">20.4</td>
      <td style="text-align: left">9.9</td>
      <td style="text-align: left">+0.51</td>
      <td style="text-align: left">824</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2006</td>
      <td style="text-align: left">20.5</td>
      <td style="text-align: left">10.1</td>
      <td style="text-align: left">+0.58</td>
      <td style="text-align: left">801</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2007</td>
      <td style="text-align: left">20.3</td>
      <td style="text-align: left">9.8</td>
      <td style="text-align: left">+0.44</td>
      <td style="text-align: left">742</td>
      <td style="text-align: left">Deficit</td>
    </tr>
    <tr>
      <td style="text-align: left">2008</td>
      <td style="text-align: left">20.0</td>
      <td style="text-align: left">9.5</td>
      <td style="text-align: left">+0.21</td>
      <td style="text-align: left">885</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2009</td>
      <td style="text-align: left">20.2</td>
      <td style="text-align: left">9.6</td>
      <td style="text-align: left">+0.32</td>
      <td style="text-align: left">920</td>
      <td style="text-align: left">Above Average</td>
    </tr>
    <tr>
      <td style="text-align: left">2010</td>
      <td style="text-align: left">20.8</td>
      <td style="text-align: left">10.4</td>
      <td style="text-align: left">+0.74</td>
      <td style="text-align: left">860</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2011</td>
      <td style="text-align: left">20.6</td>
      <td style="text-align: left">10.2</td>
      <td style="text-align: left">+0.61</td>
      <td style="text-align: left">955</td>
      <td style="text-align: left">Surge</td>
    </tr>
    <tr>
      <td style="text-align: left">2012</td>
      <td style="text-align: left">21.2</td>
      <td style="text-align: left">10.9</td>
      <td style="text-align: left">+1.02</td>
      <td style="text-align: left">698</td>
      <td style="text-align: left">Severe Deficit</td>
    </tr>
    <tr>
      <td style="text-align: left">2013</td>
      <td style="text-align: left">20.4</td>
      <td style="text-align: left">9.9</td>
      <td style="text-align: left">+0.49</td>
      <td style="text-align: left">872</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2014</td>
      <td style="text-align: left">20.7</td>
      <td style="text-align: left">10.3</td>
      <td style="text-align: left">+0.68</td>
      <td style="text-align: left">841</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2015</td>
      <td style="text-align: left">21.1</td>
      <td style="text-align: left">10.8</td>
      <td style="text-align: left">+0.95</td>
      <td style="text-align: left">815</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2016</td>
      <td style="text-align: left">21.4</td>
      <td style="text-align: left">11.1</td>
      <td style="text-align: left">+1.15</td>
      <td style="text-align: left">790</td>
      <td style="text-align: left">Below Average</td>
    </tr>
    <tr>
      <td style="text-align: left">2017</td>
      <td style="text-align: left">21.3</td>
      <td style="text-align: left">11.0</td>
      <td style="text-align: left">+1.08</td>
      <td style="text-align: left">934</td>
      <td style="text-align: left">Above Average</td>
    </tr>
    <tr>
      <td style="text-align: left">2018</td>
      <td style="text-align: left">21.6</td>
      <td style="text-align: left">11.4</td>
      <td style="text-align: left">+1.28</td>
      <td style="text-align: left">982</td>
      <td style="text-align: left">Surge</td>
    </tr>
    <tr>
      <td style="text-align: left">2019</td>
      <td style="text-align: left">21.5</td>
      <td style="text-align: left">11.2</td>
      <td style="text-align: left">+1.19</td>
      <td style="text-align: left">804</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2020</td>
      <td style="text-align: left">21.9</td>
      <td style="text-align: left">11.8</td>
      <td style="text-align: left">+1.44</td>
      <td style="text-align: left">710</td>
      <td style="text-align: left">Deficit</td>
    </tr>
    <tr>
      <td style="text-align: left">2021</td>
      <td style="text-align: left">21.7</td>
      <td style="text-align: left">11.5</td>
      <td style="text-align: left">+1.32</td>
      <td style="text-align: left">866</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2022</td>
      <td style="text-align: left">22.1</td>
      <td style="text-align: left">12.0</td>
      <td style="text-align: left">+1.56</td>
      <td style="text-align: left">1015</td>
      <td style="text-align: left">Extreme Surge</td>
    </tr>
    <tr>
      <td style="text-align: left">2023</td>
      <td style="text-align: left">22.4</td>
      <td style="text-align: left">12.3</td>
      <td style="text-align: left">+1.78</td>
      <td style="text-align: left">650</td>
      <td style="text-align: left">Extreme Deficit</td>
    </tr>
    <tr>
      <td style="text-align: left">2024</td>
      <td style="text-align: left">22.2</td>
      <td style="text-align: left">12.1</td>
      <td style="text-align: left">+1.62</td>
      <td style="text-align: left">890</td>
      <td style="text-align: left">Normal</td>
    </tr>
    <tr>
      <td style="text-align: left">2025</td>
      <td style="text-align: left">22.6</td>
      <td style="text-align: left">12.5</td>
      <td style="text-align: left">+1.85</td>
      <td style="text-align: left">765</td>
      <td style="text-align: left">Below Average</td>
    </tr>
  </tbody>
</table>

<h3 id="interpretation-of-year-over-year-dynamics">Interpretation of Year-over-Year Dynamics</h3>

<p>Reviewing the annual records in <a class="c-prose-xref c-prose-xref--cref" href="#tbl-annual-climate-record">tbl-annual-climate-record</a> shows how a long table can support detailed interpretation. Early demo years such as 1996 and 2000 contain negative temperature anomalies, while the synthetic series contains only positive anomalies after 2010.</p>

<p>The year 2012 is the first year in this demo table where the temperature anomaly crosses the $+1.0$°C threshold ($+1.02$°C), coinciding with a low precipitation total ($698$ mm). This does not prove a causal relationship, but it illustrates how a post can connect tabular evidence to a cautious interpretation. The final five years show the highest values in the synthetic anomaly series, ending with $+1.85$°C in 2025.</p>

<h2 id="visualizing-temperature-trends">Visualizing Temperature Trends</h2>

<p>To translate the tabular record into an interpretable visual sequence, the interactive line chart below charts the progression of both mean maximum and mean minimum temperatures over the 30-year demo period.</p>

<figure class="c-prose-figure c-prose-figure--chart" id="fig-temperature-line-chart" data-ref-type="figure">
  <div class="c-prose-figure__frame">
    <canvas class="c-prose-figure__canvas" id="temperatureLineChart" aria-label="Line chart comparing mean maximum and mean minimum temperatures from 1996 to 2025" role="img"></canvas>
  </div>
  <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
    Synthetic mean maximum and minimum surface temperature trajectories from 1996 to 2025.
  </figcaption>
</figure>

<h3 id="analysis-of-the-line-chart-trajectory">Analysis of the Line Chart Trajectory</h3>

<p>In this synthetic dataset, minimum temperatures rise faster than maximum temperatures. The mean maximum temperature increases from $19.4$°C in 1996 to $22.6$°C in 2025, while the mean minimum temperature increases from $8.8$°C to $12.5$°C over the same period.</p>

<p>This pattern is scientifically plausible: observed warming often affects nighttime minimum temperatures strongly because greenhouse gases reduce outgoing longwave cooling. However, the chart should be read as a demonstration of the template’s charting and caption system, not as evidence from a documented observational pipeline.</p>

<h2 id="hydrological-instability-precipitation-volatility">Hydrological Instability: Precipitation Volatility</h2>

<p>While the synthetic temperature metrics follow a steady upward trajectory, precipitation behaves differently. Rather than showing a clean linear increase or decrease, the demo series alternates between wetter and drier years.</p>

<p>The bar chart below shows annual precipitation values, organized into three decadal blocks to illustrate variability across the demo period.</p>

<figure class="c-prose-figure c-prose-figure--chart" id="fig-precipitation-bar-chart" data-ref-type="figure">
  <div class="c-prose-figure__frame">
    <canvas class="c-prose-figure__canvas" id="precipitationBarChart" aria-label="Bar chart showing annual precipitation from 1996 to 2025 grouped by decadal epoch" role="img"></canvas>
  </div>
  <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
    Synthetic annual precipitation variability grouped by decadal epoch from 1996 to 2025.
  </figcaption>
</figure>

<script id="ChartJS-demo-script" defer="" src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js" integrity="sha384-jb8JQMbMoBUzgWatfe6COACi2ljcDdZQ2OxczGA3bGNeWe+6DChMTBJemed7ZnvJ" crossorigin="anonymous" referrerpolicy="no-referrer">
</script>

<script src="/eyvan/assets/js/demo-climate-charts.js" defer="">
</script>

<h3 id="interpretation-of-hydrological-trends">Interpretation of Hydrological Trends</h3>

<p>The distribution of precipitation across the three epochs demonstrates how Eyvan handles a second chart type and a longer explanatory section. In Epoch I, precipitation remains within a relatively narrow range between $780$ mm and $910$ mm.</p>

<p>In Epoch II, the synthetic series becomes more variable, with a low value of $698$ mm in 2012 and a high value of $955$ mm in 2011. Epoch III contains the highest and lowest precipitation values in the demo table: $1015$ mm in 2022 and $650$ mm in 2023.</p>

<p>This pattern is consistent with a common climate-science explanation: a warmer atmosphere can hold more water vapor, approximately 7% more per 1°C of warming under Clausius-Clapeyron scaling. That physical relationship can contribute to heavier precipitation events in some contexts while also intensifying drying between storms. In this post, however, the precipitation sequence is illustrative rather than a formal statistical test.</p>

<h2 id="limitations--caveats">Limitations &amp; Caveats</h2>

<p>Because this is a synthetic demo post, the main limitation is that the values are not reproducible observational results. A real analysis should include downloadable data, source URLs or DOIs, processing scripts, versioned dependencies, and documented quality-control decisions.</p>

<p>Additional limitations that would matter in a real climate-data workflow include:</p>

<ul>
  <li><strong>Spatial aggregation constraints:</strong> Regional averages can hide local variation and should define the included stations or grid cells.</li>
  <li><strong>Urban heat island artifacts:</strong> Stations near expanding built environments may require careful treatment.</li>
  <li><strong>Precipitation capture efficiency:</strong> Gauges can under-report precipitation during high winds or intense events.</li>
  <li><strong>Uncertainty and significance:</strong> Trends should be tested statistically rather than inferred visually from a short table.</li>
</ul>

<h2 id="references">References</h2>

<ol>
  <li>
    <p>National Oceanic and Atmospheric Administration, <em>Global Historical Climatology Network Daily (GHCN-Daily), Version 4.0</em>, National Centers for Environmental Information, U.S. Department of Commerce (2025).</p>
  </li>
  <li>
    <p>Intergovernmental Panel on Climate Change, <em>Climate Change 2021: The Physical Science Basis</em>, Contribution of Working Group I to the Sixth Assessment Report of the Intergovernmental Panel on Climate Change, Cambridge University Press, Cambridge, England (2021).</p>
  </li>
  <li>
    <p>K. E. Trenberth, “Changes in precipitation with climate change,” <em>Climate Research</em> <strong>47</strong>, 123–138 (2011).</p>
  </li>
</ol>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>Cover image generated with Easy-Peasy.AI’s AI Image Generator, “Global Temperature Rise Visualized in Polar Perspective” (created Jan. 14, 2024), free to use with backlink attribution to <a href="https://easy-peasy.ai/ai-image-generator/images/global-rise-temperature-visualization-polar-regions-emphasis">Easy-Peasy.AI</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="data" /><category term="climate" /><category term="visualization" /><category term="analysis" /><summary type="html"><![CDATA[A data-rich demo post exploring synthetic temperature and precipitation trends using tables, math, cross-references, and embedded charts.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/global_temperature_rise.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/global_temperature_rise.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Field Notes: Iceland 2025</title><link href="https://amirhs1.github.io/eyvan/projects/field-notes-iceland-2025/" rel="alternate" type="text/html" title="Field Notes: Iceland 2025" /><published>2026-02-25T00:00:00+00:00</published><updated>2026-02-25T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/field-notes-iceland-2025</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/field-notes-iceland-2025/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools for the sole purpose of demonstrating the rich typographic and mathematical capabilities of the Eyvan template.</p>
</blockquote>

<p>The air at the edge of the Arctic Circle does not merely fill your lungs; it shocks the senses into a state of acute clarity. In the late autumn of 2025, I found myself standing on the basalt cliffs of Reykjanes, watching the North Atlantic smash itself to foam against rocks that are, geologically speaking, still in their infancy. Iceland is a landscape stripped of all ornamentation. Here, the planet’s molten spine breaks through the crust, creating a chaotic laboratory of steam, sulfur, and stone. To travel through this terrain with a camera and a notebook is to realize that the earth is not a static stage upon which life plays out, but a living, breathing entity undergoing perpetual transformation.</p>

<p>This post serves as both a creative field journal and a practical stress test for the Eyvan template’s reusable media tools: numbered figures, responsive image grids, embedded video, table captions, and cross-references. When documenting a landscape defined by scale and contrast, standard web layouts often fail to capture the sheer kinetic energy of the environment. Over the course of three weeks, I sought to blend long-form descriptive prose with diverse visual formats—ranging from high-resolution static frames and multi-image structural grids to responsive, high-definition video captures. The goal was simple: to build an immersive digital archive where text, imagery, and moving pictures do not merely coexist, but actively enrich one another’s narrative weight.</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-1" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/iceland-hero.webp" alt="Iceland: Stunning view of rugged Icelandic cliffs (basalt cliffs of Reykjanes) meeting the ocean under a cloudy sky" loading="eager" width="900" height="675" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      
A spectacular view of the rugged basalt cliffs of Reykjanes, Iceland, meeting the ocean under a cloudy sky. This image (and the cover image) from <a href="https://www.pexels.com/photo/rough-mountains-covered-with-green-moss-and-grass-near-seashore-5031526/">Pexels</a> by Lyn Ong (Aug 4, 2020), used under the <a href="https://www.pexels.com/license/">Pexels License</a>.

    </figcaption>
  
</figure>

<h2 id="the-textures-of-liquid-rock">The Textures of Liquid Rock</h2>

<p>To understand the Icelandic interior, one must learn to read the language of lava. The landscape is dominated by two common surface forms of basaltic flows: <em>hella-hraun</em> (smooth, ropey pāhoehoe) and <em>apal-hraun</em> (jagged, blocky ʻaʻā). Walking across an ancient <em>apal-hraun</em> field is a lesson in tactile geography. Every surface is razor-sharp, encrusted with a brittle layer of grey-green wool-moss (<em>Racomitrium lanuginosum</em>) that takes centuries to establish itself over the black glass. The contrast is conceptually striking—the softest, most fragile biological pioneer clinging to the hardest, most violent geological foundation.</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-1" id="fig-basalt" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/iceland-basalt.webp" alt="Hexagonal columns of dark volcanic basalt catching golden evening light" loading="eager" width="800" height="1067" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      The geometric perfection of columns at Reynisfjara. These basalt structures form via columnar jointing as thick lava flows cool slowly over months, contracting into distinct hexagonal geometric prisms. Image from <a href="https://www.pexels.com/photo/rock-formations-on-the-beach-7614602/">Pexels</a> by Batın Özen, used under the Pexels License.

    </figcaption>
  
</figure>

<p>When you isolate these structures through a lens, the scale becomes ambiguous. A close-up of a basalt joint looks identical to an aerial view of an entire canyon system. It is a fractal landscape where the micro mirrors the macro. This spatial disorientation is compounded by the quality of the Arctic light. During the shoulder seasons, the sun never rises high into the sky; instead, it scrapes along the horizon for six continuous hours, casting elongated, dramatic shadows that reveal micro-topographies invisible under a standard midday sun. Every grain of silica, every microscopic fissure in the stone, stands out in high relief.</p>

<h2 id="juxtaposition-fire-and-ice">Juxtaposition: Fire and Ice</h2>

<p>Nowhere is the paradox of Iceland more evident than at the boundaries where active geothermal areas collide with glacial runoff. In the southern valleys, one can stand with one foot immersed in a freezing meltwater stream while the back of your neck is warmed by a plume of boiling, sulfurous steam rising from an unseen vent in the earth. The color palette of these zones defies the traditional expectations of a volcanic wasteland. Far from being monochrome, the earth bleeds deep ochres, vivid turquoise, and brilliant copper greens, all synthesized by the extreme chemical interactions occurring just meters beneath the surface.</p>

<p>To capture this intense material contrast, the post uses a two-column responsive figure grid. The side-by-side structure in <a class="c-prose-xref c-prose-xref--cref" href="#fig-fire-ice">fig-fire-ice</a> provides an ideal framework for examining how these opposing environmental forces occupy the same geographic coordinates.</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-2" id="fig-fire-ice" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/iceland-vent.webp" alt="A boiling geothermal mud pot venting thick sulfurous steam in Námafjall" loading="lazy" width="900" height="601" /><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/iceland-glacier.webp" alt="Deep blue glacial ice calving into a grey glacial lagoon under an overcast sky" loading="lazy" width="900" height="595" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Fire and ice in the same frame: geothermal venting at Námafjall, where minerals stain the clay (left), and compressed ancient ice calving into the dark waters of Jökulsárlón (right). The left image from <a href="https://www.pexels.com/photo/brown-ground-near-body-of-water-464399/">Pexels</a> by Francesco Ungaro (Jun 29, 2017), used under the Pexels License, and the right image adapted from <a href="https://commons.wikimedia.org/wiki/File:Jokulsarlon_lake,_Iceland.jpg">Wikimedia Commons</a> by Kenny Muir (May 7, 2006), licensed under Creative Commons CC BY 2.0.

    </figcaption>
  
</figure>

<p>In the image on the left, the earth is actively destroying itself—acidic steam dissolving solid rock into bubbling, grey mud pools that smell intensely of elemental sulfur. In the image on the right, the process is reversed; centuries of compressed snowfall are preserved in the dense, oxygen-starved blue ice of the Breiðamerkurjökull tongue, slowly sliding toward its demise in a warming ocean. Both images represent different states of time. The geothermal vent is instantaneous, volatile, and immediate. The glacier is slow, historical, and structural, holding within its crystalline matrix the atmospheric data of past millennia.</p>

<h2 id="kinetic-horizons-the-moving-frame">Kinetic Horizons: The Moving Frame</h2>

<p>While a photograph can freeze the stark geometries of the landscape, it fundamentally strips away the element of time. Iceland is not silent, nor is it still. It is a land of continuous, roaring motion. The wind is a permanent physical presence, molding the waves, driving the low clouds, and forcing the waterfalls to blow backward over the edges of the escarpments. To truly convey this sensory environment, video must be woven directly into the fabric of the text, functioning as an extension of the prose rather than an afterthought or an external link.</p>

<p>The embed in <a class="c-prose-xref c-prose-xref--cref" href="#fig-coast-video">fig-coast-video</a> uses the reusable video include in third-party mode, maintaining a strict 16:9 widescreen aspect ratio across all viewports to preserve the cinematic horizon of the southern coast.</p>

<figure class="c-prose-figure c-prose-figure--video c-prose-figure--ratio-16-9" id="fig-coast-video" data-ref-type="figure">
  <div class="c-prose-figure__frame"><iframe class="c-prose-figure__embed" src="https://www.youtube.com/embed/BSQArfDLB88?si=MpNFWwXdhv5DcZ-r" title="YouTube video player" loading="lazy" referrerpolicy="strict-origin-when-cross-origin" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      The southern coast in motion — surf retreating across black volcanic sand at Reynisfjara, Iceland.

    </figcaption>
  
</figure>

<p>Watching the motion of water on black sand reveals patterns that a camera shutter can never capture. The white surf retreats over the volcanic grains, creating fleeting, intricate networks of fluid dynamics that mimic the branch-like structures of regional river deltas seen from space. This convergence of scales—where the motion of a single wave echoes the geometry of a continental drainage basin—is central to the experience of the Arctic landscape. The video framework must be robust enough to handle these complex high-frequency textures without compressing them into digital artifacts.</p>

<h2 id="sonic-field-notes-the-sound-of-black-pebbles">Sonic Field Notes: The Sound of Black Pebbles</h2>

<p>Images and video capture Iceland’s visible drama, but the coast is also an acoustic landscape. At Djúpalónssandur, the ocean is not only heard as a distant roar; it becomes a close, textured rhythm. Water breaks against the shore, then recedes through black pebbles in a frothy pattern of friction, pull, and return. The sound gives the landscape a physical scale that still images cannot fully carry.</p>

<p>The audio sample in <a class="c-prose-xref c-prose-xref--cref" href="#fig-djupalonssandur-audio">fig-djupalonssandur-audio</a> demonstrates the <code class="language-plaintext highlighter-rouge">audio.html</code> include using a local Opus audio file. This keeps the media lightweight while still allowing the post to include place-based sound as part of the field-note experience.</p>

<figure class="c-prose-figure c-prose-figure--audio" id="fig-djupalonssandur-audio" data-ref-type="figure">
  <audio class="c-prose-figure__audio" controls="" preload="metadata"><source src="/eyvan/assets/audios/posts/ocean-waves-on-pebbly-beach-iceland-loop.opus" type="audio/ogg; codecs=opus" />Your browser does not support the audio element.
  </audio>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Ocean waves receding over black pebbles at Djúpalónssandur Beach, Iceland. Audio: <a href="https://freesound.org/s/830254/">Closer Ocean Waves on Pebbly Beach - Iceland (loop)</a> by NickTayloe on Freesound, licensed under <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0</a>. Format converted from the original FLAC to Opus for web playback.

    </figcaption>
  
</figure>

<p>This sonic layer changes how the surrounding images are read. The basalt columns in <a class="c-prose-xref c-prose-xref--cref" href="#fig-basalt">fig-basalt</a> become less static when paired with the repeated movement of water across stone. The landscape is no longer only a composition of cliffs, sand, ice, and light; it becomes a timed event, shaped by impact, retreat, and recurrence.</p>

<h2 id="testing-proportions-and-spatial-dynamics">Testing Proportions and Spatial Dynamics</h2>

<p>Reusable media components prove their value when they preserve a coherent visual rhythm across different providers and screen sizes. After the YouTube embed above establishes the template’s handling of a wide coastal horizon, the Vimeo capture in <a class="c-prose-xref c-prose-xref--cref" href="#fig-canyon-video">fig-canyon-video</a> demonstrates that the same <code class="language-plaintext highlighter-rouge">video.html</code> include can embed a second platform while maintaining the same 16:9 structure, caption treatment, and responsive figure spacing.</p>

<figure class="c-prose-figure c-prose-figure--video c-prose-figure--ratio-16-9" id="fig-canyon-video" data-ref-type="figure">
  <div class="c-prose-figure__frame"><iframe class="c-prose-figure__embed" src="https://player.vimeo.com/video/715601839?h=889d734493" title="White waves receding across black sand along the Icelandic shoreline" loading="lazy" referrerpolicy="strict-origin-when-cross-origin" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen=""></iframe></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      A top-down shoreline study: white waves thinning across Iceland’s black sand in a high-contrast coastal frame.

    </figcaption>
  
</figure>

<p>In this footage, the emphasis remains on motion and contrast rather than on geological depth. From a top-down vantage, the viewer watches white surf dissolve into thin retreating lines across volcanic black sand, turning the shoreline into a study in texture, repetition, and tonal opposition. The key test here is structural consistency rather than a new aspect ratio: whether this page is viewed on an ultra-wide desktop monitor or a handheld mobile device, the responsive 16:9 container keeps the Vimeo embed aligned with the surrounding typography, preserving proportional balance without introducing layout drift between providers.</p>

<h2 id="local-motion-strokkur-as-a-self-hosted-video">Local Motion: Strokkur as a Self-Hosted Video</h2>

<p>Third-party embeds are useful when a video already lives on YouTube or Vimeo, but a portfolio template should also handle local video assets. A self-hosted video is especially useful for short project clips, field recordings, animation tests, and research demos where the media belongs directly to the site archive.</p>

<p>The local video in <a class="c-prose-xref c-prose-xref--cref" href="#fig-strokkur-local-video">fig-strokkur-local-video</a> tests the self-hosted mode of the <code class="language-plaintext highlighter-rouge">video.html</code> include. Unlike the YouTube and Vimeo examples above, this file is served directly from the site’s own assets folder while preserving the same responsive 16:9 frame, caption styling, and figure numbering.</p>

<figure class="c-prose-figure c-prose-figure--video c-prose-figure--ratio-16-9" id="fig-strokkur-local-video" data-ref-type="figure">
  <div class="c-prose-figure__frame"><video class="c-prose-figure__video" controls="" preload="metadata" poster="/eyvan/assets/images/posts/geysir-iceland-2023-erupting-geyser-strokkur.webp"><source src="/eyvan/assets/videos/posts/geysir-iceland-2023-erupting-geyser-strokkur.webm" type="video/webm" />Your browser does not support the video element.
      </video></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Strokkur erupting in the Geysir geothermal area, Iceland. Source video: <a href="https://www.vecteezy.com/video/23212018-geysir-iceland-2023-erupting-geyser-strokkur-strokkur-is-part-of-geothermal-area">Geysir, Iceland, 2023 - Erupting geyser Strokkur</a> by EvaL MiKo on Vecteezy, free video with attribution required. Converted from the original h264 source to WebM VP9 with Opus audio for lightweight GitHub Pages delivery.

    </figcaption>
  
</figure>

<p>This test is intentionally different from the embedded videos above. The browser now renders a native <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> element with local playback controls, a poster frame, metadata preloading, and fallback text. That makes it a useful check for whether the template handles self-hosted media with the same visual rhythm as externally embedded video.</p>

<h2 id="the-triptych-elements-in-sequence">The Triptych: Elements in Sequence</h2>

<p>When compiling field notes, individual frames often gain meaning when placed in immediate sequence with others. A single photo of a landscape can feel isolated; a triptych, however, creates a visual sentence, encouraging the eye to scan from left to right, parsing relationships, shifts in light, and thematic connections. The three-column gallery in <a class="c-prose-xref c-prose-xref--cref" href="#fig-triptych">fig-triptych</a> demonstrates our template’s capacity to handle dense spatial clusters, maintaining clean, uniform margins between independent visual assets.</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-3" id="fig-triptych" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/frozen-volcanic-ash.webp" alt="Close-up of frozen volcanic ash formations resembling black sand structures" loading="lazy" width="700" height="394" /><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/church-at-buoirdwarfed.webp" alt="A single solitary wooden church standing against a vast mountain backdrop" loading="lazy" width="700" height="525" /><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/aurora-borealis.webp" alt="The glowing green curtains of the Aurora Borealis arching over a dark sea" loading="lazy" width="700" height="500" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Three scales of the Icelandic experience: the micro-texture of black volcanic sand, the lone timber church at Búðir dwarfed by ancient volcanic masonry, and the macro-scale aurora lighting the sub-arctic sky. The left image adapted from <a href="https://imaggeo.egu.eu/view/12544/">Imaggeo</a> by Simon Thivet (Feb. 18, 2014), licensed under Creative Commons CC BY 3.0., the middle image from <a href="https://www.pexels.com/photo/wooden-church-on-a-steppe-21700769/">Pexels</a> by Bogdan Giurca (Oct. 28, 2023), used under the Pexels License, and the right image adapted from <a href="https://commons.wikimedia.org/wiki/File:Aurora_Borealis_activity_on_top_of_the_Kirkjufell_mountain_in_September_2018.jpg">Wikimedia Commons</a> by Vaidyanathan and Archana (Sep. 15, 2018), licensed under Creative Commons CC BY-SA 4.0.

    </figcaption>
  
</figure>

<p>This sequence encapsulates the three distinct scales of the Icelandic experience: first, the micro-texture of the black volcanic sand beneath your boots; second, the isolated human architectural mark—a lonely timber church at Búðir—dwarfed by the ancient volcanic masonry behind it; and finally, the macro-scale of the cosmos, where the earth’s magnetic shield interacts with solar winds, lighting up the sub-arctic sky in brilliant green curtains of aurora. By aligning these frames in parallel, the template mirrors the cognitive process of exploration, shifting fluidly between the intimate, the cultural, and the universal.</p>

<h2 id="field-summary">Field Summary</h2>

<p>A condensed log of the formats tested across the three-week expedition is given in <a class="c-prose-xref c-prose-xref--cref" href="#tbl-formats">tbl-formats</a>.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-formats" data-ref-type="table">
    Media formats stress-tested in this post, with their aspect ratios and narrative role.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Media tool</th>
      <th style="text-align: left">Example</th>
      <th style="text-align: left">Aspect ratio / layout</th>
      <th style="text-align: left">Narrative role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">figure.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-basalt">fig-basalt</a></td>
      <td style="text-align: left">Single image</td>
      <td style="text-align: left">Isolated geological detail</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">figure.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-fire-ice">fig-fire-ice</a></td>
      <td style="text-align: left">2-column grid</td>
      <td style="text-align: left">Direct visual comparison</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">video.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-coast-video">fig-coast-video</a></td>
      <td style="text-align: left">16:9 YouTube embed</td>
      <td style="text-align: left">Expansive coastal horizons</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">video.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-canyon-video">fig-canyon-video</a></td>
      <td style="text-align: left">16:9 Vimeo embed</td>
      <td style="text-align: left">Provider parity and responsive depth</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">video.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-strokkur-local-video">fig-strokkur-local-video</a></td>
      <td style="text-align: left">16:9 local WebM video with poster</td>
      <td style="text-align: left">Self-hosted playback, poster frame, native controls, and local asset delivery</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">audio.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-djupalonssandur-audio">fig-djupalonssandur-audio</a></td>
      <td style="text-align: left">Local Opus audio file</td>
      <td style="text-align: left">Ambient field recording and place-based sound</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">figure.html</code></td>
      <td style="text-align: left"><a class="c-prose-xref" href="#fig-triptych">fig-triptych</a></td>
      <td style="text-align: left">3-column grid</td>
      <td style="text-align: left">Sequential scale shifts</td>
    </tr>
  </tbody>
</table>

<h2 id="epilogue-the-transience-of-stone">Epilogue: The Transience of Stone</h2>

<p>As the final light fades from the Reykjanes peninsula, the horizon dissolves into a continuous gradient of deep indigo and soft violet. It is easy to look at Iceland and see a wilderness that is brutal, cold, and utterly indifferent to human presence. Yet, there is a profound quietness that settles over these fields once the wind dies down. The stones, cold to the touch, still hold the abstract memory of the earth’s core. They remind us that our human structures, our personal timelines, and our technological frameworks are fleeting anomalies on a planet that measures its age in epochs and cycles of ash. Documenting this landscape is an exercise in humility; we do not capture the land, we merely record our brief passage across its surface.</p>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="travel" /><category term="photography" /><category term="video" /><category term="visual" /><summary type="html"><![CDATA[A visual journey through Iceland — images, video, and prose working together.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/iceland-hero.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/iceland-hero.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Building a Token-Bucket Rate Limiter</title><link href="https://amirhs1.github.io/eyvan/projects/building-a-rate-limiter/" rel="alternate" type="text/html" title="Building a Token-Bucket Rate Limiter" /><published>2026-02-14T00:00:00+00:00</published><updated>2026-02-14T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/building-a-rate-limiter</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/building-a-rate-limiter/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools for the sole purpose of demonstrating the rich typographic, mathematical, code, figure, and table capabilities of the Eyvan template.</p>
</blockquote>

<p>Rate limiting is a foundational part of modern systems design. Whether you are running a public API, managing internal services, or protecting a database from cascading failures, controlling the flow of requests is essential. Without rate limiting, a system can become vulnerable to malicious denial-of-service attempts, accidental overload from client scripts, resource starvation, and unexpected infrastructure costs.</p>

<p>In this walkthrough, we will unpack the mathematics and mechanics behind the <strong>token-bucket algorithm</strong>: a flexible strategy used in API gateways, networking systems, and service-protection layers. We will then build clear, runnable reference implementations in both <strong>Python</strong> and <strong>Go</strong>, discuss their trade-offs, and review what would need to change before using this pattern in a distributed production system.</p>

<h2 id="the-problem-statement-why-rate-limiting-matters">The Problem Statement: Why Rate Limiting Matters</h2>

<p>At its core, a rate limiter is a traffic control mechanism. It evaluates incoming requests against a configured policy and decides whether to forward them to the downstream application or reject them, commonly with the HTTP status code <code class="language-plaintext highlighter-rouge">429 Too Many Requests</code>.</p>

<p>Without robust rate limiting, web applications face several practical risks:</p>

<ol>
  <li><strong>Resource starvation:</strong> A poorly optimized loop from a client script can saturate database connections, exhaust CPU cycles, or consume worker threads, degrading the service for other users.</li>
  <li><strong>Denial of service:</strong> Malicious actors can flood expensive endpoints, such as search, authentication, file processing, or cryptographic operations, to overload application nodes.</li>
  <li><strong>Cost control:</strong> In cloud environments, unthrottled traffic does not just risk downtime; it can also increase infrastructure, logging, queueing, and third-party API costs.</li>
</ol>

<p>The engineering challenge is to enforce these limits with minimal latency overhead. Every request must pass through the rate limiter before reaching the application logic, so the limiter should perform only a small amount of work per request.</p>

<h2 id="the-token-bucket-algorithm-explained">The Token-Bucket Algorithm Explained</h2>

<p>The token-bucket algorithm relies on a simple metaphor: a bucket with a fixed capacity that stores tokens.</p>

<h3 id="core-mechanics">Core Mechanics</h3>

<ol>
  <li><strong>The bucket:</strong> The bucket holds up to a maximum of $B$ tokens. It commonly starts full.</li>
  <li><strong>The refill:</strong> Tokens are added to the bucket at a constant refill rate of $R$ tokens per second. If the bucket is already full, extra tokens are discarded.</li>
  <li><strong>The consumption:</strong> When a request arrives, the system tries to consume a required number of tokens, usually one token per request.</li>
  <li><strong>The decision:</strong> If enough tokens are available, the request is allowed and the tokens are subtracted. If not, the request is rejected immediately.</li>
</ol>

<p>The key benefit of token bucket is that it allows <strong>controlled bursts</strong>. A client can briefly send requests faster than the refill rate, as long as it has accumulated enough tokens. Over time, however, the average request rate is still constrained by the refill rate.</p>

<h3 id="architectural-diagram">Architectural Diagram</h3>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-1" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/token-bucket-diagram.webp" alt="Token Bucket System Design Diagram" loading="lazy" width="1200" height="670" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Visual breakdown of the high-level token-bucket system architecture, illustrating request flow, token consumption, and refill mechanics. The diagram was generated with AI tools for illustrative purposes by the author using the contents of this post as the generation prompt.

    </figcaption>
  
</figure>

<h3 id="naive-vs-lazy-refills">Naive vs. Lazy Refills</h3>

<p>A naive approach might run a background timer that increments tokens every second. That can work for a small number of buckets, but it scales poorly when managing many users, API keys, IP addresses, or tenants. Maintaining active timers for millions of independent buckets would waste memory and CPU.</p>

<p>Production-oriented systems usually prefer a <strong>lazy refill strategy</strong>. Instead of updating each bucket on a timer, the bucket calculates its current token count only when a request arrives.</p>

<p>By storing the timestamp of the last update, $T_{last}$, the limiter can compute the elapsed time:</p>

\[\Delta T = T_{current} - T_{last}\]

<p>Then it can compute the new token balance:</p>

\[\text{Tokens}_{new} = \min(B, \text{Tokens}_{old} + \Delta T \times R)\]

<p>This turns the refill step into a small amount of arithmetic performed inline with the request lifecycle.</p>

<h2 id="python-implementation">Python Implementation</h2>

<p>Below is a complete, runnable Python implementation using <code class="language-plaintext highlighter-rouge">threading.Lock</code>.</p>

<p>This version is thread-safe within a single Python process. That means it can safely protect its in-memory bucket map when multiple threads access the same limiter instance. However, it does <strong>not</strong> coordinate limits across multiple worker processes, containers, or servers. For that, the bucket state usually needs to move into a shared external store such as Redis.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">threading</span>
<span class="kn">import</span> <span class="n">time</span>
<span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Tuple</span>


<span class="k">class</span> <span class="nc">TokenBucketRateLimiter</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">
    A thread-safe, in-memory token-bucket rate limiter using lazy refills.

    This implementation is intended as a clear reference example. It is safe
    within a single Python process, but it is not distributed across multiple
    processes or servers.
    </span><span class="sh">"""</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">capacity</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">refill_rate</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">capacity</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">capacity must be positive</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">refill_rate</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">refill_rate must be positive</span><span class="sh">"</span><span class="p">)</span>

        <span class="n">self</span><span class="p">.</span><span class="n">capacity</span> <span class="o">=</span> <span class="nf">float</span><span class="p">(</span><span class="n">capacity</span><span class="p">)</span>
        <span class="n">self</span><span class="p">.</span><span class="n">refill_rate</span> <span class="o">=</span> <span class="nf">float</span><span class="p">(</span><span class="n">refill_rate</span><span class="p">)</span>

        <span class="c1"># In-memory storage:
</span>        <span class="c1"># key -&gt; (current token count, last updated monotonic timestamp)
</span>        <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="n">self</span><span class="p">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">threading</span><span class="p">.</span><span class="nc">Lock</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">_refill</span><span class="p">(</span>
        <span class="n">self</span><span class="p">,</span>
        <span class="n">current_tokens</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
        <span class="n">last_update</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span>
        <span class="n">now</span><span class="p">:</span> <span class="nb">float</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
        <span class="n">elapsed</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">last_update</span>
        <span class="n">refilled_tokens</span> <span class="o">=</span> <span class="n">current_tokens</span> <span class="o">+</span> <span class="p">(</span><span class="n">elapsed</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">refill_rate</span><span class="p">)</span>
        <span class="k">return</span> <span class="nf">min</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">capacity</span><span class="p">,</span> <span class="n">refilled_tokens</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">allow_request</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">tokens_requested</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">tokens_requested</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">tokens_requested must be positive</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">tokens_requested</span> <span class="o">&gt;</span> <span class="n">self</span><span class="p">.</span><span class="n">capacity</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">False</span>

        <span class="c1"># Use a monotonic clock for elapsed-time calculations.
</span>        <span class="c1"># Unlike time.time(), time.monotonic() is not affected by system clock changes.
</span>        <span class="n">now</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="nf">monotonic</span><span class="p">()</span>

        <span class="k">with</span> <span class="n">self</span><span class="p">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">:</span>
                <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">capacity</span><span class="p">,</span> <span class="n">now</span><span class="p">)</span>

            <span class="n">current_tokens</span><span class="p">,</span> <span class="n">last_update</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
            <span class="n">updated_tokens</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">_refill</span><span class="p">(</span><span class="n">current_tokens</span><span class="p">,</span> <span class="n">last_update</span><span class="p">,</span> <span class="n">now</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">updated_tokens</span> <span class="o">&gt;=</span> <span class="n">tokens_requested</span><span class="p">:</span>
                <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">updated_tokens</span> <span class="o">-</span> <span class="n">tokens_requested</span><span class="p">,</span> <span class="n">now</span><span class="p">)</span>
                <span class="k">return</span> <span class="bp">True</span>

            <span class="c1"># Store the refilled balance even when the request is rejected.
</span>            <span class="n">self</span><span class="p">.</span><span class="n">buckets</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">updated_tokens</span><span class="p">,</span> <span class="n">now</span><span class="p">)</span>
            <span class="k">return</span> <span class="bp">False</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="c1"># Capacity of 5 tokens, refilling at 2 tokens per second.
</span>    <span class="n">limiter</span> <span class="o">=</span> <span class="nc">TokenBucketRateLimiter</span><span class="p">(</span><span class="n">capacity</span><span class="o">=</span><span class="mf">5.0</span><span class="p">,</span> <span class="n">refill_rate</span><span class="o">=</span><span class="mf">2.0</span><span class="p">)</span>
    <span class="n">user_id</span> <span class="o">=</span> <span class="sh">"</span><span class="s">user_908a</span><span class="sh">"</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">--- Bursting Initial Capacity ---</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">8</span><span class="p">):</span>
        <span class="n">allowed</span> <span class="o">=</span> <span class="n">limiter</span><span class="p">.</span><span class="nf">allow_request</span><span class="p">(</span><span class="n">user_id</span><span class="p">)</span>
        <span class="n">status</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ALLOWED</span><span class="sh">"</span> <span class="k">if</span> <span class="n">allowed</span> <span class="k">else</span> <span class="sh">"</span><span class="s">REJECTED (429)</span><span class="sh">"</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Request </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="se">\n</span><span class="s">--- Waiting 1.5 Seconds for Refill ---</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">):</span>
        <span class="n">allowed</span> <span class="o">=</span> <span class="n">limiter</span><span class="p">.</span><span class="nf">allow_request</span><span class="p">(</span><span class="n">user_id</span><span class="p">)</span>
        <span class="n">status</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ALLOWED</span><span class="sh">"</span> <span class="k">if</span> <span class="n">allowed</span> <span class="k">else</span> <span class="sh">"</span><span class="s">REJECTED (429)</span><span class="sh">"</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Subsequent Request </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<p>This implementation favors clarity over maximum throughput. The single global lock makes the dictionary safe, but it also means requests for unrelated users still serialize through the same lock. For a high-throughput in-memory implementation, one improvement would be <strong>lock striping</strong>, where keys are partitioned across multiple locks.</p>

<h2 id="go-implementation">Go Implementation</h2>

<p>Go is well suited for highly concurrent services. In the implementation below, a limiter-level <code class="language-plaintext highlighter-rouge">sync.RWMutex</code> protects the shared client map, while each bucket has its own <code class="language-plaintext highlighter-rouge">sync.Mutex</code> for token updates. This means bucket creation still uses a shared map lock, but normal request evaluation for existing buckets localizes contention to the specific client bucket.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"fmt"</span>
	<span class="s">"math"</span>
	<span class="s">"sync"</span>
	<span class="s">"time"</span>
<span class="p">)</span>

<span class="c">// Bucket represents an individual client's token state.</span>
<span class="k">type</span> <span class="n">Bucket</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">tokens</span>     <span class="kt">float64</span>
	<span class="n">lastUpdate</span> <span class="n">time</span><span class="o">.</span><span class="n">Time</span>
	<span class="n">mu</span>         <span class="n">sync</span><span class="o">.</span><span class="n">Mutex</span>
<span class="p">}</span>

<span class="c">// TokenBucketLimiter manages multiple client buckets safely.</span>
<span class="k">type</span> <span class="n">TokenBucketLimiter</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">sync</span><span class="o">.</span><span class="n">RWMutex</span>
	<span class="n">capacity</span>   <span class="kt">float64</span>
	<span class="n">refillRate</span> <span class="kt">float64</span>
	<span class="n">clients</span>    <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="n">Bucket</span>
<span class="p">}</span>

<span class="c">// NewTokenBucketLimiter creates a new token-bucket limiter.</span>
<span class="k">func</span> <span class="n">NewTokenBucketLimiter</span><span class="p">(</span><span class="n">capacity</span><span class="p">,</span> <span class="n">refillRate</span> <span class="kt">float64</span><span class="p">)</span> <span class="p">(</span><span class="o">*</span><span class="n">TokenBucketLimiter</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">capacity</span> <span class="o">&lt;=</span> <span class="m">0</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"capacity must be positive"</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">if</span> <span class="n">refillRate</span> <span class="o">&lt;=</span> <span class="m">0</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"refillRate must be positive"</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="o">&amp;</span><span class="n">TokenBucketLimiter</span><span class="p">{</span>
		<span class="n">capacity</span><span class="o">:</span>   <span class="n">capacity</span><span class="p">,</span>
		<span class="n">refillRate</span><span class="o">:</span> <span class="n">refillRate</span><span class="p">,</span>
		<span class="n">clients</span><span class="o">:</span>    <span class="nb">make</span><span class="p">(</span><span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="o">*</span><span class="n">Bucket</span><span class="p">),</span>
	<span class="p">},</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="c">// getBucket retrieves or creates a client bucket safely.</span>
<span class="k">func</span> <span class="p">(</span><span class="n">tbl</span> <span class="o">*</span><span class="n">TokenBucketLimiter</span><span class="p">)</span> <span class="n">getBucket</span><span class="p">(</span><span class="n">key</span> <span class="kt">string</span><span class="p">)</span> <span class="o">*</span><span class="n">Bucket</span> <span class="p">{</span>
	<span class="n">tbl</span><span class="o">.</span><span class="n">RLock</span><span class="p">()</span>
	<span class="n">bucket</span><span class="p">,</span> <span class="n">exists</span> <span class="o">:=</span> <span class="n">tbl</span><span class="o">.</span><span class="n">clients</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
	<span class="n">tbl</span><span class="o">.</span><span class="n">RUnlock</span><span class="p">()</span>

	<span class="k">if</span> <span class="n">exists</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">bucket</span>
	<span class="p">}</span>

	<span class="n">tbl</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
	<span class="k">defer</span> <span class="n">tbl</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>

	<span class="c">// Double-check to avoid creating duplicate buckets if another goroutine</span>
	<span class="c">// inserted the same key while this goroutine was waiting for the write lock.</span>
	<span class="k">if</span> <span class="n">bucket</span><span class="p">,</span> <span class="n">exists</span> <span class="o">=</span> <span class="n">tbl</span><span class="o">.</span><span class="n">clients</span><span class="p">[</span><span class="n">key</span><span class="p">];</span> <span class="o">!</span><span class="n">exists</span> <span class="p">{</span>
		<span class="n">bucket</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">Bucket</span><span class="p">{</span>
			<span class="n">tokens</span><span class="o">:</span>     <span class="n">tbl</span><span class="o">.</span><span class="n">capacity</span><span class="p">,</span>
			<span class="n">lastUpdate</span><span class="o">:</span> <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">(),</span>
		<span class="p">}</span>
		<span class="n">tbl</span><span class="o">.</span><span class="n">clients</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">bucket</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="n">bucket</span>
<span class="p">}</span>

<span class="c">// AllowRequest checks whether a specific client can consume tokens.</span>
<span class="k">func</span> <span class="p">(</span><span class="n">tbl</span> <span class="o">*</span><span class="n">TokenBucketLimiter</span><span class="p">)</span> <span class="n">AllowRequest</span><span class="p">(</span><span class="n">key</span> <span class="kt">string</span><span class="p">,</span> <span class="n">tokensRequested</span> <span class="kt">float64</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">tokensRequested</span> <span class="o">&lt;=</span> <span class="m">0</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">false</span>
	<span class="p">}</span>
	<span class="k">if</span> <span class="n">tokensRequested</span> <span class="o">&gt;</span> <span class="n">tbl</span><span class="o">.</span><span class="n">capacity</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">false</span>
	<span class="p">}</span>

	<span class="n">bucket</span> <span class="o">:=</span> <span class="n">tbl</span><span class="o">.</span><span class="n">getBucket</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>

	<span class="n">bucket</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
	<span class="k">defer</span> <span class="n">bucket</span><span class="o">.</span><span class="n">mu</span><span class="o">.</span><span class="n">Unlock</span><span class="p">()</span>

	<span class="n">now</span> <span class="o">:=</span> <span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span>
	<span class="n">elapsed</span> <span class="o">:=</span> <span class="n">now</span><span class="o">.</span><span class="n">Sub</span><span class="p">(</span><span class="n">bucket</span><span class="o">.</span><span class="n">lastUpdate</span><span class="p">)</span><span class="o">.</span><span class="n">Seconds</span><span class="p">()</span>

	<span class="n">bucket</span><span class="o">.</span><span class="n">tokens</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">Min</span><span class="p">(</span>
		<span class="n">tbl</span><span class="o">.</span><span class="n">capacity</span><span class="p">,</span>
		<span class="n">bucket</span><span class="o">.</span><span class="n">tokens</span><span class="o">+</span><span class="p">(</span><span class="n">elapsed</span><span class="o">*</span><span class="n">tbl</span><span class="o">.</span><span class="n">refillRate</span><span class="p">),</span>
	<span class="p">)</span>
	<span class="n">bucket</span><span class="o">.</span><span class="n">lastUpdate</span> <span class="o">=</span> <span class="n">now</span>

	<span class="k">if</span> <span class="n">bucket</span><span class="o">.</span><span class="n">tokens</span> <span class="o">&gt;=</span> <span class="n">tokensRequested</span> <span class="p">{</span>
		<span class="n">bucket</span><span class="o">.</span><span class="n">tokens</span> <span class="o">-=</span> <span class="n">tokensRequested</span>
		<span class="k">return</span> <span class="no">true</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="no">false</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="c">// Capacity: 5 tokens. Refill rate: 2 tokens per second.</span>
	<span class="n">limiter</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">NewTokenBucketLimiter</span><span class="p">(</span><span class="m">5.0</span><span class="p">,</span> <span class="m">2.0</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="nb">panic</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">clientID</span> <span class="o">:=</span> <span class="s">"client_441b"</span>

	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"--- Bursting Initial Capacity ---"</span><span class="p">)</span>
	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="m">7</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">allowed</span> <span class="o">:=</span> <span class="n">limiter</span><span class="o">.</span><span class="n">AllowRequest</span><span class="p">(</span><span class="n">clientID</span><span class="p">,</span> <span class="m">1.0</span><span class="p">)</span>

		<span class="n">status</span> <span class="o">:=</span> <span class="s">"REJECTED (429)"</span>
		<span class="k">if</span> <span class="n">allowed</span> <span class="p">{</span>
			<span class="n">status</span> <span class="o">=</span> <span class="s">"ALLOWED"</span>
		<span class="p">}</span>

		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Request %d: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">--- Waiting 1.5 Seconds for Refill ---"</span><span class="p">)</span>
	<span class="n">time</span><span class="o">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">1500</span> <span class="o">*</span> <span class="n">time</span><span class="o">.</span><span class="n">Millisecond</span><span class="p">)</span>

	<span class="k">for</span> <span class="n">i</span> <span class="o">:=</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="m">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
		<span class="n">allowed</span> <span class="o">:=</span> <span class="n">limiter</span><span class="o">.</span><span class="n">AllowRequest</span><span class="p">(</span><span class="n">clientID</span><span class="p">,</span> <span class="m">1.0</span><span class="p">)</span>

		<span class="n">status</span> <span class="o">:=</span> <span class="s">"REJECTED (429)"</span>
		<span class="k">if</span> <span class="n">allowed</span> <span class="p">{</span>
			<span class="n">status</span> <span class="o">=</span> <span class="s">"ALLOWED"</span>
		<span class="p">}</span>

		<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Subsequent Request %d: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The Go version has better concurrency behavior than the simple Python version because requests for different existing clients do not all contend on a single global lock. However, it is still an in-memory implementation. If a service runs across multiple machines, each instance would maintain its own independent bucket state unless the limiter is backed by a shared data store.</p>

<h2 id="illustrative-benchmark-results">Illustrative Benchmark Results</h2>

<p>Benchmarks for rate limiters are sensitive to the benchmark harness, CPU, language runtime, lock contention pattern, and key distribution. A test where every request targets the same key measures hot-key lock contention. A test where requests are spread across many keys measures map access, bucket lookup, and per-key parallelism differently.</p>

<p>The table below shows an illustrative benchmark profile across $1{,}000{,}000$ request evaluations on a single machine. These numbers should be treated as demonstration data, not as universal performance claims.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>======================================================================
ILLUSTRATIVE BENCHMARK RUN: Python 3.11 vs Go 1.21
OS: Linux x86_64 | CPU: AMD Ryzen 7 5800X (8 cores, 16 threads)
======================================================================

Scenario:
- 1,000,000 token-bucket evaluations
- In-memory state
- One token requested per operation
- Buckets already initialized
- No network or external datastore calls

Type             Total Ops    Total Time    Mean Latency / Op
----------------------------------------------------------------------
Python (Lock)    1,000,000    1.442 sec     1.442 μs
Go (Mutex)       1,000,000    0.084 sec     0.084 μs

Detailed Latency Percentiles:
----------------------------------------------------------------------
Metric           P50 (Median)     P95              P99
Python           1.25 μs          2.10 μs          4.80 μs
Go               0.06 μs          0.14 μs          0.31 μs

Interpretation:
Go is expected to outperform Python for this kind of tight, lock-heavy,
CPU-local loop because of compiled execution, lower runtime overhead,
and cheaper synchronization primitives. The exact ratio should not be
generalized without measuring your own workload.
</code></pre></div></div>

<p>The key lesson is not that one language is always better than another. The more important point is that the cost of the rate limiter should remain small compared with the work it protects. If the limiter requires a network call to Redis, for example, the external round trip will usually dominate the cost of the local arithmetic.</p>

<h2 id="complexity-analysis">Complexity Analysis</h2>

<p>The implementation’s request-time footprint remains small because of the lazy-refill strategy described earlier.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-token-bucket-complexity" data-ref-type="table">
    Complexity profile for token-bucket request evaluation and memory growth.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Operation / Space</th>
      <th>Time Complexity</th>
      <th>Space Complexity</th>
      <th>Architectural Profile</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Request evaluation</strong></td>
      <td>$\mathcal{O}(1)$</td>
      <td>$\mathcal{O}(1)$</td>
      <td>A fixed amount of arithmetic, timestamp comparison, and state update per request.</td>
    </tr>
    <tr>
      <td><strong>Bucket storage</strong></td>
      <td>—</td>
      <td>$\mathcal{O}(N)$</td>
      <td>Memory grows linearly with the number of unique tracked identifiers, where $N$ is the number of active clients, users, IPs, or API keys.</td>
    </tr>
  </tbody>
</table>

<p>The algorithmic complexity is attractive because each request does not require scanning history or storing every previous request. Unlike a naive log-based limiter, token bucket only needs the current token count and the last update time for each tracked key.</p>

<h2 id="edge-cases-and-gotchas">Edge Cases and Gotchas</h2>

<p>When scaling a token-bucket implementation into a larger distributed system, several important issues appear.</p>

<ol>
  <li>
    <p><strong>Distributed state synchronization:</strong> In-memory implementations are limited to one process or one server. If an application runs behind a load balancer across multiple nodes, the same user’s requests may hit different instances. This can accidentally multiply the effective limit by the number of instances. A common solution is to store bucket state in a shared low-latency datastore such as Redis and update it atomically.</p>
  </li>
  <li>
    <p><strong>Clock behavior:</strong> Lazy refill depends on elapsed time. In Python, <code class="language-plaintext highlighter-rouge">time.monotonic()</code> is safer than <code class="language-plaintext highlighter-rouge">time.time()</code> for local elapsed-time calculations because it is not affected by wall-clock adjustments. In distributed systems, clock consistency still matters when multiple machines participate in rate-limit decisions.</p>
  </li>
  <li>
    <p><strong>Lock contention:</strong> The Python implementation uses a single global lock, so requests for different users still wait behind the same mutex. For higher throughput, you can partition keys across multiple locks or use a per-key locking strategy. The Go implementation demonstrates one version of this idea by using a per-bucket mutex after the bucket has been created.</p>
  </li>
  <li>
    <p><strong>Unbounded memory growth:</strong> A limiter that stores one bucket per user, IP address, or API key needs a cleanup policy. Otherwise, old inactive keys can accumulate forever. Production systems usually add expiration, least-recently-used eviction, or datastore-level TTLs.</p>
  </li>
  <li>
    <p><strong>Atomic updates in shared stores:</strong> If bucket state is stored in Redis or another external system, the read-modify-write operation must be atomic. Otherwise, concurrent requests can observe the same token balance and both be allowed incorrectly. Redis Lua scripts or transactions are common ways to make the update atomic.</p>
  </li>
  <li>
    <p><strong>Choosing the right key:</strong> The limiter is only as good as the identifier it tracks. Limiting by IP address can be useful, but it may unfairly group users behind the same NAT or corporate proxy. Limiting by authenticated user ID or API key is often more precise.</p>
  </li>
  <li>
    <p><strong>Choosing the right response:</strong> For HTTP APIs, rejected requests commonly return <code class="language-plaintext highlighter-rouge">429 Too Many Requests</code>. It is also useful to include headers such as <code class="language-plaintext highlighter-rouge">Retry-After</code> or rate-limit metadata so clients can back off gracefully.</p>
  </li>
</ol>

<h2 id="token-bucket-vs-other-rate-limiting-strategies">Token Bucket vs. Other Rate-Limiting Strategies</h2>

<p>Token bucket is flexible, but it is not the only rate-limiting algorithm.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-rate-limiting-strategies" data-ref-type="table">
    Comparison of common rate-limiting strategies.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th>Strategy</th>
      <th>Allows Bursts?</th>
      <th>Memory Use</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Fixed window counter</strong></td>
      <td>Yes, but unevenly at boundaries</td>
      <td>Low</td>
      <td>Simple, but can allow double bursts around window edges.</td>
    </tr>
    <tr>
      <td><strong>Sliding window log</strong></td>
      <td>More precise</td>
      <td>High</td>
      <td>Stores request timestamps; accurate but memory-heavy for high traffic.</td>
    </tr>
    <tr>
      <td><strong>Sliding window counter</strong></td>
      <td>Partially</td>
      <td>Medium</td>
      <td>Smoother than fixed windows, cheaper than full logs.</td>
    </tr>
    <tr>
      <td><strong>Leaky bucket</strong></td>
      <td>Usually no</td>
      <td>Low</td>
      <td>Smooths traffic into a steady output rate.</td>
    </tr>
    <tr>
      <td><strong>Token bucket</strong></td>
      <td>Yes</td>
      <td>Low</td>
      <td>Allows controlled bursts while enforcing a long-term average rate.</td>
    </tr>
  </tbody>
</table>

<p>Token bucket is a strong default when you want to allow short bursts without losing control over the long-term request rate. For example, a user might be allowed to make 100 requests immediately after being idle, but over time still be limited to 10 requests per second.</p>

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

<p>To deepen your systems design understanding, explore these resources:</p>

<ul>
  <li><a href="https://stripe.com/blog/rate-limiters">Stripe Engineering: Scaling your API with rate limiters</a></li>
  <li><a href="https://datatracker.ietf.org/doc/html/rfc6585">RFC 6585: Additional HTTP Status Codes</a></li>
  <li><a href="https://redis.io/docs/latest/develop/programmability/eval-intro/">Redis documentation: Programmability with Lua scripting</a></li>
  <li><a href="https://pkg.go.dev/sync">Go documentation: Package sync</a></li>
  <li><a href="https://docs.python.org/3/library/time.html">Python documentation: time — Time access and conversions</a></li>
</ul>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="coding" /><category term="python" /><category term="go" /><category term="systems" /><category term="algorithms" /><summary type="html"><![CDATA[A hands-on walkthrough of implementing a token-bucket rate limiter with code in Python and Go.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/token-bucket-diagram.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/token-bucket-diagram.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Quantum Entanglement: A Primer</title><link href="https://amirhs1.github.io/eyvan/projects/quantum-entanglement-primer/" rel="alternate" type="text/html" title="Quantum Entanglement: A Primer" /><published>2026-02-01T00:00:00+00:00</published><updated>2026-02-01T00:00:00+00:00</updated><id>https://amirhs1.github.io/eyvan/projects/quantum-entanglement-primer</id><content type="html" xml:base="https://amirhs1.github.io/eyvan/projects/quantum-entanglement-primer/"><![CDATA[<blockquote>
  <p><strong>Note:</strong> This post was generated with AI tools for the sole purpose of demonstrating the rich typographic and mathematical capabilities of the Eyvan template.</p>
</blockquote>

<p>Quantum entanglement represents one of the most important departures of quantum mechanics from the classical worldview. It changes how we think about physical reality, locality, measurement, and information. First brought into sharp focus by Einstein, Podolsky, and Rosen (EPR) in 1935 as part of an argument about the incompleteness of quantum theory, entanglement describes a non-separable state of a composite system: the whole system has a well-defined quantum state, but its parts cannot always be assigned independent pure states.</p>

<p>Decades later, John Stewart Bell transformed the EPR debate from a philosophical question into an experimentally testable one. Bell showed that any theory satisfying local realism must obey statistical constraints known as Bell inequalities. Quantum mechanics predicts that entangled systems can violate those constraints. Later experiments confirmed these violations, making entanglement not merely a conceptual puzzle but a practical resource for quantum computation, quantum cryptography, quantum communication, and quantum metrology.</p>

<p>This primer introduces the basic formalism of bipartite entanglement, the density matrix description of local subsystems, the CHSH form of Bell’s inequality, and the experimental logic behind modern Bell tests.</p>

<h2 id="historical-context-and-non-separability">Historical Context and Non-Separability</h2>

<p>The intellectual origin of entanglement is closely tied to the EPR paradox. EPR argued that if local realism were true, quantum mechanics must be incomplete. Here, <em>realism</em> means that physical systems possess definite properties independent of measurement, while <em>locality</em> means that actions performed at one location cannot instantly affect a distant physical system.</p>

<p>EPR used a highly correlated bipartite state to argue that distant measurements seemed to reveal pre-existing “elements of reality.” Shortly afterward, Erwin Schrödinger recognized the deeper implication of the wave function and introduced the term <em>Verschränkung</em>, or entanglement, for situations in which the state of the whole cannot be reduced to independent states of the parts.</p>

<p>Mathematically, consider a composite Hilbert space</p>

\[\mathcal{H} = \mathcal{H}_A \otimes \mathcal{H}_B,\]

<p>where subsystem $A$ is held by Alice and subsystem $B$ is held by Bob. A pure state $\ket{\psi} \in \mathcal{H}$ is called <em>separable</em> if it can be written as a tensor product of two subsystem states:</p>

\[\ket{\psi} = \ket{\phi}_A \otimes \ket{\chi}_B.\]

<p>A state is <em>entangled</em> if it cannot be written in this product form.</p>

<p>A standard example of a maximally entangled two-qubit state is the Bell state</p>

\[\ket{\Phi^+} = \frac{1}{\sqrt{2}}(\ket{00} + \ket{11}).\]

<p>Another important Bell state is the singlet state,</p>

\[\ket{\Psi^-} = \frac{1}{\sqrt{2}}(\ket{01} - \ket{10}),\]

<p>which is especially useful in spin and polarization discussions because its correlations are rotationally invariant. Both states are maximally entangled, but their correlation functions differ by signs and basis conventions. Keeping these states distinct is important when deriving Bell-inequality violations.</p>

<h2 id="visualizing-entanglement-vs-classical-correlation">Visualizing Entanglement vs. Classical Correlation</h2>

<p>A helpful way to understand the difference between entanglement and classical correlation is to compare how each behaves under changes of measurement basis. Photon polarization experiments are especially useful for this purpose.</p>

<figure class="c-prose-figure c-prose-figure--image c-prose-figure--cols-1" id="fig-entanglement-classical-correlation" data-ref-type="figure">
  <div class="c-prose-figure__grid"><img class="c-prose-figure__asset" src="/eyvan/assets/images/posts/quantum_entanglement_vs_classical_correlation_video.webp" alt="Animated comparison of entangled photon polarization measurements and classically correlated measurements" loading="lazy" width="787" height="382" /></div>

  
    <figcaption class="c-prose-caption c-prose-figure__caption c-prose-caption--figure">
      Side-by-side simulation demonstrating the operational difference between a maximally entangled singlet state and a dephased, classically correlated mixed state. Source: <a href="https://commons.wikimedia.org/wiki/File:Quantum_entanglement_vs_classical_correlation_video.gif">Wikimedia Commons</a>, creator JozumBjada, November 27, 2020, licensed under Creative Commons CC BY-SA 4.0.

    </figcaption>
  
</figure>

<p>The visualization compares two situations:</p>

<ul>
  <li><strong>Entangled pair:</strong> the photons are described by a coherent joint quantum state.</li>
  <li><strong>Classically correlated pair:</strong> the photons are correlated in the horizontal/vertical basis, but the quantum coherence between alternatives has been removed.</li>
</ul>

<p>In both scenes, a central source emits photon pairs. One photon travels to Alice’s measurement station and the other travels to Bob’s. Each station contains a polarization analyzer and detectors. When both analyzers measure in the same horizontal/vertical basis, the entangled state and the classically correlated mixed state can produce similar-looking statistics. This is why a single measurement basis is not enough to demonstrate entanglement.</p>

<p>The difference appears when the measurement bases are rotated. For the singlet state, the correlations depend only on the relative angle between Alice’s and Bob’s measurement bases, not on their shared absolute orientation. By contrast, the dephased classically correlated state retains a preferred horizontal/vertical basis, so its statistics change under common rotations of the analyzers.</p>

<p>This is one of the key operational differences between quantum entanglement and classical correlation: entanglement is not simply “very strong correlation.” It is correlation carried by a coherent joint state that cannot be represented as a classical mixture of independent local properties.</p>

<h2 id="the-density-matrix-formalism">The Density Matrix Formalism</h2>

<p>State vectors are sufficient for describing isolated pure states, but they are not enough when we want to describe mixed states or local subsystems of an entangled pair. For that, we use the density matrix formalism.</p>

<p>For a pure state $\ket{\psi}$, the global density operator is</p>

\[\rho = \ket{\psi}\bra{\psi}.\]

<p>To determine the state accessible to Alice alone, we trace over Bob’s subsystem. This operation is called the partial trace:</p>

\[\rho_A = \operatorname{Tr}_B(\rho)
= \sum_i
(\mathbb{I}_A \otimes \bra{i}_B)
\rho
(\mathbb{I}_A \otimes \ket{i}_B).\]

<p>Apply this to the Bell state</p>

\[\ket{\Phi^+} = \frac{1}{\sqrt{2}}(\ket{00} + \ket{11}).\]

<p>The global density matrix is</p>

\[\rho =
\ket{\Phi^+}\bra{\Phi^+}
=
\frac{1}{2}
\Big(
\ket{00}\bra{00}
+
\ket{00}\bra{11}
+
\ket{11}\bra{00}
+
\ket{11}\bra{11}
\Big).\]

<p>Taking the partial trace over Bob’s qubit gives Alice’s reduced density matrix:</p>

\[\rho_A
=
\operatorname{Tr}_B(\rho)
=
\frac{1}{2}
\Big(
\ket{0}\bra{0}
+
\ket{1}\bra{1}
\Big)
=
\frac{1}{2}\mathbb{I}_A.\]

<p>This result is important. The global state $\rho$ is pure, with zero von Neumann entropy,</p>

\[S(\rho) = -\operatorname{Tr}(\rho \log \rho) = 0.\]

<p>But Alice’s local state is maximally mixed:</p>

\[S(\rho_A) = \log 2.\]

<p>Alice sees locally random outcomes, even though the two-qubit system as a whole is in a pure coherent state. This contrast between global purity and local mixedness is one of the formal signatures of entanglement.</p>

<h2 id="bells-theorem-and-the-chsh-inequality">Bell’s Theorem and the CHSH Inequality</h2>

<p>For nearly three decades after EPR, the debate about locality and realism remained largely conceptual. Bell changed this in 1964 by showing that local hidden-variable theories obey experimentally testable constraints. These constraints are now called Bell inequalities.</p>

<p>The most commonly discussed version is the Clauser-Horne-Shimony-Holt, or CHSH, inequality.</p>

<p>Suppose Alice can choose between two dichotomic observables, $A$ and $A’$, each producing outcomes in ${+1, -1}$. Bob can choose between two observables, $B$ and $B’$, also producing outcomes in ${+1, -1}$. Let $E(A,B)$ be the expectation value of the product of Alice’s and Bob’s outcomes for a given pair of settings.</p>

<p>Under local realism, the CHSH expression must satisfy</p>

\[\left|
E(A,B)
+
E(A,B')
+
E(A',B)
-
E(A',B')
\right|
\leq 2.\]

<p>The upper bound of $2$ is not a limitation of a particular apparatus. It follows from the assumptions that measurement outcomes are locally determined and that the choice of measurement setting at one site does not influence the outcome at the other site.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<p>Quantum mechanics predicts that entangled states can violate this bound. The maximum quantum value is</p>

\[2\sqrt{2} \approx 2.828,\]

<p>known as Tsirelson’s bound.</p>

<h2 id="walkthrough-derivation-of-chsh-violation">Walkthrough Derivation of CHSH Violation</h2>

<p>To see how the violation appears mathematically, we can use the Bell state $\ket{\Phi^+}$ and restrict all measurement directions to the $x$-$z$ plane.</p>

<p>Alice and Bob share</p>

\[\ket{\Phi^+} =
\frac{1}{\sqrt{2}}(\ket{00} + \ket{11}).\]

<p>Alice chooses between two measurement directions, represented by unit vectors $\vec{a}$ and $\vec{a}’$. Bob chooses between $\vec{b}$ and $\vec{b}’$. The corresponding observables are</p>

\[A = \vec{a}\cdot\vec{\sigma},
\qquad
B = \vec{b}\cdot\vec{\sigma},\]

<p>where $\vec{\sigma}$ denotes the vector of Pauli matrices.</p>

<p>For this state and this measurement plane, the quantum correlation function is</p>

\[E(\vec{a},\vec{b})
=
\bra{\Phi^+}
(\vec{a}\cdot\vec{\sigma})
\otimes
(\vec{b}\cdot\vec{\sigma})
\ket{\Phi^+}
=
\vec{a}\cdot\vec{b}
=
\cos(\theta_{\vec{a},\vec{b}}),\]

<p>where $\theta_{\vec{a},\vec{b}}$ is the angle between the two measurement directions.</p>

<p>Choose the following settings:</p>

<ul>
  <li>Alice’s first setting: $\theta_A = 0^\circ$</li>
  <li>Alice’s second setting: $\theta_{A’} = 90^\circ$</li>
  <li>Bob’s first setting: $\theta_B = 45^\circ$</li>
  <li>Bob’s second setting: $\theta_{B’} = -45^\circ$</li>
</ul>

<p>Using</p>

\[E(\vec{a},\vec{b}) = \cos(\Delta \theta),\]

<p>we get</p>

\[E(A,B) = \cos(45^\circ - 0^\circ) = \frac{\sqrt{2}}{2},\]

\[E(A,B') = \cos(-45^\circ - 0^\circ) = \frac{\sqrt{2}}{2},\]

\[E(A',B) = \cos(45^\circ - 90^\circ) = \frac{\sqrt{2}}{2},\]

<p>and</p>

\[E(A',B') = \cos(-45^\circ - 90^\circ) = -\frac{\sqrt{2}}{2}.\]

<p>Substitute these values into the CHSH expression:</p>

\[S =
E(A,B)
+
E(A,B')
+
E(A',B)
-
E(A',B').\]

<p>Then</p>

\[S =
\frac{\sqrt{2}}{2}
+
\frac{\sqrt{2}}{2}
+
\frac{\sqrt{2}}{2}
-
\left(
-\frac{\sqrt{2}}{2}
\right)
=
2\sqrt{2}.\]

<p>Because</p>

\[2\sqrt{2} &gt; 2,\]

<p>the quantum prediction violates the CHSH inequality. This means that no local hidden-variable theory satisfying the CHSH assumptions can reproduce all the statistical predictions of quantum mechanics.<sup id="fnref:2"><a href="#fn:2" class="footnote" rel="footnote" role="doc-noteref">2</a></sup></p>

<p>If the singlet state $\ket{\Psi^-}$ is used instead, the correlation function becomes</p>

\[E(\vec{a},\vec{b}) = -\vec{a}\cdot\vec{b}.\]

<p>The sign convention changes, but with appropriate measurement settings the same maximum violation magnitude, $2\sqrt{2}$, is obtained.</p>

<h2 id="summary-of-empirical-milestones">Summary of Empirical Milestones</h2>

<p>Bell-test experiments attempt to determine whether observed correlations can be explained by local hidden variables or whether they violate Bell inequalities as quantum mechanics predicts.</p>

<p>The main experimental challenge is closing loopholes.<sup id="fnref:3"><a href="#fn:3" class="footnote" rel="footnote" role="doc-noteref">3</a></sup> The classic loopholes include:</p>

<ul>
  <li><strong>Locality loophole:</strong> the possibility that information about one measurement setting or outcome reaches the other detector in time to influence the result.</li>
  <li><strong>Detection loophole:</strong> the possibility that the detected subset of particles is not representative of the full emitted ensemble.</li>
  <li><strong>Freedom-of-choice loophole:</strong> the possibility that the measurement settings are not statistically independent of hidden variables associated with the source.</li>
</ul>

<p>The following table summarizes selected milestones.</p>

<div class="c-prose-caption c-prose-caption--table-block c-prose-caption--table" id="tbl-bell-test-milestones" data-ref-type="table">
    Selected experimental milestones in Bell-test verification and loophole closure.

  </div>

<table class="c-prose-table">
  <thead>
    <tr>
      <th style="text-align: left">Experiment / Laboratory</th>
      <th style="text-align: left">Physical System</th>
      <th style="text-align: left">Reported Bell-test result</th>
      <th style="text-align: left">Statistical Confidence</th>
      <th style="text-align: left">Main Loophole Addressed</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Freedman &amp; Clauser (1972)</strong></td>
      <td style="text-align: left">Atomic calcium cascade photons</td>
      <td style="text-align: left">Bell-inequality violation observed</td>
      <td style="text-align: left">Significant early violation</td>
      <td style="text-align: left">First widely recognized experimental Bell test</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Aspect, Dalibard &amp; Roger (1982)</strong></td>
      <td style="text-align: left">Entangled photons</td>
      <td style="text-align: left">Bell-inequality violation with time-varying analyzers</td>
      <td style="text-align: left">Strong violation</td>
      <td style="text-align: left">Locality through fast analyzer switching</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Rowe et al. (2001)</strong></td>
      <td style="text-align: left">Trapped $^{9}\mathrm{Be}^{+}$ ions</td>
      <td style="text-align: left">Bell-type violation using high-efficiency ion detection</td>
      <td style="text-align: left">Strong violation</td>
      <td style="text-align: left">Detection efficiency</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Hensen et al. (Delft, 2015)</strong></td>
      <td style="text-align: left">Nitrogen-vacancy centers in diamond</td>
      <td style="text-align: left">$S = 2.42 \pm 0.20$</td>
      <td style="text-align: left">$p = 0.039$</td>
      <td style="text-align: left">Loophole-free test addressing locality and detection</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Giustina et al. (Vienna, 2015)</strong></td>
      <td style="text-align: left">Entangled photons</td>
      <td style="text-align: left">Significant Bell-inequality violation</td>
      <td style="text-align: left">$11.5\sigma$</td>
      <td style="text-align: left">Loophole-free photonic test with high-efficiency detection</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Shalm et al. (NIST, 2015)</strong></td>
      <td style="text-align: left">Entangled photons from spontaneous parametric down-conversion</td>
      <td style="text-align: left">Significant Bell-inequality violation</td>
      <td style="text-align: left">Strong rejection of local realism</td>
      <td style="text-align: left">Loophole-free photonic test with high spatial separation</td>
    </tr>
  </tbody>
</table>

<p>These experiments do not prove that measurement outcomes are controlled by faster-than-light signals. Rather, they show that the joint assumptions of locality, realism, and standard statistical independence cannot all be maintained in the simple classical form assumed by local hidden-variable models.</p>

<h2 id="reproducibility-and-numerical-verification">Reproducibility and Numerical Verification</h2>

<p>The CHSH violation can be verified numerically with basic matrix algebra. Define the Pauli matrices</p>

\[\sigma_x =
\begin{pmatrix}
0 &amp; 1 \\
1 &amp; 0
\end{pmatrix},
\qquad
\sigma_z =
\begin{pmatrix}
1 &amp; 0 \\
0 &amp; -1
\end{pmatrix}.\]

<p>A measurement direction in the $x$-$z$ plane can be represented as</p>

\[\sigma(\theta)
=
\sin(\theta)\sigma_x
+
\cos(\theta)\sigma_z.\]

<p>For two qubits, the joint observable is built using the tensor product:</p>

\[\sigma(\theta_A) \otimes \sigma(\theta_B).\]

<p>The correlation is then computed as</p>

\[E(\theta_A,\theta_B)
=
\bra{\Phi^+}
\left[
\sigma(\theta_A) \otimes \sigma(\theta_B)
\right]
\ket{\Phi^+}.\]

<p>By evaluating this expression for the four CHSH settings,</p>

\[\theta_A = 0^\circ,
\qquad
\theta_{A'} = 90^\circ,
\qquad
\theta_B = 45^\circ,
\qquad
\theta_{B'} = -45^\circ,\]

<p>one recovers</p>

\[S = 2\sqrt{2}.\]

<p>This computation is straightforward to reproduce in Python with NumPy using Kronecker products. Conceptually, it shows that the violation is not an artifact of language or interpretation; it follows from the linear algebraic structure of quantum states and measurements.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Entanglement is not merely a stronger version of classical correlation. It is a structural feature of composite quantum systems whose joint state cannot be decomposed into independent local states. The density matrix formalism shows how a globally pure state can produce locally mixed subsystems, while Bell’s theorem shows that entangled states can generate correlations beyond the limits of local hidden-variable theories.</p>

<p>The CHSH inequality makes this distinction experimentally testable. Its violation demonstrates that the classical assumptions of locality, realism, and independent measurement choice cannot all be retained in their traditional form. This is why entanglement remains central not only to the foundations of quantum mechanics, but also to modern quantum technologies.</p>

<h2 id="references">References</h2>

<ul>
  <li>Aspect, A., Dalibard, J., &amp; Roger, G. (1982). Experimental test of Bell’s inequalities using time-varying analyzers. <em>Physical Review Letters</em>, 49(25), 1804–1807.</li>
  <li>Bell, J. S. (1964). On the Einstein Podolsky Rosen paradox. <em>Physics Physique Fizika</em>, 1(3), 195–200.</li>
  <li>Clauser, J. F., Horne, M. A., Shimony, R., &amp; Holt, R. A. (1969). Proposed experiment to test local hidden-variable theories. <em>Physical Review Letters</em>, 23(15), 880–884.</li>
  <li>Einstein, A., Podolsky, B., &amp; Rosen, N. (1935). Can quantum-mechanical description of physical reality be considered complete? <em>Physical Review</em>, 47(10), 777–780.</li>
  <li>Freedman, S. J., &amp; Clauser, J. F. (1972). Experimental test of local hidden-variable theories. <em>Physical Review Letters</em>, 28(14), 938–941.</li>
  <li>Giustina, M., et al. (2015). Significant-loophole-free test of Bell’s theorem with entangled photons. <em>Physical Review Letters</em>, 115(25), 250401.</li>
  <li>Hensen, B., et al. (2015). Loophole-free Bell inequality violation using electron spins separated by 1.3 kilometres. <em>Nature</em>, 526(7575), 682–686.</li>
  <li>Rowe, M. A., et al. (2001). Experimental violation of a Bell’s inequality with efficient detection. <em>Nature</em>, 409, 791–794.</li>
  <li>Shalm, L. K., et al. (2015). Strong loophole-free test of local realism. <em>Physical Review Letters</em>, 115(25), 250402.</li>
</ul>

<h2 id="endnotes">Endnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>The CHSH inequality assumes local hidden variables, binary outcomes, and statistical independence between hidden variables and later measurement-setting choices. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2">
      <p>A superdeterministic model attempts to preserve locality by rejecting the usual statistical independence assumption. This is logically possible, but it requires measurement settings and hidden variables to be correlated in a way that standard Bell-test analyses do not allow. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3">
      <p>For photonic Bell tests, the detection loophole is especially important because lost photons can bias the detected sample. Closing this loophole requires sufficiently high total detection efficiency. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Your Name</name><email>hello@example.com</email><uri>https://example.com</uri></author><category term="physics" /><category term="math" /><category term="research" /><category term="academic" /><summary type="html"><![CDATA[A rigorous introduction to quantum entanglement with LaTeX math, citations, and footnotes.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://amirhs1.github.io/eyvan/assets/images/posts/quantum-entanglement-cover.webp" /><media:content medium="image" url="https://amirhs1.github.io/eyvan/assets/images/posts/quantum-entanglement-cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>