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