Liquid Templates Guide

Master Jekyll’s Liquid templating language for dynamic content generation.

Basics

Output Tags

Display variables and expressions:


Minecraft Mods & Packs Showcase
Complete guide to using Liquid templating in Jekyll.

Logic Tags

Control flow and iteration:


  ...



Variables

Site Variables

Minecraft Mods & Packs Showcase              # From _config.yml
Browse curated Minecraft mods, resource packs, datapacks, modpacks and plugins from our organization.

https://abc-site.devvyy.xyz
2025-12-17 01:31:20 +0000               # Build timestamp
{% assign page_lang = page.url | split: '/' | second %}
{% if page_lang == 'fr' %}
{% assign page_lang = 'fr' %}
{% else %}
{% assign page_lang = 'en' %}
{% endif %}
{% assign t = site.data[page_lang] %}

<section class="hero" style="min-height: 60vh; display: flex; align-items: center; justify-content: center;">
  <div class="hero-card" style="text-align: center; max-width: 600px;">
    <div style="font-size: 120px; font-weight: 700; color: var(--accent-primary); margin-bottom: 24px; line-height: 1;">
      404
    </div>
    <h1 style="margin: 0 0 16px 0; font-size: 32px;">{{ t.error_404_title }}</h1>
    <p class="muted" style="font-size: 16px; margin-bottom: 32px;">{{ t.error_404_message }}</p>
    
    <div class="cta-row" style="flex-direction: column; gap: 12px;">
      <a class="btn primary" href="{% if page_lang == 'fr' %}/abc-site/fr/{% else %}/abc-site/{% endif %}">
        <i class="fas fa-home"></i> {{ t.error_404_back_home }}
      </a>
      <a class="btn ghost" href="{% if page_lang == 'fr' %}/abc-site/fr/projects/{% else %}/abc-site/projects/{% endif %}">
        <i class="fas fa-list"></i> {{ t.error_404_browse }}
      </a>
    </div>

    <div style="margin-top: 48px; padding-top: 32px; border-top: 1px solid var(--border);">
      <p class="muted" style="font-size: 13px; margin: 0;">
        {% if page_lang == 'fr' %}
          Si vous pensez que c'est une erreur, <a href="{{ '/contact/' | relative_url }}" style="color: var(--accent-primary); text-decoration: none;">contactez-nous</a>.
        {% else %}
          If you think this is a mistake, <a href="{{ '/contact/' | relative_url }}" style="color: var(--accent-primary); text-decoration: none;">contact us</a>.
        {% endif %}
      </p>
    </div>

  </div>
</section>

<style>
  .cta-row {
    display: flex;
    gap: 16px;
    justify-content: center;
    flex-wrap: wrap;
  }

  @media (max-width: 640px) {
    .hero-card {
      padding: 32px 16px !important;
    }
    
    .cta-row {
      flex-direction: column;
      gap: 12px;
    }
    
    .hero-card h1 {
      font-size: 24px !important;
    }
  }
</style>
<section class="hero">
  <div class="hero-card">
    <h1>About Us</h1>
    <p class="muted">A community-driven showcase for the best Minecraft mods, resource packs, datapacks, modpacks, and plugins.</p>
  </div>
</section>

<section class="section">
  <h2>Our Mission</h2>
  <p class="muted">To provide an organized, beautiful, and accessible platform for discovering and showcasing high-quality Minecraft content.</p>
  
  <div class="grid">
    <div class="card">
      <h3><i class="fa-solid fa-bullseye"></i> Curated Collection</h3>
      <p>We handpick projects from the Modrinth ecosystem, ensuring quality and relevance for our community.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-users"></i> Community Focused</h3>
      <p>Built by and for the Minecraft community. Your feedback and contributions shape our platform.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-code"></i> Open Source</h3>
      <p>Completely open-source and transparent. Fork, modify, and contribute on GitHub.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-bolt"></i> Fast & Reliable</h3>
      <p>Static site hosted on GitHub Pages. Zero downtime, global CDN, instant loading.</p>
    </div>
  </div>
</section>

<section class="section">
  <h2>How It Works</h2>
  <div class="grid">
    <div class="card">
      <h3><i class="fa-solid fa-database"></i> Live Data</h3>
      <p>We sync project data daily from Modrinth, keeping our showcase fresh and up-to-date with the latest versions and downloads.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-filter"></i> Smart Filtering</h3>
      <p>Filter projects by type, loader, and game version. Find exactly what you're looking for in seconds.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-chart-line"></i> Statistics</h3>
      <p>Real-time statistics show total downloads, supported versions, popular categories, and trending projects.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-link"></i> Direct Links</h3>
      <p>Every project links directly to Modrinth, ensuring you always download from the official source.</p>
    </div>
  </div>
</section>

<section class="section">
  <h2>Get Involved</h2>
  <div class="grid">
    <div class="card">
      <h3><i class="fa-brands fa-discord"></i> Join Discord</h3>
      <p class="muted">Chat with our community, get support, and suggest improvements.</p>
      {% if site.social.discord %}
        <a class="btn primary" href="{{ site.social.discord }}" target="_blank" rel="noopener">Open Discord</a>
      {% endif %}
    </div>
    <div class="card">
      <h3><i class="fa-brands fa-github"></i> Contribute</h3>
      <p class="muted">Found a bug? Have an idea? Star and contribute to our repository.</p>
      {% if site.social.github %}
        <a class="btn ghost" href="{{ site.social.github }}" target="_blank" rel="noopener">View on GitHub</a>
      {% endif %}
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-heart"></i> Support</h3>
      <p class="muted">Enjoying the platform? Follow our socials and spread the word!</p>
      {% if site.social.twitter %}
        <a class="btn ghost" href="{{ site.social.twitter }}" target="_blank" rel="noopener">Follow Twitter</a>
      {% endif %}
    </div>
  </div>
</section>

<section class="section">
  <h2>Our Values</h2>
  <div class="grid">
    <div class="card">
      <h3>Accessibility</h3>
      <p>We believe everyone should have access to quality Minecraft content, regardless of technical skill or platform.</p>
    </div>
    <div class="card">
      <h3>Transparency</h3>
      <p>Open source code, public data, and clear communication. We have nothing to hide.</p>
    </div>
    <div class="card">
      <h3>Community</h3>
      <p>Built together, not for profit. We prioritize creator and player needs over monetization.</p>
    </div>
    <div class="card">
      <h3>Quality</h3>
      <p>Every project showcased meets our standards for functionality, documentation, and community support.</p>
    </div>
  </div>
</section>

<section class="section">
  <h2>Contact & Support</h2>
  <div class="grid">
    <div class="card">
      <h3><i class="fa-solid fa-envelope"></i> Need Help?</h3>
      <p class="muted">Have questions? Check our documentation or reach out on Discord.</p>
      <a class="btn primary" href="{{ '/docs/' | relative_url }}">Read Docs</a>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-bug"></i> Found a Bug?</h3>
      <p class="muted">Report issues and suggest features on our GitHub repository.</p>
      {% if site.social.github %}
        <a class="btn primary" href="{{ site.social.github }}/issues" target="_blank" rel="noopener">Report Issue</a>
      {% endif %}
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-handshake"></i> Let's Collaborate</h3>
      <p class="muted">Interested in partnering or featuring your project? Let's talk!</p>
      {% if site.social.discord %}
        <a class="btn ghost" href="{{ site.social.discord }}" target="_blank" rel="noopener">Chat with Us</a>
      {% endif %}
    </div>
  </div>
</section>
<section class="section">
  <h1>Blog</h1>
  <p class="muted">Updates from the team — releases, dev logs, and tips.</p>

  <div class="filters" style="margin: 12px 0 20px; display:flex; gap:8px; flex-wrap:wrap;">
    {% assign all_tags = site.tags %}
    {% for tag in all_tags %}
      <a href="{{ '/blog/#' | append: tag[0] | relative_url }}" style="padding:6px 10px; border:1px solid var(--border); border-radius:999px; text-decoration:none; color:var(--text-secondary);">#{{ tag[0] }}</a>
    {% endfor %}
  </div>

  <div class="filters" style="margin: 0 0 24px; display:flex; gap:8px; flex-wrap:wrap;">
    {% assign all_categories = site.categories %}
    {% for category in all_categories %}
      <a href="{{ '/blog/#' | append: category[0] | relative_url }}" style="padding:6px 10px; border:1px solid var(--border); border-radius:999px; text-decoration:none; color:var(--text-secondary);">{{ category[0] }}</a>
    {% endfor %}
  </div>

  <div class="post-list" style="display: grid; gap: 16px;">
    {% assign posts = site.posts | where_exp: 'p', 'p.published != false' %}
    {% for post in posts %}
    <article style="border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; background: var(--bg-primary);">
      <h2 style="margin: 0;">
        <a href="{{ post.url | relative_url }}" style="color: var(--text); text-decoration: none;">{{ post.title }}</a>
      </h2>
      <p class="muted" style="margin: 6px 0 12px;">{{ post.date | date: "%B %d, %Y" }}{{ post.author | default: site.site.name }}</p>
      {% if post.excerpt %}
        <p style="margin: 0 0 8px;">{{ post.excerpt }}</p>
      {% endif %}
      {% if post.tags %}
        <div style="margin:8px 0;">
          {% for tag in post.tags %}
            <span style="display:inline-block; padding: 4px 8px; border: 1px solid var(--border); border-radius: 999px; margin-right: 6px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
      {% endif %}
      <a href="{{ post.url | relative_url }}" class="button" style="display:inline-block; padding: 8px 12px; background: var(--accent-primary); color: #000; border-radius: var(--radius); text-decoration: none;">Read More</a>
    </article>
    {% endfor %}

    {% if posts.size == 0 %}
      <p class="muted">No posts yet. Stay tuned!</p>
    {% endif %}

  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Community & Contributing</h1>
    <p class="muted">Learn how to contribute to the ABC showcase and get involved.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "Community" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Developer Resources</h1>
    <p class="muted">Technical documentation, architecture, and API reference.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "Developer" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Help & Troubleshooting</h1>
    <p class="muted">Find answers to common questions and fix issues quickly.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "Help" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Setup & Configuration</h1>
    <p class="muted">Get the ABC showcase installed and configured for your needs.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "Setup" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Styling & Customization</h1>
    <p class="muted">Customize colors, themes, and appearance of your ABC showcase.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "Styling" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>User Guide</h1>
    <p class="muted">Everything you need to know as a user or project manager.</p>
  </div>
</section>

<section class="section">
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
    {% assign category_docs = site.docs | where: "category", "User Guide" %}
    {% for doc in category_docs %}
      <div class="card">
        <h3>{{ doc.title }}</h3>
        <p class="muted" style="font-size: 13px; margin-bottom: 12px;">{{ doc.description }}</p>
        <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
          {% for tag in doc.tags %}
            <span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#{{ tag }}</span>
          {% endfor %}
        </div>
        <a class="btn primary" href="{{ doc.url | relative_url }}" style="width: 100%; display: block; text-align: center;">Read More</a>
      </div>
    {% endfor %}
  </div>
</section>

<section class="section">
  <div style="text-align: center;">
    <p><a href="{{ '/docs/' | relative_url }}">← Back to all documentation</a></p>
  </div>
</section>
<section class="hero">
  <div class="hero-card">
    <p class="muted" style="margin-bottom: 6px; letter-spacing: 0.5px; text-transform: uppercase; font-size: 12px;">Releases</p>
    <h1>Changelog</h1>
    <p class="muted">Track the freshest updates across ABC mods, modpacks, resource packs, and datapacks.</p>
  </div>
</section>

<section class="section">
  <div style="display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px;">
    <div style="display: flex; gap: 10px; align-items: center;">
      <i class="fa-solid fa-rocket" style="color: var(--accent-primary);"></i>
      <p class="muted" style="margin: 0;">Sorted by latest update time</p>
    </div>
    <div id="changelog-count" class="muted" style="font-size: 14px;"></div>
  </div>

  <div id="changelog-list" class="grid" style="grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px;"></div>
  <div id="changelog-empty" class="muted" style="display: none; text-align: center; margin: 24px 0;">No releases found yet. Add entries to <code>data/mods.json</code> or <code>data/modpacks.json</code>.</div>
</section>

<script>
  document.addEventListener('DOMContentLoaded', () => {
    const listEl = document.getElementById('changelog-list');
    const countEl = document.getElementById('changelog-count');
    const emptyEl = document.getElementById('changelog-empty');

    function formatDate(value) {
      if (!value) return 'N/A';
      const date = new Date(value);
      return isNaN(date.getTime()) ? 'N/A' : date.toLocaleDateString();
    }

    function renderCard(item) {
      const versions = (item.game_versions || []).slice(0, 4).map(v => `<span class="version-badge">${v}</span>`).join('');
      const categories = (item.categories || []).slice(0, 3).map(cat => `<span class="category-pill">${cat}</span>`).join('');
      const updated = formatDate(item.updated || item.date_modified || item.published);
      const typeLabel = (item.project_type || item.type || 'mod').replace(/_/g, ' ');

      return `
        <article class="card">
          <div style="display:flex;align-items:center;gap:12px;">
            ${item.icon_url ? `<img src="${item.icon_url}" alt="${item.name}" style="width:48px;height:48px;border-radius:12px;border:1px solid var(--border);object-fit:cover;" />` : '<div style="width:48px;height:48px;border-radius:12px;border:1px dashed var(--border);"></div>'}
            <div>
              <p class="muted" style="margin:0;font-size:12px;text-transform:uppercase;letter-spacing:0.6px;">${typeLabel}</p>
              <h3 style="margin:4px 0 0;">${item.title || item.name}</h3>
            </div>
          </div>
          <p class="muted" style="margin: 4px 0 0;">${item.short_description || item.description || 'No description available.'}</p>
          <div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
            ${versions || '<span class="version-badge">All versions</span>'}
          </div>
          <div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;">
            ${categories}
          </div>
          <div style="display:flex;gap:12px;flex-wrap:wrap;font-size:13px;color:var(--text-muted);">
            <span><i class="fa-regular fa-clock"></i> Updated ${updated}</span>
            <span><i class="fa-solid fa-download"></i> ${(item.downloads || 0).toLocaleString()} downloads</span>
            <span><i class="fa-solid fa-users"></i> ${(item.followers || 0).toLocaleString()} followers</span>
          </div>
          <div style="display:flex;gap:8px;flex-wrap:wrap;">
            ${item.download ? `<a class="btn ghost" href="${item.download}" target="_blank"><i class="fa-solid fa-arrow-up-right-from-square"></i> View Project</a>` : ''}
            ${item.source_url ? `<a class="btn ghost" href="${item.source_url}" target="_blank"><i class="fa-brands fa-github"></i> Source</a>` : ''}
          </div>
        </article>
      `;
    }

    async function fetchJson(url) {
      try {
        const res = await fetch(url);
        if (!res.ok) throw new Error(`Request failed: ${res.status}`);
        return await res.json();
      } catch (err) {
        console.warn('Changelog fetch failed', err);
        return [];
      }
    }

    async function loadChangelog() {
      const [mods, modpacks] = await Promise.all([
        fetchJson('{{ '/data/mods.json' | relative_url }}'),
        fetchJson('{{ '/data/modpacks.json' | relative_url }}')
      ]);

      const items = [...mods, ...modpacks].map(item => ({
        ...item,
        updated: item.updated || item.date_modified || item.published || null,
      })).filter(item => item);

      if (!items.length) {
        emptyEl.style.display = 'block';
        countEl.textContent = '';
        return;
      }

      items.sort((a, b) => {
        const dateA = new Date(a.updated || 0).getTime();
        const dateB = new Date(b.updated || 0).getTime();
        return dateB - dateA;
      });

      listEl.innerHTML = items.map(renderCard).join('');
      countEl.textContent = `${items.length} releases`;
    }

    loadChangelog();
  });
</script>
<div class="hero" style="background-image: url('{{ '/assets/images/blocks.svg' | relative_url }}'); background-size: cover; background-position: center; min-height: 120px; padding: 0.5rem 0 !important;">
  <div class="hero-content">
    <h1 class="hero-title fade-in">Compare Modpacks</h1>
    <p class="hero-description fade-in-up">Compare features, performance, and content across modpacks</p>
  </div>
</div>

<div class="comparison-container">
  <div class="comparison-header">
    <h2>Select Modpacks to Compare</h2>
    <p>Choose up to 3 modpacks to compare side-by-side</p>
  </div>

  <div class="comparison-selector">
    <div class="selector-box">
      <label for="compare-1">Modpack 1</label>
      <select id="compare-1" class="modpack-select">
        <option value="">Select a modpack...</option>
      </select>
    </div>
    <div class="selector-box">
      <label for="compare-2">Modpack 2</label>
      <select id="compare-2" class="modpack-select">
        <option value="">Select a modpack...</option>
      </select>
    </div>
    <div class="selector-box">
      <label for="compare-3">Modpack 3</label>
      <select id="compare-3" class="modpack-select">
        <option value="">Select a modpack...</option>
      </select>
    </div>
  </div>

  <div class="comparison-actions">
    <button id="compare-btn" class="btn btn-primary" disabled>
      <i class="fas fa-balance-scale"></i> Compare Selected
    </button>
    <button id="clear-btn" class="btn btn-secondary">
      <i class="fas fa-times"></i> Clear All
    </button>
  </div>

  <div id="comparison-results" class="comparison-results hidden">
    <div class="comparison-table-wrapper">
      <table class="comparison-table">
        <thead>
          <tr>
            <th class="feature-col">Feature</th>
            <th class="modpack-col" id="header-1"></th>
            <th class="modpack-col" id="header-2"></th>
            <th class="modpack-col" id="header-3"></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td class="feature-name"><i class="fas fa-image"></i> Icon</td>
            <td id="icon-1"></td>
            <td id="icon-2"></td>
            <td id="icon-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-layer-group"></i> Type</td>
            <td id="type-1"></td>
            <td id="type-2"></td>
            <td id="type-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-info-circle"></i> Description</td>
            <td id="description-1"></td>
            <td id="description-2"></td>
            <td id="description-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-gamepad"></i> Supported MC Versions</td>
            <td id="version-1"></td>
            <td id="version-2"></td>
            <td id="version-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-download"></i> Downloads</td>
            <td id="downloads-1"></td>
            <td id="downloads-2"></td>
            <td id="downloads-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-users"></i> Followers</td>
            <td id="followers-1"></td>
            <td id="followers-2"></td>
            <td id="followers-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-calendar"></i> Last Updated</td>
            <td id="updated-1"></td>
            <td id="updated-2"></td>
            <td id="updated-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-tag"></i> Categories</td>
            <td id="categories-1"></td>
            <td id="categories-2"></td>
            <td id="categories-3"></td>
          </tr>
          <tr>
            <td class="feature-name"><i class="fas fa-link"></i> Links</td>
            <td id="links-1"></td>
            <td id="links-2"></td>
            <td id="links-3"></td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>

<style>
.comparison-container {
  max-width: 1400px;
  margin: 3rem auto;
  padding: 0 1rem;
}

.comparison-header {
  text-align: center;
  margin-bottom: 2rem;
}

.comparison-header h2 {
  font-size: 2rem;
  margin-bottom: 0.5rem;
}

.comparison-header p {
  color: var(--text-muted);
}

.comparison-selector {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

.selector-box {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.selector-box label {
  font-weight: 600;
  color: var(--text);
}

.modpack-select {
  padding: 0.75rem;
  border: 2px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 1rem;
  cursor: pointer;
  transition: all 0.2s;
}

.modpack-select:hover {
  border-color: var(--accent);
}

.modpack-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0, 255, 157, 0.1);
}

.comparison-actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  margin-bottom: 3rem;
}

.btn {
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.btn-primary {
  background: var(--accent);
  color: var(--bg);
}

.btn-primary:hover:not(:disabled) {
  background: var(--accent-hover);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 255, 157, 0.3);
}

.btn-primary:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--bg-secondary);
  color: var(--text);
  border: 2px solid var(--border);
}

.btn-secondary:hover {
  background: var(--bg-tertiary);
  border-color: var(--text-muted);
}

.comparison-results {
  opacity: 1;
  transition: opacity 0.3s;
}

.comparison-results.hidden {
  display: none;
  opacity: 0;
}

.comparison-table-wrapper {
  overflow-x: auto;
  border-radius: 12px;
  border: 2px solid var(--border);
}

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--bg);
}

.comparison-table thead {
  background: var(--bg-secondary);
  position: sticky;
  top: 0;
  z-index: 10;
}

.comparison-table th,
.comparison-table td {
  padding: 1rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.comparison-table th {
  font-weight: 700;
  color: var(--text);
}

.feature-col {
  width: 200px;
  font-weight: 600;
  background: var(--bg-secondary);
  position: sticky;
  left: 0;
  z-index: 5;
}

.feature-name {
  font-weight: 600;
  background: var(--bg-secondary);
  position: sticky;
  left: 0;
  z-index: 5;
}

.feature-name i {
  margin-right: 0.5rem;
  color: var(--accent);
}

.modpack-col {
  min-width: 250px;
}

.comparison-table tbody tr:hover {
  background: var(--bg-tertiary);
}

.modpack-icon {
  width: 64px;
  height: 64px;
  border-radius: 8px;
  object-fit: cover;
}

.category-pill {
  display: inline-block;
  padding: 0.25rem 0.75rem;
  background: var(--accent);
  color: var(--bg);
  border-radius: 999px;
  font-size: 0.875rem;
  margin: 0.25rem;
}

.link-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--accent);
  color: var(--bg);
  text-decoration: none;
  border-radius: 8px;
  margin: 0.25rem;
  transition: all 0.2s;
}

.link-button:hover {
  background: var(--accent-hover);
  transform: translateY(-2px);
}

@media (max-width: 768px) {
  .comparison-selector {
    grid-template-columns: 1fr;
  }
  
  .comparison-actions {
    flex-direction: column;
  }
  
  .btn {
    width: 100%;
  }
  
  .feature-col,
  .feature-name {
    position: static;
  }
}
</style>

<script>
// Populate selects with any content type
const modpacksData = {{ site.data.modpacks | default: "[]" | jsonify }};
const modsData = {{ site.data.mods | default: "[]" | jsonify }};

// Normalize datasets and merge
function parseData(raw, fallbackType) {
  const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw || [];
  return Array.isArray(parsed)
    ? parsed.map((item) => ({
        ...item,
        content_type: item.type || item.project_type || fallbackType,
      }))
    : [];
}

const items = [
  ...parseData(modpacksData, 'modpack'),
  ...parseData(modsData, 'mod'),
];

const selects = ['compare-1', 'compare-2', 'compare-3'];

if (Array.isArray(items) && items.length > 0) {
  selects.forEach((selectId) => {
    const select = document.getElementById(selectId);
    items.forEach((item) => {
      const option = document.createElement('option');
      option.value = item.id;
      const typeLabel = (item.content_type || 'modpack').replace(/_/g, ' ');
      option.textContent = `${item.name} (${typeLabel})`;
      select.appendChild(option);
    });
  });
} else {
  // Show message if no content available
  document.querySelector('.comparison-selector').innerHTML =
    '<p style="text-align:center;color:var(--text-muted);padding:2rem;">No content available for comparison. Add data to _data/modpacks.json or _data/mods.json to enable this feature.</p>';
  document.querySelector('.comparison-actions').style.display = 'none';
}

// Enable/disable compare button (guard if DOM missing)
function updateCompareButton() {
  const compareBtn = document.getElementById('compare-btn');
  if (!compareBtn) return;
  const selected = selects
    .map(id => document.getElementById(id))
    .filter(Boolean)
    .map(el => el.value)
    .filter(Boolean);
  compareBtn.disabled = selected.length < 2;
}

selects.forEach(id => {
  const el = document.getElementById(id);
  if (el) el.addEventListener('change', updateCompareButton);
});

const compareBtnEl = document.getElementById('compare-btn');
const clearBtnEl = document.getElementById('clear-btn');

