2
0
Files
logikonline 22844f6437 fix(pages): use navigation labels for section headings and add defaults
Use LabelValueProps and LabelFeatures from navigation config for section headings instead of hardcoded text. Removes hardcoded subheadlines that don't translate well. Adds default headlines for blog ("Latest Posts"), gallery ("Gallery"), and comparison ("How We Compare") sections when not configured. Improves consistency and translation support across all 8 page templates.
2026-03-17 21:34:34 -04:00

1464 lines
48 KiB
Handlebars

{{template "pages/base_head" .}}
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap');
:root {
--dt-bg: #0c0c0e;
--dt-surface: #141416;
--dt-elevated: #1c1c20;
--dt-text: #e0e0e4;
--dt-muted: #8b8b94;
--dt-dim: #2a2a30;
--dt-accent: {{if .Config.Theme.PrimaryColor}}{{.Config.Theme.PrimaryColor}}{{else}}#f0b429{{end}};
--dt-accent-dark: {{if .Config.Theme.AccentColor}}{{.Config.Theme.AccentColor}}{{else}}#22d3ee{{end}};
--dt-glow: color-mix(in srgb, var(--dt-accent) 12%, transparent);
--dt-glow-strong: color-mix(in srgb, var(--dt-accent) 35%, transparent);
--dt-cyan: #22d3ee;
}
html {
scroll-behavior: smooth;
}
html, body.pages-body {
overflow-x: hidden;
background: var(--dt-bg) !important;
}
/* Dot grid pattern (graph paper style) */
.dt-page::after {
content: "";
position: fixed;
inset: 0;
background-image: radial-gradient(circle, rgba(255,255,255,0.035) 1px, transparent 1px);
background-size: 24px 24px;
pointer-events: none;
z-index: 0;
}
.dt-page {
position: relative;
min-height: 100vh;
background: var(--dt-bg);
color: var(--dt-text);
font-family: 'Inter', -apple-system, sans-serif;
-webkit-font-smoothing: antialiased;
}
/* Reveal animation system */
.dt-reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94), transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.dt-reveal.visible {
opacity: 1;
transform: translateY(0);
}
.dt-reveal-delay-1 { transition-delay: 0.08s; }
.dt-reveal-delay-2 { transition-delay: 0.16s; }
.dt-reveal-delay-3 { transition-delay: 0.24s; }
.dt-reveal-delay-4 { transition-delay: 0.32s; }
/* Navigation */
.dt-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(12, 12, 14, 0.92);
backdrop-filter: blur(12px) saturate(160%);
-webkit-backdrop-filter: blur(12px) saturate(160%);
border-bottom: 1px solid var(--dt-dim);
z-index: 100;
}
.dt-nav-brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: inherit;
}
.dt-nav-logo {
width: 28px;
height: 28px;
background: var(--dt-accent);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.dt-nav-name {
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 15px;
letter-spacing: -0.01em;
color: var(--dt-text);
}
.dt-nav-links {
display: flex;
align-items: center;
gap: 4px;
}
.dt-nav-link {
color: var(--dt-muted);
text-decoration: none;
font-size: 13px;
font-weight: 500;
padding: 6px 12px;
border-radius: 4px;
transition: all 0.15s ease;
font-family: 'JetBrains Mono', monospace;
}
.dt-nav-link:hover {
color: var(--dt-text);
background: rgba(255,255,255,0.04);
}
.dt-nav-cta {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
background: rgba(255,255,255,0.05);
border: 1px solid var(--dt-dim);
color: var(--dt-text);
font-size: 13px;
font-weight: 500;
border-radius: 4px;
text-decoration: none;
transition: all 0.15s ease;
font-family: 'JetBrains Mono', monospace;
}
.dt-nav-cta:hover {
background: rgba(255,255,255,0.08);
border-color: var(--dt-accent);
}
/* Mobile menu toggle */
.dt-menu-toggle {
display: none;
background: none;
border: none;
color: var(--dt-muted);
cursor: pointer;
padding: 8px;
}
/* Buttons */
.dt-btn-primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: var(--dt-accent);
color: #0c0c0e;
font-weight: 600;
font-size: 14px;
border-radius: 4px;
text-decoration: none;
transition: all 0.2s ease;
border: none;
cursor: pointer;
font-family: 'JetBrains Mono', monospace;
letter-spacing: -0.01em;
}
.dt-btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 24px var(--dt-glow-strong);
}
.dt-btn-secondary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: transparent;
color: var(--dt-text);
font-weight: 500;
font-size: 14px;
border-radius: 4px;
text-decoration: none;
border: 1px solid var(--dt-accent);
transition: all 0.2s ease;
font-family: 'JetBrains Mono', monospace;
}
.dt-btn-secondary:hover {
background: color-mix(in srgb, var(--dt-accent) 8%, transparent);
}
/* Hero Section */
.dt-hero {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 120px 40px 100px;
text-align: center;
}
.dt-hero-content {
position: relative;
z-index: 1;
max-width: 780px;
}
/* CI status badge style */
.dt-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 12px 4px 6px;
background: var(--dt-surface);
border: 1px solid var(--dt-dim);
border-radius: 4px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
font-weight: 500;
color: var(--dt-accent);
margin-bottom: 32px;
}
.dt-badge-dot {
width: 8px;
height: 8px;
background: #22c55e;
border-radius: 2px;
flex-shrink: 0;
}
.dt-badge-label {
color: var(--dt-muted);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.05em;
padding-right: 8px;
border-right: 1px solid var(--dt-dim);
margin-right: 4px;
}
.dt-hero h1 {
font-size: clamp(36px, 5.5vw, 64px);
font-weight: 700;
line-height: 1.1;
margin-bottom: 24px;
letter-spacing: -0.04em;
color: #ffffff;
}
.dt-hero-sub {
font-size: clamp(15px, 1.8vw, 18px);
color: var(--dt-muted);
line-height: 1.7;
margin-bottom: 40px;
max-width: 540px;
margin-left: auto;
margin-right: auto;
font-weight: 400;
}
.dt-hero-ctas {
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 48px;
}
/* Code install block */
.dt-code-block {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 18px;
background: var(--dt-surface);
border: 1px solid var(--dt-dim);
border-radius: 4px;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
max-width: 520px;
margin: 0 auto;
position: relative;
}
.dt-code-prompt {
color: var(--dt-accent);
font-weight: 600;
user-select: none;
}
.dt-code-block code {
color: var(--dt-text);
flex: 1;
text-align: left;
}
.dt-copy-btn {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
background: rgba(255,255,255,0.04);
border: 1px solid var(--dt-dim);
border-radius: 4px;
color: var(--dt-muted);
cursor: pointer;
transition: all 0.15s ease;
flex-shrink: 0;
}
.dt-copy-btn:hover {
background: rgba(255,255,255,0.08);
color: var(--dt-text);
border-color: var(--dt-accent);
}
/* Stats section */
.dt-stats {
padding: 56px 40px;
border-top: 1px solid var(--dt-dim);
border-bottom: 1px solid var(--dt-dim);
background: var(--dt-surface);
}
.dt-stats-inner {
display: flex;
justify-content: center;
align-items: center;
max-width: 800px;
margin: 0 auto;
flex-wrap: wrap;
gap: 0;
}
.dt-stat-item {
text-align: center;
padding: 0 48px;
position: relative;
}
.dt-stat-item:not(:last-child)::after {
content: "";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 36px;
background: var(--dt-dim);
}
.dt-stat-value {
font-family: 'JetBrains Mono', monospace;
font-size: 28px;
font-weight: 700;
color: var(--dt-text);
letter-spacing: -0.03em;
}
.dt-stat-label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--dt-muted);
margin-top: 6px;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 500;
}
/* Downloads section */
.dt-downloads {
padding: 80px 40px;
position: relative;
}
.dt-downloads-inner {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.dt-downloads h2 {
font-size: clamp(22px, 3vw, 30px);
font-weight: 700;
margin-bottom: 8px;
letter-spacing: -0.025em;
}
.dt-downloads p {
color: var(--dt-muted);
margin-bottom: 24px;
font-size: 14px;
}
.dt-downloads-grid {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.dt-download-item {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 18px;
background: var(--dt-surface);
border: 1px solid var(--dt-dim);
border-radius: 4px;
color: var(--dt-text);
text-decoration: none;
font-size: 13px;
font-family: 'JetBrains Mono', monospace;
transition: all 0.15s ease;
}
.dt-download-item:hover {
background: var(--dt-elevated);
border-color: var(--dt-accent);
border-left: 3px solid var(--dt-accent);
}
.dt-download-size {
font-size: 11px;
color: var(--dt-muted);
}
/* Feature / value prop cards */
.dt-features {
padding: 100px 40px;
position: relative;
}
.dt-features-inner {
max-width: 1100px;
margin: 0 auto;
}
.dt-section-label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 600;
color: var(--dt-accent);
text-transform: uppercase;
letter-spacing: 0.14em;
margin-bottom: 12px;
text-align: center;
}
.dt-section-header {
text-align: center;
margin-bottom: 56px;
}
.dt-section-header h2 {
font-size: clamp(26px, 3.5vw, 40px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.03em;
color: #ffffff;
}
.dt-section-header p {
font-size: 16px;
color: var(--dt-muted);
max-width: 460px;
margin: 0 auto;
font-weight: 400;
}
.dt-features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
.dt-feature-card {
padding: 28px;
background: var(--dt-surface);
border: 1px solid var(--dt-dim);
border-radius: 4px;
transition: all 0.2s ease;
position: relative;
}
.dt-feature-card:hover {
background: var(--dt-elevated);
border-left: 3px solid var(--dt-accent);
}
.dt-feature-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--dt-accent) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--dt-accent) 15%, transparent);
border-radius: 4px;
color: var(--dt-accent);
margin-bottom: 16px;
}
.dt-feature-title {
font-size: 15px;
font-weight: 600;
color: #ffffff;
margin-bottom: 8px;
letter-spacing: -0.01em;
}
.dt-feature-desc {
font-size: 13px;
color: var(--dt-muted);
line-height: 1.65;
font-weight: 400;
}
/* Social proof */
.dt-social-proof {
padding: 80px 40px;
background: var(--dt-surface);
border-top: 1px solid var(--dt-dim);
border-bottom: 1px solid var(--dt-dim);
}
.dt-social-proof-inner {
max-width: 1100px;
margin: 0 auto;
}
.dt-logos {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 56px;
flex-wrap: wrap;
}
.dt-logo-item {
padding: 8px 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
font-weight: 500;
color: var(--dt-dim);
letter-spacing: 0.02em;
transition: color 0.2s ease;
}
.dt-logo-item:hover {
color: var(--dt-muted);
}
.dt-testimonial {
background: var(--dt-bg);
border: 1px solid var(--dt-dim);
border-left: 3px solid var(--dt-accent);
border-radius: 4px;
padding: 40px;
max-width: 640px;
margin: 0 auto;
}
.dt-testimonial-quote {
font-size: 18px;
line-height: 1.7;
color: var(--dt-text);
margin-bottom: 24px;
font-weight: 400;
font-style: italic;
}
.dt-testimonial-author {
font-family: 'JetBrains Mono', monospace;
font-weight: 600;
color: var(--dt-text);
font-size: 14px;
}
.dt-testimonial-role {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--dt-muted);
}
/* Pricing */
.dt-pricing {
padding: 100px 40px;
}
.dt-pricing-inner {
max-width: 1100px;
margin: 0 auto;
}
.dt-pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 16px;
margin-top: 56px;
}
.dt-pricing-card {
background: var(--dt-surface);
border: 1px solid var(--dt-dim);
border-radius: 4px;
padding: 32px;
position: relative;
transition: all 0.2s ease;
}
.dt-pricing-card:hover {
border-color: var(--dt-muted);
}
.dt-pricing-card.featured {
border-color: var(--dt-accent);
background: linear-gradient(180deg, color-mix(in srgb, var(--dt-accent) 4%, transparent) 0%, var(--dt-surface) 100%);
}
.dt-pricing-badge {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
padding: 4px 12px;
background: var(--dt-accent);
color: #0c0c0e;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
font-weight: 700;
border-radius: 2px;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.dt-pricing-name {
font-family: 'JetBrains Mono', monospace;
font-size: 16px;
font-weight: 600;
color: #ffffff;
margin-bottom: 8px;
}
.dt-pricing-price {
font-family: 'JetBrains Mono', monospace;
font-size: 42px;
font-weight: 700;
color: var(--dt-text);
line-height: 1;
margin-bottom: 4px;
letter-spacing: -0.04em;
}
.dt-pricing-period {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--dt-muted);
margin-bottom: 24px;
}
.dt-pricing-features {
list-style: none;
padding: 0;
margin: 0 0 28px 0;
}
.dt-pricing-features li {
padding: 8px 0;
border-bottom: 1px solid rgba(42, 42, 48, 0.6);
font-size: 13px;
color: var(--dt-muted);
display: flex;
align-items: center;
gap: 10px;
font-family: 'Inter', sans-serif;
}
.dt-pricing-features li::before {
content: "$";
font-family: 'JetBrains Mono', monospace;
color: var(--dt-accent);
font-size: 11px;
font-weight: 600;
flex-shrink: 0;
}
.dt-pricing-features li:last-child {
border-bottom: none;
}
.dt-pricing-cta {
display: block;
width: 100%;
padding: 12px 20px;
text-align: center;
background: rgba(255,255,255,0.04);
color: var(--dt-text);
font-family: 'JetBrains Mono', monospace;
font-weight: 600;
font-size: 13px;
border-radius: 4px;
text-decoration: none;
border: 1px solid var(--dt-dim);
transition: all 0.15s ease;
}
.dt-pricing-cta:hover {
background: rgba(255,255,255,0.08);
border-color: var(--dt-muted);
}
.dt-pricing-card.featured .dt-pricing-cta {
background: var(--dt-accent);
color: #0c0c0e;
border: none;
}
.dt-pricing-card.featured .dt-pricing-cta:hover {
transform: translateY(-1px);
box-shadow: 0 4px 20px var(--dt-glow-strong);
}
/* CTA section */
.dt-cta-section {
padding: 100px 40px;
text-align: center;
position: relative;
border-top: 1px solid var(--dt-dim);
}
.dt-cta-inner {
max-width: 580px;
margin: 0 auto;
position: relative;
z-index: 1;
}
.dt-cta-section h2 {
font-size: clamp(26px, 3.5vw, 40px);
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.03em;
color: #ffffff;
}
.dt-cta-section p {
font-size: 16px;
color: var(--dt-muted);
margin-bottom: 32px;
font-weight: 400;
}
/* Footer */
.dt-footer {
padding: 28px 40px;
border-top: 1px solid var(--dt-dim);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.dt-footer-brand {
display: flex;
align-items: center;
gap: 8px;
}
.dt-footer-logo {
width: 20px;
height: 20px;
background: color-mix(in srgb, var(--dt-accent) 15%, transparent);
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
}
.dt-footer-text {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--dt-dim);
}
.dt-footer-links {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.dt-footer-link {
color: var(--dt-muted);
text-decoration: none;
font-size: 12px;
font-family: 'JetBrains Mono', monospace;
transition: color 0.15s ease;
}
.dt-footer-link:hover {
color: var(--dt-text);
}
.dt-footer-social {
display: flex;
gap: 10px;
}
.dt-footer-social a {
color: var(--dt-dim);
transition: color 0.15s ease;
padding: 4px;
}
.dt-footer-social a:hover {
color: var(--dt-accent);
}
/* Blog content markdown styles */
.dt-blog-content h1, .dt-blog-content h2, .dt-blog-content h3, .dt-blog-content h4 {
color: var(--dt-text); font-family: 'Inter', sans-serif; margin: 1.5em 0 0.5em;
}
.dt-blog-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--dt-dim); padding-bottom: 8px; }
.dt-blog-content h3 { font-size: 1.25em; }
.dt-blog-content a { color: var(--dt-accent); text-decoration: underline; }
.dt-blog-content a:hover { opacity: 0.8; }
.dt-blog-content code { background: var(--dt-elevated); padding: 2px 6px; border-radius: 3px; font-family: 'JetBrains Mono', monospace; font-size: 0.9em; }
.dt-blog-content pre { background: var(--dt-surface); border: 1px solid var(--dt-dim); border-radius: 4px; padding: 16px; overflow-x: auto; margin: 16px 0; }
.dt-blog-content pre code { background: none; padding: 0; }
.dt-blog-content blockquote { border-left: 3px solid var(--dt-accent); padding-left: 16px; color: var(--dt-muted); margin: 16px 0; font-style: italic; }
.dt-blog-content img { max-width: 100%; border-radius: 4px; margin: 16px 0; }
.dt-blog-content ul, .dt-blog-content ol { padding-left: 24px; margin: 12px 0; }
.dt-blog-content li { margin: 4px 0; }
.dt-blog-content table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.dt-blog-content th, .dt-blog-content td { border: 1px solid var(--dt-dim); padding: 8px 12px; text-align: left; }
.dt-blog-content th { background: var(--dt-surface); font-weight: 600; }
.dt-blog-content hr { border: none; border-top: 1px solid var(--dt-dim); margin: 24px 0; }
/* Responsive */
@media (max-width: 768px) {
.dt-nav { padding: 0 20px; }
.dt-nav-links { display: none; }
.dt-menu-toggle { display: flex; }
.dt-hero { padding: 100px 24px 80px; }
.dt-hero-ctas { flex-direction: column; align-items: center; }
.dt-btn-primary, .dt-btn-secondary { width: 100%; justify-content: center; }
.dt-features, .dt-social-proof, .dt-cta-section, .dt-pricing { padding: 72px 24px; }
.dt-stats { padding: 40px 24px; }
.dt-stat-item { padding: 12px 24px; }
.dt-stat-item:not(:last-child)::after { display: none; }
.dt-stats-inner { flex-direction: column; }
.dt-features-grid { grid-template-columns: 1fr; }
.dt-footer { flex-direction: column; text-align: center; padding: 20px; }
.dt-testimonial { padding: 28px 20px; }
.dt-code-block { font-size: 11px; }
}
@media (max-width: 480px) {
.dt-hero h1 { font-size: 30px; }
.dt-section-header h2 { font-size: 26px; }
.dt-pricing-price { font-size: 34px; }
}
</style>
<div class="dt-page">
<!-- Navigation -->
<nav class="dt-nav">
<a href="{{.LandingURL}}" class="dt-nav-brand">
{{if .LogoURL}}
<img src="{{.LogoURL}}" alt="{{.Config.Brand.Name}}" style="height: 28px; border-radius: 3px;">
{{else}}
<div class="dt-nav-logo">
{{svg "octicon-terminal" 14}}
</div>
{{end}}
<span class="dt-nav-name">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</span>
</a>
<div class="dt-nav-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="dt-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="dt-nav-link">{{if .Config.Navigation.LabelDocs}}{{.Config.Navigation.LabelDocs}}{{else}}Docs{{end}}</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="dt-nav-link">{{if .Config.Navigation.LabelAPI}}{{.Config.Navigation.LabelAPI}}{{else}}API{{end}}</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="dt-nav-link">{{if .Config.Navigation.LabelReleases}}{{.Config.Navigation.LabelReleases}}{{else}}Releases{{end}}</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="dt-nav-link">{{if .Config.Navigation.LabelIssues}}{{.Config.Navigation.LabelIssues}}{{else}}Issues{{end}}</a>{{end}}
{{if .Config.ValueProps}}<a href="{{.LandingURL}}#value-props" class="dt-nav-link">{{if .Config.Navigation.LabelValueProps}}{{.Config.Navigation.LabelValueProps}}{{else}}Value Props{{end}}</a>{{end}}
{{if .Config.Features}}<a href="{{.LandingURL}}#features" class="dt-nav-link">{{if .Config.Navigation.LabelFeatures}}{{.Config.Navigation.LabelFeatures}}{{else}}Features{{end}}</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="{{.LandingURL}}#pricing" class="dt-nav-link">{{if .Config.Navigation.LabelPricing}}{{.Config.Navigation.LabelPricing}}{{else}}Pricing{{end}}</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}{{.LandingURL}}#blog{{end}}" class="dt-nav-link">{{if .Config.Navigation.LabelBlog}}{{.Config.Navigation.LabelBlog}}{{else}}Blog{{end}}</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="{{.LandingURL}}#gallery" class="dt-nav-link">{{if .Config.Navigation.LabelGallery}}{{.Config.Navigation.LabelGallery}}{{else}}Gallery{{end}}</a>{{end}}
{{if and .Config.Comparison.Enabled .Config.Comparison.HasData}}<a href="{{.LandingURL}}#comparison" class="dt-nav-link">{{if .Config.Navigation.LabelCompare}}{{.Config.Navigation.LabelCompare}}{{else}}Compare{{end}}</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="dt-nav-cta">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" 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="dt-menu-toggle" onclick="this.parentElement.querySelector('.dt-nav-links').style.display=this.parentElement.querySelector('.dt-nav-links').style.display==='flex'?'none':'flex'">
{{svg "octicon-three-bars" 20}}
</button>
</nav>
{{if .PageIsBlogDetail}}
<!-- Blog Detail View -->
<section class="dt-hero" style="padding-top: 100px; min-height: auto;">
<div class="dt-hero-content" style="max-width: 800px;">
{{if .BlogPost.FeaturedImage}}
<div style="margin: 0 auto 28px; border-radius: 4px; overflow: hidden; border: 1px solid var(--dt-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: 34px; margin-bottom: 8px;">{{.BlogPost.Title}}</h1>
{{if .BlogPost.Subtitle}}<p style="font-size: 1.15rem; color: var(--dt-muted); margin-bottom: 24px;">{{.BlogPost.Subtitle}}</p>{{end}}
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 40px; font-size: 13px; color: var(--dt-muted); font-family: 'JetBrains Mono', monospace;">
{{if .BlogPost.Author}}<span>{{.BlogPost.Author.DisplayName}}</span><span>&middot;</span>{{end}}
<span>{{DateUtils.AbsoluteShort .BlogPost.CreatedUnix}}</span>
{{if .BlogTags}}<span>&middot;</span>{{range .BlogTags}}<span style="background: var(--dt-elevated); border: 1px solid var(--dt-dim); padding: 2px 8px; border-radius: 3px; font-size: 11px;">{{.}}</span> {{end}}{{end}}
</div>
<div class="markup dt-blog-content" style="color: var(--dt-text); line-height: 1.8; font-size: 18px; text-align: left;">
{{.BlogRenderedContent}}
</div>
<div style="margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--dt-dim);">
<a href="{{.BlogBaseURL}}" class="dt-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="dt-features" style="padding-top: 100px;">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelBlog}}{{.Config.Navigation.LabelBlog}}{{else}}Blog{{end}}</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="dt-features-grid">
{{range .BlogListPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="dt-feature-card dt-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: 4px 4px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="dt-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="dt-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--dt-muted); font-family: 'JetBrains Mono', monospace;">
{{if .Author}}{{.Author.DisplayName}} &middot; {{end}}{{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if gt .BlogListTotal 9}}
<div style="text-align: center; margin-top: 40px;">
{{template "base/paginate" .}}
</div>
{{end}}
</div>
</section>
{{else}}
<!-- Hero Section -->
<section class="dt-hero" id="hero">
<div class="dt-hero-content">
<div class="dt-badge dt-reveal visible">
<span class="dt-badge-label">status</span>
<span class="dt-badge-dot"></span>
{{if .LatestRelease}}v{{.LatestReleaseTag}} passing{{else}}Open Source{{end}}
</div>
<h1 class="dt-reveal visible dt-reveal-delay-1">{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}</h1>
<p class="dt-hero-sub dt-reveal visible dt-reveal-delay-2">
{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}
</p>
<div class="dt-hero-ctas dt-reveal visible dt-reveal-delay-3">
{{if .Config.Hero.PrimaryCTA.Label}}
<a href="{{.Config.Hero.PrimaryCTA.URL}}" class="dt-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="dt-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="dt-reveal visible dt-reveal-delay-4">
{{if $.GooglePlayID}}
<a href="https://play.google.com/store/apps/details?id={{$.GooglePlayID}}" target="_blank" rel="noopener" class="dt-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="dt-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="dt-code-block dt-reveal visible dt-reveal-delay-4">
<span class="dt-code-prompt">$</span>
<code id="install-cmd">{{.Config.Hero.CodeExample}}</code>
<button class="dt-copy-btn" onclick="navigator.clipboard.writeText(document.getElementById('install-cmd').textContent)">
{{svg "octicon-copy" 14}}
</button>
</div>
{{end}}
</div>
</section>
<!-- Stats Section -->
{{if or .Config.Stats (gt .NumStars 0)}}
<section class="dt-stats" id="stats">
<div class="dt-stats-inner dt-reveal">
{{if .Config.Stats}}
{{range .Config.Stats}}
<div class="dt-stat-item">
<div class="dt-stat-value">{{.Value}}</div>
<div class="dt-stat-label">{{.Label}}</div>
</div>
{{end}}
{{else}}
<div class="dt-stat-item">
<div class="dt-stat-value">{{.NumStars}}</div>
<div class="dt-stat-label">Stars</div>
</div>
<div class="dt-stat-item">
<div class="dt-stat-value">{{.NumForks}}</div>
<div class="dt-stat-label">Forks</div>
</div>
{{if .LatestRelease}}
<div class="dt-stat-item">
<div class="dt-stat-value">v{{.LatestReleaseTag}}</div>
<div class="dt-stat-label">Latest</div>
</div>
{{end}}
{{end}}
</div>
</section>
{{end}}
<!-- Downloads Section -->
{{if and .PublicReleases .LatestRelease .LatestRelease.Attachments}}
<section class="dt-downloads" id="downloads">
<div class="dt-downloads-inner dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} Windows</h4>
<div class="dt-downloads-grid">
{{range $windowsFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-desktop" 16}} macOS</h4>
<div class="dt-downloads-grid">
{{range $macosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-terminal" 16}} Linux</h4>
<div class="dt-downloads-grid">
{{range $linuxFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} Android</h4>
<div class="dt-downloads-grid">
{{range $androidFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-device-mobile" 16}} iOS</h4>
<div class="dt-downloads-grid">
{{range $iosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-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(--dt-muted); font-family: 'JetBrains Mono', monospace; letter-spacing: 0.08em; text-transform: uppercase;">{{svg "octicon-file" 16}} Other</h4>
<div class="dt-downloads-grid">
{{range $otherFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="dt-download-item">{{svg "octicon-download" 16}} {{.Name}} <span class="dt-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Value Props Section -->
{{if .Config.ValueProps}}
<section class="dt-features" id="value-props">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelValueProps}}{{.Config.Navigation.LabelValueProps}}{{else}}Why choose us{{end}}</div>
<h2>{{if .Config.Navigation.LabelValueProps}}{{.Config.Navigation.LabelValueProps}}{{else}}{{if .Config.Brand.Name}}Why {{.Config.Brand.Name}}?{{else}}Why Choose Us{{end}}{{end}}</h2>
</div>
<div class="dt-features-grid">
{{range .Config.ValueProps}}
<div class="dt-feature-card dt-reveal">
<div class="dt-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "check")) 20}}
</div>
<h3 class="dt-feature-title">{{.Title}}</h3>
<p class="dt-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Features Section -->
{{if .Config.Features}}
<section class="dt-features" id="features" style="padding-top: 40px;">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelFeatures}}{{.Config.Navigation.LabelFeatures}}{{else}}Capabilities{{end}}</div>
<h2>{{if .Config.Navigation.LabelFeatures}}{{.Config.Navigation.LabelFeatures}}{{else}}Features{{end}}</h2>
</div>
<div class="dt-features-grid">
{{range .Config.Features}}
<div class="dt-feature-card dt-reveal">
<div class="dt-feature-icon">
{{svg (printf "octicon-%s" (or .Icon "zap")) 20}}
</div>
<h3 class="dt-feature-title">{{.Title}}</h3>
<p class="dt-feature-desc">{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Social Proof -->
{{if or .Config.SocialProof.Logos .Config.SocialProof.Testimonials}}
<section class="dt-social-proof" id="social-proof">
<div class="dt-social-proof-inner">
{{if .Config.SocialProof.Logos}}
<div class="dt-logos dt-reveal">
{{range .Config.SocialProof.Logos}}
<div class="dt-logo-item">{{.}}</div>
{{end}}
</div>
{{end}}
{{if .Config.SocialProof.Testimonials}}
<div class="dt-testimonials-container">
{{range .Config.SocialProof.Testimonials}}
<div class="dt-testimonial dt-reveal" style="display: none;">
<p class="dt-testimonial-quote">"{{.Quote}}"</p>
<div>
<div class="dt-testimonial-author">{{.Author}}</div>
<div class="dt-testimonial-role">{{.Role}}</div>
</div>
</div>
{{end}}
</div>
<script>
(function() {
var testimonials = document.querySelectorAll(".dt-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="dt-pricing" id="pricing">
<div class="dt-pricing-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelPricing}}{{.Config.Navigation.LabelPricing}}{{else}}Pricing{{end}}</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="dt-pricing-grid">
{{range .Config.Pricing.Plans}}
<div class="dt-pricing-card{{if .Featured}} featured{{end}} dt-reveal">
{{if .Featured}}<span class="dt-pricing-badge">Popular</span>{{end}}
<div class="dt-pricing-name">{{.Name}}</div>
<div class="dt-pricing-price">{{.Price}}</div>
<div class="dt-pricing-period">{{.Period}}</div>
{{if .Features}}
<ul class="dt-pricing-features">
{{range .Features}}<li>{{.}}</li>{{end}}
</ul>
{{end}}
<a href="#" class="dt-pricing-cta">{{if .CTA}}{{.CTA}}{{else}}Get Started{{end}}</a>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- CTA Section -->
{{if .Config.CTASection.Headline}}
<section class="dt-cta-section" id="cta">
<div class="dt-cta-inner dt-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="dt-btn-primary" data-cta="primary" style="padding: 14px 28px; font-size: 14px;">
{{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="dt-features" id="blog" style="border-top: 1px solid var(--dt-dim);">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelBlog}}{{.Config.Navigation.LabelBlog}}{{else}}Blog{{end}}</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="dt-features-grid">
{{range .BlogPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="dt-feature-card dt-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: 4px 4px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 class="dt-feature-title">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p class="dt-feature-desc">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 11px; color: var(--dt-muted); font-family: 'JetBrains Mono', monospace;">
{{if .Author}}{{.Author.DisplayName}}{{end}} · {{DateUtils.AbsoluteShort .CreatedUnix}}
</div>
</a>
{{end}}
</div>
{{if .Config.Blog.CTAButton.Label}}
<div style="text-align: center; margin-top: 40px;" class="dt-reveal">
<a href="{{if .Config.Blog.CTAButton.URL}}{{.Config.Blog.CTAButton.URL}}{{else}}{{.BlogBaseURL}}{{end}}" class="dt-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="dt-features" id="gallery" style="border-top: 1px solid var(--dt-dim);">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelGallery}}{{.Config.Navigation.LabelGallery}}{{else}}Gallery{{end}}</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: 16px;">
{{range .GalleryImages}}
<div class="dt-feature-card dt-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: 14px 18px; font-size: 12px; color: var(--dt-muted); font-family: 'JetBrains Mono', monospace;">{{.Caption}}</div>
{{end}}
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Comparison Section -->
{{if and .Config.Comparison.Enabled .Config.Comparison.HasData}}
<section class="dt-features" id="comparison" style="border-top: 1px solid var(--dt-dim);">
<div class="dt-features-inner">
<div class="dt-section-header dt-reveal">
<div class="dt-section-label">{{if .Config.Navigation.LabelCompare}}{{.Config.Navigation.LabelCompare}}{{else}}Compare{{end}}</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="dt-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(--dt-dim); color: var(--dt-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(--dt-dim); font-weight: 600; font-size: 15px;{{if .Highlight}} color: var(--dt-accent);{{else}} color: var(--dt-text);{{end}}">
{{.Name}}
{{if .Highlight}}<div style="width: 40px; height: 3px; background: var(--dt-accent); 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(--dt-muted); border-bottom: 1px solid var(--dt-dim);">{{.Name}}</td>
</tr>
{{end}}
{{range .Features}}
<tr style="border-bottom: 1px solid rgba(255,255,255,0.04);">
<td style="padding: 14px 20px; color: var(--dt-text);">{{.Name}}</td>
{{range .Values}}
<td style="text-align: center; padding: 14px 20px;">
{{if eq . "true"}}<span style="color: var(--dt-accent);">{{svg "octicon-check-circle-fill" 18}}</span>
{{else if eq . "false"}}<span style="color: var(--dt-dim);">{{svg "octicon-x-circle" 18}}</span>
{{else}}<span style="color: var(--dt-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="dt-footer">
<div class="dt-footer-brand">
<div class="dt-footer-logo">{{svg "octicon-terminal" 10}}</div>
<span class="dt-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="dt-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="dt-footer-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="dt-footer-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowRepository}}<a href="{{.RepoURL}}" class="dt-footer-link">Repository</a>{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="dt-footer-link">Documentation</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="dt-footer-link">{{if .Config.Navigation.LabelReleases}}{{.Config.Navigation.LabelReleases}}{{else}}Releases{{end}}</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="dt-footer-link">{{if .Config.Navigation.LabelIssues}}{{.Config.Navigation.LabelIssues}}{{else}}Issues{{end}}</a>{{end}}
</div>
</footer>
</div>
<!-- Scroll reveal observer -->
<script>
(function() {
var reveals = document.querySelectorAll('.dt-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" .}}