infra(cx2-5): DNS auth/NetPol substrate, air-gap landing, arm64 ARC runner + tenant landing manifests
- fc-dns: add OnePasswordItem CRD for DNS API keys + NetworkPolicy for Phase 0 auth hardening; bump dns-web image tag - fc-landing: rewrite landing HTML to remove CDN dependencies (air-gap safe); add preview.html standalone preview - github-runner: add TOOLCACHE_ARCH to install-ruby-toolcache.sh for arm64 support; add Dockerfile.arm64 for arm64 ARC runner image - docs/gx10-tenant-landing: per-user Deployment+IngressRoute manifests (andrew/dustin/erik/fit/matt) + CUTOVER-RUNBOOK.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ metadata:
|
||||
labels:
|
||||
app.kubernetes.io/part-of: bluejay-infra
|
||||
---
|
||||
# Landing page HTML (public-safe - no internal LAN references)
|
||||
# Landing page HTML (public-safe - no internal LAN references, no CDN)
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
@@ -20,144 +20,357 @@ data:
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>FlowerCore</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #0a1628 0%, #1a2744 50%, #0d1f3c 100%);
|
||||
color: #e0e8f0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.hero {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
max-width: 800px;
|
||||
}
|
||||
.logo {
|
||||
font-size: 5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
filter: drop-shadow(0 0 20px rgba(74, 158, 255, 0.3));
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
background: linear-gradient(135deg, #4a9eff, #7ab3ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 1.3rem;
|
||||
color: #7ab3ff;
|
||||
font-weight: 300;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.description {
|
||||
font-size: 1rem;
|
||||
color: #8aa8c4;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 3rem;
|
||||
max-width: 600px;
|
||||
}
|
||||
.services {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
max-width: 700px;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
.service {
|
||||
background: rgba(74, 158, 255, 0.08);
|
||||
border: 1px solid rgba(74, 158, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
padding: 1.2rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.service:hover {
|
||||
background: rgba(74, 158, 255, 0.15);
|
||||
border-color: rgba(74, 158, 255, 0.5);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.service h3 { color: #4a9eff; font-size: 0.95rem; margin-bottom: 0.3rem; }
|
||||
.service p { color: #8aa8c4; font-size: 0.8rem; }
|
||||
.status-bar {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
padding: 1rem 2rem;
|
||||
background: rgba(74, 158, 255, 0.05);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(74, 158, 255, 0.1);
|
||||
}
|
||||
.status-item { text-align: center; }
|
||||
.status-item .value { color: #4a9eff; font-size: 1.5rem; font-weight: 700; }
|
||||
.status-item .label { color: #6a8ca4; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; }
|
||||
.footer {
|
||||
margin-top: 3rem;
|
||||
color: #4a6580;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.footer a { color: #4a6580; text-decoration: none; }
|
||||
.footer a:hover { color: #7ab3ff; }
|
||||
</style>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>FlowerCore</title>
|
||||
<!--
|
||||
FlowerCore public landing page.
|
||||
Air-gap safe: zero CDN, zero external fonts, zero external scripts.
|
||||
All assets are inline SVG / CSS / JS only.
|
||||
Update Center link: https://update.flowercore.io/
|
||||
Animation: bloom mark (8-petal flower) rotates slowly with a floating
|
||||
seed-core pulse. Respects prefers-reduced-motion (animation disabled).
|
||||
-->
|
||||
<style>
|
||||
/* ── Blue Jay palette (matches decisions-waiting.html tokens) ── */
|
||||
:root {
|
||||
--bg: #0A1628;
|
||||
--bg2: #0E1E36;
|
||||
--surface: #111D33;
|
||||
--border: #1E3A5F;
|
||||
--text: #E8EDF5;
|
||||
--text-muted: #8899B3;
|
||||
--gold: #FFB300;
|
||||
--gold-light: #FFCA40;
|
||||
--gold-dim: #CC8F00;
|
||||
--ice: #82BBFF;
|
||||
--steel: #2E5FA3;
|
||||
}
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
|
||||
background: radial-gradient(ellipse at 60% 30%, #13233E 0%, #0C1A30 55%, #081222 100%);
|
||||
color: var(--text);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem 1rem;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* ── Skip link (keyboard accessibility) ── */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
left: -999px;
|
||||
top: 0;
|
||||
background: var(--gold);
|
||||
color: #0A1628;
|
||||
padding: 8px 16px;
|
||||
border-radius: 0 0 8px 0;
|
||||
font-weight: 700;
|
||||
z-index: 100;
|
||||
text-decoration: none;
|
||||
}
|
||||
.skip-link:focus { left: 0; }
|
||||
|
||||
/* ── Focus ring ── */
|
||||
a:focus-visible, button:focus-visible {
|
||||
outline: 3px solid var(--ice);
|
||||
outline-offset: 3px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* ── Background star field (CSS only, no JS needed) ── */
|
||||
.starfield {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
.star {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
opacity: 0;
|
||||
animation: twinkle var(--d, 4s) var(--delay, 0s) ease-in-out infinite;
|
||||
}
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0; transform: scale(0.5); }
|
||||
50% { opacity: var(--op, 0.5); transform: scale(1); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.star { animation: none; opacity: 0.2; }
|
||||
}
|
||||
|
||||
/* ── Main content ── */
|
||||
main {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
max-width: 520px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ── Bloom mark container ── */
|
||||
.bloom-wrap {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Outer glow ring */
|
||||
.bloom-wrap::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -24px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(255,179,0,0.12) 0%, transparent 70%);
|
||||
animation: pulse-glow 3s ease-in-out infinite;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.bloom-wrap::before { animation: none; }
|
||||
}
|
||||
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% { transform: scale(1); opacity: 1; }
|
||||
50% { transform: scale(1.12); opacity: 0.7; }
|
||||
}
|
||||
|
||||
/* The bloom SVG itself */
|
||||
.bloom-svg {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
animation: bloom-spin 24s linear infinite;
|
||||
transform-origin: center;
|
||||
filter: drop-shadow(0 0 18px rgba(255,179,0,0.35));
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.bloom-svg { animation: none; }
|
||||
}
|
||||
|
||||
@keyframes bloom-spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Seed core counter-rotates so it stays upright */
|
||||
.bloom-core {
|
||||
animation: bloom-counter 24s linear infinite;
|
||||
transform-origin: 80px 80px; /* center of 160px viewBox */
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.bloom-core { animation: none; }
|
||||
}
|
||||
|
||||
@keyframes bloom-counter {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(-360deg); }
|
||||
}
|
||||
|
||||
/* Core pulse */
|
||||
.bloom-core-circle {
|
||||
animation: core-pulse 2.4s ease-in-out infinite;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.bloom-core-circle { animation: none; }
|
||||
}
|
||||
|
||||
@keyframes core-pulse {
|
||||
0%, 100% { r: 13; }
|
||||
50% { r: 17; }
|
||||
}
|
||||
|
||||
/* ── Wordmark ── */
|
||||
.wordmark {
|
||||
letter-spacing: 0.22em;
|
||||
font-size: 1.9rem;
|
||||
font-weight: 800;
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.35rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.12em;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
/* ── Update Center link (primary action) ── */
|
||||
.update-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
background: var(--gold);
|
||||
color: #0A1628;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 0.75rem 1.75rem;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
border: 2px solid var(--gold);
|
||||
transition: background 0.18s, border-color 0.18s, transform 0.15s;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
.update-link:hover {
|
||||
background: var(--gold-light);
|
||||
border-color: var(--gold-light);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.update-link:active {
|
||||
background: var(--gold-dim);
|
||||
border-color: var(--gold-dim);
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* Arrow icon inside the button */
|
||||
.update-link svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ── "More soon" note ── */
|
||||
.more-soon {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.06em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ── Footer ── */
|
||||
footer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 3rem;
|
||||
color: #2E5FA3;
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.05em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 400px) {
|
||||
.bloom-wrap { width: 140px; height: 140px; }
|
||||
.bloom-svg { width: 124px; height: 124px; }
|
||||
.bloom-core { transform-origin: 62px 62px; }
|
||||
.wordmark { font-size: 1.5rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="hero">
|
||||
<div class="logo">🌻</div>
|
||||
<h1>FlowerCore</h1>
|
||||
<p class="subtitle">Blue Jay Lab</p>
|
||||
<p class="description">
|
||||
Multi-tenant service management platform built on .NET 10,
|
||||
Kubernetes, and GitOps. Digital signage, telephony IVR,
|
||||
MySQL/PHP hosting, and infrastructure automation.
|
||||
</p>
|
||||
<a href="#main" class="skip-link">Skip to content</a>
|
||||
|
||||
<!-- CSS-only star field: 20 stars, varied positions/sizes/speeds -->
|
||||
<div class="starfield" aria-hidden="true">
|
||||
<div class="star" style="width:2px;height:2px;top:8%;left:12%;--d:5s;--delay:0.3s;--op:0.6"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:15%;left:75%;--d:7s;--delay:1.1s;--op:0.4"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:22%;left:45%;--d:4s;--delay:0.7s;--op:0.5"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:30%;left:88%;--d:6s;--delay:2.0s;--op:0.3"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:40%;left:5%;--d:8s;--delay:0.4s;--op:0.4"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:55%;left:30%;--d:5s;--delay:1.5s;--op:0.35"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:65%;left:62%;--d:7s;--delay:0.9s;--op:0.45"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:72%;left:20%;--d:4s;--delay:2.3s;--op:0.5"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:80%;left:82%;--d:6s;--delay:0.1s;--op:0.3"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:88%;left:50%;--d:9s;--delay:1.7s;--op:0.4"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:5%;left:55%;--d:6s;--delay:3.1s;--op:0.3"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:18%;left:92%;--d:5s;--delay:0.5s;--op:0.5"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:35%;left:68%;--d:7s;--delay:1.9s;--op:0.35"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:48%;left:18%;--d:4s;--delay:2.7s;--op:0.45"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:60%;left:95%;--d:8s;--delay:0.6s;--op:0.3"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:75%;left:40%;--d:6s;--delay:1.3s;--op:0.4"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:85%;left:70%;--d:5s;--delay:2.9s;--op:0.35"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:92%;left:8%;--d:7s;--delay:0.2s;--op:0.5"></div>
|
||||
<div class="star" style="width:1px;height:1px;top:10%;left:33%;--d:4s;--delay:1.8s;--op:0.3"></div>
|
||||
<div class="star" style="width:2px;height:2px;top:93%;left:88%;--d:9s;--delay:3.5s;--op:0.4"></div>
|
||||
</div>
|
||||
|
||||
<main id="main">
|
||||
<!-- Animated bloom mark -->
|
||||
<div class="bloom-wrap" role="img" aria-label="FlowerCore bloom mark">
|
||||
<!--
|
||||
Bloom mark: 8 elliptical petals + outer ring + pulsing seed core.
|
||||
Source of truth: scripts/reformat/branding/oem-logo-bluejay.svg
|
||||
Petals rotate slowly (24s/rev). Core counter-rotates to stay upright.
|
||||
Outer glow added via CSS. Respects prefers-reduced-motion.
|
||||
-->
|
||||
<svg class="bloom-svg" viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true" focusable="false">
|
||||
<defs>
|
||||
<radialGradient id="petal-grad" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#FFCA40" stop-opacity="0.95"/>
|
||||
<stop offset="100%" stop-color="#FFB300" stop-opacity="0.7"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="core-grad" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#FFCA40"/>
|
||||
<stop offset="100%" stop-color="#CC8F00"/>
|
||||
</radialGradient>
|
||||
<!-- Petal shape: thin tall ellipse offset upward from origin -->
|
||||
<ellipse id="petal" cx="0" cy="-38" rx="6.5" ry="26"
|
||||
fill="none" stroke="url(#petal-grad)" stroke-width="1.8" opacity="0.85"/>
|
||||
</defs>
|
||||
|
||||
<!-- 8 petals, each 45° apart, centred at 80,80 -->
|
||||
<g transform="translate(80 80)">
|
||||
<use href="#petal" transform="rotate(0)"/>
|
||||
<use href="#petal" transform="rotate(45)"/>
|
||||
<use href="#petal" transform="rotate(90)"/>
|
||||
<use href="#petal" transform="rotate(135)"/>
|
||||
<use href="#petal" transform="rotate(180)"/>
|
||||
<use href="#petal" transform="rotate(225)"/>
|
||||
<use href="#petal" transform="rotate(270)"/>
|
||||
<use href="#petal" transform="rotate(315)"/>
|
||||
<!-- Outer ring -->
|
||||
<circle r="44" fill="none" stroke="#FFB300" stroke-width="1.5" opacity="0.6"/>
|
||||
<!-- Seed core: counter-rotates via CSS so it stays upright -->
|
||||
<g class="bloom-core">
|
||||
<circle class="bloom-core-circle" r="13" fill="url(#core-grad)"/>
|
||||
<circle r="13" fill="none" stroke="#0A1628" stroke-width="1.5" opacity="0.45"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="services">
|
||||
<a class="service" href="https://gitea.flowercore.io">
|
||||
<h3>Source</h3>
|
||||
<p>Gitea repositories</p>
|
||||
</a>
|
||||
<a class="service" href="https://webmail.flowercore.io">
|
||||
<h3>Mail</h3>
|
||||
<p>Webmail access</p>
|
||||
</a>
|
||||
<a class="service" href="https://element.flowercore.io">
|
||||
<h3>Chat</h3>
|
||||
<p>Matrix messaging</p>
|
||||
</a>
|
||||
<a class="service" href="https://github.com/FlowerCoreIO">
|
||||
<h3>GitHub</h3>
|
||||
<p>Open source</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="status-bar">
|
||||
<div class="status-item">
|
||||
<div class="value">17</div>
|
||||
<div class="label">Services</div>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<div class="value">13</div>
|
||||
<div class="label">VLANs</div>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<div class="value">12k+</div>
|
||||
<div class="label">Tests</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="footer">
|
||||
FlowerCore · Bare-metal RKE2 · ArgoCD managed
|
||||
· <a href="mailto:admin@flowercore.io">Contact</a>
|
||||
</p>
|
||||
|
||||
<!-- Wordmark -->
|
||||
<p class="wordmark">FlowerCore</p>
|
||||
<p class="tagline">More to come.</p>
|
||||
|
||||
<!-- Primary CTA: Update Center -->
|
||||
<a class="update-link" href="https://update.flowercore.io/" target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<!-- Inline download/arrow SVG — no external ref -->
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true" focusable="false">
|
||||
<path d="M8 2v8M4 7l4 4 4-4" stroke="#0A1628" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2 13h12" stroke="#0A1628" stroke-width="2"
|
||||
stroke-linecap="round"/>
|
||||
</svg>
|
||||
Update Center
|
||||
</a>
|
||||
|
||||
<p class="more-soon">Software updates & releases</p>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
© FlowerCore
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user