// Compare functionality
compareBtnEl?.addEventListener('click', () => {
  const selectedIds = selects
    .map(id => document.getElementById(id))
    .filter(Boolean)
    .map(el => el.value)
    .filter(Boolean);
  const selectedItems = selectedIds
    .map(id => items.find(m => m.id === id))
    .filter(Boolean);
  
  // Populate table
  selectedItems.forEach((item, index) => {
    const col = index + 1;
    const typeLabel = (item.content_type || 'modpack').replace(/_/g, ' ');
    
    // Header
    document.getElementById(`header-${col}`).innerHTML = `<strong>${item.name}</strong>`;
    
    // Icon
    document.getElementById(`icon-${col}`).innerHTML = 
      item.icon_url ? `<img src="${item.icon_url}" alt="${item.name}" class="modpack-icon">` : 'N/A';

    // Type
    document.getElementById(`type-${col}`).textContent = typeLabel;
    
    // Description
    document.getElementById(`description-${col}`).textContent = item.short_description || item.description || 'N/A';
    
    // Versions
    const versionBadges = (item.game_versions || []).slice(0, 4).map(v => `<span class="version-badge">${v}</span>`).join('');
    document.getElementById(`version-${col}`).innerHTML = versionBadges || 'N/A';
    
    // Downloads
    document.getElementById(`downloads-${col}`).innerHTML = 
      `<strong>${(item.downloads || 0).toLocaleString()}</strong>`;
    
    // Followers
    document.getElementById(`followers-${col}`).innerHTML = 
      `<strong>${(item.followers || 0).toLocaleString()}</strong>`;
    
    // Updated
    const date = item.date_modified || item.updated;
    const dateText = date ? new Date(date).toLocaleDateString() : 'N/A';
    document.getElementById(`updated-${col}`).textContent = dateText;
    
    // Categories
    const categories = (item.categories || []).map(cat => 
      `<span class="category-pill">${cat}</span>`
    ).join('');
    document.getElementById(`categories-${col}`).innerHTML = categories || 'N/A';
    
    // Links
    const links = [
      item.project_url || item.download ? `<a href="${item.project_url || item.download}" class="link-button" target="_blank"><i class="fas fa-external-link-alt"></i> View Project</a>` : '',
      item.source_url ? `<a href="${item.source_url}" class="link-button" target="_blank"><i class="fab fa-github"></i> Source</a>` : ''
    ].filter(l => l).join('');
    document.getElementById(`links-${col}`).innerHTML = links || 'N/A';
  });
  
  // Clear remaining columns
  for (let i = selectedItems.length + 1; i <= 3; i++) {
    document.getElementById(`header-${i}`).innerHTML = '';
    ['icon', 'description', 'version', 'downloads', 'followers', 'updated', 'categories', 'links'].forEach(field => {
      document.getElementById(`${field}-${i}`).innerHTML = '';
    });
  }
  
  // Show results with animation
  const results = document.getElementById('comparison-results');
  results.classList.remove('hidden');
  setTimeout(() => results.style.opacity = '1', 10);
  
  // Scroll to results
  results.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
document.getElementById('clear-btn').addEventListener('click', () => {
});

// Clear functionality
clearBtnEl?.addEventListener('click', () => {
  selects.forEach(id => {
    const el = document.getElementById(id);
    if (el) el.value = '';
  });
  updateCompareButton();
  const results = document.getElementById('comparison-results');
  if (results) results.classList.add('hidden');
});
</script>
<section class="section">
  <h1>Contact & Support</h1>
  <p class="muted">Reach out for issues, feedback, or collaboration.</p>

  <h2>Fastest ways</h2>
  <ul>
    <li>Discord: <a href="{{ site.social.discord }}" target="_blank" rel="noopener">Join our server</a></li>
    <li>GitHub: <a href="{{ site.social.github }}" target="_blank" rel="noopener">Open an issue</a> on our repos</li>
  </ul>

  <h2>Feedback</h2>
  <p>Use the "Was this helpful?" widget on docs pages for quick feedback. For broader requests, ping us on Discord.</p>
</section>
# Cookie Policy

**Last Updated:** December 2024

We use cookies and similar tracking technologies to enhance your experience on our site. This policy explains what cookies are, how we use them, and your rights regarding them.

## What Are Cookies?

Cookies are small text files stored on your browser or device that help websites remember information about your visits. They can be:

- **Session cookies**: Deleted when you close your browser
- **Persistent cookies**: Remain on your device for a set period
- **First-party cookies**: Set by our domain
- **Third-party cookies**: Set by external services (analytics, ads, etc.)

## Cookies We Use

### Analytics

We use Google Analytics to understand how visitors use our site:

- `_ga` – Identifies unique visitors
- `_ga_*` – Tracks sessions and page views
- `_gat` – Throttles request rate

**Purpose**: Analyzing site traffic and user behavior  
**Retention**: 2 years

### Functional Cookies

- `theme` – Remembers your color theme preference
- `language` – Stores your preferred language

**Purpose**: Improving site usability  
**Retention**: 1 year

### Consent Management

- `cookie_consent` – Stores your cookie preferences
- `cookie_consent_timestamp` – Records when consent was given

**Purpose**: Respecting your privacy choices  
**Retention**: 1 year

## Third-Party Services

We may use services that set their own cookies:

| Service          | Cookies         | Purpose        | Policy                                                |
| ---------------- | --------------- | -------------- | ----------------------------------------------------- |
| Google Analytics | `_ga*`, `_gat`  | Site analytics | [Privacy Policy](https://policies.google.com/privacy) |
| Font Awesome     | Session cookies | Icon delivery  | [Privacy](https://fontawesome.com/privacy)            |
| Discord          | If embedded     | Embeds/widgets | [Privacy](https://discord.com/privacy)                |

## Cookie Preferences

You can manage your cookie preferences using our cookie consent banner at the bottom of the page. You can:

- Accept all cookies
- Reject non-essential cookies
- Customize preferences

### Browser Controls

Most browsers allow you to:

- Block cookies entirely
- Clear cookies on exit
- View stored cookies
- Opt-out of tracking

**Note**: Blocking essential cookies may affect site functionality.

## Your Rights

Under GDPR and similar privacy laws, you have the right to:

- Know what cookies are used
- Opt-out of non-essential cookies
- Request deletion of your data
- Access or port your data

## Contact

If you have questions about our cookie practices:

**Email**: [contact information from site config]

We will respond within 30 days.

## Changes

We may update this policy periodically. Your continued use of the site constitutes acceptance of any changes.

---

_This Cookie Policy is part of our overall Privacy Policy and Terms of Service._
<section class="section">
  <h1>Disclaimer & Liability Waiver</h1>
  <p class="muted">Last updated: December 11, 2025</p>

  <p>This page contains important disclaimers and limitations of liability. Please read carefully before using our website and projects.</p>

  <h2>1. Website & Content Disclaimer</h2>

  <h3>1.1 "As Is" Provision</h3>
  <p>Our website and all materials are provided "AS IS" and "AS AVAILABLE" without warranties of any kind, either express or implied. We make no warranties regarding:</p>
  <ul>
    <li>Accuracy, completeness, or timeliness of information</li>
    <li>Fitness for a particular purpose</li>
    <li>Functionality or performance</li>
    <li>Non-infringement of rights</li>
    <li>Quality or reliability</li>
  </ul>

  <h3>1.2 No Professional Advice</h3>
  <p>Content on our site is for informational purposes only and does not constitute:</p>
  <ul>
    <li>Legal advice</li>
    <li>Technical support (though we'll help if we can)</li>
    <li>Professional consulting</li>
    <li>Warranty or guarantee</li>
  </ul>
  <p>Always consult appropriate professionals for critical decisions.</p>

  <h2>2. Minecraft Project Disclaimer</h2>

  <h3>2.1 No Warranty for Mods/Datapacks/Plugins</h3>
  <p>All our Minecraft projects are provided "AS IS" without any warranty. We do not guarantee:</p>
  <ul>
    <li>The mod will work with your specific Minecraft version</li>
    <li>The mod will work with other mods you have installed (compatibility)</li>
    <li>The mod won't cause crashes or performance issues</li>
    <li>The mod won't corrupt your world or save files</li>
    <li>The mod will continue to be maintained or updated</li>
    <li>The mod is free of bugs or issues</li>
  </ul>

  <h3>2.2 Save File Loss</h3>
  <p><strong>YOU ARE RESPONSIBLE FOR BACKING UP YOUR MINECRAFT WORLDS AND SAVES.</strong></p>
  <ul>
    <li>Always backup important worlds before installing mods</li>
    <li>Test mods in a separate test world first</li>
    <li>Keep multiple backups of valuable worlds</li>
    <li>We are NOT liable for corrupted, lost, or deleted save files</li>
  </ul>

  <h3>2.3 Crashes & Compatibility</h3>
  <ul>
    <li>Mod conflicts, crashes, and performance issues are common in modded Minecraft</li>
    <li>We provide projects "as is" without technical support guarantee</li>
    <li>We'll do our best to help troubleshoot but cannot guarantee solutions</li>
    <li>Some issues may require reinstalling Java, Minecraft, or removing conflicting mods</li>
  </ul>

  <h2>3. Limitation of Liability</h2>

  <h3>3.1 No Liability For</h3>
  <p><strong>In no event shall ABC, its owners, employees, contributors, or partners be liable for:</strong></p>
  <ul>
    <li>Lost or corrupted Minecraft save files or worlds</li>
    <li>Game crashes, performance degradation, or lag</li>
    <li>System damage or instability caused by our projects</li>
    <li>Loss of income, profits, or business opportunities</li>
    <li>Loss of data or information (in any form)</li>
    <li>Any indirect, incidental, special, consequential, or punitive damages</li>
    <li>Damages arising from your use or inability to use our site/projects</li>
    <li>Issues caused by other mods or software on your system</li>
    <li>Your failure to backup important data</li>
    <li>Time or inconvenience</li>
  </ul>
  <p>This applies even if we have been advised of the possibility of such damages.</p>

  <h3>3.2 Damages Cap</h3>
  <p>If any court overrides the above disclaimer, our total liability is limited to <strong>zero dollars</strong> ($0). We are providing these projects for free.</p>

  <h2>4. Assumption of Risk</h2>

  <p>By using our website and projects, you acknowledge and assume all risks associated with:</p>
  <ul>
    <li>Installing and using mods/datapacks/plugins</li>
    <li>Potential loss of save files or worlds</li>
    <li>Game crashes or instability</li>
    <li>Compatibility issues with your setup</li>
    <li>System performance changes</li>
    <li>Following installation instructions incorrectly</li>
    <li>Running outdated Java or Minecraft versions</li>
    <li>Conflicts with other mods or software</li>
  </ul>

  <h2>5. User Responsibility</h2>

  <p>You are responsible for:</p>
  <ul>
    <li>✓ Reading and understanding installation instructions</li>
    <li>✓ Keeping your Minecraft and Java updated</li>
    <li>✓ Backing up your worlds and save files regularly</li>
    <li>✓ Testing mods in a test world first</li>
    <li>✓ Managing your system and mod installations</li>
    <li>✓ Removing conflicting mods if issues arise</li>
    <li>✓ Reporting issues accurately and completely</li>
    <li>✓ Following applicable laws and terms (EULA, etc.)</li>
  </ul>

  <h2>6. Third-Party Services Disclaimer</h2>

  <p>Our website uses third-party services and links:</p>
  <ul>
    <li><strong>Modrinth:</strong> We are not responsible for content, quality, or policies</li>
    <li><strong>GitHub:</strong> External service; we don't control availability or policies</li>
    <li><strong>Discord:</strong> Community platform; moderation is best-effort</li>
    <li><strong>Google Analytics:</strong> Data collection per their privacy policy</li>
  </ul>
  <p>Review each service's terms and privacy policy before using.</p>

  <h2>7. Availability Disclaimer</h2>

  <ul>
    <li>We do not guarantee continuous service availability</li>
    <li>The website may be offline for maintenance without notice</li>
    <li>Projects may be discontinued or archived</li>
    <li>Downloads from third-party sites may become unavailable</li>
    <li>We are not liable for service interruptions or data loss</li>
  </ul>

  <h2>8. Accuracy Disclaimer</h2>

  <ul>
    <li>We strive for accuracy but do not guarantee all information is correct</li>
    <li>Documentation may become outdated</li>
    <li>Minecraft updates may change how our projects work</li>
    <li>We are not liable for decisions based on incorrect information</li>
    <li>Always verify critical information independently</li>
  </ul>

  <h2>9. Health & Safety Disclaimer</h2>

  <p>Using computers for extended periods can cause:</p>
  <ul>
    <li>Eye strain</li>
    <li>Repetitive stress injuries (RSI)</li>
    <li>Sleep disruption</li>
    <li>Posture problems</li>
  </ul>
  <p>Take regular breaks, maintain good posture, and consult a doctor if experiencing discomfort.</p>

  <h2>10. Indemnification</h2>

  <p>You agree to indemnify and hold harmless ABC and its representatives from any claims, damages, or losses arising from:</p>
  <ul>
    <li>Your use of our site or projects</li>
    <li>Violation of these disclaimers or our Terms</li>
    <li>Your violation of any laws or third-party rights</li>
    <li>Your content or actions</li>
  </ul>

  <h2>11. Questions or Concerns?</h2>

  <p>If you don't agree with these disclaimers or have concerns:</p>
  <ul>
    <li>Do not use our site or projects</li>
    <li><a href="{{ '/contact/' | relative_url }}">Contact us</a> with specific concerns</li>
  </ul>

  <hr style="margin: 32px 0; border: none; border-top: 1px solid var(--border);">

  <p class="muted" style="font-size: 12px;">
    <strong>Bottom Line:</strong> Our projects are free. Use at your own risk. Backup your saves. Test before using on important worlds. We're not responsible for any damages. Questions? Ask us.
  </p>
</section>
If you are not redirected automatically, join here: {{ site.social.discord }}
# End User License Agreement (EULA)

**Last Updated:** December 2024

This End User License Agreement ("EULA") is a legal agreement between you and ABC Team governing your use of our projects, mods, datapacks, plugins, and related software ("Software").

## 1. Grant of License

We grant you a non-exclusive, non-transferable, limited license to use the Software for personal, non-commercial purposes, subject to the terms of this agreement.

### Permitted Uses

✅ Install and use on your personal devices  
✅ Create content using the Software (videos, streams, guides)  
✅ Modify the Software for personal use  
✅ Use in private multiplayer servers

### Prohibited Uses

❌ Commercial redistribution without permission  
❌ Reselling modified versions  
❌ Claiming ownership of the Software  
❌ Reverse engineering for competitive purposes  
❌ Removing attribution or license notices

## 2. Intellectual Property Rights

All Software, including code, assets, textures, and designs, are owned by ABC Team or our contributors. You may not claim ownership or use the Software outside the scope of this license.

### Attribution

When using or referencing the Software, you agree to:

- Maintain original credits
- Link to our GitHub or website
- Not remove license files
- Acknowledge ABC Team as creators

## 3. Modifications

You may modify the Software for personal use. However:

- Modified versions cannot be redistributed commercially
- You must maintain original licenses and credits
- We are not responsible for issues caused by your modifications
- Private use of mods is always permitted

## 4. Server Usage

You may:

- Run the Software on private servers
- Run on public servers (community/multiplayer)
- Accept donations (but not force payment)

You must:

- Display credits/links in server descriptions
- Not claim the Software as your own creation
- Not charge for access to unmodified Software

## 5. Content & Creator Policy

**Streaming & YouTube**: Fully allowed. No permission required.

**Monetization**: You may monetize content featuring the Software (ads, sponsorships, Patreon). You do not owe us revenue share.

**Attribution**: Simply crediting "ABC Team" or linking to our GitHub is appreciated but not required.

## 6. Warranty Disclaimer

THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.

We do not warrant that:

- The Software will meet your requirements
- The Software will be error-free or bug-free
- The Software will be compatible with all platforms
- Updates will be provided

## 7. Limitation of Liability

TO THE MAXIMUM EXTENT PERMITTED BY LAW, WE SHALL NOT BE LIABLE FOR:

- Data loss or corruption
- Loss of profit or revenue
- Interruption of service
- Any indirect, incidental, or consequential damages

Even if we have been advised of the possibility of such damages.

## 8. Termination

We may terminate this license if you:

- Violate any terms of this EULA
- Use the Software for illegal purposes
- Redistribute the Software commercially without permission
- Harass or abuse our team

Upon termination, you must cease using the Software.

## 9. Third-Party Components

The Software may include third-party libraries or assets. You acknowledge and agree to comply with their respective licenses, which are listed in the project repository.

## 10. Governing Law

This EULA is governed by and construed in accordance with applicable laws. Any disputes shall be resolved through negotiation or mediation.

## 11. Changes to This EULA

We may update this EULA at any time. Continued use of the Software constitutes acceptance of changes. We recommend reviewing this EULA periodically.

## 12. Contact

If you have questions about this EULA:

**GitHub**: [Link from site config]  
**Discord**: [Link from site config]

---

**By installing or using this Software, you acknowledge that you have read, understood, and agree to be bound by the terms of this EULA.**

Last Updated: December 2024
{% assign t = site.data[page.lang] %}

<section class="hero">
  <div class="hero-card">
    <h1>{{ t.hero_title }}</h1>
    <p class="muted">{{ t.hero_subtitle }}</p>
    <div class="cta-row">
      <a class="btn primary" href="{{ '/fr/projects/' | relative_url }}">{{ t.browse_projects }}</a>
      <a class="btn ghost" href="{{ '/fr/about/' | relative_url }}">{{ t.learn_more }}</a>
    </div>
  </div>
</section>

<section id="featured" class="section">
  <h2>{{ t.featured_title }}</h2>
  <p class="muted">{{ t.featured_subtitle }}</p>
  
  {% if site.data.modpacks and site.data.modpacks.size > 0 %}
  <div class="featured-spotlight" style="margin-bottom: 2rem;">
    <div class="spotlight-grid">
      {% assign sorted_modpacks = site.data.modpacks | sort: 'date_modified' | reverse %}
      {% for modpack in sorted_modpacks limit:3 %}
      <div class="spotlight-card animate-on-scroll scale-in stagger-{{ forloop.index }}">
        <div class="spotlight-badge">
          <i class="fas fa-star"></i> {{ t.featured_badge }}
        </div>
        <div class="spotlight-image" style="background-image: url('{{ modpack.icon_url }}')"></div>
        <div class="spotlight-content">
          <h3>{{ modpack.name }}</h3>
          <p class="muted">{{ modpack.description | truncate: 100 }}</p>
          <div class="spotlight-meta">
            <span class="meta-item">
              <i class="fas fa-download"></i> {{ modpack.downloads | default: 0 | divided_by: 1000 }}K
            </span>
            <span class="meta-item">
              <i class="fas fa-heart"></i> {{ modpack.followers | default: 0 }}
            </span>
            {% if modpack.game_versions and modpack.game_versions.size > 0 %}
            <span class="meta-item">
              <i class="fas fa-gamepad"></i> {{ modpack.game_versions[0] }}
            </span>
            {% endif %}
          </div>
          <div class="spotlight-actions">
            <a href="{{ modpack.project_url }}" class="btn-spotlight primary" target="_blank" rel="noopener">
              <i class="fas fa-external-link-alt"></i> {{ t.view_project }}
            </a>
            {% if modpack.source_url %}
            <a href="{{ modpack.source_url }}" class="btn-spotlight ghost" target="_blank" rel="noopener">
              <i class="fab fa-github"></i> {{ t.source }}
            </a>
            {% endif %}
          </div>
        </div>
      </div>
      {% endfor %}
    </div>
  </div>
  {% endif %}
  
  {% include modpacks.html %}
</section>

<section class="section" id="project-stats">
  <h2>{{ t.stats_title }}</h2>
  <p class="muted">{{ t.stats_subtitle }}</p>
  <div class="stats-grid" id="stats-grid">
    <div class="stat-card">
      <p class="muted">{{ t.stat_total_projects }}</p>
      <div class="stat-number" id="stat-projects">—</div>
      <div class="stat-sub" id="stat-projects-sub">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_total_downloads }}</p>
      <div class="stat-number" id="stat-downloads">—</div>
      <div class="stat-sub" id="stat-downloads-sub">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_supported_loaders }}</p>
      <div class="stat-number" id="stat-loaders-count">—</div>
      <div class="stat-sub" id="stat-loaders">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_game_versions }}</p>
      <div class="stat-number" id="stat-versions">—</div>
      <div class="stat-sub" id="stat-versions-sub">{{ t.stat_loading }}</div>
    </div>
  </div>
  <div class="card" id="top-categories" style="margin-top:16px;">
    <h3 style="margin-top:0">{{ t.stat_top_categories }}</h3>
    <div id="stat-categories" class="pill-row">{{ t.stat_loading }}</div>
  </div>
  <div class="card" id="downloads-card" style="margin-top:16px;">
    <h3 style="margin-top:0">{{ t.stat_top_downloads }}</h3>
    <p class="muted" id="stat-downloads-note">{{ t.stat_downloads_note }}</p>
    <div class="line-chart" id="downloads-chart"></div>
  </div>
</section>

<section class="section">
  <div class="card">
    <h2 style="margin-top: 0">🚀 Modrinth Organization</h2>
    <div style="display: grid; gap: 16px">
      <p class="muted">Tous nos projets sont publiés et maintenus via Modrinth.</p>
      <a class="btn ghost" href="{{ site.modrinth.organization_url | default: site.social.modrinth }}" target="_blank" rel="noopener">Aller sur Modrinth</a>
    </div>
  </div>
</section>

