Files
boc/landvex-site/status/index.html
T
Bernt 6989a98d75 feat: Passwordless cross-device authentication
- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
2026-07-07 07:11:50 +00:00

715 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>System Status — Landvex</title>
<meta name="description" content="Current operational status for Landvex Intelligence Platform components, API, and data pipeline.">
<link rel="canonical" href="https://www.landvex.com/status/">
<meta name="robots" content="index, follow">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://www.landvex.com/status/">
<meta property="og:title" content="System Status — Landvex">
<meta property="og:description" content="Current operational status for Landvex Intelligence Platform components, API, and data pipeline.">
<meta property="og:image" content="https://www.landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="System Status — Landvex">
<meta name="twitter:description" content="Current operational status for Landvex Intelligence Platform.">
<!-- Favicons -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg-dark: #f5f5f7;
--blue: #0066FF;
--blue-dark: #0052CC;
--blue-glow: rgba(0, 102, 255, 0.15);
--text-dark: #0a0a0a;
--text-body: #3a3a3a;
--text-muted: #6B6B6B;
--text-light: #1d1d1f;
--text-dim: #6B6B6B;
--surface: #ffffff;
--surface-2: #f5f5f7;
--border: rgba(0,0,0,0.08);
--border-light: #e8eaf0;
--green: #16a34a;
--green-bg: #f0fdf4;
--green-border: #bbf7d0;
--green-dot: #22c55e;
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 24px;
}
html { scroll-behavior: smooth; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Helvetica Neue', sans-serif;
background: #fff;
color: var(--text-body);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
/* NAV */
nav {
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
display: flex; align-items: center; justify-content: space-between;
padding: 0 40px;
height: 64px;
background: rgba(0,0,0,0.92);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
}
.nav-logo {
font-size: 18px;
font-weight: 700;
letter-spacing: -0.3px;
color: #1d1d1f;
}
.nav-links {
display: flex; gap: 32px; list-style: none;
}
.nav-links a {
font-size: 14px;
color: var(--text-dim);
transition: color 0.2s;
}
.nav-links a:hover { color: #1d1d1f; }
.btn {
display: inline-flex; align-items: center; gap: 6px;
padding: 10px 22px;
background: var(--blue);
color: #1d1d1f;
font-size: 14px;
font-weight: 600;
border-radius: var(--radius-md);
border: none;
cursor: pointer;
transition: background 0.2s, transform 0.15s;
}
.btn:hover { background: var(--blue-dark); transform: translateY(-1px); }
.btn-outline {
background: transparent;
border: 1.5px solid rgba(0,0,0,0.18);
color: var(--text-light);
}
.btn-outline:hover { background: rgba(0,0,0,0.04); transform: translateY(-1px); }
/* HERO */
.hero {
background: var(--bg-dark);
padding: 120px 24px 72px;
text-align: center;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -120px; left: 50%; transform: translateX(-50%);
width: 900px; height: 500px;
background: radial-gradient(ellipse at center, rgba(0,102,255,0.10) 0%, transparent 70%);
pointer-events: none;
}
.hero-eyebrow {
display: inline-flex; align-items: center; gap: 8px;
background: rgba(0,102,255,0.1);
border: 1px solid rgba(0,102,255,0.25);
color: #5599ff;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 6px 16px;
border-radius: 100px;
margin-bottom: 24px;
}
.hero h1 {
font-size: clamp(32px, 5vw, 52px);
font-weight: 800;
letter-spacing: -1.5px;
line-height: 1.1;
color: #1d1d1f;
margin-bottom: 16px;
}
.hero-sub {
font-size: 17px;
color: var(--text-dim);
max-width: 520px;
line-height: 1.7;
margin: 0 auto 40px;
}
/* OVERALL STATUS BANNER */
.status-banner {
max-width: 860px;
margin: 0 auto 0;
background: var(--green-bg);
border: 1.5px solid var(--green-border);
border-radius: var(--radius-lg);
padding: 20px 28px;
display: flex;
align-items: center;
gap: 16px;
}
.status-banner-dot {
width: 14px; height: 14px;
border-radius: var(--radius-full);
background: var(--green-dot);
flex-shrink: 0;
box-shadow: 0 0 0 4px rgba(34,197,94,0.18);
animation: pulse-green 2.5s ease-in-out infinite;
}
@keyframes pulse-green {
0%, 100% { box-shadow: 0 0 0 4px rgba(34,197,94,0.18); }
50% { box-shadow: 0 0 0 8px rgba(34,197,94,0.08); }
}
.status-banner-text {
flex: 1;
}
.status-banner-title {
font-size: 16px;
font-weight: 700;
color: var(--green);
letter-spacing: -0.2px;
}
.status-banner-sub {
font-size: 13px;
color: #15803d;
margin-top: 2px;
}
.status-banner-updated {
font-size: 12px;
color: #86efac;
background: rgba(22,163,74,0.1);
border: 1px solid rgba(22,163,74,0.2);
padding: 5px 12px;
border-radius: 100px;
white-space: nowrap;
}
/* MAIN CONTENT */
.main {
max-width: 860px;
margin: 0 auto;
padding: 0 24px 80px;
}
/* UPTIME STATS */
.uptime-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin: 40px 0 0;
}
.uptime-card {
background: #f8f9fc;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 20px 22px;
text-align: center;
}
.uptime-value {
font-size: 26px;
font-weight: 800;
color: var(--text-dark);
letter-spacing: -0.8px;
margin-bottom: 4px;
}
.uptime-label {
font-size: 13px;
color: var(--text-muted);
}
/* SECTION HEADERS */
.section-heading {
font-size: 18px;
font-weight: 800;
color: var(--text-dark);
letter-spacing: -0.4px;
margin: 48px 0 16px;
padding-bottom: 12px;
border-bottom: 1px solid var(--border-light);
}
/* COMPONENT LIST */
.component-list {
display: flex;
flex-direction: column;
gap: 1px;
background: var(--border-light);
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
overflow: hidden;
}
.component-item {
background: #fff;
padding: 16px 20px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
transition: background 0.15s;
}
.component-item:hover {
background: #f8f9fc;
}
.component-left {
display: flex;
align-items: center;
gap: 14px;
}
.component-icon {
width: 36px; height: 36px;
background: rgba(0,102,255,0.07);
border-radius: var(--radius-sm);
display: flex; align-items: center; justify-content: center;
font-size: 17px;
flex-shrink: 0;
}
.component-name {
font-size: 15px;
font-weight: 600;
color: var(--text-dark);
letter-spacing: -0.2px;
}
.component-desc {
font-size: 13px;
color: var(--text-muted);
margin-top: 1px;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 12px;
border-radius: 100px;
font-size: 12px;
font-weight: 700;
flex-shrink: 0;
}
.status-badge.operational {
background: var(--green-bg);
border: 1px solid var(--green-border);
color: var(--green);
}
.status-badge.degraded {
background: #fff8ec;
border: 1px solid #f5d78a;
color: #92400e;
}
.status-badge.outage {
background: #fef2f2;
border: 1px solid #fecaca;
color: #dc2626;
}
.status-dot {
width: 7px; height: 7px;
border-radius: var(--radius-full);
flex-shrink: 0;
}
.status-dot.operational { background: var(--green-dot); }
.status-dot.degraded { background: #f59e0b; }
.status-dot.outage { background: #ef4444; }
/* INCIDENT HISTORY */
.incident-box {
background: #f8f9fc;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
padding: 32px 28px;
text-align: center;
}
.incident-box-icon {
font-size: 36px;
margin-bottom: 14px;
}
.incident-box h3 {
font-size: 17px;
font-weight: 700;
color: var(--text-dark);
margin-bottom: 8px;
letter-spacing: -0.3px;
}
.incident-box p {
font-size: 14px;
color: var(--text-muted);
line-height: 1.6;
max-width: 400px;
margin: 0 auto;
}
/* SUBSCRIBE SECTION */
.subscribe-box {
background: var(--bg-dark);
border-radius: var(--radius-lg);
padding: 36px 40px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
flex-wrap: wrap;
margin-top: 48px;
}
.subscribe-box h3 {
font-size: 18px;
font-weight: 700;
color: #1d1d1f;
margin-bottom: 6px;
letter-spacing: -0.3px;
}
.subscribe-box p {
font-size: 14px;
color: rgba(0,0,0,0.6);
}
.subscribe-link {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--blue);
color: #1d1d1f;
font-size: 14px;
font-weight: 700;
padding: 12px 24px;
border-radius: var(--radius-md);
flex-shrink: 0;
transition: background 0.2s, transform 0.15s;
}
.subscribe-link:hover {
background: var(--blue-dark);
transform: translateY(-1px);
}
/* FOOTER */
footer {
background: var(--bg-dark);
border-top: 1px solid var(--border);
padding: 40px 40px;
}
.footer-inner {
max-width: 1140px; margin: 0 auto;
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 20px;
}
.footer-logo { font-size: 17px; font-weight: 700; color: #1d1d1f; }
.footer-copy { font-size: 13px; color: var(--text-muted); }
.footer-links { display: flex; gap: 24px; align-items: center; }
.footer-links a { font-size: 14px; color: var(--text-muted); transition: color 0.2s; }
.footer-links a:hover { color: #1d1d1f; }
.footer-social {
width: 32px; height: 32px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
transition: border-color 0.2s, background 0.2s;
}
.footer-social:hover { border-color: rgba(0,0,0,0.25); background: rgba(0,0,0,0.04); }
.footer-tagline { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
/* RESPONSIVE */
@media (max-width: 700px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
.uptime-grid { grid-template-columns: 1fr; }
.status-banner { flex-direction: column; align-items: flex-start; gap: 12px; }
.subscribe-box { flex-direction: column; }
.footer-inner { flex-direction: column; }
.hero { padding: 110px 20px 56px; }
.main { padding: 0 20px 60px; }
}
@media (max-width: 600px) {
nav { padding: 0 16px !important; }
.main { padding: 0 16px 48px !important; }
.hero { padding: 100px 16px 48px !important; }
.uptime-grid { grid-template-columns: repeat(2, 1fr) !important; }
.subscribe-box { padding: 24px 16px !important; }
}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Landvex",
"item": "https://www.landvex.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "System Status",
"item": "https://www.landvex.com/status/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://www.landvex.com/">
<link rel="alternate" hreflang="en" href="https://www.landvex.com/">
<style>
@media (max-width: 640px) {
.hero h1 { font-size: 2rem !important; }
.hero p { font-size: 1rem !important; }
.card { padding: 1.5rem !important; }
.grid { grid-template-columns: 1fr !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 1rem !important; }
}
</style>
</head>
<body>
<nav aria-label="breadcrumb" style="padding: 10px 20px; color: rgba(235,235,245,0.6); font-size: 14px;">
<a href="/" style="color: #007AFF; text-decoration: none;">Home</a> / <span>status</span>
</nav>
<!-- NAV -->
<nav>
<a class="nav-logo" href="/">LandveX</a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/methodology/">Methodology</a></li>
<li><a href="https://www.landvex.com/#contact">Contact</a></li>
</ul>
<a class="btn btn-outline" href="https://www.landvex.com/#contact">Get in touch →</a>
</nav>
<!-- HERO -->
<section class="hero">
<div class="hero-eyebrow">
<span style="display:inline-block;width:8px;height:8px;border-radius: var(--radius-full);background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,0.25);"></span>
All systems ready for August 2026 launch
</div>
<h1>System Status</h1>
<p class="hero-sub">Live status for the Landvex Intelligence Platform. Updated automatically.</p>
<div style="max-width:860px;margin:0 auto;padding:0 0px;">
<div class="status-banner">
<div class="status-banner-dot"></div>
<div class="status-banner-text">
<div class="status-banner-title">All Systems Operational</div>
<div class="status-banner-sub">No degradations or outages detected across any platform component.</div>
</div>
<div class="status-banner-updated" id="last-updated">Checking…</div>
</div>
</div>
</section>
<!-- MAIN CONTENT -->
<div style="background:#fff;padding-top:40px;">
<div class="main">
<!-- UPTIME STATS -->
<div class="uptime-grid">
<div class="uptime-card">
<div class="uptime-value">99.9%</div>
<div class="uptime-label">Uptime · last 90 days</div>
</div>
<div class="uptime-card">
<div class="uptime-value">0</div>
<div class="uptime-label">Incidents · last 90 days</div>
</div>
<div class="uptime-card">
<div class="uptime-value">&lt;80ms</div>
<div class="uptime-label">API response · median</div>
</div>
</div>
<!-- COMPONENTS -->
<div class="section-heading">Platform Components</div>
<div class="component-list">
<div class="component-item">
<div class="component-left">
<div class="component-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M9 2L5 9H8L7 14L11 7H8L9 2Z" fill="#f59e0b"/></svg></div>
<div>
<div class="component-name">Intelligence API</div>
<div class="component-desc">Scores, reports, and raw data endpoints</div>
</div>
</div>
<div class="status-badge operational">
<span class="status-dot operational"></span>
Operational
</div>
</div>
<div class="component-item">
<div class="component-left">
<div class="component-icon"></div>
<div>
<div class="component-name">Field Data Collection (quiXzoom)</div>
<div class="component-desc">Contributor network ingestion and review pipeline</div>
</div>
</div>
<div class="status-badge operational">
<span class="status-dot operational"></span>
Operational
</div>
</div>
<div class="component-item">
<div class="component-left">
<div class="component-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 8C2 11.3 4.7 14 8 14C10.5 14 12.7 12.5 13.7 10.3" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M14 8C14 4.7 11.3 2 8 2C5.5 2 3.3 3.5 2.3 5.7" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M13.5 7.5L14 10L11.5 9.5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M2.5 8.5L2 6L4.5 6.5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<div>
<div class="component-name">Data Processing Pipeline</div>
<div class="component-desc">Normalization, scoring, and contradiction detection</div>
</div>
</div>
<div class="status-badge operational">
<span class="status-dot operational"></span>
Operational
</div>
</div>
<div class="component-item">
<div class="component-left">
<div class="component-icon"></div>
<div>
<div class="component-name">Web Platform</div>
<div class="component-desc">landvex.com and client portal</div>
</div>
</div>
<div class="status-badge operational">
<span class="status-dot operational"></span>
Operational
</div>
</div>
<div class="component-item">
<div class="component-left">
<div class="component-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="7" width="10" height="7" rx="1" stroke="#666" stroke-width="1.5"/><path d="M5 7V5C5 3.3 6.3 2 8 2C9.7 2 11 3.3 11 5V7" stroke="#666" stroke-width="1.5"/><circle cx="8" cy="10.5" r="1" fill="#666"/></svg></div>
<div>
<div class="component-name">Authentication</div>
<div class="component-desc">API authentication, contributor login, and session management</div>
</div>
</div>
<div class="status-badge operational">
<span class="status-dot operational"></span>
Operational
</div>
</div>
</div>
<!-- INCIDENT HISTORY -->
<div class="section-heading">Incident History</div>
<div class="incident-box">
<div class="incident-box-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#00C853" stroke-width="3"><path d="M20 6L9 17l-5-5"/></svg></div>
<h3>No incidents in the last 90 days</h3>
<p>All Landvex platform components have operated within their SLA targets for the past 90 days. No service degradations or outages have been recorded.</p>
</div>
<!-- SUBSCRIBE -->
<div class="subscribe-box">
<div>
<h3>Subscribe to status updates</h3>
<p>Get notified when we post incidents, scheduled maintenance, or service updates.</p>
</div>
<a class="subscribe-link" href="mailto:contact@landvex.com?subject=Status%20page%20updates&body=Please%20add%20me%20to%20Landvex%20status%20update%20notifications.">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
Subscribe via email
</a>
</div>
</div>
</div>
<!-- FOOTER -->
<footer>
<div class="footer-inner">
<div>
<div class="footer-logo">LandveX</div>
<div class="footer-copy">© 2026 Landvex Inc · Landvex AB (org.nr 559141-7042)</div>
<div class="footer-tagline">Decision intelligence for the physical world.</div>
</div>
<div class="footer-links">
<a href="/privacy">Privacy</a>
<a href="/terms">Terms</a>
<a href="/methodology/">Methodology</a>
<a href="mailto:contact@landvex.com">contact@landvex.com</a>
<a href="https://www.linkedin.com/company/landvex" target="_blank" rel="noopener" class="footer-social" title="LandveX on LinkedIn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" stroke="#888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="2" y="9" width="4" height="12" stroke="#888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="4" cy="4" r="2" stroke="#888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
<a href="https://x.com/landvex" target="_blank" rel="noopener" class="footer-social" title="LandveX on X">
<svg width="15" height="15" viewBox="0 0 24 24" fill="#888" xmlns="http://www.w3.org/2000/svg">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.746l7.73-8.835L1.254 2.25H8.08l4.253 5.622 5.912-5.622Zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
</a>
</div>
</div>
</footer>
<script>
// Auto-update "last updated" timestamp
function updateTimestamp() {
var el = document.getElementById('last-updated');
if (!el) return;
var now = new Date();
var pad = function(n) { return n < 10 ? '0' + n : n; };
var str = 'Updated ' + now.getFullYear() + '-' + pad(now.getMonth()+1) + '-' + pad(now.getDate()) +
' ' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ' UTC';
el.textContent = str;
}
updateTimestamp();
</script>
</body>
</html>