Files
boc/landvex-all/intelligence/city-health-index/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

503 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>City Health Index — Landvex Intelligence</title>
<meta name="description" content="A continuous composite score of urban condition, maintenance needs and change velocity. Updated from field observations. 0100 per city and district.">
<link rel="canonical" href="https://landvex.com/intelligence/city-health-index/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/intelligence/city-health-index/">
<meta property="og:title" content="City Health Index — Landvex Intelligence">
<meta property="og:description" content="A continuous composite score of urban condition, maintenance needs and change velocity. Updated from field observations. 0100 per city and district.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="City Health Index — Landvex">
<meta name="twitter:description" content="A continuous composite score of urban condition, maintenance needs, and change velocity across a defined area. Continuously verified from field observations.">
<meta name="twitter:image" content="https://landvex.com/og-image.jpg">
<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">
<script type="application/ld+json">{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "City Health Index — Landvex",
"description": "A continuous composite score of urban condition, maintenance needs, and change velocity across a defined area. Continuously verified from field observations.",
"url": "https://landvex.com/intelligence/city-health-index/",
"isPartOf": { "@type": "WebSite", "url": "https://landvex.com", "name": "Landvex" },
"publisher": { "@type": "Organization", "name": "Landvex", "url": "https://landvex.com" }
}</script>
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<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-body: #3a3a3a;
--text-muted: #6B6B6B;
--text-light: #1d1d1f;
--text-dim: #6B6B6B;
--surface: #ffffff;
--surface-2: #f5f5f7;
--border: rgba(0,0,0,0.08);
--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: var(--bg-dark);
color: var(--text-light);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
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(255,255,255,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: 16px; 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: 16px;
padding: 24px;
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); }
.btn-lg { padding: 24px; font-size: 16px; }
.hero {
min-height: 80vh;
display: flex; flex-direction: column; align-items: center; justify-content: center;
text-align: center; padding: 24px 80px;
position: relative; overflow: hidden;
}
/* Dekorativ bakgrund borttagen */
.hero-eyebrow { display: inline-flex; align-items: center; gap: 16px; color: #0066ff; font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 8px 0; }
.hero h1 {
font-size: clamp(36px, 6vw, 68px); font-weight: 800;
letter-spacing: -2px; line-height: 1.05; color: #1d1d1f;
max-width: 820px; margin-bottom: 24px;
}
.hero-sub {
font-size: clamp(16px, 2vw, 19px); color: var(--text-dim);
max-width: 640px; line-height: 1.65; margin-bottom: 40px;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
.container { max-width: 1140px; margin: 0 auto; }
section { padding: 24px; }
.section-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--blue); margin-bottom: 24px;
}
.section-title {
font-size: clamp(26px, 3.5vw, 40px); font-weight: 800;
letter-spacing: -1px; line-height: 1.1; color: #1d1d1f; margin-bottom: 24px;
}
.section-title-light { color: #0a0a0a; }
.section-sub { font-size: 17px; color: var(--text-dim); max-width: 560px; line-height: 1.7; }
.contact-form {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 40px; text-align: left;
}
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; }
.form-group { display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px; }
.form-group label { font-size: 13px; font-weight: 600; color: var(--text-dim); }
.form-group input, .form-group textarea {
background: var(--bg-dark); border: 1.5px solid var(--border);
border-radius: var(--radius-md); color: #1d1d1f; font-size: 15px;
font-family: inherit; padding: 24px; outline: none;
transition: border-color 0.2s; width: 100%;
}
.form-group input:focus, .form-group textarea:focus { border-color: var(--blue); }
.form-group input::placeholder, .form-group textarea::placeholder { color: var(--text-muted); }
.form-group textarea { min-height: 120px; resize: vertical; }
.form-note { font-size: 12px; color: var(--text-muted); margin-top: 12px; text-align: center; }
#form-message {
display: none; padding: 24px; border-radius: var(--radius-md);
font-size: 14px; font-weight: 600; text-align: center; margin-top: 16px;
}
#form-message.success { background: rgba(0,200,80,0.1); border: 1px solid rgba(0,200,80,0.25); color: #4ade80; }
#form-message.error { background: rgba(255,60,60,0.1); border: 1px solid rgba(255,60,60,0.25); color: #f87171; }
footer { border-top: 1px solid var(--border); padding: 40px; }
.footer-inner {
max-width: 1140px; margin: 0 auto;
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 16px;
}
.footer-logo { font-size: 17px; font-weight: 700; color: #1d1d1f; }
.footer-copy { font-size: 13px; color: var(--text-muted); }
.footer-tagline { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.footer-links { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.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); }
@media (max-width: 900px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
}
@media (max-width: 600px) {
section { padding: 48px 0 !important; }
.container { padding: 0 16px !important; box-sizing: border-box; }
.form-row { grid-template-columns: 1fr !important; }
.contact-form { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
[style*="grid-template-columns:1fr 1fr"] { grid-template-columns: 1fr !important; }
[style*="grid-template-columns:repeat(auto-fit,minmax(300px"] { grid-template-columns: 1fr !important; }
[style*="grid-template-columns:repeat(auto-fit,minmax(260px"] { grid-template-columns: 1fr !important; }
}
.lv-disclaimer{font-size:.75rem;color:rgba(0,0,0,.75);margin-top:24px;padding: 24px;background:rgba(0,0,0,.04);border-radius: var(--radius-md);line-height:1.6;max-width:800px}
.lv-disclaimer a{color:rgba(0,0,0,.65);text-decoration:underline}
.lv-disclaimer--light{color:#888;background:#f5f5f5}
.lv-disclaimer--light a{color:#555}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Landvex",
"item": "https://landvex.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Intelligence",
"item": "https://landvex.com/intelligence/"
},
{
"@type": "ListItem",
"position": 3,
"name": "City Health Index",
"item": "https://landvex.com/intelligence/city-health-index/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/"> <link rel="alternate" hreflang="it" href="https://landvex.it/">
</head>
<body>
<!-- NAV -->
<nav aria-label="Main navigation">
<a class="nav-logo" href="/">LandveX</a>
<ul class="nav-links">
<li><a href="/#how-it-works">How it works</a></li>
<li><a href="/#verticals">Verticals</a></li>
<li><a href="/methodology/">Methodology</a></li>
<li><a href="/security/">Security</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="#contact">Request a briefing →</a>
</nav>
<!-- HERO (dark) -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">Intelligence Index · Landvex</div>
<h1>How healthy is this city?</h1>
<p class="lv-hero-subtitle">A continuous composite score of urban condition, maintenance needs, and change velocity across a defined area. Continuously verified from field observations.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="#contact">Request a briefing →</a>
<a class="btn btn-outline btn-lg" href="#dimensions">See dimensions</a>
</div>
</section>
<!-- DIMENSIONS (white/light section) -->
<section id="dimensions">
<div class="lv-container">
<div>
<div class="section-label">What we measure</div>
<h2 class="section-title section-title-light">Five dimensions of intelligence.</h2>
<p class="section-sub">Each index is built from five independently observed and scored dimensions — combined into a single comparable score.</p>
</div>
<div>
<div onclick="location.href='#contact'" role="button" tabindex="0">
<div><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 14H14M4 14V8L8 4L12 8V14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 14V10H10V14" stroke="#666" stroke-width="1.5"/></svg></div>
<h3>Infrastructure condition</h3>
<p>Physical state of roads, utilities, public infrastructure and built environment across the area.</p>
</div>
<div onclick="location.href='#contact'" role="button" tabindex="0">
<div></div>
<h3>Commercial vitality</h3>
<p>Density and health of commercial activity — openings, closures, vacancy rates and foot traffic patterns.</p>
</div>
<div onclick="location.href='#contact'" role="button" tabindex="0">
<div></div>
<h3>Public space quality</h3>
<p>Condition of parks, squares, pedestrian zones and shared public environments.</p>
</div>
<div onclick="location.href='#contact'" role="button" tabindex="0">
<div></div>
<h3>Maintenance trajectory</h3>
<p>Rate of observable maintenance activity vs observed deterioration — leading indicator of future condition.</p>
</div>
<div onclick="location.href='#contact'" role="button" tabindex="0">
<div><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 12L6 8L9 11L14 5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 5H14V9" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<h3>Change velocity</h3>
<p>Speed and direction of visible change across the area — construction, renovation, closures, openings.</p>
</div>
</div>
</div>
</section>
<!-- USE CASES (light grey) -->
<section>
<div class="lv-container">
<div>
<div class="section-label">Use cases</div>
<h2 class="section-title section-title-light">Who uses this index.</h2>
<div>
<span>Municipal resource allocation</span>
<span>Urban planning</span>
<span>Investment screening</span>
</div>
</div>
</div>
</section>
<!-- SAMPLE OUTPUT (dark) -->
<section>
<div class="lv-container">
<div>
<div class="section-label">Sample output</div>
<h2 class="section-title">What you receive.</h2>
<p>Score 0100 + trend direction + key signals</p>
<div>
<div>
<span>Sample location · Placeholder score</span>
<span>↑ Improving</span>
</div>
<div>
<span>72</span>
<span>/100</span>
</div>
<div>
<div></div>
</div>
<div>
<span>Critical</span><span>Moderate</span><span>Strong</span>
</div>
<div>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> Placeholder values for illustration. Live intelligence from August 2026.
</div>
</div>
</div>
</div>
</section>
<!-- CONTRADICTION ENGINE (dark blue) -->
<section>
<div class="lv-container">
<div>
<div>
<div class="section-label">Advanced intelligence</div>
<h2 class="section-title">How this index detects narrative conflicts.</h2>
<p>The City Health Index compares official urban condition reports and maintenance schedules against observed field data. When official assessments rate an area as well-maintained but field observations show deferred maintenance, rising vacancies, or deteriorating public spaces — the engine flags a narrative conflict.</p>
</div>
<div>
<div>
<span></span>
<div>
<div>Contradiction Engine — How it works</div>
<div>Field observations are continuously cross-referenced against official records, registers, and published statistics. Divergence above threshold triggers a conflict flag.</div>
</div>
</div>
<div>
<div>
<div>Official record</div>
<ul>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Published condition ratings</li>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Official statistics</li>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Register data</li>
</ul>
</div>
<div>
<div>Observed reality</div>
<ul>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Field observations</li>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Real-time signals</li>
<li><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Contradiction flags</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- RELATED INDEXES (white) -->
<section>
<div class="lv-container">
<div>
<div class="section-label">Related intelligence</div>
<h2 class="section-title section-title-light">Explore related indexes.</h2>
</div>
<div>
<a href="/intelligence/neighbourhood-quality-index/" onmouseover="this.style.borderColor='#0066ff';this.style.transform='translateY(-2px)'" onmouseout="this.style.borderColor='#e5e7eb';this.style.transform='none'">
<div></div>
<div>Neighbourhood Quality Index</div>
<div>View index →</div>
</a>
<a href="/intelligence/infrastructure-risk-index/" onmouseover="this.style.borderColor='#0066ff';this.style.transform='translateY(-2px)'" onmouseout="this.style.borderColor='#e5e7eb';this.style.transform='none'">
<div><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
<div>Infrastructure Risk Index</div>
<div>View index →</div>
</a>
<a href="/intelligence/development-forecast/" onmouseover="this.style.borderColor='#0066ff';this.style.transform='translateY(-2px)'" onmouseout="this.style.borderColor='#e5e7eb';this.style.transform='none'">
<div></div>
<div>Development Forecast</div>
<div>View index →</div>
</a>
</div>
<div>
<a href="/" >← Back to Landvex</a>
</div>
</div>
</section>
<!-- CONTACT (dark) -->
<section id="contact">
<div class="lv-container">
<div>
<div class="section-label">Get in touch</div>
<h2 class="section-title">Request a briefing.</h2>
<p class="section-sub">Tell us the question you need answered. We'll show you how this index applies to your decision.</p>
<form class="contact-form" id="contact-form">
<div class="form-row">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" placeholder="Your name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@organisation.com" required>
</div>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" placeholder="Describe your question or decision — location, context, what you need to know..."></textarea>
</div>
<button type="submit" class="lv-btn lv-btn--lg">
Request briefing →
</button>
<p class="form-note">We don't spam. Your information stays private.</p>
<div id="form-message"></div>
</form>
</div>
</div>
<p class="lv-disclaimer">Intelligence outputs are indicative and advisory only. Based on field observations — not investment, financial or legal advice. Landvex AB accepts no liability for decisions made based on these outputs. <a href="/methodology/">Methodology →</a></p>
</section>
<!-- FOOTER -->
<footer class="lv-footer" role="contentinfo">
<div class="footer-inner">
<div>
<div class="footer-logo">LandveX</div>
<div class="footer-copy">© 2026 Landvex AB · Org.nr 559141-7042 · Tyresö, Sweden</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="/security/">Security</a>
<a href="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom →</a>
<a href="mailto:contact@landvex.com">contact@landvex.com</a>
<a href="mailto:security@landvex.com">security@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>
document.getElementById('contact-form').addEventListener('submit', async function(e) {
e.preventDefault();
const btn = this.querySelector('button[type="submit"]');
const msgEl = document.getElementById('form-message');
btn.disabled = true; btn.textContent = 'Sending...';
const data = {
source: 'landvex-intelligence',
index: 'city-health-index',
name: this.name.value,
email: this.email.value,
message: this.message.value
};
try {
const res = await fetch('https://api.quixzoom.com/api/qz/waitlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (res.ok || res.status === 201) {
msgEl.className = 'success';
msgEl.textContent = "<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Request received. We'll be in touch within one business day.";
msgEl.style.display = 'block';
this.reset();
} else { throw new Error('Server error ' + res.status); }
} catch(err) {
msgEl.className = 'error';
msgEl.textContent = 'Something went wrong. Please email us at contact@landvex.com.';
msgEl.style.display = 'block';
}
btn.disabled = false; btn.textContent = 'Request briefing →';
});
</script>
</body>
</html>