<script>
  // Load stats from cached mods.json and populate snapshot cards
  document.addEventListener('DOMContentLoaded', async () => {
    const modsUrl = '{{ '/data/mods.json' | relative_url }}';
    const statProjects = document.getElementById('stat-projects');
    const statProjectsSub = document.getElementById('stat-projects-sub');
    const statDownloads = document.getElementById('stat-downloads');
    const statDownloadsSub = document.getElementById('stat-downloads-sub');
    const statLoaders = document.getElementById('stat-loaders');
    const statLoadersCount = document.getElementById('stat-loaders-count');
    const statVersions = document.getElementById('stat-versions');
    const statVersionsSub = document.getElementById('stat-versions-sub');
    const statCategories = document.getElementById('stat-categories');
    const downloadsChart = document.getElementById('downloads-chart');
    const downloadsNote = document.getElementById('stat-downloads-note');

    try {
      const res = await fetch(modsUrl);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const mods = await res.json();
      if (!Array.isArray(mods) || mods.length === 0) throw new Error('{{ t.no_projects_found }}');

      const loaders = new Set();
      const versions = new Set();
      const categories = new Map();
      let totalDownloads = 0;

      mods.forEach(m => {
        (m.loaders || []).forEach(l => loaders.add(l));
        (m.game_versions || []).forEach(v => versions.add(v));
        totalDownloads += Number(m.downloads || 0);
        (m.categories || []).forEach(c => {
          categories.set(c, (categories.get(c) || 0) + 1);
        });
        (m.display_categories || []).forEach(c => {
          categories.set(c, (categories.get(c) || 0) + 1);
        });
      });

      const formatNumber = (n) => n.toLocaleString(undefined, { maximumFractionDigits: 0 });
      
      const t = {
        projects_catalog: '{{ t.stat_projects_catalog }}',
        avg_per_project: '{{ t.stat_avg_per_project }}',
        unique_versions: '{{ t.stat_unique_versions }}',
        no_categories: '{{ t.stat_no_categories }}',
        no_data: '{{ t.stat_no_data }}',
        unavailable: '{{ t.stat_unavailable }}'
      };

      statProjects.textContent = formatNumber(mods.length);
      statProjectsSub.textContent = t.projects_catalog;

      statDownloads.textContent = formatNumber(totalDownloads);
      const avgDownloads = mods.length ? Math.round(totalDownloads / mods.length) : 0;
      statDownloadsSub.textContent = `${formatNumber(avgDownloads)} ${t.avg_per_project}`;

      const loaderList = Array.from(loaders).sort();
      const versionCount = versions.size;

      statLoadersCount.textContent = loaderList.length ? formatNumber(loaderList.length) : '—';
      statLoaders.textContent = loaderList.length ? loaderList.join(', ') : '—';
      statVersions.textContent = versionCount ? formatNumber(versionCount) : '—';
      statVersionsSub.textContent = versionCount ? t.unique_versions : '—';

      const topCats = Array.from(categories.entries())
        .sort((a, b) => b[1] - a[1])
        .slice(0, 6)
        .map(([c, count]) => `<span class="pill">${c} (${count})</span>`) || [];
      statCategories.innerHTML = topCats.length ? topCats.join(' ') : t.no_categories;

      // Top downloads multi-line chart (simulated week data)
      const topDownloads = [...mods]
        .filter(m => typeof m.downloads === 'number')
        .sort((a, b) => (b.downloads || 0) - (a.downloads || 0))
        .slice(0, 11);

      if (topDownloads.length && downloadsChart) {
        downloadsChart.innerHTML = '';
        
        const colors = [
          '#1bd96f', '#10a8e0', '#22d3ee', '#a78bfa', '#f472b6',
          '#fb923c', '#fbbf24', '#4ade80', '#60a5fa', '#c084fc', '#f87171'
        ];

        // Simulate week data with realistic curves (7 days)
        const days = 7;
        const maxValue = Math.max(...topDownloads.map(m => m.downloads || 0));
        
        const chartWrapper = document.createElement('div');
        chartWrapper.style.cssText = 'display:flex;gap:20px;align-items:stretch;margin-bottom:12px;';

        // Left side: chart
        const chartContainer = document.createElement('div');
        chartContainer.style.cssText = 'flex:1;background:var(--bg-primary);border:1px solid var(--border);padding:16px;box-sizing:border-box;position:relative;';

        const svgWrapper = document.createElement('div');
        svgWrapper.style.cssText = 'width:100%;height:240px;position:relative;';
        
        // Tooltip
        const tooltip = document.createElement('div');
        tooltip.style.cssText = 'position:absolute;background:rgba(0,0,0,0.8);color:white;border:1px solid var(--border);padding:8px 12px;border-radius:6px;font-size:12px;pointer-events:none;opacity:0;transition:opacity 0.2s;z-index:10;white-space:nowrap;box-shadow:0 4px 12px rgba(0,0,0,0.4);';
        chartContainer.appendChild(tooltip);

        const width = 800;
        const height = 200;

        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
        svg.setAttribute('preserveAspectRatio', 'none');
        svg.style.cssText = 'width:100%;height:100%;display:block;';

        topDownloads.forEach((mod, idx) => {
          const color = colors[idx % colors.length];
          const baseValue = mod.downloads || 0;
          
          const points = [];
          
          for (let day = 0; day < days; day++) {
            const x = (day / (days - 1)) * width;
            const variance = Math.sin(day * 0.8 + idx) * 0.3 + Math.cos(day * 1.2 - idx) * 0.2;
            const normalizedValue = (baseValue / maxValue) * (0.4 + variance * 0.6);
            const y = height - Math.max(4, Math.min(height - 4, normalizedValue * (height * 0.9)));
            const simulatedDownloads = Math.round(baseValue * normalizedValue);
            points.push({ x, y, downloads: simulatedDownloads, day });
          }

          const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
          const d = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
          path.setAttribute('d', d);
          path.setAttribute('fill', 'none');
          path.setAttribute('stroke', color);
          path.setAttribute('stroke-width', '2');
          path.setAttribute('opacity', '0.85');
          path.style.cursor = 'pointer';
          
          points.forEach(p => {
            const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
            circle.setAttribute('cx', p.x);
            circle.setAttribute('cy', p.y);
            circle.setAttribute('r', '4.5');
            circle.setAttribute('fill', color);
            circle.setAttribute('opacity', '0.9');
            circle.style.cursor = 'pointer';
            svg.appendChild(circle);
          });
          
          path.addEventListener('mouseenter', () => {
            path.setAttribute('stroke-width', '3');
            path.setAttribute('opacity', '1');
          });
          path.addEventListener('mouseleave', () => {
            path.setAttribute('stroke-width', '2');
            path.setAttribute('opacity', '0.85');
            tooltip.style.opacity = '0';
          });
          path.addEventListener('mousemove', (e) => {
            const rect = chartContainer.getBoundingClientRect();
            const svgRect = svg.getBoundingClientRect();
            const relX = ((e.clientX - svgRect.left) / svgRect.width) * width;
            const closestPoint = points.reduce((prev, curr) => 
              Math.abs(curr.x - relX) < Math.abs(prev.x - relX) ? curr : prev
            );
            
            tooltip.innerHTML = `<div style="color:${color};font-weight:600;margin-bottom:2px;">${mod.title || mod.name}</div><div>Jour ${closestPoint.day + 1}: ${formatNumber(closestPoint.downloads)} téléchargements</div>`;
            tooltip.style.opacity = '1';
            tooltip.style.left = Math.min(rect.width - tooltip.offsetWidth - 10, Math.max(10, e.clientX - rect.left + 10)) + 'px';
            tooltip.style.top = Math.max(10, e.clientY - rect.top - 40) + 'px';
          });
          
          svg.appendChild(path);
        });

        svgWrapper.appendChild(svg);
        chartContainer.appendChild(svgWrapper);

        const legendContainer = document.createElement('div');
        legendContainer.style.cssText = 'width:200px;display:flex;flex-direction:column;gap:8px;overflow-y:auto;max-height:240px;padding-right:8px;';
        legendContainer.className = 'line-legend';
        legendContainer.innerHTML = topDownloads.map((m, idx) => {
          const color = colors[idx % colors.length];
          return `<div class="legend-item" style="display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-secondary);"><span style="width:8px;height:8px;border-radius:50%;background:${color};display:inline-block;flex-shrink:0;"></span><span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${m.title || m.name}</span></div>`;
        }).join('');

        chartWrapper.appendChild(chartContainer);
        chartWrapper.appendChild(legendContainer);
        downloadsChart.appendChild(chartWrapper);
      } else if (downloadsNote) {
        downloadsNote.textContent = t.no_data;
      }
    } catch (e) {
      statProjects.textContent = '—';
      statProjectsSub.textContent = t.unavailable;
      statDownloads.textContent = '—';
      statDownloadsSub.textContent = t.unavailable;
      statLoadersCount.textContent = '—';
      statLoaders.textContent = t.unavailable;
      statVersions.textContent = '—';
      statVersionsSub.textContent = t.unavailable;
      statCategories.textContent = `{{ t.error_loading }} ${e.message}`;
      if (downloadsNote) downloadsNote.textContent = `{{ t.error_loading }}`;
      console.warn('{{ t.failed_to_load }}:', e);
    }
  });
</script>
<section class="hero">
  <div class="hero-card">
    <h1>Documentation</h1>
    <p class="muted">Complete guides for setting up, customizing, and contributing to the ABC showcase.</p>
  </div>
</section>

<section class="section">
  <h2 style="margin-bottom: 16px;">Search & Filter</h2>
  <div style="display: flex; gap: 16px; margin-bottom: 32px; flex-wrap: wrap;">
    <input id="docs-search" type="search" placeholder="Search documentation..." style="flex: 1; min-width: 200px; padding: 10px 12px; border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text); border-radius: 6px; font-size: 14px;">
    <select id="docs-category" style="padding: 10px 12px; border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text); border-radius: 6px; font-size: 14px;">
      <option value="">All Categories</option>
      <option value="Setup">Setup</option>
      <option value="Styling">Styling</option>
      <option value="Community">Community</option>
      <option value="Help">Help</option>
      <option value="User Guide">User Guide</option>
      <option value="Developer">Developer</option>
    </select>
  </div>

  <h3 style="margin-bottom: 16px;">Browse by Category</h3>
  <div class="grid docs-grid">
    <a class="card" href="{{ '/docs/category/setup/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-gear" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">Setup</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">Installation & configuration</p>
      </div>
    </a>
    <a class="card" href="{{ '/docs/category/styling/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-palette" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">Styling</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">Themes & customization</p>
      </div>
    </a>
    <a class="card" href="{{ '/docs/category/user-guide/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-book-open" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">User Guide</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">For end users</p>
      </div>
    </a>
    <a class="card" href="{{ '/docs/category/community/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-users" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">Community</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">Contributing & support</p>
      </div>
    </a>
    <a class="card" href="{{ '/docs/category/developer/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-code" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">Developer</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">Technical reference</p>
      </div>
    </a>
    <a class="card" href="{{ '/docs/category/help/' | relative_url }}" style="text-decoration: none; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;">
      <i class="fa-solid fa-circle-question" style="font-size: 24px; color: var(--accent-primary);"></i>
      <div>
        <h3 style="margin: 0;">Help</h3>
        <p class="muted" style="margin: 0; font-size: 13px;">FAQ & troubleshooting</p>
      </div>
    </a>
  </div>

  <h3 style="margin-bottom: 16px;">All Documentation</h3>
  <div id="docs-results" class="grid docs-results-grid">
    <!-- Results will be populated by JavaScript -->
  </div>
  <div id="load-more-container" style="text-align: center; margin-top: 24px; display: none;">
    <button id="load-more-btn" class="btn primary" style="padding: 12px 32px;">
      <i class="fa-solid fa-angle-down"></i>
      Load More
    </button>
  </div>
</section>

