2
0
Files
gitcaddy-server/templates/pages/cli-terminal.tmpl
logikonline c5e35e3466 refactor(pages): move app store badges to hero section and add section IDs
Move Google Play and App Store badges from downloads section to hero section for better visibility. Removes redundant display when both downloads and app stores are present. Add id attributes to major sections (hero, stats, downloads, social-proof, cta, etc.) for anchor link navigation. Applies to all 9 page templates. Improves UX for mobile app landing pages.
2026-03-17 03:25:14 -04:00

1594 lines
48 KiB
Handlebars

{{template "pages/base_head" .}}
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
:root {
--ct-bg: #0a0e14;
--ct-surface: #0f1923;
--ct-elevated: #162030;
--ct-text: #c5cdd8;
--ct-muted: #5c6a78;
--ct-dim: #1e2d3d;
--ct-primary: {{if .Config.Theme.PrimaryColor}}{{.Config.Theme.PrimaryColor}}{{else}}#39ff14{{end}};
--ct-secondary: {{if .Config.Theme.AccentColor}}{{.Config.Theme.AccentColor}}{{else}}#ffb627{{end}};
--ct-glow: rgba(57, 255, 20, 0.15);
--ct-glow-strong: rgba(57, 255, 20, 0.4);
}
html {
scroll-behavior: smooth;
}
html, body.pages-body {
overflow-x: hidden;
background: var(--ct-bg) !important;
}
/* Scanline overlay */
.ct-page::before {
content: "";
position: fixed;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.04) 2px,
rgba(0, 0, 0, 0.04) 4px
);
pointer-events: none;
z-index: 9999;
}
.ct-page {
position: relative;
min-height: 100vh;
background: var(--ct-bg);
color: var(--ct-text);
font-family: 'Space Mono', monospace;
-webkit-font-smoothing: antialiased;
}
/* Reveal animation system */
.ct-reveal {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.ct-reveal.visible {
opacity: 1;
transform: translateY(0);
}
.ct-reveal-delay-1 { transition-delay: 0.08s; }
.ct-reveal-delay-2 { transition-delay: 0.16s; }
.ct-reveal-delay-3 { transition-delay: 0.24s; }
.ct-reveal-delay-4 { transition-delay: 0.32s; }
/* Blink cursor animation */
@keyframes ct-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
/* CRT vignette on hero */
.ct-hero-vignette {
position: absolute;
inset: 0;
background: radial-gradient(ellipse at center, transparent 50%, rgba(10, 14, 20, 0.8) 100%);
pointer-events: none;
z-index: 1;
}
/* Hero phosphor glow */
.ct-hero-glow {
position: absolute;
top: -30%;
left: 50%;
transform: translateX(-50%);
width: 120%;
height: 80%;
background: radial-gradient(ellipse at center, var(--ct-glow) 0%, transparent 60%);
pointer-events: none;
}
/* Navigation */
.ct-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 0 40px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(10, 14, 20, 0.92);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid var(--ct-dim);
z-index: 100;
}
.ct-nav-brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: var(--ct-primary);
}
.ct-nav-logo {
width: 28px;
height: 28px;
background: var(--ct-bg);
border: 1px solid var(--ct-primary);
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ct-primary);
box-shadow: 0 0 8px var(--ct-glow);
}
.ct-nav-name {
font-weight: 700;
font-size: 14px;
letter-spacing: 0.05em;
}
.ct-nav-name::before {
content: ">_ ";
color: var(--ct-muted);
font-weight: 400;
}
.ct-nav-links {
display: flex;
align-items: center;
gap: 4px;
}
.ct-nav-link {
color: var(--ct-muted);
text-decoration: none;
font-size: 12px;
font-weight: 400;
padding: 6px 12px;
border-radius: 2px;
transition: color 0.15s ease, background 0.15s ease;
letter-spacing: 0.02em;
}
.ct-nav-link:hover {
color: var(--ct-primary);
background: rgba(57, 255, 20, 0.05);
}
.ct-nav-cta {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
background: transparent;
border: 1px solid var(--ct-dim);
color: var(--ct-text);
font-size: 12px;
font-weight: 400;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
transition: border-color 0.15s ease, color 0.15s ease;
}
.ct-nav-cta:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
}
/* Mobile menu toggle */
.ct-menu-toggle {
display: none;
background: none;
border: none;
color: var(--ct-muted);
cursor: pointer;
padding: 8px;
}
/* Buttons */
.ct-btn-primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: transparent;
color: var(--ct-primary);
font-weight: 700;
font-size: 13px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
transition: all 0.15s ease;
border: 1px solid var(--ct-primary);
cursor: pointer;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-btn-primary:hover {
background: rgba(57, 255, 20, 0.08);
box-shadow: 0 0 20px var(--ct-glow), 0 0 40px rgba(57, 255, 20, 0.1);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.5);
}
.ct-btn-secondary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: transparent;
color: var(--ct-text);
font-weight: 400;
font-size: 13px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
border: 1px solid var(--ct-dim);
transition: all 0.15s ease;
letter-spacing: 0.02em;
}
.ct-btn-secondary:hover {
border-color: var(--ct-muted);
color: var(--ct-text);
}
/* Hero Section */
.ct-hero {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 140px 40px 100px;
text-align: center;
}
.ct-hero-content {
position: relative;
z-index: 2;
max-width: 800px;
}
.ct-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 5px 14px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
font-size: 11px;
font-weight: 400;
color: var(--ct-secondary);
margin-bottom: 32px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.ct-badge-dot {
width: 6px;
height: 6px;
background: var(--ct-secondary);
border-radius: 50%;
animation: ct-blink 1.4s step-end infinite;
box-shadow: 0 0 6px rgba(255, 182, 39, 0.5);
}
.ct-hero h1 {
font-size: clamp(36px, 5.5vw, 60px);
font-weight: 700;
line-height: 1.15;
margin-bottom: 24px;
letter-spacing: -0.02em;
color: var(--ct-primary);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-hero h1::before {
content: ">_ ";
color: var(--ct-muted);
font-size: 0.7em;
}
.ct-hero h1::after {
content: "\2588";
animation: ct-blink 0.7s step-end infinite;
color: var(--ct-primary);
font-size: 0.8em;
margin-left: 4px;
}
.ct-hero-sub {
font-size: clamp(14px, 1.6vw, 16px);
color: var(--ct-muted);
line-height: 1.8;
margin-bottom: 40px;
max-width: 560px;
margin-left: auto;
margin-right: auto;
font-weight: 400;
}
.ct-hero-ctas {
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 48px;
}
/* Terminal code block */
.ct-code-block {
display: inline-block;
max-width: 520px;
width: 100%;
margin: 0 auto;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
overflow: hidden;
text-align: left;
}
.ct-code-titlebar {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
background: var(--ct-elevated);
border-bottom: 1px solid var(--ct-dim);
}
.ct-code-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.ct-code-dot:nth-child(1) { background: #ff5f57; }
.ct-code-dot:nth-child(2) { background: #febc2e; }
.ct-code-dot:nth-child(3) { background: #28c840; }
.ct-code-title {
flex: 1;
text-align: center;
font-size: 11px;
color: var(--ct-muted);
letter-spacing: 0.04em;
}
.ct-code-body {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
}
.ct-code-prompt {
color: var(--ct-primary);
font-weight: 700;
user-select: none;
font-size: 13px;
}
.ct-code-body code {
color: var(--ct-text);
flex: 1;
font-size: 13px;
font-family: 'Space Mono', monospace;
}
.ct-copy-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-muted);
cursor: pointer;
transition: all 0.15s ease;
flex-shrink: 0;
}
.ct-copy-btn:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
}
/* Stats section */
.ct-stats {
padding: 56px 40px;
border-top: 1px solid var(--ct-dim);
border-bottom: 1px solid var(--ct-dim);
background: var(--ct-surface);
}
.ct-stats-inner {
display: flex;
justify-content: center;
align-items: center;
max-width: 800px;
margin: 0 auto;
flex-wrap: wrap;
gap: 0;
}
.ct-stat-item {
text-align: center;
padding: 0 40px;
position: relative;
}
.ct-stat-item:not(:last-child)::after {
content: "|";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
color: var(--ct-dim);
font-size: 24px;
}
.ct-stat-value {
font-size: 26px;
font-weight: 700;
color: var(--ct-primary);
letter-spacing: 0.02em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-stat-label {
font-size: 11px;
color: var(--ct-muted);
margin-top: 6px;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 400;
}
/* Downloads section */
.ct-downloads {
padding: 80px 40px;
position: relative;
}
.ct-downloads-inner {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.ct-downloads h2 {
font-size: clamp(22px, 3vw, 28px);
font-weight: 700;
margin-bottom: 8px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-downloads p {
color: var(--ct-muted);
margin-bottom: 24px;
font-size: 13px;
}
.ct-downloads-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
}
.ct-download-item {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-text);
text-decoration: none;
font-size: 12px;
transition: all 0.15s ease;
}
.ct-download-item:hover {
border-color: var(--ct-primary);
color: var(--ct-primary);
box-shadow: 0 0 10px var(--ct-glow);
}
.ct-download-size {
font-size: 11px;
color: var(--ct-muted);
}
/* Features / Value Props */
.ct-features {
padding: 100px 40px;
position: relative;
}
.ct-features-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-section-label {
font-size: 11px;
font-weight: 700;
color: var(--ct-secondary);
text-transform: uppercase;
letter-spacing: 0.14em;
margin-bottom: 12px;
text-align: center;
}
.ct-section-label::before {
content: "// ";
color: var(--ct-muted);
}
.ct-section-header {
text-align: center;
margin-bottom: 56px;
}
.ct-section-header h2 {
font-size: clamp(24px, 3.5vw, 36px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-section-header p {
font-size: 14px;
color: var(--ct-muted);
max-width: 480px;
margin: 0 auto;
font-weight: 400;
}
.ct-features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 12px;
}
.ct-feature-card {
padding: 28px;
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
transition: all 0.15s ease;
position: relative;
}
.ct-feature-card:hover {
border-color: rgba(57, 255, 20, 0.3);
background: var(--ct-elevated);
box-shadow: 0 0 15px rgba(57, 255, 20, 0.05);
}
.ct-feature-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
color: var(--ct-primary);
margin-bottom: 16px;
}
.ct-feature-title {
font-size: 14px;
font-weight: 700;
color: var(--ct-text);
margin-bottom: 8px;
letter-spacing: 0.02em;
}
.ct-feature-desc {
font-size: 12px;
color: var(--ct-muted);
line-height: 1.7;
font-weight: 400;
}
/* Social proof */
.ct-social-proof {
padding: 80px 40px;
background: var(--ct-surface);
border-top: 1px solid var(--ct-dim);
border-bottom: 1px solid var(--ct-dim);
}
.ct-social-proof-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-logos {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 56px;
flex-wrap: wrap;
}
.ct-logo-item {
padding: 8px 16px;
font-size: 12px;
font-weight: 400;
color: var(--ct-dim);
letter-spacing: 0.04em;
text-transform: uppercase;
transition: color 0.15s ease;
}
.ct-logo-item:hover {
color: var(--ct-muted);
}
.ct-testimonial {
background: var(--ct-bg);
border: 1px solid var(--ct-dim);
border-radius: 2px;
padding: 40px;
max-width: 640px;
margin: 0 auto;
position: relative;
}
.ct-testimonial::before {
content: "/**";
position: absolute;
top: 16px;
left: 16px;
font-size: 12px;
color: var(--ct-muted);
}
.ct-testimonial::after {
content: "*/";
position: absolute;
bottom: 16px;
right: 16px;
font-size: 12px;
color: var(--ct-muted);
}
.ct-testimonial-quote {
font-size: 16px;
line-height: 1.8;
color: var(--ct-text);
margin-bottom: 24px;
font-weight: 400;
font-style: italic;
padding: 0 16px;
}
.ct-testimonial-author {
font-weight: 700;
color: var(--ct-primary);
font-size: 13px;
padding: 0 16px;
}
.ct-testimonial-role {
font-size: 12px;
color: var(--ct-muted);
padding: 0 16px;
}
/* Pricing */
.ct-pricing {
padding: 100px 40px;
}
.ct-pricing-inner {
max-width: 1100px;
margin: 0 auto;
}
.ct-pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 12px;
margin-top: 56px;
}
.ct-pricing-card {
background: var(--ct-surface);
border: 1px solid var(--ct-dim);
border-radius: 2px;
padding: 32px;
position: relative;
transition: all 0.15s ease;
}
.ct-pricing-card:hover {
border-color: var(--ct-muted);
}
.ct-pricing-card.featured {
border-color: var(--ct-primary);
box-shadow: 0 0 20px var(--ct-glow);
}
.ct-pricing-badge {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
padding: 4px 12px;
background: var(--ct-primary);
color: var(--ct-bg);
font-size: 10px;
font-weight: 700;
border-radius: 2px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.ct-pricing-name {
font-size: 14px;
font-weight: 700;
color: var(--ct-text);
margin-bottom: 8px;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-pricing-price {
font-size: 40px;
font-weight: 700;
color: var(--ct-primary);
line-height: 1;
margin-bottom: 4px;
letter-spacing: -0.02em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-pricing-period {
font-size: 12px;
color: var(--ct-muted);
margin-bottom: 24px;
}
.ct-pricing-features {
list-style: none;
padding: 0;
margin: 0 0 28px 0;
}
.ct-pricing-features li {
padding: 8px 0;
border-bottom: 1px solid var(--ct-dim);
font-size: 12px;
color: var(--ct-muted);
display: flex;
align-items: center;
gap: 8px;
}
.ct-pricing-features li::before {
content: "$";
color: var(--ct-primary);
font-size: 11px;
flex-shrink: 0;
}
.ct-pricing-features li:last-child {
border-bottom: none;
}
.ct-pricing-cta {
display: block;
width: 100%;
padding: 11px 20px;
text-align: center;
background: transparent;
color: var(--ct-text);
font-weight: 700;
font-size: 12px;
font-family: 'Space Mono', monospace;
border-radius: 2px;
text-decoration: none;
border: 1px solid var(--ct-dim);
transition: all 0.15s ease;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.ct-pricing-cta:hover {
border-color: var(--ct-muted);
}
.ct-pricing-card.featured .ct-pricing-cta {
background: transparent;
color: var(--ct-primary);
border-color: var(--ct-primary);
}
.ct-pricing-card.featured .ct-pricing-cta:hover {
background: rgba(57, 255, 20, 0.08);
box-shadow: 0 0 20px var(--ct-glow);
}
/* CTA section */
.ct-cta-section {
padding: 100px 40px;
text-align: center;
position: relative;
}
.ct-cta-section::before {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
height: 50%;
background: radial-gradient(ellipse at center bottom, var(--ct-glow) 0%, transparent 60%);
pointer-events: none;
}
.ct-cta-inner {
max-width: 600px;
margin: 0 auto;
position: relative;
z-index: 1;
}
.ct-cta-section h2 {
font-size: clamp(24px, 3.5vw, 38px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.01em;
color: var(--ct-text);
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-cta-section p {
font-size: 14px;
color: var(--ct-muted);
margin-bottom: 32px;
font-weight: 400;
}
/* Blog content markdown styles */
.ct-blog-content h1, .ct-blog-content h2, .ct-blog-content h3, .ct-blog-content h4 {
color: var(--ct-text); font-family: 'Space Mono', monospace; margin: 1.5em 0 0.5em;
text-shadow: 0 0 10px rgba(57, 255, 20, 0.3);
}
.ct-blog-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--ct-dim); padding-bottom: 8px; }
.ct-blog-content h3 { font-size: 1.25em; }
.ct-blog-content a { color: var(--ct-primary); text-decoration: underline; }
.ct-blog-content a:hover { opacity: 0.8; }
.ct-blog-content code { background: var(--ct-elevated); padding: 2px 6px; border-radius: 2px; font-family: 'Space Mono', monospace; font-size: 0.9em; color: var(--ct-secondary); }
.ct-blog-content pre { background: var(--ct-surface); border: 1px solid var(--ct-dim); border-radius: 2px; padding: 16px; overflow-x: auto; margin: 16px 0; }
.ct-blog-content pre code { background: none; padding: 0; color: var(--ct-text); }
.ct-blog-content blockquote { border-left: 2px solid var(--ct-primary); padding-left: 16px; color: var(--ct-muted); margin: 16px 0; font-style: italic; }
.ct-blog-content img { max-width: 100%; border-radius: 2px; margin: 16px 0; }
.ct-blog-content ul, .ct-blog-content ol { padding-left: 24px; margin: 12px 0; }
.ct-blog-content li { margin: 4px 0; }
.ct-blog-content table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.ct-blog-content th, .ct-blog-content td { border: 1px solid var(--ct-dim); padding: 8px 12px; text-align: left; }
.ct-blog-content th { background: var(--ct-surface); font-weight: 700; color: var(--ct-primary); }
.ct-blog-content hr { border: none; border-top: 1px solid var(--ct-dim); margin: 24px 0; }
/* Footer */
.ct-footer {
padding: 28px 40px;
border-top: 1px solid var(--ct-dim);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.ct-footer-brand {
display: flex;
align-items: center;
gap: 8px;
}
.ct-footer-logo {
width: 20px;
height: 20px;
background: transparent;
border: 1px solid var(--ct-dim);
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ct-primary);
}
.ct-footer-text {
font-size: 11px;
color: var(--ct-muted);
}
.ct-footer-links {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.ct-footer-link {
color: var(--ct-muted);
text-decoration: none;
font-size: 11px;
transition: color 0.15s ease;
letter-spacing: 0.02em;
}
.ct-footer-link:hover {
color: var(--ct-primary);
}
.ct-footer-social {
display: flex;
gap: 10px;
}
.ct-footer-social a {
color: var(--ct-dim);
transition: color 0.15s ease;
padding: 4px;
}
.ct-footer-social a:hover {
color: var(--ct-primary);
}
/* Responsive */
@media (max-width: 768px) {
.ct-nav { padding: 0 20px; }
.ct-nav-links { display: none; }
.ct-menu-toggle { display: flex; }
.ct-hero { padding: 120px 20px 80px; }
.ct-hero-ctas { flex-direction: column; align-items: center; }
.ct-btn-primary, .ct-btn-secondary { width: 100%; justify-content: center; }
.ct-features, .ct-social-proof, .ct-cta-section, .ct-pricing { padding: 60px 20px; }
.ct-stats { padding: 40px 20px; }
.ct-stat-item { padding: 12px 20px; }
.ct-stat-item:not(:last-child)::after { display: none; }
.ct-stats-inner { flex-direction: column; }
.ct-features-grid { grid-template-columns: 1fr; }
.ct-footer { flex-direction: column; text-align: center; padding: 20px; }
.ct-testimonial { padding: 32px 20px; }
.ct-code-block { max-width: 100%; }
.ct-downloads { padding: 60px 20px; }
}
@media (max-width: 480px) {
.ct-hero h1 { font-size: 28px; }
.ct-section-header h2 { font-size: 22px; }
.ct-pricing-price { font-size: 32px; }
.ct-code-body { font-size: 11px; }
}
</style>
<div class="ct-page">
<!-- Navigation -->
<nav class="ct-nav">
<a href="{{.LandingURL}}" class="ct-nav-brand">
{{if .LogoURL}}
<img src="{{.LogoURL}}" alt="{{.Config.Brand.Name}}" style="height: 28px; border-radius: 2px;">
{{else}}
<div class="ct-nav-logo">
{{svg "octicon-terminal" 14}}
</div>
{{end}}
<span class="ct-nav-name">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</span>
</a>
<div class="ct-nav-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ct-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ct-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="ct-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ct-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ct-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="{{.LandingURL}}#value-props" class="ct-nav-link">Value Props</a>{{end}}
{{if .Config.Features}}<a href="{{.LandingURL}}#features" class="ct-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="{{.LandingURL}}#pricing" class="ct-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}{{.LandingURL}}#blog{{end}}" class="ct-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="{{.LandingURL}}#gallery" class="ct-nav-link">Gallery</a>{{end}}
{{if and .Config.Comparison.Enabled .Config.Comparison.HasData}}<a href="{{.LandingURL}}#comparison" class="ct-nav-link">Compare</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="ct-nav-cta">
<img src="/assets/img/gitcaddy-icon.svg" width="14" height="14" alt="GitCaddy">
Repository
</a>
{{end}}
{{if .LangSwitcherEnabled}}
<div class="pages-lang-switcher">
<button class="pages-lang-btn" onclick="this.nextElementSibling.classList.toggle('open')">
{{svg "octicon-globe" 14}} {{index $.LanguageNames .ActiveLang}}
</button>
<div class="pages-lang-dropdown">
{{range .AvailableLanguages}}
<a href="?lang={{.}}" class="pages-lang-option{{if eq . $.ActiveLang}} active{{end}}">{{index $.LanguageNames .}}</a>
{{end}}
</div>
</div>
{{end}}
</div>
<button class="ct-menu-toggle" onclick="this.parentElement.querySelector('.ct-nav-links').style.display=this.parentElement.querySelector('.ct-nav-links').style.display==='flex'?'none':'flex'">
{{svg "octicon-three-bars" 20}}
</button>
</nav>
{{if .PageIsBlogDetail}}
<!-- Blog Detail View -->
<section class="ct-hero" style="padding-top: 120px; min-height: auto;">
<div class="ct-hero-content" style="max-width: 800px;">
{{if .BlogPost.FeaturedImage}}
<div style="margin: 0 auto 32px; border-radius: 2px; overflow: hidden; border: 1px solid var(--ct-dim);">
<img src="{{.BlogPost.FeaturedImage.DownloadURL}}" alt="{{.BlogPost.Title}}" style="width: 100%; max-height: 400px; object-fit: cover; display: block;">
</div>
{{end}}
<h1 style="font-size: 32px; margin-bottom: 8px; text-shadow: 0 0 10px rgba(57,255,20,0.3);">{{.BlogPost.Title}}</h1>
{{if .BlogPost.Subtitle}}<p style="font-size: 1.1rem; color: var(--ct-muted); margin-bottom: 24px;">{{.BlogPost.Subtitle}}</p>{{end}}
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 48px; font-size: 12px; color: var(--ct-muted);">
{{if .BlogPost.Author}}<span>{{.BlogPost.Author.DisplayName}}</span><span style="color: var(--ct-dim);">|</span>{{end}}
<span>{{DateUtils.AbsoluteShort .BlogPost.CreatedUnix}}</span>
{{if .BlogTags}}<span style="color: var(--ct-dim);">|</span>{{range .BlogTags}}<span style="background: rgba(57,255,20,0.08); border: 1px solid rgba(57,255,20,0.15); padding: 2px 8px; border-radius: 2px; font-size: 11px; color: var(--ct-primary);">{{.}}</span> {{end}}{{end}}
</div>
<div class="markup ct-blog-content" style="color: var(--ct-text); line-height: 1.8; font-size: 18px; text-align: left;">
{{.BlogRenderedContent}}
</div>
<div style="margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--ct-dim);">
<a href="{{.BlogBaseURL}}" class="ct-btn-secondary" data-cta="secondary" style="text-decoration: none;">
{{svg "octicon-arrow-left" 16}} Back to Blog
</a>
</div>
</div>
</section>
{{else if .PageIsBlogList}}
<!-- Blog List View -->
<section class="ct-features" style="padding-top: 120px;">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Blog</div>
<h2>{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}All Posts{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p>{{.Config.Blog.Subheadline}}</p>{{end}}
</div>
<div class="ct-features-grid">
{{range .BlogListPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ct-feature-card ct-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -28px -28px 16px -28px; overflow: hidden; border-radius: 2px 2px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="ct-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="ct-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--ct-muted);">
{{if .Author}}{{.Author.DisplayName}} &middot; {{end}}{{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if gt .BlogListTotal 9}}
<div style="text-align: center; margin-top: 48px;">
{{template "base/paginate" .}}
</div>
{{end}}
</div>
</section>
{{else}}
<!-- Hero Section -->
<section class="ct-hero" id="hero">
<div class="ct-hero-glow"></div>
<div class="ct-hero-vignette"></div>
<div class="ct-hero-content">
<div class="ct-badge ct-reveal visible">
<span class="ct-badge-dot"></span>
{{if .LatestRelease}}v{{.LatestReleaseTag}} released{{else}}Open Source{{end}}
</div>
<h1 class="ct-reveal visible ct-reveal-delay-1">{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}</h1>
<p class="ct-hero-sub ct-reveal visible ct-reveal-delay-2">
{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}
</p>
<div class="ct-hero-ctas ct-reveal visible ct-reveal-delay-3">
{{if .Config.Hero.PrimaryCTA.Label}}
<a href="{{.Config.Hero.PrimaryCTA.URL}}" class="ct-btn-primary" data-cta="primary">
{{.Config.Hero.PrimaryCTA.Label}}
{{svg "octicon-arrow-right" 16}}
</a>
{{end}}
{{if .Config.Hero.SecondaryCTA.Label}}
<a href="{{.Config.Hero.SecondaryCTA.URL}}" class="ct-btn-secondary" data-cta="secondary">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
{{.Config.Hero.SecondaryCTA.Label}}
</a>
{{end}}
</div>
{{if or $.GooglePlayID $.AppStoreID}}
<div style="display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-top: 16px;" class="ct-reveal visible ct-reveal-delay-4">
{{if $.GooglePlayID}}
<a href="https://play.google.com/store/apps/details?id={{$.GooglePlayID}}" target="_blank" rel="noopener" class="ct-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M3.609 1.814L13.792 12 3.61 22.186a.996.996 0 0 1-.61-.92V2.734a1 1 0 0 1 .609-.92zm10.89 10.893l2.302 2.302-10.937 6.333 8.635-8.635zm3.199-1.4l2.834 1.64a1 1 0 0 1 0 1.726l-2.834 1.64-2.635-2.636 2.635-2.37zM5.864 2.658L16.8 9.99l-2.302 2.302-8.635-8.635z"/></svg>
Google Play
</a>
{{end}}
{{if $.AppStoreID}}
<a href="https://apps.apple.com/app/{{$.AppStoreID}}" target="_blank" rel="noopener" class="ct-download-item" style="display: inline-flex; align-items: center; gap: 10px;">
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>
App Store
</a>
{{end}}
</div>
{{end}}
{{if .Config.Hero.CodeExample}}
<div class="ct-code-block ct-reveal visible ct-reveal-delay-4">
<div class="ct-code-titlebar">
<span class="ct-code-dot"></span>
<span class="ct-code-dot"></span>
<span class="ct-code-dot"></span>
<span class="ct-code-title">terminal</span>
</div>
<div class="ct-code-body">
<span class="ct-code-prompt">$</span>
<code id="install-cmd">{{.Config.Hero.CodeExample}}</code>
<button class="ct-copy-btn" onclick="navigator.clipboard.writeText(document.getElementById('install-cmd').textContent)">
{{svg "octicon-copy" 14}}
</button>
</div>
</div>
{{end}}
</div>
</section>
<!-- Stats Section -->
{{if or .Config.Stats (gt .NumStars 0)}}
<section class="ct-stats" id="stats">
<div class="ct-stats-inner ct-reveal">
{{if .Config.Stats}}
{{range .Config.Stats}}
<div class="ct-stat-item">
<div class="ct-stat-value">{{.Value}}</div>
<div class="ct-stat-label">{{.Label}}</div>
</div>
{{end}}
{{else}}
<div class="ct-stat-item">
<div class="ct-stat-value">{{.NumStars}}</div>
<div class="ct-stat-label">Stars</div>
</div>
<div class="ct-stat-item">
<div class="ct-stat-value">{{.NumForks}}</div>
<div class="ct-stat-label">Forks</div>
</div>
{{if .LatestRelease}}
<div class="ct-stat-item">
<div class="ct-stat-value">v{{.LatestReleaseTag}}</div>
<div class="ct-stat-label">Latest</div>
</div>
{{end}}
{{end}}
</div>
</section>
{{end}}
<!-- Downloads Section -->
{{if and .PublicReleases .LatestRelease .LatestRelease.Attachments}}
<section class="ct-downloads" id="downloads">
<div class="ct-downloads-inner ct-reveal">
<h2>Download v{{.LatestReleaseTag}}</h2>
<p>Get the latest release</p>
{{$windowsFiles := newSlice}}{{$macosFiles := newSlice}}{{$linuxFiles := newSlice}}{{$androidFiles := newSlice}}{{$iosFiles := newSlice}}{{$otherFiles := newSlice}}
{{range $att := .LatestRelease.Attachments}}
{{$name := StringUtils.ToLower $att.Name}}
{{if or (StringUtils.Contains $name "android") (StringUtils.HasSuffix $name ".apk") (StringUtils.HasSuffix $name ".aab") (StringUtils.HasSuffix $name ".xapk")}}
{{$androidFiles = Append $androidFiles $att}}
{{else if or (StringUtils.Contains $name "ios") (StringUtils.Contains $name "iphone") (StringUtils.Contains $name "ipad") (StringUtils.HasSuffix $name ".ipa")}}
{{$iosFiles = Append $iosFiles $att}}
{{else if or (StringUtils.Contains $name "windows") (StringUtils.Contains $name "win64") (StringUtils.Contains $name "win32") (StringUtils.Contains $name "-win.") (StringUtils.Contains $name "_win.") (StringUtils.Contains $name "-win-") (StringUtils.Contains $name "_win_") (StringUtils.HasSuffix $name ".exe") (StringUtils.HasSuffix $name ".msi") (StringUtils.HasSuffix $name ".msix") (StringUtils.HasSuffix $name ".msixbundle") (StringUtils.HasSuffix $name ".appx") (StringUtils.HasSuffix $name ".appxbundle")}}
{{$windowsFiles = Append $windowsFiles $att}}
{{else if or (StringUtils.Contains $name "darwin") (StringUtils.Contains $name "macos") (StringUtils.Contains $name "-mac.") (StringUtils.Contains $name "_mac.") (StringUtils.Contains $name "-mac-") (StringUtils.Contains $name "_mac_") (StringUtils.Contains $name "osx") (StringUtils.HasSuffix $name ".dmg") (StringUtils.HasSuffix $name ".pkg")}}
{{$macosFiles = Append $macosFiles $att}}
{{else if or (StringUtils.Contains $name "linux") (StringUtils.Contains $name "-lin.") (StringUtils.Contains $name "_lin.") (StringUtils.Contains $name "-lin-") (StringUtils.Contains $name "_lin_") (StringUtils.HasSuffix $name ".deb") (StringUtils.HasSuffix $name ".rpm") (StringUtils.HasSuffix $name ".appimage") (StringUtils.HasSuffix $name ".flatpak") (StringUtils.HasSuffix $name ".snap")}}
{{$linuxFiles = Append $linuxFiles $att}}
{{else}}
{{$otherFiles = Append $otherFiles $att}}
{{end}}
{{end}}
{{if $windowsFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} Windows</h4>
<div class="ct-downloads-grid">
{{range $windowsFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $macosFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} macOS</h4>
<div class="ct-downloads-grid">
{{range $macosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $linuxFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-terminal" 16}} Linux</h4>
<div class="ct-downloads-grid">
{{range $linuxFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if not $.HideMobileReleases}}
{{if $androidFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} Android</h4>
<div class="ct-downloads-grid">
{{range $androidFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{if $iosFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} iOS</h4>
<div class="ct-downloads-grid">
{{range $iosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{end}}
{{if $otherFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12px; color: var(--ct-muted); letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-file" 16}} Other</h4>
<div class="ct-downloads-grid">
{{range $otherFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="ct-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="ct-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Value Props Section -->
{{if .Config.ValueProps}}
<section class="ct-features" id="value-props">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Why choose us</div>
<h2>{{if .Config.Brand.Name}}Why {{.Config.Brand.Name}}?{{else}}Why Choose Us{{end}}</h2>
<p>Everything you need to get started quickly.</p>
</div>
<div class="ct-features-grid">
{{range .Config.ValueProps}}
<div class="ct-feature-card ct-reveal">
<div class="ct-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "check")) 20}}
</div>
<h3 class="ct-feature-title">{{.Title}}</h3>
<p class="ct-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Features Section -->
{{if .Config.Features}}
<section class="ct-features" id="features" style="padding-top: 40px;">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Capabilities</div>
<h2>Features</h2>
<p>Powerful capabilities at your fingertips.</p>
</div>
<div class="ct-features-grid">
{{range .Config.Features}}
<div class="ct-feature-card ct-reveal">
<div class="ct-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "zap")) 20}}
</div>
<h3 class="ct-feature-title">{{.Title}}</h3>
<p class="ct-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Social Proof -->
{{if or .Config.SocialProof.Logos .Config.SocialProof.Testimonials}}
<section class="ct-social-proof" id="social-proof">
<div class="ct-social-proof-inner">
{{if .Config.SocialProof.Logos}}
<div class="ct-logos ct-reveal">
{{range .Config.SocialProof.Logos}}
<div class="ct-logo-item">{{.}}</div>
{{end}}
</div>
{{end}}
{{if .Config.SocialProof.Testimonials}}
<div class="ct-testimonials-container">
{{range .Config.SocialProof.Testimonials}}
<div class="ct-testimonial ct-reveal" style="display: none;">
<p class="ct-testimonial-quote">"{{.Quote}}"</p>
<div>
<div class="ct-testimonial-author">{{.Author}}</div>
<div class="ct-testimonial-role">{{.Role}}</div>
</div>
</div>
{{end}}
</div>
<script>
(function() {
var testimonials = document.querySelectorAll(".ct-testimonial");
if (testimonials.length > 0) {
var idx = Math.floor(Math.random() * testimonials.length);
testimonials[idx].style.display = "block";
}
})();
</script>
{{end}}
</div>
</section>
{{end}}
<!-- Pricing Section -->
{{if .Config.Pricing.Plans}}
<section class="ct-pricing" id="pricing">
<div class="ct-pricing-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Pricing</div>
<h2>{{if .Config.Pricing.Headline}}{{.Config.Pricing.Headline}}{{else}}Pricing{{end}}</h2>
<p>{{if .Config.Pricing.Subheadline}}{{.Config.Pricing.Subheadline}}{{else}}Choose the plan that works for you{{end}}</p>
</div>
<div class="ct-pricing-grid">
{{range .Config.Pricing.Plans}}
<div class="ct-pricing-card{{if .Featured}} featured{{end}} ct-reveal">
{{if .Featured}}<span class="ct-pricing-badge">Popular</span>{{end}}
<div class="ct-pricing-name">{{.Name}}</div>
<div class="ct-pricing-price">{{.Price}}</div>
<div class="ct-pricing-period">{{.Period}}</div>
{{if .Features}}
<ul class="ct-pricing-features">
{{range .Features}}<li>{{.}}</li>{{end}}
</ul>
{{end}}
<a href="#" class="ct-pricing-cta">{{if .CTA}}{{.CTA}}{{else}}Get Started{{end}}</a>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- CTA Section -->
{{if .Config.CTASection.Headline}}
<section class="ct-cta-section" id="cta">
<div class="ct-cta-inner ct-reveal">
<h2>{{.Config.CTASection.Headline}}</h2>
{{if .Config.CTASection.Subheadline}}
<p>{{.Config.CTASection.Subheadline}}</p>
{{end}}
<a href="{{if .Config.CTASection.Button.URL}}{{.Config.CTASection.Button.URL}}{{else}}{{.RepoURL}}{{end}}" class="ct-btn-primary" data-cta="primary" style="padding: 14px 28px; font-size: 13px;">
{{if .Config.CTASection.Button.Label}}{{.Config.CTASection.Button.Label}}{{else}}Get Started{{end}}
{{svg "octicon-arrow-right" 16}}
</a>
</div>
</section>
{{end}}
<!-- Blog Section -->
{{if and .Config.Blog.Enabled .BlogPosts}}
<section class="ct-features" id="blog" style="border-top: 1px solid var(--ct-dim);">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Blog</div>
<h2>{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}Latest Posts{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p>{{.Config.Blog.Subheadline}}</p>{{end}}
</div>
<div class="ct-features-grid">
{{range .BlogPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="ct-feature-card ct-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -28px -28px 16px -28px; overflow: hidden; border-radius: 2px 2px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="ct-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="ct-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--ct-muted);">
{{if .Author}}{{.Author.DisplayName}}{{end}} · {{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if .Config.Blog.CTAButton.Label}}
<div style="text-align: center; margin-top: 48px;" class="ct-reveal">
<a href="{{if .Config.Blog.CTAButton.URL}}{{.Config.Blog.CTAButton.URL}}{{else}}{{.BlogBaseURL}}{{end}}" class="ct-btn-secondary" data-cta="secondary">
{{.Config.Blog.CTAButton.Label}}
{{svg "octicon-arrow-right" 16}}
</a>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Gallery Section -->
{{if and .Config.Gallery.Enabled .GalleryImages}}
<section class="ct-features" id="gallery" style="border-top: 1px solid var(--ct-dim);">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Gallery</div>
<h2>{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}Gallery{{end}}</h2>
{{if .Config.Gallery.Subheadline}}<p>{{.Config.Gallery.Subheadline}}</p>{{end}}
</div>
<div style="display: grid; grid-template-columns: repeat({{if .Config.Gallery.Columns}}{{.Config.Gallery.Columns}}{{else}}3{{end}}, 1fr); gap: 12px;">
{{range .GalleryImages}}
<div class="ct-feature-card ct-reveal" style="padding: 0; overflow: hidden;">
<a href="{{.URL}}" class="pages-gallery-trigger" data-src="{{.URL}}" data-caption="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="display: block; cursor: pointer;">
<img src="{{.URL}}" alt="{{if .Caption}}{{.Caption}}{{else}}{{.Name}}{{end}}" style="width: 100%; height: 220px; object-fit: cover; display: block;">
</a>
{{if .Caption}}
<div style="padding: 12px 16px; font-size: 11px; color: var(--ct-muted); border-top: 1px solid var(--ct-dim);">{{.Caption}}</div>
{{end}}
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Comparison Section -->
{{if and .Config.Comparison.Enabled .Config.Comparison.HasData}}
<section class="ct-features" id="comparison" style="border-top: 1px solid var(--ct-dim);">
<div class="ct-features-inner">
<div class="ct-section-header ct-reveal">
<div class="ct-section-label">Compare</div>
<h2>{{if .Config.Comparison.Headline}}{{.Config.Comparison.Headline}}{{else}}How We Compare{{end}}</h2>
{{if .Config.Comparison.Subheadline}}<p>{{.Config.Comparison.Subheadline}}</p>{{end}}
</div>
<div class="ct-reveal" style="overflow-x: auto;">
<table style="width: 100%; border-collapse: collapse; font-size: 14px;">
<thead>
<tr>
<th style="text-align: left; padding: 16px 20px; border-bottom: 2px solid var(--ct-dim); color: var(--ct-muted); font-weight: 500; min-width: 200px;"></th>
{{range .Config.Comparison.Columns}}
<th style="text-align: center; padding: 16px 20px; border-bottom: 2px solid var(--ct-dim); font-weight: 600; font-size: 15px;{{if .Highlight}} color: var(--ct-primary);{{else}} color: var(--ct-text);{{end}}">
{{.Name}}
{{if .Highlight}}<div style="width: 40px; height: 3px; background: var(--ct-primary); margin: 8px auto 0; border-radius: 2px;"></div>{{end}}
</th>
{{end}}
</tr>
</thead>
<tbody>
{{range .Config.Comparison.Groups}}
{{if .Name}}
<tr>
<td colspan="4" style="padding: 20px 20px 8px; font-weight: 600; font-size: 13px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ct-muted); border-bottom: 1px solid var(--ct-dim);">{{.Name}}</td>
</tr>
{{end}}
{{range .Features}}
<tr style="border-bottom: 1px solid rgba(57,255,20,0.04);">
<td style="padding: 14px 20px; color: var(--ct-text);">{{.Name}}</td>
{{range .Values}}
<td style="text-align: center; padding: 14px 20px;">
{{if eq . "true"}}<span style="color: var(--ct-primary);">{{svg "octicon-check-circle-fill" 18}}</span>
{{else if eq . "false"}}<span style="color: var(--ct-dim);">{{svg "octicon-x-circle" 18}}</span>
{{else}}<span style="color: var(--ct-text); font-weight: 500;">{{.}}</span>
{{end}}
</td>
{{end}}
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>
</div>
</section>
{{end}}
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
<!-- Footer -->
<footer class="ct-footer">
<div class="ct-footer-brand">
<div class="ct-footer-logo">{{svg "octicon-terminal" 10}}</div>
<span class="ct-footer-text">{{if .Config.Footer.Copyright}}{{.Config.Footer.Copyright}}{{else}}&copy; <script>document.write(new Date().getFullYear())</script> {{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}{{end}}</span>
</div>
{{if .Config.Footer.Social}}
<div class="ct-footer-social">
{{range .Config.Footer.Social}}
<a href="{{.URL}}" title="{{.Platform}}">
{{if eq .Platform "twitter"}}{{svg "octicon-mention" 16}}
{{else if eq .Platform "bluesky"}}{{svg "octicon-cloud" 16}}
{{else if eq .Platform "github"}}{{svg "octicon-mark-github" 16}}
{{else if eq .Platform "discord"}}{{svg "octicon-comment-discussion" 16}}
{{else if eq .Platform "linkedin"}}{{svg "octicon-briefcase" 16}}
{{else if eq .Platform "youtube"}}{{svg "octicon-video" 16}}
{{else if eq .Platform "instagram"}}{{svg "octicon-device-camera" 16}}
{{else if eq .Platform "facebook"}}{{svg "octicon-people" 16}}
{{else if eq .Platform "substack"}}{{svg "octicon-note" 16}}
{{else if eq .Platform "threads"}}{{svg "octicon-share" 16}}
{{else if eq .Platform "tiktok"}}{{svg "octicon-play" 16}}
{{else if eq .Platform "reddit"}}{{svg "octicon-hash" 16}}
{{else if eq .Platform "mastodon"}}{{svg "octicon-megaphone" 16}}
{{else if eq .Platform "twitch"}}{{svg "octicon-broadcast" 16}}
{{else if eq .Platform "rss"}}{{svg "octicon-rss" 16}}
{{else}}{{svg "octicon-link-external" 16}}{{end}}
</a>
{{end}}
</div>
{{end}}
<div class="ct-footer-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="ct-footer-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowRepository}}<a href="{{.RepoURL}}" class="ct-footer-link">Repository</a>{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="ct-footer-link">Documentation</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="ct-footer-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="ct-footer-link">Issues</a>{{end}}
</div>
</footer>
</div>
<!-- Scroll reveal observer -->
<script>
(function() {
var reveals = document.querySelectorAll('.ct-reveal:not(.visible)');
if (!reveals.length) return;
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
reveals.forEach(function(el) { observer.observe(el); });
})();
</script>
{{template "pages/base_footer" .}}