<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Primary SEO -->
<title>WPSkins.org – Free Website Themes for WordPress, Shopify, Webflow, Astro & More</title>
<meta name="description" content="Browse 2,500+ free website themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more. Beautiful, responsive themes for every platform and niche.">
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">
<link rel="canonical" href="https://wpskins.org/">
<!-- Immediately correct canonical to actual URL path before JS loads (prevents duplicate-canonical GSC errors) -->
<script>
(function(){
  var c = document.querySelector('link[rel="canonical"]');
  if (c) {
    var p = location.pathname.replace(/\/$/, '');
    c.href = 'https://wpskins.org' + (p || '/');
  }
})();
</script>

<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="WPSkins.org">
<meta property="og:title" content="WPSkins.org – Free Website Themes for WordPress, Shopify, Webflow, Astro & More">
<meta property="og:description" content="Browse 2,500+ free website themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more. Beautiful, responsive, and ready to use.">
<meta property="og:url" id="og-url" content="https://wpskins.org/">
<meta property="og:image" content="https://wpskins.org/og-image.png">
<script>
(function(){
  var el = document.getElementById('og-url');
  if (el) {
    var p = location.pathname.replace(/\/$/, '');
    el.content = 'https://wpskins.org' + (p || '/');
  }
})();
</script>
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="WPSkins.org – Free Website Themes">
<meta property="og:locale" content="en_US">

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@wpskins">
<meta name="twitter:title" content="WPSkins.org – Free Website Themes">
<meta name="twitter:description" content="Browse 2,500+ free website themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more.">
<meta name="twitter:image" content="https://wpskins.org/og-image.png">

<!-- Structured Data: WebSite + Organization -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "WebSite",
      "@id": "https://wpskins.org/#website",
      "url": "https://wpskins.org/",
      "name": "WPSkins.org",
      "description": "Free website themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more",
      "publisher": { "@id": "https://wpskins.org/#organization" }
    },
    {
      "@type": "Organization",
      "@id": "https://wpskins.org/#organization",
      "name": "WPSkins.org",
      "url": "https://wpskins.org/",
      "logo": {
        "@type": "ImageObject",
        "url": "https://wpskins.org/images/wpskins_logo.png",
        "width": 200,
        "height": 60
      }
    }
  ]
}
</script>

<!-- Favicon -->
<link rel="icon" type="image/png" href="/images/wpskins_logo.png">
<link rel="apple-touch-icon" href="/images/wpskins_logo.png">

<!-- Performance: preconnect to critical origins -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://owrkygjvavcgyneakcbt.supabase.co">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">