<script>
  document.addEventListener('DOMContentLoaded', () => {
    const docs = [
      {% assign sorted_docs = site.docs | sort: 'nav_order' %}
      {% for doc in sorted_docs %}
        {% unless doc.url contains '/category/' %}
        {
          title: {{ doc.title | jsonify }},
          description: {{ doc.description | default: 'No description available' | jsonify }},
          url: {{ doc.url | relative_url | jsonify }},
          category: {{ doc.category | default: 'Other' | jsonify }},
          tags: {{ doc.tags | jsonify }},
          content: {{ doc.content | strip_html | truncatewords: 20 | jsonify }}
        }{% unless forloop.last %},{% endunless %}
        {% endunless %}
      {% endfor %}
    ];

    const searchEl = document.getElementById('docs-search');
    const categoryEl = document.getElementById('docs-category');
    const resultsEl = document.getElementById('docs-results');
    const loadMoreBtn = document.getElementById('load-more-btn');
    const loadMoreContainer = document.getElementById('load-more-container');
    
    let currentFiltered = [];
    let displayCount = 9;
    let isSearching = false;

    function renderDocs(filtered, count = displayCount) {
      currentFiltered = filtered;
      const docsToShow = isSearching ? filtered : filtered.slice(0, count);
      
      resultsEl.innerHTML = docsToShow.length 
        ? docsToShow.map(doc => `
          <div class="card">
            <h3>${doc.title}</h3>
            <p class="muted" style="font-size: 13px; margin-bottom: 12px;">${doc.description}</p>
            <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
              <span style="display: inline-block; padding: 4px 8px; background: var(--bg-secondary); color: var(--text-secondary); border-radius: 4px; font-size: 12px;">${doc.category}</span>
              ${doc.tags.map(tag => `<span style="display: inline-block; padding: 4px 8px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 4px; font-size: 12px;">#${tag}</span>`).join('')}
            </div>
            <a class="btn primary" href="${doc.url}" style="width: 100%; display: block; text-align: center;">Read More</a>
          </div>
        `).join('')
        : '<p class="muted" style="grid-column: 1 / -1; text-align: center;">No documentation found.</p>';
      
      // Show/hide load more button
      if (isSearching || filtered.length <= count) {
        loadMoreContainer.style.display = 'none';
      } else {
        loadMoreContainer.style.display = 'block';
        loadMoreBtn.innerHTML = `<i class="fa-solid fa-angle-down"></i> Load More (${filtered.length - count} remaining)`;
      }
    }

    function filterDocs() {
      const query = searchEl.value.toLowerCase();
      const category = categoryEl.value;
      
      isSearching = !!(query || category);

      const filtered = docs.filter(doc => {
        const matchesSearch = !query || 
          doc.title.toLowerCase().includes(query) ||
          doc.description.toLowerCase().includes(query) ||
          doc.tags.some(tag => tag.toLowerCase().includes(query));
        
        const matchesCategory = !category || doc.category === category;
        
        return matchesSearch && matchesCategory;
      });

      displayCount = 9; // Reset display count when filtering
      renderDocs(filtered);
    }

    loadMoreBtn.addEventListener('click', () => {
      displayCount += 9;
      renderDocs(currentFiltered, displayCount);
    });

    searchEl.addEventListener('input', filterDocs);
    categoryEl.addEventListener('change', filterDocs);

    // Initial render
    renderDocs(docs);
  });
</script>
{% assign t = site.data[page.lang] %}

<section class="hero">
  <div class="hero-card">
    <h1>{{ t.hero_title }}</h1>
    <p class="muted">{{ t.hero_subtitle }}</p>
    <div class="cta-row">
      <a class="btn primary" href="{{ '/projects/' | relative_url }}">{{ t.browse_projects }}</a>
      <a class="btn ghost" href="{{ '/about/' | relative_url }}">{{ t.learn_more }}</a>
    </div>
  </div>
</section>

<section id="featured" class="section">
  <h2>{{ t.featured_title }}</h2>
  <p class="muted">{{ t.featured_subtitle }}</p>
  
  {% if site.data.modpacks and site.data.modpacks.size > 0 %}
  <div class="featured-spotlight" style="margin-bottom: 2rem;">
    <div class="spotlight-grid">
      {% assign sorted_modpacks = site.data.modpacks | sort: 'date_modified' | reverse %}
      {% for modpack in sorted_modpacks limit:3 %}
      <div class="spotlight-card animate-on-scroll scale-in stagger-{{ forloop.index }}">
        <div class="spotlight-badge">
          <i class="fas fa-star"></i> {{ t.featured_badge }}
        </div>
        <div class="spotlight-image" style="background-image: url('{{ modpack.icon_url }}')"></div>
        <div class="spotlight-content">
          <h3>{{ modpack.name }}</h3>
          <p class="muted">{{ modpack.description | truncate: 100 }}</p>
          <div class="spotlight-meta">
            <span class="meta-item">
              <i class="fas fa-download"></i> {{ modpack.downloads | default: 0 | divided_by: 1000 }}K
            </span>
            <span class="meta-item">
              <i class="fas fa-heart"></i> {{ modpack.followers | default: 0 }}
            </span>
            {% if modpack.game_versions and modpack.game_versions.size > 0 %}
            <span class="meta-item">
              <i class="fas fa-gamepad"></i> {{ modpack.game_versions[0] }}
            </span>
            {% endif %}
          </div>
          <div class="spotlight-actions">
            <a href="{{ modpack.project_url }}" class="btn-spotlight primary" target="_blank" rel="noopener">
              <i class="fas fa-external-link-alt"></i> {{ t.view_project }}
            </a>
            {% if modpack.source_url %}
            <a href="{{ modpack.source_url }}" class="btn-spotlight ghost" target="_blank" rel="noopener">
              <i class="fab fa-github"></i> {{ t.source }}
            </a>
            {% endif %}
          </div>
        </div>
      </div>
      {% endfor %}
    </div>
  </div>
  {% endif %}
  
  {% include modpacks.html %}
</section>

<section class="section" id="project-stats">
  <h2>{{ t.stats_title }}</h2>
  <p class="muted">{{ t.stats_subtitle }}</p>
  <div class="stats-grid" id="stats-grid">
    <div class="stat-card">
      <p class="muted">{{ t.stat_total_projects }}</p>
      <div class="stat-number" id="stat-projects">—</div>
      <div class="stat-sub" id="stat-projects-sub">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_total_downloads }}</p>
      <div class="stat-number" id="stat-downloads">—</div>
      <div class="stat-sub" id="stat-downloads-sub">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_supported_loaders }}</p>
      <div class="stat-number" id="stat-loaders-count">—</div>
      <div class="stat-sub" id="stat-loaders">{{ t.stat_loading }}</div>
    </div>
    <div class="stat-card">
      <p class="muted">{{ t.stat_game_versions }}</p>
      <div class="stat-number" id="stat-versions">—</div>
      <div class="stat-sub" id="stat-versions-sub">{{ t.stat_loading }}</div>
    </div>
  </div>
  <div class="card" id="top-categories" style="margin-top:16px;">
    <h3 style="margin-top:0">{{ t.stat_top_categories }}</h3>
    <div id="stat-categories" class="pill-row">{{ t.stat_loading }}</div>
  </div>
  <div class="card" id="downloads-card" style="margin-top:16px;">
    <h3 style="margin-top:0">{{ t.stat_top_downloads }}</h3>
    <p class="muted" id="stat-downloads-note">{{ t.stat_downloads_note }}</p>
    <div class="line-chart" id="downloads-chart"></div>
  </div>
</section>

{% assign featured_docs = site.docs | sort: 'nav_order' | slice: 0, 3 %}
{% if featured_docs and featured_docs.size > 0 %}

<section class="section" id="featured-docs">
  <h2>Docs Spotlight</h2>
  <p class="muted">Quick links to key guides</p>
  <div class="grid">
    {% for doc in featured_docs %}
      <a class="card" href="{{ doc.url | relative_url }}" style="text-decoration:none">
        <h3 style="margin-top:0">{{ doc.title }}</h3>
        {% if doc.description %}<p class="muted">{{ doc.description }}</p>{% else %}<p class="muted">Read more</p>{% endif %}
        <span class="pill">Docs</span>
      </a>
    {% endfor %}
  </div>
</section>
{% endif %}

<section class="section">
  <h2>How It Works</h2>
  <div class="grid">
    <div class="card">
      <h3><i class="fa-solid fa-box"></i> Static Content</h3>
      <p>All projects are stored as static data. No database needed.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-arrows-rotate"></i> Auto-Update</h3>
      <p>Daily syncs from Modrinth keep your showcase fresh.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-bolt"></i> Lightning Fast</h3>
      <p>Deployed globally on GitHub Pages for instant loading.</p>
    </div>
    <div class="card">
      <h3><i class="fa-solid fa-palette"></i> Beautiful</h3>
      <p>Modern design with smooth animations and blur effects.</p>
    </div>
  </div>
</section>

<section class="section">
  <h2>Get Started</h2>
  <div class="grid">
    <div class="card">
      <h3>Read the Docs</h3>
      <p class="muted">Configure branding, fetch projects, and deploy.</p>
      <a class="btn primary" href="{{ '/docs/' | relative_url }}">Open Docs</a>
    </div>
    <div class="card">
      <h3>Browse Projects</h3>
      <p class="muted">Filter by type, loader, or version.</p>
      <a class="btn primary" href="{{ '/projects/' | relative_url }}">View Catalog</a>
    </div>
    <div class="card">
      <h3>Sync from Modrinth</h3>
      <p class="muted">Run <code>npm run fetch</code> or use the scheduled workflow.</p>
      <a class="btn ghost" href="{{ '/docs/' | relative_url }}">See Setup</a>
    </div>
  </div>
</section>

<section class="section">
  <h2>Stay in the Loop</h2>
  <div class="grid">
    <div class="card">
      <h3>Join Discord</h3>
      <p class="muted">Get support, share feedback, and see previews.</p>
      <a class="btn ghost" href="{{ site.social.discord }}" target="_blank" rel="noopener">Open Discord</a>
    </div>
    <div class="card">
      <h3>Watch GitHub</h3>
      <p class="muted">Track updates, file issues, or contribute.</p>
      <a class="btn ghost" href="{{ site.social.github }}" target="_blank" rel="noopener">View Repo</a>
    </div>
    <div class="card">
      <h3>Follow Modrinth</h3>
      <p class="muted">Stay updated on releases across all projects.</p>
      <a class="btn ghost" href="{{ site.modrinth.organization_url | default: site.social.modrinth }}" target="_blank" rel="noopener">Go to Modrinth</a>
    </div>
  </div>
</section>

<script>
  // Load stats from cached mods.json and populate snapshot cards
  document.addEventListener('DOMContentLoaded', async () => {
    const modsUrl = '{{ '/data/mods.json' | relative_url }}';
    const statProjects = document.getElementById('stat-projects');
    const statProjectsSub = document.getElementById('stat-projects-sub');
    const statDownloads = document.getElementById('stat-downloads');
    const statDownloadsSub = document.getElementById('stat-downloads-sub');
    const statLoaders = document.getElementById('stat-loaders');
    const statLoadersCount = document.getElementById('stat-loaders-count');
    const statVersions = document.getElementById('stat-versions');
    const statVersionsSub = document.getElementById('stat-versions-sub');
    const statCategories = document.getElementById('stat-categories');
    const downloadsChart = document.getElementById('downloads-chart');
    const downloadsNote = document.getElementById('stat-downloads-note');

    try {
      const res = await fetch(modsUrl);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const mods = await res.json();
      if (!Array.isArray(mods) || mods.length === 0) throw new Error('No projects found');

      const loaders = new Set();
      const versions = new Set();
      const categories = new Map();
      let totalDownloads = 0;

      mods.forEach(m => {
        (m.loaders || []).forEach(l => loaders.add(l));
        (m.game_versions || []).forEach(v => versions.add(v));
        totalDownloads += Number(m.downloads || 0);
        (m.categories || []).forEach(c => {
          categories.set(c, (categories.get(c) || 0) + 1);
        });
        (m.display_categories || []).forEach(c => {
          categories.set(c, (categories.get(c) || 0) + 1);
        });
      });

      const formatNumber = (n) => n.toLocaleString(undefined, { maximumFractionDigits: 0 });
      
      const t = {
        projects_catalog: '{{ t.stat_projects_catalog }}',
        avg_per_project: '{{ t.stat_avg_per_project }}',
        unique_versions: '{{ t.stat_unique_versions }}',
        no_categories: '{{ t.stat_no_categories }}',
        no_data: '{{ t.stat_no_data }}',
        unavailable: '{{ t.stat_unavailable }}'
      };

      statProjects.textContent = formatNumber(mods.length);
      statProjectsSub.textContent = t.projects_catalog;

      statDownloads.textContent = formatNumber(totalDownloads);
      const avgDownloads = mods.length ? Math.round(totalDownloads / mods.length) : 0;
      statDownloadsSub.textContent = `${formatNumber(avgDownloads)} ${t.avg_per_project}`;

      const loaderList = Array.from(loaders).sort();
      const versionCount = versions.size;

      statLoadersCount.textContent = loaderList.length ? formatNumber(loaderList.length) : '—';
      statLoaders.textContent = loaderList.length ? loaderList.join(', ') : '—';
      statVersions.textContent = versionCount ? formatNumber(versionCount) : '—';
      statVersionsSub.textContent = versionCount ? t.unique_versions : '—';

      const topCats = Array.from(categories.entries())
        .sort((a, b) => b[1] - a[1])
        .slice(0, 6)
        .map(([c, count]) => `<span class="pill">${c} (${count})</span>`) || [];
      statCategories.innerHTML = topCats.length ? topCats.join(' ') : t.no_categories;

      // Top downloads multi-line chart (simulated week data)
      const topDownloads = [...mods]
        .filter(m => typeof m.downloads === 'number')
        .sort((a, b) => (b.downloads || 0) - (a.downloads || 0))
        .slice(0, 11);

      if (topDownloads.length && downloadsChart) {
        downloadsChart.innerHTML = '';
        
        const colors = [
          '#1bd96f', '#10a8e0', '#22d3ee', '#a78bfa', '#f472b6',
          '#fb923c', '#fbbf24', '#4ade80', '#60a5fa', '#c084fc', '#f87171'
        ];

        // Simulate week data with realistic curves (7 days)
        const days = 7;
        const maxValue = Math.max(...topDownloads.map(m => m.downloads || 0));
        
        const chartWrapper = document.createElement('div');
        chartWrapper.style.cssText = 'display:flex;gap:20px;align-items:stretch;margin-bottom:12px;';

        // Left side: chart
        const chartContainer = document.createElement('div');
        chartContainer.style.cssText = 'flex:1;background:var(--bg-primary);border:1px solid var(--border);padding:16px;box-sizing:border-box;position:relative;';

        const svgWrapper = document.createElement('div');
        svgWrapper.style.cssText = 'width:100%;height:240px;position:relative;';
        
        // Tooltip
        const tooltip = document.createElement('div');
        tooltip.style.cssText = 'position:absolute;background:rgba(0,0,0,0.8);color:white;border:1px solid var(--border);padding:8px 12px;border-radius:6px;font-size:12px;pointer-events:none;opacity:0;transition:opacity 0.2s;z-index:10;white-space:nowrap;box-shadow:0 4px 12px rgba(0,0,0,0.4);';
        chartContainer.appendChild(tooltip);

        // Use actual pixel dimensions
        const width = 800;  // Fixed width for consistent rendering
        const height = 200; // Fixed height

        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
        svg.setAttribute('preserveAspectRatio', 'none');
        svg.style.cssText = 'width:100%;height:100%;display:block;';

        topDownloads.forEach((mod, idx) => {
          const color = colors[idx % colors.length];
          const baseValue = mod.downloads || 0;
          
          // Generate smooth curve with variation
          const points = [];
          
          for (let day = 0; day < days; day++) {
            const x = (day / (days - 1)) * width;
            const variance = Math.sin(day * 0.8 + idx) * 0.3 + Math.cos(day * 1.2 - idx) * 0.2;
            const normalizedValue = (baseValue / maxValue) * (0.4 + variance * 0.6);
            const y = height - Math.max(4, Math.min(height - 4, normalizedValue * (height * 0.9)));
            const simulatedDownloads = Math.round(baseValue * normalizedValue);
            points.push({ x, y, downloads: simulatedDownloads, day });
          }

          const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
          const d = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
          path.setAttribute('d', d);
          path.setAttribute('fill', 'none');
          path.setAttribute('stroke', color);
          path.setAttribute('stroke-width', '2');
          path.setAttribute('opacity', '0.85');
          path.style.cursor = 'pointer';
          
          // Add dots at each data point
          points.forEach(p => {
            const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
            circle.setAttribute('cx', p.x);
            circle.setAttribute('cy', p.y);
            circle.setAttribute('r', '4.5');
            circle.setAttribute('fill', color);
            circle.setAttribute('opacity', '0.9');
            circle.style.cursor = 'pointer';
            svg.appendChild(circle);
          });
          
          // Hover effect
          path.addEventListener('mouseenter', () => {
            path.setAttribute('stroke-width', '3');
            path.setAttribute('opacity', '1');
          });
          path.addEventListener('mouseleave', () => {
            path.setAttribute('stroke-width', '2');
            path.setAttribute('opacity', '0.85');
            tooltip.style.opacity = '0';
          });
          path.addEventListener('mousemove', (e) => {
            const rect = chartContainer.getBoundingClientRect();
            const svgRect = svg.getBoundingClientRect();
            const relX = ((e.clientX - svgRect.left) / svgRect.width) * width;
            const closestPoint = points.reduce((prev, curr) => 
              Math.abs(curr.x - relX) < Math.abs(prev.x - relX) ? curr : prev
            );
            
            tooltip.innerHTML = `<div style="color:${color};font-weight:600;margin-bottom:2px;">${mod.title || mod.name}</div><div>Day ${closestPoint.day + 1}: ${formatNumber(closestPoint.downloads)} downloads</div>`;
            tooltip.style.opacity = '1';
            tooltip.style.left = Math.min(rect.width - tooltip.offsetWidth - 10, Math.max(10, e.clientX - rect.left + 10)) + 'px';
            tooltip.style.top = Math.max(10, e.clientY - rect.top - 40) + 'px';
          });
          
          svg.appendChild(path);
        });

        svgWrapper.appendChild(svg);
        chartContainer.appendChild(svgWrapper);

        // Right side: legend
        const legendContainer = document.createElement('div');
        legendContainer.style.cssText = 'width:200px;display:flex;flex-direction:column;gap:8px;overflow-y:auto;max-height:240px;padding-right:8px;';
        legendContainer.className = 'line-legend';
        legendContainer.innerHTML = topDownloads.map((m, idx) => {
          const color = colors[idx % colors.length];
          return `<div class="legend-item" style="display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-secondary);"><span style="width:8px;height:8px;border-radius:50%;background:${color};display:inline-block;flex-shrink:0;"></span><span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${m.title || m.name}</span></div>`;
        }).join('');

        chartWrapper.appendChild(chartContainer);
        chartWrapper.appendChild(legendContainer);
        downloadsChart.appendChild(chartWrapper);
      } else if (downloadsNote) {
        downloadsNote.textContent = t.no_data;
      }
    } catch (e) {
      statProjects.textContent = '—';
      statProjectsSub.textContent = t.unavailable;
      statDownloads.textContent = '—';
      statDownloadsSub.textContent = t.unavailable;
      statLoadersCount.textContent = '—';
      statLoaders.textContent = t.unavailable;
      statVersions.textContent = '—';
      statVersionsSub.textContent = t.unavailable;
      statCategories.textContent = `{{ t.error_loading }} ${e.message}`;
      if (downloadsNote) downloadsNote.textContent = `{{ t.error_loading }}`;
      console.warn('{{ t.failed_to_load }}:', e);
    }
  });
</script>
# Licensing & Attribution

**Last Updated:** December 2024

This page outlines the licenses used across our projects and how to properly attribute them.

## Project Licenses

| Project       | License   | Repository | Key Terms                           |
| ------------- | --------- | ---------- | ----------------------------------- |
| Core Projects | MIT       | GitHub     | Permissive; attribution appreciated |
| Datapacks     | CC0 / MIT | GitHub     | Check individual README             |
| Plugins       | MIT       | GitHub     | Permissive; include license         |
| Documentation | CC-BY-4.0 | This Site  | Attribute ABC Team                  |

## MIT License Summary

**Permissions**:

- ✅ Commercial use
- ✅ Modification
- ✅ Distribution
- ✅ Private use

**Conditions**:

- ⚠️ Include license and copyright notice
- ⚠️ Disclose changes

**Limitations**:

- ❌ No liability
- ❌ No warranty

## Creative Commons (CC-BY-4.0)

Used for documentation and educational content.

**You are free to**:

- Share the material
- Adapt and remix
- Use commercially

**You must**:

- Give appropriate credit
- Provide a link to the license
- Indicate if changes were made

## How to Attribute

### For Code

Based on ABC Team’s [Project Name] License: MIT Source: https://github.com/devvyyxyz/[repo]


### For Documentation

Content adapted from ABC Team License: CC-BY-4.0 Source: [abc-site-url]


### For Derivative Projects

If you create a modified version:

1. Include the original license file
2. Add a notice of modifications
3. State the original source
4. Link to our GitHub

Example:

This project is based on ABC Team’s [Original Project] Original License: MIT Original Source: https://github.com/devvyyxyz/[repo] Modifications: [describe changes]


## Third-Party Dependencies

Our projects use open-source libraries. See `LICENSE` and `LICENSES/` directories in each repository for full details.

### Common Dependencies

| Dependency | License    | Link                                                       |
| ---------- | ---------- | ---------------------------------------------------------- |
| Fabric API | Apache 2.0 | [GitHub](https://github.com/FabricMC/fabric)               |
| Forge      | LGPL 2.1   | [GitHub](https://github.com/MinecraftForge/MinecraftForge) |
| Quilt      | Apache 2.0 | [GitHub](https://github.com/QuiltMC)                       |

## Minecraft & Mojang

Our projects are designed for Minecraft and follow Mojang's Brand and Asset Guidelines:

- Minecraft is owned by Mojang Studios / Microsoft
- Our projects are independent community mods
- We do not sell Minecraft or charge for access
- See [Minecraft EULA](https://account.mojang.com/terms)

## Using Our Projects Commercially

**Yes, you can use our projects commercially!**

**Requirements**:

1. Include the MIT license file
2. Attribute ABC Team in credits or documentation
3. Disclose if you modified the software
4. Provide source code access (for MIT)

**Server Usage**:

- Personal servers: Fully permitted
- Public servers: Permitted with attribution
- Paid servers: Permitted (no revenue share)

**Content Creation**:

- YouTube/Twitch: Fully permitted (no permission needed)
- Monetization: Fully permitted (no revenue share)
- Attribution appreciated but not required

## Questions About Licensing

- **Can I sell modifications?** No. Modified versions must remain free.
- **Can I bundle your code?** Yes, if you include the license.
- **Can I relicense your code?** Only under compatible licenses (MIT to Apache 2.0, etc.).
- **Can I use your code in closed-source?** No. MIT requires source disclosure or available code.

## Dispute Resolution

If you believe our projects infringe on your intellectual property, please contact us:

**Email**: [contact from config]  
**GitHub Issues**: [Repository link]

We will respond within 7 days to address concerns.

---

**Our Mission**: Create amazing, free, open-source mods and tools for the Minecraft community.

For the full legal text of each license, see the `LICENSE` file in each repository.
<section class="section">
  <h1>Privacy Policy</h1>
  <p class="muted">How we collect, use, and protect information on this site.</p>

  <h2>What we collect</h2>
  <ul>
    <li>No account data is collected by this static site.</li>
    <li>Server logs (via hosting) may include IP address, user-agent, and request metadata for basic operations and security.</li>
    <li>If you submit feedback (e.g., the docs widget), it is stored locally in your browser only.</li>
  </ul>

  <h2>Cookies & storage</h2>
  <ul>
    <li>Theme and feedback choices are stored in <code>localStorage</code> for your convenience.</li>
    <li>No tracking or advertising cookies are set by this site.</li>
  </ul>

  <h2>Third-party links</h2>
  <p>Links to Modrinth, GitHub, and Discord follow their respective privacy policies.</p>

  <h2>Contact</h2>
  <p>Questions or removal requests? <a href="{{ '/contact/' | relative_url }}">Contact us</a>.</p>
</section>
<section class="hero">
  <div class="hero-card">
    <h1>Browse All Projects</h1>
    <p class="muted">Explore our curated collection of mods, resource packs, datapacks, modpacks, and plugins.</p>
  </div>
</section>

<section class="section">
  <h1>Projects</h1>
  <p class="muted">Latest projects from ABC organization</p>

  <div class="filters" id="projects-filters">
    <input id="filter-search" type="search" placeholder="Search projects..." aria-label="Search projects">
    <select id="filter-type" aria-label="Filter by type">
      <option value="all">All types</option>
    </select>
    <select id="filter-loader" aria-label="Filter by loader">
      <option value="all">All loaders</option>
    </select>
    <select id="filter-version" aria-label="Filter by version">
      <option value="all">All versions</option>
    </select>
  </div>

  <div id="projects-count" class="muted" style="margin-top:10px"></div>
  <div id="mods-list" class="modpacks-list"></div>
</section>

<script>
  // Load projects from cached JSON file with filtering and rich metadata
  document.addEventListener('DOMContentLoaded', async () => {
    const container = document.getElementById('mods-list');
    const countEl = document.getElementById('projects-count');
    const searchEl = document.getElementById('filter-search');
    const typeEl = document.getElementById('filter-type');
    const loaderEl = document.getElementById('filter-loader');
    const versionEl = document.getElementById('filter-version');

    const state = {
      projects: [],
      filters: { search: '', type: 'all', loader: 'all', version: 'all' }
    };

    // Base options so filters always have choices even if data is missing them
    const baseTypes = ['mod', 'modpack', 'datapack', 'resourcepack', 'plugin', 'shader', 'world', 'library'];
    const baseLoaders = ['fabric', 'forge', 'quilt', 'neoforge', 'liteloader', 'rift', 'bukkit', 'paper', 'purpur', 'datapack', 'minecraft', 'resourcepack', 'shaders'];
    const baseVersions = ['1.16', '1.16.5', '1.17.1', '1.18.2', '1.19.4', '1.20', '1.20.1', '1.20.2', '1.20.4', '1.20.6', '1.21', '1.21.1', '1.21.2', '1.21.3', '1.21.4', '1.21.5'];

    function formatDate(value) {
      if (!value) return 'Unknown';
      const d = new Date(value);
      if (Number.isNaN(d.getTime())) return 'Unknown';
      return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
    }

    function populateFilters(items) {
      const types = new Set(baseTypes);
      const loaders = new Set(baseLoaders);
      const versions = new Set(baseVersions);

      items.forEach(p => {
        if (p.project_type) types.add(p.project_type);
        (p.loaders || []).forEach(l => loaders.add(l));
        (p.game_versions || []).forEach(v => versions.add(v));
      });

      typeEl.innerHTML = '<option value="all">All types</option>' +
        Array.from(types).sort().map(t => `<option value="${t}">${t}</option>`).join('');
      loaderEl.innerHTML = '<option value="all">All loaders</option>' +
        Array.from(loaders).sort().map(l => `<option value="${l}">${l}</option>`).join('');
      versionEl.innerHTML = '<option value="all">All versions</option>' +
        Array.from(versions).sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })).map(v => `<option value="${v}">${v}</option>`).join('');
    }

    function applyFilters() {
      let items = [...state.projects];
      const { search, type, loader, version } = state.filters;

      if (search) {
        const q = search.toLowerCase();
        items = items.filter(p => (
          (p.title || p.name || '').toLowerCase().includes(q) ||
          (p.short_description || '').toLowerCase().includes(q)
        ));
      }

      if (type !== 'all') {
        items = items.filter(p => (p.project_type || p.type) === type);
      }

      if (loader !== 'all') {
        items = items.filter(p => (p.loaders || []).includes(loader));
      }

      if (version !== 'all') {
        items = items.filter(p => (p.game_versions || []).includes(version));
      }

      renderProjects(items);
    }

    function renderProjects(items) {
      if (!items.length) {
        container.innerHTML = '<p class="muted">No projects found for this filter.</p>';
        countEl.textContent = '0 projects';
        return;
      }

      container.innerHTML = '';
      countEl.textContent = `${items.length} project${items.length === 1 ? '' : 's'}`;

      items.forEach((m, i) => {
        const el = document.createElement('div');
        el.className = 'modpack';
        el.style.animationDelay = (i * 60) + 'ms';

        // Generate project slug for detail page link
        const slug = (m.slug || m.title.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''));
        const detailPageUrl = `/abc-site/projects/${slug}/`;

        const thumb = document.createElement('div');
        thumb.className = 'thumb';
        thumb.style.backgroundImage = `url(${m.icon_url || m.thumbnail || '/assets/images/favicon.svg'})`;
        thumb.style.cursor = 'pointer';
        thumb.addEventListener('click', () => window.location.href = detailPageUrl);

        const meta = document.createElement('div');
        meta.className = 'meta';
        meta.style.cursor = 'pointer';
        meta.addEventListener('click', () => window.location.href = detailPageUrl);
        const shortDesc = m.short_description || m.summary || m.description || '';
        const desc = shortDesc.length > 160 ? `${shortDesc.substring(0, 160)}...` : shortDesc;
        const versions = (m.game_versions || []).slice(-3).reverse();
        const loaders = (m.loaders || []).slice(0, 3);

        const pill = (label, icon) => `<span class="pill">${icon ? `<i class="fa-solid fa-${icon}"></i>` : ''}${label}</span>`;
        const metaInfo = [
          m.updated || m.published ? pill(`Updated ${formatDate(m.updated || m.published)}`, 'clock') : '',
          versions.length ? pill(`MC ${versions.join(', ')}`, 'cube') : '',
          loaders.length ? pill(`Loaders: ${loaders.join(', ')}`, 'cogs') : '',
          m.license_id ? pill(`License: ${m.license_id}`, 'file-alt') : ''
        ].filter(Boolean).join('');

        meta.innerHTML = `
          <h3>${m.title || m.name}</h3>
          <p>${desc}</p>
        `;

        const pillSection = document.createElement('div');
        pillSection.className = 'pill-section';
        const metaInfoHTML = [
          m.updated || m.published ? pill(`Updated ${formatDate(m.updated || m.published)}`, 'clock') : '',
          versions.length ? pill(`MC ${versions.join(', ')}`, 'cube') : '',
          loaders.length ? pill(`Loaders: ${loaders.join(', ')}`, 'cogs') : '',
          m.license_id ? pill(`License: ${m.license_id}`, 'file-alt') : ''
        ].filter(Boolean).join('');
        
        const categoriesHTML = (m.display_categories || m.categories || []).slice(0, 4).map(c => `<span class="pill">#${c}</span>`).join(' ');
        
        pillSection.innerHTML = `${metaInfoHTML} ${categoriesHTML}`;

        const action = document.createElement('div');
        action.className = 'actions';
        
        // Check if source_url exists (GitHub link)
        const sourceUrl = m.source_url || m.repository;
        
        let buttonsHTML = '';
        buttonsHTML += `<a class="btn primary" href="${detailPageUrl}" title="View details">Details</a>`;
        if (sourceUrl) {
          buttonsHTML += `<a class="btn secondary" href="${sourceUrl}" target="_blank" rel="noopener" title="View source"><i class="fa-brands fa-github"></i></a>`;
        }
        buttonsHTML += `<a class="btn ghost" href="${m.download || `https://modrinth.com/mod/${m.slug}`}" target="_blank" rel="noopener">View</a>`;
        
        action.innerHTML = buttonsHTML;

        el.appendChild(thumb);
        el.appendChild(meta);
        el.appendChild(pillSection);
        el.appendChild(action);
        container.appendChild(el);
      });
    }

    function handleFilterChange() {
      state.filters = {
        search: searchEl.value.trim(),
        type: typeEl.value,
        loader: loaderEl.value,
        version: versionEl.value
      };
      applyFilters();
    }

    // Wire up filters
    searchEl.addEventListener('input', () => {
      state.filters.search = searchEl.value.trim();
      applyFilters();
    });
    [typeEl, loaderEl, versionEl].forEach(el => el.addEventListener('change', handleFilterChange));

    try {
      const res = await fetch('{{ '/data/mods.json' | relative_url }}');
      if (!res.ok) throw new Error(`HTTP ${res.status}: Failed to load projects`);
      const projects = await res.json();

      if (!Array.isArray(projects) || projects.length === 0) {
        container.innerHTML = '<p class="muted">No projects found. Projects will be synced automatically.</p>';
        return;
      }

      // Sort newest updated first
      state.projects = projects.sort((a, b) => new Date(b.updated || b.published || 0) - new Date(a.updated || a.published || 0));
      populateFilters(state.projects);
      applyFilters();
    } catch (e) {
      console.error('Failed to load projects:', e);
      container.innerHTML = `<p class="muted">Error: ${e.message}</p>`;
    }
  });
</script>
<section class="hero">
  <div class="hero-card">
    <h1>Documentation Overview</h1>
    <p class="muted">Complete reference of all available guides and resources.</p>
  </div>
</section>

<section class="section">
  <h2>📚 All Documentation Pages</h2>

  <h3>Setup & Configuration (2 pages)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/getting-started/' | relative_url }}">Getting Started</a></strong> — Quick start guide for new users</li>
    <li><strong><a href="{{ '/docs/setup/' | relative_url }}">Setup & Configuration</a></strong> — Detailed setup and Modrinth integration instructions</li>
  </ul>

  <h3>Styling & Customization (1 page)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/customization/' | relative_url }}">Customization</a></strong> — Theming, colors, and CSS customization</li>
  </ul>

  <h3>Community & Contributing (1 page)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/contributing/' | relative_url }}">Contributing</a></strong> — Guidelines for contributors and pull requests</li>
  </ul>

  <h3>Help & Troubleshooting (2 pages)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/faq/' | relative_url }}">FAQ</a></strong> — Frequently asked questions</li>
    <li><strong><a href="{{ '/docs/troubleshooting/' | relative_url }}">Troubleshooting</a></strong> — Common issues and solutions</li>
  </ul>

  <h3>User Guide (1 page)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/how-to-install/' | relative_url }}">How to Install</a></strong> — Step-by-step installation guide</li>
  </ul>

  <h3>Developer Resources (3 pages)</h3>
  <ul style="list-style: none; padding: 0;">
    <li><strong><a href="{{ '/docs/api-reference/' | relative_url }}">API Reference</a></strong> — Project data structure and Modrinth API</li>
    <li><strong><a href="{{ '/docs/project-structure/' | relative_url }}">Project Structure</a></strong> — File organization and architecture</li>
    <li><strong><a href="{{ '/docs/troubleshooting/' | relative_url }}">Troubleshooting</a></strong> — Debugging and common errors</li>
  </ul>

</section>

<section class="section">
  <h2>🏷️ Tag Cloud</h2>
  <div style="display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 24px;">
    {% assign all_tags = site.docs | map: "tags" | join: "," | default: "" | split: "," | uniq | sort %}
    {% for tag in all_tags %}
      {% if tag != "" %}
        <span style="display: inline-block; padding: 6px 12px; background: rgba(27, 217, 111, 0.1); color: var(--accent-primary); border-radius: 999px; border: 1px solid var(--accent-primary); font-size: 13px; cursor: pointer;" onclick="document.location.href='{{ '/docs/' | relative_url }}?filter={{ tag }}'">
          #{{ tag }}
        </span>
      {% endif %}
    {% endfor %}
  </div>
</section>

<section class="section">
  <h2>📂 Browse by Category</h2>
  <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px;">
    <a class="card" href="{{ '/docs/category/setup/' | relative_url }}" style="text-decoration: none;">
      <h3>⚙️ Setup</h3>
      <p class="muted">Installation and configuration guides</p>
    </a>
    <a class="card" href="{{ '/docs/category/styling/' | relative_url }}" style="text-decoration: none;">
      <h3>🎨 Styling</h3>
      <p class="muted">Theming and customization</p>
    </a>
    <a class="card" href="{{ '/docs/category/user-guide/' | relative_url }}" style="text-decoration: none;">
      <h3>📖 User Guide</h3>
      <p class="muted">For end users and managers</p>
    </a>
    <a class="card" href="{{ '/docs/category/community/' | relative_url }}" style="text-decoration: none;">
      <h3>🤝 Community</h3>
      <p class="muted">Contributing and support</p>
    </a>
    <a class="card" href="{{ '/docs/category/developer/' | relative_url }}" style="text-decoration: none;">
      <h3>💻 Developer</h3>
      <p class="muted">Technical reference</p>
    </a>
    <a class="card" href="{{ '/docs/category/help/' | relative_url }}" style="text-decoration: none;">
      <h3>❓ Help</h3>
      <p class="muted">FAQ and troubleshooting</p>
    </a>
  </div>
</section>

<section class="section">
  <h2>🔍 Quick Search</h2>
  <p class="muted">Use the <a href="{{ '/docs/' | relative_url }}">main documentation page</a> to search and filter all guides by keyword or category.</p>
</section>
<section class="section">
  <h1>Terms of Use</h1>
  <p class="muted">Guidelines for using this site and its content.</p>

  <h2>Content</h2>
  <ul>
    <li>Downloads link to Modrinth or other platforms; their licenses govern use.</li>
    <li>Site content is provided "as is" without warranties.</li>
  </ul>

  <h2>Acceptable use</h2>
  <ul>
    <li>Do not misuse the site, attempt to break security, or scrape abusively.</li>
    <li>Respect the licenses of each mod, pack, or resource.</li>
  </ul>

  <h2>Attribution</h2>
  <p>Credit the project authors as listed on their respective pages and licenses.</p>

  <h2>Contact</h2>
  <p>Questions? <a href="{{ '/contact/' | relative_url }}">Contact us</a>.</p>
</section>
# Testing & Validation Checklist

## 1. Polish & Preloader Testing

### Preloader Functionality
- [ ] Preloader appears on page load
- [ ] Preloader spinner animates smoothly
- [ ] Preloader hides after page content loads
- [ ] No content visible behind preloader during load

### Responsive Scaling
- [ ] Hero section scales properly on mobile (320px)
- [ ] Navigation responsive at tablet (768px) and desktop (1200px)
- [ ] Typography scales fluidly using clamp()
- [ ] Grid gaps adjust based on viewport width
- [ ] Buttons and cards maintain proper spacing on all screens

### Cross-browser Testing
- [ ] Chrome/Chromium: Full functionality
- [ ] Firefox: Full functionality
- [ ] Safari: Full functionality
- [ ] Mobile Safari: Responsive and preloader works
- [ ] Edge: Full functionality

---

## 2. Theme Toggle & Animations

### Dark/Light Mode Toggle
- [ ] Toggle button appears in nav
- [ ] Dark mode applies correct CSS variables
- [ ] Light mode applies correct CSS variables
- [ ] Theme preference persists in localStorage
- [ ] System preference detected on first visit
- [ ] Respects prefers-color-scheme
- [ ] Both themes have sufficient contrast

### Enhanced Animations
- [ ] Card entries animate on page load
- [ ] Stat cards stagger animation works
- [ ] Button ripple effect on click
- [ ] Smooth scroll behavior enabled
- [ ] Page transitions fade smoothly
- [ ] Focus states visible and animated

---

## 3. Performance Optimization

### Lazy Loading
- [ ] Images load only when scrolled into view
- [ ] Fallback works for older browsers
- [ ] Performance impact measured

### Resource Optimization
- [ ] Critical CSS inlined in head
- [ ] Non-critical CSS deferred
- [ ] JavaScript split and loaded asynchronously
- [ ] Unused styles removed
- [ ] Images optimized and compressed

### Scroll to Top Button
- [ ] Button appears after scrolling 300px down
- [ ] Button scrolls page smoothly to top
- [ ] Button disappears when at top
- [ ] Keyboard accessible (Enter/Space)

---

## 4. SEO & Content Structure

### Sitemap & Robots
- [ ] sitemap.xml generates correctly
- [ ] robots.txt blocks aggressive crawlers
- [ ] Canonical URLs set on all pages
- [ ] Meta descriptions present

### Schema Markup
- [ ] Organization schema correct
- [ ] Breadcrumb schema renders properly
- [ ] Article/Page schema includes date
- [ ] Schema validates with Google SDTT

### Heading Hierarchy
- [ ] H1 only appears once per page
- [ ] Heading levels flow logically
- [ ] Headings use semantic HTML

