Initial commit: railwayka.ru landing page as dcape app
- Dcape app structure with Makefile, docker-compose.yml - Woodpecker CI/CD pipeline configuration - Custom Dockerfile with nginx alpine - Static website with dark theme and animations - Service cards, tech stack, GitOps workflow visualization - Konami code easter egg
This commit is contained in:
commit
90314a5851
|
|
@ -0,0 +1,2 @@
|
|||
.env
|
||||
.env.bak
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# Woodpecker CI pipeline for railwayka landing page
|
||||
|
||||
variables:
|
||||
- &dcape_img 'dcape-compose'
|
||||
|
||||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
lfs: false
|
||||
tags: false
|
||||
|
||||
steps:
|
||||
deploy:
|
||||
image: *dcape_img
|
||||
commands:
|
||||
- make .default-deploy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ARG IMAGE=nginx
|
||||
ARG IMAGE_VER=1.27-alpine
|
||||
|
||||
FROM --platform=$BUILDPLATFORM ${IMAGE}:${IMAGE_VER}
|
||||
|
||||
COPY html /usr/share/nginx/html
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
## dcape-app-railwayka-landing Makefile
|
||||
## This file extends Makefile.app from dcape
|
||||
#:
|
||||
|
||||
SHELL = /bin/bash
|
||||
CFG ?= .env
|
||||
CFG_BAK ?= $(CFG).bak
|
||||
|
||||
#- Docker repo & image name without version
|
||||
IMAGE ?= nginx
|
||||
|
||||
#- ver
|
||||
IMAGE_VER ?= 1.27-alpine
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# app custom config
|
||||
|
||||
# Overwrite for setup
|
||||
APP_SITE ?= railwayka.ru
|
||||
|
||||
#- domain (no www for this site)
|
||||
APP_ACME_DOMAIN ?= $(APP_SITE)
|
||||
|
||||
PERSIST_FILES =
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# if exists - load old values
|
||||
-include $(CFG_BAK)
|
||||
export
|
||||
|
||||
-include $(CFG)
|
||||
export
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Find and include DCAPE_ROOT/Makefile
|
||||
DCAPE_COMPOSE ?= dcape-compose
|
||||
DCAPE_ROOT ?= $(shell docker inspect -f "{{.Config.Labels.dcape_root}}" $(DCAPE_COMPOSE))
|
||||
|
||||
ifeq ($(shell test -e $(DCAPE_ROOT)/Makefile.app && echo -n yes),yes)
|
||||
include $(DCAPE_ROOT)/Makefile.app
|
||||
else
|
||||
include /opt/dcape/Makefile.app
|
||||
endif
|
||||
|
||||
.default-deploy: docker-build
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
# railwayka.ru Landing Page
|
||||
|
||||
Business card website for railwayka.ru infrastructure, deployed via [dcape](https://github.com/dopos/dcape) GitOps platform.
|
||||
|
||||
## Features
|
||||
|
||||
- Modern dark theme with animated stars background
|
||||
- Service cards showcasing current and planned services
|
||||
- Technology stack descriptions
|
||||
- GitOps workflow visualization
|
||||
- Konami code easter egg
|
||||
- Responsive design
|
||||
|
||||
## Technology Stack
|
||||
|
||||
- **Nginx**: Alpine-based web server
|
||||
- **Docker**: Containerized deployment
|
||||
- **Traefik**: Automatic HTTPS via Let's Encrypt
|
||||
- **Dcape**: GitOps-based deployment
|
||||
|
||||
## Deployment
|
||||
|
||||
This application uses GitOps workflow:
|
||||
|
||||
1. Push code to Git repository
|
||||
2. Woodpecker CI automatically triggers
|
||||
3. Application builds and deploys
|
||||
4. Service goes live at https://railwayka.ru
|
||||
|
||||
### Manual Deployment
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://git.dc.railwayka.ru/howl/railwayka-landing.git
|
||||
cd railwayka-landing
|
||||
|
||||
# Configure environment
|
||||
make config
|
||||
# Edit .env.sample and rename to .env
|
||||
mv .env.sample .env
|
||||
|
||||
# Build and deploy
|
||||
make docker-build
|
||||
make up
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
To run locally:
|
||||
|
||||
```bash
|
||||
# Serve files with any web server
|
||||
cd html
|
||||
python3 -m http.server 8000
|
||||
# Visit http://localhost:8000
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── Makefile # Dcape app Makefile
|
||||
├── docker-compose.yml # Service definition
|
||||
├── Dockerfile # Custom nginx image
|
||||
├── .woodpecker.yml # CI/CD pipeline
|
||||
├── html/ # Static website files
|
||||
│ ├── index.html
|
||||
│ ├── style.css
|
||||
│ └── script.js
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Railwayka Landing Page - dcape app config
|
||||
|
||||
services:
|
||||
app:
|
||||
labels:
|
||||
- traefik.http.routers.${APP_TAG}.rule=Host(`${APP_SITE:?Must be set}`)
|
||||
# TLS support
|
||||
- traefik.http.routers.${APP_TAG}.tls.domains[0].main=${APP_SITE}
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
IMAGE: "${IMAGE}"
|
||||
IMAGE_VER: "${IMAGE_VER}"
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>railwayka.ru - Infrastructure & Services</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="stars"></div>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1 class="glitch" data-text="railwayka.ru">railwayka.ru</h1>
|
||||
<p class="tagline">Self-Hosted Infrastructure & Services</p>
|
||||
</header>
|
||||
|
||||
<section class="intro">
|
||||
<p>Welcome to my personal infrastructure platform, powered by modern DevOps technologies and GitOps workflows.</p>
|
||||
</section>
|
||||
|
||||
<section class="services">
|
||||
<h2>Available Services</h2>
|
||||
<div class="service-grid">
|
||||
<div class="service-card">
|
||||
<div class="service-icon">🔧</div>
|
||||
<h3>Git Repository</h3>
|
||||
<p>Self-hosted Git server with web interface</p>
|
||||
<a href="https://git.dc.railwayka.ru" class="service-link">Visit Gitea →</a>
|
||||
</div>
|
||||
|
||||
<div class="service-card coming-soon">
|
||||
<div class="service-icon">💬</div>
|
||||
<h3>Matrix Server</h3>
|
||||
<p>Decentralized, secure messaging</p>
|
||||
<span class="badge">Coming Soon</span>
|
||||
</div>
|
||||
|
||||
<div class="service-card coming-soon">
|
||||
<div class="service-icon">📝</div>
|
||||
<h3>Blog</h3>
|
||||
<p>Technical writing and documentation</p>
|
||||
<span class="badge">Coming Soon</span>
|
||||
</div>
|
||||
|
||||
<div class="service-card coming-soon">
|
||||
<div class="service-icon">🔐</div>
|
||||
<h3>Password Manager</h3>
|
||||
<p>Self-hosted credential storage</p>
|
||||
<span class="badge">Coming Soon</span>
|
||||
</div>
|
||||
|
||||
<div class="service-card coming-soon">
|
||||
<div class="service-icon">☁️</div>
|
||||
<h3>Cloud Storage</h3>
|
||||
<p>Private file storage and sync</p>
|
||||
<span class="badge">Coming Soon</span>
|
||||
</div>
|
||||
|
||||
<div class="service-card coming-soon">
|
||||
<div class="service-icon">📊</div>
|
||||
<h3>Monitoring</h3>
|
||||
<p>System metrics and dashboards</p>
|
||||
<span class="badge">Coming Soon</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tech-stack">
|
||||
<h2>Technology Stack</h2>
|
||||
<div class="tech-info">
|
||||
<div class="tech-item">
|
||||
<h3>🚀 Dcape</h3>
|
||||
<p>GitOps-based infrastructure management platform. Deploy applications with simple <code>git push</code> commands.</p>
|
||||
</div>
|
||||
<div class="tech-item">
|
||||
<h3>🐳 Docker</h3>
|
||||
<p>All services run in isolated containers with automatic orchestration and health monitoring.</p>
|
||||
</div>
|
||||
<div class="tech-item">
|
||||
<h3>🔒 Let's Encrypt</h3>
|
||||
<p>Automatic SSL/TLS certificates with wildcard domain support for secure HTTPS connections.</p>
|
||||
</div>
|
||||
<div class="tech-item">
|
||||
<h3>🌐 Traefik</h3>
|
||||
<p>Modern reverse proxy with automatic service discovery and HTTPS routing.</p>
|
||||
</div>
|
||||
<div class="tech-item">
|
||||
<h3>🗄️ PostgreSQL</h3>
|
||||
<p>Shared production-grade database for application data persistence.</p>
|
||||
</div>
|
||||
<div class="tech-item">
|
||||
<h3>📡 PowerDNS</h3>
|
||||
<p>Self-hosted authoritative DNS server with API-driven zone management.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="about-gitops">
|
||||
<h2>What is GitOps?</h2>
|
||||
<p>GitOps is a modern infrastructure management approach where Git serves as the single source of truth. All infrastructure changes and application deployments are made through Git commits and pull requests.</p>
|
||||
<div class="gitops-flow">
|
||||
<div class="flow-step">
|
||||
<span class="step-number">1</span>
|
||||
<p>Push code to Git repository</p>
|
||||
</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">
|
||||
<span class="step-number">2</span>
|
||||
<p>CI/CD pipeline builds</p>
|
||||
</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">
|
||||
<span class="step-number">3</span>
|
||||
<p>Automatic deployment</p>
|
||||
</div>
|
||||
<div class="flow-arrow">→</div>
|
||||
<div class="flow-step">
|
||||
<span class="step-number">4</span>
|
||||
<p>Service goes live</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>Powered by open-source technologies and self-hosted infrastructure</p>
|
||||
<p class="footer-note">This server runs on <strong>Ubuntu 24.04</strong> with hardened SSH security (key-only authentication)</p>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Smooth scroll for any future internal links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add fade-in animation to cards on scroll
|
||||
const observerOptions = {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = '0';
|
||||
entry.target.style.transform = 'translateY(20px)';
|
||||
entry.target.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||
|
||||
setTimeout(() => {
|
||||
entry.target.style.opacity = '1';
|
||||
entry.target.style.transform = 'translateY(0)';
|
||||
}, 100);
|
||||
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
// Observe all service cards and tech items
|
||||
document.querySelectorAll('.service-card, .tech-item, .flow-step').forEach(el => {
|
||||
observer.observe(el);
|
||||
});
|
||||
|
||||
// Easter egg: Konami code detector
|
||||
let konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];
|
||||
let konamiIndex = 0;
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === konamiCode[konamiIndex]) {
|
||||
konamiIndex++;
|
||||
if (konamiIndex === konamiCode.length) {
|
||||
document.body.style.animation = 'rainbow 2s ease infinite';
|
||||
setTimeout(() => {
|
||||
document.body.style.animation = '';
|
||||
konamiIndex = 0;
|
||||
}, 5000);
|
||||
}
|
||||
} else {
|
||||
konamiIndex = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Add CSS for rainbow animation
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@keyframes rainbow {
|
||||
0% { filter: hue-rotate(0deg); }
|
||||
100% { filter: hue-rotate(360deg); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Console message for developers
|
||||
console.log('%c👋 Hello, developer!', 'font-size: 20px; color: #6366f1; font-weight: bold;');
|
||||
console.log('%cInterested in the infrastructure? Check out https://git.dc.railwayka.ru', 'font-size: 14px; color: #a1a1aa;');
|
||||
console.log('%cPowered by Dcape - GitOps infrastructure management', 'font-size: 12px; color: #6366f1;');
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--bg-primary: #0a0e27;
|
||||
--bg-secondary: #141b3d;
|
||||
--text-primary: #e4e4e7;
|
||||
--text-secondary: #a1a1aa;
|
||||
--accent: #6366f1;
|
||||
--accent-hover: #4f46e5;
|
||||
--card-bg: rgba(20, 27, 61, 0.6);
|
||||
--border: rgba(99, 102, 241, 0.2);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.stars {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, white, transparent),
|
||||
radial-gradient(2px 2px at 60px 70px, white, transparent),
|
||||
radial-gradient(1px 1px at 50px 50px, white, transparent),
|
||||
radial-gradient(1px 1px at 130px 80px, white, transparent),
|
||||
radial-gradient(2px 2px at 90px 10px, white, transparent);
|
||||
background-size: 200px 200px;
|
||||
animation: twinkle 5s ease-in-out infinite;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.4; }
|
||||
50% { opacity: 0.7; }
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
padding: 4rem 0 2rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 4rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, var(--accent) 0%, #ec4899 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 0.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.glitch {
|
||||
animation: glitch 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes glitch {
|
||||
0%, 90%, 100% {
|
||||
text-shadow: none;
|
||||
}
|
||||
92% {
|
||||
text-shadow: 2px 2px #ff00de, -2px -2px #00fff9;
|
||||
}
|
||||
94% {
|
||||
text-shadow: -2px 2px #ff00de, 2px -2px #00fff9;
|
||||
}
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: 1.25rem;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
section {
|
||||
margin: 4rem 0;
|
||||
}
|
||||
|
||||
.intro {
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-secondary);
|
||||
max-width: 600px;
|
||||
margin: 2rem auto;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.service-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(10px);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.service-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.1), transparent);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.service-card:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.service-card:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 10px 30px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.service-card h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.service-card p {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.service-link {
|
||||
display: inline-block;
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.service-link:hover {
|
||||
color: var(--accent-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.service-card.coming-soon {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 20px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.tech-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.tech-item {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.tech-item h3 {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.tech-item p {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
code {
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-family: 'Courier New', monospace;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.about-gitops {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 3rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.about-gitops p {
|
||||
text-align: center;
|
||||
max-width: 800px;
|
||||
margin: 0 auto 2rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.gitops-flow {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
background: rgba(99, 102, 241, 0.1);
|
||||
border: 2px solid var(--accent);
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
min-width: 150px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.flow-step:hover {
|
||||
transform: scale(1.05);
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
}
|
||||
|
||||
.step-number {
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto 0.5rem;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.flow-arrow {
|
||||
color: var(--accent);
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 3rem 0 2rem;
|
||||
color: var(--text-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
footer strong {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.service-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.gitops-flow {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flow-arrow {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue