first commit
This commit is contained in:
18
.dockerignore
Normal file
18
.dockerignore
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Compiled binaries (built inside Docker)
|
||||||
|
arcline-landing
|
||||||
|
landing
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
# CI/CD
|
||||||
|
.gitlab-ci.yml
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
49
.gitlab-ci.yml
Normal file
49
.gitlab-ci.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
variables:
|
||||||
|
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
||||||
|
IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
image: docker:26
|
||||||
|
services:
|
||||||
|
- docker:26-dind
|
||||||
|
before_script:
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
script:
|
||||||
|
- docker pull $IMAGE_LATEST || true
|
||||||
|
- docker build --pull --cache-from $IMAGE_LATEST --tag $IMAGE --tag $IMAGE_LATEST .
|
||||||
|
- docker push $IMAGE
|
||||||
|
- docker push $IMAGE_LATEST
|
||||||
|
only:
|
||||||
|
- main
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
stage: deploy
|
||||||
|
image: alpine:3.21
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache openssh-client
|
||||||
|
- eval $(ssh-agent -s)
|
||||||
|
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
|
||||||
|
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||||
|
- echo "$SSH_HOST_KEY" >> ~/.ssh/known_hosts
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
ssh $SSH_USER@$SSH_HOST "
|
||||||
|
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY &&
|
||||||
|
docker pull $IMAGE_LATEST &&
|
||||||
|
docker stop arcline-landing 2>/dev/null || true &&
|
||||||
|
docker rm arcline-landing 2>/dev/null || true &&
|
||||||
|
docker run -d \
|
||||||
|
--name arcline-landing \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-p 8080:8080 \
|
||||||
|
$IMAGE_LATEST
|
||||||
|
"
|
||||||
|
only:
|
||||||
|
- main
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
34
Dockerfile
Normal file
34
Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# ── Stage 1: Build ─────────────────────────────────────────────────────────
|
||||||
|
FROM golang:1.26-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY go.* ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o landing .
|
||||||
|
|
||||||
|
# ── Stage 2: Runtime ────────────────────────────────────────────────────────
|
||||||
|
FROM alpine:3.21 AS runtime
|
||||||
|
|
||||||
|
RUN apk add --no-cache ca-certificates && \
|
||||||
|
addgroup -S arcline && \
|
||||||
|
adduser -S -G arcline arcline
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /build/landing ./
|
||||||
|
COPY --from=builder /build/static ./static
|
||||||
|
COPY --from=builder /build/templates ./templates
|
||||||
|
|
||||||
|
RUN chown -R arcline:arcline /app
|
||||||
|
|
||||||
|
USER arcline
|
||||||
|
|
||||||
|
ENV PORT=8080
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["./landing"]
|
||||||
BIN
arcline-landing
Executable file
BIN
arcline-landing
Executable file
Binary file not shown.
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Arcline Project — Landing Page
|
||||||
|
#
|
||||||
|
# Deploy: docker compose up -d
|
||||||
|
# Stop: docker compose down
|
||||||
|
# Logs: docker compose logs -f
|
||||||
|
# Build: docker compose build
|
||||||
|
|
||||||
|
services:
|
||||||
|
landing:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: arcline-landing
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
environment:
|
||||||
|
- PORT=8080
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
80
main.go
Normal file
80
main.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
port := os.Getenv("PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve static assets
|
||||||
|
fs := http.FileServer(http.Dir("static"))
|
||||||
|
http.Handle("/static/", http.StripPrefix("/static/", fs))
|
||||||
|
|
||||||
|
// Page routes
|
||||||
|
http.HandleFunc("/", handleIndex)
|
||||||
|
|
||||||
|
// HTMX partial routes
|
||||||
|
http.HandleFunc("/partials/waitlist", handleWaitlist)
|
||||||
|
|
||||||
|
log.Printf("Arcline Project server starting on :%s", port)
|
||||||
|
if err := http.ListenAndServe(":"+port, nil); err != nil {
|
||||||
|
log.Fatalf("server failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path != "/" {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles("templates/base.html", "templates/index.html")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("template error: %v", err)
|
||||||
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"Title": "Arcline Project",
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
if err := tmpl.ExecuteTemplate(w, "base", data); err != nil {
|
||||||
|
log.Printf("render error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleWaitlist(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
email := r.FormValue("email")
|
||||||
|
|
||||||
|
// Parse edition preferences (checkboxes with same name)
|
||||||
|
r.ParseForm()
|
||||||
|
editions := r.Form["edition"]
|
||||||
|
log.Printf("Waitlist signup: %s | editions: %v", email, editions)
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles("templates/partials/waitlist_confirmation.html")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("template error: %v", err)
|
||||||
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
if err := tmpl.Execute(w, map[string]string{"Email": email}); err != nil {
|
||||||
|
log.Printf("render error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
813
static/css/style.css
Normal file
813
static/css/style.css
Normal file
@@ -0,0 +1,813 @@
|
|||||||
|
/* ========================================
|
||||||
|
Arcline Project — Landing Page
|
||||||
|
Hand-crafted, not generated.
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg: #0d0e10;
|
||||||
|
--bg-raised: #15171b;
|
||||||
|
--bg-card: #1a1c22;
|
||||||
|
--bg-card-hover: #1f2128;
|
||||||
|
--border: hsl(225 7% 18%);
|
||||||
|
--border-hover: hsl(225 8% 26%);
|
||||||
|
--text: hsl(223 8% 88%);
|
||||||
|
--text-soft: hsl(223 6% 65%);
|
||||||
|
--text-faint: hsl(223 5% 41%);
|
||||||
|
--accent: #0acf97;
|
||||||
|
--accent-dim: hsl(162 88% 33%);
|
||||||
|
--accent-bg: hsla(162 88% 43% / 0.09);
|
||||||
|
--accent-border: hsla(162 88% 43% / 0.18);
|
||||||
|
--amber: #f09d51;
|
||||||
|
--amber-bg: hsla(28 84% 63% / 0.07);
|
||||||
|
--mono: "JetBrains Mono", "Fira Code", "SF Mono", "Cascadia Code", monospace;
|
||||||
|
--sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
--pad-card: 22px;
|
||||||
|
--w-main: 1040px;
|
||||||
|
--w-narrow: 680px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--sans);
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.65;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::after {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.022;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav */
|
||||||
|
.nav {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: hsl(225 6% 6% / 0.88);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
-webkit-backdrop-filter: blur(18px);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-inner {
|
||||||
|
max-width: var(--w-main);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 28px;
|
||||||
|
height: 58px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 11px;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon { flex-shrink: 0; }
|
||||||
|
|
||||||
|
.nav nav { display: flex; gap: 2px; }
|
||||||
|
|
||||||
|
.nav nav a {
|
||||||
|
color: var(--text-soft);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 7px 14px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
font-weight: 470;
|
||||||
|
transition: color 0.18s, background 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav nav a:hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: hsl(225 6% 14%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero */
|
||||||
|
.hero {
|
||||||
|
padding: 130px 28px 110px;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -40%;
|
||||||
|
left: 30%;
|
||||||
|
width: 960px;
|
||||||
|
height: 960px;
|
||||||
|
background: radial-gradient(ellipse at center, hsla(162 88% 43% / 0.075) 0%, transparent 60%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.03;
|
||||||
|
background:
|
||||||
|
linear-gradient(25deg, transparent 48%, var(--border) 48%, var(--border) 52%, transparent 52%),
|
||||||
|
linear-gradient(25deg, transparent 48%, var(--border) 48%, var(--border) 52%, transparent 52%);
|
||||||
|
background-size: 90px 90px;
|
||||||
|
background-position: 0 0, 45px 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-inner {
|
||||||
|
max-width: var(--w-narrow);
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--accent);
|
||||||
|
background: hsla(162 88% 43% / 0.06);
|
||||||
|
border: 1px solid var(--accent-border);
|
||||||
|
padding: 5px 14px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-badge::before {
|
||||||
|
content: "$ ";
|
||||||
|
color: var(--text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: clamp(2.4rem, 6vw, 4rem);
|
||||||
|
font-weight: 750;
|
||||||
|
letter-spacing: -0.035em;
|
||||||
|
line-height: 1.08;
|
||||||
|
margin-bottom: 26px;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-highlight { color: var(--accent); }
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
color: var(--text-soft);
|
||||||
|
margin-bottom: 42px;
|
||||||
|
line-height: 1.7;
|
||||||
|
max-width: 520px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--accent);
|
||||||
|
color: hsl(0 0% 8%);
|
||||||
|
padding: 13px 30px;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-weight: 620;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.18s, transform 0.14s;
|
||||||
|
font-family: var(--mono);
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta:hover {
|
||||||
|
background: var(--accent-dim);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-secondary {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-soft);
|
||||||
|
padding: 13px 30px;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-weight: 470;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
transition: border-color 0.18s, color 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-secondary:hover {
|
||||||
|
border-color: var(--border-hover);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
.section {
|
||||||
|
padding: 105px 28px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-alt { background: var(--bg-raised); }
|
||||||
|
|
||||||
|
.section-inner {
|
||||||
|
max-width: var(--w-main);
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--accent);
|
||||||
|
margin-bottom: 14px;
|
||||||
|
text-transform: lowercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label::before { content: "// "; color: var(--text-faint); }
|
||||||
|
|
||||||
|
.section-inner h2 {
|
||||||
|
font-size: clamp(1.6rem, 3.6vw, 2.35rem);
|
||||||
|
font-weight: 680;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
line-height: 1.22;
|
||||||
|
color: var(--text);
|
||||||
|
max-width: 680px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-desc {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 1rem;
|
||||||
|
max-width: 590px;
|
||||||
|
margin-bottom: 52px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Principles */
|
||||||
|
.principles-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(302px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.principle {
|
||||||
|
display: flex;
|
||||||
|
gap: 17px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: var(--pad-card);
|
||||||
|
transition: border-color 0.22s;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.principle::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: -1px;
|
||||||
|
background: var(--accent-bg);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.25s;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.principle:hover { border-color: var(--accent-border); }
|
||||||
|
.principle:hover::after { opacity: 1; }
|
||||||
|
|
||||||
|
.principle-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--accent);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.principle h3 {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.83rem;
|
||||||
|
font-weight: 620;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: var(--text);
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.principle p {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.845rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack Grid */
|
||||||
|
.stack-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: border-color 0.22s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; bottom: 0;
|
||||||
|
width: 3px;
|
||||||
|
transition: width 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card:nth-child(1)::before { background: var(--accent); }
|
||||||
|
.stack-card:nth-child(2)::before { background: hsl(280 45% 55%); }
|
||||||
|
.stack-card:nth-child(3)::before { background: hsl(200 60% 52%); }
|
||||||
|
.stack-card:nth-child(4)::before { background: var(--amber); }
|
||||||
|
|
||||||
|
.stack-card:hover { border-color: var(--border-hover); }
|
||||||
|
.stack-card:hover::before { width: 5px; }
|
||||||
|
|
||||||
|
.stack-header {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 650;
|
||||||
|
text-transform: lowercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
padding: 20px 22px 10px 22px;
|
||||||
|
color: var(--text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card:nth-child(1) .stack-header { color: var(--accent); }
|
||||||
|
.stack-card:nth-child(2) .stack-header { color: hsl(280 45% 65%); }
|
||||||
|
.stack-card:nth-child(3) .stack-header { color: hsl(200 60% 58%); }
|
||||||
|
.stack-card:nth-child(4) .stack-header { color: var(--amber); }
|
||||||
|
|
||||||
|
.stack-card ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0 22px 22px 22px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card li {
|
||||||
|
position: relative;
|
||||||
|
padding: 6px 0 6px 16px;
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.83rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card li::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 12px;
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack-card:nth-child(1) li::before { background: var(--accent); opacity: 0.55; }
|
||||||
|
.stack-card:nth-child(2) li::before { background: hsl(280 45% 55%); opacity: 0.55; }
|
||||||
|
.stack-card:nth-child(3) li::before { background: hsl(200 60% 52%); opacity: 0.55; }
|
||||||
|
.stack-card:nth-child(4) li::before { background: var(--amber); opacity: 0.55; }
|
||||||
|
|
||||||
|
/* Edition Teaser */
|
||||||
|
.edition-teaser {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
border: 1px dashed var(--accent-border);
|
||||||
|
background: hsla(162 88% 43% / 0.04);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-teaser-badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.64rem;
|
||||||
|
color: var(--accent-dim);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-teaser p {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
max-width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-teaser strong { color: var(--text); font-weight: 660; }
|
||||||
|
|
||||||
|
/* Tool Grid */
|
||||||
|
.tool-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(296px, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 0 solid var(--accent-border);
|
||||||
|
border-left-width: 2px;
|
||||||
|
padding: 19px 22px;
|
||||||
|
transition: border-color 0.2s, background 0.18s, border-left-width 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool:hover {
|
||||||
|
border-left-width: 4px;
|
||||||
|
border-left-color: var(--accent);
|
||||||
|
background: var(--bg-card-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool code {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-weight: 580;
|
||||||
|
color: var(--accent);
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool span {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.81rem;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare Grid */
|
||||||
|
.compare-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 26px 22px;
|
||||||
|
transition: border-color 0.22s, background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-card:hover { border-color: var(--border-hover); }
|
||||||
|
|
||||||
|
.compare-highlight {
|
||||||
|
border-color: var(--accent-border);
|
||||||
|
background: linear-gradient(155deg, var(--bg-card) 0%, hsla(162 88% 43% / 0.06) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-label {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 620;
|
||||||
|
text-transform: lowercase;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-highlight .compare-label { color: var(--accent); }
|
||||||
|
|
||||||
|
.compare-desc {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contribute Grid */
|
||||||
|
.contribute-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contribute-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 28px 22px;
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: border-color 0.22s, background 0.2s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contribute-card::after {
|
||||||
|
content: " →";
|
||||||
|
position: absolute;
|
||||||
|
right: 22px;
|
||||||
|
top: 28px;
|
||||||
|
font-family: var(--mono);
|
||||||
|
color: var(--accent);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-8px);
|
||||||
|
transition: opacity 0.2s, transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contribute-card:hover { border-color: var(--accent-border); }
|
||||||
|
.contribute-card:hover::after { opacity: 1; transform: translateX(0); }
|
||||||
|
|
||||||
|
.contribute-card span {
|
||||||
|
font-size: 0.96rem;
|
||||||
|
font-weight: 640;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contribute-card small {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contribute-icon {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: hsla(162 88% 43% / 0.07);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline Link */
|
||||||
|
.inline-link {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid var(--accent-border);
|
||||||
|
padding-bottom: 1px;
|
||||||
|
transition: border-color 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-link:hover { border-bottom-color: var(--accent); }
|
||||||
|
|
||||||
|
/* Sponsor */
|
||||||
|
.sponsor-section .section-inner { text-align: left; }
|
||||||
|
|
||||||
|
.sponsor-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 22px;
|
||||||
|
max-width: 620px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsor-desc {
|
||||||
|
max-width: 600px;
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.94rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsor-desc strong { color: var(--text); font-weight: 660; }
|
||||||
|
|
||||||
|
.sponsor-tagline {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: var(--text-faint);
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsor-tagline::before { content: "# "; color: var(--border-hover); }
|
||||||
|
|
||||||
|
/* Waitlist */
|
||||||
|
.waitlist-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
|
margin-top: 6px;
|
||||||
|
max-width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.waitlist-form .input,
|
||||||
|
.waitlist-form .btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Edition Checkboxes */
|
||||||
|
.edition-checkboxes {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-checkboxes legend {
|
||||||
|
font-size: 0.83rem;
|
||||||
|
color: var(--text-soft);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 0;
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--text-soft);
|
||||||
|
user-select: none;
|
||||||
|
transition: color 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-checkbox:hover { color: var(--text); }
|
||||||
|
|
||||||
|
.edition-checkbox input[type="checkbox"] {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
background: var(--bg-card);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: border-color 0.18s, background 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-checkbox input[type="checkbox"]:checked {
|
||||||
|
border-color: var(--accent);
|
||||||
|
background: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.edition-checkbox input[type="checkbox"]:checked::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 4px;
|
||||||
|
top: 2px;
|
||||||
|
width: 5px;
|
||||||
|
height: 9px;
|
||||||
|
border: solid hsl(0 0% 8%);
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Waitlist Form Row */
|
||||||
|
.waitlist-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
padding: 13px 18px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
min-width: 310px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.18s, box-shadow 0.18s;
|
||||||
|
font-family: var(--mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input::placeholder { color: var(--text-faint); font-family: var(--mono); }
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
border-color: var(--accent);
|
||||||
|
box-shadow: 0 0 0 3px var(--accent-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 13px 30px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--accent);
|
||||||
|
color: hsl(0 0% 8%);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 620;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.18s;
|
||||||
|
font-family: var(--mono);
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover { background: var(--accent-dim); }
|
||||||
|
|
||||||
|
.confirmation {
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: var(--accent);
|
||||||
|
background: var(--accent-bg);
|
||||||
|
border: 1px solid var(--accent-border);
|
||||||
|
font-weight: 520;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: var(--mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
.waitlist-note {
|
||||||
|
margin-top: 22px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
padding: 44px 28px 30px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-inner {
|
||||||
|
max-width: var(--w-main);
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand p {
|
||||||
|
color: var(--text-soft);
|
||||||
|
font-size: 0.84rem;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-logo {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 620;
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links { display: flex; gap: 22px; }
|
||||||
|
|
||||||
|
.footer-links a {
|
||||||
|
color: var(--text-soft);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
transition: color 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links a:hover { color: var(--text); }
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
max-width: var(--w-main);
|
||||||
|
margin: 28px auto 0;
|
||||||
|
padding-top: 18px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom p {
|
||||||
|
font-family: var(--mono);
|
||||||
|
color: var(--text-faint);
|
||||||
|
font-size: 0.74rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 920px) {
|
||||||
|
.stack-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.hero { padding: 90px 22px 72px; }
|
||||||
|
.section { padding: 68px 22px; }
|
||||||
|
.hero-actions { flex-direction: column; align-items: stretch; }
|
||||||
|
.cta, .cta-secondary { justify-content: center; text-align: center; }
|
||||||
|
.principles-grid { grid-template-columns: 1fr; }
|
||||||
|
.tool-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 580px) {
|
||||||
|
.hero { padding: 62px 18px 50px; }
|
||||||
|
.hero h1 { font-size: 1.85rem; }
|
||||||
|
.section { padding: 50px 18px; }
|
||||||
|
.section-inner h2 { font-size: 1.4rem; }
|
||||||
|
.nav nav a { padding: 7px 9px; font-size: 0.76rem; }
|
||||||
|
.input { min-width: 100%; }
|
||||||
|
.btn { width: 100%; }
|
||||||
|
.stack-grid { grid-template-columns: 1fr; }
|
||||||
|
.compare-grid { grid-template-columns: 1fr; }
|
||||||
|
.contribute-grid { grid-template-columns: 1fr; }
|
||||||
|
.footer-inner { flex-direction: column; }
|
||||||
|
}
|
||||||
|
|
||||||
6
static/favicon.svg
Normal file
6
static/favicon.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<rect width="32" height="32" rx="6" ry="6" fill="#0d0e10"/>
|
||||||
|
<path d="M5 27L16 5L27 27" fill="none" stroke="#0acf97" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9 20H23" fill="none" stroke="#0acf97" stroke-width="2.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 374 B |
1
static/js/htmx.min.js
vendored
Normal file
1
static/js/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
17
templates/base.html
Normal file
17
templates/base.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{{define "base"}}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{.Title}}</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
|
<script src="/static/js/htmx.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{template "content" .}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
400
templates/index.html
Normal file
400
templates/index.html
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
{{define "content"}}
|
||||||
|
<header class="nav">
|
||||||
|
<div class="nav-inner">
|
||||||
|
<a href="/" class="logo">
|
||||||
|
<svg class="logo-icon" width="28" height="28" viewBox="0 0 32 32" fill="none">
|
||||||
|
<rect width="32" height="32" rx="6" fill="#0d0e10"/>
|
||||||
|
<path d="M5 27L16 5L27 27" fill="none" stroke="#0acf97" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9 20H23" fill="none" stroke="#0acf97" stroke-width="2.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>Arcline Project</span>
|
||||||
|
</a>
|
||||||
|
<nav>
|
||||||
|
<a href="#about">About</a>
|
||||||
|
<a href="#toolchain">Toolchain</a>
|
||||||
|
<a href="#contribute">Contribute</a>
|
||||||
|
<a href="#get-started">Get Started</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<!-- Hero -->
|
||||||
|
<section class="hero">
|
||||||
|
<div class="hero-inner">
|
||||||
|
<h1>
|
||||||
|
The Linux OS for<br>
|
||||||
|
<span class="hero-highlight">people who run infrastructure.</span>
|
||||||
|
</h1>
|
||||||
|
<p class="tagline">
|
||||||
|
Arcline OS is a hardened, privacy-first operating system built on Debian.
|
||||||
|
Ships pre-configured with monitoring, auditing, and security tooling —
|
||||||
|
so your systems are production-ready from first boot.
|
||||||
|
</p>
|
||||||
|
<div class="hero-actions">
|
||||||
|
<a href="#get-started" class="cta">Get Early Access</a>
|
||||||
|
<a href="#about" class="cta-secondary">Learn more</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- What is Arcline OS -->
|
||||||
|
<section id="about" class="section section-alt">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">what is arcline os?</div>
|
||||||
|
<h2>A Debian-derived OS that doesn't<br>make you start from scratch.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
Debian gives you a rock-solid base. Arcline OS hardens it, layers on a
|
||||||
|
full observability stack, and ships with pre-configured container
|
||||||
|
infrastructure. No telemetry. No snap store. No cloud integration.
|
||||||
|
Just a secure, auditable OS that respects your hardware.
|
||||||
|
</p>
|
||||||
|
<div class="principles-grid">
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<rect x="3" y="3" width="18" height="18" rx="3"/>
|
||||||
|
<path d="M8 12l2.5 2.5L16 9"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Secure by default</h3>
|
||||||
|
<p>Hardened Linux kernel with seccomp, AppArmor profiles, and restrictive nftables firewall. You opt in to exposure — never out.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<path d="M12 6v6l4 2"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Privacy-first</h3>
|
||||||
|
<p>Zero telemetry. Zero analytics. Zero cloud integration. No network calls you didn't initiate.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<rect x="2" y="2" width="20" height="20" rx="3"/>
|
||||||
|
<rect x="6" y="6" width="12" height="12" rx="1.5" stroke-dasharray="3 2"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>btrfs-native</h3>
|
||||||
|
<p>btrfs root with subvolume snapshots, transparent compression, and boot-to-snapshot rollback — not bolted on, built in.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M4 7h16v12H4V7z"/>
|
||||||
|
<path d="M8 3v4"/>
|
||||||
|
<path d="M16 3v4"/>
|
||||||
|
<path d="M4 13h16" stroke-dasharray="2 1"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Developer-ready</h3>
|
||||||
|
<p>Go, Rust, Python, Node.js toolchains pre-configured. Git, Make, LLVM/Clang included. Start building immediately.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="3"/>
|
||||||
|
<path d="M12 2L22 8.5v7L12 22 2 15.5v-7L12 2z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Infrastructure-aware</h3>
|
||||||
|
<p>Prometheus node_exporter, Grafana dashboards, and Loki log aggregation — pre-configured out of the box.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="principle">
|
||||||
|
<div class="principle-icon">
|
||||||
|
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M4 4h8l4 4v12H4V4z"/>
|
||||||
|
<path d="M12 4v4h4"/>
|
||||||
|
<line x1="8" y1="12" x2="16" y2="12" stroke-opacity="0.5"/>
|
||||||
|
<line x1="8" y1="15" x2="13" y2="15" stroke-opacity="0.5"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Fully documented</h3>
|
||||||
|
<p>Every feature and tool includes offline man pages and a hardening guide. You own the system — and you understand it.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- What's Included -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">what's included</div>
|
||||||
|
<h2>Production-ready from first boot.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
Arcline OS layers pre-configured infrastructure tooling on top of a hardened
|
||||||
|
Debian base. Everything is documented, auditable, and yours.
|
||||||
|
</p>
|
||||||
|
<div class="stack-grid">
|
||||||
|
<div class="stack-card">
|
||||||
|
<div class="stack-header">Base System</div>
|
||||||
|
<ul>
|
||||||
|
<li>Debian stable (Bookworm)</li>
|
||||||
|
<li>Hardened Linux kernel (lockdown, seccomp)</li>
|
||||||
|
<li>btrfs root + snapshot rollback</li>
|
||||||
|
<li>nftables firewall (default-deny)</li>
|
||||||
|
<li>Docker + Podman containers</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="stack-card">
|
||||||
|
<div class="stack-header">Arcline Toolchain</div>
|
||||||
|
<ul>
|
||||||
|
<li>arcline-uptime — service monitoring</li>
|
||||||
|
<li>arcline-check — privacy auditor</li>
|
||||||
|
<li>arcline-audit — site health scanner</li>
|
||||||
|
<li>arcline-dns — propagation checker</li>
|
||||||
|
<li>arcline-vault — secrets store</li>
|
||||||
|
<li>arcline-email — self-hosted mail stack</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="stack-card">
|
||||||
|
<div class="stack-header">Developer Environment</div>
|
||||||
|
<ul>
|
||||||
|
<li>Go, Rust, Python, Node.js</li>
|
||||||
|
<li>Git, Make, CMake, LLVM/Clang</li>
|
||||||
|
<li>Docker / Podman pre-configured</li>
|
||||||
|
<li>VS Code / Helix / Vim configs</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="stack-card">
|
||||||
|
<div class="stack-header">Observability</div>
|
||||||
|
<ul>
|
||||||
|
<li>Prometheus node_exporter</li>
|
||||||
|
<li>Grafana dashboards</li>
|
||||||
|
<li>Loki log aggregation</li>
|
||||||
|
<li>Pre-built alerting rules</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="edition-teaser">
|
||||||
|
<div class="edition-teaser-badge">// also in the works</div>
|
||||||
|
<p>
|
||||||
|
<strong>Arcline Workstation</strong> — same hardened base, with a lightweight KDE Plasma desktop,
|
||||||
|
pre-configured dev toolchains, and privacy-hardened browser profiles.
|
||||||
|
One ISO. Two targets. Pick yours at install time.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Toolchain deep-dive -->
|
||||||
|
<section id="toolchain" class="section section-alt">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">the toolchain</div>
|
||||||
|
<h2>11 Go tools. Built in production.<br>Yours to use.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
Every Arcline tool was built to solve real infrastructure problems.
|
||||||
|
They run in production at Arcline IT. Now they ship with Arcline OS.
|
||||||
|
</p>
|
||||||
|
<div class="tool-grid">
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-uptime</code>
|
||||||
|
<span>HTTP, TCP, TLS, DNS monitoring with Prometheus metrics export</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-check</code>
|
||||||
|
<span>CDN and transparency auditor — verifies sites aren't leaking data</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-audit</code>
|
||||||
|
<span>Full site health scanner — SSL, headers, performance, accessibility</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-dns</code>
|
||||||
|
<span>DNS propagation checker across multiple resolvers</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-vault</code>
|
||||||
|
<span>Encrypted secrets store with REST API and CLI</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-email</code>
|
||||||
|
<span>Self-hosted SMTP/IMAP stack — OpenSMTPD + Dovecot + Rspamd</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-migrate</code>
|
||||||
|
<span>cPanel and Plesk to Arcline migration tool</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-billing</code>
|
||||||
|
<span>Stripe-powered subscription management</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-portal</code>
|
||||||
|
<span>Customer dashboard with SSL monitoring and ticketing</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-website</code>
|
||||||
|
<span>Go HTTP server powering arcline.it</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool">
|
||||||
|
<code>arcline-status</code>
|
||||||
|
<span>Static status page generator</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Why Arcline OS -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">why arcline os?</div>
|
||||||
|
<h2>No major Linux distro ships<br>pre-hardened for production.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
Debian gives you the packages. Arcline OS assembles them into a finished
|
||||||
|
system. A privacy-first, zero-telemetry operating system with built-in
|
||||||
|
monitoring, auditing, and security — configured the way you'd do it
|
||||||
|
yourself, if you had the weekend.
|
||||||
|
</p>
|
||||||
|
<div class="compare-grid">
|
||||||
|
<div class="compare-card">
|
||||||
|
<div class="compare-label">Ubuntu Server</div>
|
||||||
|
<div class="compare-desc">Great ecosystem and hardware support — but Snap packages and cloud integration are baked in by default.</div>
|
||||||
|
</div>
|
||||||
|
<div class="compare-card">
|
||||||
|
<div class="compare-label">Fedora Server</div>
|
||||||
|
<div class="compare-desc">Cutting-edge kernel and tooling — but rapid release cycles mean more churn on production machines.</div>
|
||||||
|
</div>
|
||||||
|
<div class="compare-card">
|
||||||
|
<div class="compare-label">Alpine Linux</div>
|
||||||
|
<div class="compare-desc">Minimal and musl-based — ideal for containers, but limited as a full-featured server workstation.</div>
|
||||||
|
</div>
|
||||||
|
<div class="compare-card compare-highlight">
|
||||||
|
<div class="compare-label">Arcline OS</div>
|
||||||
|
<div class="compare-desc">Hardened Debian base. Pre-configured toolchain. Built-in observability. Zero telemetry. Ready to deploy.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Contribute -->
|
||||||
|
<section id="contribute" class="section section-alt">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">community</div>
|
||||||
|
<h2>Built in the open. Shaped by the<br>people who use it.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
Arcline OS is open-source under the GPL. The code lives on
|
||||||
|
<a href="https://git.arcline.it" class="inline-link">git.arcline.it</a>.
|
||||||
|
Every tool, every config, every build script — auditable and forkable.
|
||||||
|
</p>
|
||||||
|
<div class="contribute-grid">
|
||||||
|
<a href="https://git.arcline.it" class="contribute-card">
|
||||||
|
<div class="contribute-icon">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 00-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0020 4.77 5.07 5.07 0 0019.91 1S18.73.65 15.23 2.5a13.38 13.38 0 00-7 0C5.27.65 4.09 1 4.09 1A5.07 5.07 0 004 4.77a5.44 5.44 0 00-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 008 18.13V22"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span>Browse the source</span>
|
||||||
|
<small>All 11 tools, build scripts, and infrastructure code.</small>
|
||||||
|
</a>
|
||||||
|
<a href="https://git.arcline.it" class="contribute-card">
|
||||||
|
<div class="contribute-icon">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
|
||||||
|
<polyline points="14 2 14 8 20 8"/>
|
||||||
|
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||||
|
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span>Read the docs</span>
|
||||||
|
<small>Hardening guides, install docs, and infrastructure cookbook.</small>
|
||||||
|
</a>
|
||||||
|
<a href="https://git.arcline.it" class="contribute-card">
|
||||||
|
<div class="contribute-icon">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<path d="M12 6v6l4 2"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span>Contribute</span>
|
||||||
|
<small>Submit patches, report issues, or join the discussion.</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Get Started -->
|
||||||
|
<section id="get-started" class="section">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">get started</div>
|
||||||
|
<h2>Arcline OS is in active development.<br>Be there at the start.</h2>
|
||||||
|
<p class="section-desc">
|
||||||
|
We're packaging the tools, building the ISO pipeline, and hardening the defaults.
|
||||||
|
Sign up to receive early access and help shape the first release.
|
||||||
|
</p>
|
||||||
|
<form
|
||||||
|
hx-post="/partials/waitlist"
|
||||||
|
hx-target="#waitlist-result"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
class="waitlist-form"
|
||||||
|
>
|
||||||
|
<fieldset class="edition-checkboxes">
|
||||||
|
<legend>I'm interested in:</legend>
|
||||||
|
<label class="edition-checkbox">
|
||||||
|
<input type="checkbox" name="edition" value="server" checked>
|
||||||
|
<span>Server</span>
|
||||||
|
</label>
|
||||||
|
<label class="edition-checkbox">
|
||||||
|
<input type="checkbox" name="edition" value="workstation">
|
||||||
|
<span>Workstation</span>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
placeholder="you@example.com"
|
||||||
|
required
|
||||||
|
class="input"
|
||||||
|
>
|
||||||
|
<button type="submit" class="btn">Get Early Access</button>
|
||||||
|
</form>
|
||||||
|
<div id="waitlist-result"></div>
|
||||||
|
<p class="waitlist-note">No spam. No tracking. We'll only email you when there's something to try.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Sponsor -->
|
||||||
|
<section class="section section-alt sponsor-section">
|
||||||
|
<div class="section-inner">
|
||||||
|
<div class="section-label">sponsored by</div>
|
||||||
|
<div class="sponsor-content">
|
||||||
|
<div class="sponsor-desc">
|
||||||
|
<p>The Arcline Project is funded and operated by <strong>Arcline IT LLC</strong> — the same model as Red Hat and Fedora. The commercial services business at <a href="https://arcline.it" class="inline-link">arcline.it</a> keeps the lights on so the OS stays independent and sustainable.</p>
|
||||||
|
</div>
|
||||||
|
<div class="sponsor-tagline">Secure by default. Self-hosted by principle.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="footer-inner">
|
||||||
|
<div class="footer-brand">
|
||||||
|
<a href="/" class="footer-logo">Arcline Project</a>
|
||||||
|
<p>An open-source OS for people who run infrastructure.</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-links">
|
||||||
|
<a href="https://arcline.it">Arcline IT</a>
|
||||||
|
<a href="https://git.arcline.it">Git</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>© 2026 Arcline IT LLC. GPL Licensed. No telemetry. No tracking.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
2
templates/partials/waitlist_confirmation.html
Normal file
2
templates/partials/waitlist_confirmation.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<p class="confirmation">Thanks {{.Email}}! We'll be in touch.</p>
|
||||||
|
|
||||||
Reference in New Issue
Block a user