---

## 5. Accessibility (a11y)

### WCAG 2.1 Compliance
- [ ] Color contrast meets AA standard (4.5:1 for text)
- [ ] All buttons and links keyboard accessible
- [ ] Focus states visible
- [ ] Skip to main content link works

### Keyboard Navigation
- [ ] Tab through all interactive elements
- [ ] Enter/Space activates buttons
- [ ] Escape closes modals
- [ ] Focus order logical

### Screen Reader Testing
- [ ] Page structure announced properly
- [ ] Images have alt text or are decorative (role="presentation")
- [ ] Form labels associated with inputs
- [ ] ARIA labels on icon-only buttons
- [ ] Live regions for dynamic content

### Responsive Text
- [ ] Text resizes with browser zoom (150%)
- [ ] No horizontal scroll at 200% zoom
- [ ] Text remains readable

### Motion & Animation
- [ ] Animations respect prefers-reduced-motion
- [ ] Critical content not animation-dependent
- [ ] No auto-playing media

---

## 6. Mobile & Touch Testing

### Touch Targets
- [ ] All buttons minimum 44x44px
- [ ] Touch targets have adequate spacing
- [ ] No accidental click overlap

### Viewport Testing
- [ ] Mobile (320px, 375px, 414px)
- [ ] Tablet (768px, 1024px)
- [ ] Desktop (1440px, 1920px, 4K)

### Performance on Mobile
- [ ] Page loads in < 3s on 4G
- [ ] Preloader doesn't block interaction
- [ ] Navigation doesn't cover content

---

## Performance Metrics

### Core Web Vitals
- [ ] LCP (Largest Contentful Paint): < 2.5s
- [ ] FID (First Input Delay): < 100ms
- [ ] CLS (Cumulative Layout Shift): < 0.1

### Additional Metrics
- [ ] First Contentful Paint: < 1.8s
- [ ] Time to Interactive: < 3.8s
- [ ] Total Blocking Time: < 200ms

### Lighthouse Score
- [ ] Performance: > 90
- [ ] Accessibility: > 95
- [ ] Best Practices: > 90
- [ ] SEO: > 95

---

## Testing Tools

### Online Tools
- [Google PageSpeed Insights](https://pagespeed.web.dev/)
- [Google Mobile-Friendly Test](https://search.google.com/test/mobile-friendly)
- [Schema.org Structured Data Tester](https://validator.schema.org/)
- [WAVE Accessibility Checker](https://wave.webaim.org/)
- [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci)

### Browser DevTools
- Chrome DevTools Lighthouse
- Firefox Accessibility Inspector
- Safari Accessibility Inspector

---

## Sign-off

- [ ] All tests passed
- [ ] No critical issues
- [ ] Accessibility approved
- [ ] Performance validated
- [ ] SEO optimized
- [ ] Ready for production

**Date Tested:** _______________  
**Tested By:** _______________  
**Approved By:** _______________
<?xml version="1.0" encoding="utf-8"?>{% if page.xsl %}<?xml-stylesheet type="text/xml" href="{{ '/feed.xslt.xml' | absolute_url }}"?>{% endif %}<feed xmlns="http://www.w3.org/2005/Atom" {% if site.lang %}xml:lang="{{ site.lang }}"{% endif %}><generator uri="https://jekyllrb.com/" version="{{ jekyll.version }}">Jekyll</generator><link href="{{ page.url | absolute_url }}" rel="self" type="application/atom+xml" /><link href="{{ '/' | absolute_url }}" rel="alternate" type="text/html" {% if site.lang %}hreflang="{{ site.lang }}" {% endif %}/><updated>{{ site.time | date_to_xmlschema }}</updated><id>{{ page.url | absolute_url | xml_escape }}</id>{% assign title = site.title | default: site.name %}{% if page.collection != "posts" %}{% assign collection = page.collection | capitalize %}{% assign title = title | append: " | " | append: collection %}{% endif %}{% if page.category %}{% assign category = page.category | capitalize %}{% assign title = title | append: " | " | append: category %}{% endif %}{% if title %}<title type="html">{{ title | smartify | xml_escape }}</title>{% endif %}{% if site.description %}<subtitle>{{ site.description | xml_escape }}</subtitle>{% endif %}{% if site.author %}<author><name>{{ site.author.name | default: site.author | xml_escape }}</name>{% if site.author.email %}<email>{{ site.author.email | xml_escape }}</email>{% endif %}{% if site.author.uri %}<uri>{{ site.author.uri | xml_escape }}</uri>{% endif %}</author>{% endif %}{% if page.tags %}{% assign posts = site.tags[page.tags] %}{% else %}{% assign posts = site[page.collection] %}{% endif %}{% if page.category %}{% assign posts = posts | where: "categories", page.category %}{% endif %}{% unless site.show_drafts %}{% assign posts = posts | where_exp: "post", "post.draft != true" %}{% endunless %}{% assign posts = posts | sort: "date" | reverse %}{% assign posts_limit = site.feed.posts_limit | default: 10 %}{% for post in posts limit: posts_limit %}<entry{% if post.lang %}{{" "}}xml:lang="{{ post.lang }}"{% endif %}>{% assign post_title = post.title | smartify | strip_html | normalize_whitespace | xml_escape %}<title type="html">{{ post_title }}</title><link href="{{ post.url | absolute_url }}" rel="alternate" type="text/html" title="{{ post_title }}" /><published>{{ post.date | date_to_xmlschema }}</published><updated>{{ post.last_modified_at | default: post.date | date_to_xmlschema }}</updated><id>{{ post.id | absolute_url | xml_escape }}</id>{% assign excerpt_only = post.feed.excerpt_only | default: site.feed.excerpt_only %}{% unless excerpt_only %}<content type="html" xml:base="{{ post.url | absolute_url | xml_escape }}"><![CDATA[{{ post.content | strip }}]]></content>{% endunless %}{% assign post_author = post.author | default: post.authors[0] | default: site.author %}{% assign post_author = site.data.authors[post_author] | default: post_author %}{% assign post_author_email = post_author.email | default: nil %}{% assign post_author_uri = post_author.uri | default: nil %}{% assign post_author_name = post_author.name | default: post_author %}<author><name>{{ post_author_name | default: "" | xml_escape }}</name>{% if post_author_email %}<email>{{ post_author_email | xml_escape }}</email>{% endif %}{% if post_author_uri %}<uri>{{ post_author_uri | xml_escape }}</uri>{% endif %}</author>{% if post.category %}<category term="{{ post.category | xml_escape }}" />{% elsif post.categories %}{% for category in post.categories %}<category term="{{ category | xml_escape }}" />{% endfor %}{% endif %}{% for tag in post.tags %}<category term="{{ tag | xml_escape }}" />{% endfor %}{% assign post_summary = post.description | default: post.excerpt %}{% if post_summary and post_summary != empty %}<summary type="html"><![CDATA[{{ post_summary | strip_html | normalize_whitespace }}]]></summary>{% endif %}{% assign post_image = post.image.path | default: post.image %}{% if post_image %}{% unless post_image contains "://" %}{% assign post_image = post_image | absolute_url %}{% endunless %}<media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="{{ post_image | xml_escape }}" /><media:content medium="image" url="{{ post_image | xml_escape }}" xmlns:media="http://search.yahoo.com/mrss/" />{% endif %}</entry>{% endfor %}</feed>              # All pages

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Welcome to the Blog</title>
    <meta
      name="description"
      content="Kicking off our new blog — what's coming next."
    />
    <meta
      name="robots"
      content="index, follow"
    />

    <!-- SEO Meta Tags -->
          

    <meta
      property="og:title"
      content="Welcome to the Blog"
    />
    <meta
      property="og:description"
      content="Kicking off our new blog — what's coming next."
    />
    <meta property="og:url" content="https://abc-site.devvyy.xyz/blog/blog-test/" />
    <meta property="og:image" content="https://abc-site.devvyy.xyz/assets/images/logo.svg" />
    <meta property="og:image:alt" content="ABC Mods & Packs" />
    <meta property="og:type" content="post" />
    <meta property="og:site_name" content="ABC" />
    <meta
      property="og:locale"
      content="en_US"
    />

    <!-- hreflang tags for multilingual SEO -->
    <link
      rel="alternate"
      hreflang="en"
      href="https://abc-site.devvyy.xyz/blog/blog-test/"
    />
    <link
      rel="alternate"
      hreflang="fr"
      href="https://abc-site.devvyy.xyz/fr/blog/blog-test/"
    />
    <link
      rel="alternate"
      hreflang="x-default"
      href="https://abc-site.devvyy.xyz/blog/blog-test/"
    />

    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary_large_image" />
    <meta
      name="twitter:title"
      content="Welcome to the Blog"
    />
    <meta
      name="twitter:description"
      content="Kicking off our new blog — what's coming next."
    />
    <meta
      name="twitter:image"
      content="https://abc-site.devvyy.xyz/assets/images/logo.svg"
    />
    <meta name="twitter:image:alt" content="ABC Mods & Packs" />
    <meta
      name="twitter:creator"
      content="@devvyyxyz"
    />
    <meta
      name="twitter:site"
      content="@devvyyxyz"
    />

    <meta
      name="theme-color"
      content="#1bd96f"
    />

    <!-- Favicon -->
    <link
      rel="icon"
      type="image/svg+xml"
      href="/favicon.svg"
    />
    <link
      rel="icon"
      type="image/x-icon"
      href="/favicon.svg"
    />
    <link
      rel="apple-touch-icon"
      href="/assets/images/logo.svg"
    />

    <!-- Google Fonts - Preload -->
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      rel="preload"
      as="style"
      href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c&display=swap"
    />
    <link
      href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c&display=swap"
      rel="stylesheet"
    />

    <!-- Font Awesome Icons - Async load -->
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
      media="print"
      onload="this.media='all'"
    />
    <noscript>
      <link
        rel="stylesheet"
        href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
      />
    </noscript>

    <!-- Stylesheets - Critical -->
    <link rel="stylesheet" href="/assets/css/root.css" />
    <link
      rel="stylesheet"
      href="/assets/css/layout.css"
    />
    <link
      rel="stylesheet"
      href="/assets/css/loading.css"
    />

    <!-- Stylesheets - Deferred (non-critical) -->
    <link
      rel="stylesheet"
      href="/assets/css/components.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/modpacks.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/animations.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/theme.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/a11y.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/visual-enhancements.css"
      media="print"
      onload="this.media='all'"
    />
    <link
      rel="stylesheet"
      href="/assets/css/mobile.css"
      media="print"
      onload="this.media='all'"
    />
    <noscript>
      <link
        rel="stylesheet"
        href="/assets/css/components.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/modpacks.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/animations.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/theme.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/a11y.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/visual-enhancements.css"
      />
      <link
        rel="stylesheet"
        href="/assets/css/mobile.css"
      />
    </noscript>

    <!-- Canonical URL -->
    <link rel="canonical" href="https://abc-site.devvyy.xyz/blog/blog-test/" />

    <!-- Schema Markup -->
    <!-- Schema.org JSON-LD -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Organization",
    "name": "ABC",
    "description": "Browse curated Minecraft mods, resource packs, datapacks, modpacks and plugins.",
    "url": "https://abc-site.devvyy.xyz",
    "logo": "https://abc-site.devvyy.xyz/assets/images/logo.svg",
    "sameAs": [
      "https://github.com/devvyyxyz",
      "https://twitter.com/devvyyxyz",
      "https://dc.gg/devvyyxyz"
    ],
    "contactPoint": {
      "@type": "ContactPoint",
      "contactType": "Community Support",
      "url": "https://dc.gg/devvyyxyz"
    }
  }
</script>

<!-- Breadcrumb Schema -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": 1,
        "name": "Home",
        "item": "https://abc-site.devvyy.xyz"
      }
      
      , {
        "@type": "ListItem",
        "position": 2,
        "name": "Welcome to the Blog",
        "item": "https://abc-site.devvyy.xyz/blog/blog-test/"
      }
      
    ]
  }
</script>

<!-- Project/Software Application Schema (for project pages) -->

<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "Welcome to the Blog",
    "description": "Kicking off our new blog — what's coming next.",
    "image": "",
    "datePublished": "2025-12-16T00:00:00+00:00",
    "dateModified": "2025-12-16T00:00:00+00:00",
    "author": {
      "@type": "Organization",
      "name": "ABC"
    },
    "publisher": {
      "@type": "Organization",
      "name": "ABC",
      "logo": {
        "@type": "ImageObject",
        "url": "https://abc-site.devvyy.xyz/assets/images/logo.svg"
      }
    }
  }
</script>
<!-- WebPage Schema -->



    <!-- Preloader Script (critical, inline) -->
    <script>
      (function () {
        if (!document.body) return; // Exit if body not ready yet

        const isDarkMode =
          window.matchMedia &&
          window.matchMedia("(prefers-color-scheme: dark)").matches;
        const bgColor = isDarkMode ? "#0d0d0d" : "#f6fbfa";
        document.documentElement.style.backgroundColor = bgColor;
        document.body.style.backgroundColor = bgColor;

        const overlay = document.createElement("div");
        overlay.className = "loading-overlay";
        overlay.id = "loading-overlay";
        overlay.innerHTML = '<div class="spinner"></div>';
        document.body.appendChild(overlay);

        if (document.readyState === "loading") {
          document.addEventListener("DOMContentLoaded", hidePreloader);
        } else {
          hidePreloader();
        }

        function hidePreloader() {
          const preloader = document.getElementById("loading-overlay");
          if (preloader) {
            preloader.classList.add("hidden");
          }
        }

        window.hidePreloader = hidePreloader;
      })();
    </script>
  </head>
  <body>
    <a href="#main" class="skip-to-main">Skip to main content</a>
    <header class="floating-nav">
  <div class="nav-inner">
    <a
      class="logo"
      href="/"
      style="display: flex; align-items: center; gap: 8px"
      aria-label="ABC"
    >
      <img
        src="/assets/images/logo.svg"
        alt="ABC"
        style="height: 32px; width: auto"
      />
      
    </a>
    <button
      class="mobile-menu-toggle"
      aria-label="Toggle menu"
      id="mobile-menu-toggle"
    >
      <i class="fas fa-bars"></i>
    </button>
    <nav class="links" id="mobile-nav">
      <a href="/">Home</a>
      <a href="/about/">About</a>
      <a href="/docs/">Docs</a>
      <a href="/changelog/">Changelog</a>
      <a href="/blog/">Blog</a>
      <div class="nav-dropdown">
        <a href="/projects/" class="dropdown-toggle">
          Projects <i class="fas fa-chevron-down"></i>
        </a>
        <div class="dropdown-menu">
          <a href="/projects/">All Projects</a>
          <a href="/compare/"
            ><i class="fas fa-balance-scale"></i> Compare Modpacks</a
          >
          <a href="/changelog/"
            ><i class="fas fa-rocket"></i> Releases & Changelog</a
          >
        </div>
      </div>
      <div class="nav-dropdown">
        <a href="#" class="dropdown-toggle">
          Legal <i class="fas fa-chevron-down"></i>
        </a>
        <div class="dropdown-menu">
          <a href="/privacy/">Privacy Policy</a>
          <a href="/terms/">Terms of Service</a>
          <a href="/cookie-policy/">Cookie Policy</a>
          <a href="/licensing/">Licensing</a>
          <a href="/eula/">EULA</a>
          <a href="/disclaimer/">Disclaimer</a>
        </div>
      </div>
      <a
        href="https://modrinth.com/organization/abcxyz"
        target="_blank"
        rel="noopener"
        >Organization</a
      >
    </nav>
    <div class="nav-actions">
      <div
        id="social-links-nav"
        style="display: flex; gap: 6px; align-items: center"
      ></div>
      <!-- Theme Toggle -->
<div class="theme-toggle" id="theme-toggle" title="Toggle dark/light mode">
  <button id="theme-dark" class="active" aria-label="Dark mode" title="Dark mode">
    <i class="fa-solid fa-moon"></i>
  </button>
  <button id="theme-light" aria-label="Light mode" title="Light mode">
    <i class="fa-solid fa-sun"></i>
  </button>
</div>

<script>
  // Theme toggle functionality
  const themeToggle = {
    init() {
      this.darkBtn = document.getElementById('theme-dark');
      this.lightBtn = document.getElementById('theme-light');
      this.html = document.documentElement;

      // Load saved theme or use system preference
      const saved = localStorage.getItem('theme');
      const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
      const theme = saved || (systemDark ? 'dark' : 'light');

      this.setTheme(theme);

      // Listen for changes
      this.darkBtn.addEventListener('click', () => this.setTheme('dark'));
      this.lightBtn.addEventListener('click', () => this.setTheme('light'));

      // Listen for system theme changes
      window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
        if (!localStorage.getItem('theme')) {
          this.setTheme(e.matches ? 'dark' : 'light');
        }
      });
    },

    setTheme(theme) {
      this.html.setAttribute('data-theme', theme);
      localStorage.setItem('theme', theme);

      this.darkBtn.classList.toggle('active', theme === 'dark');
      this.lightBtn.classList.toggle('active', theme === 'light');

      // Update meta theme-color
      const color = theme === 'dark' ? '#1bd96f' : '#1bd96f';
      document.querySelector('meta[name="theme-color"]').setAttribute('content', color);
    }
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => themeToggle.init());
  } else {
    themeToggle.init();
  }
</script>

    </div>
  </div>
</header>

<script>
  // Mobile menu toggle
  document.addEventListener("DOMContentLoaded", () => {
    const toggle = document.getElementById("mobile-menu-toggle");
    const nav = document.getElementById("mobile-nav");

    if (toggle && nav) {
      toggle.addEventListener("click", () => {
        nav.classList.toggle("mobile-open");
        const icon = toggle.querySelector("i");
        if (nav.classList.contains("mobile-open")) {
          icon.classList.remove("fa-bars");
          icon.classList.add("fa-times");
        } else {
          icon.classList.remove("fa-times");
          icon.classList.add("fa-bars");
        }
      });

      // Close menu when clicking a link
      nav.querySelectorAll("a").forEach((link) => {
        link.addEventListener("click", () => {
          nav.classList.remove("mobile-open");
          const icon = toggle.querySelector("i");
          icon.classList.remove("fa-times");
          icon.classList.add("fa-bars");
        });
      });

      // Close menu when clicking outside
      document.addEventListener("click", (e) => {
        if (!toggle.contains(e.target) && !nav.contains(e.target)) {
          nav.classList.remove("mobile-open");
          const icon = toggle.querySelector("i");
          icon.classList.remove("fa-times");
          icon.classList.add("fa-bars");
        }
      });
    }
  });
</script>


    <main id="main" class="container"><main class="content">
  <article class="post" style="max-width: 820px; margin: 0 auto; padding: 24px">
    <header>
      <h1 style="margin: 0 0 8px">Welcome to the Blog</h1>
      <p class="muted" style="margin: 0 0 16px">
        December 16, 2025 • ABC Team
      </p>
    </header>
    <section class="post-body"><p>We’re launching a blog to share updates, release notes, and behind-the-scenes dev logs.</p>

<!--more-->

<p>What you can expect:</p>

<ul>
  <li>Deep dives into mods, datapacks, and plugins</li>
  <li>Roadmap updates and upcoming releases</li>
  <li>Performance tips and compatibility notes</li>
  <li>Community showcases and contributions</li>
</ul>

<p>If you have topics you’d like us to cover, let us know on the contact page or Discord.</p>
</section>

    
    <footer style="margin-top: 24px">
      <strong>Tags:</strong>
      
      <span
        style="
          display: inline-block;
          padding: 4px 8px;
          border: 1px solid var(--border);
          border-radius: 999px;
          margin-right: 6px;
          font-size: 12px;
        "
        >#announcement</span
      >
      
      <span
        style="
          display: inline-block;
          padding: 4px 8px;
          border: 1px solid var(--border);
          border-radius: 999px;
          margin-right: 6px;
          font-size: 12px;
        "
        >#roadmap</span
      >
       
      <div style="margin-top: 8px">
        <strong>Categories:</strong>
        
        <span
          style="
            display: inline-block;
            padding: 4px 8px;
            border: 1px solid var(--border);
            border-radius: 999px;
            margin-right: 6px;
            font-size: 12px;
          "
          >updates</span
        >
        
      </div>
      
    </footer>
    
  </article>
</main>
</main>

    <footer class="floating-footer">
  <div class="footer-inner">
    <div style="display: flex; gap: 16px; align-items: flex-start">
      <img
        src="/assets/images/logo.svg"
        alt="ABC logo"
        style="height: 100px; flex-shrink: 0; width: auto"
        width="100"
        height="100"
      />
      <div style="display: flex; flex-direction: column; gap: 8px">
        <div>
          <h4
            style="
              margin: 0;
              font-size: 18px;
              font-weight: 700;
              color: var(--text);
            "
          >
            ABC
          </h4>
          <p
            style="
              margin: 2px 0 0 0;
              font-size: 12px;
              color: var(--text-secondary);
            "
          >
            Established 2025
          </p>
        </div>
        <p
          style="
            margin: 0;
            font-size: 13px;
            color: var(--text-secondary);
            line-height: 1.6;
          "
        >
          Browse curated Minecraft mods, resource packs, datapacks, modpacks and plugins.
        </p>
      </div>
    </div>
    <div style="display: flex; gap: 48px">
      <div>
        <h4
          style="
            margin: 0 0 16px;
            font-size: 11px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--text);
          "
        >
          Links
        </h4>
        <div
          style="
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
            gap: 10px 12px;
            font-size: 13px;
            max-width: 320px;
          "
        >
          <a
            href="/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Home</a
          >
          <a
            href="/about/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >About</a
          >
          <a
            href="/docs/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Docs</a
          >
          <a
            href="/projects/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Projects</a
          >
          <a
            href="/compare/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Compare</a
          >
          <a
            href="/changelog/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Changelog</a
          >
          <a
            href="https://modrinth.com/organization/abcxyz"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            target="_blank"
            rel="noopener"
            >Modrinth Org</a
          >
          <a
            href="https://github.com/devvyyxyz"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            target="_blank"
            rel="noopener"
            >GitHub Org</a
          >
          <a
            href="/sitemap.xml"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Sitemap</a
          >
          <a
            href="/feed.xml"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >RSS Feed</a
          >
          <a
            href="/blog/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Blog</a
          >
        </div>
      </div>
      <div>
        <h4
          style="
            margin: 0 0 16px;
            font-size: 11px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--text);
          "
        >
          Help
        </h4>
        <div
          style="
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
            gap: 10px 12px;
            font-size: 13px;
            max-width: 320px;
          "
        >
          <a
            href="/contact/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Contact</a
          >
          <a
            href="/docs/faq/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >FAQ</a
          >
          <a
            href="/docs/troubleshooting/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Troubleshooting</a
          >
          <a
            href="/docs/contributing/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Contributing</a
          >
          <a
            href="/status/"
            style="
              color: var(--text-secondary);
              text-decoration: none;
              transition: color 0.2s;
            "
            >Status</a
          >
        </div>
      </div>
      <div>
        <h4
          style="
            margin: 0 0 16px;
            font-size: 11px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--text);
          "
        >
          Community
        </h4>
        <div
          id="social-links-footer"
          style="display: flex; gap: 12px; flex-direction: column"
        ></div>
      </div>
    </div>
  </div>
  <div
    style="
      border-top: 1px solid var(--border);
      margin-top: 32px;
      padding-top: 24px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 12px;
      color: var(--text-secondary);
      flex-wrap: wrap;
      gap: 16px;
    "
  >
    <div style="display: flex; gap: 16px; align-items: center; flex-wrap: wrap">
      <div>
        © <span id="year"></span> ABC. All rights reserved.
      </div>
      <div
        id="language-switcher"
        style="display: flex; gap: 8px; align-items: center"
      >
        <span style="font-size: 12px; color: var(--text-secondary)"
          >Language:</span
        >
        <select
          id="lang-select"
          style="
            padding: 4px 8px;
            border: 1px solid var(--border);
            border-radius: var(--radius);
            background: var(--bg-secondary);
            color: var(--text);
            font-size: 12px;
            cursor: pointer;
          "
        >
          <option value="en">English</option>
          <option value="fr">Français</option>
        </select>
      </div>
    </div>
    <div style="display: flex; gap: 20px">
      <a
        href="/privacy/"
        style="
          color: var(--text-secondary);
          text-decoration: none;
          transition: color 0.2s;
        "
        >Privacy</a
      >
      <a
        href="/terms/"
        style="
          color: var(--text-secondary);
          text-decoration: none;
          transition: color 0.2s;
        "
        >Terms</a
      >
    </div>
  </div>
