2
0
Files
gitcaddy-server/templates/pages/saas-conversion.tmpl
logikonline 433214fb91
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 2m56s
Build and Release / Unit Tests (push) Successful in 8m52s
Build and Release / Lint (push) Successful in 9m21s
Build and Release / Build Binaries (amd64, darwin, macos) (push) Failing after 1s
Build and Release / Build Binaries (arm64, darwin, macos) (push) Failing after 1s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 4m54s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 9h5m27s
Build and Release / Build Binary (linux/arm64) (push) Failing after 13m25s
feat(pages): add app store links to downloads section
Add GooglePlayID and AppStoreID config fields to display app store download buttons on landing pages. Shows "App Stores" section with Google Play and/or App Store badges when IDs are configured. Useful for mobile apps distributed via stores instead of direct downloads. Includes branded SVG icons for both stores. Applies to all four page templates.
2026-03-16 02:04:33 -04:00

1661 lines
50 KiB
Handlebars

{{template "pages/base_head" .}}
<style>
@import url('https://fonts.googleapis.com/css2?family=General+Sans:wght@400;500;600;700&family=Instrument+Serif:ital@0;1&display=swap');
:root {
--gm-bg: #0a0a12;
--gm-surface: rgba(255, 255, 255, 0.03);
--gm-glass: rgba(255, 255, 255, 0.06);
--gm-glass-border: rgba(255, 255, 255, 0.08);
--gm-text: #f0eef5;
--gm-muted: rgba(240, 238, 245, 0.6);
--gm-light: rgba(240, 238, 245, 0.35);
--gm-primary: {{if .Config.Theme.PrimaryColor}}{{.Config.Theme.PrimaryColor}}{{else}}#7dd3fc{{end}};
--gm-secondary: {{if .Config.Theme.AccentColor}}{{.Config.Theme.AccentColor}}{{else}}#c4b5fd{{end}};
--gm-aurora-1: var(--gm-primary);
--gm-aurora-2: var(--gm-secondary);
--gm-aurora-3: #34d399;
}
/* Scroll reveal */
.gm-reveal {
opacity: 0;
transform: translateY(28px);
transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1), transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.gm-reveal.visible {
opacity: 1;
transform: translateY(0);
}
.gm-reveal-delay-1 { transition-delay: 0.12s; }
.gm-reveal-delay-2 { transition-delay: 0.24s; }
.gm-reveal-delay-3 { transition-delay: 0.36s; }
.gm-page {
min-height: 100vh;
background: var(--gm-bg);
color: var(--gm-text);
font-family: 'General Sans', -apple-system, sans-serif;
line-height: 1.6;
overflow-x: hidden;
position: relative;
}
/* Aurora background */
.gm-aurora {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
overflow: hidden;
}
.gm-aurora-orb {
position: absolute;
border-radius: 50%;
filter: blur(120px);
opacity: 0.3;
animation: gm-drift 20s ease-in-out infinite;
}
.gm-aurora-orb-1 {
width: 600px;
height: 600px;
background: var(--gm-aurora-1);
top: -10%;
left: -10%;
opacity: 0.15;
}
.gm-aurora-orb-2 {
width: 500px;
height: 500px;
background: var(--gm-aurora-2);
top: 30%;
right: -15%;
opacity: 0.12;
animation-delay: -7s;
animation-duration: 25s;
}
.gm-aurora-orb-3 {
width: 400px;
height: 400px;
background: var(--gm-aurora-3);
bottom: 10%;
left: 20%;
opacity: 0.1;
animation-delay: -14s;
animation-duration: 22s;
}
@keyframes gm-drift {
0%, 100% { transform: translate(0, 0) scale(1); }
25% { transform: translate(40px, -30px) scale(1.05); }
50% { transform: translate(-20px, 40px) scale(0.95); }
75% { transform: translate(30px, 20px) scale(1.02); }
}
/* Noise overlay */
.gm-page::before {
content: '';
position: fixed;
inset: 0;
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 1;
}
/* Glass panel mixin */
.gm-glass-panel {
background: var(--gm-glass);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid var(--gm-glass-border);
border-radius: 20px;
}
/* --- Navigation --- */
.gm-nav {
position: fixed;
top: 16px;
left: 16px;
right: 16px;
padding: 14px 28px;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(10, 10, 18, 0.6);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--gm-glass-border);
border-radius: 16px;
z-index: 100;
}
.gm-nav-brand {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
}
.gm-nav-logo {
width: 32px;
height: 32px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: var(--gm-bg);
}
.gm-nav-name {
font-weight: 700;
font-size: 18px;
color: var(--gm-text);
}
.gm-nav-links {
display: flex;
align-items: center;
gap: 32px;
}
.gm-nav-link {
color: var(--gm-muted);
text-decoration: none;
font-weight: 500;
font-size: 14px;
transition: color 0.3s ease;
}
.gm-nav-link:hover {
color: var(--gm-text);
}
.gm-nav-repo {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--gm-muted);
text-decoration: none;
font-weight: 500;
font-size: 14px;
transition: color 0.3s ease;
}
.gm-nav-repo:hover {
color: var(--gm-text);
}
/* Mobile toggle */
.gm-mobile-toggle {
display: none;
background: var(--gm-glass);
border: 1px solid var(--gm-glass-border);
border-radius: 8px;
padding: 8px 14px;
cursor: pointer;
color: var(--gm-text);
font-family: 'General Sans', sans-serif;
font-size: 13px;
font-weight: 500;
}
.gm-mobile-menu {
display: none;
position: fixed;
top: 80px;
left: 16px;
right: 16px;
background: rgba(10, 10, 18, 0.9);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid var(--gm-glass-border);
border-radius: 16px;
padding: 24px;
z-index: 99;
flex-direction: column;
gap: 16px;
}
.gm-mobile-menu.open {
display: flex;
}
/* --- Buttons --- */
.gm-btn-primary {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 14px 28px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
color: var(--gm-bg);
font-weight: 600;
font-size: 15px;
border-radius: 12px;
text-decoration: none;
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
border: none;
cursor: pointer;
position: relative;
overflow: hidden;
}
.gm-btn-primary::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, var(--gm-aurora-2) 0%, var(--gm-aurora-3) 100%);
opacity: 0;
transition: opacity 0.4s ease;
border-radius: 12px;
}
.gm-btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 32px color-mix(in srgb, var(--gm-primary) 25%, transparent);
}
.gm-btn-primary:hover::before {
opacity: 1;
}
.gm-btn-primary span {
position: relative;
z-index: 1;
display: inline-flex;
align-items: center;
gap: 10px;
}
.gm-btn-secondary {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 14px 28px;
background: var(--gm-glass);
color: var(--gm-text);
font-weight: 600;
font-size: 15px;
border-radius: 12px;
text-decoration: none;
border: 1px solid var(--gm-glass-border);
transition: all 0.3s ease;
cursor: pointer;
backdrop-filter: blur(12px);
}
.gm-btn-secondary:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.15);
transform: translateY(-2px);
}
/* --- Hero --- */
.gm-hero {
position: relative;
z-index: 2;
min-height: 100vh;
display: flex;
align-items: center;
padding: 140px 48px 100px;
}
.gm-hero-inner {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 80px;
max-width: 1280px;
margin: 0 auto;
align-items: center;
}
.gm-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: color-mix(in srgb, var(--gm-primary) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--gm-primary) 20%, transparent);
border-radius: 100px;
margin-bottom: 28px;
font-size: 13px;
font-weight: 600;
color: var(--gm-aurora-1);
}
.gm-hero h1 {
font-size: clamp(40px, 5.5vw, 60px);
font-weight: 700;
line-height: 1.1;
margin-bottom: 24px;
color: var(--gm-text);
letter-spacing: -0.02em;
}
.gm-hero h1 .gm-serif {
font-family: 'Instrument Serif', Georgia, serif;
font-weight: 400;
font-style: italic;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gm-hero-sub {
font-size: 18px;
color: var(--gm-muted);
line-height: 1.7;
margin-bottom: 36px;
max-width: 500px;
}
.gm-hero-ctas {
display: flex;
gap: 16px;
margin-bottom: 36px;
}
.gm-hero-note {
display: flex;
gap: 20px;
font-size: 13px;
color: var(--gm-light);
}
.gm-hero-note span {
display: inline-flex;
align-items: center;
gap: 6px;
}
/* Hero glass mockup */
.gm-hero-mockup {
border-radius: 24px;
padding: 24px;
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--gm-glass-border);
position: relative;
}
.gm-hero-mockup::after {
content: '';
position: absolute;
inset: -1px;
border-radius: 24px;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 15%, transparent) 0%, transparent 40%, transparent 60%, color-mix(in srgb, var(--gm-secondary) 15%, transparent) 100%);
z-index: -1;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
-webkit-mask-composite: xor;
padding: 1px;
}
.gm-mockup-bar {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.gm-mockup-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.15);
}
.gm-mockup-content {
display: flex;
flex-direction: column;
gap: 14px;
}
.gm-mockup-row {
height: 28px;
background: rgba(255, 255, 255, 0.04);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.04);
}
.gm-mockup-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.gm-mockup-cell {
height: 72px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.04);
}
.gm-mockup-cell:nth-child(1) {
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 15%, transparent) 0%, color-mix(in srgb, var(--gm-secondary) 10%, transparent) 100%);
}
.gm-mockup-cell:nth-child(2) {
background: rgba(255, 255, 255, 0.03);
}
.gm-mockup-cell:nth-child(3) {
background: rgba(255, 255, 255, 0.03);
}
.gm-mockup-bar-chart {
height: 100px;
background: linear-gradient(180deg, color-mix(in srgb, var(--gm-primary) 8%, transparent) 0%, color-mix(in srgb, var(--gm-aurora-3) 4%, transparent) 100%);
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.04);
}
/* --- Stats --- */
.gm-stats {
position: relative;
z-index: 2;
padding: 60px 48px;
}
.gm-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 16px;
max-width: 900px;
margin: 0 auto;
}
.gm-stat-card {
text-align: center;
padding: 32px 20px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 16px;
transition: all 0.3s ease;
}
.gm-stat-card:hover {
background: rgba(255, 255, 255, 0.08);
transform: translateY(-2px);
}
.gm-stat-value {
font-size: 36px;
font-weight: 700;
margin-bottom: 4px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gm-stat-label {
font-size: 13px;
color: var(--gm-light);
text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: 500;
}
/* --- Downloads --- */
.gm-downloads {
position: relative;
z-index: 2;
padding: 60px 48px;
}
.gm-downloads-inner {
max-width: 900px;
margin: 0 auto;
}
.gm-downloads-header {
text-align: center;
margin-bottom: 28px;
}
.gm-downloads-header h2 {
font-size: 28px;
font-weight: 700;
margin-bottom: 8px;
color: var(--gm-text);
}
.gm-downloads-header p {
font-size: 15px;
color: var(--gm-muted);
}
.gm-downloads-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 12px;
}
.gm-download-item {
display: flex;
align-items: center;
gap: 14px;
padding: 20px 24px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 14px;
color: var(--gm-text);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
}
.gm-download-item:hover {
background: rgba(255, 255, 255, 0.1);
border-color: color-mix(in srgb, var(--gm-primary) 30%, transparent);
transform: translateY(-2px);
}
.gm-download-size {
margin-left: auto;
font-size: 12px;
color: var(--gm-light);
}
/* --- Trust bar --- */
.gm-trust {
position: relative;
z-index: 2;
padding: 48px;
}
.gm-trust-label {
text-align: center;
font-size: 12px;
color: var(--gm-light);
margin-bottom: 24px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.12em;
}
.gm-trust-bar {
display: flex;
align-items: center;
justify-content: center;
gap: 48px;
flex-wrap: wrap;
padding: 28px 40px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 16px;
max-width: 900px;
margin: 0 auto;
}
.gm-trust-logo {
font-size: 16px;
font-weight: 600;
color: var(--gm-light);
transition: color 0.3s ease;
}
.gm-trust-logo:hover {
color: var(--gm-muted);
}
/* --- Sections --- */
.gm-section {
position: relative;
z-index: 2;
padding: 100px 48px;
}
.gm-section-inner {
max-width: 1200px;
margin: 0 auto;
}
.gm-section-header {
text-align: center;
margin-bottom: 64px;
}
.gm-section-header h2 {
font-size: clamp(32px, 4vw, 48px);
font-weight: 700;
margin-bottom: 16px;
color: var(--gm-text);
letter-spacing: -0.02em;
}
.gm-section-header h2 .gm-serif {
font-family: 'Instrument Serif', Georgia, serif;
font-weight: 400;
font-style: italic;
}
.gm-section-header p {
font-size: 17px;
color: var(--gm-muted);
max-width: 500px;
margin: 0 auto;
}
/* --- Value props grid --- */
.gm-value-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 16px;
}
.gm-value-card {
padding: 36px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 20px;
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
position: relative;
overflow: hidden;
}
.gm-value-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, var(--gm-aurora-1), var(--gm-aurora-2), var(--gm-aurora-3));
opacity: 0;
transition: opacity 0.4s ease;
}
.gm-value-card:hover {
transform: translateY(-4px);
background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.12);
}
.gm-value-card:hover::before {
opacity: 1;
}
.gm-value-card h3 {
font-size: 22px;
font-weight: 600;
margin-bottom: 10px;
color: var(--gm-text);
}
.gm-value-card p {
font-size: 15px;
color: var(--gm-muted);
line-height: 1.7;
}
/* --- Features --- */
.gm-features-list {
display: flex;
flex-direction: column;
gap: 16px;
max-width: 900px;
margin: 0 auto;
}
.gm-feature-step {
display: flex;
gap: 20px;
padding: 28px 32px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 16px;
transition: all 0.3s ease;
align-items: flex-start;
}
.gm-feature-step:hover {
background: rgba(255, 255, 255, 0.08);
border-color: color-mix(in srgb, var(--gm-primary) 20%, transparent);
transform: translateX(4px);
}
.gm-step-icon {
width: 44px;
height: 44px;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 15%, transparent) 0%, color-mix(in srgb, var(--gm-secondary) 15%, transparent) 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: var(--gm-aurora-1);
flex-shrink: 0;
}
.gm-feature-step h3 {
font-size: 18px;
font-weight: 600;
margin-bottom: 6px;
color: var(--gm-text);
}
.gm-feature-step p {
font-size: 15px;
color: var(--gm-muted);
line-height: 1.6;
}
/* --- Testimonials --- */
.gm-testimonial-card {
padding: 48px;
background: var(--gm-glass);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid var(--gm-glass-border);
border-radius: 24px;
max-width: 800px;
margin: 0 auto;
position: relative;
}
.gm-testimonial-card::before {
content: '';
position: absolute;
inset: -1px;
border-radius: 24px;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 12%, transparent) 0%, transparent 40%, transparent 60%, color-mix(in srgb, var(--gm-aurora-3) 12%, transparent) 100%);
z-index: -1;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
-webkit-mask-composite: xor;
padding: 1px;
}
.gm-testimonial-quote-mark {
font-family: 'Instrument Serif', Georgia, serif;
font-size: 80px;
font-style: italic;
line-height: 0.8;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
opacity: 0.3;
margin-bottom: 8px;
}
.gm-testimonial-quote {
font-size: 22px;
line-height: 1.7;
color: var(--gm-text);
margin-bottom: 28px;
}
.gm-testimonial-author {
display: flex;
align-items: center;
gap: 16px;
}
.gm-testimonial-avatar {
width: 48px;
height: 48px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
border-radius: 50%;
overflow: hidden;
}
.gm-testimonial-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.gm-testimonial-name {
font-weight: 600;
font-size: 15px;
color: var(--gm-text);
}
.gm-testimonial-role {
font-size: 13px;
color: var(--gm-muted);
}
/* --- Pricing --- */
.gm-pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
align-items: start;
max-width: 1100px;
margin: 0 auto;
}
.gm-pricing-card {
padding: 36px;
background: var(--gm-glass);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--gm-glass-border);
border-radius: 20px;
transition: all 0.3s ease;
}
.gm-pricing-card:hover {
border-color: rgba(255, 255, 255, 0.12);
}
.gm-pricing-card.featured {
border-color: color-mix(in srgb, var(--gm-primary) 30%, transparent);
background: color-mix(in srgb, var(--gm-primary) 6%, transparent);
position: relative;
}
.gm-pricing-card.featured::before {
content: '';
position: absolute;
inset: -1px;
border-radius: 20px;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 25%, transparent) 0%, color-mix(in srgb, var(--gm-secondary) 25%, transparent) 100%);
z-index: -1;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
-webkit-mask-composite: xor;
padding: 1px;
}
.gm-pricing-badge {
display: inline-block;
padding: 6px 14px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
color: var(--gm-bg);
font-size: 11px;
font-weight: 700;
border-radius: 100px;
margin-bottom: 16px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.gm-pricing-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
color: var(--gm-text);
}
.gm-pricing-price {
font-size: 48px;
font-weight: 700;
color: var(--gm-text);
letter-spacing: -0.02em;
}
.gm-pricing-period {
color: var(--gm-muted);
font-size: 14px;
}
.gm-pricing-features {
list-style: none;
padding: 0;
margin: 24px 0 28px;
}
.gm-pricing-features li {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
color: var(--gm-muted);
font-size: 14px;
}
.gm-pricing-check {
color: var(--gm-aurora-3);
flex-shrink: 0;
}
/* --- CTA --- */
.gm-cta-gradient {
border-radius: 28px;
padding: 80px;
text-align: center;
max-width: 1100px;
margin: 0 auto;
position: relative;
overflow: hidden;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 12%, transparent) 0%, color-mix(in srgb, var(--gm-secondary) 12%, transparent) 50%, color-mix(in srgb, var(--gm-aurora-3) 12%, transparent) 100%);
border: 1px solid var(--gm-glass-border);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
.gm-cta-gradient::before {
content: '';
position: absolute;
inset: -1px;
border-radius: 28px;
background: linear-gradient(135deg, color-mix(in srgb, var(--gm-primary) 20%, transparent) 0%, transparent 30%, transparent 70%, color-mix(in srgb, var(--gm-aurora-3) 20%, transparent) 100%);
z-index: -1;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
-webkit-mask-composite: xor;
padding: 1px;
}
.gm-cta-gradient h2 {
font-size: clamp(32px, 4vw, 48px);
font-weight: 700;
margin-bottom: 16px;
position: relative;
z-index: 1;
letter-spacing: -0.02em;
}
.gm-cta-gradient p {
font-size: 18px;
color: var(--gm-muted);
margin-bottom: 32px;
position: relative;
z-index: 1;
}
/* --- Footer --- */
.gm-footer {
position: relative;
z-index: 2;
padding: 40px 48px;
border-top: 1px solid var(--gm-glass-border);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 24px;
}
.gm-footer-brand {
display: flex;
align-items: center;
gap: 10px;
}
.gm-footer-logo {
width: 24px;
height: 24px;
background: linear-gradient(135deg, var(--gm-aurora-1) 0%, var(--gm-aurora-2) 100%);
border-radius: 6px;
}
.gm-footer-copyright {
font-size: 13px;
color: var(--gm-light);
}
.gm-footer-links {
display: flex;
gap: 28px;
flex-wrap: wrap;
}
.gm-footer-link {
color: var(--gm-light);
text-decoration: none;
font-size: 13px;
transition: color 0.3s ease;
}
.gm-footer-link:hover {
color: var(--gm-text);
}
.gm-footer-social {
display: flex;
gap: 16px;
}
.gm-footer-social a {
color: var(--gm-light);
transition: color 0.3s ease;
}
.gm-footer-social a:hover {
color: var(--gm-aurora-1);
}
/* --- Responsive --- */
@media (max-width: 1024px) {
.gm-hero-inner { grid-template-columns: 1fr; }
.gm-hero-mockup { display: none; }
.gm-pricing-grid { max-width: 420px; margin: 0 auto; }
}
@media (max-width: 768px) {
.gm-nav { top: 8px; left: 8px; right: 8px; padding: 12px 20px; }
.gm-nav-links { display: none; }
.gm-mobile-toggle { display: block; }
.gm-hero { padding: 120px 24px 80px; }
.gm-hero h1 { font-size: 36px; }
.gm-hero-ctas { flex-direction: column; }
.gm-hero-note { flex-direction: column; gap: 8px; }
.gm-section { padding: 64px 24px; }
.gm-stats { padding: 40px 24px; }
.gm-trust { padding: 32px 24px; }
.gm-cta-gradient { padding: 48px 24px; border-radius: 20px; }
.gm-downloads { padding: 40px 24px; }
.gm-footer { flex-direction: column; text-align: center; padding: 32px 24px; }
.gm-value-grid { grid-template-columns: 1fr; }
.gm-pricing-grid { grid-template-columns: 1fr; }
}
/* Blog content markdown styles */
.gm-blog-content h1, .gm-blog-content h2, .gm-blog-content h3, .gm-blog-content h4 {
color: var(--gm-text); margin: 1.5em 0 0.5em;
}
.gm-blog-content h2 { font-size: 1.5em; border-bottom: 1px solid var(--gm-glass-border); padding-bottom: 8px; }
.gm-blog-content h3 { font-size: 1.25em; }
.gm-blog-content a { color: var(--gm-primary); text-decoration: underline; }
.gm-blog-content a:hover { opacity: 0.8; }
.gm-blog-content code { background: var(--gm-glass); padding: 2px 6px; border-radius: 4px; font-size: 0.9em; }
.gm-blog-content pre { background: rgba(0,0,0,0.3); border: 1px solid var(--gm-glass-border); border-radius: 8px; padding: 16px; overflow-x: auto; margin: 16px 0; }
.gm-blog-content pre code { background: none; padding: 0; }
.gm-blog-content blockquote { border-left: 3px solid var(--gm-primary); padding-left: 16px; color: var(--gm-muted); margin: 16px 0; font-style: italic; }
.gm-blog-content img { max-width: 100%; border-radius: 8px; margin: 16px 0; }
.gm-blog-content ul, .gm-blog-content ol { padding-left: 24px; margin: 12px 0; }
.gm-blog-content li { margin: 4px 0; }
.gm-blog-content table { border-collapse: collapse; width: 100%; margin: 16px 0; }
.gm-blog-content th, .gm-blog-content td { border: 1px solid var(--gm-glass-border); padding: 8px 12px; text-align: left; }
.gm-blog-content th { background: var(--gm-glass); font-weight: 600; }
.gm-blog-content hr { border: none; border-top: 1px solid var(--gm-glass-border); margin: 24px 0; }
</style>
<div class="gm-page">
<!-- Aurora background -->
<div class="gm-aurora">
<div class="gm-aurora-orb gm-aurora-orb-1"></div>
<div class="gm-aurora-orb gm-aurora-orb-2"></div>
<div class="gm-aurora-orb gm-aurora-orb-3"></div>
</div>
<!-- Navigation -->
<nav class="gm-nav">
<a href="/" class="gm-nav-brand">
{{if .LogoURL}}
<img src="{{.LogoURL}}" alt="{{.Config.Brand.Name}}" style="height: 32px; border-radius: 6px;">
{{else}}
<div class="gm-nav-logo">
{{svg "octicon-package" 16}}
</div>
{{end}}
<span class="gm-nav-name">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</span>
</a>
<div class="gm-nav-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="gm-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="gm-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="gm-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="gm-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="gm-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="#value-props" class="gm-nav-link">Why</a>{{end}}
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="gm-nav-link">Gallery</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="gm-nav-repo">
<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}}
<a href="{{if .Config.Hero.PrimaryCTA.URL}}{{.Config.Hero.PrimaryCTA.URL}}{{else}}{{.RepoURL}}{{end}}" class="gm-btn-primary" data-cta="primary" style="padding: 10px 20px; font-size: 13px;">
<span>{{if .Config.Hero.PrimaryCTA.Label}}{{.Config.Hero.PrimaryCTA.Label}}{{else}}Get Started{{end}}</span>
</a>
</div>
<button class="gm-mobile-toggle" onclick="document.getElementById('gm-mobile-nav').classList.toggle('open')">Menu</button>
</nav>
<div class="gm-mobile-menu" id="gm-mobile-nav">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="gm-nav-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="gm-nav-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowAPI}}<a href="{{.RepoURL}}/swagger" class="gm-nav-link">API</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="gm-nav-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="gm-nav-link">Issues</a>{{end}}
{{if .Config.ValueProps}}<a href="#value-props" class="gm-nav-link">Why</a>{{end}}
{{if .Config.Features}}<a href="#features" class="gm-nav-link">Features</a>{{end}}
{{if .Config.Pricing.Plans}}<a href="#pricing" class="gm-nav-link">Pricing</a>{{end}}
{{if .Config.Blog.Enabled}}<a href="{{if .BlogBaseURL}}{{.BlogBaseURL}}{{else}}#blog{{end}}" class="gm-nav-link">Blog</a>{{end}}
{{if .Config.Gallery.Enabled}}<a href="#gallery" class="gm-nav-link">Gallery</a>{{end}}
{{if .Config.Navigation.ShowRepository}}
<a href="{{.RepoURL}}" class="gm-nav-repo">
<img src="/assets/img/gitcaddy-icon.svg" width="16" height="16" alt="GitCaddy">
Repository
</a>
{{end}}
</div>
{{if .PageIsBlogDetail}}
<!-- Blog Detail View -->
<section class="gm-hero" style="padding-top: 120px; min-height: auto;">
<div class="gm-hero-inner" style="max-width: 800px;">
{{if .BlogPost.FeaturedImage}}
<div style="margin-bottom: 32px; border-radius: 12px; overflow: hidden;">
<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: 36px; margin-bottom: 8px;">{{.BlogPost.Title}}</h1>
{{if .BlogPost.Subtitle}}<p style="font-size: 1.2rem; color: var(--gm-muted); margin-bottom: 24px;">{{.BlogPost.Subtitle}}</p>{{end}}
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 48px; font-size: 14px; color: var(--gm-muted);">
{{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(--gm-glass); border: 1px solid var(--gm-glass-border); padding: 2px 8px; border-radius: 20px; font-size: 12px;">{{.}}</span> {{end}}{{end}}
</div>
<div class="markup gm-blog-content" style="color: var(--gm-text); line-height: 1.8; font-size: 16px; text-align: left;">
{{.BlogRenderedContent}}
</div>
<div style="margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--gm-glass-border);">
<a href="{{.BlogBaseURL}}" class="gm-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="gm-section" style="padding-top: 120px;">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<div class="gm-section-eyebrow">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="gm-value-grid">
{{range .BlogListPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="gm-value-card gm-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -32px -32px 20px -32px; overflow: hidden; border-radius: 16px 16px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3 style="font-size: 1.1rem; margin-bottom: 8px;">{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p style="color: var(--gm-muted); font-size: 14px; margin-bottom: 8px;">{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 12px; font-size: 12px; color: var(--gm-light);">
{{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="gm-hero">
<div class="gm-hero-inner">
<div>
{{if gt .NumStars 100}}
<div class="gm-badge gm-reveal">
{{svg "octicon-star-fill" 14}}
<span>{{.NumStars}} stars</span>
</div>
{{end}}
<h1 class="gm-reveal gm-reveal-delay-1">{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}</h1>
<p class="gm-hero-sub gm-reveal gm-reveal-delay-2">
{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}
</p>
<div class="gm-hero-ctas gm-reveal gm-reveal-delay-3">
<a href="{{if .Config.Hero.PrimaryCTA.URL}}{{.Config.Hero.PrimaryCTA.URL}}{{else}}{{.RepoURL}}{{end}}" class="gm-btn-primary" data-cta="primary">
<span>
{{if .Config.Hero.PrimaryCTA.Label}}{{.Config.Hero.PrimaryCTA.Label}}{{else}}Get Started{{end}}
{{svg "octicon-arrow-right" 16}}
</span>
</a>
{{if .Config.Hero.SecondaryCTA.Label}}
<a href="{{.Config.Hero.SecondaryCTA.URL}}" class="gm-btn-secondary" data-cta="secondary">
{{svg "octicon-play" 16}}
{{.Config.Hero.SecondaryCTA.Label}}
</a>
{{end}}
</div>
<div class="gm-hero-note gm-reveal gm-reveal-delay-3">
<span>{{svg "octicon-check" 14}} Free to use</span>
<span>{{svg "octicon-check" 14}} Open source</span>
<span>{{svg "octicon-check" 14}} MIT License</span>
</div>
</div>
<div class="gm-hero-mockup gm-reveal gm-reveal-delay-2">
<div class="gm-mockup-bar">
<div class="gm-mockup-dot"></div>
<div class="gm-mockup-dot"></div>
<div class="gm-mockup-dot"></div>
</div>
<div class="gm-mockup-content">
<div class="gm-mockup-row" style="width: 55%;"></div>
<div class="gm-mockup-grid">
<div class="gm-mockup-cell"></div>
<div class="gm-mockup-cell"></div>
<div class="gm-mockup-cell"></div>
</div>
<div class="gm-mockup-bar-chart"></div>
</div>
</div>
</div>
</section>
<!-- Stats Section -->
{{if .Config.Stats}}
<section class="gm-stats">
<div class="gm-stats-grid">
{{range .Config.Stats}}
<div class="gm-stat-card gm-reveal">
<div class="gm-stat-value">{{.Value}}</div>
<div class="gm-stat-label">{{.Label}}</div>
</div>
{{end}}
</div>
</section>
{{end}}
{{if and .PublicReleases .LatestRelease .LatestRelease.Attachments}}
<section class="gm-downloads">
<div class="gm-downloads-inner">
<div class="gm-downloads-header gm-reveal">
<h2>Download v{{.LatestReleaseTag}}</h2>
<p>Get the latest release</p>
</div>
{{$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: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-device-desktop" 16}} Windows</h4>
<div class="gm-downloads-grid">
{{range $windowsFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-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: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-device-desktop" 16}} macOS</h4>
<div class="gm-downloads-grid">
{{range $macosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-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: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-terminal" 16}} Linux</h4>
<div class="gm-downloads-grid">
{{range $linuxFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-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: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-device-mobile" 16}} Android</h4>
<div class="gm-downloads-grid">
{{range $androidFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-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: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-device-mobile" 16}} iOS</h4>
<div class="gm-downloads-grid">
{{range $iosFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
{{end}}
{{if or $.GooglePlayID $.AppStoreID}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-device-mobile" 16}} App Stores</h4>
<div style="display: flex; gap: 12px; flex-wrap: wrap;">
{{if $.GooglePlayID}}
<a href="https://play.google.com/store/apps/details?id={{$.GooglePlayID}}" target="_blank" rel="noopener" class="gm-download-item gm-reveal" 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="gm-download-item gm-reveal" 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>
</div>
{{end}}
{{if $otherFiles}}
<div style="margin-bottom: 24px;">
<h4 style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 14px; color: var(--gm-light); font-weight: 600;">{{svg "octicon-file" 16}} Other</h4>
<div class="gm-downloads-grid">
{{range $otherFiles}}<a href="{{$.RepoURL}}/releases/download/{{$.LatestRelease.TagName}}/{{.Name}}" class="gm-download-item gm-reveal">{{svg "octicon-download" 16}} {{.Name}} <span class="gm-download-size">{{FileSize .Size}}</span></a>{{end}}
</div>
</div>
{{end}}
</div>
</section>
{{end}}
<!-- Trust Bar -->
{{if .Config.SocialProof.Logos}}
<section class="gm-trust">
<p class="gm-trust-label gm-reveal">Trusted by teams at</p>
<div class="gm-trust-bar gm-reveal gm-reveal-delay-1">
{{range .Config.SocialProof.Logos}}
<span class="gm-trust-logo">{{.}}</span>
{{end}}
</div>
</section>
{{end}}
<!-- Value Props -->
{{if .Config.ValueProps}}
<section class="gm-section" id="value-props">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<h2>Why <span class="gm-serif">{{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</span></h2>
<p>Built for developers who value their time</p>
</div>
<div class="gm-value-grid">
{{range .Config.ValueProps}}
<div class="gm-value-card gm-reveal">
<h3>{{.Title}}</h3>
<p>{{.Description}}</p>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Features -->
{{if .Config.Features}}
<section id="features" class="gm-section">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<h2>How it <span class="gm-serif">works</span></h2>
<p>Get started in minutes, not weeks</p>
</div>
<div class="gm-features-list">
{{range .Config.Features}}
<div class="gm-feature-step gm-reveal">
<div class="gm-step-icon">
{{svg (printf "octicon-%s" (or .Icon "zap")) 22}}
</div>
<div>
<h3>{{.Title}}</h3>
<p>{{.Description}}</p>
</div>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Testimonials -->
{{if .Config.SocialProof.Testimonials}}
<section class="gm-section">
<div class="gm-testimonial-card">
<div class="gm-testimonials-container">
{{range .Config.SocialProof.Testimonials}}
<div class="gm-testimonial-item" style="display: none;">
<div class="gm-testimonial-quote-mark">&ldquo;</div>
<p class="gm-testimonial-quote">{{.Quote}}</p>
<div class="gm-testimonial-author">
<div class="gm-testimonial-avatar">
{{if .Avatar}}<img src="{{.Avatar}}" alt="{{.Author}}">{{end}}
</div>
<div>
<div class="gm-testimonial-name">{{.Author}}</div>
<div class="gm-testimonial-role">{{.Role}}</div>
</div>
</div>
</div>
{{end}}
</div>
</div>
</section>
<script>
(function() {
var items = document.querySelectorAll(".gm-testimonial-item");
if (items.length > 0) {
var idx = Math.floor(Math.random() * items.length);
items[idx].style.display = "block";
}
})();
</script>
{{end}}
<!-- Pricing -->
{{if .Config.Pricing.Plans}}
<section id="pricing" class="gm-section">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<h2>{{if .Config.Pricing.Headline}}{{.Config.Pricing.Headline}}{{else}}Simple, <span class="gm-serif">transparent</span> pricing{{end}}</h2>
</div>
<div class="gm-pricing-grid">
{{range .Config.Pricing.Plans}}
<div class="gm-pricing-card{{if .Featured}} featured{{end}} gm-reveal">
{{if .Featured}}<div class="gm-pricing-badge">Most Popular</div>{{end}}
<h3 class="gm-pricing-name">{{.Name}}</h3>
<div style="margin-bottom: 24px;">
<span class="gm-pricing-price">{{.Price}}</span>
<span class="gm-pricing-period">{{.Period}}</span>
</div>
{{if .Features}}
<ul class="gm-pricing-features">
{{range .Features}}
<li><span class="gm-pricing-check">{{svg "octicon-check" 16}}</span> {{.}}</li>
{{end}}
</ul>
{{end}}
<a href="#" class="{{if .Featured}}gm-btn-primary{{else}}gm-btn-secondary{{end}}" style="width: 100%; justify-content: center;">
<span>{{if .CTA}}{{.CTA}}{{else}}Get Started{{end}}</span>
</a>
</div>
{{end}}
</div>
</div>
</section>
{{end}}
<!-- Final CTA -->
{{if .Config.CTASection.Headline}}
<section class="gm-section">
<div class="gm-cta-gradient gm-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="gm-btn-primary" data-cta="primary" style="font-size: 16px; padding: 16px 36px;">
<span>
{{if .Config.CTASection.Button.Label}}{{.Config.CTASection.Button.Label}}{{else}}Get Started Free{{end}}
{{svg "octicon-arrow-right" 16}}
</span>
</a>
</div>
</section>
{{end}}
<!-- Blog Section -->
{{if and .Config.Blog.Enabled .BlogPosts}}
<section class="gm-section" id="blog">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<h2>{{if .Config.Blog.Headline}}{{.Config.Blog.Headline}}{{else}}Latest <span class="gm-serif">Posts</span>{{end}}</h2>
{{if .Config.Blog.Subheadline}}<p>{{.Config.Blog.Subheadline}}</p>{{end}}
</div>
<div class="gm-value-grid">
{{range .BlogPosts}}
<a href="{{$.BlogBaseURL}}/{{.ID}}" class="gm-value-card gm-reveal" style="text-decoration: none; color: inherit; display: flex; flex-direction: column;">
{{if .FeaturedImage}}
<div style="margin: -36px -36px 24px -36px; overflow: hidden; border-radius: 20px 20px 0 0;">
<img src="{{.FeaturedImage.DownloadURL}}" alt="{{.Title}}" style="width: 100%; height: 180px; object-fit: cover; display: block;">
</div>
{{end}}
<h3>{{.Title}}</h3>
{{if and $.Config.Blog.ShowExcerpt .Subtitle}}
<p>{{.Subtitle}}</p>
{{end}}
<div style="margin-top: auto; padding-top: 16px; font-size: 12px; color: var(--gm-light);">
{{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="gm-reveal">
<a href="{{if .Config.Blog.CTAButton.URL}}{{.Config.Blog.CTAButton.URL}}{{else}}{{.BlogBaseURL}}{{end}}" class="gm-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="gm-section" id="gallery">
<div class="gm-section-inner">
<div class="gm-section-header gm-reveal">
<h2>{{if .Config.Gallery.Headline}}{{.Config.Gallery.Headline}}{{else}}<span class="gm-serif">Gallery</span>{{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="gm-value-card gm-reveal" style="padding: 0; overflow: hidden;">
<a href="{{.URL}}" target="_blank" style="display: block;">
<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: 16px 20px; font-size: 14px; color: var(--gm-light);">{{.Caption}}</div>
{{end}}
</div>
{{end}}
</div>
</div>
</section>
{{end}}
{{end}}{{/* end PageIsBlogDetail / PageIsBlogList / else */}}
<!-- Footer -->
<footer class="gm-footer">
<div class="gm-footer-brand">
<div class="gm-footer-logo"></div>
<span class="gm-footer-copyright">{{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="gm-footer-social">
{{range .Config.Footer.Social}}
<a href="{{.URL}}" title="{{.Platform}}">
{{if eq .Platform "twitter"}}{{svg "octicon-mention" 18}}
{{else if eq .Platform "bluesky"}}{{svg "octicon-cloud" 18}}
{{else if eq .Platform "github"}}{{svg "octicon-mark-github" 18}}
{{else if eq .Platform "discord"}}{{svg "octicon-comment-discussion" 18}}
{{else if eq .Platform "linkedin"}}{{svg "octicon-briefcase" 18}}
{{else if eq .Platform "youtube"}}{{svg "octicon-video" 18}}
{{else if eq .Platform "instagram"}}{{svg "octicon-device-camera" 18}}
{{else if eq .Platform "facebook"}}{{svg "octicon-people" 18}}
{{else if eq .Platform "substack"}}{{svg "octicon-note" 18}}
{{else if eq .Platform "threads"}}{{svg "octicon-share" 18}}
{{else if eq .Platform "tiktok"}}{{svg "octicon-play" 18}}
{{else if eq .Platform "reddit"}}{{svg "octicon-hash" 18}}
{{else if eq .Platform "mastodon"}}{{svg "octicon-megaphone" 18}}
{{else if eq .Platform "twitch"}}{{svg "octicon-broadcast" 18}}
{{else if eq .Platform "rss"}}{{svg "octicon-rss" 18}}
{{else}}{{svg "octicon-link-external" 18}}{{end}}
</a>
{{end}}
</div>
{{end}}
<div class="gm-footer-links">
{{range .Config.Footer.Links}}
<a href="{{.URL}}" class="gm-footer-link">{{.Label}}</a>
{{end}}
{{if .Config.Navigation.ShowRepository}}<a href="{{.RepoURL}}" class="gm-footer-link">Repository</a>{{end}}
{{if .Config.Navigation.ShowDocs}}<a href="{{.RepoURL}}/wiki" class="gm-footer-link">Docs</a>{{end}}
{{if .Config.Navigation.ShowReleases}}<a href="{{.RepoURL}}/releases" class="gm-footer-link">Releases</a>{{end}}
{{if .Config.Navigation.ShowIssues}}<a href="{{.RepoURL}}/issues" class="gm-footer-link">Issues</a>{{end}}
</div>
</footer>
</div>
<script>
/* Scroll reveal */
(function() {
var reveals = document.querySelectorAll('.gm-reveal');
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.08, rootMargin: '0px 0px -40px 0px' });
reveals.forEach(function(el) { observer.observe(el); });
})();
</script>
{{template "pages/base_footer" .}}