<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&display=swap" rel="stylesheet">
<script data-cfasync="false" src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
--wp-dark:#ffffff;--wp-panel:#f8f9fa;--wp-card:#ffffff;--wp-border:#e1e4e8;
--wp-accent:#3b82f6;--wp-accent2:#8b5cf6;--wp-gold:#f59e0b;
--wp-green:#10b981;--wp-red:#ef4444;--wp-text:#1a1a1a;
--wp-muted:#6b7280;--wp-subtle:#4a5568;
--font-head:Arial,sans-serif;--font-body:'DM Sans',sans-serif;
}
body{background:var(--wp-dark);color:var(--wp-text);font-family:var(--font-body);font-size:15px;line-height:1.6;min-height:100vh}
#nav{background:var(--wp-panel);border-bottom:1px solid var(--wp-border);padding:0 24px;display:flex;align-items:center;height:56px;position:sticky;top:0;z-index:100}
.nav-logo{font-family:var(--font-head);font-weight:800;font-size:20px;color:#fff;text-decoration:none;margin-right:32px;letter-spacing:-0.5px;cursor:pointer}
.nav-logo span{color:var(--wp-accent)}
.nav-links{display:flex;gap:4px;flex:1}
.nav-link{background:none;border:none;color:var(--wp-muted);font-family:var(--font-body);font-size:14px;font-weight:500;padding:6px 14px;border-radius:8px;cursor:pointer;transition:all .2s}
.nav-link:hover,.nav-link.active{background:rgba(59,130,246,.12);color:var(--wp-accent)}
.nav-link.admin-link{color:#f59e0b}.nav-link.admin-link:hover{background:rgba(245,158,11,.12)}
.nav-right{display:flex;align-items:center;gap:10px;margin-left:auto}
.nav-btn{background:var(--wp-accent);border:none;color:#fff;font-family:var(--font-body);font-size:13px;font-weight:600;padding:7px 16px;border-radius:8px;cursor:pointer;transition:all .2s}
.nav-btn:hover{background:#2563eb}
.nav-btn.ghost{background:transparent;border:1px solid var(--wp-border);color:var(--wp-text)}
.nav-btn.ghost:hover{border-color:var(--wp-accent);color:var(--wp-accent)}
.user-avatar{width:32px;height:32px;border-radius:50%;background:var(--wp-accent2);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;cursor:pointer;color:#fff}
.page{display:none}.page.active{display:block}
.container{max-width:1280px;margin:0 auto;padding:0 24px}
.with-sidebar{display:grid;grid-template-columns:240px 1fr;gap:24px;padding-top:24px}
.sidebar{position:sticky;top:80px;height:calc(100vh - 100px);overflow-y:auto}
.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:var(--wp-border);border-radius:4px}
.sidebar-box{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:12px;padding:16px;margin-bottom:16px}
.sidebar-box h3{font-family:var(--font-head);font-size:12px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px}
.sidebar select{width:100%;background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:13px;padding:8px 10px;border-radius:8px;cursor:pointer;outline:none}
.color-swatches{display:flex;flex-wrap:wrap;gap:6px}
.swatch-item{display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer}
.swatch{width:22px;height:22px;border-radius:50%;border:2px solid transparent;transition:all .2s;cursor:pointer}
.swatch.checked,.swatch:hover{border-color:#fff;transform:scale(1.1)}
.swatch-label{font-size:9px;color:var(--wp-muted)}
.filter-row{display:flex;flex-direction:column;gap:6px}
.filter-btn{background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-muted);font-size:12px;padding:5px 10px;border-radius:6px;cursor:pointer;text-align:left;transition:all .2s;font-family:var(--font-body)}
.filter-btn:hover,.filter-btn.active{background:rgba(59,130,246,.12);border-color:var(--wp-accent);color:var(--wp-accent)}
.clear-btn{width:100%;background:transparent;border:1px solid var(--wp-border);color:var(--wp-muted);font-size:12px;padding:8px;border-radius:8px;cursor:pointer;font-family:var(--font-body);transition:all .2s}
.clear-btn:hover{border-color:var(--wp-red);color:var(--wp-red)}
.latest-list{list-style:none}
.latest-list li{border-bottom:1px solid var(--wp-border);padding:8px 0;cursor:pointer}
.latest-list li:last-child{border-bottom:none}
.latest-list li .t{font-size:13px;color:var(--wp-text);font-weight:500}
.latest-list li .m{font-size:11px;color:var(--wp-muted)}
.latest-list li:hover .t{color:var(--wp-accent)}
.main-area{padding-top:24px;padding-bottom:48px}
.sort-tabs{display:flex;gap:4px;margin-bottom:20px;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:10px;padding:4px;width:fit-content}
.sort-tab{background:none;border:none;color:var(--wp-muted);font-family:var(--font-body);font-size:13px;font-weight:500;padding:6px 16px;border-radius:7px;cursor:pointer;transition:all .2s}
.sort-tab.active{background:var(--wp-accent);color:#fff}
.themes-count{font-size:13px;color:var(--wp-muted);margin-bottom:16px}
.themes-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:20px}
.theme-card{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:12px;overflow:hidden;cursor:pointer;transition:all .2s;position:relative}
.theme-card:hover{border-color:var(--wp-accent);transform:translateY(-3px);box-shadow:0 8px 32px rgba(59,130,246,.15)}
.theme-thumb{width:100%;aspect-ratio:4/3;background:var(--wp-card);position:relative;overflow:hidden}
.theme-thumb img{width:100%;height:100%;object-fit:cover}
.theme-thumb .no-img{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:40px;color:var(--wp-border)}
.platform-badge{position:absolute;top:8px;left:8px;color:white;padding:4px 10px;border-radius:6px;font-size:10px;font-weight:700;backdrop-filter:blur(8px);opacity:0.95}
.badge-featured{position:absolute;top:8px;right:8px;background:#f59e0b;color:#1c1400;font-size:10px;font-weight:700;padding:3px 8px;border-radius:6px}
.theme-info{padding:14px}
.theme-name{font-family:var(--font-head);font-size:15px;font-weight:700;color:var(--wp-text);margin-bottom:4px}
.theme-meta{display:flex;gap:12px;font-size:12px;color:var(--wp-muted)}
.theme-tags{display:flex;gap:4px;margin-top:8px;flex-wrap:wrap}
.tag{background:rgba(59,130,246,.1);color:var(--wp-accent);font-size:10px;padding:2px 7px;border-radius:4px;font-weight:500}
.detail-grid{display:grid;grid-template-columns:1fr 340px;gap:32px;padding:32px 0}
.detail-img{width:100%;border-radius:12px;border:1px solid var(--wp-border);aspect-ratio:16/10;object-fit:cover;background:var(--wp-card)}
.detail-title{font-family:var(--font-head);font-size:32px;font-weight:800;margin-bottom:8px}
.detail-stats{display:flex;gap:16px;margin-bottom:20px}
.stat-box{background:var(--wp-card);border:1px solid var(--wp-border);border-radius:10px;padding:12px 16px;text-align:center;flex:1}
.stat-box .n{font-family:var(--font-head);font-size:22px;font-weight:700}
.stat-box .l{font-size:11px;color:var(--wp-muted);margin-top:2px}
.dl-btn{width:100%;background:var(--wp-accent);border:none;color:#fff;font-family:var(--font-head);font-size:16px;font-weight:700;padding:14px;border-radius:10px;cursor:pointer;transition:all .2s;margin-bottom:12px;display:block;text-align:center}
.dl-btn:hover{background:#2563eb}
.demo-btn{width:100%;background:transparent;border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:14px;padding:10px;border-radius:10px;cursor:pointer;transition:all .2s;margin-bottom:8px}
.demo-btn:hover{border-color:var(--wp-accent);color:var(--wp-accent)}
.pro-btn{width:100%;background:linear-gradient(135deg,#f59e0b,#d97706);border:none;color:#1c1400;font-family:var(--font-head);font-size:14px;font-weight:700;padding:11px;border-radius:10px;cursor:pointer;transition:all .2s;margin-bottom:8px}
.pro-btn:hover{opacity:.9}
.premium-btn{width:100%;background:transparent;border:1px solid #f59e0b;color:#f59e0b;font-family:var(--font-body);font-size:13px;padding:9px;border-radius:10px;cursor:pointer;transition:all .2s;margin-bottom:16px}
.premium-btn:hover{background:rgba(245,158,11,.1)}
.affiliate-label{font-size:10px;color:var(--wp-muted);text-align:center;margin-bottom:12px}
.section-title{font-family:var(--font-head);font-size:13px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--wp-border)}
.detail-meta-table{width:100%;font-size:13px}
.detail-meta-table tr td{padding:6px 0;vertical-align:top}
.detail-meta-table tr td:first-child{color:var(--wp-muted);width:100px}
.similar-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:16px}
.similar-card{background:var(--wp-card);border:1px solid var(--wp-border);border-radius:10px;overflow:hidden;cursor:pointer;transition:all .2s}
.similar-card:hover{border-color:var(--wp-accent)}
.similar-card img{width:100%;aspect-ratio:16/10;object-fit:cover;display:block}
.similar-card .no-img-sm{width:100%;aspect-ratio:16/10;background:var(--wp-panel);display:flex;align-items:center;justify-content:center;font-size:24px}
.similar-card .s-name{font-size:12px;font-weight:600;padding:6px 8px;color:var(--wp-text)}
.envato-box{background:rgba(245,158,11,.08);border:1px solid rgba(245,158,11,.25);border-radius:10px;padding:14px;margin-top:16px}
.envato-box p{font-size:13px;color:var(--wp-muted);margin-bottom:10px}
.envato-btn{width:100%;background:#f59e0b;border:none;color:#1c1400;font-family:var(--font-head);font-size:13px;font-weight:700;padding:9px;border-radius:8px;cursor:pointer}
.auth-wrap{max-width:420px;margin:60px auto;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:16px;padding:40px}
.auth-title{font-family:var(--font-head);font-size:28px;font-weight:800;text-align:center;margin-bottom:6px}
.auth-sub{color:var(--wp-muted);text-align:center;font-size:14px;margin-bottom:28px}
.form-group{margin-bottom:16px}
.form-group label{display:block;font-size:13px;font-weight:500;color:var(--wp-muted);margin-bottom:6px}
.form-group input,.form-group select,.form-group textarea{width:100%;background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:14px;padding:10px 14px;border-radius:10px;outline:none;transition:border .2s}
.form-group input:focus,.form-group select:focus,.form-group textarea:focus{border-color:var(--wp-accent)}
.form-group textarea{height:90px;resize:vertical}
.form-submit{width:100%;background:var(--wp-accent);border:none;color:#fff;font-family:var(--font-head);font-size:15px;font-weight:700;padding:12px;border-radius:10px;cursor:pointer;transition:all .2s;margin-top:8px}
.form-submit:hover{background:#2563eb}
.form-submit:disabled{opacity:.5;cursor:not-allowed}
.auth-divider{text-align:center;color:var(--wp-muted);font-size:13px;margin:16px 0;position:relative}
.auth-divider::before,.auth-divider::after{content:'';position:absolute;top:50%;width:42%;height:1px;background:var(--wp-border)}
.auth-divider::before{left:0}.auth-divider::after{right:0}
.google-btn{width:100%;background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:14px;font-weight:500;padding:11px;border-radius:10px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:10px;transition:all .2s}
.google-btn:hover{border-color:var(--wp-accent);color:var(--wp-accent)}
.auth-switch{text-align:center;font-size:13px;color:var(--wp-muted);margin-top:20px}
.auth-switch a{color:var(--wp-accent);cursor:pointer}
.submit-wrap{max-width:680px;margin:0 auto;padding:40px 0}
.submit-title{font-family:var(--font-head);font-size:28px;font-weight:800;margin-bottom:6px}
.submit-sub{color:var(--wp-muted);font-size:14px;margin-bottom:28px}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.color-picker-grid{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
.color-pick-item{display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer}
.color-pick-item input[type=checkbox]{width:14px;height:14px;accent-color:var(--wp-accent)}
.color-dot{width:14px;height:14px;border-radius:50%;flex-shrink:0}
.submit-card{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:14px;padding:24px;margin-bottom:24px}
.submit-card h2{font-family:var(--font-head);font-size:16px;font-weight:700;margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid var(--wp-border)}
.helper{font-size:12px;color:var(--wp-muted);margin-top:4px}
.validate-msg{font-size:12px;margin-top:4px}
.validate-msg.ok{color:var(--wp-green)}.validate-msg.err{color:var(--wp-red)}
.dash-title{font-family:var(--font-head);font-size:28px;font-weight:800;margin-bottom:24px;padding-top:32px}
.status-badge{display:inline-block;font-size:11px;font-weight:700;padding:3px 10px;border-radius:6px;letter-spacing:.5px}
.status-badge.pending{background:rgba(245,158,11,.15);color:#f59e0b}
.status-badge.approved{background:rgba(16,185,129,.15);color:#10b981}
.status-badge.rejected{background:rgba(239,68,68,.15);color:#ef4444}
.status-badge.featured{background:rgba(245,158,11,.25);color:#f59e0b}
.dash-table{width:100%;border-collapse:collapse}
.dash-table th{font-size:12px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--wp-muted);padding:10px 14px;text-align:left;border-bottom:1px solid var(--wp-border)}
.dash-table td{padding:12px 14px;border-bottom:1px solid rgba(42,49,80,.5);font-size:13px;vertical-align:middle}
.dash-table tr:hover td{background:rgba(255,255,255,.02)}
.thumb-sm{width:60px;height:38px;border-radius:6px;object-fit:cover;background:var(--wp-card);flex-shrink:0}
.admin-tabs{display:flex;gap:4px;margin-bottom:24px;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:10px;padding:4px;width:fit-content;flex-wrap:wrap}
.admin-tab{background:none;border:none;color:var(--wp-muted);font-family:var(--font-body);font-size:13px;font-weight:500;padding:6px 16px;border-radius:7px;cursor:pointer;transition:all .2s}
.admin-tab.active{background:var(--wp-gold);color:#1c1400}
.admin-action-btn{background:none;border:1px solid var(--wp-border);color:var(--wp-muted);font-size:12px;padding:5px 10px;border-radius:6px;cursor:pointer;font-family:var(--font-body);transition:all .2s;margin:2px}
.admin-action-btn.approve{border-color:var(--wp-green);color:var(--wp-green)}
.admin-action-btn.approve:hover{background:rgba(16,185,129,.1)}
.admin-action-btn.reject{border-color:var(--wp-red);color:var(--wp-red)}
.admin-action-btn.reject:hover{background:rgba(239,68,68,.1)}
.admin-action-btn.feature{border-color:var(--wp-gold);color:var(--wp-gold)}
.admin-action-btn.feature:hover{background:rgba(245,158,11,.1)}
.admin-action-btn.danger{border-color:var(--wp-red);color:var(--wp-red)}
.reject-reason-input{background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:12px;padding:6px 8px;border-radius:6px;width:130px;outline:none;margin:2px}
.admin-settings{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:14px;padding:24px;margin-bottom:24px}
.admin-settings h3{font-family:var(--font-head);font-size:16px;font-weight:700;margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid var(--wp-border)}
.settings-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.save-settings-btn{background:var(--wp-green);border:none;color:#fff;font-family:var(--font-head);font-size:13px;font-weight:700;padding:9px 20px;border-radius:8px;cursor:pointer;margin-top:12px}
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.75);z-index:200;align-items:center;justify-content:center}
.modal-overlay.open{display:flex}
.modal{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:16px;padding:32px;max-width:440px;width:90%;position:relative}
.modal h2{font-family:var(--font-head);font-size:20px;font-weight:800;margin-bottom:12px}
.modal-close{position:absolute;top:16px;right:20px;background:none;border:none;color:var(--wp-muted);font-size:20px;cursor:pointer}
.modal-btns{display:flex;gap:8px;justify-content:flex-end;margin-top:20px}
.modal-btns button{font-family:var(--font-body);font-size:13px;font-weight:600;padding:8px 18px;border-radius:8px;cursor:pointer;border:none}
.modal-btns .cancel{background:var(--wp-card);color:var(--wp-text)}
.modal-btns .confirm{background:var(--wp-red);color:#fff}
.modal-btns .confirm.ok{background:var(--wp-green)}
#toast{position:fixed;bottom:24px;right:24px;z-index:300;display:flex;flex-direction:column;gap:8px;pointer-events:none}
.toast-item{background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:10px;padding:12px 18px;font-size:13px;font-weight:500;min-width:220px;animation:slideUp .3s ease}
.toast-item.success{border-color:var(--wp-green);color:var(--wp-green)}
.toast-item.error{border-color:var(--wp-red);color:var(--wp-red)}
.toast-item.info{border-color:var(--wp-accent);color:var(--wp-accent)}
@keyframes slideUp{from{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}
.hero{background:var(--wp-panel);border-bottom:1px solid var(--wp-border);padding:40px 0 32px;text-align:center}
.hero h1{font-family:var(--font-head);font-size:42px;font-weight:800;margin-bottom:10px;line-height:1.1}
.hero h1 span{color:var(--wp-accent)}
.hero p{color:var(--wp-muted);font-size:16px;max-width:560px;margin:0 auto 24px}
.hero-search{display:flex;max-width:480px;margin:0 auto;gap:8px}
.hero-search input{flex:1;background:var(--wp-card);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:14px;padding:11px 16px;border-radius:10px;outline:none}
.hero-search input:focus{border-color:var(--wp-accent)}
.hero-search button{background:var(--wp-accent);border:none;color:#fff;font-family:var(--font-head);font-size:14px;font-weight:700;padding:11px 20px;border-radius:10px;cursor:pointer}
.empty{text-align:center;padding:80px 20px;color:var(--wp-muted)}
.empty .icon{font-size:56px;margin-bottom:14px}
.back-btn{background:none;border:none;color:var(--wp-muted);font-family:var(--font-body);font-size:14px;cursor:pointer;display:flex;align-items:center;gap:6px;padding:20px 0;transition:color .2s}
.back-btn:hover{color:var(--wp-text)}
.desc-text{font-size:14px;color:var(--wp-muted);line-height:1.7;margin-top:16px}
hr.sep{border:none;border-top:1px solid var(--wp-border);margin:20px 0}
.inline-admin-form{background:var(--wp-card);border:1px solid var(--wp-border);border-radius:10px;padding:14px;margin-top:8px}
.inline-admin-form label{font-size:11px;color:var(--wp-muted);display:block;margin-bottom:3px;font-weight:500}
.inline-admin-form input{width:100%;background:var(--wp-panel);border:1px solid var(--wp-border);color:var(--wp-text);font-family:var(--font-body);font-size:12px;padding:6px 8px;border-radius:6px;outline:none;margin-bottom:8px}
.inline-admin-form input:focus{border-color:var(--wp-accent)}
.save-inline-btn{background:var(--wp-accent);border:none;color:#fff;font-family:var(--font-head);font-size:11px;font-weight:700;padding:6px 12px;border-radius:6px;cursor:pointer}
.loading-spinner{display:flex;align-items:center;justify-content:center;padding:60px;color:var(--wp-muted);font-size:14px;gap:10px}
.spinner{width:20px;height:20px;border:2px solid var(--wp-border);border-top-color:var(--wp-accent);border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.config-notice{background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);border-radius:10px;padding:16px;margin:24px 0;font-size:13px;color:#ef4444}
.config-notice a{color:#f87171}
.inline-admin-form input:last-of-type{margin-bottom:0}
.home-hero{background:linear-gradient(135deg,var(--wp-panel) 0%,var(--wp-card) 100%);border-bottom:1px solid var(--wp-border);margin-bottom:32px}
.platform-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;margin-bottom:40px}
.platform-card{background:var(--wp-card);border:2px solid var(--wp-border);border-radius:10px;padding:14px 10px;text-align:center;cursor:pointer;transition:all .25s;text-decoration:none;display:block;color:inherit}
.platform-card:hover{border-color:var(--wp-accent);transform:translateY(-2px);box-shadow:0 6px 16px rgba(59,130,246,.12)}
.platform-icon{font-size:26px;line-height:1;margin-bottom:7px}
.platform-name{font-family:var(--font-head);font-size:13px;font-weight:700;color:var(--wp-text);margin-bottom:3px;line-height:1.2}
.platform-count{font-size:11px;color:var(--wp-muted);font-weight:500}
@media(max-width:900px){.with-sidebar{grid-template-columns:1fr}.sidebar{position:static;height:auto}.detail-grid{grid-template-columns:1fr}.form-row{grid-template-columns:1fr}.settings-grid{grid-template-columns:1fr}}
</style>
</head>
<body>

<!-- ── CONFIG NOTICE ─────────────────────────────────────────── -->
<div id="config-notice" class="config-notice container" style="display:none">
  ⚠ <strong>Setup required:</strong> Replace <code>SUPABASE_URL</code> and <code>SUPABASE_ANON_KEY</code> in this file with your Supabase project values.
  <a href="https://supabase.com/dashboard" target="_blank">Open Supabase Dashboard →</a>
</div>

<!-- ── NAV ───────────────────────────────────────────────────── -->
<nav id="nav">
  <span class="nav-logo" onclick="showPage('home')">WP<span>Skins</span>.org</span>
  <div class="nav-links">
    <button class="nav-link active" onclick="showPage('home')">Browse Themes</button>
    <button class="nav-link" onclick="window.location.href='/resources'">Resources</button>
    <button class="nav-link" onclick="navSubmit()">Submit Theme</button>
    <button class="nav-link" onclick="navDash()">My Themes</button>
    <button class="nav-link admin-link" id="admin-nav-btn" style="display:none" onclick="window.location.href='/admin.html'">⚙ Admin</button>
  </div>
  <div class="nav-right" id="nav-right">
    <button class="nav-btn ghost" onclick="showPage('login')">Log In</button>
    <button class="nav-btn" onclick="showPage('register')">Sign Up</button>
  </div>
</nav>

<!-- ── TOAST ─────────────────────────────────────────────────── -->
<div id="toast"></div>

<!-- ── MODAL ─────────────────────────────────────────────────── -->
<div class="modal-overlay" id="modal">
  <div class="modal">
    <button class="modal-close" onclick="closeModal()">✕</button>
    <h2 id="modal-title">Confirm</h2>
    <p id="modal-body" style="font-size:14px;color:var(--wp-muted)"></p>
    <div class="modal-btns">
      <button class="cancel" onclick="closeModal()">Cancel</button>
      <button class="confirm" id="modal-confirm-btn" onclick="modalAction()">Confirm</button>
    </div>
  </div>
</div>

<!-- ══════════════ PAGES ══════════════ -->

<!-- DIRECTORY -->
<!-- HOME PAGE -->
<div id="page-home" class="page active">
  <div class="hero">
    <div class="container">
      <h1>Free <span>Website Themes</span><br>for Every Platform</h1>
      <p>Discover, download, and share beautiful themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more. 100% free, community-powered.</p>
      <div class="hero-search">
        <input type="text" id="hero-search-input" placeholder="Search themes..." oninput="liveSearch()">
        <button onclick="liveSearch()">Search</button>
      </div>
    </div>
  </div>
  
  <div class="container">
    <div class="with-sidebar">
      <aside class="sidebar">
        <div class="sidebar-box">
          <h3>Platform</h3>
          <div class="filter-row" id="platform-list"></div>
        </div>
        <div class="sidebar-box">
          <h3>Category</h3>
          <div class="filter-row" id="category-list"></div>
        </div>
        <div class="sidebar-box"><button class="clear-btn" onclick="clearFilters()">✕ Clear All Filters</button></div>
        <div class="sidebar-box">
          <h3>Also Latest</h3>
          <ul class="latest-list" id="latest-list"></ul>
        </div>
      </aside>
      <main class="main-area">
        <div class="platform-cards">
          <!-- Platform cards will be inserted here by JS -->
        </div>
        <div id="seo-intro" style="display:none"></div>
        <div class="sort-tabs">
          <button class="sort-tab active" onclick="setSort('latest',this)">Latest</button>
          <button class="sort-tab" onclick="setSort('featured',this)">Featured</button>
          <button class="sort-tab" onclick="setSort('views',this)">Top Viewed</button>
        </div>
        <div class="themes-count" id="themes-count"></div>
        <div id="themes-grid-wrap">
          <div class="loading-spinner"><div class="spinner"></div> Loading themes…</div>
        </div>
        <div id="seo-faq" style="display:none"></div>
      </main>
    </div>
  </div>
</div>

<!-- DETAIL -->
<div id="page-detail" class="page">
  <div class="container with-sidebar">
    <div class="sidebar">
      <button class="back-btn" onclick="showPage('home')" style="width:100%;margin-bottom:20px">← Back</button>
      <div class="sidebar-box">
        <h3>Platform</h3>
        <div class="filter-row" id="detail-platform-list"></div>
      </div>
      <div class="sidebar-box">
        <h3>Category</h3>
        <div class="filter-row" id="detail-category-list"></div>
      </div>
    </div>
    <div id="detail-content"><div class="loading-spinner"><div class="spinner"></div> Loading…</div></div>
  </div>
</div>

<!-- LOGIN -->
<div id="page-login" class="page">
  <div class="auth-wrap">
    <div class="auth-title">Welcome back</div>
    <div class="auth-sub">Sign in to your WPSkins account</div>
    <div class="form-group"><label>Email</label><input type="email" id="login-email" placeholder="you@example.com"></div>
    <div class="form-group"><label>Password</label><input type="password" id="login-pass" placeholder="••••••••" onkeydown="if(event.key==='Enter')doLogin()"></div>
    <button class="form-submit" id="login-btn" onclick="doLogin()">Sign In</button>
    <div class="auth-divider">or</div>
    <button class="google-btn" onclick="doGoogleLogin()">
      <svg width="18" height="18" viewBox="0 0 18 18"><path fill="#4285F4" d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z"/><path fill="#34A853" d="M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z"/><path fill="#FBBC05" d="M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z"/><path fill="#EA4335" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z"/></svg>
      Continue with Google
    </button>
    <div class="auth-switch">Don't have an account? <a href="#register" role="link" tabindex="0" onclick="event.preventDefault();showPage('register')" onkeydown="if(event.key==='Enter'){event.preventDefault();showPage('register')}" style="cursor:pointer;color:var(--wp-accent)">Sign up free</a></div>
  </div>
</div>

<!-- REGISTER -->
<div id="page-register" class="page">
  <div class="auth-wrap">
    <div class="auth-title">Create account</div>
    <div class="auth-sub">Join the WPSkins community</div>
    <div class="form-group"><label>Display Name</label><input type="text" id="reg-name" placeholder="Your name"></div>
    <div class="form-group"><label>Email</label><input type="email" id="reg-email" placeholder="you@example.com"></div>
    <div class="form-group"><label>Password</label><input type="password" id="reg-pass" placeholder="Min 6 characters" onkeydown="if(event.key==='Enter')doRegister()"></div>
    <button class="form-submit" id="reg-btn" onclick="doRegister()">Create Account</button>
    <div class="auth-divider">or</div>
    <button class="google-btn" onclick="doGoogleLogin()">
      <svg width="18" height="18" viewBox="0 0 18 18"><path fill="#4285F4" d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z"/><path fill="#34A853" d="M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z"/><path fill="#FBBC05" d="M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z"/><path fill="#EA4335" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z"/></svg>
      Sign up with Google
    </button>
    <div class="auth-switch">Already have an account? <a href="#login" role="link" tabindex="0" onclick="event.preventDefault();showPage('login')" onkeydown="if(event.key==='Enter'){event.preventDefault();showPage('login')}" style="cursor:pointer;color:var(--wp-accent)">Sign in</a></div>
  </div>
</div>

<!-- ══════════════ JAVASCRIPT ══════════════ -->
<script data-version="1777749204">
// VERSION: 2026-05-02 12:24:54 - If you see {{{ braces }}}, clear your cache!
window.onerror = function(msg, url, line, col, error) {
  console.error('Global error:', msg, 'at line', line);
  return false;
};


// ─────────────────────────────────────────────────────────────
// !! REPLACE THESE TWO VALUES WITH YOUR SUPABASE PROJECT !!
// Find them at: Supabase Dashboard → Settings → API
// ─────────────────────────────────────────────────────────────
const SUPABASE_URL  = 'https://owrkygjvavcgyneakcbt.supabase.co';
const SUPABASE_ANON = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im93cmt5Z2p2YXZjZ3luZWFrY2J0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc0OTIwNDksImV4cCI6MjA5MzA2ODA0OX0.RmBRCtN9P-QOy3CxxKjvvQOPsOgMaLkM75tEkQpFst4';
// ─────────────────────────────────────────────────────────────

const COLORS = [
  {name:'White',hex:'#f8f8f8'},{name:'Black',hex:'#1a1a1a'},{name:'Blue',hex:'#3b82f6'},
  {name:'Red',hex:'#ef4444'},{name:'Orange',hex:'#f97316'},{name:'Yellow',hex:'#eab308'},
  {name:'Green',hex:'#22c55e'},{name:'Pink',hex:'#ec4899'},{name:'Purple',hex:'#a855f7'},
  {name:'Brown',hex:'#92400e'},{name:'Grey',hex:'#6b7280'}
];

const PLATFORMS = [
  {id: 'wordpress',   name: 'WordPress',   enabled: true, emoji: '📝', color: '#21759b'},
  {id: 'shopify',     name: 'Shopify',     enabled: true, emoji: '🛒', color: '#96bf48'},
  {id: 'webflow',     name: 'Webflow',     enabled: true, emoji: '🎨', color: '#4353ff'},
  {id: 'framer',      name: 'Framer',      enabled: true, emoji: '⚡', color: '#0055ff'},
  {id: 'ghost',       name: 'Ghost',       enabled: true, emoji: '👻', color: '#15171A'},
  {id: 'hugo',        name: 'Hugo',        enabled: true, emoji: '🦉', color: '#ff4088'},
  {id: 'jekyll',      name: 'Jekyll',      enabled: true, emoji: '💎', color: '#cc0000'},
  {id: 'astro',       name: 'Astro',       enabled: true, emoji: '🚀', color: '#FF5D01'},
  {id: 'eleventy',    name: 'Eleventy',    enabled: true, emoji: '🕚', color: '#222222'},
  {id: 'joomla',      name: 'Joomla',      enabled: true, emoji: '🔶', color: '#F44321'},
  {id: 'drupal',      name: 'Drupal',      enabled: true, emoji: '💧', color: '#0678BE'},
  {id: 'bigcommerce', name: 'BigCommerce', enabled: true, emoji: '🛍', color: '#34313F'},
  {id: 'gatsby',      name: 'Gatsby',      enabled: true, emoji: '💜', color: '#663399'},
  {id: 'nuxt',        name: 'Nuxt',        enabled: true, emoji: '💚', color: '#00DC82'},
  {id: 'next',        name: 'Next.js',     enabled: true, emoji: '▲',  color: '#000000'}
];

// ── SEO Content: per-platform intro blocks ─────────────────
const PLATFORM_SEO = {
  wordpress: {
    intro: `<p>Welcome to the largest curated collection of <strong>free WordPress themes</strong> on the web. Every theme below is 100% free to download, fully responsive, and built to work with the latest version of WordPress. Whether you're building a personal blog, a business site, an online store with WooCommerce, or a creative portfolio, you'll find a professional theme here that fits.</p>
<p>All of our WordPress themes are sourced from trusted developers and the official WordPress.org repository. Each one supports the Gutenberg block editor, is translation-ready, and works with popular plugins like Yoast SEO, Elementor, and WooCommerce. No subscriptions, no email walls — just clean code and clean design.</p>`,
    faq: [
      { q: "Are these WordPress themes really free?", a: "Yes — every theme on this page is 100% free to download and use. There are no hidden fees, subscriptions, or limits on the number of sites where you can install them. Some themes do offer optional paid 'pro' versions with additional features, but the free version is always fully functional." },
      { q: "Can I use these free WordPress themes commercially?", a: "Yes. All WordPress themes here are released under the GPL license (the same license WordPress itself uses), which means you can use them on commercial sites, modify them, and distribute your modifications. Always check the specific theme's license details for any attribution requirements." },
      { q: "Are these themes compatible with WooCommerce?", a: "Many of our themes are fully WooCommerce-compatible — look for themes tagged in the eCommerce category. WooCommerce-ready themes include styled product pages, shopping cart layouts, and checkout templates." },
      { q: "How do I install a free WordPress theme?", a: "After downloading the theme's .zip file, log into your WordPress admin panel, go to Appearance → Themes → Add New → Upload Theme, select the .zip file, click Install Now, and then Activate. The whole process takes under a minute." },
      { q: "Will these themes work with page builders like Elementor or Divi?", a: "Most modern WordPress themes work well with popular page builders like Elementor, Beaver Builder, and Divi. Themes with the 'Page builder compatible' tag have been specifically tested with major builders." }
    ]
  },
  shopify: {
    intro: `<p>Browse our handpicked collection of <strong>free Shopify themes</strong> — every one is officially released by Shopify and available at no cost from the Shopify Theme Store. These themes are built on Shopify's Online Store 2.0 architecture, which means full support for sections everywhere, metafields, and drag-and-drop customization without writing a line of code.</p>
<p>Each free Shopify theme is mobile-optimized, fast-loading, and supports the latest commerce features like AI-generated product descriptions, Shop Pay, and Shopify Markets for international selling. Whether you're launching your first store or migrating from another platform, a free Shopify theme is a professional starting point.</p>`,
    faq: [
      { q: "Are Shopify's free themes good enough for a real store?", a: "Absolutely. Free Shopify themes like Dawn, Sense, and Horizon are made by Shopify itself, fully supported, and used by hundreds of thousands of live stores. They include every feature you need to sell professionally — product variants, collections, checkout, customer accounts, and more." },
      { q: "Do I need a Shopify account to use these themes?", a: "Yes — Shopify themes only run on Shopify's platform. You'll need an active Shopify store (free 3-day trial available). Once logged in, click the theme's preview link, then 'Add theme to library' to install it on your store for free." },
      { q: "Can I customize a free Shopify theme without coding?", a: "Yes. All current free Shopify themes use Online Store 2.0, which lets you add, remove, and reorder sections through Shopify's visual editor — no code required. For deeper customization, you can edit the theme's Liquid templates and CSS directly." },
      { q: "Which free Shopify theme is fastest?", a: "Dawn and Sense consistently score highest on Shopify's performance benchmarks. Both are built with minimal JavaScript and lazy-loaded images, helping your store load quickly even on slow connections." },
      { q: "What's the difference between free and paid Shopify themes?", a: "Free themes are made by Shopify and cover most use cases excellently. Paid themes (typically $200-400) from third-party developers often include more pre-built sections, niche layouts (like jewelry or restaurant menus), and built-in features like product filtering or wishlist functionality." }
    ]
  },
  webflow: {
    intro: `<p>Discover <strong>free Webflow templates</strong> for portfolios, landing pages, blogs, eCommerce, and SaaS sites. Webflow gives you the design power of a code editor with the simplicity of a visual builder — and these free templates give you a professional starting point you can customize without writing CSS or JavaScript.</p>
<p>Every Webflow template here is fully responsive, hosted on Webflow's global CDN, and includes CMS-ready collections for blog posts, projects, team members, and more. Clone any template directly into your Webflow account in one click and start customizing immediately.</p>`,
    faq: [
      { q: "What does 'cloneable' mean for a Webflow template?", a: "A cloneable Webflow template can be copied to your own Webflow account in one click. Once cloned, you have full edit access — change designs, add CMS collections, swap content, and publish to your own domain. Most free Webflow templates here are cloneables." },
      { q: "Do I need to pay for Webflow to use these templates?", a: "You can start with Webflow's free Starter plan to design and preview your site. To publish to your own custom domain (like yoursite.com), you'll need a paid Site Plan starting at $14/month. The templates themselves are always free." },
      { q: "Can I edit a Webflow template's design?", a: "Yes — that's the whole point of Webflow. Once you clone a template, you can change every color, font, layout, image, and animation through Webflow's visual designer. No code knowledge required." },
      { q: "Are Webflow templates SEO-friendly?", a: "Yes. Webflow generates clean, semantic HTML and includes built-in SEO tools for meta tags, sitemaps, robots.txt, and structured data. All free Webflow templates here are optimized for Core Web Vitals out of the box." },
      { q: "What's the difference between Webflow templates and Webflow apps?", a: "Templates are starting designs you customize. Webflow Apps add functionality to your site (forms, ecommerce, marketing integrations). Free templates here include the design — you add functionality through Webflow's built-in features or apps." }
    ]
  },
  framer: {
    intro: `<p>Browse the best <strong>free Framer templates</strong> for portfolios, SaaS landing pages, agency sites, and creative projects. Framer is a modern no-code website builder used by designers at Google, Stripe, and thousands of indie creators — and free templates give you a professional starting point that's already optimized for performance and conversion.</p>
<p>Each Framer template is fully responsive, includes built-in CMS for blogs and dynamic content, and can be customized without writing code. Just click "Use template," sign in to Framer (free), and start editing in the visual canvas. Framer hosts your site on a global CDN with automatic HTTPS — no extra hosting needed.</p>`,
    faq: [
      { q: "Are Framer templates really free?", a: "Yes. All templates here are free to use — created by the Framer community and the Framer team. You can clone any template into your Framer account at no cost and customize it however you want." },
      { q: "Do I need to pay for Framer hosting?", a: "Framer's free plan lets you publish to a framer.website subdomain at no cost. For a custom domain (yoursite.com), you'll need a paid plan starting at $5/month per site. Templates themselves are always free." },
      { q: "What's the difference between Framer and Webflow?", a: "Both are visual website builders. Framer is faster to learn and has a more modern, animation-focused design system — better for portfolios, landing pages, and creative sites. Webflow has deeper CMS features and is generally preferred for content-heavy or eCommerce sites." },
      { q: "Can I add a blog to a Framer template?", a: "Yes. Framer includes a built-in CMS that lets you create blog posts, project case studies, team pages, and more. Most templates here include CMS collections ready to populate with your own content." },
      { q: "Are Framer sites good for SEO?", a: "Yes. Framer generates clean HTML, supports custom meta tags and Open Graph images, generates sitemaps automatically, and offers excellent Core Web Vitals scores. All templates here are SEO-optimized out of the box." }
    ]
  },
  ghost: {
    intro: `<p>Discover the best <strong>free Ghost themes</strong> for blogs, newsletters, membership sites, and online publications. Ghost is a modern, open-source publishing platform loved by independent writers, journalists, and content creators — and a great free theme gives you a beautiful site from day one.</p>
<p>Ghost themes are built with Handlebars templating and are fully customizable. Every theme here works with Ghost's native membership system, newsletter tools, and built-in SEO. Whether you're launching a personal blog or a paid newsletter community, these free Ghost themes give you a professional head start.</p>`,
    faq: [
      { q: "Are these Ghost themes really free?", a: "Yes. Every Ghost theme listed here is free to download and use. Ghost themes are distributed under open-source licenses (MIT or GPL) unless otherwise noted. You can use them on self-hosted Ghost or Ghost(Pro) sites." },
      { q: "Do these themes work with Ghost memberships and newsletters?", a: "Yes. All modern Ghost themes support Ghost's native membership and newsletter features including subscribe buttons, member-only content, and email signup forms. Ghost handles all the delivery — the theme just controls the design." },
      { q: "Can I use Ghost for free?", a: "Ghost is free and open-source. You can self-host it on any VPS (DigitalOcean, Vultr, etc.) for just the cost of the server. Ghost(Pro) managed hosting starts at $9/month. The themes themselves are always free." },
      { q: "How do I install a Ghost theme?", a: "Download the theme's .zip file, log into your Ghost admin panel, go to Settings → Design → Change theme → Upload theme, and select the .zip. The theme activates immediately. No coding required." },
      { q: "Can I customize a free Ghost theme?", a: "Yes. Ghost themes use Handlebars templates and standard CSS/JS — you can edit any file to change layouts, colors, fonts, and functionality. Ghost also has a built-in theme editor for quick style changes without touching code." }
    ]
  },
  hugo: {
    intro: `<p>Browse the best <strong>free Hugo themes</strong> for blogs, portfolios, documentation sites, and personal projects. Hugo is the world's fastest static site generator — sites build in milliseconds and load instantly, making it a favourite among developers, technical bloggers, and performance-focused creators.</p>
<p>Hugo themes are written in Go templates and work with Hugo's powerful content pipeline. Hosting is free on GitHub Pages, Netlify, or Cloudflare Pages. Every theme here is open source, SEO-friendly, and ready to deploy in minutes.</p>`,
    faq: [
      { q: "Are Hugo themes free?", a: "Yes. Hugo themes are open source and free to use. Most are licensed under MIT, Apache, or Creative Commons licenses. You can use them for personal and commercial projects without paying anything." },
      { q: "How do I install a Hugo theme?", a: "After downloading the theme, add it to your Hugo project's /themes folder (or use it as a Git submodule), then set theme = 'theme-name' in your hugo.toml config. Run hugo server to preview and hugo to build." },
      { q: "Where can I host a Hugo site for free?", a: "Hugo sites can be hosted for free on GitHub Pages, Netlify, Vercel, and Cloudflare Pages. All support automatic deployment from a GitHub repo — push your code and the site rebuilds automatically." },
      { q: "Is Hugo hard to learn?", a: "Hugo has a learning curve compared to drag-and-drop builders, but if you're comfortable with Markdown and a text editor, you can be up and running in an afternoon. The Hugo community has excellent documentation and a helpful forum." },
      { q: "Can Hugo sites be used for non-technical people?", a: "Hugo works best when the site owner is comfortable with a text editor and command line. For non-technical users, consider pairing Hugo with a headless CMS like Forestry, Netlify CMS, or Decap CMS for a visual editing experience." }
    ]
  },
  jekyll: {
    intro: `<p>Find the best <strong>free Jekyll themes</strong> for blogs, project documentation, portfolios, and GitHub Pages sites. Jekyll is one of the oldest and most trusted static site generators, with native support built directly into GitHub Pages — which means free, automatic hosting with zero configuration.</p>
<p>Jekyll themes use Liquid templating and are fully customizable. Every theme listed here is open source, mobile-friendly, and ready to deploy. Whether you're building a personal developer blog or a project documentation site, Jekyll's simplicity and GitHub integration make it a rock-solid choice.</p>`,
    faq: [
      { q: "Are Jekyll themes free?", a: "Yes. All Jekyll themes listed here are free and open source. Most are MIT-licensed, meaning you can use them on personal and commercial projects, modify them freely, and distribute your changes." },
      { q: "How do I use a Jekyll theme with GitHub Pages?", a: "For GitHub Pages, add gem: 'theme-name' to your Gemfile and theme: theme-name to your _config.yml, then push. For self-hosted Jekyll, download the theme, copy it into your project, and run bundle install. Jekyll builds your site automatically." },
      { q: "Is Jekyll hosting really free?", a: "Yes. GitHub Pages hosts Jekyll sites for free with automatic HTTPS, custom domain support, and unlimited bandwidth for public repositories. It's the most popular free hosting for Jekyll sites." },
      { q: "Do Jekyll themes work with blog posts?", a: "Yes. Jekyll was originally built as a blogging engine. Every theme here supports Jekyll's built-in blogging system — just add Markdown files to your _posts folder with the right filename format and they appear automatically." },
      { q: "How is Jekyll different from Hugo?", a: "Both are static site generators, but Jekyll uses Ruby and has native GitHub Pages support with zero setup. Hugo uses Go and is significantly faster at building large sites. Jekyll is generally easier for beginners; Hugo is preferred for sites with thousands of pages." }
    ]
  },
  astro: {
    intro: `<p>Browse the best <strong>free Astro themes</strong> for blogs, portfolios, documentation sites, SaaS landing pages, and e-commerce. Astro is the fastest-growing modern static site framework — it ships zero JavaScript by default, builds lightning-fast sites, and works with React, Vue, Svelte, or any other component library you already know.</p>
<p>Every Astro theme here is open source and free to use. Astro's component islands architecture means your site loads fast without sacrificing rich interactivity. Deploy for free on Netlify, Vercel, or Cloudflare Pages in minutes.</p>`,
    faq: [
      { q: "Are these Astro themes free?", a: "Yes. All Astro themes listed here are free and open source, typically MIT-licensed. You can use them for personal and commercial projects without any cost." },
      { q: "How do I use an Astro theme?", a: "Download or clone the theme repository, run npm install, then npm run dev to preview locally. Astro themes are standard Node.js projects — customize the pages, content, and styles, then deploy to any static host." },
      { q: "Where can I host an Astro site for free?", a: "Astro sites deploy for free on Netlify, Vercel, Cloudflare Pages, and GitHub Pages. All support direct GitHub integration — push your code and the site rebuilds automatically with HTTPS and a CDN included." },
      { q: "Can I use Astro with React or Vue components?", a: "Yes. Astro supports React, Vue, Svelte, Solid, Preact, and Lit components in the same project. Astro's 'islands' architecture only hydrates interactive components in the browser — the rest is pure static HTML, keeping sites fast." },
      { q: "Is Astro good for SEO?", a: "Astro is excellent for SEO. Pages are pre-rendered as static HTML, load near-instantly, and ship minimal JavaScript — all factors Google rewards. Most Astro themes also include built-in meta tags, Open Graph support, and sitemaps." }
    ]
  },
  eleventy: {
    intro: `<p>Discover the best <strong>free Eleventy (11ty) themes and starters</strong> for blogs, portfolios, documentation sites, and personal projects. Eleventy is a beloved static site generator used by Google, the Netlify team, and thousands of developers who want full control without framework overhead.</p>
<p>Eleventy works with any templating language — Nunjucks, Liquid, Markdown, JavaScript, or HTML — and adds zero client-side JavaScript by default. Every starter here is open source, fast, and flexible enough to build exactly the site you have in mind.</p>`,
    faq: [
      { q: "Are Eleventy starters free to use?", a: "Yes. All Eleventy starters and themes listed here are free and open source, typically MIT-licensed. You can use, modify, and deploy them for personal or commercial projects at no cost." },
      { q: "How do I start with an Eleventy theme?", a: "Clone or download the starter repository, run npm install in the project folder, then npx @11ty/eleventy --serve to start a local preview server. Edit the Markdown files to update your content and deploy to Netlify, Vercel, or GitHub Pages." },
      { q: "Is Eleventy hard to learn?", a: "Eleventy is one of the simpler static site generators. If you know HTML, CSS, and a little Markdown, you can be productive quickly. There's no JSX or complex build tooling required — just templates and content files." },
      { q: "How is Eleventy different from Astro or Hugo?", a: "Eleventy is the most flexible SSG — it supports 10+ templating languages and imposes almost no opinions on project structure. Hugo is faster at build time for very large sites. Astro supports interactive component islands. Eleventy is the best choice if you want maximum control." },
      { q: "Where can I host an Eleventy site for free?", a: "Netlify, Vercel, Cloudflare Pages, and GitHub Pages all host Eleventy sites for free with automatic HTTPS, CDN delivery, and GitHub integration. Netlify is the most popular choice in the Eleventy community." }
    ]
  },
  joomla: {
    intro: `<p>Browse the best <strong>free Joomla templates</strong> for business websites, blogs, portfolios, e-commerce, and community sites. Joomla is one of the world's most popular open-source CMS platforms — powering millions of sites with its powerful extension ecosystem, multilingual support, and flexible content management.</p>
<p>Every Joomla template listed here is free to download and use. Joomla templates control your site's layout, design, and typography — and free templates from providers like JoomlArt, JoomShaper, and GavickPro give you a professional result without spending a cent.</p>`,
    faq: [
      { q: "Are these Joomla templates free?", a: "Yes. All Joomla templates listed here are free to download and use. Many providers offer free versions of their templates — perfect for personal blogs, small business sites, and community projects." },
      { q: "How do I install a Joomla template?", a: "Download the template's .zip file, then in your Joomla admin panel go to Extensions → Install, upload the .zip, and the template will be installed. Go to Extensions → Templates to set it as your active template." },
      { q: "What is the difference between Joomla templates and extensions?", a: "Templates control the visual design and layout of your site. Extensions (components, modules, plugins) add functionality like contact forms, sliders, and social sharing. Most free templates work with Joomla's built-in features plus popular free extensions." },
      { q: "Are free Joomla templates responsive?", a: "Yes. All modern Joomla templates listed here are fully responsive and mobile-friendly. They use Bootstrap 4 or 5 as a responsive grid system and adapt automatically to any screen size." },
      { q: "What version of Joomla do these templates support?", a: "Most templates listed here support Joomla 4 and/or Joomla 5. Joomla 3 is end-of-life. We note the supported version on each theme page — always verify compatibility before installing." }
    ]
  },
  drupal: {
    intro: `<p>Find the best <strong>free Drupal themes</strong> for enterprise websites, government portals, large content sites, blogs, and community platforms. Drupal is the most powerful open-source CMS — trusted by NASA, the White House, and thousands of universities and enterprises for its unmatched flexibility and security.</p>
<p>Every Drupal theme here is free and available on Drupal.org. From minimal base themes for developers to full designs for business sites, these themes work with Drupal 9, 10, and beyond.</p>`,
    faq: [
      { q: "Are these Drupal themes free?", a: "Yes. All themes listed here are free and available from Drupal.org or GitHub. They are GPL-licensed, meaning you can use, modify, and distribute them freely for personal and commercial projects." },
      { q: "How do I install a Drupal theme?", a: "Download the theme from Drupal.org, extract it to your /themes/contrib folder, then go to Appearance in your Drupal admin and click Install on your new theme. You can then set it as the default theme." },
      { q: "What is a Drupal base theme?", a: "A base theme provides structural HTML and CSS that sub-themes inherit. Popular base themes like Bootstrap, Zen, and Radix give you a solid foundation to build custom designs without starting from scratch." },
      { q: "What versions of Drupal are these themes compatible with?", a: "Most themes listed here support Drupal 9 and 10. Some also support Drupal 8. Drupal 7 is end-of-life. Check each theme's project page on Drupal.org for exact compatibility." },
      { q: "Is Drupal harder than WordPress?", a: "Drupal has a steeper learning curve than WordPress but offers far more power for complex content architectures, permissions, and multilingual sites. It's the preferred choice for large enterprise and government websites." }
    ]
  },
  bigcommerce: {
    intro: `<p>Browse the best <strong>free BigCommerce themes</strong> for online stores of every size. BigCommerce is a leading enterprise-grade e-commerce platform — powering brands like Skullcandy, Ben & Jerry's, and thousands of growing businesses with fast storefronts, powerful SEO, and no transaction fees.</p>
<p>BigCommerce's free Cornerstone theme is the official starting point for every store — responsive, fast, and built on the modern Stencil framework. Customize it with the Theme Editor or clone it locally with the Stencil CLI to build a fully custom storefront.</p>`,
    faq: [
      { q: "Are BigCommerce themes free?", a: "BigCommerce offers free themes in its Theme Marketplace, including the official Cornerstone theme in multiple style variations. Free themes give you a fully functional, professional storefront at no extra cost beyond your BigCommerce plan." },
      { q: "What is the Cornerstone theme?", a: "Cornerstone is BigCommerce's official free theme and the foundation for all Stencil-based themes. It includes a responsive design, product image zoom, faceted search, cart drawer, and full Theme Editor support." },
      { q: "Can I customize a BigCommerce theme without coding?", a: "Yes. BigCommerce's Theme Editor lets you change colors, fonts, banners, and layout options visually without touching code. For deeper customization, BigCommerce uses the Stencil CLI — a local development environment for theme developers." },
      { q: "How do I switch themes in BigCommerce?", a: "In your BigCommerce store admin, go to Storefront → Themes, click Marketplace to find a theme, and click Apply to make it live. You can switch themes without losing your products or orders." },
      { q: "Does BigCommerce charge transaction fees?", a: "BigCommerce does not charge transaction fees on any plan, unlike Shopify which charges fees if you don't use Shopify Payments. This makes BigCommerce attractive for high-volume stores using third-party payment processors." }
    ]
  },
  gatsby: {
    intro: `<p>Discover the best <strong>free Gatsby starters and themes</strong> for blogs, portfolios, documentation sites, and e-commerce. Gatsby is a powerful React-based static site framework with an enormous plugin ecosystem, built-in image optimization, and blazing-fast page loads thanks to its GraphQL data layer and static rendering.</p>
<p>Every Gatsby starter listed here is free and open source. Deploy instantly to Netlify, Vercel, or Gatsby Cloud. Gatsby's rich ecosystem includes integrations with WordPress, Contentful, Shopify, and dozens of other data sources.</p>`,
    faq: [
      { q: "Are these Gatsby starters free?", a: "Yes. All Gatsby starters and themes listed here are free and open source, typically MIT-licensed. You can use them for personal and commercial projects at no cost." },
      { q: "How do I use a Gatsby starter?", a: "Install the Gatsby CLI with npm install -g gatsby-cli, then run gatsby new my-site https://github.com/owner/starter-repo. This clones the starter and installs dependencies. Run gatsby develop to start a local server." },
      { q: "Is Gatsby still worth learning in 2025?", a: "Gatsby remains a solid choice for React-based static sites, especially when you need a rich plugin ecosystem, CMS integrations, or e-commerce via Shopify. For simpler sites, Astro or Next.js might be more efficient. Gatsby's strength is its huge library of source plugins." },
      { q: "Where can I host a Gatsby site for free?", a: "Gatsby sites deploy for free on Netlify, Vercel, and Cloudflare Pages. All offer GitHub integration, automatic HTTPS, and CDN delivery. Gatsby Cloud (now Netlify) also provides Gatsby-optimized builds." },
      { q: "Can Gatsby connect to WordPress or a CMS?", a: "Yes. gatsby-source-wordpress lets you use WordPress as a headless CMS while Gatsby handles the frontend. Gatsby also has official source plugins for Contentful, Sanity, DatoCMS, Shopify, and many more." }
    ]
  },
  nuxt: {
    intro: `<p>Browse the best <strong>free Nuxt themes and starters</strong> for blogs, portfolios, SaaS apps, documentation sites, and full-stack web applications. Nuxt is the most popular Vue.js framework — bringing file-based routing, server-side rendering, static generation, and a powerful module ecosystem to Vue developers.</p>
<p>Every Nuxt starter here is free and open source. Nuxt 3 runs on Nitro — a universal server engine that deploys seamlessly to Netlify, Vercel, Cloudflare, and more. Whether you're building a simple blog or a complex SaaS product, there's a Nuxt starter here for you.</p>`,
    faq: [
      { q: "Are these Nuxt themes free?", a: "Yes. All Nuxt themes and starters listed here are free and open source, typically MIT-licensed. You can use them for personal and commercial projects at no cost." },
      { q: "How do I start with a Nuxt theme?", a: "Clone the starter repository and run npm install, then npm run dev to start the local development server. Nuxt starters are standard Node.js projects — edit the pages, components, and content files, then deploy to your chosen host." },
      { q: "What is the difference between Nuxt and Vue?", a: "Vue is a JavaScript UI component framework. Nuxt is a full application framework built on top of Vue — it adds file-based routing, SSR, static generation, API routes, and a rich module ecosystem. Think of Vue as the engine and Nuxt as the car." },
      { q: "Where can I host a Nuxt site for free?", a: "Nuxt sites deploy for free on Netlify, Vercel, and Cloudflare Pages. For full-stack Nuxt apps with server routes and a database, NuxtHub (powered by Cloudflare) offers a generous free tier with edge deployment." },
      { q: "Is Nuxt good for SEO?", a: "Nuxt is excellent for SEO. It supports server-side rendering (SSR) and static generation (SSG) out of the box, ensuring search engines see fully-rendered HTML. Nuxt's useHead() composable makes managing meta tags, Open Graph, and structured data straightforward." }
    ]
  },
  next: {
    intro: `<p>Browse the best <strong>free Next.js themes and starter templates</strong> for blogs, portfolios, SaaS apps, e-commerce, and documentation sites. Next.js is the world's most popular React framework — built by Vercel with support for server-side rendering, static generation, the App Router, and edge deployment built right in.</p>
<p>Every Next.js starter here is free and open source. The Next.js ecosystem is massive — from minimal personal blogs to enterprise-grade SaaS platforms, the starters below give you a production-ready foundation you can customise and deploy to Vercel, Netlify, or Cloudflare in minutes.</p>`,
    faq: [
      { q: "Are these Next.js themes free?", a: "Yes. All Next.js starters and themes listed here are free and open source, typically MIT-licensed. You can use them for personal and commercial projects at no cost. Some include optional paid integrations (like Stripe or a CMS), but the code itself is always free." },
      { q: "How do I use a Next.js starter?", a: "Clone the repository with git clone or use create-next-app with the --example flag: npx create-next-app@latest my-app --example https://github.com/owner/repo. Then run npm install and npm run dev to start the local development server on localhost:3000." },
      { q: "What is the difference between Next.js and Gatsby?", a: "Both are React frameworks for building fast websites, but they take different approaches. Next.js is a full-stack framework with SSR, SSG, API routes, and the App Router — built for apps as much as sites. Gatsby is more focused on static sites with a rich plugin and data-sourcing ecosystem. Next.js has significantly more adoption in 2025." },
      { q: "Where can I host a Next.js site for free?", a: "Vercel (built by the Next.js team) offers the best Next.js hosting with a generous free tier. Netlify and Cloudflare Pages also support Next.js for free. For full-stack apps using server actions and edge functions, Vercel's free tier covers most personal and small commercial projects." },
      { q: "Is Next.js good for SEO?", a: "Next.js is excellent for SEO. Its server-side rendering (SSR) and static generation (SSG) ensure Googlebot sees fully-rendered HTML without waiting for JavaScript. The Metadata API in the App Router makes managing page titles, descriptions, Open Graph tags, and JSON-LD structured data clean and straightforward." }
    ]
  }
};

// Generic FAQ for category pages (cross-platform)
const GENERIC_CATEGORY_FAQ = [
  { q: "Are all these themes really free?", a: "Yes. Every theme listed at WPSkins.org is 100% free to download. We curate themes from official sources — WordPress.org, the Shopify Theme Store, Webflow's and Framer's marketplaces, Ghost's theme library, the Hugo themes gallery, Jekyll's gem repository, Astro's theme store, and community directories for Eleventy, Gatsby, Nuxt, Joomla, Drupal, and BigCommerce — so you can trust they're legitimate and safe to use." },
  { q: "Can I use these free themes for commercial projects?", a: "In nearly all cases, yes. WordPress, Joomla, and Drupal themes are GPL-licensed. Shopify, Webflow, and Framer themes follow their respective platform terms. Static site themes for Hugo, Jekyll, Astro, Eleventy, Gatsby, and Nuxt are typically MIT-licensed. Ghost themes are usually MIT or GPL. Always check the individual theme license for specific terms, especially if you're reselling client work." },
  { q: "Which platforms does WPSkins.org cover?", a: "WPSkins covers 15 website platforms: WordPress, Shopify, Webflow, Framer, Ghost, Hugo, Jekyll, Astro, Eleventy, Joomla, Drupal, BigCommerce, Gatsby, Nuxt, and Next.js. We add new platforms as they grow in popularity." },
  { q: "Do I need to credit WPSkins.org if I use a theme?", a: "No — credit goes to the original theme developer (linked on each theme page). WPSkins is just a directory; we don't add anything to the themes themselves." },
  { q: "How often do you add new themes?", a: "New themes are added every week as developers publish them across WordPress.org, the Shopify Theme Store, Webflow and Framer marketplaces, Ghost's theme library, the Hugo themes gallery, and other platform directories. Bookmark this page and check back for the latest additions." }
];

const CATEGORIES = ['Corporate', 'Creative', 'Retail', 'eCommerce', 'Blog Magazine', 'Technology', 'Entertainment', 'Nonprofit', 'Education', 'Real Estate', 'Miscellaneous', 'Wedding', 'BuddyPress', 'Mobile'];

const CATEGORY_SLUGS = {
  // Original WordPress categories
  'Corporate': 'corporate', 'Creative': 'creative', 'Retail': 'retail',
  'eCommerce': 'ecommerce', 'Blog Magazine': 'blog-magazine',
  'Technology': 'technology', 'Entertainment': 'entertainment',
  'Nonprofit': 'nonprofit', 'Education': 'education',
  'Real Estate': 'real-estate', 'Miscellaneous': 'miscellaneous',
  'Wedding': 'wedding', 'BuddyPress': 'buddypress', 'Mobile': 'mobile',
  // New canonical categories used by Shopify/Webflow/Framer importers
  'Business': 'business',
  'Blog': 'blog',
  'Portfolio': 'portfolio',
  'Magazine / News': 'magazine-news',
  'Creative & Design': 'creative-design',
  'Photography': 'photography',
  'Travel & Lifestyle': 'travel-lifestyle',
  'Fashion & Beauty': 'fashion-beauty',
  'Restaurant': 'restaurant',
  'Health & Wellness': 'health-wellness',
  'Non-Profit': 'non-profit',
  'Music': 'music',
  'Podcast': 'podcast',
  'Community / Membership': 'community-membership',
  'Food & Drink': 'food-drink'
};

const SLUG_TO_CATEGORY = Object.fromEntries(
  Object.entries(CATEGORY_SLUGS).map(([k,v]) => [v,k])
);

// Map internal categories to ThemeForest categories
const CATEGORY_TO_THEMEFOREST = {
  'Corporate': 'corporate',
  'Creative': 'creative', 
  'Retail': 'retail',
  'eCommerce': 'ecommerce',
  'Blog Magazine': 'blog-magazine',
  'Technology': 'technology',
  'Entertainment': 'entertainment',
  'Nonprofit': 'nonprofit',
  'Education': 'education',
  'Real Estate': 'real-estate',
  'Miscellaneous': 'miscellaneous',
  'Wedding': 'wedding',
  'BuddyPress': 'buddypress',
  'Mobile': 'mobile',
  // Fallback for any others
  'Blog': 'blog-magazine',
  'Magazine': 'blog-magazine',
  'Photography': 'creative',
  'Portfolio': 'creative',
  'Business': 'corporate'
};


// Helper function for direct REST API calls (Supabase JS client is broken)
// ── Cached session token — avoids getSession() on every restQuery ──────
let _cachedToken = null;
let _tokenFetchedAt = 0;
const TOKEN_TTL = 55 * 60 * 1000; // refresh after 55 min (tokens last 1hr)

async function getAuthToken() {
  const now = Date.now();
  if (_cachedToken && (now - _tokenFetchedAt) < TOKEN_TTL) return _cachedToken;
  try {
    if (sb?.auth) {
      const result = await Promise.race([
        sb.auth.getSession(),
        new Promise((_, reject) => setTimeout(() => reject(new Error('session timeout')), 3000))
      ]);
      if (result?.data?.session?.access_token) {
        _cachedToken = result.data.session.access_token;
        _tokenFetchedAt = now;
        return _cachedToken;
      }
    }
  } catch(e) { /* fall back to anon */ }
  return SUPABASE_ANON;
}

function invalidateTokenCache() { _cachedToken = null; _tokenFetchedAt = 0; }

async function restQuery(table, params = {}) {
  const url = new URL(`${SUPABASE_URL}/rest/v1/${table}`);
  
  if (params.select) url.searchParams.append('select', params.select);
  if (params.eq) {
    for (const [col, val] of Object.entries(params.eq)) {
      url.searchParams.append(col, `eq.${val}`);
    }
  }
  if (params.order) url.searchParams.append('order', params.order);
  if (params.limit) url.searchParams.append('limit', params.limit);
  
  const token = await getAuthToken();
  
  const headers = {
    'apikey': SUPABASE_ANON,
    'Authorization': 'Bearer ' + token
  };
  
  if (params.count) headers['Prefer'] = 'count=exact';
  
  const response = await fetch(url, { headers });
  if (!response.ok) throw new Error('Query failed: ' + response.status);
  
  const data = await response.json();
  const count = params.count ? response.headers.get('Content-Range')?.split('/')[1] : null;
  
  return { data, count: count ? parseInt(count) : null, error: null };
}

// ── Supabase init ──────────────────────────────────────────
let sb;
try {
  if (SUPABASE_URL.includes('YOUR_PROJECT')) {
    document.getElementById('config-notice').style.display = 'block';
    sb = null;
  } else {
    sb = supabase.createClient(SUPABASE_URL, SUPABASE_ANON, {
      auth: {
        flowType: 'pkce',
        detectSessionInUrl: true,
        persistSession: true,
        storage: window.localStorage
      }
    });
  }
} catch(e) { sb = null; }

// ── In-site analytics tracking ─────────────────────────────
// Fire-and-forget event insert. Skips known bots to keep data clean.
const _BOT_UA = /bot|crawl|spider|slurp|prerender|monitor|preview|lighthouse|headless|wget|curl|chrome-lighthouse/i;
const _IS_BOT = _BOT_UA.test(navigator.userAgent || '');
function trackEvent(eventType, props) {
  if (!sb || _IS_BOT) return; // skip if no client or bot
  try {
    const _clip = (v, n) => v == null ? null : String(v).slice(0, n);
    const payload = {
      event_type: eventType,
      theme_id: props?.theme_id || null,
      platform: _clip(props?.platform, 50),
      category: _clip(props?.category, 80),
      affiliate_target: _clip(props?.affiliate_target, 60),
      search_query: _clip(props?.search_query, 200),
      referrer: _clip(document.referrer, 500),
      path: _clip(location.pathname, 500),
    };
    // Fire-and-forget — don't block UI, swallow errors
    sb.from('events').insert(payload).then(() => {}, () => {});
  } catch (e) { /* never block UX on tracking */ }
}

// Detect which affiliate brand a destination URL points to (for affiliate_click events)
function _affiliateBrand(url) {
  if (!url) return null;
  const u = String(url).toLowerCase();
  if (u.includes('shopify.pxf.io') || u.includes('shopify.com')) return 'shopify';
  if (u.includes('bluehost.sjv.io') || u.includes('bluehost.com')) return 'bluehost';
  if (u.includes('namecheap.pxf.io') || u.includes('namecheap.com')) return 'namecheap';
  if (u.includes('m.do.co') || u.includes('digitalocean.com')) return 'digitalocean';
  if (u.includes('elegantthemes.com') || u.includes('idevaffiliate')) return 'elegantthemes';
  if (u.includes('wpastra.com') || u.includes('bsf=')) return 'astra';
  if (u.includes('themeforest.net') || u.includes('envato.com') || u.includes('elements.envato')) return 'envato';
  if (u.includes('cloudways.com')) return 'cloudways';
  if (u.includes('beehiiv.com')) return 'beehiiv';
  if (u.includes('bunny.net')) return 'bunny';
  if (u.includes('looka.com')) return 'looka';
  if (u.includes('mangools.com')) return 'mangools';
  if (u.includes('semrush.com')) return 'semrush';
  if (u.includes('kadencewp.com')) return 'kadence';
  if (u.includes('elementor.com')) return 'elementor';
  if (u.includes('porkbun.com')) return 'porkbun';
  if (u.includes('hover.com')) return 'hover';
  if (u.includes('cloudflare.com')) return 'cloudflare';
  if (u.includes('mailerlite.com')) return 'mailerlite';
  if (u.includes('kit.com') || u.includes('convertkit.com')) return 'kit';
  if (u.includes('klaviyo.com')) return 'klaviyo';
  if (u.includes('shortpixel.com')) return 'shortpixel';
  if (u.includes('canva.com')) return 'canva';
  if (u.includes('brandmark.io')) return 'brandmark';
  if (u.includes('tailorbrands.com')) return 'tailorbrands';
  return null;
}

// ── State ──────────────────────────────────────────────────
let currentUser = null;
let currentProfile = null;
let allThemes = [];
let activeSort = 'latest';
let searchQuery = '';
let filterCategory = '';
let filters = {platform: '', category: ''};
let filterColors = [];
let filterCols = '';
let filterLayout = '';
let displayedThemes = [];   // themes currently shown in grid
let serverOffset = 0;       // how many we've loaded so far
let serverTotal = 0;        // total matching on server
let serverLoading = false;  // prevent double fetches
const PAGE_SIZE = 24;
let currentThemeId = null;
let modalCallback = null;
let affiliateConfig = {};
let homepageAffiliates = { bottomUrl: '', hostingUrl: '' };
let platformAffiliatesMap = {}; // platform_id -> row from platform_affiliates
let homepagePremiumThemes = [];

// ── Page system ────────────────────────────────────────────
function showPage(p) {
  document.querySelectorAll('.page').forEach(el => el.classList.remove('active'));
  document.getElementById('page-'+p).classList.add('active');
  document.querySelectorAll('.nav-link').forEach(el => el.classList.remove('active'));
  const idx = {home:0, directory:0};
  const links = document.querySelectorAll('.nav-link');
  if (idx[p] !== undefined && links[idx[p]]) links[idx[p]].classList.add('active');
  if (p === 'home') {
    loadAndRender();
    updateSEO({}); // reset to homepage defaults
    renderSeoIntro(null);
    renderFAQ(null);
  }
  if (p === 'directory') loadAndRender();
  if (p === 'detail') renderDetail(currentThemeId);
  window.scrollTo(0,0);
}

function navSubmit() {
  if (!currentUser) { toast('Please log in to submit a theme','info'); showPage('login'); return; }
  window.location.href = 'submit.html';
}
function navDash() {
  if (!currentUser) { toast('Please log in first','info'); showPage('login'); return; }
  window.location.href = 'dashboard.html';
}

// ── Auth ───────────────────────────────────────────────────
async function doLogin() {
  if (!sb) { toast('Supabase not configured','error'); return; }
  const email = document.getElementById('login-email').value.trim();
  const pass  = document.getElementById('login-pass').value;
  if (!email || !pass) { toast('Fill in all fields','error'); return; }
  setBusy('login-btn', true, 'Signing in…');
  const { data, error } = await sb.auth.signInWithPassword({ email, password: pass });
  setBusy('login-btn', false, 'Sign In');
  if (error) { toast(error.message, 'error'); return; }
  await afterAuth(data.user);
  showPage('home');
}

async function doRegister() {
  if (!sb) { toast('Supabase not configured','error'); return; }
  const name  = document.getElementById('reg-name').value.trim();
  const email = document.getElementById('reg-email').value.trim();
  const pass  = document.getElementById('reg-pass').value;
  if (!name || !email || !pass) { toast('Fill in all fields','error'); return; }
  if (pass.length < 6) { toast('Password must be 6+ characters','error'); return; }
  setBusy('reg-btn', true, 'Creating account…');
  const { data, error } = await sb.auth.signUp({ email, password: pass, options: { data: { full_name: name } } });
  setBusy('reg-btn', false, 'Create Account');
  if (error) { toast(error.message,'error'); return; }
  if (data.user && !data.session) { toast('Check your email to confirm your account!','info'); showPage('login'); return; }
  await afterAuth(data.user);
  showPage('home');
}

async function doGoogleLogin() {
  if (!sb) { toast('Supabase not configured','error'); return; }
  const { error } = await sb.auth.signInWithOAuth({
    provider: 'google',
    options: { redirectTo: window.location.origin + '/' }
  });
  if (error) toast(error.message,'error');
}

async function doLogout() {
  if (sb) await sb.auth.signOut();
  invalidateTokenCache();
  currentUser = null; currentProfile = null;
  updateNavAuth();
  toast('Signed out','info');
  showPage('home');
}

async function afterAuth(user) {
  invalidateTokenCache();
  currentUser = user;
  // Load profile — publicly readable, anon key is sufficient
  if (user) {
    try {
      const url = `${SUPABASE_URL}/rest/v1/profiles?id=eq.${encodeURIComponent(user.id)}&select=*&limit=1`;
      const res = await fetch(url, {
        headers: { 'apikey': SUPABASE_ANON, 'Authorization': 'Bearer ' + SUPABASE_ANON }
      });
      if (res.ok) {
        const rows = await res.json();
        currentProfile = rows[0] || null;
      }
    } catch(e) { /* profile load failed */ }
  }
  updateNavAuth();
  toast('Welcome back!', 'success');
}

function updateNavAuth() {
  const nr = document.getElementById('nav-right');
  const ab = document.getElementById('admin-nav-btn');
  if (currentUser) {
    const name = currentProfile?.name || currentUser.email;
    const initials = name.split(' ').map(w=>w[0]).join('').slice(0,2).toUpperCase();
    nr.innerHTML = `<div class="user-avatar" title="${escAttr(name)}">${esc(initials)}</div><button class="nav-btn ghost" onclick="doLogout()">Sign Out</button>`;
    
    // Show admin button if user is admin (check is_admin field OR hardcoded user ID)
    const isAdmin = currentProfile?.is_admin === true;
    ab.style.display = isAdmin ? 'block' : 'none';
  } else {
    nr.innerHTML = `<button class="nav-btn ghost" onclick="showPage('login')">Log In</button><button class="nav-btn" onclick="showPage('register')">Sign Up</button>`;
    ab.style.display = 'none';
  }
}

// ── Init auth state on load ────────────────────────────────
async function initAuth() {
  if (!sb) return;

  // Explicitly exchange OAuth code if present in URL (PKCE flow)
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get('code');
  if (code) {
    try {
      await sb.auth.exchangeCodeForSession(code);
    } catch(e) { /* session exchange failed, continue */ }
    // Clean the code out of the URL so it doesn't persist
    window.history.replaceState({}, '', window.location.pathname);
  }

  const { data: { session } } = await sb.auth.getSession();
  if (session?.user) await afterAuth(session.user);

  sb.auth.onAuthStateChange(async (event, session) => {
    if (session?.user && (event === 'SIGNED_IN' || event === 'INITIAL_SESSION')) await afterAuth(session.user);
    if (event === 'SIGNED_OUT') { currentUser = null; currentProfile = null; updateNavAuth(); }
  });
}

// ── Themes loading ─────────────────────────────────────────
// ── Theme cache (localStorage) ─────────────────────────────
const CACHE_KEY = 'wpskins_themes_v1';
const CACHE_TTL = 10 * 60 * 1000; // 10 minutes

function readCache() {
  try {
    const raw = localStorage.getItem(CACHE_KEY);
    if (!raw) return null;
    const { ts, data } = JSON.parse(raw);
    if (Date.now() - ts > CACHE_TTL) return null; // expired
    return data;
  } catch(e) { return null; }
}

function writeCache(data) {
  try { localStorage.setItem(CACHE_KEY, JSON.stringify({ ts: Date.now(), data })); } catch(e) {}
}

async function fetchAllThemes() {
  // Themes are public (status=approved + RLS allows anon SELECT) — use anon key
  // directly to avoid waiting for Supabase JS to initialize and getSession() to resolve.
  const PAGE = 1000;
  let allData = [], offset = 0;
  while (true) {
    const url = new URL(`${SUPABASE_URL}/rest/v1/themes`);
    url.searchParams.append('select', 'id,name,slug,platform,category,status,views,created_at,author');
    url.searchParams.append('status', 'eq.approved');
    url.searchParams.append('order', 'created_at.desc');
    url.searchParams.append('limit', PAGE);
    url.searchParams.append('offset', offset);
    const res = await fetch(url, { headers: { 'apikey': SUPABASE_ANON, 'Authorization': 'Bearer ' + SUPABASE_ANON } });
    if (!res.ok) throw new Error('Query failed: ' + res.status);
    const page = await res.json();
    if (!page.length) break;
    allData = allData.concat(page);
    if (page.length < PAGE) break;
    offset += PAGE;
  }
  return allData;
}

// Build PostgREST filter string from current UI state
function buildFilterParams() {
  const parts = ['status=eq.approved'];
  parts.push('select=id,name,slug,platform,category,status,screenshot_url,featured,views,created_at,author,description,zip_url,demo_url,pro_url,premium_url');
  if (filters.platform) parts.push(`platform=eq.${encodeURIComponent(filters.platform)}`);
  if (filters.category) parts.push(`category=cs.%7B${encodeURIComponent(filters.category)}%7D`);
  if (searchQuery) {
    const q = encodeURIComponent(searchQuery);
    parts.push(`or=(name.ilike.*${q}*,description.ilike.*${q}*,author.ilike.*${q}*)`);
  }
  if (activeSort === 'views') parts.push('order=views.desc,created_at.desc');
  else if (activeSort === 'featured') { parts.push('featured=eq.true'); parts.push('order=views.desc,created_at.desc'); }
  else parts.push('order=created_at.desc');
  return parts.join('&');
}

async function fetchThemesPage(offset = 0) {
  if (serverLoading) return;
  serverLoading = true;
  const url = `${SUPABASE_URL}/rest/v1/themes?${buildFilterParams()}&limit=${PAGE_SIZE}&offset=${offset}`;
  try {
    const res = await fetch(url, {
      headers: { 'apikey': SUPABASE_ANON, 'Authorization': 'Bearer ' + SUPABASE_ANON, 'Prefer': 'count=exact' }
    });
    if (!res.ok) throw new Error('Failed to load themes');
    const range = res.headers.get('Content-Range');
    if (range) { const t = parseInt(range.split('/')[1]); if (!isNaN(t)) serverTotal = t; }
    const data = await res.json();
    displayedThemes = offset === 0 ? data : displayedThemes.concat(data);
    serverOffset = offset + data.length;
  } catch(e) {
    console.error('fetchThemesPage error:', e);
  } finally {
    serverLoading = false;
  }
  renderDirectory();
}

async function resetAndFetch() {
  displayedThemes = [];
  serverOffset = 0;
  serverTotal = 0;
  const wrap = document.getElementById('themes-grid-wrap');
  if (wrap) wrap.innerHTML = '<div class="loading-spinner"><div class="spinner"></div> Loading themes…</div>';
  await fetchThemesPage(0);
}

async function loadMoreThemes() {
  if (serverLoading || serverOffset >= serverTotal) return;
  await fetchThemesPage(serverOffset);
}

let _platformCardsBuilt = false;
function applyThemesAndRender(data) {
  allThemes = data;
  try { buildPlatformList(); buildCategoryList(); } catch(e) {}
  if (!_platformCardsBuilt) { try { buildPlatformCards(); _platformCardsBuilt = true; } catch(e) {} }
  resetAndFetch();
  renderLatestList();
}

async function loadAndRender() {
  const wrap = document.getElementById('themes-grid-wrap');

  // ── Step 1: show cached data instantly if available ──────
  const cached = readCache();
  if (cached && cached.length > 0) {
    applyThemesAndRender(cached);
    // Refresh in background — user already sees content
    fetchAllThemes()
      .then(fresh => {
        writeCache(fresh);
        // Only re-render if data actually changed (count or newest id)
        const changed = fresh.length !== cached.length || fresh[0]?.id !== cached[0]?.id;
        if (changed) applyThemesAndRender(fresh);
      })
      .catch(e => console.warn('Background refresh failed:', e));
    return;
  }

  // ── Step 2: no cache — show spinner and fetch ────────────
  wrap.innerHTML = '<div class="loading-spinner"><div class="spinner"></div> Loading themes…</div>';
  try {
    const data = await fetchAllThemes();
    writeCache(data);
    applyThemesAndRender(data);
  } catch(err) {
    wrap.innerHTML = '<div class="empty"><div class="icon">⚠</div><p>Error loading themes</p></div>';
    console.error('loadAndRender error:', err);
  }
}

// ── Affiliate config ───────────────────────────────────────
async function loadAffiliateConfig() {
  // Default config if database isn't set up
  affiliateConfig = {
    envato_base: 'https://themeforest.net',
    envato_cat: 'https://themeforest.net/category/wordpress/{category}?ref=wpskins'
  };
  
  // Try to load from database
  try {
    const { data } = await restQuery('affiliate_config', {
      select: '*',
      eq: { id: 1 }
    });
    if (data && data[0]) {
      affiliateConfig = data[0];
    }
  } catch(err) {
    console.log('Using default affiliate config');
  }
  
  // Load ALL platform affiliate rows once and cache by platform id
  try {
    const { data: affAll } = await restQuery('platform_affiliates', { select: '*' });
    if (Array.isArray(affAll)) {
      platformAffiliatesMap = {};
      for (const row of affAll) {
        if (row && row.platform) platformAffiliatesMap[row.platform] = row;
      }
      const wp = platformAffiliatesMap['wordpress'];
      if (wp) {
        homepageAffiliates.bottomUrl  = wp.bottom_url  || wp.general_url || '';
        homepageAffiliates.hostingUrl = wp.hosting_url || '';
      }
    }
  } catch(err) {
    console.log('Platform affiliate URLs not loaded');
  }
  
  // Load all active premium themes (caller filters by platform at render time)
  try {
    const { data: premium } = await restQuery('premium_themes', {
      select: '*',
      eq: { active: true },
      order: 'display_order.asc'
    });
    homepagePremiumThemes = premium || [];
  } catch(err) {
    console.log('Homepage premium themes not loaded');
  }
}

// ── Filters & sort ─────────────────────────────────────────
function buildPlatformList() {
  if (!document.getElementById('platform-list')) return;
  const container = document.getElementById('platform-list');
  container.innerHTML = '';
  PLATFORMS.filter(p => p.enabled).forEach(p => {
    const count = allThemes.filter(t => t.platform === p.id).length;
    const active = filters.platform === p.id ? ' active' : '';
    const btn = document.createElement('button');
    btn.className = 'filter-btn' + active;
    btn.innerHTML = `${p.emoji} ${p.name} <span style="color:var(--wp-muted);font-size:11px">(${count})</span>`;
    btn.onclick = () => {
      filters.platform = p.id;
      filters.category = '';
      applyFilters();
      buildPlatformList();
      buildCategoryList();
      const platformName = p.name;
      const count = allThemes.filter(t => t.platform === p.id).length;
      window.history.pushState({}, '', `/${p.id}`);
      const seo = PLATFORM_SEO[p.id];
      updateSEO({
        title: `Free ${platformName} Themes`,
        description: `Browse ${count}+ free ${platformName} themes. Responsive, customizable, and ready to download.`,
        canonical: `/${p.id}`,
        breadcrumbs: [
          { name: 'Home', path: '/' },
          { name: `Free ${platformName} Themes`, path: `/${p.id}` }
        ],
        jsonldExtra: seo ? escFaqJson(seo.faq) : null
      });
      renderSeoIntro(seo ? { heading: `Free ${platformName} Themes`, html: seo.intro } : null);
      renderFAQ(seo ? seo.faq : null);
    };
    container.appendChild(btn);
  });
}

// Normalize a theme's category field (could be array or PG braced string) into a plain array
function getThemeCategories(theme) {
  if (!theme) return [];
  if (Array.isArray(theme.category)) return theme.category.filter(Boolean);
  return String(theme.category || '').replace(/[{}"]/g, '').split(',').map(c => c.trim()).filter(Boolean);
}

// ── Theme page content enrichment ────────────────────────────
// Generates unique, per-theme text so detail pages aren't thin/templated.
// Pulls from real theme data (platform, categories, author, colors, layout)
// so every page reads differently.
const PLATFORM_BLURB = {
  wordpress:   'installs through the WordPress dashboard in a couple of clicks and works with the thousands of plugins in the WordPress ecosystem',
  shopify:     'comes with Shopify’s built-in payments, checkout, and inventory tools, so you can start selling without extra setup',
  webflow:     'gives you Webflow’s visual editor and clean hosting, no code required to customize the layout',
  framer:      'uses Framer’s drag-and-drop editor and publishes to fast, hosted pages out of the box',
  ghost:       'runs on Ghost’s lightweight publishing engine, built for writers who want speed and a clean reading experience',
  hugo:        'builds as a static site with Hugo, which means near-instant page loads and easy hosting on any CDN',
  jekyll:      'builds with Jekyll and deploys cleanly to GitHub Pages or any static host, with no database to maintain',
  astro:       'is built for Astro, shipping minimal JavaScript so your pages stay fast by default',
  eleventy:    'uses Eleventy (11ty), a simple static site generator that keeps your output lean and fast',
  joomla:      'installs as a Joomla template and works with Joomla’s extension library for added functionality',
  drupal:      'runs on Drupal, suited to content-heavy sites that need flexible structure and access control',
  bigcommerce: 'works with BigCommerce’s hosted commerce platform and its built-in store features',
  gatsby:      'is a Gatsby starter that builds to a fast static site backed by React',
  nuxt:        'is built on Nuxt, giving you Vue-powered pages that render fast and stay easy to extend',
  next:        'is a Next.js starter, deployable to Vercel or any Node host, with React under the hood'
};

const CATEGORY_USECASE = {
  'Corporate': 'company and corporate websites',
  'Creative': 'creative studios and agencies',
  'Creative & Design': 'design portfolios and creative studios',
  'Retail': 'retail and shop sites',
  'eCommerce': 'online stores and product catalogs',
  'Blog': 'personal blogs and writing sites',
  'Blog Magazine': 'blogs and online magazines',
  'Magazine / News': 'news sites and online magazines',
  'Technology': 'tech, SaaS, and startup sites',
  'Entertainment': 'entertainment and media sites',
  'Education': 'schools, courses, and education sites',
  'Real Estate': 'property listings and real estate sites',
  'Business': 'small business and service sites',
  'Portfolio': 'portfolios and personal showcase sites',
  'Photography': 'photography portfolios and galleries',
  'Travel & Lifestyle': 'travel blogs and lifestyle sites',
  'Fashion & Beauty': 'fashion, beauty, and boutique brands',
  'Restaurant': 'restaurants, cafes, and food businesses',
  'Health & Wellness': 'health, fitness, and wellness sites',
  'Music': 'musicians, bands, and music sites',
  'Podcast': 'podcasts and audio shows',
  'Community / Membership': 'communities and membership sites',
  'Food & Drink': 'food, drink, and recipe sites',
  'Wedding': 'weddings and event sites',
  'Mobile': 'app landing pages and mobile-first sites',
  'Miscellaneous': 'all kinds of websites'
};

function listToProse(arr) {
  const a = arr.filter(Boolean);
  if (a.length === 0) return '';
  if (a.length === 1) return a[0];
  if (a.length === 2) return a[0] + ' and ' + a[1];
  return a.slice(0, -1).join(', ') + ', and ' + a[a.length - 1];
}

function buildThemeEnrichment(t, platformName, allCats) {
  const name = esc(t.name);
  const catProse = listToProse(allCats.map(c => (c || '').toLowerCase()));
  const useCases = listToProse([...new Set(allCats.map(c => CATEGORY_USECASE[c]).filter(Boolean))]);
  const colors = Array.isArray(t.colors) ? t.colors.filter(Boolean) : [];
  const platBlurb = PLATFORM_BLURB[t.platform] || 'is ready to download and customize for your project';
  const updated = t.updated_at ? new Date(t.updated_at).toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) : '';

  // Intro paragraph — varies per theme based on which fields exist
  let intro = `${name} is a free ${esc(platformName)} theme`;
  intro += catProse ? ` made for ${esc(catProse)} websites. ` : '. ';
  intro += t.author ? `Built by ${esc(t.author)}, it’s ` : 'It’s ';
  intro += `100% free to download — no subscription, no email wall, no catch. `;
  intro += `The theme ${platBlurb}.`;

  // Second paragraph — design notes
  let design = '';
  if (colors.length) design += `Its color palette leans ${esc(listToProse(colors.map(c => c.toLowerCase())))}, `;
  design += colors.length ? 'and it’s ' : 'It’s ';
  design += `responsive out of the box, so it adapts to phones, tablets, and desktops without extra work. `;
  if (useCases) design += `It’s a solid fit for ${esc(useCases)}.`;

  // Key details list
  const details = [];
  details.push(['Platform', esc(platformName)]);
  if (allCats.length) details.push(['Category', esc(allCats.join(', '))]);
  if (t.author) details.push(['Author', esc(t.author)]);
  if (t.layout) details.push(['Layout', esc(t.layout)]);
  if (colors.length) details.push(['Colors', esc(colors.join(', '))]);
  details.push(['Price', 'Free']);
  if (updated) details.push(['Last updated', esc(updated)]);

  const detailRows = details.map(([k, v]) =>
    `<div style="display:flex;justify-content:space-between;gap:16px;padding:9px 0;border-bottom:1px solid var(--wp-border)"><span style="color:var(--wp-muted);font-size:14px">${k}</span><span style="color:var(--wp-text);font-size:14px;font-weight:600;text-align:right">${v}</span></div>`
  ).join('');

  // Theme-specific FAQ
  const faq = [
    [`Is ${name} really free?`, `Yes. ${name} is completely free to download and use. There’s no subscription, no trial, and no email signup required.`],
    [`What platform does ${name} work with?`, `${name} is built for ${esc(platformName)}. You’ll need a ${esc(platformName)} site to use it.`],
    [`Can I use ${name} for a commercial project?`, `In almost all cases, yes. Most free ${esc(platformName)} themes allow commercial use, but check the theme author’s license on the demo or download page to be sure, especially if you’re building for a client.`],
  ];
  if (t.demo_url) faq.push([`Is there a live demo of ${name}?`, `Yes — use the "Live Demo" button above to preview ${name} before downloading.`]);

  const faqHtml = faq.map((q, i) => `
    <details style="border-bottom:1px solid var(--wp-border);padding:14px 0" ${i === 0 ? 'open' : ''}>
      <summary style="font-weight:600;cursor:pointer;color:var(--wp-text);list-style:none">${q[0]}</summary>
      <div style="color:var(--wp-text);line-height:1.7;padding:12px 0 0;opacity:.9">${q[1]}</div>
    </details>`).join('');

  // FAQ structured data
  const faqJsonLd = {
    '@context': 'https://schema.org',
    '@type': 'FAQPage',
    'mainEntity': faq.map(q => ({
      '@type': 'Question',
      'name': q[0].replace(/<[^>]+>/g, ''),
      'acceptedAnswer': { '@type': 'Answer', 'text': q[1].replace(/<[^>]+>/g, '') }
    }))
  };

  return {
    introHtml: `<p style="color:var(--wp-text);line-height:1.7;margin:0 0 16px">${intro}</p><p style="color:var(--wp-text);line-height:1.7;margin:0">${design}</p>`,
    detailsHtml: `<h3 style="font-family:var(--font-head);font-size:18px;font-weight:700;margin:28px 0 8px">Theme details</h3><div>${detailRows}</div>`,
    faqHtml: `<h3 style="font-family:var(--font-head);font-size:18px;font-weight:700;margin:28px 0 8px">Frequently asked questions</h3>${faqHtml}`,
    faqJsonLd
  };
}

function buildCategoryList() {
  if (!document.getElementById('category-list')) return;
  const container = document.getElementById('category-list');
  container.innerHTML = '';
  CATEGORIES.forEach(cat => {
    const count = allThemes.filter(t => getThemeCategories(t).includes(cat)).length;
    // Skip empty categories — don't render zero-count buttons (unless it's the active filter)
    if (count === 0 && filters.category !== cat) return;
    const active = filters.category === cat ? ' active' : '';
    const btn = document.createElement('button');
    btn.className = 'filter-btn' + active;
    btn.innerHTML = `${cat} <span style="color:var(--wp-muted);font-size:11px">(${count})</span>`;
    btn.onclick = () => {
      filters.category = cat;
      filters.platform = '';
      applyFilters();
      buildCategoryList();
      buildPlatformList();
      const slug = CATEGORY_SLUGS[cat] || cat.toLowerCase().replace(/\s+/g,'-');
      const count = allThemes.filter(t => getThemeCategories(t).includes(cat)).length;
      window.history.pushState({}, '', `/themes/${slug}`);
      updateSEO({
        title: `Free ${cat} Website Themes`,
        description: `Download ${count}+ free ${cat} website themes for WordPress, Shopify, Webflow, Astro, Ghost, Hugo, and more. All themes are free and responsive.`,
        canonical: `/themes/${slug}`,
        breadcrumbs: [
          { name: 'Home', path: '/' },
          { name: `${cat} Themes`, path: `/themes/${slug}` }
        ],
        jsonldExtra: escFaqJson(GENERIC_CATEGORY_FAQ)
      });
      renderSeoIntro({
        heading: `Free ${cat} Website Themes`,
        html: `<p>Browse our curated collection of <strong>free ${cat.toLowerCase()} themes</strong> for WordPress, Shopify, Webflow, Astro, Ghost, Hugo, Gatsby, Nuxt, and more. Every theme below is professionally designed, fully responsive, and 100% free to download — no signups, no email walls, no hidden fees.</p>
<p>${cat} themes are designed specifically for ${cat.toLowerCase()}-focused websites, with layouts, color schemes, and features tailored to that use case. Whether you're a freelancer, agency, or just starting out, you'll find a free ${cat.toLowerCase()} theme here that gives you a professional starting point.</p>`
      });
      renderFAQ(GENERIC_CATEGORY_FAQ);
    };
    container.appendChild(btn);
  });
}

function buildColorSwatches() {
  const el = document.getElementById('color-swatches');
  if (!el) return;
  el.innerHTML = COLORS.map(c =>
    `<div class="swatch-item" onclick="toggleColor('${c.name}',this)">
      <div class="swatch" style="background:${c.hex}" data-color="${c.name}"></div>
      <span class="swatch-label">${c.name}</span>
    </div>`).join('');
}

function buildColorPickers() {
  ['submit-color-picker','admin-color-picker'].forEach(id => {
    const el = document.getElementById(id);
    if (!el) return;
    el.innerHTML = COLORS.map(c =>
      `<label class="color-pick-item">
        <input type="checkbox" value="${c.name}" class="${id}-cb">
        <div class="color-dot" style="background:${c.hex}"></div>${c.name}
      </label>`).join('');
  });
}


function toggleColor(name, item) {
  const swatch = item.querySelector('.swatch');
  const idx = filterColors.indexOf(name);
  if (idx >= 0) { filterColors.splice(idx,1); swatch.classList.remove('checked'); }
  else { filterColors.push(name); swatch.classList.add('checked'); }
  resetAndFetch();
}

function toggleFilter(type, val, btn) {
  if (type === 'col')    filterCols   = filterCols   === val ? '' : val;
  if (type === 'layout') filterLayout = filterLayout === val ? '' : val;
  document.querySelectorAll(type==='col'?'#col-filters .filter-btn':'#layout-filters .filter-btn')
    .forEach(b => b.classList.remove('active'));
  if ((type==='col'&&filterCols)||(type==='layout'&&filterLayout)) btn.classList.add('active');
  resetAndFetch();
}

function setSort(s, btn) {
  activeSort = s;
  document.querySelectorAll('.sort-tab').forEach(t => t.classList.remove('active'));
  btn.classList.add('active');
  resetAndFetch();
}

let _liveSearchTimer = null;
let _lastTrackedSearch = '';
function liveSearch() {
  clearTimeout(_liveSearchTimer);
  _liveSearchTimer = setTimeout(() => {
    searchQuery = document.getElementById('hero-search-input').value.toLowerCase();
    resetAndFetch();
    // Track search only for non-trivial queries, and only once per unique query (avoid duplicates)
    const q = searchQuery.trim();
    if (q && q.length >= 3 && q !== _lastTrackedSearch) {
      _lastTrackedSearch = q;
      trackEvent('search', { search_query: q });
    }
  }, 800);  // longer debounce so we track after they stop typing
}

function applyFilters() {
  // Update URL based on filters
  if (filters.platform && filters.category) {
    const categorySlug = CATEGORY_SLUGS[filters.category];
    if (categorySlug) {
      window.history.pushState({}, '', `/${filters.platform}/${categorySlug}`);
    }
  } else if (filters.platform) {
    window.history.pushState({}, '', `/${filters.platform}`);
  } else {
    window.history.pushState({}, '', '/');
  }

  resetAndFetch();
}

function clearFilters() {
  filterCategory=''; filterColors=[]; filterCols=''; filterLayout=''; searchQuery='';
  filters.platform=''; filters.category='';
  document.getElementById('hero-search-input').value = '';
  document.querySelectorAll('.swatch').forEach(s => s.classList.remove('checked'));
  document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
  window.history.pushState({}, '', '/');
  buildPlatformList();
  buildCategoryList();
  resetAndFetch();
}

function buildPlatformCards() {
  const container = document.querySelector('.platform-cards');
  if (!container) return;
  container.innerHTML = '';
  
  PLATFORMS.filter(p => p.enabled).forEach(p => {
    const count = allThemes.filter(t => t.platform === p.id).length;
    const card = document.createElement('a');
    card.href = '#';
    card.className = 'platform-card';
    card.innerHTML = `
      <div class="platform-icon">${p.emoji}</div>
      <div class="platform-name">${p.name}</div>
      <div class="platform-count">${count} themes</div>
    `;
    card.onclick = (e) => {
      e.preventDefault();
      window.history.pushState({}, '', `/${p.id}`);
      checkDeepLink();
      window.scrollTo({ top: 0, behavior: 'smooth' });
      return false;
    };
    container.appendChild(card);
  });
}

// ── Directory render ───────────────────────────────────────
function renderDirectory() {
  const wrap = document.getElementById('themes-grid-wrap');
  if (!wrap) return;

  const showing = displayedThemes.length;
  const total = serverTotal;
  document.getElementById('themes-count').textContent =
    (showing < total ? `Showing ${showing} of ${total}` : `${total} theme${total!==1?'s':''}`) +
    (searchQuery ? ` for "${searchQuery}"` : '');

  if (!showing && !serverLoading) {
    wrap.innerHTML = '<div class="empty"><div class="icon">🎨</div><p>No themes match your filters.</p></div>';
    return;
  }
  if (!showing) return; // still loading, spinner already shown

  const bottomUrl = homepageAffiliates.bottomUrl;
  const hostingUrl = homepageAffiliates.hostingUrl;

  const ctaBlock = `
    <div style="margin-top:48px;background:var(--wp-card);border:2px solid var(--wp-border);border-radius:16px;padding:40px;text-align:center;box-shadow:0 4px 20px rgba(0,0,0,.06)">
      <h2 style="font-family:var(--font-head);font-size:26px;font-weight:700;margin:0 0 24px;color:var(--wp-text)">Ready to build a better website?</h2>
      <div style="display:flex;gap:12px;max-width:${hostingUrl ? '720px' : '500px'};margin:0 auto 12px;flex-wrap:wrap;justify-content:center">
        ${bottomUrl ? `<button onclick="openLink('${safeUrl(bottomUrl)}')" style="flex:1;min-width:180px;padding:18px;background:#f97316;border:none;border-radius:10px;color:white;font-size:16px;font-weight:700;cursor:pointer;box-shadow:0 4px 12px rgba(249,115,22,.3);transition:all .2s" onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 6px 16px rgba(249,115,22,.4)'" onmouseout="this.style.transform='';this.style.boxShadow='0 4px 12px rgba(249,115,22,.3)'">Upgrade to Professional Themes →</button>` : ''}
        <button onclick="document.getElementById('hero-search-input')?.focus();window.scrollTo({top:0,behavior:'smooth'})" style="flex:1;min-width:160px;padding:18px;background:#3b82f6;border:none;border-radius:10px;color:white;font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(59,130,246,.2)">Browse Free Themes</button>
        ${hostingUrl ? `<button onclick="openLink('${safeUrl(hostingUrl)}')" style="flex:1;min-width:200px;padding:18px;background:#10b981;border:none;border-radius:10px;color:white;font-size:14px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(16,185,129,.25);transition:all .2s;line-height:1.3" onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 6px 16px rgba(16,185,129,.35)'" onmouseout="this.style.transform='';this.style.boxShadow='0 2px 8px rgba(16,185,129,.25)'">Get fast, reliable ${esc(PLATFORMS.find(p=>p.id===filters.platform)?.name || 'website')} hosting →</button>` : ''}
      </div>
      <div style="font-size:13px;color:var(--wp-muted)">${hostingUrl ? 'Launching your website? Start free, upgrade with premium, or get reliable hosting.' : 'Start free or unlock more with premium features'}</div>
    </div>`;

  // Filter premium themes to the current platform (or show all on the homepage when no filter is active)
  const _platformPremium = (homepagePremiumThemes || []).filter(e => {
    if (!filters.platform) return true;                 // homepage: show whatever exists
    const list = Array.isArray(e.platforms) ? e.platforms : [];
    return list.includes(filters.platform);             // platform page: only matching premium themes
  });

  // Build a premium-themes block, rotated so each subsequent block starts at a different item.
  // With ≥3 premium themes this gives variety; with <3 we just repeat what's there.
  function buildPremiumRow(rotation) {
    if (!_platformPremium.length) return '';
    const items = [];
    for (let i = 0; i < 3; i++) {
      items.push(_platformPremium[(rotation + i) % _platformPremium.length]);
    }
    return `
    <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin:32px 0">
      ${items.map(e => `
        <div onclick="openLink('${safeUrl(e.affiliate_url)}')" style="cursor:pointer;background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;overflow:hidden;transition:all .2s;box-shadow:0 2px 8px rgba(0,0,0,.04)" onmouseover="this.style.transform='translateY(-4px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,.1)'" onmouseout="this.style.transform='';this.style.boxShadow='0 2px 8px rgba(0,0,0,.04)'">
          <img loading="lazy" decoding="async" src="${safeUrl(e.image_url)}" alt="${escAttr(e.name)} – Premium theme" style="width:100%;aspect-ratio:4/3;object-fit:cover;display:block">
          <div style="padding:12px">
            <div style="font-weight:600;font-size:14px;color:var(--wp-text);margin-bottom:4px">${esc(e.name)}</div>
            <div style="display:flex;align-items:center;justify-content:space-between">
              <span style="font-size:12px;color:var(--wp-muted)">${esc(e.sales_text)} sales</span>
              <span style="background:rgba(245,158,11,.12);color:#d97706;font-size:10px;font-weight:700;padding:2px 7px;border-radius:4px">Premium</span>
            </div>
          </div>
        </div>`).join('')}
    </div>`;
  }

  const gridStyle = 'display:grid;grid-template-columns:repeat(3,1fr);gap:20px';

  // Build interleaved layout: 3 regular → 3 premium → 3 regular → 3 premium → …
  let interleavedHtml = '';
  let premiumRotation = 0;
  for (let i = 0; i < displayedThemes.length; i += 3) {
    const chunk = displayedThemes.slice(i, i + 3);
    const mt = i === 0 ? '' : ';margin-top:32px';
    interleavedHtml += `<div style="${gridStyle}${mt}">` + chunk.map(themeCard).join('') + '</div>';
    // Insert premium row after each FULL chunk of 3 (skip if partial trailing chunk)
    if (chunk.length === 3) {
      interleavedHtml += buildPremiumRow(premiumRotation);
      premiumRotation += 3; // rotate the start index so each block looks different
    }
  }

  const hasMore = serverOffset < serverTotal && !serverLoading;
  const loadMoreBtn = hasMore ? `
    <div style="text-align:center;margin-top:40px">
      <button onclick="loadMoreThemes()"
              style="padding:14px 40px;background:var(--wp-card);border:1.5px solid var(--wp-border);border-radius:10px;color:var(--wp-text);font-size:15px;font-weight:600;cursor:pointer;transition:all .2s"
              onmouseover="this.style.borderColor='#3b82f6';this.style.color='#3b82f6'"
              onmouseout="this.style.borderColor='';this.style.color=''">
        Load more themes (${serverTotal - serverOffset} remaining)
      </button>
    </div>` : '';

  wrap.innerHTML = interleavedHtml + loadMoreBtn + ctaBlock;
}

function themeCard(t) {
  const platform = PLATFORMS.find(p => p.id === (t.platform || 'wordpress'));
  const platformBadge = platform ? `<div class="platform-badge" style="background:${platform.color}">${platform.emoji} ${platform.name}</div>` : '';
  
  return `<div class="theme-card" onclick="openTheme('${t.id}')">
    <div class="theme-thumb">
      ${t.screenshot_url ? `<img src="${safeUrl(t.screenshot_url)}" alt="${escAttr(t.name)} – Free ${esc(PLATFORMS.find(p=>p.id===t.platform)?.name || 'Website')} Theme Screenshot" loading="lazy" decoding="async" onerror="this.outerHTML='<div class=\\'no-img\\'>🎨</div>'">` : '<div class="no-img">🎨</div>'}
      ${platformBadge}
      ${t.featured ? '<div class="badge-featured">★ Featured</div>' : ''}
    </div>
    <div class="theme-info">
      <div class="theme-name">${esc(t.name)}</div>
      <div class="theme-meta">
        <span>👁 ${(t.views || 0).toLocaleString()}</span>
        ${(!t.pro_url && !t.premium_url) ? '<span style="background:rgba(16,185,129,.15);color:#059669;font-size:10px;font-weight:700;padding:2px 7px;border-radius:4px">Free</span>' : ''}
      </div>
      <div class="theme-tags">
        ${getThemeCategories(t).slice(0, 3).map(c => `<span class="tag">${esc(c)}</span>`).join('')}
      </div>
    </div>
  </div>`;
}

function renderLatestList() {
  const items = [...allThemes].filter(t=>t.status==='approved')
    .sort((a,b) => new Date(b.created_at) - new Date(a.created_at)).slice(0,10);
  document.getElementById('latest-list').innerHTML = items.map(t =>
    `<li onclick="openTheme('${t.id}')">
      <div class="t">${esc(t.name)}</div>
      <div class="m">${esc(getThemeCategories(t).join(', '))} · ${esc(timeAgo(t.created_at))}</div>
    </li>`).join('');
}

// ── Detail page ────────────────────────────────────────────
async function openTheme(id) {
  currentThemeId = id;

  const theme = allThemes.find(t => t.id === id);
  if (theme && theme.slug) {
    const platform = theme.platform || 'wordpress';
    const canonicalPath = `/${platform}/theme/${theme.slug}`;
    window.history.pushState({}, '', canonicalPath);
    // Track theme view
    trackEvent('theme_view', { theme_id: id, platform, category: getThemeCategories(theme)[0] || null });

    // Build per-theme SEO
    const platformName = PLATFORMS.find(p => p.id === platform)?.name || 'WordPress';
    const cats = getThemeCategories(theme).join(', ');
    const desc = theme.description
      ? theme.description.replace(/<[^>]+>/g, '').slice(0, 155).trim()
      : `Download ${theme.name} — a free ${platformName} theme for ${cats} websites. Responsive design, ready to use.`;

    updateSEO({
      title: `${theme.name} – Free ${platformName} Theme`,
      description: desc,
      image: theme.screenshot_url || DEFAULT_IMG,
      canonical: canonicalPath,
      breadcrumbs: [
        { name: 'Home', path: '/' },
        { name: `Free ${platformName} Themes`, path: `/${platform}` },
        { name: theme.name, path: canonicalPath }
      ],
      ogType: 'product',
      jsonld: {
        '@context': 'https://schema.org',
        '@type': 'Product',
        'name': theme.name,
        'description': desc,
        'image': theme.screenshot_url || DEFAULT_IMG,
        'url': SITE + canonicalPath,
        'brand': { '@type': 'Brand', 'name': platformName },
        'offers': {
          '@type': 'Offer',
          'price': '0',
          'priceCurrency': 'USD',
          'availability': 'https://schema.org/InStock',
          'url': SITE + canonicalPath
        },
        ...(theme.author ? { 'author': { '@type': 'Person', 'name': theme.author } } : {}),
        ...(theme.demo_url ? { 'sameAs': theme.demo_url } : {})
      }
    });
  }
  
  showPage('detail');
  // Increment view counter and update display
  if (sb) {
    sb.rpc('increment_views', { theme_id: id })
      .then(() => {
        // Update the local count immediately so display reflects it
        const theme = allThemes.find(t => t.id === id);
        if (theme) {
          theme.views = (theme.views || 0) + 1;
          const viewEl = document.getElementById('view-count-' + id);
          if (viewEl) viewEl.textContent = theme.views.toLocaleString() + ' views';
        }
      })
      .catch(err => console.log('View count update failed:', err));
  }
}

function populateDetailSidebar() {
  const platformList = document.getElementById('detail-platform-list');
  if (platformList) {
    platformList.innerHTML = '';
    PLATFORMS.filter(p => p.enabled).forEach(p => {
      const count = allThemes.filter(t => t.platform === p.id).length;
      const btn = document.createElement('button');
      btn.className = 'filter-btn';
      btn.innerHTML = `${p.emoji} ${p.name} <span style="color:var(--wp-muted);font-size:11px">(${count})</span>`;
      btn.onclick = () => {
        window.history.pushState({}, '', `/${p.id}`);
        checkDeepLink();
        window.scrollTo({ top: 0, behavior: 'smooth' });
      };
      platformList.appendChild(btn);
    });
  }
  
  const categoryList = document.getElementById('detail-category-list');
  if (categoryList) {
    categoryList.innerHTML = '';
    CATEGORIES.forEach(cat => {
      const count = allThemes.filter(t => getThemeCategories(t).includes(cat)).length;
      if (count === 0) return; // skip empty categories
      const btn = document.createElement('button');
      btn.className = 'filter-btn';
      btn.innerHTML = `${cat} <span style="color:var(--wp-muted);font-size:11px">(${count})</span>`;
      btn.onclick = () => {
        const slug = CATEGORY_SLUGS[cat] || cat.toLowerCase().replace(/\s+/g, '-');
        window.history.pushState({}, '', `/themes/${slug}`);
        checkDeepLink();
        window.scrollTo({ top: 0, behavior: 'smooth' });
      };
      categoryList.appendChild(btn);
    });
  }
}

async function renderDetail(id) {
  populateDetailSidebar();
  const el = document.getElementById('detail-content');
  el.innerHTML = '<div class="loading-spinner"><div class="spinner"></div> Loading…</div>';

  // ── Step 1: get theme — fetch full record (cache only has lightweight fields) ──
  let t = allThemes.find(x => x.id === id);
  // If cached theme is missing detail fields, refetch the full record
  if (!t || t.zip_url === undefined) {
    try {
      const result = await Promise.race([
        restQuery('themes', { select: '*', eq: { id } }),
        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 6000))
      ]);
      const full = result.data?.[0];
      if (full) {
        // Merge full record back into allThemes so subsequent lookups have zip_url
        const idx = allThemes.findIndex(x => x.id === id);
        if (idx >= 0) allThemes[idx] = full;
        else allThemes.push(full);
        t = full;
      }
    } catch(err) {
      el.innerHTML = `
        <div style="text-align:center;padding:60px 24px;">
          <div style="font-size:40px;margin-bottom:12px;">⏱</div>
          <p style="color:var(--wp-muted);margin-bottom:20px;">Took too long to load — please try again.</p>
          <button class="nav-btn" onclick="renderDetail('${id}')">Retry</button>
          <button class="nav-btn ghost" onclick="showPage('home')" style="margin-left:8px">Back to browse</button>
        </div>`;
      return;
    }
  }

  if (!t) {
    // Trigger real 404 SEO signals (noindex, "404" prefix, etc.)
    show404(window.location.pathname);
    return;
  }

  const cfg = affiliateConfig;
  const allCats = getThemeCategories(t);
  const cleanCat = allCats[0] || 'Miscellaneous';
  const tfCategory = CATEGORY_TO_THEMEFOREST[cleanCat] || cleanCat.toLowerCase().replace(/\s+/g, '-');
  const _platformNameForEnrich = PLATFORMS.find(p => p.id === t.platform)?.name || 'WordPress';
  const themeEnrich = buildThemeEnrichment(t, _platformNameForEnrich, allCats);
  
  // ── Smart similar themes: rank by (1) same platform + category overlap, (2) same platform, (3) same category cross-platform
  const similar1 = (() => {
    const tCats = new Set(allCats);
    return allThemes
      .filter(x => x.status === 'approved' && x.id !== id)
      .map(x => {
        const xCats = getThemeCategories(x);
        const overlap = xCats.filter(c => tCats.has(c)).length;
        const samePlatform = x.platform === t.platform ? 1 : 0;
        // Score: same platform AND category overlap is best
        const score = (samePlatform * 10) + (overlap * 5);
        return { theme: x, score };
      })
      .filter(s => s.score > 0)
      .sort((a, b) => b.score - a.score)
      .slice(0, 4)
      .map(s => s.theme);
  })();

  // ── Step 2: fire secondary fetches in parallel, don't block render ───────
  const [affResult, premiumResult] = await Promise.allSettled([
    restQuery('platform_affiliates', { select: '*', eq: { platform: t.platform } }),
    restQuery('premium_themes', { select: '*', eq: { active: true }, order: 'display_order.asc' })
  ]);

  let heroUrl = '', sidebarUrl = '', midpageUrl = '', bottomUrl = '', hostingUrl = '', generalUrl = '';
  if (affResult.status === 'fulfilled' && affResult.value?.data?.[0]) {
    const a = affResult.value.data[0];
    generalUrl  = a.general_url  || '';
    heroUrl     = a.hero_url     || '';
    sidebarUrl  = a.sidebar_url  || '';
    midpageUrl  = a.midpage_url  || '';
    bottomUrl   = a.bottom_url   || '';
    hostingUrl  = a.hosting_url  || '';
  }

  let envatoThemes = [];
  if (premiumResult.status === 'fulfilled') {
    envatoThemes = (premiumResult.value?.data || []).filter(p =>
      !p.platforms || p.platforms.length === 0 || p.platforms.includes(t.platform)
    ).slice(0, 4);
  }

  const envatoUrl    = generalUrl || (cfg.envato_cat ? cfg.envato_cat.replace('{category}', tfCategory) : '');
  const heroAffUrl   = heroUrl    || envatoUrl;
  const midpageAffUrl= midpageUrl || envatoUrl;
  const bottomAffUrl = bottomUrl  || envatoUrl;
  const cleanCategory = esc(getThemeCategories(t).join(', '));
  const envatoBox = envatoUrl ? `<div class="envato-box" style="margin-top:16px"><p>Looking for premium ${cleanCategory} themes?</p><button class="envato-btn" onclick="openLink('${safeUrl(envatoUrl)}')">Browse premium ${cleanCategory} themes on ThemeForest →</button></div>` : '';

  el.innerHTML = `
    <!-- MAX WIDTH CONTAINER -->
    <div style="max-width:1200px;margin:0 auto;padding:40px 20px">
    
      <!-- ABOVE THE FOLD: TWO COLUMN -->
      <div style="display:grid;grid-template-columns:60% 40%;gap:32px;margin-bottom:24px">
        
        <!-- LEFT: SCREENSHOT GALLERY -->
        <div>
          ${t.screenshot_url ? `
            <img id="main-screenshot" src="${safeUrl(t.screenshot_url)}" alt="${escAttr(t.name)} – Free ${esc(PLATFORMS.find(p=>p.id===t.platform)?.name || 'Website')} ${esc(allCats.join(', '))} theme screenshot"
                 decoding="async" fetchpriority="high"
                 style="width:100%;border-radius:16px;box-shadow:0 4px 20px rgba(0,0,0,.08);display:block;margin-bottom:16px"
                 onerror="this.outerHTML='<div style=\\'width:100%;aspect-ratio:4/3;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:16px;display:flex;align-items:center;justify-content:center;font-size:96px;color:var(--wp-border);margin-bottom:16px\\'>🎨</div>'">
          ` : `
            <div style="width:100%;aspect-ratio:4/3;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:16px;display:flex;align-items:center;justify-content:center;font-size:96px;color:var(--wp-border);margin-bottom:16px">🎨</div>
          `}
        </div>
        
        <!-- RIGHT: TITLE, RATING, ACTIONS -->
        <div>
          <h1 style="font-family:var(--font-head);font-size:32px;font-weight:800;margin:0 0 16px;line-height:1.2;color:var(--wp-text)">${esc(t.name)}</h1>
          
          <!-- CATEGORY + PLATFORM -->
          <div style="font-size:13px;color:var(--wp-muted);margin-bottom:20px">${esc(allCats.join(', '))} · ${esc(PLATFORMS.find(p=>p.id===t.platform)?.name||'WordPress')}</div>
          
          <div style="height:1px;background:var(--wp-border);margin:0 0 20px"></div>
          
          <!-- 1. HERO CTA (TOP RIGHT - MOST IMPORTANT) -->
          ${envatoUrl ? `
            <div style="background:linear-gradient(135deg,#fef3c7,#fed7aa);border:2px solid #f59e0b;border-radius:12px;padding:24px;margin-bottom:16px;box-shadow:0 4px 16px rgba(245,158,11,.2)">
              <div style="font-size:14px;font-weight:600;color:#92400e;margin-bottom:12px">Upgrade to premium designs used by professionals</div>
              
              <!-- Bullet points -->
              <div style="margin-bottom:16px">
                <div style="display:flex;align-items:center;gap:8px;color:#78350f;margin-bottom:8px">
                  <span style="color:#10b981;font-weight:700">✔</span>
                  <span style="font-size:14px;font-weight:600">More layouts</span>
                </div>
                <div style="display:flex;align-items:center;gap:8px;color:#78350f;margin-bottom:8px">
                  <span style="color:#10b981;font-weight:700">✔</span>
                  <span style="font-size:14px;font-weight:600">Better performance</span>
                </div>
                <div style="display:flex;align-items:center;gap:8px;color:#78350f">
                  <span style="color:#10b981;font-weight:700">✔</span>
                  <span style="font-size:14px;font-weight:600">Premium support</span>
                </div>
              </div>
              
              <!-- PRIMARY BUTTON (Affiliate) -->
              <button onclick="openLink('${safeUrl(heroAffUrl)}')"
                      style="width:100%;padding:16px;background:#f97316;border:none;border-radius:10px;color:white;font-size:16px;font-weight:700;cursor:pointer;box-shadow:0 4px 12px rgba(249,115,22,.3);margin-bottom:12px;transition:all .2s"
                      onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 6px 16px rgba(249,115,22,.4)'"
                      onmouseout="this.style.transform='';this.style.boxShadow='0 4px 12px rgba(249,115,22,.3)'">
                Upgrade to Professional Themes →
              </button>
              
              <!-- DOWNLOAD + DEMO SIDE BY SIDE -->
              <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
                <button onclick="downloadTheme('${id}')"
                        style="padding:14px;background:#3b82f6;border:none;border-radius:10px;color:white;font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(59,130,246,.2)">
                  ⬇ Download Free
                </button>
                ${t.demo_url ? `
                  <button onclick="openDemo('${id}')"
                          style="padding:14px;background:#ffffff;border:1.5px solid var(--wp-border);border-radius:10px;color:var(--wp-text);font-size:14px;font-weight:600;cursor:pointer">
                    👁 Live Demo
                  </button>
                ` : `<div></div>`}
              </div>
            </div>
          ` : `
            <!-- If no affiliate URL, just show download + demo -->
            <div style="display:grid;grid-template-columns:1fr${t.demo_url?' 1fr':''};gap:8px;margin-bottom:16px">
              <button onclick="downloadTheme('${id}')"
                      style="padding:16px;background:#3b82f6;border:none;border-radius:10px;color:white;font-size:16px;font-weight:700;cursor:pointer;box-shadow:0 2px 8px rgba(59,130,246,.2)">
                ⬇ Download Free
              </button>
              ${t.demo_url ? `
                <button onclick="openDemo('${id}')"
                        style="padding:16px;background:#ffffff;border:1.5px solid var(--wp-border);border-radius:10px;color:var(--wp-text);font-size:14px;font-weight:600;cursor:pointer">
                  👁 Live Demo
                </button>
              ` : ''}
            </div>
          `}
        </div>
      </div>
      
      <!-- BELOW THE FOLD SECTIONS -->
      
      <!-- ABOUT + PREMIUM CTA merged -->
      <div style="background:var(--wp-card);border:1px solid var(--wp-border);border-radius:16px;padding:32px;box-shadow:0 2px 12px rgba(0,0,0,.04);margin-bottom:32px">
        <h2 style="font-family:var(--font-head);font-size:24px;font-weight:700;margin:0 0 16px">About ${esc(t.name)}</h2>
        ${themeEnrich.introHtml}
        ${t.description ? `<div style="height:1px;background:var(--wp-border);margin:24px 0"></div><p style="color:var(--wp-text);line-height:1.7;margin:0;white-space:pre-line">${esc(t.description)}</p>` : ''}
        ${themeEnrich.detailsHtml}
        ${themeEnrich.faqHtml}
        ${midpageAffUrl ? `
          <div style="height:1px;background:var(--wp-border);margin:24px 0"></div>
          <div style="display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap">
            <div>
              <div style="font-size:15px;font-weight:700;color:var(--wp-text);margin-bottom:4px">Want more powerful features?</div>
              <div style="font-size:13px;color:var(--wp-muted)">Premium themes built for performance, flexibility, and professional results.</div>
            </div>
            <button onclick="openLink('${safeUrl(midpageAffUrl)}')"
                    style="flex-shrink:0;padding:11px 22px;background:#3b82f6;border:none;border-radius:10px;color:white;font-size:14px;font-weight:700;cursor:pointer;white-space:nowrap;transition:opacity .15s"
                    onmouseover="this.style.opacity='.85'" onmouseout="this.style.opacity='1'">
              View Premium Themes →
            </button>
          </div>
        ` : ''}
      </div>
      
      <!-- 4. MORE THEMES LIKE THIS -->
      <!-- 4. MORE THEMES (3 SECTIONS) -->
      <div style="margin-bottom:48px">
        
        <!-- SECTION 1: First 4 WPSkins Themes -->
        ${similar1.length > 0 ? `
          <h2 style="font-family:var(--font-head);font-size:28px;font-weight:800;margin:0 0 24px">More themes like this</h2>
          <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-bottom:48px">
            ${similar1.map(s=>`
              <div onclick="openTheme('${s.id}')" style="cursor:pointer;background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;overflow:hidden;transition:all .2s;box-shadow:0 2px 8px rgba(0,0,0,.04)"
                   onmouseover="this.style.transform='translateY(-4px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,.1)'"
                   onmouseout="this.style.transform='';this.style.boxShadow='0 2px 8px rgba(0,0,0,.04)'">
                ${s.screenshot_url 
                  ? `<img loading="lazy" decoding="async" src="${safeUrl(s.screenshot_url)}" alt="${escAttr(s.name)} – Free theme screenshot" style="width:100%;aspect-ratio:4/3;object-fit:cover;display:block" onerror="this.outerHTML='<div style=\\'width:100%;aspect-ratio:4/3;background:var(--wp-panel);display:flex;align-items:center;justify-content:center;font-size:32px;color:var(--wp-border)\\'>🎨</div>'">`
                  : `<div style="width:100%;aspect-ratio:4/3;background:var(--wp-panel);display:flex;align-items:center;justify-content:center;font-size:32px;color:var(--wp-border)">🎨</div>`
                }
                <div style="padding:12px">
                  <div style="font-weight:600;font-size:14px;color:var(--wp-text);margin-bottom:4px">${esc(s.name)}</div>
                  <div style="font-size:12px;color:var(--wp-muted)">Free</div>
                </div>
              </div>
            `).join('')}
          </div>
        ` : ''}
        
        <!-- SECTION 2: Premium Themes - blended naturally -->
        ${envatoUrl && envatoThemes.length > 0 ? `
          <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-bottom:48px">
            ${envatoThemes.map(e=>`
              <div onclick="openLink('${safeUrl(e.affiliate_url)}')" style="cursor:pointer;background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;overflow:hidden;transition:all .2s;box-shadow:0 2px 8px rgba(0,0,0,.04)"
                   onmouseover="this.style.transform='translateY(-4px)';this.style.boxShadow='0 8px 24px rgba(0,0,0,.1)'"
                   onmouseout="this.style.transform='';this.style.boxShadow='0 2px 8px rgba(0,0,0,.04)'">
                <img loading="lazy" decoding="async" src="${safeUrl(e.image_url)}" alt="${escAttr(e.name)} – Premium theme" style="width:100%;aspect-ratio:4/3;object-fit:cover;display:block">
                <div style="padding:12px">
                  <div style="font-weight:600;font-size:14px;color:var(--wp-text);margin-bottom:4px">${esc(e.name)}</div>
                  <div style="display:flex;align-items:center;justify-content:space-between">
                    <span style="font-size:12px;color:var(--wp-muted)">${esc(e.sales_text)} sales</span>
                    <span style="background:rgba(245,158,11,.12);color:#d97706;font-size:10px;font-weight:700;padding:2px 7px;border-radius:4px">Premium</span>
                  </div>
                </div>
              </div>
            `).join('')}
          </div>
        ` : ''}
        
      </div>
      
      <!-- BOTTOM FINAL CTA (LAST CHANCE) -->
      <div style="background:var(--wp-card);border:2px solid var(--wp-border);border-radius:16px;padding:40px;text-align:center;box-shadow:0 4px 20px rgba(0,0,0,.06)">
        <h2 style="font-family:var(--font-head);font-size:26px;font-weight:700;margin:0 0 24px;color:var(--wp-text)">Ready to build a better website?</h2>
        <div style="display:flex;gap:12px;max-width:${hostingUrl ? '720px' : '500px'};margin:0 auto 12px;flex-wrap:wrap">
          ${bottomAffUrl ? `
            <!-- PRIMARY: Premium (Orange) -->
            <button onclick="openLink('${safeUrl(bottomAffUrl)}')"
                    style="flex:1;min-width:180px;padding:18px;background:#f97316;border:none;border-radius:10px;color:white;font-size:16px;font-weight:700;cursor:pointer;box-shadow:0 4px 12px rgba(249,115,22,.3);transition:all .2s"
                    onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 6px 16px rgba(249,115,22,.4)'"
                    onmouseout="this.style.transform='';this.style.boxShadow='0 4px 12px rgba(249,115,22,.3)'">
              Upgrade to Professional Themes →
            </button>
          ` : ''}
          <!-- SECONDARY: Download (Blue) -->
          <button onclick="downloadTheme('${id}')"
                  style="flex:1;min-width:160px;padding:18px;background:#3b82f6;border:none;border-radius:10px;color:white;font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(59,130,246,.2)">
            Download Free
          </button>
          ${hostingUrl ? `
            <!-- TERTIARY: Hosting (Green) -->
            <button onclick="openLink('${safeUrl(hostingUrl)}')"
                    style="flex:1;min-width:200px;padding:18px;background:#10b981;border:none;border-radius:10px;color:white;font-size:14px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(16,185,129,.25);transition:all .2s;line-height:1.3"
                    onmouseover="this.style.transform='translateY(-2px)';this.style.boxShadow='0 6px 16px rgba(16,185,129,.35)'"
                    onmouseout="this.style.transform='';this.style.boxShadow='0 2px 8px rgba(16,185,129,.25)'">
              Get fast, reliable ${esc(PLATFORMS.find(p=>p.id===t.platform)?.name||'WordPress')} hosting →
            </button>
          ` : ''}
        </div>
        <div style="font-size:13px;color:var(--wp-muted)">${hostingUrl ? 'Launching your website? Start free, upgrade with premium, or get reliable hosting.' : 'Start free or unlock more with premium features'}</div>
        ${affiliateConfig.domain_url ? `
          <div style="margin-top:12px;padding:12px 16px;background:rgba(244,68,16,.06);border:1px solid rgba(244,68,16,.18);border-radius:8px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">
            <span style="font-size:13px;color:var(--wp-text)">🌐 Need a domain? Get one from Namecheap (from $5.98/yr)</span>
            <button onclick="openLink('${safeUrl(affiliateConfig.domain_url)}')" style="padding:8px 16px;background:#ff5000;border:none;border-radius:6px;color:white;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap">
              Browse Domains →
            </button>
          </div>
        ` : ''}
      </div>

    </div>
  `;

  // Inject FAQ structured data for this theme (helps rich results + adds unique signal)
  let faqScript = document.getElementById('seo-theme-faq');
  if (!faqScript) {
    faqScript = document.createElement('script');
    faqScript.type = 'application/ld+json';
    faqScript.id = 'seo-theme-faq';
    document.head.appendChild(faqScript);
  }
  faqScript.textContent = JSON.stringify(themeEnrich.faqJsonLd);
}

// Wrap a destination URL through the platform's affiliate template (if any).
// Template format: any string containing `{url}` — gets replaced with the
// URL-encoded destination. If template is empty or invalid, returns dest unchanged.
function wrapWithAffiliate(platform, dest) {
  if (!dest) return dest;
  const tmpl = platformAffiliatesMap?.[platform]?.download_url_template;
  if (!tmpl || typeof tmpl !== 'string' || !tmpl.includes('{url}')) return dest;
  // Skip templates that still contain placeholder text (e.g., YOUR_SHOPIFY_PARTNER_ID).
  // Prevents broken affiliate links going live until admin fills in real IDs.
  if (/YOUR_[A-Z_]+/.test(tmpl)) return dest;
  try {
    const wrapped = tmpl.replace('{url}', encodeURIComponent(dest));
    return isValidUrl(wrapped) ? wrapped : dest;
  } catch { return dest; }
}

async function downloadTheme(id) {
  // CRITICAL: open the popup SYNCHRONOUSLY (during the click event) so browsers
  // don't treat it as a programmatic open and block it. We'll set the real URL
  // after any async lookups complete.
  // Note: do NOT use 'noopener' here — it makes window.open() return null,
  // which prevents us from redirecting the popup. We null out .opener after.
  const popup = window.open('about:blank', '_blank');

  let theme = allThemes.find(t => t.id === id);
  let zipUrl   = theme && theme.zip_url;
  let demoUrl  = theme && theme.demo_url;
  let platform = theme && theme.platform;

  // Fallback: if cached record is lightweight (missing fields), refetch full row
  if ((zipUrl === undefined || demoUrl === undefined || !platform) && sb) {
    try {
      const { data } = await sb.from('themes').select('zip_url, demo_url, platform').eq('id', id).single();
      if (data) {
        if (zipUrl  === undefined) zipUrl  = data.zip_url;
        if (demoUrl === undefined) demoUrl = data.demo_url;
        platform = platform || data.platform;
        if (theme) { theme.zip_url = data.zip_url; theme.demo_url = data.demo_url; theme.platform = data.platform; }
      }
    } catch (e) { /* fall through */ }
  }

  // Pick destination: WP keeps direct zip; others prefer zip then demo
  let dest = null;
  let toastMsg = '';
  let toastKind = 'success';
  if (platform === 'wordpress' && zipUrl && isValidUrl(zipUrl)) {
    dest = zipUrl; toastMsg = 'Download starting!'; toastKind = 'success';
  } else if (zipUrl && isValidUrl(zipUrl)) {
    dest = zipUrl; toastMsg = 'Download starting!'; toastKind = 'success';
  } else if (demoUrl && isValidUrl(demoUrl)) {
    dest = demoUrl;
  }

  if (!dest) {
    if (popup) popup.close();
    toast('No download URL set for this theme', 'error');
    return;
  }

  const finalUrl = wrapWithAffiliate(platform, dest);
  if (!toastMsg) {
    toastMsg  = (finalUrl !== dest) ? 'Opening theme — affiliate link' : 'Opening theme source';
    toastKind = 'info';
  }

  // Track download click (and the affiliate brand if the URL was wrapped)
  trackEvent('download_click', {
    theme_id: id,
    platform,
    affiliate_target: _affiliateBrand(finalUrl) || (finalUrl !== dest ? 'wrapped' : null),
  });

  // Redirect the pre-opened popup. If popup was blocked, fall back.
  if (popup && !popup.closed) {
    try {
      popup.location.href = finalUrl;
      try { popup.opener = null; } catch {} // null out opener for security (post-nav)
    } catch {
      window.open(finalUrl, '_blank', 'noopener,noreferrer');
    }
  } else {
    window.open(finalUrl, '_blank', 'noopener,noreferrer');
  }
  toast(toastMsg, toastKind);
}

function copyLink(id) {
  const url = window.location.href.split('?')[0]+'?theme='+id;
  navigator.clipboard.writeText(url).then(()=>toast('Link copied!','success')).catch(()=>toast('URL: '+url,'info'));
}

// ── Submit ─────────────────────────────────────────────────
function validateUrl(inputId, msgId) {
  const val = document.getElementById(inputId).value.trim();
  const msg = document.getElementById(msgId);
  if (!val) { msg.textContent=''; return; }
  try { new URL(val); msg.textContent='✓ Valid URL'; msg.className='validate-msg ok'; }
  catch { msg.textContent='⚠ Enter a valid URL'; msg.className='validate-msg err'; }
}
function previewScreenshot() {
  const url = document.getElementById('s-screenshot').value.trim();
  const wrap = document.getElementById('screenshot-preview');
  const img  = document.getElementById('screenshot-img');
  if (url) { try { new URL(url); img.src=url; wrap.style.display='block'; } catch { wrap.style.display='none'; } }
  else wrap.style.display='none';
}
function getCheckedColors(cls) {
  return Array.from(document.querySelectorAll('.'+cls+':checked')).map(c=>c.value);
}


// ── Dashboard ──────────────────────────────────────────────

// ── Admin ──────────────────────────────────────────────────
// Admin action functions




// ── Modal ──────────────────────────────────────────────────
function showConfirmModal(title, body, confirmLabel, type, cb) {
  document.getElementById('modal-title').textContent = title;
  document.getElementById('modal-body').textContent  = body;
  const btn = document.getElementById('modal-confirm-btn');
  btn.textContent = confirmLabel;
  btn.className = 'confirm' + (type==='danger'?' ':'ok');
  btn.style.background = type==='danger'?'var(--wp-red)':'var(--wp-green)';
  modalCallback = cb;
  document.getElementById('modal').classList.add('open');
}
function closeModal() { document.getElementById('modal').classList.remove('open'); modalCallback=null; }
function modalAction() { if(modalCallback)modalCallback(); closeModal(); }

// ── Toast ──────────────────────────────────────────────────
function toast(msg, type='info') {
  const c = document.getElementById('toast');
  const el = document.createElement('div');
  el.className = 'toast-item '+type;
  el.textContent = msg;
  c.appendChild(el);
  setTimeout(()=>el.remove(), 3500);
}

// ── Helpers ────────────────────────────────────────────────
function v(id) { const el=document.getElementById(id); return el?el.value.trim():''; }
function esc(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
function escAttr(s) { return String(s||'').replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/'/g,'&#39;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
function safeUrl(url) {
  if (!url) return '#';
  try {
    const u = new URL(url, window.location.origin);
    return (u.protocol === 'http:' || u.protocol === 'https:') ? escAttr(url) : '#';
  } catch { return '#'; }
}
function isValidUrl(url) {
  if (!url) return false;
  try {
    const u = new URL(url);
    return u.protocol === 'http:' || u.protocol === 'https:';
  } catch { return false; }
}
function openLink(url) {
  if (!url || url === '#') return;
  try {
    const u = new URL(url);
    if (u.protocol !== 'http:' && u.protocol !== 'https:') return;
    // Track affiliate clicks (only if URL matches a known affiliate brand)
    const brand = _affiliateBrand(url);
    if (brand) trackEvent('affiliate_click', { affiliate_target: brand });
    window.open(url,'_blank','noopener,noreferrer');
  } catch {}
}

// Sync-safe demo opener: looks up demo_url by theme id, so we don't need to
// inline (and escape) URLs inside HTML attributes. Called from inline onclick.
async function openDemo(id) {
  // Open popup synchronously so it isn't blocked. NOT 'noopener' — that makes
  // window.open() return null and we lose the reference needed for redirect.
  const popup = window.open('about:blank', '_blank');
  let theme = allThemes.find(t => t.id === id);
  let url = theme && theme.demo_url;
  // Track demo click
  trackEvent('demo_click', { theme_id: id, platform: theme && theme.platform });
  if (url === undefined && sb) {
    try {
      const { data } = await sb.from('themes').select('demo_url').eq('id', id).single();
      url = data?.demo_url;
      if (theme) theme.demo_url = url;
    } catch (e) {}
  }
  if (!url || !isValidUrl(url)) {
    if (popup) popup.close();
    toast('No demo available for this theme', 'error');
    return;
  }
  if (popup && !popup.closed) {
    try {
      popup.location.href = url;
      try { popup.opener = null; } catch {}
    } catch {
      window.open(url, '_blank', 'noopener,noreferrer');
    }
  } else {
    window.open(url, '_blank', 'noopener,noreferrer');
  }
}
function setBusy(id, busy, label) {
  const el=document.getElementById(id);
  if(!el)return;
  el.disabled=busy;
  el.textContent=label;
}
function timeAgo(ts) {
  const s=Math.floor((Date.now()-new Date(ts))/1000);
  if(s<60)return 'just now';
  if(s<3600)return Math.floor(s/60)+'m ago';
  if(s<86400)return Math.floor(s/3600)+'h ago';
  return Math.floor(s/86400)+'d ago';
}

// ── SEO: dynamic <head> update ─────────────────────────────
const SITE = 'https://wpskins.org';
const SITE_NAME = 'WPSkins.org';
const DEFAULT_DESC = 'Browse 2,500+ free website themes for WordPress, Shopify, Webflow, Framer, Ghost, Hugo, Astro, Gatsby, Nuxt, and more. Beautiful, responsive, and ready to use.';
const DEFAULT_IMG = SITE + '/og-image.png';

function setMeta(sel, attr, val) {
  let el = document.querySelector(sel);
  if (el) el.setAttribute(attr, val);
}

// ── SEO content blocks (visible on platform/category pages) ──────────────
function renderSeoIntro(opts) {
  const { heading, html } = opts || {};
  // We're on a non-theme page (home/platform/category), so drop any stale theme FAQ schema
  document.getElementById('seo-theme-faq')?.remove();
  const el = document.getElementById('seo-intro');
  const hero = document.querySelector('.hero');
  const heroH1 = hero ? hero.querySelector('h1') : null;
  if (!el) return;
  if (!heading && !html) {
    el.innerHTML = ''; el.style.display = 'none';
    // Restore hero h1 on the home page so we have an h1
    if (hero) hero.style.display = '';
    if (heroH1) { heroH1.style.display = ''; }
    return;
  }
  // On filtered/platform/category pages: hide hero so seo-intro h1 is the only h1
  if (hero) hero.style.display = 'none';
  el.style.display = 'block';
  el.innerHTML = `
    <div style="background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;padding:24px;margin-bottom:24px">
      ${heading ? `<h1 style="font-family:var(--font-head);font-size:28px;font-weight:700;margin:0 0 12px;color:var(--wp-text)">${heading}</h1>` : ''}
      ${html ? `<div style="color:var(--wp-text);line-height:1.7">${html}</div>` : ''}
    </div>
  `;
}

function renderFAQ(faqItems) {
  const el = document.getElementById('seo-faq');
  if (!el) return;
  if (!faqItems || !faqItems.length) { el.innerHTML = ''; el.style.display = 'none'; return; }
  el.style.display = 'block';
  el.innerHTML = `
    <div style="background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;padding:24px;margin-top:48px">
      <h2 style="font-family:var(--font-head);font-size:24px;font-weight:700;margin:0 0 16px;color:var(--wp-text)">Frequently asked questions</h2>
      ${faqItems.map((item, i) => `
        <details style="border-bottom:1px solid var(--wp-border);padding:14px 0" ${i === 0 ? 'open' : ''}>
          <summary style="font-weight:600;cursor:pointer;color:var(--wp-text);list-style:none;display:flex;justify-content:space-between;align-items:center">
            <span>${esc(item.q)}</span>
            <span style="color:var(--wp-muted);font-weight:400;margin-left:12px">+</span>
          </summary>
          <div style="color:var(--wp-text);line-height:1.7;padding:12px 0 0;opacity:.9">${esc(item.a)}</div>
        </details>
      `).join('')}
    </div>
  `;
}

function escFaqJson(faqItems) {
  return {
    '@context': 'https://schema.org',
    '@type': 'FAQPage',
    'mainEntity': faqItems.map(item => ({
      '@type': 'Question',
      'name': item.q,
      'acceptedAnswer': { '@type': 'Answer', 'text': item.a }
    }))
  };
}

function updateSEO({ title, description, image, canonical, jsonld, jsonldExtra, breadcrumbs, ogType } = {}) {
  const fullTitle = title ? `${title} | ${SITE_NAME}` : `${SITE_NAME} – Free Website Themes for WordPress, Shopify, Webflow, Astro & More`;
  const desc = description || DEFAULT_DESC;
  const img  = image || DEFAULT_IMG;
  const url  = canonical ? SITE + canonical : SITE + '/';

  // <title>
  document.title = fullTitle;

  // Canonical
  let can = document.querySelector('link[rel="canonical"]');
  if (!can) { can = document.createElement('link'); can.rel = 'canonical'; document.head.appendChild(can); }
  can.href = url;

  // Meta description
  setMeta('meta[name="description"]', 'content', desc);

  // Ensure robots is indexable (404 handler may have set noindex)
  setMeta('meta[name="robots"]', 'content', 'index, follow, max-snippet:-1, max-image-preview:large');

  // OG
  setMeta('meta[property="og:type"]',        'content', ogType || 'website');
  setMeta('meta[property="og:title"]',       'content', fullTitle);
  setMeta('meta[property="og:description"]', 'content', desc);
  setMeta('meta[property="og:url"]',         'content', url);
  setMeta('meta[property="og:image"]',       'content', img);
  setMeta('meta[property="og:image:alt"]',   'content', title || SITE_NAME);

  // Twitter
  setMeta('meta[name="twitter:title"]',       'content', fullTitle);
  setMeta('meta[name="twitter:description"]', 'content', desc);
  setMeta('meta[name="twitter:image"]',       'content', img);

  // Primary JSON-LD (theme / page entity)
  if (jsonld) {
    let existing = document.getElementById('seo-jsonld-dynamic');
    if (!existing) {
      existing = document.createElement('script');
      existing.type = 'application/ld+json';
      existing.id = 'seo-jsonld-dynamic';
      document.head.appendChild(existing);
    }
    existing.textContent = JSON.stringify(jsonld);
  } else {
    document.getElementById('seo-jsonld-dynamic')?.remove();
  }

  // Extra JSON-LD (FAQ etc.)
  if (jsonldExtra) {
    let extra = document.getElementById('seo-jsonld-extra');
    if (!extra) {
      extra = document.createElement('script');
      extra.type = 'application/ld+json';
      extra.id = 'seo-jsonld-extra';
      document.head.appendChild(extra);
    }
    extra.textContent = JSON.stringify(jsonldExtra);
  } else {
    document.getElementById('seo-jsonld-extra')?.remove();
  }

  // Breadcrumb JSON-LD (separate block, easier to manage)
  if (breadcrumbs && breadcrumbs.length) {
    let bc = document.getElementById('seo-breadcrumbs');
    if (!bc) {
      bc = document.createElement('script');
      bc.type = 'application/ld+json';
      bc.id = 'seo-breadcrumbs';
      document.head.appendChild(bc);
    }
    bc.textContent = JSON.stringify({
      '@context': 'https://schema.org',
      '@type': 'BreadcrumbList',
      'itemListElement': breadcrumbs.map((b, i) => ({
        '@type': 'ListItem',
        'position': i + 1,
        'name': b.name,
        'item': SITE + b.path
      }))
    });
  } else {
    document.getElementById('seo-breadcrumbs')?.remove();
  }
}

function checkDeepLink() {
  const path = window.location.pathname || '/';
  const params = new URLSearchParams(window.location.search);
  
  // Handle query params (?theme=ID) — validate UUID format before using
  const tid = params.get('theme');
  if (tid && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(tid)) {
    currentThemeId = tid;
    showPage('detail');
    return;
  }
  
  // Platform only: /wordpress, /shopify, /astro, /nuxt, etc. — dynamic, covers all platforms
  const _platformOnly = PLATFORMS.find(p => path === '/' + p.id);
  if (_platformOnly) {
    const platform = _platformOnly.id;
    const platformName = _platformOnly.name;
    const count = allThemes.filter(t => t.platform === platform).length;
    filters.platform = platform;
    filters.category = '';
    applyFilters();
    buildPlatformList();
    buildCategoryList();
    const seo = PLATFORM_SEO[platform];
    updateSEO({
      title: `Free ${platformName} Themes`,
      description: `Browse ${count}+ free ${platformName} themes. Responsive, customizable, and ready to download — all completely free.`,
      canonical: path,
      breadcrumbs: [
        { name: 'Home', path: '/' },
        { name: `Free ${platformName} Themes`, path }
      ],
      jsonldExtra: seo ? escFaqJson(seo.faq) : null
    });
    showPage('home');
    renderSeoIntro(seo ? { heading: `Free ${platformName} Themes`, html: seo.intro } : null);
    renderFAQ(seo ? seo.faq : null);
    return;
  }

  // Platform + Category: /wordpress/corporate-themes, /astro/blog-magazine, etc. — all platforms
  const _platformIds = PLATFORMS.map(p => p.id).join('|');
  const platformCategoryMatch = path.match(new RegExp('^\/(' + _platformIds + ')\/([a-z0-9-]+)$'));
  if (platformCategoryMatch) {
    const platform = platformCategoryMatch[1];
    const categorySlug = platformCategoryMatch[2];
    const category = SLUG_TO_CATEGORY[categorySlug];
    
    if (category) {
      const platformName = PLATFORMS.find(p => p.id === platform)?.name || platform;
      const count = allThemes.filter(t => t.platform === platform && getThemeCategories(t).includes(category)).length;
      // Empty platform+category combo = soft 404. Return real 404.
      if (count === 0) return show404(path);
      filters.platform = platform;
      filters.category = category;
      applyFilters();
      buildPlatformList();
      buildCategoryList();
      updateSEO({
        title: `Free ${category} ${platformName} Themes`,
        description: `Download ${count}+ free ${category} ${platformName} themes. All themes are free, responsive, and easy to customize.`,
        canonical: path,
        breadcrumbs: [
          { name: 'Home', path: '/' },
          { name: `Free ${platformName} Themes`, path: `/${platform}` },
          { name: category, path }
        ],
        jsonldExtra: escFaqJson(GENERIC_CATEGORY_FAQ)
      });
      showPage('home');
      renderSeoIntro({
        heading: `Free ${category} ${platformName} Themes`,
        html: `<p>Discover <strong>free ${category.toLowerCase()} themes for ${platformName}</strong> — every theme below is professionally designed and 100% free to download. ${category} ${platformName} themes are built specifically for ${category.toLowerCase()} websites, with layouts and features tailored to that use case.</p>
<p>Whether you're launching a new ${category.toLowerCase()} site or rebuilding an existing one, these free ${platformName} themes give you a professional starting point. All themes are responsive, mobile-optimized, and ready to customize.</p>`
      });
      renderFAQ(GENERIC_CATEGORY_FAQ);
      return;
    }
  }
  
  // Theme detail: /wordpress/theme/slug, /astro/theme/slug, etc. — all platforms
  const themeMatch = path.match(new RegExp('^\/(' + _platformIds + ')\/theme\/([a-z0-9-]+)$'));
  if (themeMatch) {
    const slug = themeMatch[2];
    const theme = allThemes.find(t => t.slug === slug);
    if (theme) {
      openTheme(theme.id);
      return;
    }
    // Theme slug doesn't exist — 404
    return show404(path);
  }
  
  // Themes index page: /themes (HTML directory of all categories & combos)
  if (path === '/themes' || path === '/themes/') {
    renderThemesIndex();
    return;
  }
  
  // Cross-platform category page: /themes/business, /themes/portfolio, etc.
  const categoryOnlyMatch = path.match(/^\/themes\/([a-z0-9-]+)\/?$/);
  if (categoryOnlyMatch) {
    const categorySlug = categoryOnlyMatch[1];
    const category = SLUG_TO_CATEGORY[categorySlug];
    if (category) {
      const count = allThemes.filter(t => getThemeCategories(t).includes(category)).length;
      // Empty category page = soft 404. Return real 404 instead so Google de-indexes it.
      if (count === 0) return show404(path);
      filters.platform = '';
      filters.category = category;
      applyFilters();
      buildPlatformList();
      buildCategoryList();
      updateSEO({
        title: `Free ${category} Website Themes`,
        description: `Download ${count}+ free ${category} website themes for WordPress, Shopify, Webflow, Astro, Ghost, Hugo, and more. All themes are free and responsive.`,
        canonical: path,
        breadcrumbs: [
          { name: 'Home', path: '/' },
          { name: `${category} Themes`, path }
        ],
        jsonldExtra: escFaqJson(GENERIC_CATEGORY_FAQ)
      });
      showPage('home');
      renderSeoIntro({
        heading: `Free ${category} Website Themes`,
        html: `<p>Browse our curated collection of <strong>free ${category.toLowerCase()} themes</strong> for WordPress, Shopify, Webflow, Astro, Ghost, Hugo, Gatsby, Nuxt, and more. Every theme below is professionally designed, fully responsive, and 100% free to download — no signups, no email walls, no hidden fees.</p>
<p>${category} themes are designed specifically for ${category.toLowerCase()}-focused websites, with layouts, color schemes, and features tailored to that use case. Whether you're a freelancer, agency, or just starting out, you'll find a free ${category.toLowerCase()} theme here that gives you a professional starting point.</p>`
      });
      renderFAQ(GENERIC_CATEGORY_FAQ);
      return;
    }
    // Unknown category slug — 404
    return show404(path);
  }
  
  // About & Contact are static HTML files — full page load (SEO-friendly)
  if (path === '/about' || path === '/about/') {
    window.location.href = '/about';
    return;
  }
  if (path === '/contact' || path === '/contact/') {
    window.location.href = '/contact';
    return;
  }
  
  // Default: if path is root, show home page
  if (path === '/' || path === '') {
    showPage('home');
    return;
  }
  
  // Unknown path — 404
  show404(path);
}


// ── /themes — HTML directory page with all categories & combos ────────────
function renderThemesIndex() {
  filters.platform = '';
  filters.category = '';
  
  const platformCounts = PLATFORMS.map(p => ({
    ...p,
    count: allThemes.filter(t => t.platform === p.id).length
  }));
  
  const allCatsSet = new Set();
  allThemes.forEach(t => getThemeCategories(t).forEach(c => allCatsSet.add(c)));
  const categoryCounts = Array.from(allCatsSet).map(cat => ({
    name: cat,
    slug: CATEGORY_SLUGS[cat] || cat.toLowerCase().replace(/\s+/g,'-'),
    count: allThemes.filter(t => getThemeCategories(t).includes(cat)).length
  })).sort((a,b) => b.count - a.count);
  
  const wrap = document.getElementById('themes-grid-wrap');
  if (wrap) {
    wrap.innerHTML = `
      <div style="background:var(--wp-card);border:1px solid var(--wp-border);border-radius:12px;padding:32px;margin-bottom:24px">
        <h2 style="font-family:var(--font-head);font-size:22px;font-weight:700;margin:0 0 16px;color:var(--wp-text)">Browse by Platform</h2>
        <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px;margin-bottom:32px">
          ${platformCounts.map(p => `
            <a href="/${p.id}" onclick="event.preventDefault();window.history.pushState({},'','/${p.id}');checkDeepLink();return false"
               style="display:block;padding:12px 10px;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:10px;text-decoration:none;color:var(--wp-text);transition:all .15s;text-align:center"
               onmouseover="this.style.borderColor='var(--wp-accent)';this.style.transform='translateY(-2px)'"
               onmouseout="this.style.borderColor='var(--wp-border)';this.style.transform=''">
              <div style="font-size:22px;margin-bottom:4px">${p.emoji}</div>
              <div style="font-weight:600;font-size:13px;color:var(--wp-text)">${esc(p.name)}</div>
              <div style="font-size:11px;color:var(--wp-muted);margin-top:2px">${p.count} themes</div>
            </a>
          `).join('')}
        </div>
        
        <h2 style="font-family:var(--font-head);font-size:22px;font-weight:700;margin:24px 0 16px;color:var(--wp-text)">Browse by Category</h2>
        <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px;margin-bottom:32px">
          ${categoryCounts.map(c => `
            <a href="/themes/${c.slug}" onclick="event.preventDefault();window.history.pushState({},'','/themes/${c.slug}');checkDeepLink();return false"
               style="display:flex;justify-content:space-between;align-items:center;padding:10px 14px;background:var(--wp-panel);border:1px solid var(--wp-border);border-radius:8px;text-decoration:none;color:var(--wp-text);font-size:14px;transition:all .15s"
               onmouseover="this.style.borderColor='var(--wp-accent)'"
               onmouseout="this.style.borderColor='var(--wp-border)'">
              <span>${esc(c.name)}</span>
              <span style="color:var(--wp-muted);font-size:12px">${c.count}</span>
            </a>
          `).join('')}
        </div>
        
        <h2 style="font-family:var(--font-head);font-size:22px;font-weight:700;margin:24px 0 16px;color:var(--wp-text)">Platform + Category</h2>
        <p style="color:var(--wp-muted);font-size:14px;margin-bottom:16px">Looking for something specific? Browse by platform and category combo:</p>
        <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:6px">
          ${PLATFORMS.flatMap(p => 
            categoryCounts.map(c => ({ p, c, count: allThemes.filter(t => t.platform === p.id && getThemeCategories(t).includes(c.name)).length }))
          ).filter(x => x.count > 0).map(({p, c, count}) => `
            <a href="/${p.id}/${c.slug}" onclick="event.preventDefault();window.history.pushState({},'','/${p.id}/${c.slug}');checkDeepLink();return false"
               style="display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:var(--wp-card);border:1px solid var(--wp-border);border-radius:6px;text-decoration:none;color:var(--wp-text);font-size:13px;transition:all .15s"
               onmouseover="this.style.background='var(--wp-panel)'"
               onmouseout="this.style.background='var(--wp-card)'">
              <span>${p.emoji} ${esc(c.name)} ${esc(p.name)}</span>
              <span style="color:var(--wp-muted);font-size:11px">${count}</span>
            </a>
          `).join('')}
        </div>
      </div>`;
  }
  
  document.getElementById('themes-count').textContent = '';
  
  updateSEO({
    title: 'All Free Themes — Browse by Platform & Category',
    description: 'Complete directory of free website themes. Browse by platform (WordPress, Shopify, Webflow, Astro, Ghost, Hugo, Gatsby, Nuxt, and more) or category (business, portfolio, eCommerce, blog, and more).',
    canonical: '/themes',
    breadcrumbs: [
      { name: 'Home', path: '/' },
      { name: 'All Themes', path: '/themes' }
    ]
  });
  renderSeoIntro({
    heading: 'All Free Themes — Complete Directory',
    html: `<p>Welcome to the complete <strong>WPSkins.org theme directory</strong>. Browse 2,500+ free website themes organized by platform and category. Every theme is professionally designed, fully responsive, and 100% free to download — no subscriptions, no email walls, no hidden fees.</p>
<p>Use the sections below to find themes by platform (WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more), by category (business, portfolio, eCommerce, and more), or by specific combinations like "Free WordPress eCommerce themes" or "Free Astro blog themes."</p>`
  });
  renderFAQ(null);
  showPage('home');
}

function show404(path) {
  updateSEO({
    title: '404 – Page Not Found',
    description: 'The page you are looking for does not exist. Browse our collection of free themes instead.',
    canonical: path
  });
  // Add noindex for 404 pages
  let robots = document.querySelector('meta[name="robots"]');
  if (robots) robots.setAttribute('content', 'noindex, follow');
  // Also clear any prior SEO intro/FAQ so 404 doesn't inherit them
  if (typeof renderSeoIntro === 'function') renderSeoIntro(null);
  if (typeof renderFAQ === 'function') renderFAQ(null);
  
  // Render 404 content
  const page = document.getElementById('page-home');
  if (page) {
    const wrap = document.getElementById('themes-grid-wrap');
    if (wrap) {
      wrap.innerHTML = `
        <div style="text-align:center;padding:80px 24px;max-width:600px;margin:0 auto">
          <div style="font-size:72px;font-weight:800;color:var(--wp-muted);margin-bottom:16px">404</div>
          <h1 style="font-family:var(--font-head);font-size:28px;margin-bottom:12px">Page not found</h1>
          <p style="color:var(--wp-muted);margin-bottom:24px">The page "<code>${path.replace(/[<>&"']/g, '')}</code>" doesn't exist. It may have been moved or the link is incorrect.</p>
          <a href="/" class="nav-btn" style="display:inline-block;text-decoration:none">← Back to homepage</a>
        </div>`;
    }
    document.getElementById('themes-count').textContent = '';
    showPage('home');
  }
}

// ── Boot ───────────────────────────────────────────────────
buildColorSwatches();
buildColorPickers();

// 1. Render cached themes IMMEDIATELY (synchronous, microseconds).
//    Themes are public — no auth needed for read.
const _cached = readCache();
if (_cached && _cached.length > 0) {
  applyThemesAndRender(_cached);
}

// 2. Kick off all async work in parallel — none of these block each other.
const _authPromise   = initAuth();
const _affPromise    = loadAffiliateConfig();
const _themesPromise = fetchAllThemes()
  .then(fresh => {
    writeCache(fresh);
    const changed = !_cached
      || fresh.length !== _cached.length
      || fresh[0]?.id !== _cached[0]?.id;
    if (changed) applyThemesAndRender(fresh);
  })
  .catch(e => {
    console.warn('Theme fetch failed:', e);
    if (!_cached) {
      const w = document.getElementById('themes-grid-wrap');
      if (w) w.innerHTML = '<div class="empty"><div class="icon">⚠</div><p>Error loading themes</p></div>';
    }
  });

// 3. Route as soon as we have themes (or immediately if cache hit).
//    Wait for affiliateConfig too so detail pages render with correct affiliate URLs.
const _themesReady = (_cached && _cached.length > 0)
  ? Promise.resolve()
  : _themesPromise;
Promise.all([_themesReady, _affPromise.catch(() => {})]).then(() => {
    checkDeepLink();
    if (!window.location.search && !window.location.hash
        && window.location.pathname === '/') {
      showPage('home');
    }
  });
</script>

<!-- ── FOOTER ─────────────────────────────────────────────────── -->
<footer style="background:var(--wp-panel);border-top:1px solid var(--wp-border);padding:48px 24px 32px;margin-top:40px">
  <div style="max-width:1280px;margin:0 auto">
    <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:32px;margin-bottom:40px">

      <div>
        <div style="font-family:var(--font-head);font-weight:800;font-size:18px;margin-bottom:12px">WP<span style="color:var(--wp-accent)">Skins</span>.org</div>
        <p style="font-size:13px;color:var(--wp-muted);line-height:1.7">Free website themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro, Gatsby, Nuxt, and more. 2,500+ themes, community-powered, 100% free.</p>
      </div>

      <div>
        <div style="font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px">Platforms</div>
        <ul style="list-style:none;display:flex;flex-direction:column;gap:8px">
          <li><a href="/wordpress"   style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">📝 WordPress Themes</a></li>
          <li><a href="/shopify"     style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🛒 Shopify Themes</a></li>
          <li><a href="/webflow"     style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🎨 Webflow Themes</a></li>
          <li><a href="/framer"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">⚡ Framer Themes</a></li>
          <li><a href="/ghost"       style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">👻 Ghost Themes</a></li>
          <li><a href="/hugo"        style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🦉 Hugo Themes</a></li>
          <li><a href="/jekyll"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">💎 Jekyll Themes</a></li>
          <li><a href="/astro"       style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🚀 Astro Themes</a></li>
          <li><a href="/eleventy"    style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🕚 Eleventy Themes</a></li>
          <li><a href="/joomla"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🔶 Joomla Themes</a></li>
          <li><a href="/drupal"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">💧 Drupal Themes</a></li>
          <li><a href="/bigcommerce" style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">🛍 BigCommerce Themes</a></li>
          <li><a href="/gatsby"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">💜 Gatsby Themes</a></li>
          <li><a href="/nuxt"        style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">💚 Nuxt Themes</a></li>
          <li><a href="/next"        style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">▲ Next.js Themes</a></li>
        </ul>
      </div>

      <div>
        <div style="font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px">Categories</div>
        <ul style="list-style:none;display:flex;flex-direction:column;gap:8px">
          <li><a href="/themes/corporate"    style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Corporate Themes</a></li>
          <li><a href="/themes/ecommerce"    style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">eCommerce Themes</a></li>
          <li><a href="/themes/portfolio"    style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Portfolio Themes</a></li>
          <li><a href="/themes/blog-magazine" style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Blog &amp; Magazine Themes</a></li>
          <li><a href="/themes/creative"     style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Creative Themes</a></li>
          <li><a href="/themes"              style="font-size:13px;color:var(--wp-accent);text-decoration:none;font-weight:600">Browse all categories →</a></li>
        </ul>
      </div>

      <div>
        <div style="font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px">Popular</div>
        <ul style="list-style:none;display:flex;flex-direction:column;gap:8px">
          <li><a href="/wordpress/corporate"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">WordPress Corporate</a></li>
          <li><a href="/wordpress/ecommerce"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">WordPress eCommerce</a></li>
          <li><a href="/shopify/retail"           style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Shopify Retail</a></li>
          <li><a href="/webflow/portfolio"        style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Webflow Portfolio</a></li>
          <li><a href="/framer/creative"          style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Framer Creative</a></li>
          <li><a href="/ghost/blog-magazine"      style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Ghost Blog Themes</a></li>
          <li><a href="/hugo/portfolio"           style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Hugo Portfolio</a></li>
          <li><a href="/gatsby/blog-magazine"     style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Gatsby Blog Themes</a></li>
          <li><a href="/drupal/corporate"         style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Drupal Corporate</a></li>
          <li><a href="/joomla/corporate"         style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Joomla Corporate</a></li>
          <li><a href="/next/blog-magazine"       style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Next.js Blog Themes</a></li>
          <li><a href="/next/portfolio"           style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Next.js Portfolio</a></li>
        </ul>
      </div>

      <div>
        <div style="font-size:11px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--wp-muted);margin-bottom:12px">Site</div>
        <ul style="list-style:none;display:flex;flex-direction:column;gap:8px">
          <li><a href="/about"     style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">About</a></li>
          <li><a href="/contact"   style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Contact</a></li>
          <li><a href="/resources" style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Resources</a></li>
          <li><a href="/submit"    style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Submit a Theme</a></li>
          <li><a href="/sitemap.xml" style="font-size:13px;color:var(--wp-text);text-decoration:none" onmouseover="this.style.color='var(--wp-accent)'" onmouseout="this.style.color='var(--wp-text)'">Sitemap</a></li>
        </ul>
      </div>

    </div>
    <div style="border-top:1px solid var(--wp-border);padding-top:24px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px">
      <p style="font-size:12px;color:var(--wp-muted)">© 2026 WPSkins.org — Free themes for WordPress, Shopify, Webflow, Ghost, Hugo, Astro &amp; more.</p>
      <p style="font-size:12px;color:var(--wp-muted)">We don't host themes — links go to the original developers.</p>
    </div>
  </div>
</footer>

</body>
</html>