</footer>

<script>
  // Social links configuration
  const socials = {
    github: {
      name: "GitHub",
      icon: "fab fa-github",
      url: "https://github.com/devvyyxyz",
    },
    twitter: {
      name: "Twitter",
      icon: "fab fa-x-twitter",
      url: "https://twitter.com/devvyyxyz",
    },
    discord: {
      name: "Discord",
      icon: "fab fa-discord",
      url: "https://dc.gg/devvyyxyz",
    },
  };

  function renderSocialLinks() {
    const navContainer = document.getElementById("social-links-nav");
    const footerContainer = document.getElementById("social-links-footer");

    Object.entries(socials).forEach(([key, social]) => {
      if (social.url && social.url.trim()) {
        // Nav icon button
        const navLink = document.createElement("a");
        navLink.href = social.url;
        navLink.target = "_blank";
        navLink.rel = "noopener";
        navLink.title = social.name;
        navLink.style.cssText =
          "display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:var(--radius);background:var(--bg-secondary);color:var(--text-secondary);text-decoration:none;font-size:16px;transition:all 0.2s ease;border:1px solid var(--border)";
        const icon = document.createElement("i");
        icon.className = social.icon;
        icon.style.fontSize = "18px";
        navLink.appendChild(icon);
        navLink.onmouseover = () => {
          navLink.style.background = "var(--accent-primary)";
          navLink.style.color = "#000000";
          navLink.style.borderColor = "var(--accent-primary)";
        };
        navLink.onmouseout = () => {
          navLink.style.background = "var(--bg-secondary)";
          navLink.style.color = "var(--text-secondary)";
          navLink.style.borderColor = "var(--border)";
        };
        if (navContainer) navContainer.appendChild(navLink);

        // Footer text link with icon
        const footerLink = document.createElement("a");
        footerLink.href = social.url;
        footerLink.target = "_blank";
        footerLink.rel = "noopener";
        footerLink.style.cssText =
          "display:flex;align-items:center;gap:8px;color:var(--text-secondary);text-decoration:none;transition:color 0.2s;font-size:13px";
        const footerIcon = document.createElement("i");
        footerIcon.className = social.icon;
        footerIcon.style.width = "16px";
        const footerText = document.createElement("span");
        footerText.textContent = social.name;
        footerLink.appendChild(footerIcon);
        footerLink.appendChild(footerText);
        footerLink.onmouseover = () => {
          footerLink.style.color = "var(--accent-primary)";
        };
        footerLink.onmouseout = () => {
          footerLink.style.color = "var(--text-secondary)";
        };
        if (footerContainer) footerContainer.appendChild(footerLink);
      }
    });
  }

  document.addEventListener("DOMContentLoaded", renderSocialLinks);

  // Set year in footer
  document.getElementById("year").textContent = new Date().getFullYear();

  // Language switcher
  const langSelect = document.getElementById("lang-select");
  if (langSelect) {
    const currentLang = 'en';
    langSelect.value = currentLang;

    langSelect.addEventListener("change", (e) => {
      const selectedLang = e.target.value;
      const currentPath = window.location.pathname;
      const baseUrl = "";

      // Remove existing language prefix
      let cleanPath = currentPath.replace(baseUrl, "");
      cleanPath = cleanPath.replace(/^\/(en|fr)/, "");

      // Build new URL
      const newPath =
        selectedLang === "en"
          ? baseUrl + cleanPath
          : baseUrl + "/" + selectedLang + cleanPath;

      window.location.href = newPath;
    });
  }
</script>
 <!-- Scroll to top button -->
<button id="scroll-to-top" class="scroll-to-top" aria-label="Scroll to top" title="Back to top">
  <i class="fa-solid fa-chevron-up"></i>
</button>

<script>
  // Scroll to top functionality
  const scrollButton = document.getElementById('scroll-to-top');

  window.addEventListener('scroll', () => {
    if (window.scrollY > 300) {
      scrollButton.classList.add('visible');
    } else {
      scrollButton.classList.remove('visible');
    }
  });

  scrollButton.addEventListener('click', () => {
    window.scrollTo({ top: 0, behavior: 'smooth' });
  });

  // Handle keyboard interaction
  scrollButton.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }
  });
</script>

<!-- Lazy loading images with placeholder -->
<script>
  // Intersection Observer for lazy loading
  if ('IntersectionObserver' in window) {
    const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src || img.src;
          img.classList.remove('lazy');
          observer.unobserve(img);
        }
      });
    }, {
      rootMargin: '50px 0px',
      threshold: 0.01
    });

    document.querySelectorAll('img[data-src]').forEach(img => {
      imageObserver.observe(img);
    });
  }
</script>

<!-- Smooth page transitions -->
<script>
  // Add page transition class on load
  document.addEventListener('DOMContentLoaded', () => {
    document.body.classList.add('page-transition');
  });

  // Handle link clicks for smooth transitions
  document.addEventListener('click', (e) => {
    const link = e.target.closest('a');
    if (link && !link.target && link.hostname === window.location.hostname) {
      // Internal link - add transition
      e.preventDefault();
      document.body.style.opacity = '0.8';
      setTimeout(() => {
        window.location.href = link.href;
      }, 150);
    }
  });
</script>


    <!-- Cookie Consent Banner -->
    <div
  id="cookie-consent"
  class="cookie-consent-banner"
  role="alertdialog"
  aria-labelledby="cookie-title"
  aria-describedby="cookie-description"
  style="display: none"
>
  <div class="cookie-consent-content">
    <div class="cookie-consent-text">
      <h3 id="cookie-title" class="cookie-consent-title">
          Cookie Preferences
      </h3>
      <p id="cookie-description" class="cookie-consent-message">
        We use cookies to improve your experience and analyze site performance. No personal data is collected.
      </p>
      <p class="cookie-consent-subtext">
        <a
          href="/privacy/"
          target="_blank"
          rel="noopener"
          >Privacy Policy</a
        >
      </p>
    </div>
    <div class="cookie-consent-actions">
      <button
        id="cookie-manage"
        class="cookie-btn cookie-btn-manage"
        aria-label="Manage cookie preferences"
      >
        Manage Preferences
      </button>
      <button
        id="cookie-reject"
        class="cookie-btn cookie-btn-reject"
        aria-label="Reject cookies"
      >
        Reject
      </button>
      <button
        id="cookie-accept"
        class="cookie-btn cookie-btn-accept"
        aria-label="Accept all cookies"
      >
        Accept All
      </button>
    </div>
  </div>
</div>

<!-- Cookie Settings Modal -->
<div
  id="cookie-modal"
  class="cookie-modal"
  style="display: none"
  role="dialog"
  aria-labelledby="modal-title"
  aria-hidden="true"
>
  <div class="cookie-modal-overlay"></div>
  <div class="cookie-modal-content">
    <div class="cookie-modal-header">
      <h2 id="modal-title" class="cookie-modal-title">Cookie Preferences</h2>
      <button
        id="modal-close"
        class="cookie-modal-close"
        aria-label="Close modal"
      >
        <i class="fas fa-times"></i>
      </button>
    </div>

    <div class="cookie-modal-body">
      <!-- Categories -->
      <div class="cookie-categories">
        <!-- Essential -->
        <div class="cookie-category">
          <div class="cookie-category-header">
            <label class="cookie-checkbox-label">
              <input
                type="checkbox"
                id="cookie-essential"
                class="cookie-checkbox"
                checked
                disabled
              />
              <span class="cookie-category-title"
                >Essential</span
              >
            </label>
            <span class="cookie-badge essential">Essential</span>
          </div>
          <p class="cookie-category-desc">Required for core site functionality. Always enabled.</p>
        </div>

        <!-- Analytics -->
        <div class="cookie-category">
          <div class="cookie-category-header">
            <label class="cookie-checkbox-label">
              <input
                type="checkbox"
                id="cookie-analytics"
                class="cookie-checkbox"
              />
              <span class="cookie-category-title"
                >Analytics</span
              >
            </label>
          </div>
          <p class="cookie-category-desc">Help us understand how you use our site to improve it.</p>
          <details class="cookie-details">
            <summary>All Cookies</summary>
            <div class="cookie-list">
              <div class="cookie-item">
                <span class="cookie-item-name">_ga, _ga_*</span>
                <span class="cookie-item-expiration">2 years</span>
              </div>
              <div class="cookie-item">
                <span class="cookie-item-name">_gat</span>
                <span class="cookie-item-expiration">1 minute</span>
              </div>
            </div>
          </details>
        </div>

        <!-- Performance -->
        <div class="cookie-category">
          <div class="cookie-category-header">
            <label class="cookie-checkbox-label">
              <input
                type="checkbox"
                id="cookie-performance"
                class="cookie-checkbox"
              />
              <span class="cookie-category-title"
                >Performance</span
              >
            </label>
          </div>
          <p class="cookie-category-desc">Improve page speed and user experience.</p>
        </div>

        <!-- Marketing -->
        <div class="cookie-category">
          <div class="cookie-category-header">
            <label class="cookie-checkbox-label">
              <input
                type="checkbox"
                id="cookie-marketing"
                class="cookie-checkbox"
              />
              <span class="cookie-category-title"
                >Marketing</span
              >
            </label>
          </div>
          <p class="cookie-category-desc">Allow us to show you relevant content and offers.</p>
        </div>
      </div>

      <div class="cookie-modal-footer-info">
        <small class="cookie-updated"
          >Last updated: December 11, 2025</small
        >
      </div>
    </div>

    <div class="cookie-modal-footer">
      <button id="modal-reject" class="cookie-btn cookie-btn-reject">
        Reject
      </button>
      <button id="modal-save" class="cookie-btn cookie-btn-accept">
        Save Preferences
      </button>
    </div>
  </div>
</div>

<style>
  .cookie-consent-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-secondary);
    border-top: 1px solid var(--border);
    border-left: 3px solid var(--accent-primary);
    padding: 20px;
    z-index: 1000;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
    animation: slideUp 0.3s ease-out;
  }

  @keyframes slideUp {
    from {
      transform: translateY(100%);
      opacity: 0;
    }
    to {
      transform: translateY(0);
      opacity: 1;
    }
  }

  .cookie-consent-content {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
  }

  .cookie-consent-text {
    flex: 1;
    min-width: 280px;
  }

  .cookie-consent-title {
    margin: 0 0 8px 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
  }

  .cookie-consent-message {
    margin: 0 0 8px 0;
    font-size: 14px;
    color: var(--text-secondary);
    line-height: 1.5;
  }

  .cookie-consent-subtext {
    margin: 8px 0 0 0;
    font-size: 12px;
    color: var(--text-secondary);
  }

  .cookie-consent-subtext a {
    color: var(--accent-primary);
    text-decoration: none;
    font-weight: 500;
  }

  .cookie-consent-subtext a:hover {
    text-decoration: underline;
  }

  .cookie-consent-actions {
    display: flex;
    gap: 12px;
    flex-shrink: 0;
  }

  .cookie-btn {
    padding: 8px 16px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
    white-space: nowrap;
  }

  .cookie-btn-manage {
    background: var(--bg-primary);
    color: var(--accent-primary);
    border-color: var(--accent-primary);
    font-weight: 600;
  }

  .cookie-btn-manage:hover {
    background: var(--bg);
    opacity: 0.9;
  }

  .cookie-btn-reject {
    background: var(--bg-primary);
    color: var(--text);
    border-color: var(--border);
  }

  .cookie-btn-reject:hover {
    background: var(--bg);
    border-color: var(--text-secondary);
  }

  .cookie-btn-accept {
    background: var(--accent-primary);
    color: #000000;
    border-color: var(--accent-primary);
    font-weight: 600;
  }

  .cookie-btn-accept:hover {
    opacity: 0.9;
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(27, 217, 111, 0.2);
  }

  .cookie-btn:active {
    transform: translateY(0);
  }

  @media (max-width: 768px) {
    .cookie-consent-banner {
      padding: 16px;
    }

    .cookie-consent-content {
      flex-direction: column;
      gap: 16px;
    }

    .cookie-consent-actions {
      width: 100%;
      flex-direction: column;
    }

    .cookie-btn {
      width: 100%;
      padding: 10px 16px;
    }
  }

  /* Modal Styles */
  .cookie-modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: fadeIn 0.3s ease-out;
  }

  @keyframes fadeIn {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  .cookie-modal-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    cursor: pointer;
  }

  .cookie-modal-content {
    position: relative;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    max-width: 600px;
    width: 90%;
    max-height: 90vh;
    overflow: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    animation: slideIn 0.3s ease-out;
  }

  @keyframes slideIn {
    from {
      transform: scale(0.95);
      opacity: 0;
    }
    to {
      transform: scale(1);
      opacity: 1;
    }
  }

  .cookie-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 24px;
    border-bottom: 1px solid var(--border);
  }

  .cookie-modal-title {
    margin: 0;
    font-size: 20px;
    font-weight: 600;
    color: var(--text);
  }

  .cookie-modal-close {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: 20px;
    cursor: pointer;
    padding: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    transition: all 0.2s;
  }

  .cookie-modal-close:hover {
    background: var(--border);
    color: var(--text);
  }

  .cookie-modal-body {
    padding: 24px;
  }

  .cookie-categories {
    display: flex;
    flex-direction: column;
    gap: 24px;
    margin-bottom: 24px;
  }

  .cookie-category {
    padding: 16px;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }

  .cookie-category-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
  }

  .cookie-checkbox-label {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    flex: 1;
  }

  .cookie-checkbox {
    width: 18px;
    height: 18px;
    cursor: pointer;
    accent-color: var(--accent-primary);
  }

  .cookie-checkbox:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .cookie-category-title {
    font-weight: 600;
    color: var(--text);
  }

  .cookie-badge {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    background: var(--accent-primary);
    color: #000000;
  }

  .cookie-category-desc {
    margin: 8px 0 0 28px;
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.5;
  }

  .cookie-details {
    margin: 12px 0 0 28px;
    cursor: pointer;
  }

  .cookie-details summary {
    font-size: 12px;
    color: var(--accent-primary);
    font-weight: 500;
    text-decoration: underline;
    padding: 4px 0;
  }

  .cookie-details summary:hover {
    opacity: 0.8;
  }

  .cookie-list {
    margin-top: 8px;
    padding: 8px;
    background: var(--bg);
    border-radius: 4px;
    border: 1px solid var(--border);
  }

  .cookie-item {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    padding: 6px 0;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
  }

  .cookie-item:last-child {
    border-bottom: none;
  }

  .cookie-item-name {
    font-family: monospace;
    font-weight: 500;
    color: var(--text);
  }

  .cookie-item-expiration {
    font-size: 11px;
  }

  .cookie-modal-footer-info {
    margin-bottom: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
  }

  .cookie-updated {
    font-size: 12px;
    color: var(--text-secondary);
  }

  .cookie-modal-footer {
    display: flex;
    gap: 12px;
    padding: 16px 24px;
    border-top: 1px solid var(--border);
    background: var(--bg-primary);
    justify-content: flex-end;
  }

  .cookie-modal-footer .cookie-btn {
    flex: 1;
  }

  @media (max-width: 640px) {
    .cookie-modal-content {
      width: 95%;
      max-height: 95vh;
    }

    .cookie-modal-header {
      padding: 16px;
    }

    .cookie-modal-body {
      padding: 16px;
    }

    .cookie-modal-footer {
      flex-direction: column;
      padding: 16px;
    }

    .cookie-modal-footer .cookie-btn {
      width: 100%;
    }

    .cookie-category-desc {
      margin-left: 28px;
    }

    .cookie-details {
      margin-left: 28px;
    }
  }
</style>

<script>
  document.addEventListener("DOMContentLoaded", () => {
    const banner = document.getElementById("cookie-consent");
    const modal = document.getElementById("cookie-modal");
    const acceptBtn = document.getElementById("cookie-accept");
    const rejectBtn = document.getElementById("cookie-reject");
    const manageBtn = document.getElementById("cookie-manage");
    const modalClose = document.getElementById("modal-close");
    const modalOverlay = document.querySelector(".cookie-modal-overlay");
    const modalRejectBtn = document.getElementById("modal-reject");
    const modalSaveBtn = document.getElementById("modal-save");
    const consentKey = "abc-cookie-consent";
    const categoriesKey = "abc-cookie-categories";

    // Preference checkboxes
    const analyticsCheckbox = document.getElementById("cookie-analytics");
    const performanceCheckbox = document.getElementById("cookie-performance");
    const marketingCheckbox = document.getElementById("cookie-marketing");

    // Load saved preferences
    const loadPreferences = () => {
      const saved = localStorage.getItem(categoriesKey);
      if (saved) {
        const prefs = JSON.parse(saved);
        analyticsCheckbox.checked = prefs.analytics || false;
        performanceCheckbox.checked = prefs.performance || false;
        marketingCheckbox.checked = prefs.marketing || false;
      }
    };

    // Save preferences
    const savePreferences = () => {
      const prefs = {
        analytics: analyticsCheckbox.checked,
        performance: performanceCheckbox.checked,
        marketing: marketingCheckbox.checked,
      };
      localStorage.setItem(categoriesKey, JSON.stringify(prefs));
      localStorage.setItem(consentKey, "custom");
      dismissBanner();
      updateConsent(prefs);
    };

    // Dismiss banner with animation
    const dismissBanner = () => {
      banner.style.animation = "slideDown 0.3s ease-out forwards";
      setTimeout(() => {
        banner.style.display = "none";
      }, 300);
      modal.style.animation = "fadeOut 0.3s ease-out forwards";
      setTimeout(() => {
        modal.style.display = "none";
      }, 300);
    };

    // Update analytics consent
    const updateConsent = (prefs) => {
      if (window.gtag) {
        gtag("consent", "update", {
          analytics_storage: prefs.analytics ? "granted" : "denied",
        });
      }
    };

    // Check if user has already made a choice
    const userConsent = localStorage.getItem(consentKey);

    if (!userConsent) {
      setTimeout(() => {
        banner.style.display = "flex";
      }, 1000);
    }

    loadPreferences();

    // Accept all cookies
    acceptBtn.addEventListener("click", () => {
      analyticsCheckbox.checked = true;
      performanceCheckbox.checked = true;
      marketingCheckbox.checked = true;
      savePreferences();
    });

    // Reject all cookies (keep only essential)
    const rejectAllCookies = () => {
      analyticsCheckbox.checked = false;
      performanceCheckbox.checked = false;
      marketingCheckbox.checked = false;
      localStorage.setItem(
        categoriesKey,
        JSON.stringify({
          analytics: false,
          performance: false,
          marketing: false,
        })
      );
      localStorage.setItem(consentKey, "rejected");
      dismissBanner();
      updateConsent({ analytics: false, performance: false, marketing: false });
    };

    rejectBtn.addEventListener("click", rejectAllCookies);
    modalRejectBtn.addEventListener("click", rejectAllCookies);

    // Manage preferences
    manageBtn.addEventListener("click", () => {
      modal.style.display = "flex";
      loadPreferences();
    });

    // Modal controls
    modalClose.addEventListener("click", () => {
      modal.style.animation = "fadeOut 0.3s ease-out forwards";
      setTimeout(() => {
        modal.style.display = "none";
      }, 300);
    });

    modalOverlay.addEventListener("click", () => {
      modalClose.click();
    });

    // Save preferences from modal
    modalSaveBtn.addEventListener("click", savePreferences);

    // ESC key to close modal
    document.addEventListener("keydown", (e) => {
      if (e.key === "Escape" && modal.style.display === "flex") {
        modalClose.click();
      }
    });

    // Add fadeOut animation
    const style = document.createElement("style");
    style.textContent = `
      @keyframes slideDown {
        to {
          transform: translateY(100%);
          opacity: 0;
        }
      }
      @keyframes fadeOut {
        to {
          opacity: 0;
        }
      }
    `;
    document.head.appendChild(style);
  });
</script>


    <!-- Scripts -->
    <script src="/assets/js/search.js"></script>
    <script src="/assets/js/performance.js"></script>
    <script src="/assets/js/visual-enhancements.js"></script>
  </body>
</html>
              # All posts
{"en"=>{"hero_title"=>"Showcase: Minecraft Mods & Packs", "hero_subtitle"=>"Mods, resource packs, datapacks, modpacks and plugins — curated from our organization.", "browse_projects"=>"Browse Projects", "learn_more"=>"Learn More", "featured_title"=>"Featured Highlights", "featured_subtitle"=>"Latest additions to our growing collection", "featured_badge"=>"Featured", "view_project"=>"View Project", "source"=>"Source", "stats_title"=>"Project Snapshot", "stats_subtitle"=>"Live data pulled from our Modrinth cache", "stat_total_projects"=>"Total Projects", "stat_total_downloads"=>"Total Downloads", "stat_supported_loaders"=>"Supported Loaders", "stat_game_versions"=>"Game Versions", "stat_top_categories"=>"Top Categories", "stat_top_downloads"=>"Top Downloads", "stat_downloads_note"=>"Highest downloaded projects", "stat_loading"=>"Loading…", "stat_unavailable"=>"Unavailable", "stat_projects_catalog"=>"Projects in catalog", "stat_avg_per_project"=>"avg per project", "stat_unique_versions"=>"Unique game versions", "stat_no_categories"=>"No categories yet", "stat_no_data"=>"No download data available yet", "error_loading"=>"Error loading", "failed_to_load"=>"Failed to load", "no_projects_found"=>"No projects found. They will sync automatically.", "error_404_title"=>"Page Not Found", "error_404_description"=>"The page you're looking for doesn't exist.", "error_404_message"=>"Sorry, we couldn't find what you were looking for.", "error_404_back_home"=>"Back to Home", "error_404_browse"=>"Browse Projects", "cookie_title"=>"Cookie Preferences", "cookie_message"=>"We use cookies to improve your experience and analyze site performance. No personal data is collected.", "cookie_accept"=>"Accept All", "cookie_reject"=>"Reject", "cookie_learn_more"=>"Learn More", "cookie_manage"=>"Manage Preferences", "cookie_close"=>"Close", "cookie_save"=>"Save Preferences", "cookie_privacy_policy"=>"Privacy Policy", "cookie_essential"=>"Essential", "cookie_essential_desc"=>"Required for core site functionality. Always enabled.", "cookie_analytics"=>"Analytics", "cookie_analytics_desc"=>"Help us understand how you use our site to improve it.", "cookie_marketing"=>"Marketing", "cookie_marketing_desc"=>"Allow us to show you relevant content and offers.", "cookie_performance"=>"Performance", "cookie_performance_desc"=>"Improve page speed and user experience.", "cookie_last_updated"=>"Last updated", "cookie_all_cookies"=>"All Cookies", "cookie_cookie_name"=>"Cookie Name", "cookie_purpose"=>"Purpose", "cookie_expiration"=>"Expiration"}, "fr"=>{"hero_title"=>"Vitrine : Mods & Packs Minecraft", "hero_subtitle"=>"Mods, packs de ressources, datapacks, modpacks et plugins — sélectionnés par notre organisation.", "browse_projects"=>"Parcourir les Projets", "learn_more"=>"En Savoir Plus", "featured_title"=>"Points Forts", "featured_subtitle"=>"Derniers ajouts à notre collection", "featured_badge"=>"En Vedette", "view_project"=>"Voir le Projet", "source"=>"Source", "stats_title"=>"Aperçu des Projets", "stats_subtitle"=>"Données en direct de notre cache Modrinth", "stat_total_projects"=>"Projets Totaux", "stat_total_downloads"=>"Téléchargements Totaux", "stat_supported_loaders"=>"Chargeurs Supportés", "stat_game_versions"=>"Versions du Jeu", "stat_top_categories"=>"Meilleures Catégories", "stat_top_downloads"=>"Meilleurs Téléchargements", "stat_downloads_note"=>"Projets les plus téléchargés", "stat_loading"=>"Chargement…", "stat_unavailable"=>"Indisponible", "stat_projects_catalog"=>"Projets dans le catalogue", "stat_avg_per_project"=>"moy par projet", "stat_unique_versions"=>"Versions de jeu uniques", "stat_no_categories"=>"Pas encore de catégories", "stat_no_data"=>"Aucune donnée de téléchargement disponible", "error_loading"=>"Erreur de chargement", "failed_to_load"=>"Échec du chargement", "no_projects_found"=>"Aucun projet trouvé. Ils se synchroniseront automatiquement.", "error_404_title"=>"Page Non Trouvée", "error_404_description"=>"La page que vous recherchez n'existe pas.", "error_404_message"=>"Désolé, nous n'avons pas pu trouver ce que vous cherchiez.", "error_404_back_home"=>"Retour à l'Accueil", "error_404_browse"=>"Parcourir les Projets", "cookie_title"=>"Préférences de Cookies", "cookie_message"=>"Nous utilisons des cookies pour améliorer votre expérience et analyser les performances du site. Aucune donnée personnelle n'est collectée.", "cookie_accept"=>"Accepter Tous", "cookie_reject"=>"Rejeter", "cookie_learn_more"=>"En Savoir Plus", "cookie_manage"=>"Gérer les Préférences", "cookie_close"=>"Fermer", "cookie_save"=>"Enregistrer les Préférences", "cookie_privacy_policy"=>"Politique de Confidentialité", "cookie_essential"=>"Essentiels", "cookie_essential_desc"=>"Requis pour les fonctionnalités principales du site. Toujours activés.", "cookie_analytics"=>"Analyse", "cookie_analytics_desc"=>"Nous aider à comprendre comment vous utilisez notre site pour l'améliorer.", "cookie_marketing"=>"Marketing", "cookie_marketing_desc"=>"Nous permettre de vous montrer du contenu et des offres pertinents.", "cookie_performance"=>"Performance", "cookie_performance_desc"=>"Améliorer la vitesse et l'expérience utilisateur des pages.", "cookie_last_updated"=>"Dernière mise à jour", "cookie_all_cookies"=>"Tous les Cookies", "cookie_cookie_name"=>"Nom du Cookie", "cookie_purpose"=>"Objet", "cookie_expiration"=>"Expiration"}}               # Data files

Page Variables

{{ page.title }}              # Current page title
{{ page.url }}                # Page URL
{{ page.date }}               # Post date
{{ page.content }}            # Page content
{{ page.excerpt }}            # Auto excerpt
{{ page.custom_field }}       # Custom frontmatter

Custom Data

Access _data/ files:


Filters

String Filters

Hello world        # "Hello world"
HELLO WORLD            # "HELLO WORLD"
hello world          # "hello world"
hello...       # "hello..."
hello there  # "hello there"
abc              # ["a", "b", "c"]
hello                 # "hello"
hello world        # "hello world"
hello world       # "hello world"
hello-world           # "hello-world"

Number Filters

6              # 6
2             # 2
8             # 8
2        # 2
5              # 5
5               # 5
4              # 4
12.34 # 12.34

Array Filters

{{ array | join: ", " }}       # Join with separator
{{ array | first }}            # First element
{{ array | last }}             # Last element
{{ array | size }}             # Array length
{{ array | reverse }}          # Reverse order
{{ array | sort }}             # Sort ascending
{{ array | uniq }}             # Remove duplicates
{{ array | where: "key", "value" }}  # Filter by property
{{ array | map: "name" }}      # Extract property

Date Filters

           # 2025-12-10
          # December 10, 2025
             # 10 Dec 2025
        # 10 December 2025
             # RFC-822 format
2025              # 2025

URL Filters

/assets/style.css     # /abc-site/assets/style.css
https://abc-site.devvyy.xyz/page                 # https://site.com/abc-site/page
path/to/file.html

Jekyll-Specific Filters

<section class="section">
  <p class="muted" style="margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px">Docs</p>
  <h1 style="margin-top:0">How to Download &amp; Install</h1>
  <p class="muted" style="max-width:680px">Step-by-step guide to download and install Minecraft content.</p>
  <article class="card" style="margin-top:20px;padding:20px;background:var(--card);border:1px solid var(--border)">
    <h2 id="step-by-step-guide">Step-by-Step Guide</h2>

<ol>
  <li>
    <p><strong>Open the Project Page</strong><br />
Visit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.</p>
  </li>
  <li>
    <p><strong>Find the Versions or Files Section</strong><br />
Look for a tab or section labelled <strong>Versions</strong>, <strong>Files</strong>, <strong>Releases</strong>, or <strong>Downloads</strong>.</p>
  </li>
  <li>
    <p><strong>Select Your Minecraft Version</strong></p>

    <ul>
      <li>Locate a list or dropdown called <strong>Version</strong>, <strong>Game Version</strong>, or <strong>Supported Versions</strong>.</li>
      <li>Pick the version that matches your Minecraft installation (e.g., <em>1.20.1</em>, <em>1.19.2</em>).</li>
    </ul>
  </li>
  <li>
    <p><strong>Choose the Correct File Type</strong><br />
The file type depends on the kind of content:</p>

    <ul>
      <li><strong>Mods:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Plugins:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Addons (Bedrock):</strong> <code class="language-plaintext highlighter-rouge">.mcaddon</code> / <code class="language-plaintext highlighter-rouge">.mcpack</code></li>
      <li><strong>Texture Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code></li>
      <li><strong>Data Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code> or extracted folder</li>
      <li><strong>Capes / Skin Addons:</strong> whichever format the creator provides</li>
    </ul>
  </li>
  <li>
    <p><strong>Download the File</strong><br />
Click the <strong>Download</strong>, <strong>Get</strong>, or <strong>File</strong> button next to the version you need.<br />
Save the file to your device.</p>
  </li>
  <li>
    <p><strong>Install According to Content Type</strong></p>

    <ul>
      <li><strong>Mods:</strong> place the <code class="language-plaintext highlighter-rouge">.jar</code> inside <code class="language-plaintext highlighter-rouge">.minecraft/mods</code>.</li>
      <li><strong>Plugins:</strong> move the <code class="language-plaintext highlighter-rouge">.jar</code> into your server’s <code class="language-plaintext highlighter-rouge">plugins</code> folder.</li>
      <li><strong>Texture Packs:</strong> place the <code class="language-plaintext highlighter-rouge">.zip</code> into <code class="language-plaintext highlighter-rouge">.minecraft/resourcepacks</code>.</li>
      <li><strong>Data Packs:</strong> put inside <code class="language-plaintext highlighter-rouge">world/datapacks</code>.</li>
      <li><strong>Addons (Bedrock):</strong> double-click <code class="language-plaintext highlighter-rouge">.mcaddon</code> or <code class="language-plaintext highlighter-rouge">.mcpack</code> to import automatically.</li>
    </ul>
  </li>
  <li>
    <p><strong>Restart Minecraft or Your Server</strong><br />
Reload or restart to apply the new content.</p>
  </li>
</ol>

  </article>
</section>
             # Convert Markdown to HTML

  Docs
  How to Download & Install
  Step-by-step guide to download and install Minecraft content.
  
    Step-by-Step Guide


  
    Open the Project Page
Visit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.
  
  
    Find the Versions or Files Section
Look for a tab or section labelled Versions, Files, Releases, or Downloads.
  
  
    Select Your Minecraft Version

    
      Locate a list or dropdown called Version, Game Version, or Supported Versions.
      Pick the version that matches your Minecraft installation (e.g., 1.20.1, 1.19.2).
    
  
  
    Choose the Correct File Type
The file type depends on the kind of content:

    
      Mods: .jar
      Plugins: .jar
      Addons (Bedrock): .mcaddon / .mcpack
      Texture Packs: .zip
      Data Packs: .zip or extracted folder
      Capes / Skin Addons: whichever format the creator provides
    
  
  
    Download the File
Click the Download, Get, or File button next to the version you need.
Save the file to your device.
  
  
    Install According to Content Type

    
      Mods: place the .jar inside .minecraft/mods.
      Plugins: move the .jar into your server’s plugins folder.
      Texture Packs: place the .zip into .minecraft/resourcepacks.
      Data Packs: put inside world/datapacks.
      Addons (Bedrock): double-click .mcaddon or .mcpack to import automatically.
    
  
  
    Restart Minecraft or Your Server
Reload or restart to apply the new content.
  


  

              # Remove HTML tags
270         # Word count
"<section class=\"section\">\n  <p class=\"muted\" style=\"margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px\">Docs</p>\n  <h1 style=\"margin-top:0\">How to Download & Install</h1>\n  <p class=\"muted\" style=\"max-width:680px\">Step-by-step guide to download and install Minecraft content.</p>\n  <article class=\"card\" style=\"margin-top:20px;padding:20px;background:var(--card);border:1px solid var(--border)\">\n    <h2 id=\"step-by-step-guide\">Step-by-Step Guide</h2>\n\n<ol>\n  <li>\n    <p><strong>Open the Project Page</strong><br />\nVisit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.</p>\n  </li>\n  <li>\n    <p><strong>Find the Versions or Files Section</strong><br />\nLook for a tab or section labelled <strong>Versions</strong>, <strong>Files</strong>, <strong>Releases</strong>, or <strong>Downloads</strong>.</p>\n  </li>\n  <li>\n    <p><strong>Select Your Minecraft Version</strong></p>\n\n    <ul>\n      <li>Locate a list or dropdown called <strong>Version</strong>, <strong>Game Version</strong>, or <strong>Supported Versions</strong>.</li>\n      <li>Pick the version that matches your Minecraft installation (e.g., <em>1.20.1</em>, <em>1.19.2</em>).</li>\n    </ul>\n  </li>\n  <li>\n    <p><strong>Choose the Correct File Type</strong><br />\nThe file type depends on the kind of content:</p>\n\n    <ul>\n      <li><strong>Mods:</strong> <code class=\"language-plaintext highlighter-rouge\">.jar</code></li>\n      <li><strong>Plugins:</strong> <code class=\"language-plaintext highlighter-rouge\">.jar</code></li>\n      <li><strong>Addons (Bedrock):</strong> <code class=\"language-plaintext highlighter-rouge\">.mcaddon</code> / <code class=\"language-plaintext highlighter-rouge\">.mcpack</code></li>\n      <li><strong>Texture Packs:</strong> <code class=\"language-plaintext highlighter-rouge\">.zip</code></li>\n      <li><strong>Data Packs:</strong> <code class=\"language-plaintext highlighter-rouge\">.zip</code> or extracted folder</li>\n      <li><strong>Capes / Skin Addons:</strong> whichever format the creator provides</li>\n    </ul>\n  </li>\n  <li>\n    <p><strong>Download the File</strong><br />\nClick the <strong>Download</strong>, <strong>Get</strong>, or <strong>File</strong> button next to the version you need.<br />\nSave the file to your device.</p>\n  </li>\n  <li>\n    <p><strong>Install According to Content Type</strong></p>\n\n    <ul>\n      <li><strong>Mods:</strong> place the <code class=\"language-plaintext highlighter-rouge\">.jar</code> inside <code class=\"language-plaintext highlighter-rouge\">.minecraft/mods</code>.</li>\n      <li><strong>Plugins:</strong> move the <code class=\"language-plaintext highlighter-rouge\">.jar</code> into your server’s <code class=\"language-plaintext highlighter-rouge\">plugins</code> folder.</li>\n      <li><strong>Texture Packs:</strong> place the <code class=\"language-plaintext highlighter-rouge\">.zip</code> into <code class=\"language-plaintext highlighter-rouge\">.minecraft/resourcepacks</code>.</li>\n      <li><strong>Data Packs:</strong> put inside <code class=\"language-plaintext highlighter-rouge\">world/datapacks</code>.</li>\n      <li><strong>Addons (Bedrock):</strong> double-click <code class=\"language-plaintext highlighter-rouge\">.mcaddon</code> or <code class=\"language-plaintext highlighter-rouge\">.mcpack</code> to import automatically.</li>\n    </ul>\n  </li>\n  <li>\n    <p><strong>Restart Minecraft or Your Server</strong><br />\nReload or restart to apply the new content.</p>\n  </li>\n</ol>\n\n  </article>\n</section>\n"                 # Convert to JSON
&lt;section class=&quot;section&quot;&gt;
  &lt;p class=&quot;muted&quot; style=&quot;margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px&quot;&gt;Docs&lt;/p&gt;
  &lt;h1 style=&quot;margin-top:0&quot;&gt;How to Download &amp; Install&lt;/h1&gt;
  &lt;p class=&quot;muted&quot; style=&quot;max-width:680px&quot;&gt;Step-by-step guide to download and install Minecraft content.&lt;/p&gt;
  &lt;article class=&quot;card&quot; style=&quot;margin-top:20px;padding:20px;background:var(--card);border:1px solid var(--border)&quot;&gt;
    &lt;h2 id=&quot;step-by-step-guide&quot;&gt;Step-by-Step Guide&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Open the Project Page&lt;/strong&gt;&lt;br /&gt;
Visit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Find the Versions or Files Section&lt;/strong&gt;&lt;br /&gt;
Look for a tab or section labelled &lt;strong&gt;Versions&lt;/strong&gt;, &lt;strong&gt;Files&lt;/strong&gt;, &lt;strong&gt;Releases&lt;/strong&gt;, or &lt;strong&gt;Downloads&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Select Your Minecraft Version&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Locate a list or dropdown called &lt;strong&gt;Version&lt;/strong&gt;, &lt;strong&gt;Game Version&lt;/strong&gt;, or &lt;strong&gt;Supported Versions&lt;/strong&gt;.&lt;/li&gt;
      &lt;li&gt;Pick the version that matches your Minecraft installation (e.g., &lt;em&gt;1.20.1&lt;/em&gt;, &lt;em&gt;1.19.2&lt;/em&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Choose the Correct File Type&lt;/strong&gt;&lt;br /&gt;
The file type depends on the kind of content:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Mods:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jar&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Plugins:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jar&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Addons (Bedrock):&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mcaddon&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mcpack&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Texture Packs:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.zip&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Data Packs:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.zip&lt;/code&gt; or extracted folder&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Capes / Skin Addons:&lt;/strong&gt; whichever format the creator provides&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Download the File&lt;/strong&gt;&lt;br /&gt;
Click the &lt;strong&gt;Download&lt;/strong&gt;, &lt;strong&gt;Get&lt;/strong&gt;, or &lt;strong&gt;File&lt;/strong&gt; button next to the version you need.&lt;br /&gt;
Save the file to your device.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install According to Content Type&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Mods:&lt;/strong&gt; place the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jar&lt;/code&gt; inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.minecraft/mods&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Plugins:&lt;/strong&gt; move the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jar&lt;/code&gt; into your server’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugins&lt;/code&gt; folder.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Texture Packs:&lt;/strong&gt; place the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.zip&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.minecraft/resourcepacks&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Data Packs:&lt;/strong&gt; put inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;world/datapacks&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Addons (Bedrock):&lt;/strong&gt; double-click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mcaddon&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mcpack&lt;/code&gt; to import automatically.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Restart Minecraft or Your Server&lt;/strong&gt;&lt;br /&gt;
Reload or restart to apply the new content.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

  &lt;/article&gt;
&lt;/section&gt;
              # Escape XML characters
%3Csection+class%3D%22section%22%3E%0A++%3Cp+class%3D%22muted%22+style%3D%22margin-bottom%3A6px%3Bletter-spacing%3A0.5px%3Btext-transform%3Auppercase%3Bfont-size%3A12px%22%3EDocs%3C%2Fp%3E%0A++%3Ch1+style%3D%22margin-top%3A0%22%3EHow+to+Download+%26+Install%3C%2Fh1%3E%0A++%3Cp+class%3D%22muted%22+style%3D%22max-width%3A680px%22%3EStep-by-step+guide+to+download+and+install+Minecraft+content.%3C%2Fp%3E%0A++%3Carticle+class%3D%22card%22+style%3D%22margin-top%3A20px%3Bpadding%3A20px%3Bbackground%3Avar%28--card%29%3Bborder%3A1px+solid+var%28--border%29%22%3E%0A++++%3Ch2+id%3D%22step-by-step-guide%22%3EStep-by-Step+Guide%3C%2Fh2%3E%0A%0A%3Col%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3EOpen+the+Project+Page%3C%2Fstrong%3E%3Cbr+%2F%3E%0AVisit+the+Modrinth%2C+CurseForge%2C+GitHub%2C+or+project+website+for+the+content+you+want+to+download.%3C%2Fp%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3EFind+the+Versions+or+Files+Section%3C%2Fstrong%3E%3Cbr+%2F%3E%0ALook+for+a+tab+or+section+labelled+%3Cstrong%3EVersions%3C%2Fstrong%3E%2C+%3Cstrong%3EFiles%3C%2Fstrong%3E%2C+%3Cstrong%3EReleases%3C%2Fstrong%3E%2C+or+%3Cstrong%3EDownloads%3C%2Fstrong%3E.%3C%2Fp%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3ESelect+Your+Minecraft+Version%3C%2Fstrong%3E%3C%2Fp%3E%0A%0A++++%3Cul%3E%0A++++++%3Cli%3ELocate+a+list+or+dropdown+called+%3Cstrong%3EVersion%3C%2Fstrong%3E%2C+%3Cstrong%3EGame+Version%3C%2Fstrong%3E%2C+or+%3Cstrong%3ESupported+Versions%3C%2Fstrong%3E.%3C%2Fli%3E%0A++++++%3Cli%3EPick+the+version+that+matches+your+Minecraft+installation+%28e.g.%2C+%3Cem%3E1.20.1%3C%2Fem%3E%2C+%3Cem%3E1.19.2%3C%2Fem%3E%29.%3C%2Fli%3E%0A++++%3C%2Ful%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3EChoose+the+Correct+File+Type%3C%2Fstrong%3E%3Cbr+%2F%3E%0AThe+file+type+depends+on+the+kind+of+content%3A%3C%2Fp%3E%0A%0A++++%3Cul%3E%0A++++++%3Cli%3E%3Cstrong%3EMods%3A%3C%2Fstrong%3E+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.jar%3C%2Fcode%3E%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EPlugins%3A%3C%2Fstrong%3E+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.jar%3C%2Fcode%3E%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EAddons+%28Bedrock%29%3A%3C%2Fstrong%3E+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.mcaddon%3C%2Fcode%3E+%2F+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.mcpack%3C%2Fcode%3E%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3ETexture+Packs%3A%3C%2Fstrong%3E+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.zip%3C%2Fcode%3E%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EData+Packs%3A%3C%2Fstrong%3E+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.zip%3C%2Fcode%3E+or+extracted+folder%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3ECapes+%2F+Skin+Addons%3A%3C%2Fstrong%3E+whichever+format+the+creator+provides%3C%2Fli%3E%0A++++%3C%2Ful%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3EDownload+the+File%3C%2Fstrong%3E%3Cbr+%2F%3E%0AClick+the+%3Cstrong%3EDownload%3C%2Fstrong%3E%2C+%3Cstrong%3EGet%3C%2Fstrong%3E%2C+or+%3Cstrong%3EFile%3C%2Fstrong%3E+button+next+to+the+version+you+need.%3Cbr+%2F%3E%0ASave+the+file+to+your+device.%3C%2Fp%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3EInstall+According+to+Content+Type%3C%2Fstrong%3E%3C%2Fp%3E%0A%0A++++%3Cul%3E%0A++++++%3Cli%3E%3Cstrong%3EMods%3A%3C%2Fstrong%3E+place+the+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.jar%3C%2Fcode%3E+inside+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.minecraft%2Fmods%3C%2Fcode%3E.%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EPlugins%3A%3C%2Fstrong%3E+move+the+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.jar%3C%2Fcode%3E+into+your+server%E2%80%99s+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3Eplugins%3C%2Fcode%3E+folder.%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3ETexture+Packs%3A%3C%2Fstrong%3E+place+the+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.zip%3C%2Fcode%3E+into+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.minecraft%2Fresourcepacks%3C%2Fcode%3E.%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EData+Packs%3A%3C%2Fstrong%3E+put+inside+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3Eworld%2Fdatapacks%3C%2Fcode%3E.%3C%2Fli%3E%0A++++++%3Cli%3E%3Cstrong%3EAddons+%28Bedrock%29%3A%3C%2Fstrong%3E+double-click+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.mcaddon%3C%2Fcode%3E+or+%3Ccode+class%3D%22language-plaintext+highlighter-rouge%22%3E.mcpack%3C%2Fcode%3E+to+import+automatically.%3C%2Fli%3E%0A++++%3C%2Ful%3E%0A++%3C%2Fli%3E%0A++%3Cli%3E%0A++++%3Cp%3E%3Cstrong%3ERestart+Minecraft+or+Your+Server%3C%2Fstrong%3E%3Cbr+%2F%3E%0AReload+or+restart+to+apply+the+new+content.%3C%2Fp%3E%0A++%3C%2Fli%3E%0A%3C%2Fol%3E%0A%0A++%3C%2Farticle%3E%0A%3C%2Fsection%3E%0A              # URL encode
%3Csection%20class=%22section%22%3E%0A%20%20%3Cp%20class=%22muted%22%20style=%22margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px%22%3EDocs%3C/p%3E%0A%20%20%3Ch1%20style=%22margin-top:0%22%3EHow%20to%20Download%20&%20Install%3C/h1%3E%0A%20%20%3Cp%20class=%22muted%22%20style=%22max-width:680px%22%3EStep-by-step%20guide%20to%20download%20and%20install%20Minecraft%20content.%3C/p%3E%0A%20%20%3Carticle%20class=%22card%22%20style=%22margin-top:20px;padding:20px;background:var(--card);border:1px%20solid%20var(--border)%22%3E%0A%20%20%20%20%3Ch2%20id=%22step-by-step-guide%22%3EStep-by-Step%20Guide%3C/h2%3E%0A%0A%3Col%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3EOpen%20the%20Project%20Page%3C/strong%3E%3Cbr%20/%3E%0AVisit%20the%20Modrinth,%20CurseForge,%20GitHub,%20or%20project%20website%20for%20the%20content%20you%20want%20to%20download.%3C/p%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3EFind%20the%20Versions%20or%20Files%20Section%3C/strong%3E%3Cbr%20/%3E%0ALook%20for%20a%20tab%20or%20section%20labelled%20%3Cstrong%3EVersions%3C/strong%3E,%20%3Cstrong%3EFiles%3C/strong%3E,%20%3Cstrong%3EReleases%3C/strong%3E,%20or%20%3Cstrong%3EDownloads%3C/strong%3E.%3C/p%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3ESelect%20Your%20Minecraft%20Version%3C/strong%3E%3C/p%3E%0A%0A%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%3Cli%3ELocate%20a%20list%20or%20dropdown%20called%20%3Cstrong%3EVersion%3C/strong%3E,%20%3Cstrong%3EGame%20Version%3C/strong%3E,%20or%20%3Cstrong%3ESupported%20Versions%3C/strong%3E.%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3EPick%20the%20version%20that%20matches%20your%20Minecraft%20installation%20(e.g.,%20%3Cem%3E1.20.1%3C/em%3E,%20%3Cem%3E1.19.2%3C/em%3E).%3C/li%3E%0A%20%20%20%20%3C/ul%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3EChoose%20the%20Correct%20File%20Type%3C/strong%3E%3Cbr%20/%3E%0AThe%20file%20type%20depends%20on%20the%20kind%20of%20content:%3C/p%3E%0A%0A%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EMods:%3C/strong%3E%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.jar%3C/code%3E%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EPlugins:%3C/strong%3E%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.jar%3C/code%3E%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EAddons%20(Bedrock):%3C/strong%3E%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.mcaddon%3C/code%3E%20/%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.mcpack%3C/code%3E%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3ETexture%20Packs:%3C/strong%3E%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.zip%3C/code%3E%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EData%20Packs:%3C/strong%3E%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.zip%3C/code%3E%20or%20extracted%20folder%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3ECapes%20/%20Skin%20Addons:%3C/strong%3E%20whichever%20format%20the%20creator%20provides%3C/li%3E%0A%20%20%20%20%3C/ul%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3EDownload%20the%20File%3C/strong%3E%3Cbr%20/%3E%0AClick%20the%20%3Cstrong%3EDownload%3C/strong%3E,%20%3Cstrong%3EGet%3C/strong%3E,%20or%20%3Cstrong%3EFile%3C/strong%3E%20button%20next%20to%20the%20version%20you%20need.%3Cbr%20/%3E%0ASave%20the%20file%20to%20your%20device.%3C/p%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3EInstall%20According%20to%20Content%20Type%3C/strong%3E%3C/p%3E%0A%0A%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EMods:%3C/strong%3E%20place%20the%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.jar%3C/code%3E%20inside%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.minecraft/mods%3C/code%3E.%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EPlugins:%3C/strong%3E%20move%20the%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.jar%3C/code%3E%20into%20your%20server%E2%80%99s%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3Eplugins%3C/code%3E%20folder.%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3ETexture%20Packs:%3C/strong%3E%20place%20the%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.zip%3C/code%3E%20into%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.minecraft/resourcepacks%3C/code%3E.%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EData%20Packs:%3C/strong%3E%20put%20inside%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3Eworld/datapacks%3C/code%3E.%3C/li%3E%0A%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EAddons%20(Bedrock):%3C/strong%3E%20double-click%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.mcaddon%3C/code%3E%20or%20%3Ccode%20class=%22language-plaintext%20highlighter-rouge%22%3E.mcpack%3C/code%3E%20to%20import%20automatically.%3C/li%3E%0A%20%20%20%20%3C/ul%3E%0A%20%20%3C/li%3E%0A%20%20%3Cli%3E%0A%20%20%20%20%3Cp%3E%3Cstrong%3ERestart%20Minecraft%20or%20Your%20Server%3C/strong%3E%3Cbr%20/%3E%0AReload%20or%20restart%20to%20apply%20the%20new%20content.%3C/p%3E%0A%20%20%3C/li%3E%0A%3C/ol%3E%0A%0A%20%20%3C/article%3E%0A%3C/section%3E%0A              # URI encode

Control Flow

If Statements


  <span class="badge">Developer</span>





  # Liquid Templates Guide

Master Jekyll's Liquid templating language for dynamic content generation.

## Basics

### Output Tags

Display variables and expressions:

```liquid
{{ variable }}
{{ site.title }}
{{ page.description }}

Logic Tags

Control flow and iteration:

{% if condition %}
  ...
{% elsif other_condition %}
  ...
{% else %}
  ...
{% endif %}

{% for item in array %}
  {{ item }}
{% endfor %}

Variables

Site Variables

{{ site.title }}              # From _config.yml
{{ site.description }}
{{ site.baseurl }}
{{ site.url }}
{{ site.time }}               # Build timestamp
{{ site.pages }}              # All pages
{{ site.posts }}              # All posts
{{ site.data }}               # Data files

Page Variables

{% raw %}

{{ page.title }}              # Current page title
{{ page.url }}                # Page URL
{{ page.date }}               # Post date
{{ page.content }}            # Page content
{{ page.excerpt }}            # Auto excerpt
{{ page.custom_field }}       # Custom frontmatter

{% endraw %}

Custom Data

Access _data/ files:

{% for modpack in site.data.mods.modpacks %}
  {{ modpack.name }}
  {{ modpack.description }}
{% endfor %}

Filters

String Filters

{{ "hello world" | capitalize }}        # "Hello world"
{{ "hello world" | upcase }}            # "HELLO WORLD"
{{ "HELLO WORLD" | downcase }}          # "hello world"
{{ "hello world" | truncate: 8 }}       # "hello..."
{{ "hello world" | replace: "world", "there" }}  # "hello there"
{{ "a,b,c" | split: "," }}              # ["a", "b", "c"]
{{ " hello " | strip }}                 # "hello"
{{ "hello" | append: " world" }}        # "hello world"
{{ "world" | prepend: "hello " }}       # "hello world"
{{ "hello-world" | slugify }}           # "hello-world"

Number Filters

{{ 4 | plus: 2 }}              # 6
{{ 4 | minus: 2 }}             # 2
{{ 4 | times: 2 }}             # 8
{{ 4 | divided_by: 2 }}        # 2
{{ 4.5 | round }}              # 5
{{ 4.5 | ceil }}               # 5
{{ 4.5 | floor }}              # 4
{{ 1234 | divided_by: 100.0 }} # 12.34

Array Filters

{% raw %}

{{ array | join: ", " }}       # Join with separator
{{ array | first }}            # First element
{{ array | last }}             # Last element
{{ array | size }}             # Array length
{{ array | reverse }}          # Reverse order
{{ array | sort }}             # Sort ascending
{{ array | uniq }}             # Remove duplicates
{{ array | where: "key", "value" }}  # Filter by property
{{ array | map: "name" }}      # Extract property

{% endraw %}

Date Filters

{{ page.date | date: "%Y-%m-%d" }}           # 2025-12-10
{{ page.date | date: "%B %d, %Y" }}          # December 10, 2025
{{ page.date | date_to_string }}             # 10 Dec 2025
{{ page.date | date_to_long_string }}        # 10 December 2025
{{ page.date | date_to_rfc822 }}             # RFC-822 format
{{ "2025-12-10" | date: "%Y" }}              # 2025

URL Filters

{{ "/assets/style.css" | relative_url }}     # /abc-site/assets/style.css
{{ "/page" | absolute_url }}                 # https://site.com/abc-site/page
{{ "path/to/file.md" | replace: ".md", ".html" }}

Jekyll-Specific Filters

{{ content | markdownify }}             # Convert Markdown to HTML
{{ content | strip_html }}              # Remove HTML tags
{{ content | number_of_words }}         # Word count
{{ content | jsonify }}                 # Convert to JSON
{{ content | xml_escape }}              # Escape XML characters
{{ content | cgi_escape }}              # URL encode
{{ content | uri_escape }}              # URI encode

Control Flow

If Statements

{% if page.category == "Developer" %}
  <span class="badge">Developer</span>
{% endif %}

{% if page.tags contains "featured" %}
  <span class="featured">★</span>
{% endif %}

{% unless page.published == false %}
  {{ page.content }}
{% endunless %}

Case Statements

{% case page.category %}
  {% when "Setup" %}
    <i class="fa-gear"></i>
  {% when "Styling" %}
    <i class="fa-palette"></i>
  {% else %}
    <i class="fa-file"></i>
{% endcase %}

Loops

{% for doc in site.docs %}
  <li>{{ doc.title }}</li>
{% endfor %}

{% for doc in site.docs limit:5 %}
  <!-- First 5 only -->
{% endfor %}

{% for doc in site.docs offset:5 %}
  <!-- Skip first 5 -->
{% endfor %}

{% for doc in site.docs reversed %}
  <!-- Reverse order -->
{% endfor %}

Loop Variables

{% for item in array %}
  {{ forloop.index }}        # 1, 2, 3, ...
  {{ forloop.index0 }}       # 0, 1, 2, ...
  {{ forloop.first }}        # true on first iteration
  {{ forloop.last }}         # true on last iteration
  {{ forloop.length }}       # Total iterations
  {{ forloop.rindex }}       # Reverse index (from end)
{% endfor %}

Break & Continue

{% for item in array %}
  {% if item.hide %}
    {% continue %}
  {% endif %}

  {% if forloop.index > 10 %}
    {% break %}
  {% endif %}

  {{ item.name }}
{% endfor %}

Advanced Techniques

Assign Variables

{% assign my_var = "value" %}
{% assign count = site.docs | size %}
{% assign featured = site.docs | where: "featured", true %}

Capture Blocks

{% capture my_variable %}
  Complex content with {{ page.title }}
  and calculations: {{ 5 | times: 10 }}
{% endcapture %}

{{ my_variable }}

Includes

Create reusable components in _includes/:

{% raw %}

{% include header.html %}
{% include card.html title="Test" description="Description" %}

{% endraw %}

With parameters:

{% raw %}

<!-- _includes/card.html -->
<div class="card">
  <h3>{{ include.title }}</h3>
  <p>{{ include.description }}</p>
</div>

{% endraw %}

Layouts

Inherit from layouts:

<!-- _layouts/docs.html -->
<!DOCTYPE html>
<html>
  <body>
    {{ content }}
  </body>
</html>

In page frontmatter:

---
layout: docs
title: My Page
---

Practical Examples

<nav>
  {% for item in site.data.navigation %}
    <a href="{{ item.url | relative_url }}"
       {% if page.url == item.url %}class="active"{% endif %}>
      {{ item.title }}
    </a>
  {% endfor %}
</nav>
<nav class="breadcrumbs">
  <a href="{{ '/' | relative_url }}">Home</a>
  {% if page.category %}
    <span>/</span>
    <a href="{{ '/docs/category/' | append: page.category | slugify | append: '/' | relative_url }}">
      {{ page.category }}
    </a>
  {% endif %}
  <span>/</span>
  <span>{{ page.title }}</span>
</nav>

Pagination

{% if paginator.total_pages > 1 %}
  <div class="pagination">
    {% if paginator.previous_page %}
      <a href="{{ paginator.previous_page_path | relative_url }}">Previous</a>
    {% endif %}

    <span>Page {{ paginator.page }} of {{ paginator.total_pages }}</span>

    {% if paginator.next_page %}
      <a href="{{ paginator.next_page_path | relative_url }}">Next</a>
    {% endif %}
  </div>
{% endif %}
{% assign related = site.docs | where: "category", page.category |
                    where_exp: "doc", "doc.url != page.url" |
                    limit: 3 %}

{% if related.size > 0 %}
  <h3>Related Documentation</h3>
  <ul>
    {% for doc in related %}
      <li><a href="{{ doc.url | relative_url }}">{{ doc.title }}</a></li>
    {% endfor %}
  </ul>
{% endif %}

Conditional CSS Classes

<article class="
  {% if page.featured %}featured{% endif %}
  {% if page.category %}category-{{ page.category | slugify }}{% endif %}
  {% if page.tags contains 'important' %}important{% endif %}
">
  {{ content }}
</article>

Performance Tips

  1. Assign once, use many times:

    {% assign docs = site.docs | where: "category", "Setup" %}
    
  2. Avoid nested loops when possible:

    <!-- Slow -->
    {% for doc in site.docs %}
      {% for tag in doc.tags %}
        ...
      {% endfor %}
    {% endfor %}
    
    <!-- Faster -->
    {% assign all_tags = site.docs | map: "tags" | join: "," | default: "" | split: "," | uniq %}
    
  3. Cache expensive operations:

    {% capture cached_content %}
      <!-- Complex logic here -->
    {% endcapture %}
    

Debugging

Inspect Variables

{{ variable | inspect }}
{{ site.data | jsonify }}

Check Types

{% if variable %}
  Variable exists and is truthy
{% endif %}

{% if variable == nil %}
  Variable is nil
{% endif %}

{% if variable == blank %}
  Variable is nil, false, or empty
{% endif %}

Next Steps


### Case Statements

```liquid

    <i class="fa-file"></i>

Loops


  <li>Accessibility Guide</li>

  <li>Adding Modpacks</li>

  <li>API Reference</li>

  <li>Browser Support</li>

  <li>Common Errors & Troubleshooting</li>

  <li>Content Guidelines</li>

  <li>Contributing</li>

  <li>CSS Variables Reference</li>

  <li>Customization</li>

  <li>Deployment Guide</li>

  <li>FAQ</li>

  <li>Getting Started</li>

  <li>GitHub Actions</li>

  <li>How to Download & Install</li>

  <li>Liquid Templates</li>

  <li>Performance Optimization</li>

  <li>Project Structure</li>

  <li>SEO Guide</li>

  <li>Setup & Configuration</li>

  <li>Troubleshooting</li>



  <!-- First 5 only -->

  <!-- First 5 only -->

  <!-- First 5 only -->

  <!-- First 5 only -->

  <!-- First 5 only -->



  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->

  <!-- Skip first 5 -->



  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

  <!-- Reverse order -->

Loop Variables


Break & Continue


Advanced Techniques

Assign Variables




Capture Blocks




  Complex content with Liquid Templates
  and calculations: 50

Includes

Create reusable components in _includes/:

{% include header.html %}
{% include card.html title="Test" description="Description" %}

With parameters:

<!-- _includes/card.html -->
<div class="card">
  <h3>{{ include.title }}</h3>
  <p>{{ include.description }}</p>
</div>

Layouts

Inherit from layouts:

<!-- _layouts/docs.html -->
<!DOCTYPE html>
<html>
  <body>
    <section class="section">
  <p class="muted" style="margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px">Docs</p>
  <h1 style="margin-top:0">How to Download & Install</h1>
  <p class="muted" style="max-width:680px">Step-by-step guide to download and install Minecraft content.</p>
  <article class="card" style="margin-top:20px;padding:20px;background:var(--card);border:1px solid var(--border)">
    <h2 id="step-by-step-guide">Step-by-Step Guide</h2>

<ol>
  <li>
    <p><strong>Open the Project Page</strong><br />
Visit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.</p>
  </li>
  <li>
    <p><strong>Find the Versions or Files Section</strong><br />
Look for a tab or section labelled <strong>Versions</strong>, <strong>Files</strong>, <strong>Releases</strong>, or <strong>Downloads</strong>.</p>
  </li>
  <li>
    <p><strong>Select Your Minecraft Version</strong></p>

    <ul>
      <li>Locate a list or dropdown called <strong>Version</strong>, <strong>Game Version</strong>, or <strong>Supported Versions</strong>.</li>
      <li>Pick the version that matches your Minecraft installation (e.g., <em>1.20.1</em>, <em>1.19.2</em>).</li>
    </ul>
  </li>
  <li>
    <p><strong>Choose the Correct File Type</strong><br />
The file type depends on the kind of content:</p>

    <ul>
      <li><strong>Mods:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Plugins:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Addons (Bedrock):</strong> <code class="language-plaintext highlighter-rouge">.mcaddon</code> / <code class="language-plaintext highlighter-rouge">.mcpack</code></li>
      <li><strong>Texture Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code></li>
      <li><strong>Data Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code> or extracted folder</li>
      <li><strong>Capes / Skin Addons:</strong> whichever format the creator provides</li>
    </ul>
  </li>
  <li>
    <p><strong>Download the File</strong><br />
Click the <strong>Download</strong>, <strong>Get</strong>, or <strong>File</strong> button next to the version you need.<br />
Save the file to your device.</p>
  </li>
  <li>
    <p><strong>Install According to Content Type</strong></p>

    <ul>
      <li><strong>Mods:</strong> place the <code class="language-plaintext highlighter-rouge">.jar</code> inside <code class="language-plaintext highlighter-rouge">.minecraft/mods</code>.</li>
      <li><strong>Plugins:</strong> move the <code class="language-plaintext highlighter-rouge">.jar</code> into your server’s <code class="language-plaintext highlighter-rouge">plugins</code> folder.</li>
      <li><strong>Texture Packs:</strong> place the <code class="language-plaintext highlighter-rouge">.zip</code> into <code class="language-plaintext highlighter-rouge">.minecraft/resourcepacks</code>.</li>
      <li><strong>Data Packs:</strong> put inside <code class="language-plaintext highlighter-rouge">world/datapacks</code>.</li>
      <li><strong>Addons (Bedrock):</strong> double-click <code class="language-plaintext highlighter-rouge">.mcaddon</code> or <code class="language-plaintext highlighter-rouge">.mcpack</code> to import automatically.</li>
    </ul>
  </li>
  <li>
    <p><strong>Restart Minecraft or Your Server</strong><br />
Reload or restart to apply the new content.</p>
  </li>
</ol>

  </article>
</section>

  </body>
</html>

In page frontmatter:

---
layout: docs
title: My Page
---

Practical Examples

<nav>
  
</nav>
<nav class="breadcrumbs">
  <a href="/">Home</a>
  
    <span>/</span>
    <a href="/docs-category-developer/">
      Developer
    </a>
  
  <span>/</span>
  <span>Liquid Templates</span>
</nav>

Pagination





  <h3>Related Documentation</h3>
  <ul>
    
      <li><a href="/docs/api-reference/">API Reference</a></li>
    
      <li><a href="/docs/deployment/">Deployment Guide</a></li>
    
      <li><a href="/docs/github-actions/">GitHub Actions</a></li>
    
      <li><a href="/docs/performance/">Performance Optimization</a></li>
    
      <li><a href="/docs/project-structure/">Project Structure</a></li>
    
      <li><a href="/docs/seo-guide/">SEO Guide</a></li>
    
  </ul>

Conditional CSS Classes

<article class="
  
  category-developer
  
">
  <section class="section">
  <p class="muted" style="margin-bottom:6px;letter-spacing:0.5px;text-transform:uppercase;font-size:12px">Docs</p>
  <h1 style="margin-top:0">How to Download & Install</h1>
  <p class="muted" style="max-width:680px">Step-by-step guide to download and install Minecraft content.</p>
  <article class="card" style="margin-top:20px;padding:20px;background:var(--card);border:1px solid var(--border)">
    <h2 id="step-by-step-guide">Step-by-Step Guide</h2>

<ol>
  <li>
    <p><strong>Open the Project Page</strong><br />
Visit the Modrinth, CurseForge, GitHub, or project website for the content you want to download.</p>
  </li>
  <li>
    <p><strong>Find the Versions or Files Section</strong><br />
Look for a tab or section labelled <strong>Versions</strong>, <strong>Files</strong>, <strong>Releases</strong>, or <strong>Downloads</strong>.</p>
  </li>
  <li>
    <p><strong>Select Your Minecraft Version</strong></p>

    <ul>
      <li>Locate a list or dropdown called <strong>Version</strong>, <strong>Game Version</strong>, or <strong>Supported Versions</strong>.</li>
      <li>Pick the version that matches your Minecraft installation (e.g., <em>1.20.1</em>, <em>1.19.2</em>).</li>
    </ul>
  </li>
  <li>
    <p><strong>Choose the Correct File Type</strong><br />
The file type depends on the kind of content:</p>

    <ul>
      <li><strong>Mods:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Plugins:</strong> <code class="language-plaintext highlighter-rouge">.jar</code></li>
      <li><strong>Addons (Bedrock):</strong> <code class="language-plaintext highlighter-rouge">.mcaddon</code> / <code class="language-plaintext highlighter-rouge">.mcpack</code></li>
      <li><strong>Texture Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code></li>
      <li><strong>Data Packs:</strong> <code class="language-plaintext highlighter-rouge">.zip</code> or extracted folder</li>
      <li><strong>Capes / Skin Addons:</strong> whichever format the creator provides</li>
    </ul>
  </li>
  <li>
    <p><strong>Download the File</strong><br />
Click the <strong>Download</strong>, <strong>Get</strong>, or <strong>File</strong> button next to the version you need.<br />
Save the file to your device.</p>
  </li>
  <li>
    <p><strong>Install According to Content Type</strong></p>

    <ul>
      <li><strong>Mods:</strong> place the <code class="language-plaintext highlighter-rouge">.jar</code> inside <code class="language-plaintext highlighter-rouge">.minecraft/mods</code>.</li>
      <li><strong>Plugins:</strong> move the <code class="language-plaintext highlighter-rouge">.jar</code> into your server’s <code class="language-plaintext highlighter-rouge">plugins</code> folder.</li>
      <li><strong>Texture Packs:</strong> place the <code class="language-plaintext highlighter-rouge">.zip</code> into <code class="language-plaintext highlighter-rouge">.minecraft/resourcepacks</code>.</li>
      <li><strong>Data Packs:</strong> put inside <code class="language-plaintext highlighter-rouge">world/datapacks</code>.</li>
      <li><strong>Addons (Bedrock):</strong> double-click <code class="language-plaintext highlighter-rouge">.mcaddon</code> or <code class="language-plaintext highlighter-rouge">.mcpack</code> to import automatically.</li>
    </ul>
  </li>
  <li>
    <p><strong>Restart Minecraft or Your Server</strong><br />
Reload or restart to apply the new content.</p>
  </li>
</ol>

  </article>
</section>

</article>

Performance Tips

  1. Assign once, use many times:

       
    
  2. Avoid nested loops when possible:

    <!-- Slow -->
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
         
        ...
         
        ...
         
        ...
         
        ...
         
       
    
    <!-- Faster -->
       
    
  3. Cache expensive operations:

       
    

Debugging

Inspect Variables

nil
{"en":{"hero_title":"Showcase: Minecraft Mods & Packs","hero_subtitle":"Mods, resource packs, datapacks, modpacks and plugins — curated from our organization.","browse_projects":"Browse Projects","learn_more":"Learn More","featured_title":"Featured Highlights","featured_subtitle":"Latest additions to our growing collection","featured_badge":"Featured","view_project":"View Project","source":"Source","stats_title":"Project Snapshot","stats_subtitle":"Live data pulled from our Modrinth cache","stat_total_projects":"Total Projects","stat_total_downloads":"Total Downloads","stat_supported_loaders":"Supported Loaders","stat_game_versions":"Game Versions","stat_top_categories":"Top Categories","stat_top_downloads":"Top Downloads","stat_downloads_note":"Highest downloaded projects","stat_loading":"Loading…","stat_unavailable":"Unavailable","stat_projects_catalog":"Projects in catalog","stat_avg_per_project":"avg per project","stat_unique_versions":"Unique game versions","stat_no_categories":"No categories yet","stat_no_data":"No download data available yet","error_loading":"Error loading","failed_to_load":"Failed to load","no_projects_found":"No projects found. They will sync automatically.","error_404_title":"Page Not Found","error_404_description":"The page you're looking for doesn't exist.","error_404_message":"Sorry, we couldn't find what you were looking for.","error_404_back_home":"Back to Home","error_404_browse":"Browse Projects","cookie_title":"Cookie Preferences","cookie_message":"We use cookies to improve your experience and analyze site performance. No personal data is collected.","cookie_accept":"Accept All","cookie_reject":"Reject","cookie_learn_more":"Learn More","cookie_manage":"Manage Preferences","cookie_close":"Close","cookie_save":"Save Preferences","cookie_privacy_policy":"Privacy Policy","cookie_essential":"Essential","cookie_essential_desc":"Required for core site functionality. Always enabled.","cookie_analytics":"Analytics","cookie_analytics_desc":"Help us understand how you use our site to improve it.","cookie_marketing":"Marketing","cookie_marketing_desc":"Allow us to show you relevant content and offers.","cookie_performance":"Performance","cookie_performance_desc":"Improve page speed and user experience.","cookie_last_updated":"Last updated","cookie_all_cookies":"All Cookies","cookie_cookie_name":"Cookie Name","cookie_purpose":"Purpose","cookie_expiration":"Expiration"},"fr":{"hero_title":"Vitrine : Mods & Packs Minecraft","hero_subtitle":"Mods, packs de ressources, datapacks, modpacks et plugins — sélectionnés par notre organisation.","browse_projects":"Parcourir les Projets","learn_more":"En Savoir Plus","featured_title":"Points Forts","featured_subtitle":"Derniers ajouts à notre collection","featured_badge":"En Vedette","view_project":"Voir le Projet","source":"Source","stats_title":"Aperçu des Projets","stats_subtitle":"Données en direct de notre cache Modrinth","stat_total_projects":"Projets Totaux","stat_total_downloads":"Téléchargements Totaux","stat_supported_loaders":"Chargeurs Supportés","stat_game_versions":"Versions du Jeu","stat_top_categories":"Meilleures Catégories","stat_top_downloads":"Meilleurs Téléchargements","stat_downloads_note":"Projets les plus téléchargés","stat_loading":"Chargement…","stat_unavailable":"Indisponible","stat_projects_catalog":"Projets dans le catalogue","stat_avg_per_project":"moy par projet","stat_unique_versions":"Versions de jeu uniques","stat_no_categories":"Pas encore de catégories","stat_no_data":"Aucune donnée de téléchargement disponible","error_loading":"Erreur de chargement","failed_to_load":"Échec du chargement","no_projects_found":"Aucun projet trouvé. Ils se synchroniseront automatiquement.","error_404_title":"Page Non Trouvée","error_404_description":"La page que vous recherchez n'existe pas.","error_404_message":"Désolé, nous n'avons pas pu trouver ce que vous cherchiez.","error_404_back_home":"Retour à l'Accueil","error_404_browse":"Parcourir les Projets","cookie_title":"Préférences de Cookies","cookie_message":"Nous utilisons des cookies pour améliorer votre expérience et analyser les performances du site. Aucune donnée personnelle n'est collectée.","cookie_accept":"Accepter Tous","cookie_reject":"Rejeter","cookie_learn_more":"En Savoir Plus","cookie_manage":"Gérer les Préférences","cookie_close":"Fermer","cookie_save":"Enregistrer les Préférences","cookie_privacy_policy":"Politique de Confidentialité","cookie_essential":"Essentiels","cookie_essential_desc":"Requis pour les fonctionnalités principales du site. Toujours activés.","cookie_analytics":"Analyse","cookie_analytics_desc":"Nous aider à comprendre comment vous utilisez notre site pour l'améliorer.","cookie_marketing":"Marketing","cookie_marketing_desc":"Nous permettre de vous montrer du contenu et des offres pertinents.","cookie_performance":"Performance","cookie_performance_desc":"Améliorer la vitesse et l'expérience utilisateur des pages.","cookie_last_updated":"Dernière mise à jour","cookie_all_cookies":"Tous les Cookies","cookie_cookie_name":"Nom du Cookie","cookie_purpose":"Objet","cookie_expiration":"Expiration"}}

Check Types




  Variable is nil



Next Steps