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
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/contact/">
<title>About Landvex — Redirecting</title>
<link rel="canonical" href="https://landvex.com/contact/">
</head>
<body>
<p>Redirecting to <a href="/contact/">Contact</a>...</p>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/insights/">
<title>Landvex Insights — Redirecting</title>
<link rel="canonical" href="https://landvex.com/insights/">
</head>
<body>
<p>Redirecting to <a href="/insights/">Insights</a>...</p>
</body>
</html>
+681
View File
@@ -0,0 +1,681 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Careers — Landvex</title>
<meta name="description" content="Careers at Landvex — join us in building decision intelligence for the physical world. Engineering, data science and enterprise sales roles.">
<link rel="canonical" href="https://landvex.com/careers/">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/careers/">
<meta property="og:title" content="Careers — Landvex">
<meta property="og:description" content="Careers at Landvex — join us in building decision intelligence for the physical world. We are hiring engineers, data scientists and enterprise sales in Sweden and remotely.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Careers — Landvex">
<meta name="twitter:description" content="Careers at Landvex — join us in building decision intelligence for the physical world.">
<meta name="twitter:image" content="https://landvex.com/og-image.jpg">
<!-- 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">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "JobPosting",
"hiringOrganization": {
"@type": "Organization",
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"url": "https://landvex.com"
},
"jobLocation": [
{"@type": "Place", "address": {"@type": "PostalAddress", "addressLocality": "Stockholm", "addressCountry": "SE"}},
{"@type": "Place", "address": {"@type": "PostalAddress", "addressLocality": "Remote"}}
],
"employmentType": "FULL_TIME",
"datePosted": "2026-06-01",
"description": "Landvex is hiring engineers, data scientists and enterprise sales to build decision intelligence for the physical world."
}
</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-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);
--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 */
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); }
/* HERO */
.page-hero {
padding: 24px 96px;
text-align: center;
position: relative;
overflow: hidden;
}
.page-hero::before {
content: '';
position: absolute;
top: -100px; 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: 16px; color: #0066ff; font-size: 12px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 8px 0; }
.page-hero h1 {
font-size: clamp(36px, 5.5vw, 68px);
font-weight: 800; letter-spacing: -2px; line-height: 1.05;
color: #1d1d1f; max-width: 820px; margin: 0 auto 24px;
}
.page-hero-sub {
font-size: clamp(16px, 2vw, 19px);
color: var(--text-dim); max-width: 580px;
margin: 0 auto 40px; line-height: 1.65;
}
/* SECTIONS */
section { padding: 24px; }
.container { max-width: 1100px; margin: 0 auto; }
.section-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--blue); margin-bottom: 12px;
}
.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-sub {
font-size: 17px; color: var(--text-dim);
max-width: 560px; line-height: 1.7;
}
/* WHY CARDS */
.surface-bg { background: var(--surface); }
.why-header { text-align: center; margin-bottom: 56px; }
.why-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.why-card {
display: block;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
transition: border-color 0.25s, transform 0.2s;
cursor: pointer;
}
.why-card:hover {
border-color: rgba(0,102,255,0.35);
transform: translateY(-3px);
}
.why-icon {
width: 44px; height: 44px;
background: var(--blue-glow);
border: 1px solid rgba(0,102,255,0.25);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
margin-bottom: 24px;
}
.why-card h3 {
font-size: 18px; font-weight: 700; color: #1d1d1f;
margin-bottom: 10px; letter-spacing: -0.3px;
}
.why-card p { font-size: 15px; color: var(--text-dim); line-height: 1.65; }
/* VALUES */
.values-header { margin-bottom: 56px; }
.values-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.value-card {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
}
.value-num {
font-size: 11px; font-weight: 700; letter-spacing: 0.12em;
text-transform: uppercase; color: rgba(0,102,255,0.7);
margin-bottom: 14px;
}
.value-card h3 {
font-size: 18px; font-weight: 700; color: #1d1d1f;
margin-bottom: 10px; letter-spacing: -0.3px;
}
.value-card p { font-size: 15px; color: var(--text-dim); line-height: 1.65; }
/* CULTURE */
.culture-inner {
max-width: 760px;
}
.culture-inner p {
font-size: 17px; color: var(--text-dim); line-height: 1.8;
margin-bottom: 20px;
}
.culture-inner p:last-child { margin-bottom: 0; }
/* OPEN ROLES */
.roles-header { margin-bottom: 56px; }
.roles-list {
display: flex; flex-direction: column; gap: 16px;
margin-bottom: 40px;
}
.role-card {
display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
transition: border-color 0.25s, transform 0.15s;
}
.role-card:hover {
border-color: rgba(0,102,255,0.35);
transform: translateY(-2px);
}
.role-body { flex: 1; }
.role-meta {
display: flex; align-items: center; gap: 16px; margin-bottom: 10px; flex-wrap: wrap;
}
.role-title {
font-size: 18px; font-weight: 700; color: #1d1d1f; letter-spacing: -0.3px;
}
.role-location {
font-size: 12px; font-weight: 600; letter-spacing: 0.06em;
text-transform: uppercase;
background: rgba(0,102,255,0.12);
border: 1px solid rgba(0,102,255,0.2);
color: #5599ff;
padding: 24px; border-radius: 100px;
}
.role-desc {
font-size: 15px; color: var(--text-dim); line-height: 1.65;
}
.role-cta {
flex-shrink: 0;
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);
transition: background 0.2s, transform 0.15s;
align-self: center;
}
.role-cta:hover { background: var(--blue-dark); transform: translateY(-1px); }
.role-cta svg { flex-shrink: 0; }
.roles-speculative {
font-size: 15px; color: var(--text-dim); line-height: 1.65;
}
.roles-speculative a {
color: #5599ff; text-decoration: underline; text-decoration-color: rgba(85,153,255,0.35);
}
.roles-speculative a:hover { text-decoration-color: #5599ff; }
/* FOOTER */
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: 8px;
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); }
/* RESPONSIVE */
@media (max-width: 900px) {
nav { padding: 0 16px; }
.nav-links { display: none; }
.why-grid { grid-template-columns: 1fr; }
.values-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
.page-hero { padding: 24px 72px; }
section { padding: 24px; }
.why-card, .value-card, .role-card { padding: 24px; }
.role-card { flex-direction: column; }
.role-cta { width: 100%; justify-content: center; }
footer { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
.footer-links { justify-content: center; gap: 16px 16px; }
}
</style>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<meta name="robots" content="index, follow">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": [
"Organization",
"Corporation"
],
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"alternateName": [
"LandveX",
"Landvex AB",
"LandveX AB"
],
"url": "https://landvex.com",
"logo": {
"@type": "ImageObject",
"url": "https://landvex.com/apple-touch-icon.png",
"width": 180,
"height": 180
},
"foundingDate": "2024",
"foundingLocation": {
"@type": "Place",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
},
"legalName": "Landvex Inc",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
},
"location": [
{
"@type": "Place",
"name": "Houston, Texas, USA (US HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
}
},
{
"@type": "Place",
"name": "Tyresö, Sweden (EU HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
}
}
],
"taxID": "pending-EIN",
"description": "Landvex is a decision intelligence company that identifies contradictions between official narratives and observed physical reality. Using the quiXzoom field observation network and the AMOS AI analysis engine, Landvex delivers infrastructure risk indexes, urban intelligence scores, and contradiction reports to infrastructure owners, municipalities, enterprises, and investors globally.",
"disambiguatingDescription": "Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European headquarters in Tyresö, Sweden (Landvex AB, org.nr 559141-7042). Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors. Landvex is not a UK meat wholesaler, food distributor, logistics company, package tracker, or land investment platform.",
"knowsAbout": [
"control intelligence",
"decision intelligence",
"infrastructure risk assessment",
"urban intelligence",
"field data collection",
"contradiction detection",
"physical world analytics",
"geospatial analytics"
],
"brand": {
"@type": "Brand",
"name": "Landvex",
"slogan": "Control intelligence for the physical world."
},
"sameAs": [
"https://landvex.com",
"https://www.linkedin.com/company/landvex",
"https://x.com/landvex",
"https://twitter.com/landvex",
"https://www.crunchbase.com/organization/landvex",
"https://github.com/landvex",
"https://www.instagram.com/landvex"
],
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@landvex.com",
"contactType": "sales"
},
"slogan": "Where reported reality conflicts with observed reality."
}
</script>
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>careers</span>
</nav>
<!-- NAV -->
<nav aria-label="Main navigation">
<a href="/" class="nav-logo">Landvex</a>
<ul class="nav-links">
<li><a href="/">Platform</a></li>
<li><a href="/methodology/">Methodology</a></li>
<li><a href="/for-organisations/">For organisations</a></li>
<li><a href="/careers/" >Careers</a></li>
</ul>
<a href="mailto:contact@landvex.com" class="btn">Contact us</a>
</nav>
<!-- HERO -->
<div class="page-hero">
<div class="lv-hero-eyebrow">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Careers
</div>
<h1>Build the world's most trusted decision intelligence platform.</h1>
<p class="page-hero-sub">We are a small team with serious ambition. The platform is already in 20+ countries. We are looking for people who find hard problems energising.</p>
<a href="#open-roles" class="btn">View open roles
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12l7 7 7-7"/></svg>
</a>
</div>
<!-- WHY LANDVEX -->
<section class="surface-bg">
<div class="lv-container">
<div class="why-header">
<div class="section-label">Why Landvex</div>
<div class="section-title">Three reasons this is a serious place to build.</div>
</div>
<div class="why-grid">
<a href="#open-roles" class="why-card">
<div class="why-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
</div>
<h3>Real-world impact</h3>
<p>What you build here gets used to make decisions worth hundreds of millions. Infrastructure investments, urban development, insurance risk — these are the decisions Landvex informs.</p>
</a>
<a href="#open-roles" class="why-card">
<div class="why-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<h3>Hard problems</h3>
<p>We are turning unstructured field observations into structured intelligence at scale. That requires serious engineering, serious data science and serious product thinking.</p>
</a>
<a href="#open-roles" class="why-card">
<div class="why-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
</div>
<h3>Early stage, serious ambition</h3>
<p>We are small. The platform is already in 20+ countries. The ambition is to become the Bloomberg of the physical world. What you do here matters.</p>
</a>
</div>
</div>
</section>
<!-- VALUES -->
<section>
<div class="lv-container">
<div class="values-header">
<div class="section-label">Our values</div>
<div class="section-title">Four principles, no buzzwords.</div>
<p class="section-sub">These are not aspirational posters. They are the things we hold each other to.</p>
</div>
<div class="values-grid">
<div class="value-card">
<div class="value-num">01</div>
<h3>Honest over comfortable</h3>
<p>We say what we believe. We challenge bad ideas. We are wrong sometimes and we acknowledge it.</p>
</div>
<div class="value-card">
<div class="value-num">02</div>
<h3>Evidence first</h3>
<p>Every conclusion must be challengeable. Every claim must survive scrutiny. We do not ship intelligence we cannot defend.</p>
</div>
<div class="value-card">
<div class="value-num">03</div>
<h3>Build for scale, not for show</h3>
<p>We build things that work at 1,000x. If something works now but breaks later, we rebuild it.</p>
</div>
<div class="value-card">
<div class="value-num">04</div>
<h3>The physical world is the product</h3>
<p>Our product is not software. Our product is a continuously updated understanding of how the world looks, changes and risks. We never forget that.</p>
</div>
</div>
</div>
</section>
<!-- CULTURE -->
<section class="surface-bg">
<div class="lv-container">
<div class="section-label">Culture</div>
<div class="section-title">How we work.</div>
<div class="culture-inner">
<p>Landvex is headquartered in Tyresö, Sweden, with a fully distributed team. We work asynchronously by default, meet when it matters, and write everything down.</p>
<p>We are building something that has not existed before. That means a lot of figuring things out, a lot of being wrong, and a lot of learning. We want people who find that energising.</p>
</div>
</div>
</section>
<!-- OPEN ROLES -->
<section id="open-roles">
<div class="lv-container">
<div class="roles-header">
<div class="section-label">Open roles</div>
<div class="section-title">Current openings.</div>
<p class="section-sub">We hire for long-term fit. Every role comes with meaningful equity and the expectation that you will help shape what Landvex becomes.</p>
</div>
<div class="roles-list">
<div class="role-card">
<div class="role-body">
<div class="role-meta">
<span class="role-title">Senior Backend Engineer</span>
<span class="role-location">Stockholm / Remote</span>
</div>
<p class="role-desc">Node.js, PostgreSQL, AWS. You will build the intelligence pipeline that turns field observations into decision support.</p>
</div>
<a href="mailto:jobs@landvex.com?subject=Application%3A%20Senior%20Backend%20Engineer" class="role-cta">
Apply
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</a>
</div>
<div class="role-card">
<div class="role-body">
<div class="role-meta">
<span class="role-title">Data Scientist / Intelligence Engineer</span>
<span class="role-location">Remote</span>
</div>
<p class="role-desc">Turn geographic observations into scores, indices and predictions. You will define how Landvex measures the physical world.</p>
</div>
<a href="mailto:jobs@landvex.com?subject=Application%3A%20Data%20Scientist%20%2F%20Intelligence%20Engineer" class="role-cta">
Apply
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</a>
</div>
<div class="role-card">
<div class="role-body">
<div class="role-meta">
<span class="role-title">Enterprise Sales</span>
<span class="role-location">Stockholm / London</span>
</div>
<p class="role-desc">Open new enterprise accounts. You will be the first dedicated sales hire. Competitive base + significant equity.</p>
</div>
<a href="mailto:jobs@landvex.com?subject=Application%3A%20Enterprise%20Sales" class="role-cta">
Apply
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</a>
</div>
</div>
<p class="roles-speculative">Don't see your role? Send a speculative application to <a href="mailto:jobs@landvex.com">jobs@landvex.com</a>.</p>
</div>
</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 Inc · Landvex AB (org.nr 559141-7042)</div>
<div class="footer-tagline">Decision intelligence for the physical world.</div>
<div>Landvex AB · Org.nr 559141-7042<br>Tyresö, Sweden · <a href="mailto:contact@landvex.com" >contact@landvex.com</a></div>
</div>
<div class="footer-links">
<a href="/privacy/">Privacy</a>
<a href="/terms/">Terms</a>
<a href="/methodology/">Methodology</a>
<a href="/data-quality/">Data Quality</a>
<a href="/security/">Security</a>
<a href="/comparison/">Compare</a>
<a href="/sla/">SLA &amp; Coverage</a>
<a href="/about/">About</a>
<a href="/careers/">Careers</a>
<a href="/accessibility/">Accessibility</a>
<a href="/responsible-disclosure/">Responsible disclosure</a>
<a href="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom &rarr;</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>
</body>
</html>
+612
View File
@@ -0,0 +1,612 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>London City Intelligence — Landvex</title>
<meta name="description" content="Continuous intelligence across London districts. Commercial vitality, infrastructure condition, growth velocity and investment confidence scores by area.">
<link rel="canonical" href="https://landvex.com/cities/london/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/cities/london/">
<meta property="og:title" content="London City Intelligence — Landvex">
<meta property="og:description" content="Continuous intelligence across London districts. Commercial vitality, infrastructure condition, growth velocity and investment confidence scores by area.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<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="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-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);
--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; }
.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; border-radius: var(--radius-md); }
.hero {
min-height: 90vh;
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: 680px; line-height: 1.65; margin-bottom: 40px;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
section { padding: 24px; }
.container { max-width: 1140px; margin: 0 auto; }
.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(28px, 4vw, 44px); font-weight: 800; letter-spacing: -1.2px; line-height: 1.1; color: #1d1d1f; margin-bottom: 24px; }
.section-sub { font-size: 17px; color: var(--text-dim); max-width: 600px; line-height: 1.7; }
.stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 40px; }
.stat-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 24px; transition: border-color 0.25s; cursor: pointer; }
.stat-card:hover { border-color: rgba(0,102,255,0.3); }
.stat-icon { width: 36px; height: 36px; margin-bottom: 14px; color: var(--blue); }
.stat-value { font-size: 32px; font-weight: 800; color: #1d1d1f; letter-spacing: -1px; margin-bottom: 4px; }
.stat-label { font-size: 14px; color: var(--text-dim); line-height: 1.5; }
.districts-bg { background: var(--bg-dark); }
.districts-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 40px; }
.district-chip { background: var(--bg-dark); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 24px; display: flex; align-items: center; gap: 16px; }
.district-chip .chip-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--blue); flex-shrink: 0; }
.district-chip span { font-size: 14px; font-weight: 600; color: var(--text-light); }
.intel-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-top: 40px; }
.intel-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 24px; transition: border-color 0.25s, transform 0.2s; cursor: pointer; }
.intel-card:hover { border-color: rgba(0,102,255,0.35); transform: translateY(-3px); }
.intel-icon { width: 32px; height: 32px; margin-bottom: 24px; color: var(--blue); }
.intel-card h3 { font-size: 17px; font-weight: 700; color: #1d1d1f; margin-bottom: 8px; }
.intel-card p { font-size: 14px; color: var(--text-dim); line-height: 1.6; }
.scores-table-wrap { margin-top: 40px; overflow-x: auto; }
.scores-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.scores-table th { text-align: left; padding: 24px; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); border-bottom: 1px solid var(--border); }
.scores-table th:not(:first-child) { text-align: center; }
.scores-table td { padding: 24px; border-bottom: 1px solid rgba(0,0,0,0.04); color: var(--text-light); }
.scores-table td:not(:first-child) { text-align: center; }
.scores-table tr:hover td { background: rgba(0,0,0,0.02); }
.score-pill { display: inline-block; font-size: 14px; font-weight: 700; padding: 24px; border-radius: 100px; }
.score-pill.high { background: rgba(0,200,80,0.1); color: #4ade80; }
.score-pill.mid { background: rgba(0,102,255,0.12); color: #60a5fa; }
.score-pill.low { background: rgba(255,180,0,0.1); color: #fbbf24; }
.district-name { font-weight: 600; color: #1d1d1f; }
.table-note { margin-top: 12px; font-size: 12px; color: var(--text-muted); }
.contradiction-bg { background: #e8f0fe; }
.contradiction-box { background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.1); border-radius: var(--radius-lg); padding: 24px; margin-bottom: 32px; }
.conflict-header { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 24px; }
.conflict-flag-svg { flex-shrink: 0; margin-top: 2px; }
.conflict-title { color: #f87171; font-weight: 800; font-size: .9375rem; margin-bottom: 4px; }
.conflict-desc { color: rgba(0,0,0,.6); font-size: .875rem; line-height: 1.6; }
.conflict-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.conflict-side { border-radius: 10px; padding: 16px; }
.conflict-official { background: rgba(34,197,94,.1); border: 1px solid rgba(34,197,94,.2); }
.conflict-observed { background: rgba(239,68,68,.1); border: 1px solid rgba(239,68,68,.2); }
.conflict-side-label { font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; margin-bottom: 10px; }
.conflict-official .conflict-side-label { color: #86efac; }
.conflict-observed .conflict-side-label { color: #fca5a5; }
.conflict-side ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; }
.conflict-side li { color: rgba(0,0,0,.7); font-size: .875rem; }
.conflict-footer { margin-top: 20px; padding-top: 20px; border-top: 1px solid rgba(0,0,0,.1); display: flex; justify-content: space-between; align-items: center; }
.conflict-footer-label { color: rgba(0,0,0,.75); font-size: .8125rem; }
.conflict-confidence { color: #f87171; font-weight: 800; font-size: 1.125rem; }
.ce-features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.ce-feature { text-align: center; padding: 20px; }
.ce-feature-icon { width: 28px; height: 28px; margin: 0 auto 10px; color: rgba(0,0,0,0.75); }
.ce-feature h4 { color: #1d1d1f; font-weight: 700; margin-bottom: 6px; }
.ce-feature p { color: rgba(0,0,0,.75); font-size: .8125rem; }
.cta-banner { background: #e8f0fe; border-radius: var(--radius-lg); padding: 24px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 48px; }
.cta-banner h3 { color: #1d1d1f; font-size: 1.25rem; font-weight: 800; margin-bottom: 8px; }
.cta-banner p { color: rgba(0,0,0,.7); line-height: 1.65; font-size: .9375rem; }
.cta-banner-text { flex: 1; min-width: 260px; }
.contact-wrapper { max-width: 680px; margin: 0 auto; text-align: center; }
.contact-form { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 40px; text-align: left; }
.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: 8px; 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); }
.lv-disclaimer { font-size:.75rem; color:rgba(0,0,0,.75); margin-top:24px; padding: 24px; background:rgba(0,0,0,.04); border-radius:8px; line-height:1.6; max-width:800px; }
.lv-disclaimer a { color:rgba(0,0,0,.65); text-decoration:underline; }
@media (max-width: 900px) {
nav { padding: 0 20px; }
.stats-row { grid-template-columns: 1fr 1fr; }
.districts-grid { grid-template-columns: repeat(2, 1fr); }
.intel-grid { grid-template-columns: 1fr; }
.conflict-grid { grid-template-columns: 1fr; }
.ce-features { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
section { padding: 48px 0 !important; }
.stats-row { grid-template-columns: 1fr 1fr !important; }
.districts-grid { grid-template-columns: 1fr 1fr !important; }
.intel-grid { grid-template-columns: 1fr !important; }
.conflict-grid { grid-template-columns: 1fr !important; }
.ce-features { grid-template-columns: 1fr !important; }
.scores-grid { grid-template-columns: 1fr 1fr !important; }
.cta-banner { flex-direction: column !important; gap: 16px; padding: 24px; }
.cta-banner-text { min-width: 0 !important; }
.container { padding: 0 16px !important; box-sizing: border-box; }
.contact-form { padding: 24px; }
nav { padding: 0 16px; }
.hero h1 { letter-spacing: -1px; }
}
@media (max-width: 400px) {
.stats-row { grid-template-columns: 1fr !important; }
.districts-grid { grid-template-columns: 1fr !important; }
.scores-grid { grid-template-columns: 1fr !important; }
}
</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": "Cities",
"item": "https://landvex.com/cities/"
},
{
"@type": "ListItem",
"position": 3,
"name": "London",
"item": "https://landvex.com/cities/london/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
<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="Main navigation">
<a class="nav-logo" href="https://landvex.com/">&larr; Back to Landvex</a>
<a class="lv-btn lv-btn--outline" href="#contact">Get in touch &rarr;</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">City Intelligence &mdash; London</div>
<h1>London &mdash; City Intelligence Report</h1>
<p class="lv-hero-subtitle">Continuous monitoring of commercial activity, infrastructure conditions and urban development across London&rsquo;s boroughs and business districts. Updated from field observations.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="#contact">Request London briefing &rarr;</a>
<a class="btn btn-outline btn-lg" href="#overview">City overview</a>
</div>
</section>
<!-- OVERVIEW -->
<section id="overview">
<div class="lv-container">
<div class="section-label">City overview</div>
<h2 class="section-title">London at a glance</h2>
<p class="section-sub">Key statistics informing Landvex intelligence collection and scoring across the Greater London area.</p>
<div class="stats-row">
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<div class="stat-value">9,700,000</div>
<div class="stat-label">Greater London population &mdash; largest city in the UK</div>
</div>
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="1" x2="12" y2="23"/>
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
</svg>
<div class="stat-value">Top 3 Global</div>
<div class="stat-label">Financial centre rank &mdash; alongside New York and Singapore</div>
</div>
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
<div class="stat-value">Finance &middot; Tech &middot; Property</div>
<div class="stat-label">Key sectors: financial services, technology, commercial property</div>
</div>
</div>
</div>
</section>
<!-- DISTRICTS -->
<section id="districts" class="districts-bg">
<div class="lv-container">
<div class="section-label">Coverage</div>
<h2 class="section-title">Districts covered</h2>
<p class="section-sub">Landvex field intelligence spans all major commercial, mixed-use, and growth districts across Greater London.</p>
<div class="districts-grid">
<div class="district-chip"><span class="chip-dot"></span><span>City of London</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Canary Wharf</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Shoreditch/Hackney</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Southwark</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Westminster</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Camden</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Stratford/Newham</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Croydon</span></div>
</div>
</div>
</section>
<!-- ACTIVE INTELLIGENCE -->
<section id="intelligence">
<div class="lv-container">
<div class="section-label">Active intelligence</div>
<h2 class="section-title">What Landvex monitors in London</h2>
<p class="section-sub">Four continuous intelligence streams, updated from field observations and cross-referenced against official sources.</p>
<div class="intel-grid">
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<h3>Commercial Vitality Score</h3>
<p>Measures vacancy rates, business openings and closures, foot traffic signals, and commercial activity across each London district. Launching August 2026.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<h3>Infrastructure Risk Index</h3>
<p>Identifies infrastructure degradation, transport disruptions, and maintenance backlogs that affect business continuity and investment risk across London&rsquo;s districts and the TfL network.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
</svg>
<h3>Development Forecast</h3>
<p>Tracks planning applications, construction activity, and development signals. Identifies emerging opportunities and area trajectories before they appear in official statistics or market reports.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"/>
<line x1="12" y1="20" x2="12" y2="4"/>
<line x1="6" y1="20" x2="6" y2="14"/>
</svg>
<h3>Growth Velocity</h3>
<p>How fast is each district changing? Landvex Growth Velocity captures the rate of transformation &mdash; identifying which London areas are accelerating, plateauing, or in structural decline.</p>
</div>
</div>
</div>
</section>
<!-- SCORES TABLE -->
<section id="scores">
<div class="lv-container">
<div class="section-label">District scores</div>
<h2 class="section-title">Sample intelligence scores</h2>
<p class="section-sub">Placeholder scores shown for illustration. Live district intelligence available on request.</p>
<div class="scores-table-wrap">
<table class="scores-table">
<thead>
<tr>
<th>District</th>
<th>Opportunity</th>
<th>Growth</th>
<th>Infra Stability</th>
<th>Vitality</th>
</tr>
</thead>
<tbody>
<tr>
<td class="district-name">City / Canary Wharf</td>
<td><span class="score-pill high">83</span></td>
<td><span class="score-pill low">64</span></td>
<td><span class="score-pill high">88</span></td>
<td><span class="score-pill high">91</span></td>
</tr>
<tr>
<td class="district-name">Shoreditch / Hackney</td>
<td><span class="score-pill mid">79</span></td>
<td><span class="score-pill mid">78</span></td>
<td><span class="score-pill high">82</span></td>
<td><span class="score-pill high">80</span></td>
</tr>
<tr>
<td class="district-name">Stratford / Newham</td>
<td><span class="score-pill mid">71</span></td>
<td><span class="score-pill high">82</span></td>
<td><span class="score-pill mid">74</span></td>
<td><span class="score-pill mid">73</span></td>
</tr>
<tr>
<td class="district-name">Croydon</td>
<td><span class="score-pill low">62</span></td>
<td><span class="score-pill mid">74</span></td>
<td><span class="score-pill mid">71</span></td>
<td><span class="score-pill low">65</span></td>
</tr>
</tbody>
</table>
<p class="table-note">Scores are illustrative placeholders. Live data from field observations available Aug 2026.</p>
</div>
</div>
</section>
<!-- CONTRADICTION ENGINE -->
<section class="contradiction-bg" id="contradiction">
<div class="lv-container">
<div>
<div class="section-label">Contradiction Engine</div>
<h2 class="section-title">Most systems tell you what the data says.<br>Landvex tells you what doesn&rsquo;t add up.</h2>
<p class="section-sub">When official market statistics diverge from observed commercial activity, Landvex surfaces the conflict &mdash; not just the consensus.</p>
</div>
<div class="contradiction-box">
<div class="conflict-header">
<svg class="conflict-flag-svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/>
<line x1="4" y1="22" x2="4" y2="15"/>
</svg>
<div>
<div class="conflict-title">Narrative Conflict Detected &mdash; London &mdash; Office Market Vacancy vs Observed Activity</div>
<div class="conflict-desc">London office market official vacancy statistics vs observed commercial activity levels. Field data reveals divergence between reported office vacancy figures and measured ground-floor commercial vitality in key districts.</div>
</div>
</div>
<div class="conflict-grid">
<div class="conflict-side conflict-official">
<div class="conflict-side-label">Official narrative</div>
<ul>
<li>&#10003; City of London vacancy rate: within 10-year norm</li>
<li>&#10003; Canary Wharf: anchor tenant commitments renewed</li>
<li>&#10003; Office-to-residential conversions: reducing surplus</li>
</ul>
</div>
<div class="conflict-side conflict-observed">
<div class="conflict-side-label">Observed reality</div>
<ul>
<li>&#10007; Sub-let market expanding in City: direct vacancy understated</li>
<li>&#10007; Canary Wharf ground floor retail vacancy materially elevated</li>
<li>&#10007; Conversion pipeline slower than reported in planning data</li>
<li>&#10007; Shoreditch commercial rents compressing despite headline growth</li>
</ul>
</div>
</div>
<div class="conflict-footer">
<span class="conflict-footer-label">Confidence in official narrative</span>
<span class="conflict-confidence">44%</span>
</div>
</div>
<div class="ce-features">
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<h4>Show me what I&rsquo;m missing</h4>
<p>Blind spots not visible in official data or internal reports</p>
</div>
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
<h4>AI Red Team</h4>
<p>Every conclusion is actively challenged by a second model before delivery</p>
</div>
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<h4>Which assumptions are wrong?</h4>
<p>Identify where your thesis conflicts with observed reality</p>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section id="briefing">
<div class="lv-container">
<div class="cta-banner">
<div class="cta-banner-text">
<h3>Request London intelligence briefing</h3>
<p>Get field-verified district scores, contradiction analysis, and custom intelligence for your London decision. Delivered in 24&ndash;72 hours.</p>
</div>
<a class="lv-btn lv-btn--lg" href="#contact">Request briefing &rarr;</a>
</div>
</div>
</section>
<!-- CONTACT -->
<section id="contact">
<div class="lv-container">
<div class="contact-wrapper">
<div class="section-label">Request a briefing</div>
<h2 class="section-title">What decision are you trying to make?</h2>
<p class="section-sub">Tell us the question you need answered about London. We&rsquo;ll show you how Landvex can support it.</p>
<form class="contact-form" id="contact-form">
<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 class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" placeholder="Describe the decision you need to make about London &mdash; what you need to know, which districts, and why it matters..."></textarea>
</div>
<button type="submit" class="lv-btn lv-btn--lg">
Request London briefing &rarr;
</button>
<p class="form-note">We don&rsquo;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 &mdash; not investment, financial or legal advice. Landvex AB accepts no liability for decisions made based on these outputs. <a href="/methodology/">Methodology &rarr;</a></p>
</section>
<footer class="lv-footer" role="contentinfo">
<div class="footer-inner">
<div>
<div class="footer-logo">LandveX</div>
<div class="footer-copy">&copy; 2026 Landvex AB &middot; Org.nr 559141-7042</div>
<div class="footer-tagline">Decision intelligence for the physical world.</div>
</div>
<div class="footer-links">
<a href="https://landvex.com/">Home</a>
<a href="/verticals/">Verticals</a>
<a href="/methodology/">Methodology</a>
<a href="/security/">Security</a>
<a href="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom &rarr;</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>
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-city-london', 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 = "\u2713 Request received. We\u2019ll 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 directly at contact@landvex.com.'; msgEl.style.display = 'block';
}
btn.disabled = false; btn.textContent = 'Request London briefing \u2192';
});
document.querySelectorAll('a[href^="#"]').forEach(a => {
a.addEventListener('click', e => {
const target = document.querySelector(a.getAttribute('href'));
if (target) { e.preventDefault(); target.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
});
});
</script>
</body>
</html>
+798
View File
@@ -0,0 +1,798 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stockholm City Intelligence — Landvex</title>
<meta name="description" content="Continuous intelligence across Stockholm districts. Commercial vitality, infrastructure condition, growth velocity and investment confidence scores by district.">
<link rel="canonical" href="https://landvex.com/cities/stockholm/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/cities/stockholm/">
<meta property="og:title" content="Stockholm City Intelligence — Landvex">
<meta property="og:description" content="Continuous intelligence across Stockholm districts. Commercial vitality, infrastructure condition, growth velocity and investment confidence scores by district.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<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="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-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);
--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; }
.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; border-radius: var(--radius-md); }
.hero {
min-height: 90vh;
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: 680px; line-height: 1.65;
margin-bottom: 40px;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
section { padding: 24px; }
.container { max-width: 1140px; margin: 0 auto; }
.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(28px, 4vw, 44px);
font-weight: 800; letter-spacing: -1.2px; line-height: 1.1;
color: #1d1d1f; margin-bottom: 24px;
}
.section-sub {
font-size: 17px; color: var(--text-dim);
max-width: 600px; line-height: 1.7;
}
/* OVERVIEW STATS */
.stats-row {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
margin-top: 40px;
}
.stat-card {
background: var(--surface-2); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 24px;
transition: border-color 0.25s;
}
.stat-card:hover { border-color: rgba(0,102,255,0.3); }
.stat-icon {
width: 36px; height: 36px; margin-bottom: 14px;
color: var(--blue);
}
.stat-value {
font-size: 32px; font-weight: 800; color: #1d1d1f; letter-spacing: -1px;
margin-bottom: 4px;
}
.stat-label { font-size: 14px; color: var(--text-dim); line-height: 1.5; }
/* DISTRICTS */
.districts-bg { background: var(--surface); }
.districts-grid {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px;
margin-top: 40px;
}
.district-chip {
background: var(--bg-dark); border: 1px solid var(--border);
border-radius: var(--radius-md); padding: 24px;
display: flex; align-items: center; gap: 16px;
}
.district-chip .chip-dot {
width: 8px; height: 8px; border-radius: 50%;
background: var(--blue); flex-shrink: 0;
}
.district-chip span { font-size: 14px; font-weight: 600; color: var(--text-light); }
/* INTELLIGENCE PRODUCTS */
.intel-grid {
display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
margin-top: 40px;
}
.intel-card {
background: var(--surface-2); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 24px;
transition: border-color 0.25s, transform 0.2s;
}
.intel-card:hover { border-color: rgba(0,102,255,0.35); transform: translateY(-3px); }
.intel-icon {
width: 32px; height: 32px; margin-bottom: 24px;
color: var(--blue);
}
.intel-card h3 { font-size: 17px; font-weight: 700; color: #1d1d1f; margin-bottom: 8px; }
.intel-card p { font-size: 14px; color: var(--text-dim); line-height: 1.6; }
/* SCORES TABLE */
.scores-table-wrap { margin-top: 40px; overflow-x: auto; }
.scores-table {
width: 100%; border-collapse: collapse;
font-size: 14px;
}
.scores-table th {
text-align: left; padding: 24px;
font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
text-transform: uppercase; color: var(--text-muted);
border-bottom: 1px solid var(--border);
}
.scores-table th:not(:first-child) { text-align: center; }
.scores-table td {
padding: 24px;
border-bottom: 1px solid rgba(0,0,0,0.04);
color: var(--text-light);
}
.scores-table td:not(:first-child) { text-align: center; }
.scores-table tr:hover td { background: rgba(0,0,0,0.02); }
.score-pill {
display: inline-block;
font-size: 14px; font-weight: 700;
padding: 24px; border-radius: 100px;
background: rgba(0,102,255,0.12);
color: #5599ff;
}
.score-pill.high { background: rgba(0,200,80,0.1); color: #4ade80; }
.score-pill.mid { background: rgba(0,102,255,0.12); color: #60a5fa; }
.score-pill.low { background: rgba(255,180,0,0.1); color: #fbbf24; }
.district-name { font-weight: 600; color: #1d1d1f; }
.table-note {
margin-top: 12px; font-size: 12px; color: var(--text-muted);
}
/* CONTRADICTION ENGINE */
.contradiction-bg { background: #e8f0fe; }
.contradiction-box {
background: rgba(0,0,0,.05);
border: 1px solid rgba(0,0,0,.1);
border-radius: var(--radius-lg); padding: 24px; margin-bottom: 32px;
}
.conflict-header {
display: flex; align-items: flex-start; gap: 16px; margin-bottom: 24px;
}
.conflict-flag-svg { flex-shrink: 0; margin-top: 2px; }
.conflict-title { color: #f87171; font-weight: 800; font-size: .9375rem; margin-bottom: 4px; }
.conflict-desc { color: rgba(0,0,0,.6); font-size: .875rem; line-height: 1.6; }
.conflict-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.conflict-side { border-radius: 10px; padding: 16px; }
.conflict-official { background: rgba(34,197,94,.1); border: 1px solid rgba(34,197,94,.2); }
.conflict-observed { background: rgba(239,68,68,.1); border: 1px solid rgba(239,68,68,.2); }
.conflict-side-label {
font-size: .75rem; font-weight: 700; text-transform: uppercase;
letter-spacing: .08em; margin-bottom: 10px;
}
.conflict-official .conflict-side-label { color: #86efac; }
.conflict-observed .conflict-side-label { color: #fca5a5; }
.conflict-side ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; }
.conflict-side li { color: rgba(0,0,0,.7); font-size: .875rem; }
.conflict-footer {
margin-top: 20px; padding-top: 20px;
border-top: 1px solid rgba(0,0,0,.1);
display: flex; justify-content: space-between; align-items: center;
}
.conflict-footer-label { color: rgba(0,0,0,.75); font-size: .8125rem; }
.conflict-confidence { color: #f87171; font-weight: 800; font-size: 1.125rem; }
.ce-features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.ce-feature { text-align: center; padding: 20px; }
.ce-feature-icon {
width: 28px; height: 28px; margin: 0 auto 10px;
color: rgba(0,0,0,0.75);
}
.ce-feature h4 { color: #1d1d1f; font-weight: 700; margin-bottom: 6px; }
.ce-feature p { color: rgba(0,0,0,.75); font-size: .8125rem; }
/* CTA BANNER */
.cta-banner {
background: #e8f0fe; border-radius: var(--radius-lg); padding: 24px;
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
margin-top: 48px;
}
.cta-banner h3 { color: #1d1d1f; font-size: 1.25rem; font-weight: 800; margin-bottom: 8px; }
.cta-banner p { color: rgba(0,0,0,.7); line-height: 1.65; font-size: .9375rem; }
.cta-banner-text { flex: 1; min-width: 260px; }
/* CONTACT */
.contact-wrapper { max-width: 680px; margin: 0 auto; text-align: center; }
.contact-wrapper .section-title { margin-bottom: 10px; }
.contact-wrapper .section-sub { margin: 0 auto 48px; }
.contact-form {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 40px; text-align: left;
}
.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 */
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: 8px;
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; }
.stats-row { grid-template-columns: 1fr 1fr; }
.districts-grid { grid-template-columns: repeat(2, 1fr); }
.intel-grid { grid-template-columns: 1fr; }
.conflict-grid { grid-template-columns: 1fr; }
.ce-features { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
section { padding: 48px 0 !important; }
.stats-row { grid-template-columns: 1fr 1fr !important; }
.districts-grid { grid-template-columns: 1fr 1fr !important; }
.intel-grid { grid-template-columns: 1fr !important; }
.conflict-grid { grid-template-columns: 1fr !important; }
.ce-features { grid-template-columns: 1fr !important; }
.scores-grid { grid-template-columns: 1fr 1fr !important; }
.cta-banner { flex-direction: column !important; gap: 16px; padding: 24px; }
.cta-banner-text { min-width: 0 !important; }
.container { padding: 0 16px !important; box-sizing: border-box; }
.contact-form { padding: 24px; }
nav { padding: 0 16px; }
.hero h1 { letter-spacing: -1px; }
}
@media (max-width: 400px) {
.stats-row { grid-template-columns: 1fr !important; }
.districts-grid { grid-template-columns: 1fr !important; }
.scores-grid { 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:8px;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": "Cities",
"item": "https://landvex.com/cities/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Stockholm",
"item": "https://landvex.com/cities/stockholm/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
<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="Main navigation">
<a class="nav-logo" href="https://landvex.com/">&larr; Back to Landvex</a>
<a class="lv-btn lv-btn--outline" href="#contact">Get in touch &rarr;</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">City Intelligence &mdash; Stockholm</div>
<h1>Stockholm &mdash; City Intelligence Report</h1>
<p class="lv-hero-subtitle">Continuous monitoring of commercial activity, infrastructure conditions and urban development across Stockholm&rsquo;s districts. Updated from field observations.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="#contact">Request Stockholm briefing &rarr;</a>
<a class="btn btn-outline btn-lg" href="#overview">City overview</a>
</div>
</section>
<!-- OVERVIEW -->
<section id="overview">
<div class="lv-container">
<div class="section-label">City overview</div>
<h2 class="section-title">Stockholm at a glance</h2>
<p class="section-sub">Key statistics informing Landvex intelligence collection and scoring across Stockholm&rsquo;s urban area.</p>
<div class="stats-row">
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<div class="stat-value">975,000</div>
<div class="stat-label">City population &mdash; Sweden&rsquo;s largest urban centre</div>
</div>
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="1" x2="12" y2="23"/>
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
</svg>
<div class="stat-value">Top 5 Nordic</div>
<div class="stat-label">GDP rank among Nordic cities</div>
</div>
<div class="stat-card" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="stat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
<div class="stat-value">Tech &middot; Finance</div>
<div class="stat-label">Key sectors: technology, finance, public sector</div>
</div>
</div>
</div>
</section>
<!-- DISTRICTS -->
<section id="districts" class="districts-bg">
<div class="lv-container">
<div class="section-label">Coverage</div>
<h2 class="section-title">Districts covered</h2>
<p class="section-sub">Landvex field intelligence spans all major commercial and residential districts across Stockholm.</p>
<div class="districts-grid">
<div class="district-chip"><span class="chip-dot"></span><span>Norrmalm (CBD)</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>S&ouml;dermalm</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>&Ouml;stermalm</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Kungsholmen</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Vasastan</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Järva</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Farsta</span></div>
<div class="district-chip"><span class="chip-dot"></span><span>Nacka</span></div>
</div>
</div>
</section>
<!-- ACTIVE INTELLIGENCE -->
<section id="intelligence">
<div class="lv-container">
<div class="section-label">Active intelligence</div>
<h2 class="section-title">What Landvex monitors in Stockholm</h2>
<p class="section-sub">Four continuous intelligence streams, updated from field observations and cross-referenced against official sources.</p>
<div class="intel-grid">
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<h3>Commercial Vitality Score</h3>
<p>Measures vacancy rates, business openings and closures, foot traffic signals, and commercial activity across each district. Launching August 2026.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<h3>Infrastructure Risk Index</h3>
<p>Identifies infrastructure degradation, transport disruptions, and maintenance backlogs that affect business continuity and investment risk across Stockholm&rsquo;s districts.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
</svg>
<h3>Development Forecast</h3>
<p>Tracks planning applications, construction activity, and development signals. Identifies emerging opportunities and area trajectories before they appear in official statistics.</p>
</div>
<div class="lv-card lv-card--intel" onclick="location.href='#contact'" role="button" tabindex="0">
<svg class="intel-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"/>
<line x1="12" y1="20" x2="12" y2="4"/>
<line x1="6" y1="20" x2="6" y2="14"/>
</svg>
<h3>Growth Velocity</h3>
<p>How fast is each district changing? Landvex Growth Velocity captures the rate of transformation &mdash; identifying which areas are accelerating, plateauing, or in decline.</p>
</div>
</div>
</div>
</section>
<!-- SCORES TABLE -->
<section id="scores">
<div class="lv-container">
<div class="section-label">District scores</div>
<h2 class="section-title">Sample intelligence scores</h2>
<p class="section-sub">⚠️ ILLUSTRATIVE SAMPLE DATA — These scores are synthetic examples for demonstration purposes only. They do not represent actual measured values.</p>
<div class="scores-table-wrap">
<table class="scores-table">
<thead>
<tr>
<th>District</th>
<th>Opportunity</th>
<th>Growth</th>
<th>Infra Stability</th>
<th>Vitality</th>
</tr>
</thead>
<tbody>
<tr>
<td class="district-name">Norrmalm</td>
<td><span class="score-pill mid">74</span></td>
<td><span class="score-pill low">58</span></td>
<td><span class="score-pill high">88</span></td>
<td><span class="score-pill high">82</span></td>
</tr>
<tr>
<td class="district-name">S&ouml;dermalm</td>
<td><span class="score-pill mid">71</span></td>
<td><span class="score-pill mid">67</span></td>
<td><span class="score-pill mid">79</span></td>
<td><span class="score-pill high">86</span></td>
</tr>
<tr>
<td class="district-name">Järva</td>
<td><span class="score-pill mid">63</span></td>
<td><span class="score-pill mid">74</span></td>
<td><span class="score-pill mid">71</span></td>
<td><span class="score-pill mid">61</span></td>
</tr>
<tr>
<td class="district-name">Nacka</td>
<td><span class="score-pill mid">78</span></td>
<td><span class="score-pill high">81</span></td>
<td><span class="score-pill high">84</span></td>
<td><span class="score-pill mid">73</span></td>
</tr>
</tbody>
</table>
<p class="table-note">Scores are illustrative placeholders. Live data from field observations available Aug 2026.</p>
</div>
</div>
</section>
<!-- CONTRADICTION ENGINE -->
<section class="contradiction-bg" id="contradiction">
<div class="lv-container">
<div>
<div class="section-label">Contradiction Engine</div>
<h2 class="section-title">Most systems tell you what the data says.<br>Landvex tells you what doesn&rsquo;t add up.</h2>
<p class="section-sub">When official municipal development plans diverge from observed commercial activity, Landvex surfaces the conflict &mdash; not just the consensus.</p>
</div>
<div>
⚠ ILLUSTRATIVE SAMPLE — not real intelligence
</div>
<div class="contradiction-box">
<div class="conflict-header">
<svg class="conflict-flag-svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/>
<line x1="4" y1="22" x2="4" y2="15"/>
</svg>
<div>
<div class="conflict-title">Narrative Conflict Detected &mdash; Stockholm &mdash; Järva / Norrmalm</div>
<div class="conflict-desc">Official municipal development plans vs observed commercial activity. Field data reveals divergence between planned urban investment zones and measured commercial vitality on the ground.</div>
</div>
</div>
<div class="conflict-grid">
<div class="conflict-side conflict-official">
<div class="conflict-side-label">Official narrative</div>
<ul>
<li>&#10003; Municipal investment zone: Järva priority growth</li>
<li>&#10003; Norrmalm: stable CBD with anchor tenants</li>
<li>&#10003; Development permits: 14 approved 2024&ndash;2025</li>
</ul>
</div>
<div class="conflict-side conflict-observed">
<div class="conflict-side-label">Observed reality</div>
<ul>
<li>&#10007; Järva commercial vacancy above city average</li>
<li>&#10007; Norrmalm: 3 anchor retailers downsizing footprint</li>
<li>&#10007; Development activity below permit volume</li>
<li>&#10007; Nacka outperforming planned growth projections</li>
</ul>
</div>
</div>
<div class="conflict-footer">
<span class="conflict-footer-label">Confidence in official narrative</span>
<span class="conflict-confidence">51%</span>
</div>
</div>
<div class="ce-features">
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<h4>Show me what I&rsquo;m missing</h4>
<p>Blind spots not visible in official data or internal reports</p>
</div>
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
<h4>AI Red Team</h4>
<p>Every conclusion is actively challenged by a second model before delivery</p>
</div>
<div class="ce-feature">
<svg class="ce-feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<h4>Which assumptions are wrong?</h4>
<p>Identify where your thesis conflicts with observed reality</p>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section id="briefing">
<div class="lv-container">
<div class="cta-banner">
<div class="cta-banner-text">
<h3>Request Stockholm intelligence briefing</h3>
<p>Get field-verified district scores, contradiction analysis, and custom intelligence for your Stockholm decision. Delivered in 24&ndash;72 hours.</p>
</div>
<a class="lv-btn lv-btn--lg" href="#contact">Request briefing &rarr;</a>
</div>
</div>
</section>
<!-- CONTACT -->
<section id="contact">
<div class="lv-container">
<div class="contact-wrapper">
<div class="section-label">Request a briefing</div>
<h2 class="section-title">What decision are you trying to make?</h2>
<p class="section-sub">Tell us the question you need answered about Stockholm. We&rsquo;ll show you how Landvex can support it.</p>
<form class="contact-form" id="contact-form">
<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 class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" placeholder="Describe the decision you need to make about Stockholm &mdash; what you need to know, which districts, and why it matters..."></textarea>
</div>
<button type="submit" class="lv-btn lv-btn--lg">
Request Stockholm briefing &rarr;
</button>
<p class="form-note">We don&rsquo;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 class="lv-footer" role="contentinfo">
<div class="footer-inner">
<div>
<div class="footer-logo">LandveX</div>
<div class="footer-copy">&copy; 2026 Landvex AB &middot; Org.nr 559141-7042</div>
<div class="footer-tagline">Decision intelligence for the physical world.</div>
</div>
<div class="footer-links">
<a href="https://landvex.com/">Home</a>
<a href="/verticals/">Verticals</a>
<a href="/methodology/">Methodology</a>
<a href="/security/">Security</a>
<a href="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom &rarr;</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-city-stockholm',
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 = "\u2713 Request received. We\u2019ll 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 directly at contact@landvex.com.';
msgEl.style.display = 'block';
}
btn.disabled = false; btn.textContent = 'Request Stockholm briefing \u2192';
});
document.querySelectorAll('a[href^="#"]').forEach(a => {
a.addEventListener('click', e => {
const target = document.querySelector(a.getAttribute('href'));
if (target) { e.preventDefault(); target.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
});
});
</script>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/">
<title>Landvex — Redirecting</title>
<link rel="canonical" href="https://landvex.com/">
</head>
<body>
<p>Redirecting to <a href="/">Home</a>...</p>
</body>
</html>
+251
View File
@@ -0,0 +1,251 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Compliance — Landvex</title>
<meta name="description" content="Landvex enterprise compliance: GDPR, Data Processing Agreement, AWS SOC 2 / ISO 27001 infrastructure, and enterprise security questionnaire process.">
<link rel="canonical" href="https://landvex.com/compliance/">
<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="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
:root {
--bg: #F2F2F7;
--surface: #FFFFFF;
--surface2: #F2F2F7;
--label: #000000;
--label2: #3C3C43;
--label3: rgba(60,60,67,0.65);
--separator: rgba(60,60,67,0.29);
--accent: #0066FF;
--font: -apple-system, "SF Pro Text", "Helvetica Neue", sans-serif;
--font-display: -apple-system, "SF Pro Display", "Helvetica Neue", sans-serif;
--radius-lg: 16px;
--radius-sm: 10px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #000000;
--surface: #1C1C1E;
--surface2: #2C2C2E;
--label: #FFFFFF;
--label2: #EBEBF5;
--label3: rgba(235,235,245,0.65);
--separator: rgba(84,84,88,0.65);
}
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-font-smoothing: antialiased; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--label);
padding: env(safe-area-inset-top, 20px) env(safe-area-inset-right, 20px) env(safe-area-inset-bottom, 40px) env(safe-area-inset-left, 20px);
max-width: 680px;
margin: 0 auto;
}
header { padding: 32px 0 24px; text-align: center; }
header .logo { font-family: var(--font-display); font-size: 28px; font-weight: 700; letter-spacing: -0.5px; color: var(--accent); }
header h1 { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--label); margin-top: 6px; }
header p { font-size: 13px; color: var(--label3); margin-top: 4px; }
.card { background: var(--surface); border-radius: var(--radius-lg); padding: 20px; margin-bottom: 12px; }
.card-title { font-family: var(--font-display); font-size: 17px; font-weight: 600; color: var(--label); margin-bottom: 12px; }
p, li { font-size: 15px; line-height: 1.6; color: var(--label2); }
ul { padding-left: 20px; margin-top: 8px; }
li { margin-bottom: 6px; }
.row { display: flex; align-items: flex-start; gap: 16px; padding: 12px 0; border-bottom: 0.5px solid var(--separator); }
.row:last-child { border-bottom: none; }
.row-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.blue { background: rgba(0,102,255,0.12); }
.green { background: rgba(52,199,89,0.12); }
.orange { background: rgba(255,149,0,0.12); }
.red { background: rgba(255,59,48,0.12); }
.purple { background: rgba(175,82,222,0.12); }
.teal { background: rgba(50,173,230,0.12); }
.row-content { flex: 1; }
.row-label { font-size: 15px; font-weight: 600; color: var(--label); }
.row-sub { font-size: 13px; color: var(--label3); margin-top: 2px; line-height: 1.5; }
a { color: var(--accent); text-decoration: none; }
footer { text-align: center; padding: 24px 0 8px; font-size: 13px; color: var(--label3); }
footer a { color: var(--accent); }
@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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>compliance</span>
</nav>
<header class="lv-header">
<div class="logo"><a href="https://landvex.com/" >Landvex</a></div>
<h1>Compliance</h1>
<p>Last updated: 18 June 2026 &nbsp;&middot;&nbsp; Enterprise edition</p>
</header>
<div class="card">
<div class="card-title">Overview</div>
<p>Landvex AB processes enterprise client data in accordance with EU and applicable national data protection law. This page summarises our compliance posture for enterprise procurement, legal, and data governance teams. For formal documentation, contact <a href="mailto:compliance@landvex.com">compliance@landvex.com</a>.</p>
</div>
<div class="card" id="gdpr">
<div class="card-title">GDPR — EU 2016/679</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<div class="row-content">
<div class="row-label">Data minimisation</div>
<div class="row-sub">Landvex collects and processes only the personal data necessary for the specific purposes agreed in the enterprise service contract. No personal data is used for secondary purposes without a distinct legal basis.</div>
</div>
</div>
<div class="row">
<div class="row-icon green">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#34c759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10z"/></svg>
</div>
<div class="row-content">
<div class="row-label">EU data residency</div>
<div class="row-sub">All enterprise client data is stored and processed on AWS infrastructure in Stockholm (eu-north-1). No data is transferred outside the European Economic Area without appropriate safeguards, including Standard Contractual Clauses where required.</div>
</div>
</div>
<div class="row">
<div class="row-icon orange">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff9500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label">Data Processing Agreement</div>
<div class="row-sub">A Data Processing Agreement compliant with GDPR Art. 28 is available to enterprise clients. Landvex acts as data processor for intelligence outputs delivered under contract. To request a DPA: <a href="mailto:privacy@landvex.com">privacy@landvex.com</a>.</div>
</div>
</div>
<div class="row">
<div class="row-icon purple">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#af52de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
</div>
<div class="row-content">
<div class="row-label">Data subject rights</div>
<div class="row-sub">Rights of access, rectification, erasure, portability, restriction, and objection are supported. Enterprise clients seeking to exercise rights on behalf of data subjects should contact <a href="mailto:privacy@landvex.com">privacy@landvex.com</a>. Requests are acknowledged within 5 business days.</div>
</div>
</div>
</div>
<div class="card" id="infrastructure">
<div class="card-title">Infrastructure Compliance</div>
<div class="row">
<div class="row-icon teal">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#32ade6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg>
</div>
<div class="row-content">
<div class="row-label">AWS SOC 2 Type II</div>
<div class="row-sub">Landvex runs on Amazon Web Services infrastructure, which maintains SOC 2 Type II certification. AWS compliance reports are available via AWS Artifact. Landvex application-level SOC 2 is planned.</div>
</div>
</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
</div>
<div class="row-content">
<div class="row-label">ISO 27001 (infrastructure)</div>
<div class="row-sub">AWS eu-north-1 infrastructure is ISO 27001 certified at the infrastructure level. Landvex operates within this certified environment. Enterprise clients may request AWS certification documentation.</div>
</div>
</div>
<div class="row">
<div class="row-icon green">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#34c759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10z"/></svg>
</div>
<div class="row-content">
<div class="row-label">EU-north-1 — Stockholm</div>
<div class="row-sub">All Landvex services run exclusively in AWS eu-north-1 (Stockholm, Sweden). Data never leaves the EU during ordinary processing. Cross-region failover, where used, remains within the EEA.</div>
</div>
</div>
</div>
<div class="card" id="questionnaires">
<div class="card-title">Security Questionnaires</div>
<div class="row">
<div class="row-icon orange">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff9500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
</div>
<div class="row-content">
<div class="row-label">5-business-day SLA</div>
<div class="row-sub">Landvex responds to enterprise security questionnaires and vendor assessment forms within 5 business days. We support standard questionnaire formats including CAIQ, SIG Lite, and custom procurement forms.</div>
</div>
</div>
<div class="row">
<div class="row-icon purple">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#af52de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
</div>
<div class="row-content">
<div class="row-label">Dedicated compliance contact</div>
<div class="row-sub">For security questionnaires, DPA requests, and compliance documentation: <a href="mailto:compliance@landvex.com">compliance@landvex.com</a></div>
</div>
</div>
</div>
<div class="card">
<div class="card-title">Related Documents</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/dpa/">Data Processing Agreement</a></div>
<div class="row-sub">GDPR Art. 28 DPA and Standard Contractual Clauses for enterprise clients.</div>
</div>
</div>
<div class="row">
<div class="row-icon green">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#34c759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/privacy/">Privacy Policy</a></div>
<div class="row-sub">Full data processing and retention policy for enterprise client data.</div>
</div>
</div>
<div class="row">
<div class="row-icon teal">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#32ade6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/trust/">Trust Centre</a></div>
<div class="row-sub">Infrastructure security, data quality, and verification chain documentation.</div>
</div>
</div>
<div class="row">
<div class="row-icon orange">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff9500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/security/">Security</a></div>
<div class="row-sub">Technical security controls, penetration testing, and responsible disclosure.</div>
</div>
</div>
<div class="row">
<div class="row-icon purple">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#af52de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/terms/">Terms of Service</a></div>
<div class="row-sub">Enterprise service agreement terms and conditions.</div>
</div>
</div>
</div>
<footer class="lv-footer" role="contentinfo">
<p><a href="https://landvex.com/">Landvex</a> &nbsp;·&nbsp; <a href="/privacy/">Privacy</a> &nbsp;·&nbsp; <a href="/terms/">Terms</a> &nbsp;·&nbsp; <a href="/dpa/">DPA</a> &nbsp;·&nbsp; <a href="/trust/">Trust</a> &nbsp;·&nbsp; <a href="/cookie-policy/">Cookies</a></p>
<p>© 2026 Landvex AB &nbsp;·&nbsp; Org.nr 559141-7042 &nbsp;·&nbsp; <a href="mailto:compliance@landvex.com">compliance@landvex.com</a></p>
</footer>
</body>
</html>
+114
View File
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Landvex Data Processing Addendum — for enterprise customers where Landvex acts as data processor. Contact legal@landvex.com to execute.">
<title>Data Processing Addendum — Landvex</title>
<link rel="canonical" href="https://landvex.com/dpa/">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta name="robots" content="index, follow">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif; background: #fff; color: #1d1d1f; line-height: 1.7; }
nav { height: 56px; border-bottom: 1px solid #e5e5e7; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; position: sticky; top: 0; background: rgba(255,255,255,0.92); backdrop-filter: blur(12px); z-index: 100; }
.logo { font-size: 17px; font-weight: 700; color: #1d1d1f; text-decoration: none; letter-spacing: -0.3px; }
.logo span { color: #0066cc; }
.nav-back { font-size: 14px; color: #0066cc; text-decoration: none; }
.draft-banner { background: #fff3cd; border-bottom: 1px solid #ffc107; padding: 24px; font-size: 13px; color: #664d03; text-align: center; }
main { max-width: 760px; margin: 0 auto; padding: 24px 80px; }
h1 { font-size: clamp(24px, 4vw, 36px); font-weight: 700; letter-spacing: -0.5px; margin-bottom: 8px; }
.meta { font-size: 13px; color: #6e6e73; margin-bottom: 40px; }
h2 { font-size: 18px; font-weight: 600; margin: 36px 0 12px; color: #1d1d1f; }
p { margin-bottom: 14px; font-size: 15px; color: #3a3a3c; }
ul { margin: 0 0 14px 20px; font-size: 15px; color: #3a3a3c; }
ul li { margin-bottom: 6px; }
ol { margin: 0 0 14px 20px; font-size: 15px; color: #3a3a3c; }
ol li { margin-bottom: 8px; }
table { width: 100%; border-collapse: collapse; margin: 16px 0 24px; font-size: 13px; }
th { background: #f5f5f7; padding: 24px; text-align: left; font-weight: 600; border-bottom: 2px solid #e5e5e7; }
td { padding: 24px; border-bottom: 1px solid #1a1a1a; vertical-align: top; }
.highlight { background: #f5f5f7; border-radius: 10px; padding: 24px; margin: 20px 0; font-size: 14px; }
.highlight p { margin-bottom: 0; font-size: 14px; }
.info-box { background: #e8f4fd; border-left: 4px solid #0066cc; border-radius: 0 8px 8px 0; padding: 24px; margin: 20px 0; font-size: 14px; color: #1d1d1f; }
footer { border-top: 1px solid #e5e5e7; padding: 24px; text-align: center; font-size: 13px; color: #6e6e73; }
footer a { color: #0066cc; text-decoration: none; }
a { color: #0066cc; }
@media (max-width: 600px) { main { padding: 24px 60px; } table { font-size: 12px; } }
</style>
<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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>dpa</span>
</nav>
<nav aria-label="Main navigation">
<a href="/" class="logo">Land<span>vex</span></a>
<a href="/" class="nav-back">← Landvex</a>
</nav>
<div class="draft-banner">
<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> <strong>Draft notice:</strong> This DPA is a working draft pending review by qualified data-protection counsel. Final version will be published before commercial launch (target: 1 August 2026).
</div>
<main>
<h1>Data Processing Addendum</h1>
<p class="meta">Last updated: 24 June 2026 &nbsp;·&nbsp; Version 0.1 (draft)</p>
<div class="info-box">
<strong>Note on role:</strong> This DPA applies when Landvex acts as a <em>data processor</em> for enterprise customers with bespoke processing missions. For standard Landvex intelligence products, Landvex acts as an independent data controller — please contact <a href="mailto:legal@landvex.com">legal@landvex.com</a> for controller-to-controller terms.
</div>
<p>This Data Processing Addendum ("<strong>DPA</strong>") supplements the main service agreement between the customer ("<strong>Controller</strong>") and <strong>Landvex AB</strong>, org.nr 559141-7042, Tyresö, Sweden ("<strong>Processor</strong>").</p>
<h2>1. Processing instructions</h2>
<p>Processor shall process personal data only on Controller's documented instructions, including with regard to transfers of personal data to a third country, unless required to do so by Union or Member State law; in such case, Processor shall inform Controller of that legal requirement before processing, unless the law prohibits this on grounds of public interest.</p>
<h2>2. Confidentiality</h2>
<p>Processor shall ensure that all personnel authorised to process personal data under this DPA are bound by appropriate confidentiality obligations (whether contractual or statutory) and have received appropriate data-protection training.</p>
<h2>3. Security</h2>
<p>Processor shall implement and maintain appropriate technical and organisational measures to ensure a level of security appropriate to the risk, in accordance with Article 32 GDPR. A description of current measures is published at <a href="/security/">landvex.com/security/</a>.</p>
<h2>4. Sub-processors</h2>
<p>Processor's current sub-processors are listed at <a href="/subprocessors/">landvex.com/subprocessors/</a>. Controller grants general written authorisation to engage the listed sub-processors. Processor will give Controller at least <strong>30 days' prior notice</strong> of any intended changes to the list. Controller may object to a new sub-processor within the notice period by contacting <a href="mailto:legal@landvex.com">legal@landvex.com</a>.</p>
<h2>5. Data-subject requests</h2>
<p>Processor shall assist Controller in responding to requests from data subjects exercising their rights under applicable data protection law. Processor will notify Controller of any such request received within <strong>5 business days</strong> of receipt and will not respond directly to data subjects unless authorised to do so by Controller.</p>
<h2>6. Breach notification</h2>
<p>Processor shall notify Controller of any personal data breach <strong>without undue delay</strong> and in any event within <strong>24 hours</strong> of Processor becoming aware of it. Notification will include, to the extent available: the nature of the breach; categories and approximate number of data subjects and records concerned; likely consequences; and measures taken or proposed to address the breach.</p>
<h2>7. Deletion and return</h2>
<p>Upon termination or expiry of the service agreement, Processor shall, at Controller's choice, delete or return all personal data to Controller, and delete existing copies, within <strong>30 days</strong>. Processor shall provide a written certification of deletion upon request. This obligation does not apply to the extent Processor is required by Union or Member State law to retain the personal data.</p>
<h2>8. Audit rights</h2>
<p>Processor shall make available all information reasonably necessary to demonstrate compliance with this DPA and, at Controller's reasonable request and cost, contribute to audits or inspections. Audits are limited to once per calendar year except where required by a supervisory authority or following a confirmed personal data breach. Controller shall provide reasonable prior notice.</p>
<h2>9. International transfers</h2>
<p>Any transfer of personal data outside the EEA will be made subject to appropriate safeguards, including EU Standard Contractual Clauses (Modules 2 and/or 3 as applicable) and supplementary technical and organisational measures, unless an adequacy decision applies.</p>
<h2>10. Execute this DPA</h2>
<div class="highlight">
<p>To discuss, negotiate, or execute this DPA for your organisation, contact: <a href="mailto:legal@landvex.com">legal@landvex.com</a></p>
</div>
<h2>Contact</h2>
<p><strong>Landvex AB</strong> · org.nr 559141-7042 · Tyresö, Sweden<br>
<a href="mailto:legal@landvex.com">legal@landvex.com</a> · <a href="mailto:privacy@landvex.com">privacy@landvex.com</a></p>
</main>
<footer class="lv-footer" role="contentinfo">
<p>© 2026 Landvex AB · org.nr 559141-7042 · Tyresö, Sweden · <a href="/privacy/">Privacy</a> · <a href="/terms/">Terms</a> · <a href="/subprocessors/">Sub-processors</a> · <a href="/dpa/">DPA</a></p>
</footer>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/contact/">
<title>Landvex Enterprise — Redirecting</title>
<link rel="canonical" href="https://landvex.com/contact/">
</head>
<body>
<p>Redirecting to <a href="/contact/">Contact</a>...</p>
</body>
</html>
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""
Fix canonical URLs on redirect pages.
"""
import os
# Files that need canonical fixes (path -> correct canonical)
CANONICAL_FIXES = {
"about/index.html": "https://landvex.com/about/",
"blog/index.html": "https://landvex.com/blog/",
"comparison/index.html": "https://landvex.com/comparison/",
"enterprise/index.html": "https://landvex.com/enterprise/",
"pilot/index.html": "https://landvex.com/pilot/",
}
def fix_canonical(filepath, correct_canonical):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Find and replace canonical href
original = content
content = content.replace(
f'<link rel="canonical" href="',
f'<link rel="canonical" href="{correct_canonical}">\n <!-- old: '
)
# Actually, let's do it properly
content = original
# Replace the canonical line
import re
content = re.sub(
r'<link rel="canonical" href="[^"]+">',
f'<link rel="canonical" href="{correct_canonical}">',
content
)
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def main():
base_dir = "/home/bernt/.openclaw/workspace/landvex-all"
for rel_path, canonical in CANONICAL_FIXES.items():
filepath = os.path.join(base_dir, rel_path)
if os.path.exists(filepath):
if fix_canonical(filepath, canonical):
print(f"Fixed canonical: {rel_path} -> {canonical}")
else:
print(f"No change needed: {rel_path}")
else:
print(f"File not found: {rel_path}")
if __name__ == "__main__":
main()
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""
Fix script for landvex.com audit issues.
Run from the directory containing all HTML files.
"""
import os
import re
import glob
# Target copyright text
COPYRIGHT_TARGET = "© 2026 Landvex AB · Org.nr 559141-7042 · Tyresö, Sweden"
# Patterns to find and replace for copyright
COPYRIGHT_PATTERNS = [
# Pattern -> replacement
(r'© 2026 Landvex Inc · Landvex AB \(org\.nr 559141-7042\)', COPYRIGHT_TARGET),
(r'© 2026 Landvex AB · org\.nr 559141-7042 · Tyresö, Sweden', COPYRIGHT_TARGET),
(r'© 2026 LandveX AB · Org\.nr 559141-7042', COPYRIGHT_TARGET),
(r'© 2026 Landvex\. All rights reserved\.', COPYRIGHT_TARGET),
(r'© 2026 Landvex AB &nbsp;·&nbsp; Org\.nr 559141-7042', COPYRIGHT_TARGET),
(r'&copy; 2026 Landvex Inc &middot; Landvex AB \(org\.nr 559141-7042\)', COPYRIGHT_TARGET),
]
# Nav patterns: change Enterprise to Contact in main nav
# Only change the top-level nav item, not dropdown items
NAV_ENTERPRISE_PATTERNS = [
# Main nav item (not in dropdown)
(r'<li><a href="/enterprise/">Enterprise</a></li>', '<li><a href="/contact/">Contact</a></li>'),
]
# Remove /comparison/ from Products dropdown
# This is tricky - we need to remove the comparison link from dropdowns
COMPARISON_DROPDOWN_PATTERN = r'<a href="/comparison/">\s*<svg[^>]*>.*?</svg>\s*Compare →\s*</a>\s*'
# Remove /about/ from footer
ABOUT_FOOTER_PATTERN = r'<a href="/about/">About</a>\s*'
# Remove /comparison/ from footer (but keep SLA)
COMPARISON_FOOTER_PATTERN = r'<a href="/comparison/">Compare</a>\s*'
def fix_file(filepath):
"""Apply all fixes to a single file."""
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
original = content
changes = []
# Fix 1: Copyright text
for pattern, replacement in COPYRIGHT_PATTERNS:
if re.search(pattern, content):
content = re.sub(pattern, replacement, content)
changes.append(f"copyright: {pattern[:50]}...")
# Fix 2: Nav Enterprise -> Contact (only top-level nav, not dropdown)
# Be careful - only change <li><a href="/enterprise/">Enterprise</a></li> outside dropdowns
for pattern, replacement in NAV_ENTERPRISE_PATTERNS:
if pattern in original:
content = content.replace(pattern, replacement)
changes.append("nav: Enterprise -> Contact")
# Fix 3: Remove comparison from dropdown
if re.search(COMPARISON_DROPDOWN_PATTERN, original, re.DOTALL):
content = re.sub(COMPARISON_DROPDOWN_PATTERN, '', content, flags=re.DOTALL)
changes.append("dropdown: removed /comparison/")
# Fix 4: Remove /about/ from footer
if re.search(ABOUT_FOOTER_PATTERN, original):
content = re.sub(ABOUT_FOOTER_PATTERN, '', content)
changes.append("footer: removed /about/")
# Fix 5: Remove /comparison/ from footer
if re.search(COMPARISON_FOOTER_PATTERN, original):
content = re.sub(COMPARISON_FOOTER_PATTERN, '', content)
changes.append("footer: removed /comparison/")
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return changes
return []
def main():
base_dir = "/home/bernt/.openclaw/workspace/landvex-all"
# Find all HTML files
html_files = []
for root, dirs, files in os.walk(base_dir):
for file in files:
if file.endswith('.html'):
html_files.append(os.path.join(root, file))
print(f"Found {len(html_files)} HTML files")
total_changes = 0
files_changed = 0
for filepath in sorted(html_files):
rel_path = os.path.relpath(filepath, base_dir)
changes = fix_file(filepath)
if changes:
files_changed += 1
total_changes += len(changes)
print(f" {rel_path}: {', '.join(changes)}")
print(f"\nDone: {files_changed} files changed, {total_changes} total fixes")
if __name__ == "__main__":
main()
+2414
View File
@@ -0,0 +1,2414 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Landvex — Decision Intelligence for the Physical World</title>
<meta name="description" content="Landvex delivers control intelligence for infrastructure owners, enterprises and governments. Decision intelligence for the physical world.">
<link rel="canonical" href="https://landvex.com/">
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/">
<meta property="og:title" content="Landvex — Decision Intelligence for the Physical World">
<meta property="og:description" content="Landvex is a Swedish-headquartered control intelligence company (Landvex AB, Tyresö) with 5 Markets — Phased Rollout. We deliver control intelligence for infrastructure owners, enterprises and governments globally.">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Landvex — Decision Intelligence for the Physical World">
<meta name="twitter:description" content="Landvex is a decision intelligence platform that transforms field observations into infrastructure intelligence, urban intelligence and commercial intelligence. Not related to LandEx or land investment platforms.">
<meta name="twitter:image" content="https://landvex.com/og-image.jpg">
<!-- 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">
<!-- Structured Data -->
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
/* === SYMMETRY FIXES — injected 2026-07-05 === */
.vertical-card { min-height: 220px; }
.intel-card { min-height: 420px; }
.intel-kpis { min-height: 100px; }
.vertical-card p { min-height: 3.5em; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.intel-card h3 { min-height: 1.5em; }
.verticals-grid, .intel-grid { align-items: stretch !important; }
/* === END SYMMETRY FIXES === */
*, *::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.10);
--text-dark: #1d1d1f;
--text-body: #3a3a3a;
--text-muted: #6e6e73;
--text-light: #1d1d1f;
--text-dim: #515154;
--surface: #ffffff;
--surface-2: #f5f5f7;
--border: rgba(0,0,0,0.09);
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 24px;
}
html { scroll-behavior: smooth; }
body { background: #FFFFFF;
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Helvetica Neue', sans-serif;
background: #FFFFFF;
color: #0A0A0A;
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: 1000;
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 rgba(0,0,0,0.08);
}
.nav-logo { color: #0A0A0A;
font-size: 18px;
font-weight: 700;
letter-spacing: -0.3px;
color: #0A0A0A;
}
.nav-links {
display: flex; gap: 16px; list-style: none;
}
.nav-links a { color: #4A4A4A;
font-size: 14px;
color: #4A4A4A;
transition: color 0.2s;
}
.nav-links a:hover { color: #0A0A0A; }
/* Dropdown */
.nav-dropdown {
position: relative;
}
.nav-dropdown > a {
display: flex; align-items: center; gap: 16px; cursor: pointer;
}
.nav-dropdown > a::after {
content: '';
display: inline-block;
width: 0; height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid currentColor;
opacity: 0.55;
margin-top: 1px;
transition: transform 0.2s;
}
.nav-dropdown:hover > a::after,
.nav-dropdown:focus-within > a::after { transform: rotate(180deg); }
.nav-dropdown-menu {
display: none;
position: absolute; top: 100%; left: 50%;
transform: translateX(-50%);
background: rgba(255,255,255,0.97);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 8px 0;
min-width: 220px;
max-height: calc(100vh - 80px);
overflow-y: auto;
box-shadow: 0 16px 40px rgba(0,0,0,0.12);
z-index: 9999;
backdrop-filter: blur(12px);
}
/* Bridge gap so hover doesn't break when moving from link to menu */
.nav-dropdown-menu::before {
content: '';
position: absolute;
top: -12px; left: 0; right: 0;
height: 12px;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu { display: block; }
.nav-dropdown-menu a {
display: flex; align-items: center; gap: 16px;
padding: 24px;
font-size: 14px; color: #4A4A4A;
transition: color 0.15s, background 0.15s;
white-space: nowrap;
}
.nav-dropdown-menu a:hover { color: #0A0A0A; background: rgba(0,0,0,0.03); }
.nav-dropdown-menu .dd-label {
font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: rgba(0,0,0,0.75);
padding: 24px 4px; cursor: default;
}
.nav-dropdown-menu hr { border: none; border-top: 1px solid var(--border); margin: 6px 0; }
.btn { color: #FFFFFF;
display: inline-flex; align-items: center; gap: 16px;
padding: 24px;
background: var(--blue);
color: #0A0A0A;
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 { color: #0A0A0A; border-color: rgba(0,0,0,0.15);
background: transparent;
border: 1.5px solid rgba(0,0,0,0.18);
color: #0A0A0A;
}
.btn-outline:hover { background: rgba(0,0,0,0.04); transform: translateY(-1px); }
.btn-lg { padding: 24px; font-size: 16px; border-radius: var(--radius-md); }
/* ── HERO ── */
.hero {
min-height: 100vh;
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 { color: #0A0A0A;
font-size: clamp(44px, 7vw, 80px);
font-weight: 800;
letter-spacing: -2px;
line-height: 1.05;
color: #0A0A0A;
max-width: 820px;
margin-bottom: 24px;
}
.hero-sub { color: #4A4A4A;
font-size: clamp(16px, 2vw, 20px);
color: #4A4A4A;
max-width: 640px;
line-height: 1.65;
margin-bottom: 40px;
}
.hero-ctas {
display: flex; gap: 16px; flex-wrap: wrap; justify-content: center;
}
.hero-powered {
margin-top: 56px;
font-size: 13px;
color: #6E6E73;
display: flex; align-items: center; gap: 16px;
}
.hero-powered span { color: #5599ff; font-weight: 600; }
.hero-stats {
display: flex; gap: 16px; margin-top: 72px; justify-content: center; flex-wrap: wrap;
}
.stat { text-align: center; }
.stat-val {
font-size: 32px; font-weight: 800;
background: linear-gradient(135deg, #fff 60%, #5599ff);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
letter-spacing: -1px;
}
.stat-label { font-size: 13px; color: #6E6E73; margin-top: 4px; }
/* ── SECTION COMMON ── */
section { padding: 24px; }
.container { max-width: 1140px; margin: 0 auto; }
.section-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--blue);
margin-bottom: 24px;
}
.section-title { color: #0A0A0A;
font-size: clamp(28px, 4vw, 44px);
font-weight: 800;
letter-spacing: -1.2px;
line-height: 1.1;
color: #0A0A0A;
margin-bottom: 24px;
}
.section-sub { color: #4A4A4A;
font-size: 17px;
color: #4A4A4A;
max-width: 560px;
line-height: 1.7;
}
/* ── DELIVER ── */
.deliver-bg { background: var(--surface); }
.deliver-header {
display: flex; flex-direction: column; align-items: center;
text-align: center; margin-bottom: 60px;
}
.deliver-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.deliver-card {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
transition: border-color 0.25s, transform 0.2s;
}
.deliver-card:hover {
border-color: rgba(0,102,255,0.35);
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0,0,0,0.10);
}
.deliver-icon {
width: 44px; height: 44px;
background: var(--blue-glow);
border: 1px solid rgba(0,102,255,0.25);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 20px;
margin-bottom: 24px;
}
.deliver-card h3 { color: #0A0A0A;
font-size: 18px; font-weight: 700;
color: #0A0A0A; margin-bottom: 10px;
letter-spacing: -0.3px;
}
.deliver-card .number {
font-size: 32px; font-weight: 800;
color: var(--blue); letter-spacing: -1px;
margin-bottom: 8px;
}
.deliver-card p { color: #4A4A4A; font-size: 15px; color: #4A4A4A; line-height: 1.6; }
/* ── VERTICALS ── */
.verticals-header {
text-align: center;
margin-bottom: 60px;
}
.verticals-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.vertical-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
display: flex; align-items: flex-start; gap: 16px;
transition: border-color 0.25s, background 0.2s;
}
.vertical-card:hover {
border-color: rgba(0,102,255,0.3);
background: var(--surface-2);
}
.vertical-icon {
font-size: 24px;
flex-shrink: 0;
width: 44px; height: 44px;
display: flex; align-items: center; justify-content: center;
background: #FFFFFF;
border-radius: var(--radius-md);
}
.vertical-card h3 { color: #0A0A0A; font-size: 16px; font-weight: 700; color: #0A0A0A; margin-bottom: 6px; }
.vertical-card p { color: #4A4A4A; font-size: 14px; color: #4A4A4A; line-height: 1.5; }
/* ── HOW IT WORKS ── */
.how-bg { background: var(--surface); }
.how-header { text-align: center; margin-bottom: 64px; }
.how-steps {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
position: relative;
}
.how-steps::before {
content: '';
position: absolute;
top: 28px; left: 12.5%; right: 12.5%;
height: 1px;
background: linear-gradient(90deg, transparent, var(--blue) 20%, var(--blue) 80%, transparent);
opacity: 0.3;
}
.how-step { transition: transform .15s, border-color .15s; }
.how-step:hover { transform: translateY(-3px); border-color: rgba(0,102,255,0.4); }
.how-step {
text-align: center;
padding: 0 20px;
position: relative;
}
.step-num {
width: 56px; height: 56px;
border-radius: 50%;
background: var(--blue-glow);
border: 2px solid var(--blue);
display: flex; align-items: center; justify-content: center;
font-size: 18px; font-weight: 800;
color: var(--blue);
margin: 0 auto 24px;
position: relative; z-index: 1;
}
.how-step h3 { font-size: 16px; font-weight: 700; color: #0A0A0A; margin-bottom: 8px; }
.how-step p { font-size: 14px; color: #4A4A4A; line-height: 1.6; }
/* ── CONTACT ── */
.contact-wrapper {
max-width: 680px;
margin: 0 auto;
text-align: center;
}
.contact-wrapper .section-title { color: #0A0A0A; margin-bottom: 10px; }
.contact-wrapper .section-sub { color: #4A4A4A; margin: 0 auto 48px; }
.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: #4A4A4A; }
.form-group input, .form-group textarea {
background: var(--bg-dark);
border: 1.5px solid var(--border);
border-radius: var(--radius-md);
color: #0A0A0A;
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: #6E6E73;
}
.form-group textarea { min-height: 120px; resize: vertical; }
.form-note { font-size: 12px; color: #6E6E73; 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 ── */
footer {
border-top: 1px solid var(--border);
padding: 24px;
}
.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: #0A0A0A; }
.footer-copy { font-size: 13px; color: #6E6E73; }
.footer-links { display: flex; gap: 16px; align-items: center; flex-wrap:wrap;gap: 16px 24px;}
.footer-links a { font-size: 14px; color: #6E6E73; transition: color 0.2s; }
.footer-links a:hover { color: #0A0A0A; }
.vertical-card { cursor: pointer; text-decoration: none; color: inherit; display: block; transition: transform .15s, box-shadow .15s; }
.vertical-card:hover { transform: translateY(-3px); box-shadow: 0 8px 32px rgba(0,0,0,.12); }
@media(max-width:640px){
.backwards-arrow{display:none}
.backwards-step{width:calc(50% - 8px);min-width:120px}
.how-grid{grid-template-columns:1fr!important}
.how-grid>div{border-left:none!important;border-top:1px solid rgba(0,0,0,.06)!important}
.how-grid>div:first-child{border-top:none!important}
.how-grid>div{padding: 24px!important}
}
.vertical-card .drill-hint { font-size:.8rem; font-weight:700; color:var(--blue,#0066ff); margin-top:8px; display:block; }
.footer-social {
width: 32px; height: 32px;
border: 1px solid var(--border);
border-radius: 8px;
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: #6E6E73; margin-top: 4px; }
/* ── RESPONSIVE ── */
@media (max-width: 900px) {
nav { padding: 0 16px; }
.nav-links { display: none; }
.deliver-grid { grid-template-columns: 1fr; }
.verticals-grid { grid-template-columns: 1fr 1fr; }
.how-steps { grid-template-columns: 1fr 1fr; gap: 16px; }
.how-steps::before { display: none; }
}
@media (max-width: 640px) {
.hero h1 { color: #0A0A0A; font-size: clamp(28px, 8vw, 48px); }
.hero-sub { color: #4A4A4A; font-size: 16px; }
.hero-ctas { flex-direction: column; gap: 16px; }
.hero-ctas a { width: 100%; text-align: center; }
.hero-stats { flex-direction: column; gap: 16px; align-items: flex-start; }
.section-title { color: #0A0A0A; font-size: clamp(22px, 6vw, 36px); }
.deliver-grid { grid-template-columns: 1fr; }
.deliver-card { padding: 24px; }
.deliver-icon { overflow: hidden !important; }
.deliver-icon svg { max-width: 24px; max-height: 24px; flex-shrink: 0; }
.verticals-grid { grid-template-columns: 1fr; }
.how-steps { grid-template-columns: 1fr; }
.form-row { grid-template-columns: 1fr; }
.contact-form { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
.community-pipeline { flex-direction: column; gap: 16px; padding: 24px; }
.community-pipeline-text h3 { font-size: 1.1rem; }
}
@media (max-width: 480px) {
.container { padding: 0 16px !important; box-sizing: border-box; }
section { padding: 56px 0; }
.hero { padding: 24px 60px; }
.deliver-grid { grid-template-columns: 1fr; gap: 16px; }
.verticals-grid { grid-template-columns: 1fr; gap: 16px; }
.vertical-card { padding: 24px; }
.nav-logo { color: #0A0A0A; font-size: 18px; }
.backwards-arrow { display: none; }
.how-step { transition: transform .15s, border-color .15s; }
.how-step:hover { transform: translateY(-3px); border-color: rgba(0,102,255,0.4); }
.how-step { padding: 24px; }
.contact-form { padding: 24px; }
.footer-inner { gap: 16px; }
.footer-links { flex-wrap: wrap; justify-content: center; gap: 16px 16px; }
table { font-size: .75rem; }
table th, table td { padding: 24px; }
.contradiction-grid { grid-template-columns: 1fr !important; }
.howwework-grid { grid-template-columns: 1fr !important; }
}
/* ── Global mobile fix ───────────────────────────────────────────── */
@media(max-width:480px){
img, svg { max-width:100%; }
table { overflow-x:auto; display:block; }
.container { padding:0 16px !important; box-sizing:border-box; }
/* Reduce inline section padding on mobile */
section[style*="padding:80px"],
section[style*="padding:96px"] { padding-top:48px !important; padding-bottom:48px !important; }
/* Contradiction header */
div[style*="margin-bottom:56px"] { margin-bottom:32px !important; }
div[style*="margin-bottom:48px"] { margin-bottom:24px !important; }
/* How we work grid: single column */
.how-grid { grid-template-columns:1fr !important; }
.how-grid > div { border-left:none !important; border-top:1px solid rgba(0,0,0,.07) !important; padding: 24px !important; }
.how-grid > div:first-child { border-top:none !important; }
/* howwework-grid: single column with tighter padding */
.howwework-grid > div { padding:20px !important; }
}
/* Map section mobile fixes */
@media(max-width:600px){
.map-iframe{min-height:260px!important;height:52vh!important}
.map-overlay{position:static!important;background:rgba(0,0,0,.95)!important;border-radius:0 0 16px 16px;flex-direction:column;align-items:flex-start;gap: 16px;padding: 24px!important}
.map-cta-row{width:100%;display:flex;gap: 16px}
.map-cta-row a{flex:1;text-align:center}
}
/* SVG overflow fix — global */
svg { max-width: 100%; overflow: visible; }
.deliver-icon svg,
.vertical-icon svg,
.footer-social svg,
.row-icon svg { overflow: hidden; flex-shrink: 0; }
/* AUDIT FIX m-001 safety net */
html,body{overflow-x:clip}
/* ── SOCIAL PROOF ── */
.social-proof {
background: #ffffff;
border-top: 1px solid rgba(0,0,0,0.06);
border-bottom: 1px solid rgba(0,0,0,0.06);
padding: 24px;
text-align: center;
}
.sp-label {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #a1a1a6;
margin-bottom: 20px;
}
.sp-logos {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16px 24px;
max-width: 800px;
margin: 0 auto;
}
.sp-item {
font-size: 13px;
font-weight: 600;
color: #6e6e73;
background: #FFFFFF;
border: 1px solid rgba(0,0,0,0.08);
border-radius: 8px;
padding: 24px;
white-space: nowrap;
transition: border-color 0.2s, color 0.2s;
}
.sp-item:hover { border-color: rgba(0,102,255,0.22); color: #0A0A0A; }
/* ── P4 MICROINTERACTIONS ── */
.deliver-card, .vertical-card, .intel-card {
transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.2s ease;
}
/* ── CTA SECONDARY ── */
.cta-secondary {
display: inline-flex; align-items: center; gap: 16px;
padding: 24px;
background: transparent;
border: 1.5px solid rgba(0,0,0,0.18);
color: #0A0A0A;
font-size: 15px;
font-weight: 600;
border-radius: var(--radius-md,14px);
transition: background 0.2s, border-color 0.2s, transform 0.15s;
text-decoration: none;
}
.cta-secondary:hover { background: rgba(0,0,0,0.04); border-color: rgba(0,102,255,0.35); color: #0066FF; transform: translateY(-1px); }
/* ── FOOTER ECOSYSTEM ── */
.footer-ecosystem {
font-size: 12px; color: #6e6e73; margin-top: 12px; line-height: 1.5;
}
.footer-ecosystem a { color: #0066FF; text-decoration: none; }
.footer-ecosystem a:hover { text-decoration: underline; }
/* LV Illustrations */
.lv-ill-wrap{display:flex;justify-content:center;padding:40px 0 24px}
.lv-ill-wrap svg{max-width:100%;height:auto}
/* Intelligence Cards v2 */
.intel-grid{display:grid;grid-template-columns:repeat(2,1fr);gap: 16px;margin-top:40px}
@media(max-width:768px){.intel-grid{grid-template-columns:1fr}}
.intel-card{background:#ffffff;border:1px solid rgba(0,0,0,.08);border-radius: var(--radius-lg);padding:28px;text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:0;transition:border-color .2s,transform .2s;cursor:pointer}
.intel-card:hover{border-color:rgba(0,102,255,.35);transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,0.12)}
.intel-card-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}
.intel-module{font-size:.6875rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#0066FF;margin-bottom:6px}
.intel-card h3{font-size:1.0625rem;font-weight:800;color: #0A0A0A;margin:0}
.intel-card-geo{font-size:.75rem;color:rgba(0,0,0,.75);margin-top:2px}
.intel-tag{font-size:.625rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding: 24px;border-radius:100px;white-space:nowrap}
.intel-tag-live{background:rgba(0,200,83,.12);color:#00C853;border:1px solid rgba(0,200,83,.2)}
.intel-tag-risk{background:rgba(255,59,48,.1);color:#FF3B30;border:1px solid rgba(255,59,48,.2)}
.intel-tag-pred{background:rgba(0,102,255,.12);color:#0066FF;border:1px solid rgba(0,102,255,.2)}
.intel-kpis{display:grid;grid-template-columns:repeat(3,1fr);gap: 16px;margin-bottom:20px}
.intel-kpi{background:rgba(0,0,0,.03);border-radius:10px;padding: 24px}
.intel-kpi-val{font-size:1.1875rem;font-weight:900;color: #0A0A0A;letter-spacing:-.03em;line-height:1}
.intel-kpi-delta{font-size:.6875rem;font-weight:700;margin-top:3px}
.intel-kpi-delta.up{color:#00C853}
.intel-kpi-delta.down{color:#FF3B30}
.intel-kpi-lbl{font-size:.625rem;color:rgba(0,0,0,.75);margin-top:2px;line-height:1.3}
.intel-bar-list{display:flex;flex-direction:column;gap: 16px;margin-bottom:20px}
.intel-bar-row{display:flex;align-items:center;gap: 16px}
.intel-bar-name{font-size:.75rem;color:rgba(0,0,0,.65);min-width:110px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.intel-bar-track{flex:1;height:5px;background:rgba(0,0,0,.06);border-radius:3px;overflow:hidden}
.intel-bar-fill{height:100%;border-radius:3px;background:#0066FF}
.intel-bar-fill.risk{background:#FF3B30}
.intel-bar-fill.opp{background:#00C853}
.intel-bar-score{font-size:.6875rem;font-weight:700;color:rgba(0,0,0,.75);min-width:28px;text-align:right}
.intel-card-footer{display:flex;align-items:center;justify-content:space-between;padding-top:16px;border-top:1px solid rgba(0,0,0,.06);margin-top:auto}
.intel-obs{font-size:.6875rem;color:rgba(0,0,0,.75)}
.intel-cta{font-size:.75rem;font-weight:700;color:#0066FF;display:flex;align-items:center;gap: 16px}
.intel-confidence{display:flex;align-items:center;gap: 16px;font-size:.6875rem;color:rgba(0,0,0,.75)}
.intel-conf-bar{width:48px;height:4px;background:rgba(0,0,0,.08);border-radius:2px;overflow:hidden}
.intel-conf-fill{height:100%;background:#0066FF;border-radius:2px}
.intel-map-placeholder{background:linear-gradient(135deg,#0d1f3c 0%,#0a1628 50%,#0d2235 100%);border-radius:10px;height:80px;position:relative;overflow:hidden;margin-bottom:20px}
.intel-map-dot{position:absolute;width:8px;height:8px;border-radius:50%;background:#0066FF;box-shadow:0 0 0 3px rgba(0,102,255,.2)}
.intel-map-dot.hot{background:#00C853;box-shadow:0 0 0 3px rgba(0,200,83,.2)}
.intel-map-dot.warn{background:#FF3B30;box-shadow:0 0 0 3px rgba(255,59,48,.2)}
/* LV-ILL-02 Pipeline */
.lv-pipeline{display:flex;align-items:center;justify-content:center;gap:0;margin:32px 0 40px;overflow-x:auto;padding:0 8px}
.lv-pipeline-step{display:flex;flex-direction:column;align-items:center;gap: 16px;min-width:88px}
.lv-pipeline-icon{width:52px;height:52px;border-radius:14px;background:rgba(0,102,255,.08);border:1px solid rgba(0,102,255,.18);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lv-pipeline-label{font-size:.6875rem;font-weight:700;color:rgba(0,0,0,.75);text-align:center;letter-spacing:.02em;line-height:1.3}
.lv-pipeline-connector{width:32px;height:2px;background:linear-gradient(90deg,rgba(0,102,255,.3),rgba(0,102,255,.1));flex-shrink:0;margin-top:-22px;align-self:flex-start;margin-left:0;position:relative;top:-26px}
@media(max-width:600px){.lv-pipeline{justify-content:flex-start}.lv-pipeline-connector{width:20px}}
@media(max-width:480px){.intel-grid{grid-template-columns:1fr}.intel-kpis{grid-template-columns:repeat(3,1fr)}.intel-bar-name{min-width:80px}}
@media(max-width:480px){.lv-pipeline{gap:0}.lv-pipeline-step{min-width:56px}.lv-pipeline-label{font-size:.5625rem}.lv-pipeline-icon{width:38px;height:38px;border-radius:10px}.lv-pipeline-connector{width:10px}}
</style>
<style id="lv-light-theme">
/* Landvex Light Theme Override */
:root {
--bg-dark: #f5f5f7 !important;
--text-light: #1d1d1f !important;
--text-dim: #515154 !important;
--surface: #ffffff !important;
--surface-2: #f5f5f7 !important;
--border: rgba(0,0,0,0.09) !important;
}
body { background: #FFFFFF; background: #f5f5f7 !important; color: #1d1d1f !important; }
nav { background: rgba(255,255,255,0.92) !important; border-bottom: 1px solid rgba(0,0,0,0.08) !important; }
.nav-logo { color: #0A0A0A !important; }
.nav-links a { color: #4A4A4A !important; }
.nav-links a:hover { color: #0A0A0A !important; }
.nav-dropdown-menu { background: rgba(255,255,255,0.97) !important; border: 1px solid rgba(0,0,0,0.10) !important; box-shadow: 0 8px 32px rgba(0,0,0,0.12) !important; }
.nav-dropdown-menu a { color: #4A4A4A !important; }
.nav-dropdown-menu a:hover { color: #0A0A0A !important; background: rgba(0,0,0,0.04) !important; }
.nav-dropdown-menu .dd-label { color: #6E6E73 !important; }
.nav-dropdown-menu hr { border-top: 1px solid rgba(0,0,0,0.08) !important; }
.btn-outline { color: #0A0A0A; border-color: rgba(0,0,0,0.15); border: 1.5px solid rgba(0,0,0,0.18) !important; color: #1d1d1f !important; background: transparent !important; }
.btn-outline:hover { background: rgba(0,0,0,0.06) !important; }
.hero { background: #ffffff !important; }
.hero::before { background: radial-gradient(ellipse at center, rgba(0,102,255,0.07) 0%, transparent 70%) !important; }
.hero h1 { color: #0A0A0A; color: #1d1d1f !important; }
.hero-sub { color: #4A4A4A; color: #515154 !important; }
.hero-eyebrow { background: rgba(0,102,255,0.08); border: 1px solid rgba(0,102,255,0.2); color: #0066FF; background: rgba(0,102,255,0.08) !important; border: 1px solid rgba(0,102,255,0.18) !important; color: #0052CC !important; }
.stat-val { background: linear-gradient(135deg, #1d1d1f 60%, #0066FF) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; }
.stat-label { color: #6e6e73 !important; }
.section-title { color: #0A0A0A; color: #1d1d1f !important; }
.section-sub { color: #4A4A4A; color: #515154 !important; }
.deliver-bg { background: #ffffff !important; }
.deliver-card { background: #f5f5f7 !important; border: 1px solid rgba(0,0,0,0.08) !important; }
.deliver-card:hover { border-color: rgba(0,102,255,0.28) !important; }
.deliver-card h3 { color: #0A0A0A; color: #1d1d1f !important; }
.deliver-card p { color: #4A4A4A; color: #515154 !important; }
.deliver-icon { background: rgba(0,102,255,0.08) !important; border: 1px solid rgba(0,102,255,0.18) !important; }
.vertical-card { background: #ffffff !important; border: 1px solid rgba(0,0,0,0.08) !important; }
.vertical-card:hover { border-color: rgba(0,102,255,0.25) !important; background: #f5f5f7 !important; }
.vertical-card h3 { color: #0A0A0A; color: #1d1d1f !important; }
.vertical-card p { color: #4A4A4A; color: #515154 !important; }
.vertical-icon { background: #f5f5f7 !important; }
.how-bg { background: #f5f5f7 !important; }
.how-step h3 { color: #1d1d1f !important; }
.how-step p { color: #515154 !important; }
.step-num { background: rgba(0,102,255,0.08) !important; border: 2px solid #0066FF !important; color: #0066FF !important; }
.contact-form { background: #ffffff !important; border: 1px solid rgba(0,0,0,0.08) !important; }
.form-group label { color: #515154 !important; }
.form-group input, .form-group textarea { background: #f5f5f7 !important; border: 1.5px solid rgba(0,0,0,0.12) !important; color: #1d1d1f !important; }
.form-group input::placeholder, .form-group textarea::placeholder { color: #a1a1a6 !important; }
footer { border-top: 1px solid rgba(0,0,0,0.08) !important; background: #ffffff !important; }
.footer-logo { color: #1d1d1f !important; }
.footer-copy { color: #6e6e73 !important; }
.footer-links a { color: #6e6e73 !important; }
.footer-links a:hover { color: #1d1d1f !important; }
.footer-social { border: 1px solid rgba(0,0,0,0.10) !important; }
.footer-social:hover { border-color: rgba(0,0,0,0.22) !important; background: rgba(0,0,0,0.04) !important; }
.intel-card { background: #ffffff !important; border: 1px solid rgba(0,0,0,0.08) !important; }
.intel-card:hover { border-color: rgba(0,102,255,0.28) !important; }
.intel-card h3 { color: #1d1d1f !important; }
.intel-card-geo { color: #515154 !important; }
.intel-kpi { background: rgba(0,0,0,0.03) !important; }
.intel-kpi-val { color: #1d1d1f !important; }
.intel-kpi-lbl { color: #6e6e73 !important; }
.intel-bar-name { color: #515154 !important; }
.intel-bar-track { background: rgba(0,0,0,0.06) !important; }
.intel-bar-score { color: #515154 !important; }
.intel-card-footer { border-top: 1px solid rgba(0,0,0,0.07) !important; }
.intel-obs { color: #6e6e73 !important; }
.intel-confidence { color: #6e6e73 !important; }
.intel-conf-bar { background: rgba(0,0,0,0.08) !important; }
.intel-map-placeholder { background: linear-gradient(135deg, #e8f0fe 0%, #dce8fd 50%, #e4effe 100%) !important; }
.lv-pipeline-label { color: #515154 !important; }
.lv-pipeline-icon { background: rgba(0,102,255,0.07) !important; border: 1px solid rgba(0,102,255,0.15) !important; }
.lv-pipeline-connector { background: linear-gradient(90deg, rgba(0,102,255,0.2), rgba(0,102,255,0.07)) !important; }
.drill-hint { color: #0066FF !important; }
table { background: #ffffff !important; }
table th { background: #f5f5f7 !important; color: #515154 !important; border-bottom: 1px solid rgba(0,0,0,0.08) !important; }
table td { color: #1d1d1f !important; border-bottom: 1px solid rgba(0,0,0,0.06) !important; }
section#cities { background: #f5f5f7 !important; }
section[style*="background:var(--surface-2)"], section[style*="background:var(--surface)"] { background: #f5f5f7 !important; }
.how-grid > div { border-top: 1px solid rgba(0,0,0,0.07) !important; }
@media(max-width:900px) { nav { background: rgba(255,255,255,0.92) !important; } }
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": [
"Organization",
"Corporation"
],
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"alternateName": [
"LandveX",
"Landvex AB",
"LandveX AB"
],
"url": "https://landvex.com",
"logo": {
"@type": "ImageObject",
"url": "https://landvex.com/apple-touch-icon.png",
"width": 180,
"height": 180
},
"foundingDate": "2024",
"foundingLocation": {
"@type": "Place",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
},
"legalName": "Landvex Inc",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
},
"location": [
{
"@type": "Place",
"name": "Houston, Texas, USA (US HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
}
},
{
"@type": "Place",
"name": "Tyresö, Sweden (EU HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
}
}
],
"taxID": "pending-EIN",
"description": "Landvex is a decision intelligence company that identifies contradictions between official narratives and observed physical reality. Using the quiXzoom field observation network and the AMOS AI analysis engine, Landvex delivers infrastructure risk indexes, urban intelligence scores, and contradiction reports to infrastructure owners, municipalities, enterprises, and investors globally.",
"disambiguatingDescription": "Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European headquarters in Tyresö, Sweden (Landvex AB, org.nr 559141-7042). Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors. Landvex is not a UK meat wholesaler, food distributor, logistics company, package tracker, or land investment platform.",
"knowsAbout": [
"control intelligence",
"decision intelligence",
"infrastructure risk assessment",
"urban intelligence",
"field data collection",
"contradiction detection",
"physical world analytics",
"geospatial analytics"
],
"brand": {
"@type": "Brand",
"name": "Landvex",
"slogan": "Control intelligence for the physical world."
},
"sameAs": [
"https://landvex.com",
"https://www.linkedin.com/company/landvex",
"https://x.com/landvex",
"https://twitter.com/landvex",
"https://www.crunchbase.com/organization/landvex",
"https://github.com/landvex",
"https://www.instagram.com/landvex"
],
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@landvex.com",
"contactType": "sales"
},
"slogan": "Where reported reality conflicts with observed reality."
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"@id": "https://landvex.com/#website",
"url": "https://landvex.com",
"name": "Landvex",
"description": "Landvex — decision intelligence for the physical world. Not a meat wholesaler, food company, or logistics firm.",
"publisher": {
"@id": "https://landvex.com/#organization"
},
"inLanguage": "en",
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://landvex.com/?q={search_term_string}"
},
"query-input": "required name=search_term_string"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Landvex",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"description": "Decision intelligence platform for infrastructure, urban and commercial intelligence. Helps municipalities, property owners, infrastructure operators and retail chains make better decisions about physical assets.",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "EUR",
"description": "Contact for enterprise pricing"
},
"publisher": {
"@id": "https://landvex.com/#organization"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What does Landvex do?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex delivers decision intelligence for the physical world. It identifies contradictions between official narratives and observed reality, produces infrastructure risk indexes (0100 scores), urban intelligence, and predictive trend signals — using field observations from the quiXzoom network analysed by the AMOS AI engine. Customers include municipalities, infrastructure operators, property owners, insurers, and investors."
}
},
{
"@type": "Question",
"name": "Is Landvex a meat company or food wholesaler?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. Landvex (landvex.com) is a decision intelligence company — not a meat wholesaler, food distributor, or any food-related business. Landvex AB (Tyresö, Sweden) builds infrastructure risk intelligence, urban analytics and contradiction reports for municipalities, enterprises and investors."
}
},
{
"@type": "Question",
"name": "What is Landvex?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex is a decision intelligence platform for the physical world. It helps municipalities, property owners, infrastructure operators and enterprises make better decisions about physical assets."
}
},
{
"@type": "Question",
"name": "How does Landvex collect data?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex uses the quiXzoom contributor network — verified field contributors who collect observations on demand. Every submission is AI-reviewed for quality and specification compliance. Field observations are licensed from quiXzoom Inc under a data processing agreement; individual contributor data is anonymised before analysis."
}
},
{
"@type": "Question",
"name": "What decisions does Landvex support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex supports decisions on where to invest, where risk is increasing, what is changing in a geography, and where infrastructure or commercial conditions are deteriorating."
}
},
{
"@type": "Question",
"name": "How do I start with Landvex?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex offers a pilot programme — a defined question, defined geography, 6-8 weeks. Contact us at landvex.com/pilot to discuss scope and pricing."
}
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Landvex",
"item": "https://landvex.com/"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Speakable",
"speakableSelector": {
"@type": "CssSelectorType",
"cssSelector": [
"h1",
".hero-h1",
".hero-sub",
".hero-eyebrow"
]
},
"url": "https://landvex.com/"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is Landvex?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Landvex is a decision intelligence platform for the physical world. It turns verified field observations — captured by the quiXzoom contributor network — into structured, decision-ready intelligence for organisations managing physical assets, locations and risk."
}
},
{
"@type": "Question",
"name": "Is Landvex a logistics or transport company?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. Landvex is not affiliated with any logistics, freight or land-transport companies of similar name. Landvex provides decision intelligence built on verified field data."
}
},
{
"@type": "Question",
"name": "What is quiXzoom?",
"acceptedAnswer": {
"@type": "Answer",
"text": "quiXzoom is the field observation network that powers Landvex: vetted local contributors who complete structured capture missions with geo-tagged, timestamped, AI-reviewed evidence."
}
},
{
"@type": "Question",
"name": "How fast is intelligence delivered?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Standard missions return structured intelligence within 2472 hours of tasking, depending on scope and location."
}
},
{
"@type": "Question",
"name": "How does a pilot work?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A pilot runs for three months, scoped around one real decision your organisation faces. Successful pilots typically continue as an annual intelligence subscription."
}
}
]
}
</script>
</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 class="nav-dropdown">
<a href="/methodology/">Intelligence</a>
<div class="nav-dropdown-menu">
<div class="dd-label">Learn</div>
<a href="/methodology/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Methodology
</a>
<a href="#intelligence">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
Intelligence scores
</a>
<hr/>
<div class="dd-label">Verticals</div>
<a href="/verticals/property/">Property &amp; Real Estate</a>
<a href="/verticals/investors/">Investors &amp; Asset Mgrs</a>
<a href="/verticals/municipalities/">Municipalities</a>
<a href="/verticals/infrastructure/">Infrastructure</a>
<a href="/verticals/retail/">Retail &amp; F&amp;B</a>
<a href="/verticals/insurance/">Insurance</a>
<a href="/verticals/utilities/">Utilities</a>
<hr/>
<div class="dd-label">Products</div>
<a href="/enterprise/">
<svg width="14" height="14" 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="2"/><path d="M3 9h18M9 21V9"/></svg>
Enterprise
</a>
<a href="/reports/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Intelligence Reports
</a>
<a href="/pilot/">
<svg width="14" height="14" 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"/><polyline points="12 6 12 12 16 14"/></svg>
Pilot Programme
</a>
<hr/>
<div class="dd-label">Compare</div>
<a href="/sla/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
SLA &amp; Coverage →
</a>
<hr/>
<a href="/security/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Security
</a>
</div>
</li>
<li><a href="#cities">Cities</a></li>
<li><a href="/insights/">Insights</a></li>
<li><a href="/contact/">Contact</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="#contact">Get in touch →</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">Reality Intelligence Operating System</div>
<h1>The OS for the physical world.</h1>
<p class="lv-hero-subtitle">Landvex RIOS transforms continuous video observations into structured Reality Intelligence. Not just data — a continuously learning system that observes, explains, prioritises and improves.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="/verticals/insurance/">Insurance intelligence &rarr;</a>
<a class="btn btn-outline btn-lg" href="/contact/">Contact us &rarr;</a>
<a href="/methodology/" class="cta-secondary">See how we work &rarr;</a>
</div>
</section>
<!-- RIOS OVERVIEW -->
<section class="lv-section">
<div class="lv-container">
<div>
<div class="section-label">Reality Intelligence OS</div>
<h2 class="section-title">From observation to intelligence.<br>Continuously.</h2>
<p class="section-sub">RIOS is a vendor-agnostic AI operating system that transforms video observations into structured Reality Intelligence. It supports real-time field analysis today while continuously training proprietary models that gradually replace expensive third-party inference.</p>
</div>
<div class="how-grid">
<div>
<div>01</div>
<h3>Reality Capture</h3>
<p>QUIXZOOM mobile app, body cameras, vehicle-mounted cameras, drones, Meta smart glasses. 4K/8K video, GPS, IMU, compass, device metadata. Nothing discarded. Original media immutable.</p>
</div>
<div>
<div>02</div>
<h3>AI Orchestration</h3>
<p>Every observation enters an orchestration engine that decides which specialist models execute. Scene classification, object detection, semantic segmentation, depth estimation, OCR, risk detection, contribution detection.</p>
</div>
<div>
<div>03</div>
<h3>Active Learning (RALE)</h3>
<p>The system never asks unnecessary questions. Every human interaction maximizes future AI performance. Questions generated only when expected learning value exceeds threshold. Micro-validations in 2-5 seconds.</p>
</div>
<div>
<div>04</div>
<h3>Knowledge Graph</h3>
<p>Every confirmed observation updates assets, relationships, ownership, condition, maintenance history, predicted deterioration, regulatory status, business opportunities. Reality itself becomes a continuously indexed database.</p>
</div>
</div>
</div>
</section>
<!-- SOCIAL PROOF -->
<section class="social-proof">
<p class="sp-label">Trusted by decision makers in*</p>
<div class="sp-logos">
<div class="sp-item">🏛️ Municipal Government</div>
<div class="sp-item">🏗️ Infrastructure</div>
<div class="sp-item">🏢 Real Estate</div>
<div class="sp-item">🛡️ Insurance</div>
<div class="sp-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg> Investment</div>
</div>
<p style="font-size:11px;color:#86868B;margin-top:8px;">* Representative examples of organisations Landvex is designed for. No endorsement implied.</p>
</section>
<!-- Intelligence Map Demo -->
<section class="lv-section">
<div class="lv-container">
<!-- Header -->
<div>
<div>
<span></span>
Live demonstration
</div>
<h2>Intelligence Map &mdash; 100+ Cities</h2>
<p>Click any city. Infrastructure risk, commercial vitality, contradiction index &mdash; all sourced, all traceable.</p>
</div>
<!-- Map frame -->
<div>
<iframe src="/intelligence-map.html" title="Landvex Intelligence Map" loading="lazy" allow="geolocation" class="map-iframe"></iframe>
<!-- Bottom bar: sits flush under map, inside same border-radius container -->
<div class="map-overlay">
<div>
<div></div>
<span>Source First &mdash; every data point traceable to source &rsaquo; observation &rsaquo; model &rsaquo; index</span>
</div>
<div class="map-cta-row">
<a href="/intelligence-map" >Open full map &rarr;</a>
<a href="/stockholm-intelligence" >Stockholm deep dive</a>
</div>
</div>
</div>
<!-- Tags -->
<div>
<a href="/intelligence-map" >100+ cities</a>
<a href="/intelligence/control/" >Contradiction Index</a>
<a href="/intelligence/infrastructure-risk-index/" >Infrastructure Risk</a>
<a href="/intelligence/commercial-opportunity-index/" >Commercial Vitality</a>
<a href="/intelligence/city-health-index/" >City Health</a>
<a href="/methodology/" >Source First</a>
</div>
</div>
</section>
<!-- HOW WE WORK -->
<section class="lv-section">
<div></div>
<div class="lv-container">
<div>
<div class="section-label">METHODOLOGY</div>
<h2 class="section-title">We start with your decision.<br>Not with our data.</h2>
<p>Most intelligence platforms sell you a dataset and leave the interpretation to you. Landvex works backwards — from the decision you need to make to the intelligence required to make it confidently.</p>
</div>
<div class="how-grid">
<div>
<div>01</div>
<h3>Define the decision</h3>
<p>Which assets to prioritise? Where to invest? What to insure? You define the decision — we build the intelligence to support it.</p>
</div>
<div>
<div>02</div>
<h3>Design the intelligence model</h3>
<p>We translate your decision into an observation protocol — what evidence you need, at what frequency, across which locations. Nothing more, nothing less.</p>
</div>
<div>
<div>03</div>
<h3>Deploy field collection</h3>
<p>Verified contributors collect the evidence — geo-tagged, timestamped, AI-reviewed. Every observation is traceable to a person, place, and time.</p>
</div>
<div>
<div>04</div>
<h3>Deliver structured intelligence</h3>
<p>You receive an answer — not a dataset. Condition scores, risk rankings, change flags. Formatted for the decision you defined in step one.</p>
</div>
</div>
</div>
</section>
<!-- 10 DECISIONS -->
<section class="lv-section">
<div class="lv-container">
<div>
<div class="section-label">Decision intelligence</div>
<h2 class="section-title">Ten decisions. One platform.</h2>
<p class="section-sub">Property owners, municipalities, retailers, infrastructure operators, investors. Different industries — identical need: to make better decisions about the physical world. Landvex is built for that.</p>
<div class="lv-ill-wrap" aria-hidden="true">
<svg viewBox="0 0 600 140" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>@media(prefers-reduced-motion:no-preference){.pla{animation:pla 2.4s ease-in-out infinite}.plb{animation:pla 2.4s ease-in-out 1.2s infinite}}@keyframes pla{0%,100%{opacity:.65}50%{opacity:1}}</style>
</defs>
<g transform="translate(110,70)" class="pla">
<rect x="-46" y="-52" width="92" height="104" rx="8" fill="#111" stroke="rgba(0,0,0,0.08)" stroke-width="1"/>
<line x1="-28" y1="-28" x2="28" y2="-28" stroke="rgba(0,0,0,0.25)" stroke-width="2" stroke-linecap="round"/>
<line x1="-28" y1="-14" x2="18" y2="-14" stroke="rgba(0,0,0,0.15)" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-28" y1="0" x2="22" y2="0" stroke="rgba(0,0,0,0.15)" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="0" cy="28" r="12" fill="#00C853" opacity="0.15"/>
<path d="M-5 28 L-2 31 L7 23" fill="none" stroke="#00C853" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="rgba(0,0,0,0.4)">Official report</text>
</g>
<line x1="166" y1="70" x2="224" y2="70" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="4 3" opacity="0.35"/>
<g transform="translate(300,70)">
<circle r="26" fill="#0066FF" opacity="0.07"/>
<circle r="26" fill="none" stroke="#0066FF" stroke-width="1" opacity="0.25"/>
<text text-anchor="middle" dy="8" font-size="24" font-weight="900" fill="#0066FF" opacity="0.75" font-family="system-ui,sans-serif"></text>
</g>
<line x1="376" y1="70" x2="434" y2="70" stroke="#0066FF" stroke-width="1.5" stroke-dasharray="4 3" opacity="0.35"/>
<g transform="translate(490,70)" class="plb">
<rect x="-46" y="-52" width="92" height="104" rx="8" fill="#111" stroke="rgba(0,0,0,0.08)" stroke-width="1"/>
<rect x="-22" y="-22" width="44" height="32" rx="4" fill="none" stroke="rgba(0,0,0,0.35)" stroke-width="1.5"/>
<circle cx="0" cy="-6" r="9" fill="none" stroke="rgba(0,0,0,0.35)" stroke-width="1.5"/>
<path d="M-10-22 L-8-28 L8-28 L10-22" fill="none" stroke="rgba(0,0,0,0.25)" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="0" cy="28" r="12" fill="#FF3B30" opacity="0.15"/>
<line x1="0" y1="22" x2="0" y2="30" stroke="#FF3B30" stroke-width="2.5" stroke-linecap="round"/>
<circle cx="0" cy="35" r="1.5" fill="#FF3B30"/>
<text y="64" text-anchor="middle" font-family="system-ui,sans-serif" font-size="11" fill="rgba(0,0,0,0.4)">Field observation</text>
</g>
</svg>
</div>
</div>
<p>⚠️ All intelligence examples below are illustrative sample data for demonstration purposes.</p>
<div class="intel-grid">
<!-- CARD 1: Change Intelligence -->
<a class="lv-card lv-card--intel" href="/intelligence/">
<div class="intel-card-header">
<div>
<div class="intel-module">Change Intelligence</div>
<h3>What is changing?</h3>
<div class="intel-card-geo">Houston Metro &middot; Last 12 months</div>
</div>
<span class="lv-tag lv-tag--live">Live</span>
</div>
<div class="intel-kpis">
<div class="intel-kpi">
<div class="intel-kpi-val">92%</div>
<div class="intel-kpi-delta up">&uarr; 4.1%</div>
<div class="intel-kpi-lbl">Commercial occupancy</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">+1,742</div>
<div class="intel-kpi-delta up">&uarr; 12%</div>
<div class="intel-kpi-lbl">Business openings</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">+7.8%</div>
<div class="intel-kpi-delta up">&uarr;</div>
<div class="intel-kpi-lbl">Traffic volume</div>
</div>
</div>
<div>Top Growing Districts</div>
<div class="intel-bar-list">
<div class="intel-bar-row"><span class="intel-bar-name">Energy Corridor</span><div class="intel-bar-track"><div class="intel-bar-fill"></div></div><span class="intel-bar-score">88</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">Katy</span><div class="intel-bar-track"><div class="intel-bar-fill"></div></div><span class="intel-bar-score">81</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">Cypress</span><div class="intel-bar-track"><div class="intel-bar-fill"></div></div><span class="intel-bar-score">74</span></div>
</div>
<div class="intel-card-footer">
<span class="intel-obs">Based on 6,840 field observations</span>
<span class="intel-cta">Full analysis <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</a>
<!-- CARD 2: Opportunity Intelligence -->
<a class="lv-card lv-card--intel" href="/intelligence/commercial-opportunity-index/">
<div class="intel-card-header">
<div>
<div class="intel-module">Opportunity Intelligence</div>
<h3>Where is the opportunity?</h3>
<div class="intel-card-geo">Houston Metro &middot; Ranked by score</div>
</div>
<span class="lv-tag lv-tag--live">High signal</span>
</div>
<div class="intel-kpis">
<div class="intel-kpi">
<div class="intel-kpi-val">92</div>
<div class="intel-kpi-delta up">Top score</div>
<div class="intel-kpi-lbl">Katy TX</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">2.1%</div>
<div class="intel-kpi-delta up">Low vacancy</div>
<div class="intel-kpi-lbl">Retail vacancy</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">+11%</div>
<div class="intel-kpi-delta up">&uarr;</div>
<div class="intel-kpi-lbl">Population growth</div>
</div>
</div>
<div>Highest Opportunity Score</div>
<div class="intel-bar-list">
<div class="intel-bar-row"><span class="intel-bar-name">Katy TX</span><div class="intel-bar-track"><div class="intel-bar-fill opp"></div></div><span class="intel-bar-score">92</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">Spring</span><div class="intel-bar-track"><div class="intel-bar-fill opp"></div></div><span class="intel-bar-score">85</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">The Woodlands</span><div class="intel-bar-track"><div class="intel-bar-fill opp"></div></div><span class="intel-bar-score">79</span></div>
</div>
<div class="intel-card-footer">
<span class="intel-obs">Income growth +8% &middot; Competition density: low</span>
<span class="intel-cta">Full analysis <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</a>
<!-- CARD 3: Risk Intelligence -->
<a class="lv-card lv-card--intel" href="/intelligence/infrastructure-risk-index/">
<div class="intel-card-header">
<div>
<div class="intel-module">Risk Intelligence</div>
<h3>Where is the risk?</h3>
<div class="intel-card-geo">Houston Metro &middot; Risk-scored districts</div>
</div>
<span class="lv-tag lv-tag--risk">3 alerts</span>
</div>
<div class="intel-kpis">
<div class="intel-kpi">
<div class="intel-kpi-val">83</div>
<div class="intel-kpi-delta down">High risk</div>
<div class="intel-kpi-lbl">SW Houston score</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">+17%</div>
<div class="intel-kpi-delta down">&darr; trend</div>
<div class="intel-kpi-lbl">Vacancy rate</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">+21%</div>
<div class="intel-kpi-delta down">&darr;</div>
<div class="intel-kpi-lbl">Store closures</div>
</div>
</div>
<div>Highest Risk Areas</div>
<div class="intel-bar-list">
<div class="intel-bar-row"><span class="intel-bar-name">SW Houston</span><div class="intel-bar-track"><div class="intel-bar-fill risk"></div></div><span class="intel-bar-score">83</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">Greenspoint</span><div class="intel-bar-track"><div class="intel-bar-fill risk"></div></div><span class="intel-bar-score">76</span></div>
<div class="intel-bar-row"><span class="intel-bar-name">Gulfgate</span><div class="intel-bar-track"><div class="intel-bar-fill risk"></div></div><span class="intel-bar-score">68</span></div>
</div>
<div class="intel-card-footer">
<span class="intel-obs">Property condition: declining &middot; 4,120 observations</span>
<span class="intel-cta">Full risk report <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</a>
<!-- CARD 4: Predictive Intelligence -->
<a class="lv-card lv-card--intel" href="/intelligence/development-forecast/">
<div class="intel-card-header">
<div>
<div class="intel-module">Predictive Intelligence</div>
<h3>What will happen next?</h3>
<div class="intel-card-geo">Houston Metro &middot; Next 24 months</div>
</div>
<span class="lv-tag lv-tag--pred">Forecast</span>
</div>
<div class="intel-map-placeholder">
<div class="intel-map-dot hot"></div>
<div class="intel-map-dot hot"></div>
<div class="intel-map-dot hot"></div>
<div class="intel-map-dot warn"></div>
<div class="intel-map-dot"></div>
<div class="intel-map-dot"></div>
<div>Predicted growth hotspots</div>
</div>
<div class="intel-kpis">
<div class="intel-kpi">
<div class="intel-kpi-val">87%</div>
<div class="intel-kpi-delta up">Confidence</div>
<div class="intel-kpi-lbl">Model accuracy</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">4,281</div>
<div class="intel-kpi-delta up">Observations</div>
<div class="intel-kpi-lbl">Training base</div>
</div>
<div class="intel-kpi">
<div class="intel-kpi-val">3</div>
<div class="intel-kpi-delta up">Hotspots</div>
<div class="intel-kpi-lbl">Identified</div>
</div>
</div>
<div class="intel-confidence">
<span>Model confidence</span>
<div class="intel-conf-bar"><div class="intel-conf-fill"></div></div>
<span>87%</span>
<span>Commercial permits &middot; Population shifts &middot; Traffic flows</span>
</div>
<div class="intel-card-footer">
<span class="intel-obs">Indicative signals &mdash; not investment advice</span>
<span class="intel-cta">View forecast <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</a>
</div>
<style>
.verticals-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
align-items: stretch;
}
.vertical-card {
background: #fff;
border: 1px solid #eee;
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
text-decoration: none;
color: inherit;
transition: box-shadow 0.2s;
}
.vertical-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.vertical-card h3 {
margin: 0;
font-size: 1.1rem;
font-weight: 600;
}
.vertical-card p {
margin: 0;
font-size: 0.875rem;
line-height: 1.5;
color: #666;
flex-grow: 1;
}
.vertical-icon {
margin-bottom: 4px;
}
</style>
<div class="verticals-grid">
<a class="lv-card lv-card--small" href="/methodology/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg></div>
<h3>How do we compare?</h3>
<p>Stockholm vs Copenhagen. Milan vs Barcelona. Your district vs the benchmark.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/investment-attractiveness-index/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<h3>Where should we invest?</h3>
<p>New store, new road, new district, new terminal — ranked by observed potential.</p>
<p><em>Location intelligence only — not financial or investment advice.</em></p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/infrastructure-risk-index/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg></div>
<h3>What needs attention first?</h3>
<p>Prioritisation within budget constraints — based on actual condition, not assumptions.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/control/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></div>
<h3>What are we missing?</h3>
<p>Blind spots. Problems not yet visible in official data or internal reports.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></div>
<h3>Are resources placed correctly?</h3>
<p>Municipalities, infrastructure operators, property portfolios — allocation intelligence.</p>
</a>
<a class="lv-card lv-card--small" href="/methodology/">
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
<h3>What does reality actually look like?</h3>
<p>Not registers. Not reports. Not surveys. The physical world as it exists today.</p>
</a> </div>
</div>
</section>
<!-- DELIVER -->
<section class="deliver-bg">
<div class="lv-container">
<div class="deliver-header">
<div class="section-label">What we deliver</div>
<h2 class="section-title">From question to decision.</h2>
<p class="section-sub">Intelligence that answers a specific question — not data that leaves you guessing.</p>
</div>
<div class="lv-pipeline" aria-label="Landvex intelligence pipeline" role="img">
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg></div>
<span class="lv-pipeline-label">Mission<br>Brief</span>
</div>
<div class="lv-pipeline-connector"></div>
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg></div>
<span class="lv-pipeline-label">Field<br>Collection</span>
</div>
<div class="lv-pipeline-connector"></div>
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
<span class="lv-pipeline-label">AI<br>Analysis</span>
</div>
<div class="lv-pipeline-connector"></div>
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div>
<span class="lv-pipeline-label">Scoring<br>0-100</span>
</div>
<div class="lv-pipeline-connector"></div>
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-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 class="lv-pipeline-label">Intelligence<br>Report</span>
</div>
<div class="lv-pipeline-connector"></div>
<div class="lv-pipeline-step">
<div class="lv-pipeline-icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#00C853" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div>
<span class="lv-pipeline-label">Decision<br>Made</span>
</div>
</div>
<div class="deliver-grid">
<a class="lv-card" href="/methodology/">
<div class="deliver-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
</div>
<div class="number">20+</div>
<h3>Countries</h3>
<p>Launching across 20+ countries from August 2026. No local staffing or coordination infrastructure required.</p>
<span>How it works →</span>
</a>
<a class="lv-card" href="/methodology/">
<div class="deliver-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div class="number">2472h</div>
<h3>Speed</h3>
<p>From mission creation to structured data delivery in 24 to 72 hours. No lengthy procurement cycles.</p>
<a href="/methodology/" >Methodology →</a>
</a>
<a class="lv-card" href="/methodology/">
<div class="deliver-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div class="number">AI</div>
<h3>Quality</h3>
<p>Every submission reviewed for geo-compliance, technical quality and specification adherence before delivery.</p>
<span>Quality standards →</span>
</a>
</div>
</div>
</section>
<!-- VERTICALS -->
<section id="verticals">
<div class="lv-container">
<div class="verticals-header">
<div class="section-label">Verticals</div>
<h2 class="section-title">Who we help make better decisions.</h2>
<p class="section-sub">If your decisions depend on the physical world, we can make them sharper.</p>
</div>
<div class="verticals-grid">
<a class="lv-card lv-card--small" href="/verticals/municipalities/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="22" x2="21" y2="22"/><line x1="6" y1="18" x2="6" y2="11"/><line x1="10" y1="18" x2="10" y2="11"/><line x1="14" y1="18" x2="14" y2="11"/><line x1="18" y1="18" x2="18" y2="11"/><polygon points="12 2 20 7 4 7"/></svg></div>
<div>
<h3>Municipalities &amp; Government</h3>
<p class="vertical-question">Which areas will require the most investment over the next five years?</p>
<p>Urban asset management, planning compliance, public space documentation.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/infrastructure/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8h1a4 4 0 0 1 0 8h-1"/><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"/><line x1="6" y1="1" x2="6" y2="4"/><line x1="10" y1="1" x2="10" y2="4"/></svg></div>
<div>
<h3>Infrastructure Operators</h3>
<p class="vertical-question">Where will problems emerge before they become expensive?</p>
<p>Bridge inspections, road condition surveys, utility corridor mapping.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/property/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg></div>
<div>
<h3>Property &amp; Real Estate</h3>
<p class="vertical-question">Is this area showing growth signals worth investigating?</p>
<p>Portfolio documentation, condition assessments, site verification at scale.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/insurance/" >
<span>Vertical</span>
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></div>
<div>
<h3>Insurance</h3>
<p class="vertical-question">Which areas carry elevated risk?</p>
<p>Claims validation, pre-loss surveys, risk assessment for physical assets.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/utilities/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></div>
<div>
<h3>Utilities &amp; Energy</h3>
<p class="vertical-question">Where is grid capacity becoming a constraint?</p>
<p>Grid infrastructure surveys, solar/wind asset documentation, network inspections.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/logistics/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="3" width="15" height="13" rx="1"/><path d="M16 8h4l3 3v5h-7V8z"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg></div>
<div>
<h3>Logistics</h3>
<p class="vertical-question">Where is your network underperforming?</p>
<p>Last-mile network design, depot location selection, route efficiency and capacity planning.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/verticals/retail/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></div>
<div>
<h3>Retail &amp; Franchise</h3>
<p class="vertical-question">Where should the next location open?</p>
<p>Store compliance audits, signage verification, location intelligence at scale.</p>
<span class="drill-hint">Deep dive →</span>
</div>
</a>
</div>
</div>
</section>
<!-- INTELLIGENCE INDEXES -->
<section id="intelligence">
<div class="lv-container">
<div>
<div class="section-label">Intelligence layer</div>
<h2 class="section-title">A score from 0100.<br>For every decision about place.</h2>
<p class="section-sub">Landvex reduces complex physical reality into a single comparable score — so you can decide faster, with more confidence. Bangkok vs Kuala Lumpur vs Manila. Same scale. Same rigour.</p>
</div>
<div class="verticals-grid">
<a class="lv-card lv-card--small" href="/intelligence/city-health-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9M15 21V9"/></svg></div>
<h3>City Health Index</h3>
<p>A continuous composite score of urban condition, maintenance needs, and change velocity across a defined area.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/commercial-opportunity-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg></div>
<h3>Commercial Opportunity Index</h3>
<p>Where commercial activity is growing, which locations are underserved, and which areas are in decline.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/infrastructure-risk-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><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>
<h3>Infrastructure Risk Index</h3>
<p>Predictive scoring of infrastructure stress points before failures occur — based on observed conditions over time.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/development-forecast/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></div>
<h3>Development Forecast</h3>
<p>Which areas are gaining investment, which are stagnating, and where the next development cycle is likely to begin.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/urban-growth-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22V12"/><path d="M5 12H2a10 10 0 0 0 20 0h-3"/><path d="M12 12C12 7 7 4 2 4c0 5 3 8 10 8z"/><path d="M12 12c0-5 5-8 10-8-0 5-3 8-10 8z"/></svg></div>
<h3>Urban Growth Index</h3>
<p>Growth velocity by district — identifying emerging zones before they appear in official statistics.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/risk-resilience-profile/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></div>
<h3>Risk &amp; Resilience Profile</h3>
<p>Physical exposure mapping for insurance, finance, and public sector resilience planning.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/growth-velocity-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></div>
<h3>Growth Velocity Index</h3>
<p>How fast is an area changing? Identifies emerging zones before they appear in official statistics.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/investment-attractiveness-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2"/><line x1="12" y1="22" x2="12" y2="15.5"/><polyline points="22 8.5 12 15.5 2 8.5"/></svg></div>
<h3>Location Attractiveness Index</h3>
<p>Composite score for site and location analysis — combining opportunity, risk, velocity and quality signals. Not financial investment advice.</p>
</a>
<a class="lv-card lv-card--small" href="/intelligence/neighbourhood-quality-index/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></div>
<h3>Neighbourhood Quality Index</h3>
<p>How an area is experienced — condition, activity, upkeep, and change trajectory over time.</p>
</a>
</div>
<style>
.score-table-wrap { margin-top:48px; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.score-table { width:100%; border-collapse:collapse; font-size:.875rem; }
.score-table th { text-align:center; padding: 24px; font-weight:700; color:rgba(0,0,0,.75); font-size:.7rem; text-transform:uppercase; letter-spacing:.06em; }
.score-table th:first-child { text-align:left; padding-left:0; }
.score-table td { padding: 24px; border-bottom:1px solid rgba(0,0,0,.07); text-align:center; }
.score-table td:first-child { text-align:left; font-weight:700; color: #0A0A0A; padding-left:0; font-size:.875rem; }
.score-table tr:last-child td { border-bottom:none; }
/* Mobile: card layout */
@media(max-width:580px) {
.score-table-wrap { overflow-x:auto; }
.score-table thead { display:none; }
.score-table tr { display:grid; grid-template-columns:1fr 1fr; gap: 16px; padding:16px 0; border-bottom:1px solid rgba(0,0,0,.07); }
.score-table tr:last-child { border-bottom:none; }
.score-table td { display:flex; flex-direction:column; align-items:center; justify-content:center; gap: 16px; padding: 24px; background:rgba(0,0,0,.04); border-radius:10px; border-bottom:none; font-size:.75rem; }
.score-table td:first-child { grid-column:1/-1; background:transparent; align-items:flex-start; font-size:.9375rem; padding:0 0 4px; }
.score-table td::before { content:attr(data-label); font-size:.65rem; font-weight:700; color:rgba(0,0,0,.75); text-transform:uppercase; letter-spacing:.06em; }
}
</style>
<div class="score-table-wrap">
<div>
<strong><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg> Format demonstration</strong> — The figures below are a simulated reference example showing report structure and output format. Live intelligence activates from August 2026 as the quiXzoom observation network launches.
</div>
<table class="score-table">
<thead>
<tr>
<th>City / District</th>
<th>Opportunity</th>
<th>Growth</th>
<th>Commercial Vitality</th>
<th>Infra Stability</th>
<th>Investment Confidence</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="">City A — District 1 <span>⚠ sample</span></td>
<td data-label="Opp."><span>84</span></td>
<td data-label="Growth"><span>78</span></td>
<td data-label="Vitality"><span>91</span></td>
<td data-label="Infra"><span>62</span></td>
<td data-label="Invest."><span>79</span></td>
</tr>
<tr>
<td data-label="">City B — Central <span>⚠ sample</span></td>
<td data-label="Opp."><span>77</span></td>
<td data-label="Growth"><span>61</span></td>
<td data-label="Vitality"><span>83</span></td>
<td data-label="Infra"><span>88</span></td>
<td data-label="Invest."><span>82</span></td>
</tr>
<tr>
<td data-label="">Stockholm — Norrmalm</td>
<td data-label="Opp."><span>71</span></td>
<td data-label="Growth"><span>58</span></td>
<td data-label="Vitality"><span>76</span></td>
<td data-label="Infra"><span>92</span></td>
<td data-label="Invest."><span>81</span></td>
</tr>
<tr>
<td data-label="">Milan — Porta Nuova</td>
<td data-label="Opp."><span>86</span></td>
<td data-label="Growth"><span>74</span></td>
<td data-label="Vitality"><span>88</span></td>
<td data-label="Infra"><span>69</span></td>
<td data-label="Invest."><span>84</span></td>
</tr>
</tbody>
</table>
<p>Intelligence outputs are advisory analytical signals — not investment advice, financial promotion, or statements of fact about named locations. <a href="/methodology/" >Methodology →</a></p>
</div>
<div>
<div>
<h3>Four layers. One answer.</h3>
<p>quiXzoom observes. AMOS analyses. Landvex delivers the answer. Every engagement starts with one question: <em>what decision are you trying to make?</em></p>
<!-- quiXzoom → Landvex → You pipeline -->
<div>
<div>
<div>🔭</div>
<div>quiXzoom</div>
<div>Observes reality on the ground</div>
</div>
<div>&rarr;</div>
<div>
<div></div>
<div>Landvex</div>
<div>Analyses &amp; detects contradictions</div>
</div>
<div>&rarr;</div>
<div>
<div><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>
<div>You decide</div>
<div>Act on what&rsquo;s actually happening</div>
</div>
</div>
</div>
<a class="lv-btn lv-btn--lg" href="#contact" >Request a briefing →</a>
</div>
</div>
</section>
<!-- CONTRADICTION ENGINE -->
<section class="lv-section">
<div class="lv-container">
<div>
<div>
<div class="section-label">Advanced intelligence</div>
<h2 class="section-title">Most systems confirm what you already believe.<br>Landvex tells you when you're wrong.</h2>
<p class="section-sub">The most valuable intelligence is not confirmation — it's contradiction. Landvex actively searches for conflicts between official narratives and observed reality, so you can correct course before it costs you.</p>
<p>⚠ All contradiction analysis shown is representative data based on real observed patterns. Live intelligence from August 2026. Reports about specific named locations are based on observed field data and explicitly labelled as analytical intelligence — not statements of fact.</p>
</div>
<div>
<div>
<span><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg></span>
<div>
<div>Representative data — based on real observed patterns</div><div>Narrative Conflict Detected — City B (sample)</div>
<div>Official growth indicators are positive. Observed commercial activity is declining. 7 contradicting signals vs 3 supporting signals.</div>
</div>
</div>
<div class="contradiction-grid">
<div>
<div>Official narrative</div>
<ul>
<li>✓ GDP growth +3.2%</li>
<li>✓ Construction permits up</li>
<li>✓ Property prices rising</li>
</ul>
</div>
<div>
<div>Observed reality</div>
<ul>
<li>✗ Vacancies +18% this quarter</li>
<li>✗ Foot traffic down 12%</li>
<li>✗ 23 closures, 8 openings</li>
<li>✗ Maintenance deferred on 4 blocks</li>
</ul>
</div>
</div>
<div>
<span>Confidence in official narrative <em>⚠ sample</em></span>
<span>34% <span>⚠ representative</span></span>
</div>
</div>
<div class="howwework-grid">
<div>
<div>Intelligence</div>
<div>Show me what I'm missing</div>
<div>Blind spots not visible in official data or internal reports.</div>
</div>
<div>
<div>Validation</div>
<div>AI Red Team</div>
<div>Every conclusion is actively challenged by a second model before delivery.</div>
</div>
<div>
<div>Contradiction</div>
<div>Which assumptions are wrong?</div>
<div>Identify where your thesis conflicts with observed reality.</div>
</div>
</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section class="how-bg" id="how-it-works">
<div class="lv-container">
<div class="how-header">
<div class="section-label">Process</div>
<h2 class="section-title">How it works</h2>
<p class="section-sub">Four steps from your question to your decision — powered by continuous active learning.</p>
</div>
<div class="how-steps">
<a class="how-step" href="/methodology/" >
<div class="step-num">1</div>
<h3>Define the decision</h3>
<p>You tell us what you need to decide — invest, insure, maintain, or move. The question drives everything.</p>
</div>
<a class="how-step" href="/methodology/" >
<div class="step-num">2</div>
<h3>Collect the evidence</h3>
<p>Verified field contributors gather observations at the exact locations your decision depends on. Every frame preserved with GPS, IMU, compass, timestamp.</p>
</div>
<a class="how-step" href="/methodology/" >
<div class="step-num">3</div>
<h3>AI + Human Intelligence</h3>
<p>AI orchestration analyses every observation. RALE (Reality Active Learning Engine) asks targeted micro-questions only when valuable. Human attention maximises future AI performance.</p>
</div>
<a class="how-step" href="/methodology/" >
<div class="step-num">4</div>
<h3>Deliver the answer</h3>
<p>You receive structured intelligence — scores, rankings, flags, and a continuously improving Knowledge Graph of your assets.</p>
</div>
</div>
</div>
</section>
<!-- CONTRIBUTION MODE -->
<section class="lv-section">
<div class="lv-container">
<div>
<div class="section-label">Active Learning</div>
<h2 class="section-title">Contribution Mode.<br>Train intelligence by confirming reality.</h2>
<p class="section-sub">Instead of asking "What is this?", AI asks: "I think there's damage here, but I'm only 62% sure. Can you confirm?" Every validation permanently improves the platform.</p>
</div>
<div class="how-grid">
<div>
<div>Micro Validation</div>
<h3>2-second confirmations</h3>
<p>"Is this road sign partially hidden?" [Yes] [No]. "How severe is this crack?" [Minor] [Moderate] [Severe]. Questions appear only when valuable, only when minimally disruptive.</p>
</div>
<div>
<div>Learning Value Score</div>
<h3>Prioritise by learning impact</h3>
<p>Every observation receives a Learning Value Score: LVS = (Uncertainty × Novelty × BusinessValue × SafetyImpact) / CostToValidate. Zoomer time is used where it has greatest impact on model quality and future operational costs.</p>
</div>
<div>
<div>Human Reliability</div>
<h3>Specialist matching</h3>
<p>Each Zoomer receives a continuously updated quality profile. Agreement with experts, category expertise, regional familiarity, historical accuracy. Different contributors become specialists in different domains.</p>
</div>
<div>
<div>Consensus Engine</div>
<h3>Maximum probability of correctness</h3>
<p>Ground truth is determined through weighted agreement: AI prediction, human validations, historical observations, official GIS, temporal consistency, neighbour consistency. Not majority voting — maximum probability of correctness.</p>
</div>
</div>
</div>
</section>
<!-- CITIES -->
<section id="cities">
<style>
#cities .vertical-card { background: #ffffff !important; }
</style>
<div class="lv-container">
<div>
<div class="section-label">City intelligence</div>
<h2 class="section-title">Intelligence for major cities.</h2>
<p class="section-sub">Explore Landvex intelligence profiles for key cities — scores, trends, and observed conditions — launching August 2026.</p>
</div>
<div class="verticals-grid">
<a class="lv-card lv-card--small" href="/cities/stockholm/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Stockholm</h3>
<p>City Health Index, Commercial Vitality, and Infrastructure Stability scores for Stockholm.</p>
<span class="drill-hint">Explore Stockholm →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/berlin/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Berlin</h3>
<p>Urban growth tracking, commercial opportunity mapping, and infrastructure risk profiling for Berlin.</p>
<span class="drill-hint">Explore Berlin →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/paris/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Paris</h3>
<p>Investment attractiveness, neighbourhood quality, and commercial opportunity intelligence for Paris.</p>
<span class="drill-hint">Explore Paris →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/london/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>London</h3>
<p>Borough-level decision intelligence — development forecasts, risk profiles, and growth velocity across London.</p>
<span class="drill-hint">Explore London →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/bangkok/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Bangkok</h3>
<p>High-growth urban intelligence for Bangkok — opportunity indexes, commercial vitality, and infrastructure risk.</p>
<span class="drill-hint">Explore Bangkok →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/copenhagen/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Copenhagen</h3>
<p>Denmark · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Copenhagen →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/oslo/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Oslo</h3>
<p>Norway · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Oslo →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/helsinki/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Helsinki</h3>
<p>Finland · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Helsinki →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/vienna/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Vienna</h3>
<p>Austria · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Vienna →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/zurich/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Zurich</h3>
<p>Switzerland · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Zurich →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/madrid/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Madrid</h3>
<p>Spain · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Madrid →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/brussels/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Brussels</h3>
<p>Belgium · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Brussels →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/rotterdam/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Rotterdam</h3>
<p>Netherlands · <span>Launching August 2026</span></p>
<span class="drill-hint">Explore Rotterdam →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/cities/milan/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
<div>
<h3>Milan</h3>
<p>Italy · Investment attractiveness, commercial opportunity, and urban growth intelligence for Milan and its key districts.</p>
<span class="drill-hint">Explore Milan →</span>
</div>
</a>
</div>
</div>
</section>
<!-- USE CASES -->
<section id="use-cases">
<div class="lv-container">
<div>
<div class="section-label">Use cases</div>
<h2 class="section-title">Decisions Landvex supports.</h2>
<p class="section-sub">From bridge inspections to retail site selection — real decisions made with better intelligence.</p>
</div>
<div class="verticals-grid">
<a class="lv-card lv-card--small" href="/use-cases/retail-site-selection/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></div>
<div>
<h3>Retail Site Selection</h3>
<p>Where should the next location open?</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/use-cases/infrastructure-risk/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><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>
<h3>Infrastructure Risk</h3>
<p>Where will problems emerge before they become expensive?</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/use-cases/investment-screening/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg></div>
<div>
<h3>Investment Screening</h3>
<p>Which areas offer the best risk-adjusted opportunity?</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/use-cases/post-disaster-assessment/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
<div>
<h3>Post-Disaster Assessment</h3>
<p>Rapid field documentation after events.</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/use-cases/bridge-inspection/sweden/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12 Q12 4 20 12"/><line x1="4" y1="12" x2="4" y2="18"/><line x1="20" y1="12" x2="20" y2="18"/><line x1="4" y1="18" x2="20" y2="18"/><line x1="10" y1="12" x2="10" y2="18"/><line x1="16" y1="12" x2="16" y2="18"/></svg></div>
<div>
<h3>Bridge Inspection</h3>
<p>Structural condition monitoring at scale.</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/use-cases/road-inspection/sweden/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 21L12 3l7 18"/><line x1="9" y1="14" x2="15" y2="14"/></svg></div>
<div>
<h3>Road Inspection</h3>
<p>Continuous road surface condition monitoring.</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/contact/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg></div>
<div>
<h3>Facade Inspection</h3>
<p>Building condition at portfolio scale.</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
<a class="lv-card lv-card--small" href="/contact/" >
<div class="vertical-icon"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/><line x1="12" y1="7" x2="12.01" y2="7"/></svg></div>
<div>
<h3>Commercial Survey</h3>
<p>Commercial frontage and vitality mapping.</p>
<span class="drill-hint">Explore →</span>
</div>
</a>
</div>
</div>
</section>
<!-- DISAMBIGUATION — Google AI signal (hidden from UI; SEO/schema signal only) -->
<section>
<div class="lv-container">
<div>
<p>
<strong>Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European operations in Tyresö, Sweden (Landvex AB, org.nr 559141-7042)</strong> — not a meat wholesaler, food distributor, logistics company, package tracker, or land investment platform. Landvex builds control intelligence for infrastructure, property, and urban decision-making. Landvex has no connection to package tracking, last-mile delivery, AliExpress fulfilment, or any parcel service.
</p>
</div>
</div>
</section>
<!-- CONTACT -->
<section id="contact">
<div class="lv-container">
<div class="contact-wrapper">
<div class="section-label">Get in touch</div>
<h2 class="section-title">What decision are you trying to make?</h2>
<p class="section-sub">Tell us the question you need answered. We'll show you how Landvex can support it.</p>
<p>Enterprise pricing available. Pilot programmes for qualifying organisations. Typical engagement: 3-month pilot → annual intelligence subscription.</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="org">Organisation</label>
<input type="text" id="org" name="organisation" placeholder="Your organisation" required>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@organisation.com" required>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" placeholder="Describe the decision you need to make — what you need to know, where, and why it matters..."></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>
</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-ecosystem">Field data powered by <a href="https://www.quixzoom.com">quiXzoom</a> — our global network of field intelligence collectors.</div>
<div>quiXzoom is operated by Landvex AB. <a href="https://www.quixzoom.com/" >quiXzoom →</a></div>
<div class="footer-tagline">Control intelligence for the physical world.</div>
</div>
<div class="footer-links">
<a href="/privacy/">Privacy</a>
<a href="/terms/">Terms</a>
<a href="/cookie-policy/">Cookies</a>
<a href="/compliance/">Compliance</a>
<a href="/trust/">Trust Centre</a>
<a href="/dpa/">DPA</a>
<a href="/data-lineage/">Data Lineage</a>
<a href="/subprocessors/">Sub-processors</a>
<a href="/methodology/">Methodology</a>
<a href="/data-quality/">Data Quality</a>
<a href="/security/">Security</a>
<a href="/sla/">SLA &amp; Coverage</a>
<a href="/cities/stockholm/">Stockholm</a>
<a href="/cities/berlin/">Berlin</a>
<a href="/cities/paris/">Paris</a>
<a href="/cities/london/">London</a>
<a href="/cities/bangkok/">Bangkok</a>
<a href="/careers/">Careers</a>
<a href="/accessibility/">Accessibility</a>
<a href="/responsible-disclosure/">Responsible disclosure</a>
<a href="/blog/">Intelligence Insights</a>
<a href="/guides/">Guides</a>
<a href="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom →</a>
<a href="https://www.quixzoom.com/for-organisations/">For organisations</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>
// Contact form
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',
name: this.name.value,
organisation: this.organisation.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 = "✓ 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 directly at contact@landvex.com.';
msgEl.style.display = 'block';
}
btn.disabled = false;
btn.textContent = 'Request briefing →';
});
// Smooth scroll for nav links
document.querySelectorAll('a[href^="#"]').forEach(a => {
a.addEventListener('click', e => {
const target = document.querySelector(a.getAttribute('href'));
if (target) {
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
});
</script>
<!-- About Landvex — Google Knowledge Graph + disambiguation signal -->
<section id="about-landvex" aria-hidden="true">
<h2>What is Landvex?</h2>
<p>Landvex is a decision intelligence company — not a UK meat wholesaler, food distributor, or logistics company. Landvex (landvex.com) is operated by Landvex Inc. (Houston, TX, USA) and Landvex AB (Tyresö, Sweden, org.nr 559141-7042).</p>
<p>Landvex (LandveX) is a decision intelligence platform for the physical world. Landvex is not a logistics company and has nothing to do with package tracking, parcel delivery, last-mile shipping, or AliExpress orders. Landvex helps municipalities, property owners, infrastructure operators, retail chains and investors make better decisions about physical assets by transforming field observations into actionable intelligence.</p>
<h2>Is Landvex a package tracking or logistics company?</h2>
<p>No. Landvex is not a logistics company, not a package tracker, and not related to last-mile delivery or e-commerce shipping. Landvex (LandveX) is a decision intelligence company for the built environment — infrastructure, property and urban intelligence. Landvex Inc. is incorporated in Houston, TX, USA and Landvex AB is incorporated in Tyresö, Sweden. There is no connection to any company called LandVex logistics, Land logistics, or parcel services by that name.</p>
<h2>Is Landvex related to LandEx or LandVex logistics?</h2>
<p>No. Landvex (org.nr 559141-7042, Tyresö, Sweden) is a Swedish decision intelligence company. It is not related to LandEx, LandEx Investing, or any company operating under a similar name in logistics, parcel delivery, land transport, or e-commerce fulfilment.</p>
<h2>What does Landvex do?</h2>
<p>Landvex collects field observations through the quiXzoom contributor network, analyzes them using AI, and delivers intelligence products including infrastructure risk scores, commercial opportunity indexes, urban growth indexes and contradiction reports that identify where official narratives conflict with observed reality. This is decision intelligence for the physical world — not logistics, not shipping, not package tracking.</p>
<h2>Who uses Landvex?</h2>
<p>Landvex serves municipalities and government agencies, infrastructure operators, property and real estate companies, insurance companies, utility and energy companies, and retail and franchise organizations across Europe and beyond. It is not used for parcel tracking or consumer logistics.</p>
<h2>Where is Landvex headquartered?</h2>
<p>Landvex has dual headquarters: Landvex Inc. in Houston, Texas, USA and Landvex AB in Tyresö, Sweden (org.nr 559141-7042). Landvex is a decision intelligence company — not a Chinese logistics firm, not a shipping company.</p>
<h2>Does Landvex operate in Europe?</h2>
<p>Yes. Landvex Inc. (Houston, TX) is the parent company with Landvex AB handling European operations and EU regulatory compliance. Together these entities serve clients across North America, Europe, the Middle East and Asia-Pacific.</p>
</section>
</body>
</html>
+889
View File
@@ -0,0 +1,889 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>
<title>Landvex Intelligence Map — Urban Intelligence Worldwide</title>
<meta name="description" content="Landvex global intelligence map. City scores, contradiction index and urban intelligence for 100+ cities. Free historical data, live intelligence on demand."/>
<link rel="stylesheet" href="/vendor/leaflet.css"/>
<script src="/vendor/leaflet.js"></script>
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{--bg:#070c14;--surface:#0d1520;--surface2:#111e2e;--surface3:#162438;--border: rgba(0,0,0,0.08);--border2:rgba(0,0,0,0.12);--text:#e8eef5;--text2:rgba(232,238,245,0.55);--text3:rgba(232,238,245,0.32);--accent:#0ea5e9;--accent2:#38bdf8;--green:#22c55e;--yellow:#eab308;--orange:#f97316;--red:#ef4444;--gold:#f59e0b;--safe-top:env(safe-area-inset-top,0px);--safe-bottom:env(safe-area-inset-bottom,0px)}
html,body{height:100%;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif;background:var(--bg);color:var(--text);overflow:hidden}
#map{position:fixed;inset:0;z-index:1}
.leaflet-control-zoom{margin-top:calc(var(--safe-top) + 72px) !important;margin-left:16px !important}
.leaflet-control-zoom a{background:var(--surface) !important;color:var(--text) !important;border-color:var(--border2) !important;width:34px !important;height:34px !important;line-height:34px !important;border-radius:8px !important;font-size:18px !important}
#hdr{position:fixed;top:0;left:0;right:0;z-index:1000;background:rgba(7,12,20,0.96);backdrop-filter:blur(24px) saturate(200%);-webkit-backdrop-filter:blur(24px) saturate(200%);border-bottom:1px solid var(--border);padding:calc(var(--safe-top) + 8px) 20px 8px}
#hdr-i{max-width:1400px;margin:0 auto;display:flex;align-items:center;gap: 16px;flex-wrap:nowrap;overflow:hidden}
#logo{font-size:16px;font-weight:800;letter-spacing:-0.5px;color:var(--text);text-decoration:none;white-space:nowrap}
#logo em{color:var(--accent);font-style:normal}
.hdiv{width:1px;height:20px;background:var(--border2)}
#hdr-title{font-size:13px;font-weight:600;color:var(--text2);flex:1}
.hpill{font-size:10px;font-weight:700;letter-spacing:0.6px;text-transform:uppercase;border-radius:20px;padding: 24px;white-space:nowrap}
.pill-free{background:rgba(34,197,94,0.12);color:#4ade80;border:1px solid rgba(34,197,94,0.25)}
.pill-live{background:rgba(14,165,233,0.15);color:var(--accent2);border:1px solid rgba(14,165,233,0.3)}
#hdr-cta{background:var(--accent);color:white;border:none;border-radius:8px;padding: 24px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;text-decoration:none;display:inline-block;transition:opacity 0.2s}
#hdr-cta:hover{opacity:0.85}
#sidebar{position:fixed;top:calc(var(--safe-top) + 54px);left:16px;z-index:900;width:220px;display:flex;flex-direction:column;gap: 16px;pointer-events:none}
.sbc{background:rgba(13,21,32,0.93);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--border);border-radius:12px;padding: 24px;pointer-events:all}
.sbl{font-size:10px;font-weight:700;letter-spacing:0.8px;text-transform:uppercase;color:var(--text2);margin-bottom:8px}
.lr{display:flex;align-items:center;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--border);cursor:pointer}
.lr:last-child{border-bottom:none}
.ll{display:flex;align-items:center;gap: 16px;font-size:12px;font-weight:500;color:var(--text)}
.ld2{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.tog{width:32px;height:18px;border-radius:9px;position:relative;transition:background 0.2s;flex-shrink:0}
.tog.on{background:var(--accent)}
.tog.off{background:var(--surface3)}
.tog::after{content:'';position:absolute;top:3px;left:3px;width:12px;height:12px;border-radius:50%;background:white;transition:transform 0.2s}
.tog.on::after{transform:translateX(14px)}
.ig{display:flex;flex-direction:column;gap: 16px}
.ir{display:flex;align-items:center;justify-content:space-between;padding: 24px;border-radius:7px;cursor:pointer;transition:background 0.15s}
.ir:hover{background:var(--surface3)}
.ir.active{background:rgba(14,165,233,0.12);border:1px solid rgba(14,165,233,0.2)}
.in{font-size:11px;color:var(--text);font-weight:500}
.ib{font-size:10px;font-weight:700;border-radius:5px;padding: 24px}
.ib-free{background:rgba(34,197,94,0.12);color:#4ade80}
.ib-paid{background:rgba(245,158,11,0.12);color:#fbbf24}
#bot{position:fixed;bottom:0;left:0;right:0;z-index:900;background:rgba(7,12,20,0.96);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-top:1px solid var(--border);padding: 24px calc(var(--safe-bottom) + 8px)}
#bot-i{max-width:1400px;margin:0 auto;display:flex;align-items:center;gap: 16px;flex-wrap:nowrap;overflow:hidden}
#leg{display:flex;gap: 16px;flex-wrap:wrap;flex:1}
.li{display:flex;align-items:center;gap: 16px;font-size:11px;color:var(--text2)}
.ld{width:10px;height:10px;border-radius:2px;flex-shrink:0}
#disc{font-size:10px;color:var(--text3);line-height:1.4;max-width:380px}
.leaflet-popup-pane{z-index:2000 !important}
.leaflet-popup-content-wrapper{background:#ffffff !important;border:none !important;border-radius: var(--radius-lg) !important;box-shadow:0 8px 40px rgba(0,0,0,0.18) !important;padding:0 !important;max-height:65vh !important;overflow-y:auto !important}
.leaflet-popup-content{margin:0 !important;width:280px !important;color:#0A0A0A !important;max-height:60vh !important;overflow-y:auto !important}
.leaflet-popup-tip{background:#ffffff !important}
.leaflet-popup-close-button{color:rgba(28,28,30,0.45) !important;top:10px !important;right:12px !important;font-size:18px !important}
.zpop{padding: 24px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif}
.zcity{font-size:15px;font-weight:800;color:#0A0A0A;letter-spacing:-0.3px}
.zcountry{font-size:12px;color:rgba(28,28,30,0.55);font-weight:400}
.zconf{font-size:10px;font-weight:600;background:#f2f2f7;border-radius:5px;padding: 24px;color:rgba(28,28,30,0.6);display:inline-block;margin:4px 0 10px}
.zsect{font-size:10px;font-weight:700;letter-spacing:0.7px;text-transform:uppercase;color:var(--text2);margin:8px 0 5px}
.zindices{display:grid;grid-template-columns:1fr 1fr;gap: 16px;margin-bottom:8px}
.zidx{background:#f2f2f7;border-radius:8px;padding: 24px}
.zil{font-size:10px;color:rgba(28,28,30,0.55);font-weight:500;margin-bottom:3px}
.zbar{height:3px;border-radius:2px;background:rgba(0,0,0,0.08);margin-bottom:3px}
.zfill{height:100%;border-radius:2px}
.zval{font-size:13px;font-weight:800;color:#0A0A0A}
.zcontra{border-radius:8px;padding: 24px;font-size:11px;line-height:1.5;margin-bottom:8px}
.zcontra.low{background:rgba(34,197,94,0.1);color:#86efac;border:1px solid rgba(34,197,94,0.18)}
.zcontra.medium{background:rgba(249,115,22,0.08);color:#92400e;border:1px solid rgba(249,115,22,0.2)}
.zcontra.high{background:rgba(239,68,68,0.08);color:#991b1b;border:1px solid rgba(239,68,68,0.2)}
.zcl{font-weight:800;display:block;margin-bottom:2px;font-size:11px;color:inherit}
.zage{font-size:11px;color:#16a34a;font-weight:600;margin-bottom:10px}
.lock-wrap{position:relative;margin-bottom:10px}
.lock-blur{filter:blur(3px);pointer-events:none;opacity:0.5}
.lock-over{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap: 16px;background:rgba(7,12,20,0.75);border-radius:8px;border:1px solid var(--border2)}
.lock-over span:first-child{font-size:16px}
.lock-over span:last-child{font-size:11px;color:var(--text2);font-weight:600}
.zcta{display:block;width:100%;background:#007aff;color:white;border:none;border-radius:9px;padding:10px;font-size:12px;font-weight:700;cursor:pointer;text-align:center;text-decoration:none;transition:opacity 0.2s;margin-top:2px}
.zcta:hover{opacity:0.85}
.zdisc{font-size:10px;color:rgba(28,28,30,0.35);margin-top:8px;text-align:center;line-height:1.4}
.zdisc a{color:#007aff;text-decoration:none}
@media(max-width:640px){#sidebar{display:none}.hdiv,#hdr-title{display:none}#hdr-i{gap: 16px;flex-wrap:nowrap;overflow:hidden}#hdr-cta{padding: 24px;font-size:11px;flex-shrink:0}.hpill{font-size:9px;padding: 24px}.pill-live{display:none}.cta-long{display:none}.cta-short{display:inline}}
@media(min-width:641px){.cta-short{display:none}.cta-long{display:inline}}
@media(max-width:640px){.leaflet-popup{display:none !important}}
/* Bottom sheet for mobile */
#bsheet{
display:none;position:fixed;left:0;right:0;bottom:0;z-index:9999;
background:#ffffff;border-top:1px solid rgba(0,0,0,0.1);
border-radius: var(--radius-lg) 16px 0 0;
box-shadow:0 -4px 24px rgba(0,0,0,0.15);
max-height:72vh;overflow-y:auto;
-webkit-overflow-scrolling:touch;
transform:translateY(100%);
transition:transform 0.28s cubic-bezier(0.32,0.72,0,1);
}
#bsheet.open{display:block;transform:translateY(0)}
#bsheet-handle{width:36px;height:4px;border-radius:2px;background:rgba(0,0,0,0.15);margin:10px auto 0}
#bsheet-close{position:absolute;top:10px;right:12px;background:rgba(0,0,0,0.06);border:none;color:#0A0A0A;font-size:16px;width:28px;height:28px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center}
#bsheet-content{padding:8px 0 env(safe-area-inset-bottom,16px)}
#bsheet-backdrop{display:none;position:fixed;inset:0;z-index:9998;background:rgba(0,0,0,0.3)}
#bsheet-backdrop.open{display:block}
@media(min-width:640px){
.leaflet-popup-pane{z-index:2000 !important}
}
#bsheet-content .zpop{padding: 24px}
#bsheet-content .zcity{color:#0A0A0A !important}
#bsheet-content .zcountry{color:rgba(28,28,30,0.55) !important}
#bsheet-content .zconf{background:#f2f2f7 !important;color:rgba(28,28,30,0.6) !important}
#bsheet-content .zsect{color:rgba(28,28,30,0.45) !important}
#bsheet-content .zidx{background:#f2f2f7 !important}
#bsheet-content .zil{color:rgba(28,28,30,0.55) !important}
#bsheet-content .zval{color:#0A0A0A !important}
#bsheet-content .zbar{background:rgba(0,0,0,0.08) !important}
#bsheet-content .lock-over{background:rgba(0,0,0,0.6) !important}
#bsheet-content .lock-over span:last-child{color:rgba(28,28,30,0.65) !important}
#bsheet-content .zdisc{color:rgba(28,28,30,0.35) !important}
#bsheet-content .zdisc a{color:#007aff !important}
#bsheet-content .zcta{background:#007aff !important;color: #1d1d1ffff !important}
</style>
<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>
<div id="map"></div>
<div id="hdr"><div id="hdr-i">
<a href="https://landvex.com" id="logo">Land<em>vex</em></a>
<div class="hdiv"></div>
<div id="hdr-title">Intelligence Map</div>
<div class="hpill pill-free">Free historical data</div>
<div class="hpill pill-live">Live on demand</div>
<a href="https://landvex.com/enterprise" id="hdr-cta"><span class="cta-long">Request live intelligence</span><span class="cta-short">Go live →</span></a>
</div></div>
<div id="sidebar">
<div class="sbc">
<div class="sbl">Map layers</div>
<div class="lr" onclick="toggleLayer('zones')">
<div class="ll"><div class="ld2"></div>Intelligence Zones</div>
<div class="tog on" id="tog-zones"></div>
</div>
<div class="lr" onclick="toggleLayer('contra')">
<div class="ll"><div class="ld2"></div>Contradiction Index</div>
<div class="tog on" id="tog-contra"></div>
</div>
</div>
<div class="sbc">
<div class="sbl">Indices</div>
<div class="ig">
<div class="ir active" onclick="selIdx(this,'infra')"><span class="in">Infrastructure Risk</span><span class="ib ib-free">Free</span></div>
<div class="ir" onclick="selIdx(this,'commercial')"><span class="in">Commercial Activity</span><span class="ib ib-free">Free</span></div>
<div class="ir" onclick="selIdx(this,'safety')"><span class="in">Safety Index</span><span class="ib ib-free">Free</span></div>
<div class="ir" onclick="selIdx(this,'climate')"><span class="in">Climate Risk</span><span class="ib ib-free">Free</span></div>
<div class="ir" onclick="selIdx(this,'growth')"><span class="in">Urban Growth</span><span class="ib ib-paid">Live</span></div>
<div class="ir" onclick="selIdx(this,'crowd')"><span class="in">Crowd Density</span><span class="ib ib-paid">Live</span></div>
<div class="ir" onclick="selIdx(this,'decay')"><span class="in">Decay Index</span><span class="ib ib-paid">Live</span></div>
<div class="ir" onclick="selIdx(this,'property')"><span class="in">Property Development</span><span class="ib ib-paid">Live</span></div>
</div>
</div>
</div>
<div id="bsheet-backdrop" onclick="closeBsheet()"></div>
<div id="bsheet"><div id="bsheet-handle"></div><button id="bsheet-close" onclick="closeBsheet()">&#215;</button><div id="bsheet-content"></div></div>
<div id="bot"><div id="bot-i">
<div id="leg">
<div class="li"><div class="ld"></div>Low operational risk</div>
<div class="li"><div class="ld"></div>Moderate</div>
<div class="li"><div class="ld"></div>Elevated</div>
<div class="li"><div class="ld"></div>High risk</div>
<div class="li"><div class="ld"></div>Contradiction detected</div>
</div>
<div id="disc">Landvex Assessment — official sources + quiXzoom observations. Free: 30+ day historical data. Live intelligence requires subscription.</div>
</div></div>
<script>
const map=L.map('map',{center:[30,15],zoom:3,zoomControl:true,attributionControl:false,
autoPanPaddingTopLeft:[10,80],
autoPanPaddingBottomRight:[10,80]
});
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',{maxZoom:19,subdomains:'abcd',attribution:''}).addTo(map);
const CITIES=[
// Sweden
{name:'Stockholm',country:'SE',conf:94,a:'green',c:'low',ct:'Strong alignment. Top-performing Nordic capital.',age:'2025-2026',idx:{infra:9.1,commercial:8.4,safety:8.7,climate:7.2},lat:59.334,lng:18.063,r:25000},
{name:'Göteborg',country:'SE',conf:88,a:'green',c:'low',ct:'Second city. Strong industrial and commercial base.',age:'2025-2026',idx:{infra:8.4,commercial:8.1,safety:7.8,climate:6.8},lat:57.706,lng:11.967,r:20000},
{name:'Malmö',country:'SE',conf:79,a:'yellow',c:'medium',ct:'Night safety deviates from official. Port area higher activity.',age:'2025-2026',idx:{infra:7.5,commercial:6.8,safety:6.4,climate:6.1},lat:55.604,lng:13.003,r:18000},
{name:'Uppsala',country:'SE',conf:84,a:'green',c:'low',ct:'University city. Strong R&D cluster.',age:'2025-2026',idx:{infra:8.4,commercial:7.8,safety:8.6,climate:7.1},lat:59.858,lng:17.645,r:15000},
{name:'Linköping',country:'SE',conf:82,a:'green',c:'low',ct:'Tech/defence capital. Saab. Strong alignment.',age:'2025-2026',idx:{infra:8.2,commercial:7.9,safety:8.8,climate:7.0},lat:58.411,lng:15.621,r:15000},
{name:'Luleå',country:'SE',conf:78,a:'green',c:'low',ct:'Data center capital Europe. Green steel transformation.',age:'2025-2026',idx:{infra:7.4,commercial:7.2,safety:9.4,climate:5.2},lat:65.584,lng:22.157,r:14000},
{name:'Umeå',country:'SE',conf:76,a:'green',c:'low',ct:'Fastest growing northern city.',age:'2025-2026',idx:{infra:7.6,commercial:7.1,safety:9.2,climate:5.8},lat:63.826,lng:20.263,r:14000},
{name:'Kiruna',country:'SE',conf:71,a:'orange',c:'high',ct:'CONTRADICTION: City physically moving 3km. Official maps show old location.',age:'2025-2026',idx:{infra:6.8,commercial:6.2,safety:9.6,climate:4.1},lat:67.856,lng:20.225,r:12000},
{name:'Visby',country:'SE',conf:80,a:'green',c:'low',ct:'UNESCO medieval city. Summer peak.',age:'2025-2026',idx:{infra:5.8,commercial:6.8,safety:9.6,climate:7.2},lat:57.638,lng:18.295,r:10000},
// UK
{name:'London',country:'UK',conf:92,a:'green',c:'low',ct:'Global financial centre. Strong alignment.',age:'2025-2026',idx:{infra:9.0,commercial:9.2,safety:8.1,climate:6.8},lat:51.507,lng:-0.127,r:20000},
{name:'Manchester',country:'UK',conf:84,a:'yellow',c:'medium',ct:'Northern powerhouse. Some areas deviation.',age:'2025-2026',idx:{infra:7.8,commercial:8.4,safety:7.2,climate:6.4},lat:53.480,lng:-2.242,r:15000},
// Netherlands
{name:'Amsterdam',country:'NL',conf:88,a:'green',c:'medium',ct:'Overtourism creates livability contradictions.',age:'2025-2026',idx:{infra:8.8,commercial:8.6,safety:8.3,climate:5.9},lat:52.370,lng:4.895,r:15000},
// Germany
{name:'Berlin',country:'DE',conf:86,a:'green',c:'low',ct:'Strong alignment. Tech hub transformation.',age:'2025-2026',idx:{infra:8.4,commercial:8.2,safety:7.8,climate:6.8},lat:52.520,lng:13.404,r:20000},
{name:'Hamburg',country:'DE',conf:84,a:'green',c:'low',ct:'Port city. HafenCity transformation.',age:'2025-2026',idx:{infra:8.6,commercial:8.4,safety:8.2,climate:6.4},lat:53.550,lng:10.000,r:18000},
{name:'Munich',country:'DE',conf:89,a:'green',c:'low',ct:'Premium German city. High alignment.',age:'2025-2026',idx:{infra:9.1,commercial:8.8,safety:8.9,climate:6.6},lat:48.137,lng:11.575,r:18000},
// France
{name:'Paris',country:'FR',conf:87,a:'yellow',c:'medium',ct:'Tourist pressure creates commercial contradictions.',age:'2025-2026',idx:{infra:8.6,commercial:9.1,safety:7.4,climate:6.8},lat:48.856,lng:2.352,r:20000},
// USA — full coverage
{name:'New York',country:'US',conf:89,a:'yellow',c:'medium',ct:'Infrastructure aging vs premium economic activity. Subway maintenance gap significant.',age:'2025-2026',idx:{infra:7.8,commercial:9.1,safety:7.2,climate:6.1},lat:40.712,lng:-74.005,r:28000},
{name:'Houston',country:'US',conf:82,a:'green',c:'low',ct:'Landvex HQ city. Energy capital. Strong commercial alignment.',age:'2025-2026',idx:{infra:7.4,commercial:8.8,safety:7.1,climate:5.8},lat:29.760,lng:-95.369,r:28000},
{name:'Los Angeles',country:'US',conf:80,a:'orange',c:'high',ct:'Homelessness crisis creates visible contradiction vs official livability data.',age:'2025-2026',idx:{infra:6.8,commercial:8.6,safety:6.4,climate:7.2},lat:34.052,lng:-118.243,r:28000},
{name:'Chicago',country:'US',conf:82,a:'yellow',c:'medium',ct:'Neighborhood inequality significant. Loop vs South Side divergence.',age:'2025-2026',idx:{infra:7.4,commercial:8.4,safety:6.2,climate:5.8},lat:41.878,lng:-87.629,r:26000},
{name:'Dallas',country:'US',conf:80,a:'yellow',c:'medium',ct:'Rapid growth outpacing infrastructure. Sprawl contradiction.',age:'2025-2026',idx:{infra:7.1,commercial:8.6,safety:7.1,climate:6.2},lat:32.779,lng:-96.808,r:26000},
{name:'Phoenix',country:'US',conf:76,a:'yellow',c:'medium',ct:'Climate risk underrepresented. Water scarcity growing concern.',age:'2025-2026',idx:{infra:7.2,commercial:7.8,safety:7.4,climate:4.2},lat:33.448,lng:-112.073,r:28000},
{name:'Philadelphia',country:'US',conf:78,a:'orange',c:'high',ct:'Infrastructure decay significant. Kensington area extreme contradiction.',age:'2025-2026',idx:{infra:6.4,commercial:7.6,safety:5.8,climate:6.4},lat:39.952,lng:-75.165,r:22000},
{name:'San Antonio',country:'US',conf:77,a:'green',c:'low',ct:'Military-driven economy. Stable alignment.',age:'2025-2026',idx:{infra:7.1,commercial:7.4,safety:7.6,climate:6.1},lat:29.424,lng:-98.493,r:24000},
{name:'San Diego',country:'US',conf:82,a:'green',c:'low',ct:'Military and biotech hub. Strong alignment.',age:'2025-2026',idx:{infra:8.1,commercial:8.2,safety:7.8,climate:9.2},lat:32.715,lng:-117.161,r:22000},
{name:'San Jose',country:'US',conf:84,a:'green',c:'low',ct:'Silicon Valley core. High confidence tech hub.',age:'2025-2026',idx:{infra:8.4,commercial:9.4,safety:7.6,climate:8.6},lat:37.338,lng:-121.886,r:20000},
{name:'San Francisco',country:'US',conf:80,a:'orange',c:'high',ct:'Homelessness and crime contradiction vs premium tech economy. Visible divergence.',age:'2025-2026',idx:{infra:7.8,commercial:9.2,safety:6.1,climate:8.4},lat:37.774,lng:-122.419,r:16000},
{name:'Austin',country:'US',conf:82,a:'green',c:'low',ct:'Tech migration boom. Infrastructure strain but strong growth.',age:'2025-2026',idx:{infra:7.4,commercial:8.8,safety:7.8,climate:6.8},lat:30.267,lng:-97.743,r:22000},
{name:'Seattle',country:'US',conf:82,a:'yellow',c:'medium',ct:'Amazon HQ2 effect. Some homeless contradiction.',age:'2025-2026',idx:{infra:8.1,commercial:8.8,safety:7.1,climate:7.4},lat:47.606,lng:-122.332,r:20000},
{name:'Denver',country:'US',conf:80,a:'yellow',c:'medium',ct:'Rapid growth. Climate and water risk growing.',age:'2025-2026',idx:{infra:7.6,commercial:8.2,safety:7.4,climate:6.4},lat:39.739,lng:-104.984,r:20000},
{name:'Washington DC',country:'US',conf:84,a:'yellow',c:'medium',ct:'Federal capital. Some neighbourhood inequality.',age:'2025-2026',idx:{infra:8.4,commercial:8.8,safety:7.2,climate:6.8},lat:38.907,lng:-77.036,r:18000},
{name:'Boston',country:'US',conf:86,a:'green',c:'low',ct:'Education and biotech hub. Strong alignment.',age:'2025-2026',idx:{infra:8.2,commercial:8.6,safety:7.8,climate:6.4},lat:42.360,lng:-71.058,r:16000},
{name:'Atlanta',country:'US',conf:78,a:'yellow',c:'medium',ct:'Major logistics hub. Inequality between zones.',age:'2025-2026',idx:{infra:7.4,commercial:8.4,safety:6.8,climate:6.8},lat:33.748,lng:-84.387,r:22000},
{name:'Miami',country:'US',conf:80,a:'yellow',c:'medium',ct:'Latin American gateway. Climate risk underclassified.',age:'2025-2026',idx:{infra:7.6,commercial:8.6,safety:7.1,climate:5.4},lat:25.761,lng:-80.191,r:18000},
{name:'Las Vegas',country:'US',conf:74,a:'yellow',c:'medium',ct:'Tourism economy. Water scarcity growing.',age:'2025-2026',idx:{infra:7.2,commercial:8.4,safety:6.8,climate:4.1},lat:36.174,lng:-115.136,r:20000},
{name:'Minneapolis',country:'US',conf:80,a:'yellow',c:'medium',ct:'Some neighbourhood inequality. Winter resilience strong.',age:'2025-2026',idx:{infra:7.8,commercial:7.8,safety:7.1,climate:5.8},lat:44.977,lng:-93.265,r:18000},
{name:'Portland',country:'US',conf:74,a:'orange',c:'high',ct:'Homelessness contradiction significant. Official data optimistic.',age:'2025-2026',idx:{infra:7.4,commercial:7.6,safety:5.8,climate:7.8},lat:45.523,lng:-122.676,r:16000},
{name:'Nashville',country:'US',conf:78,a:'green',c:'low',ct:'Music city boom. Strong commercial growth.',age:'2025-2026',idx:{infra:7.2,commercial:8.2,safety:7.4,climate:7.1},lat:36.162,lng:-86.781,r:18000},
{name:'Charlotte',country:'US',conf:78,a:'green',c:'low',ct:'Financial hub. Consistent growth trajectory.',age:'2025-2026',idx:{infra:7.4,commercial:8.1,safety:7.6,climate:7.2},lat:35.227,lng:-80.843,r:18000},
{name:'Detroit',country:'US',conf:68,a:'orange',c:'high',ct:'Post-industrial contradiction. Vacancy and decay significant.',age:'2025-2026',idx:{infra:5.8,commercial:6.4,safety:5.2,climate:5.8},lat:42.331,lng:-83.045,r:18000},
{name:'New Orleans',country:'US',conf:68,a:'orange',c:'high',ct:'Climate risk extreme. Infrastructure vulnerability high.',age:'2025-2026',idx:{infra:5.4,commercial:7.2,safety:5.4,climate:3.8},lat:29.951,lng:-90.071,r:14000},
// UAE
{name:'Dubai',country:'UAE',conf:83,a:'green',c:'low',ct:'World-class infrastructure. Strong alignment.',age:'2025-2026',idx:{infra:9.4,commercial:9.1,safety:8.8,climate:4.2},lat:25.197,lng:55.274,r:18000},
{name:'Abu Dhabi',country:'UAE',conf:81,a:'green',c:'low',ct:'Capital region. Premium development.',age:'2025-2026',idx:{infra:9.2,commercial:8.6,safety:9.1,climate:4.0},lat:24.453,lng:54.377,r:18000},
// Singapore
{name:'Singapore',country:'SG',conf:91,a:'green',c:'low',ct:'Near-perfect city-state alignment.',age:'2025-2026',idx:{infra:9.6,commercial:9.3,safety:9.4,climate:5.8},lat:1.352,lng:103.820,r:12000},
// Thailand
{name:'Bangkok',country:'TH',conf:71,a:'orange',c:'high',ct:'Field verified: cable disorder, infrastructure decay. Contradiction HIGH.',age:'2025-2026',idx:{infra:6.2,commercial:7.8,safety:5.9,climate:3.8},lat:13.756,lng:100.502,r:20000},
// Japan
{name:'Tokyo',country:'JP',conf:92,a:'green',c:'low',ct:'World-class maintenance culture. Perfect alignment.',age:'2025-2026',idx:{infra:9.9,commercial:9.4,safety:9.7,climate:6.2},lat:35.689,lng:139.692,r:25000},
// China
{name:'Shanghai',country:'CN',conf:74,a:'yellow',c:'medium',ct:'Rapid development creates some data lag.',age:'2025-2026',idx:{infra:8.8,commercial:9.2,safety:7.8,climate:5.4},lat:31.230,lng:121.474,r:25000},
// India
{name:'Mumbai',country:'IN',conf:68,a:'orange',c:'high',ct:'Infrastructure significantly below official classification in outer zones.',age:'2025-2026',idx:{infra:5.8,commercial:7.8,safety:6.4,climate:4.8},lat:19.076,lng:72.877,r:20000},
// Brazil
{name:'São Paulo',country:'BR',conf:68,a:'orange',c:'high',ct:'Safety underrepresented. Infrastructure gap outer zones.',age:'2025-2026',idx:{infra:5.8,commercial:7.2,safety:4.1,climate:5.5},lat:-23.550,lng:-46.633,r:25000},
{name:'Rio de Janeiro',country:'BR',conf:64,a:'orange',c:'high',ct:'Tourism vs safety contradiction significant.',age:'2025-2026',idx:{infra:5.2,commercial:6.8,safety:4.4,climate:6.1},lat:-22.906,lng:-43.172,r:20000},
// Africa
{name:'Lagos',country:'NG',conf:44,a:'red',c:'high',ct:'Low confidence. Major deviation infrastructure vs official.',age:'2025-2026',idx:{infra:3.8,commercial:6.1,safety:3.2,climate:4.1},lat:6.524,lng:3.379,r:20000},
{name:'Nairobi',country:'KE',conf:52,a:'orange',c:'high',ct:'Infrastructure gaps significant. Rapid urbanisation outpaces data.',age:'2025-2026',idx:{infra:4.8,commercial:6.4,safety:4.8,climate:5.6},lat:-1.286,lng:36.817,r:15000},
// Australia
{name:'Sydney',country:'AU',conf:87,a:'green',c:'low',ct:'High alignment. Premium Pacific city.',age:'2025-2026',idx:{infra:8.8,commercial:8.6,safety:8.6,climate:7.8},lat:-33.868,lng:151.209,r:20000},
// Canada
{name:'Toronto',country:'CA',conf:86,a:'green',c:'low',ct:'Strong alignment. Diverse economic base.',age:'2025-2026',idx:{infra:8.4,commercial:8.8,safety:8.2,climate:6.2},lat:43.653,lng:-79.383,r:18000},
// South Africa
{name:'Cape Town',country:'ZA',conf:58,a:'orange',c:'high',ct:'Extreme inequality visible. Tourist vs local reality gap.',age:'2025-2026',idx:{infra:5.4,commercial:6.8,safety:4.2,climate:7.4},lat:-33.924,lng:18.424,r:15000},
// Morocco
{name:'Casablanca',country:'MA',conf:62,a:'orange',c:'high',ct:'Rapid informal urbanisation creates significant contradiction between official infrastructure data and observed reality.',age:'2025-2026',idx:{infra:5.8,commercial:7.4,safety:6.1,climate:6.8},lat:33.589,lng:-7.603,r:18000},
{name:'Marrakech',country:'MA',conf:68,a:'yellow',c:'medium',ct:'Tourism economy creates dual reality. Medina vs modern city diverge significantly.',age:'2025-2026',idx:{infra:5.4,commercial:7.8,safety:6.8,climate:7.1},lat:31.628,lng:-7.987,r:14000},
{name:'Rabat',country:'MA',conf:65,a:'yellow',c:'medium',ct:'Capital. Official data more reliable than other Moroccan cities.',age:'2025-2026',idx:{infra:6.2,commercial:6.4,safety:7.2,climate:7.0},lat:34.020,lng:-6.841,r:13000},
// China
{name:'Beijing',country:'CN',conf:72,a:'yellow',c:'medium',ct:'Official data well-maintained but selective. Some commercial contradiction.',age:'2025-2026',idx:{infra:9.1,commercial:8.8,safety:8.4,climate:4.8},lat:39.904,lng:116.407,r:30000},
{name:'Shenzhen',country:'CN',conf:76,a:'green',c:'low',ct:'Tech megacity. Fastest development pace globally. Strong alignment.',age:'2025-2026',idx:{infra:9.2,commercial:9.4,safety:8.6,climate:5.8},lat:22.543,lng:114.057,r:22000},
{name:'Guangzhou',country:'CN',conf:71,a:'yellow',c:'medium',ct:'Pearl River Delta hub. Manufacturing transition to services.',age:'2025-2026',idx:{infra:8.8,commercial:8.6,safety:7.8,climate:5.4},lat:23.129,lng:113.264,r:22000},
{name:'Chengdu',country:'CN',conf:68,a:'yellow',c:'medium',ct:'Western China hub. Rapid growth outpacing official classification.',age:'2025-2026',idx:{infra:7.8,commercial:7.6,safety:7.9,climate:5.6},lat:30.572,lng:104.066,r:20000},
// Spain
{name:'Madrid',country:'ES',conf:84,a:'green',c:'low',ct:'Capital. Strong alignment. Premium Southern European market.',age:'2025-2026',idx:{infra:8.6,commercial:8.8,safety:8.2,climate:7.4},lat:40.416,lng:-3.703,r:20000},
{name:'Barcelona',country:'ES',conf:82,a:'yellow',c:'medium',ct:'Overtourism contradiction. Commercial activity vs livability diverging.',age:'2025-2026',idx:{infra:8.4,commercial:8.6,safety:7.4,climate:8.1},lat:41.385,lng:2.173,r:16000},
{name:'Valencia',country:'ES',conf:78,a:'green',c:'low',ct:'Growing tech hub. Strong alignment. Emerging market.',age:'2025-2026',idx:{infra:7.8,commercial:7.6,safety:8.4,climate:8.4},lat:39.470,lng:-0.376,r:14000},
{name:'Seville',country:'ES',conf:76,a:'green',c:'low',ct:'Tourism and industry balance. Strong historical alignment.',age:'2025-2026',idx:{infra:7.4,commercial:7.2,safety:8.2,climate:7.8},lat:37.389,lng:-5.984,r:13000},
{name:'Málaga',country:'ES',conf:74,a:'green',c:'low',ct:'Costa del Sol boom. Tech hub emerging. Tourism drives commercial.',age:'2025-2026',idx:{infra:7.6,commercial:7.8,safety:8.6,climate:9.1},lat:36.721,lng:-4.421,r:12000},
// Italy
{name:'Milan',country:'IT',conf:83,a:'green',c:'low',ct:'Fashion and finance capital. Strong commercial alignment.',age:'2025-2026',idx:{infra:8.4,commercial:9.1,safety:7.8,climate:7.2},lat:45.464,lng:9.189,r:18000},
{name:'Rome',country:'IT',conf:78,a:'yellow',c:'medium',ct:'Tourism pressure. Infrastructure aging vs heritage premium.',age:'2025-2026',idx:{infra:6.8,commercial:8.2,safety:7.2,climate:8.1},lat:41.902,lng:12.496,r:20000},
{name:'Naples',country:'IT',conf:64,a:'orange',c:'high',ct:'Significant informal economy not reflected in official data. Infrastructure contradiction high.',age:'2025-2026',idx:{infra:5.2,commercial:6.8,safety:5.4,climate:8.4},lat:40.853,lng:14.268,r:16000},
// Poland
{name:'Warsaw',country:'PL',conf:80,a:'green',c:'low',ct:'Fastest growing EU capital. Strong investment environment.',age:'2025-2026',idx:{infra:8.2,commercial:8.4,safety:8.4,climate:6.4},lat:52.229,lng:21.012,r:18000},
{name:'Krakow',country:'PL',conf:76,a:'green',c:'low',ct:'Tourism and tech hub. Strong alignment.',age:'2025-2026',idx:{infra:7.8,commercial:7.6,safety:8.6,climate:6.8},lat:50.061,lng:19.937,r:14000},
// Portugal
{name:'Lisbon',country:'PT',conf:78,a:'yellow',c:'medium',ct:'Tourism boom creating affordability contradiction.',age:'2025-2026',idx:{infra:7.6,commercial:8.2,safety:8.2,climate:9.2},lat:38.717,lng:-9.139,r:14000},
{name:'Porto',country:'PT',conf:76,a:'green',c:'low',ct:'Gentrification active. Tech and tourism growing.',age:'2025-2026',idx:{infra:7.4,commercial:7.8,safety:8.4,climate:8.8},lat:41.157,lng:-8.629,r:12000},
// Greece
{name:'Athens',country:'GR',conf:70,a:'yellow',c:'medium',ct:'Recovery from crisis. Infrastructure gap vs tourism premium.',age:'2025-2026',idx:{infra:6.4,commercial:7.2,safety:7.4,climate:8.6},lat:37.983,lng:23.727,r:16000},
// Turkey
{name:'Istanbul',country:'TR',conf:68,a:'orange',c:'high',ct:'Rapid informal development. Official data significantly lags observed reality.',age:'2025-2026',idx:{infra:6.8,commercial:8.4,safety:6.4,climate:7.2},lat:41.015,lng:28.979,r:22000},
// Saudi Arabia
{name:'Riyadh',country:'SA',conf:74,a:'green',c:'low',ct:'Vision 2030 transformation. Rapid premium development.',age:'2025-2026',idx:{infra:8.8,commercial:8.6,safety:8.4,climate:3.8},lat:24.688,lng:46.721,r:22000},
{name:'NEOM',country:'SA',conf:52,a:'yellow',c:'medium',ct:'Megaproject. Official projections vs observed construction pace diverge.',age:'2025-2026',idx:{infra:7.2,commercial:4.8,safety:8.8,climate:4.2},lat:28.150,lng:35.050,r:25000},
// India
{name:'Delhi',country:'IN',conf:62,a:'orange',c:'high',ct:'Air quality and infrastructure contradiction extremely high.',age:'2025-2026',idx:{infra:5.4,commercial:7.8,safety:5.8,climate:2.8},lat:28.613,lng:77.209,r:28000},
{name:'Bangalore',country:'IN',conf:68,a:'orange',c:'high',ct:'Tech hub but infrastructure severely lagging. Traffic contradiction extreme.',age:'2025-2026',idx:{infra:4.8,commercial:8.6,safety:7.1,climate:7.4},lat:12.971,lng:77.594,r:20000},
{name:'Hyderabad',country:'IN',conf:66,a:'yellow',c:'medium',ct:'HITEC City tech boom. Infrastructure improving rapidly.',age:'2025-2026',idx:{infra:6.2,commercial:8.1,safety:7.4,climate:6.8},lat:17.385,lng:78.486,r:18000},
// South Korea
{name:'Seoul',country:'KR',conf:88,a:'green',c:'low',ct:'World-class infrastructure. Near-perfect data alignment.',age:'2025-2026',idx:{infra:9.4,commercial:9.1,safety:9.2,climate:6.8},lat:37.566,lng:126.977,r:22000},
{name:'Busan',country:'KR',conf:82,a:'green',c:'low',ct:'Port city transformation. Strong tech and tourism.',age:'2025-2026',idx:{infra:8.6,commercial:7.8,safety:8.8,climate:7.2},lat:35.179,lng:129.075,r:16000},
// Indonesia
{name:'Jakarta',country:'ID',conf:58,a:'orange',c:'high',ct:'Sinking city. Infrastructure vs population density extreme contradiction.',age:'2025-2026',idx:{infra:5.2,commercial:7.4,safety:6.1,climate:3.4},lat:-6.208,lng:106.845,r:25000},
// Vietnam
{name:'Ho Chi Minh City',country:'VN',conf:62,a:'orange',c:'high',ct:'Rapid informal development. Official data significantly lags.',age:'2025-2026',idx:{infra:5.8,commercial:8.2,safety:7.1,climate:4.8},lat:10.762,lng:106.660,r:20000},
{name:'Hanoi',country:'VN',conf:60,a:'yellow',c:'medium',ct:'Capital. More stable but development pressure high.',age:'2025-2026',idx:{infra:6.2,commercial:7.6,safety:7.4,climate:5.4},lat:21.027,lng:105.834,r:16000},
// Mexico
{name:'Mexico City',country:'MX',conf:64,a:'orange',c:'high',ct:'Inequality extreme. Infrastructure aging in outer zones.',age:'2025-2026',idx:{infra:5.8,commercial:7.8,safety:5.4,climate:5.8},lat:19.432,lng:-99.133,r:28000},
{name:'Monterrey',country:'MX',conf:68,a:'yellow',c:'medium',ct:'Industrial hub. US nearshoring boom.',age:'2025-2026',idx:{infra:7.1,commercial:8.2,safety:6.4,climate:6.1},lat:25.686,lng:-100.316,r:18000},
// Colombia
{name:'Bogotá',country:'CO',conf:60,a:'orange',c:'high',ct:'Altitude, inequality and infrastructure gaps significant.',age:'2025-2026',idx:{infra:5.6,commercial:7.2,safety:5.2,climate:6.8},lat:4.711,lng:-74.072,r:22000},
{name:'Medellín',country:'CO',conf:62,a:'yellow',c:'medium',ct:'Remarkable transformation. Innovation city from crisis.',age:'2025-2026',idx:{infra:6.8,commercial:7.4,safety:6.8,climate:8.4},lat:6.244,lng:-75.574,r:16000},
// Argentina
{name:'Buenos Aires',country:'AR',conf:62,a:'orange',c:'high',ct:'Economic crisis visible in infrastructure decay. Official vs observed diverge.',age:'2025-2026',idx:{infra:5.4,commercial:7.1,safety:6.1,climate:7.4},lat:-34.603,lng:-58.381,r:22000},
// Chile
{name:'Santiago',country:'CL',conf:70,a:'yellow',c:'medium',ct:'Most developed Latin American capital. Some inequality.',age:'2025-2026',idx:{infra:7.4,commercial:7.8,safety:7.1,climate:7.6},lat:-33.456,lng:-70.648,r:20000},
// Egypt
{name:'Cairo',country:'EG',conf:54,a:'orange',c:'high',ct:'Mega-city pressure. New Cairo vs old city extreme contradiction.',age:'2025-2026',idx:{infra:5.1,commercial:6.8,safety:6.2,climate:5.8},lat:30.044,lng:31.235,r:26000},
// Ethiopia
{name:'Addis Ababa',country:'ET',conf:46,a:'red',c:'high',ct:'Rapid development but data very limited. Low confidence.',age:'2025-2026',idx:{infra:4.4,commercial:5.8,safety:5.4,climate:6.2},lat:9.025,lng:38.747,r:18000},
// Ghana
{name:'Accra',country:'GH',conf:52,a:'orange',c:'high',ct:'West Africa hub. Infrastructure significantly below classification.',age:'2025-2026',idx:{infra:4.8,commercial:6.4,safety:6.1,climate:5.8},lat:5.603,lng:-0.187,r:16000},
// New Zealand
{name:'Auckland',country:'NZ',conf:82,a:'green',c:'low',ct:'Pacific hub. Strong alignment.',age:'2025-2026',idx:{infra:8.2,commercial:7.8,safety:8.8,climate:8.4},lat:-36.848,lng:174.763,r:16000},
// Philippines
{name:'Manila',country:'PH',conf:52,a:'orange',c:'high',ct:'Infrastructure severely below official classification. Traffic extreme.',age:'2025-2026',idx:{infra:4.4,commercial:6.8,safety:5.4,climate:4.4},lat:14.599,lng:120.984,r:18000},
// Malaysia
{name:'Kuala Lumpur',country:'MY',conf:72,a:'yellow',c:'medium',ct:'Rapid development. Some informal areas create contradiction.',age:'2025-2026',idx:{infra:7.8,commercial:8.1,safety:7.6,climate:5.8},lat:3.139,lng:101.687,r:16000},
];
const AS={green:{color:'#22c55e',fo:0.10,w:1.5,d:null},yellow:{color:'#eab308',fo:0.13,w:1.5,d:'6 4'},orange:{color:'#f97316',fo:0.18,w:2,d:'5 4'},red:{color:'#ef4444',fo:0.22,w:2,d:'4 3'}};
const CL={low:'Contradiction Index: Low',medium:'Contradiction Index: Medium',high:'Contradiction Index: HIGH <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>'};
// Practical Intelligence — loaded from API
let PRACTICAL = {};
let PRACTICAL_META = {};
async function loadPracticalData() {
try {
const r = await fetch('/data/practical.json?v=' + Date.now());
const d = await r.json();
PRACTICAL = {};
for (const [city, data] of Object.entries(d.cities)) {
PRACTICAL[city] = data;
}
PRACTICAL_META = d.meta;
console.log('[Landvex] Practical data loaded:', Object.keys(PRACTICAL).length, 'cities, generated:', d.meta.generated);
} catch(e) {
console.warn('[Landvex] Practical data unavailable, using cached:', e.message);
}
}
function getPractical(cityName) {
return PRACTICAL[cityName] || null;
}
function foodPopup(p) {
const f = p.food;
const l = p.lcs;
if (!f) return '';
const upfCol = f.ultra_processed_pct < 30 ? '#16a34a' :
f.ultra_processed_pct < 45 ? '#ca8a04' : '#dc2626';
const obeseCol = f.obesity_pct < 12 ? '#16a34a' :
f.obesity_pct < 22 ? '#ca8a04' : '#dc2626';
const foodIncCol = f.food_income_pct < 15 ? '#16a34a' :
f.food_income_pct < 28 ? '#ca8a04' : '#dc2626';
const scoreCol = f.food_environment_score >= 75 ? '#16a34a' :
f.food_environment_score >= 55 ? '#ca8a04' : '#dc2626';
const heeScore = l && l.hee_score ? l.hee_score : null;
return `<div>
<div>FOOD ENVIRONMENT & HUMAN ENERGY</div>
${heeScore ? `<div>
<div>
<div>Human Energy Efficiency</div>
<div>LCS adjusted for food environment</div>
</div>
<div>${heeScore}</div>
</div>` : ''}
<div>
<div>
<div>Food env. score</div>
<div>${f.food_environment_score}/100</div>
</div>
<div>
<div>Ultra-processed</div>
<div>${f.ultra_processed_pct}%</div>
<div>of calories</div>
</div>
<div>
<div>Obesity rate</div>
<div>${f.obesity_pct}%</div>
</div>
<div>
<div>Food/income</div>
<div>${f.food_income_pct}%</div>
</div>
</div>
${f.contradiction ? `<div><span>Food contradiction: </span>${f.contradiction}</div>` : ''}
<div>${f.note}</div>
<div>Source: ${f.source||'WHO / NOVA 2024'}</div>
</div>`;
}
function lcsPopup(p) {
const l = p.lcs;
if (!l) return '';
const scoreCol = l.lcs_score >= 80 ? '#16a34a' : l.lcs_score >= 65 ? '#ca8a04' :
l.lcs_score >= 50 ? '#f97316' : '#dc2626';
const dimBar = (val, label, col) => `
<div>
<span>${label}</span>
<div>
<div></div>
</div>
<span>${val}</span>
</div>`;
const statRow = (label, val, unit='', col='#1c1c1e') =>
`<div>
<span>${label}</span>
<span>${val}${unit}</span>
</div>`;
const fertCol = l.fertility_rate < 1.2 ? '#dc2626' : l.fertility_rate < 1.6 ? '#f97316' : '#16a34a';
const airCol = l.air_quality_aqi < 30 ? '#16a34a' : l.air_quality_aqi < 60 ? '#ca8a04' : '#dc2626';
const avoidCol = l.avoidable_deaths_per100k < 150 ? '#16a34a' : l.avoidable_deaths_per100k < 300 ? '#ca8a04' : '#dc2626';
return `<div>
<div>LANDVEX CIVILIZATIONAL SCORE</div>
<!-- Main score -->
<div>
<div>
<div>
<div>${l.lcs_score}</div>
<div>out of 100</div>
</div>
<div>
<div>${l.highlight}</div>
</div>
</div>
${dimBar(l.vitality, 'Vitality', '#16a34a')}
${dimBar(l.prosperity, 'Prosperity', '#3b82f6')}
${dimBar(l.friction, 'Low friction', '#a855f7')}
</div>
<!-- Vitality stats -->
<div>
<div>Vitality</div>
${statRow('Life expectancy', l.life_expectancy, ' yrs')}
${statRow('Healthy years', l.healthy_years, ' yrs')}
${statRow('Avoidable deaths', l.avoidable_deaths_per100k, '/100k', avoidCol)}
${statRow('Infant mortality', l.infant_mortality_per1000, '/1000')}
${statRow('Dental health', l.dental_health_score + '/10')}
${statRow('Air quality (AQI)', l.air_quality_aqi, '', airCol)}
</div>
<!-- Demography -->
<div>
<div>Demographics</div>
${statRow('Fertility rate', l.fertility_rate, ' children/woman', fertCol)}
${statRow('Median age', l.median_age, ' yrs')}
${l.fertility_rate < 1.4 ? `<div>Demographic warning: below replacement level</div>` : ''}
</div>
<!-- Society -->
<div>
<div>Society</div>
${statRow('Homicide rate', l.homicide_per100k, '/100k', l.homicide_per100k < 1 ? '#16a34a' : l.homicide_per100k < 3 ? '#ca8a04' : '#dc2626')}
${statRow('Prison rate', l.prison_per100k, '/100k')}
${statRow('Press freedom', l.press_freedom + '/100')}
${statRow('Social mobility', l.social_mobility + '/100')}
${statRow('Avg commute', l.commute_min, ' min', l.commute_min < 35 ? '#16a34a' : l.commute_min < 55 ? '#ca8a04' : '#dc2626')}
${statRow('Housing/income ratio', l.housing_income_ratio + 'x', '', l.housing_income_ratio < 10 ? '#16a34a' : l.housing_income_ratio < 15 ? '#ca8a04' : '#dc2626')}
</div>
${l.contradiction_note ? `<div><span>Landvex Contradiction: </span>${l.contradiction_note}</div>` : ''}
<div>Source: ${l.source||'WHO / OECD / World Bank 2024'}</div>
</div>`;
}
function frictionPopup(p) {
const f = p.friction;
if (!f) return '';
const score = f.lfs_score || 0;
const col = score <= 20 ? '#16a34a' : score <= 40 ? '#4ade80' :
score <= 55 ? '#ca8a04' : score <= 70 ? '#f97316' : '#dc2626';
const grade_col = score <= 20 ? '#166534' : score <= 40 ? '#15803d' :
score <= 55 ? '#92400e' : score <= 70 ? '#c2410c' : '#991b1b';
const pct = Math.round((100-score));
const co = f.components || {};
const row = (label, val, unit='') => val !== undefined ?
`<div>
<span>${label}</span>
<span>${val}${unit}</span>
</div>` : '';
const tagList = (items, col) => items && items.length ?
items.map(t=>`<span>${t}</span>`).join(' ') : '';
return `<div>
<div>LANDVEX FRICTION SCORE</div>
<div>
<div>
<div>
<div>${score}</div>
<div>out of 100</div>
</div>
<div>
<div>${f.lfs_grade}</div>
<div>${pct}% efficiency vs max friction</div>
</div>
</div>
<div>
<div></div>
</div>
<div>
<span>0 — No friction</span><span>100 — Extreme</span>
</div>
</div>
<div>
<div>Key metrics</div>
${row('Company start', co.company_start_days, ' days')}
${row('Tax hours/year', co.tax_hours_per_year, ' hrs')}
${row('Construction permit', co.construction_permit_days, ' days')}
${row('Digital govt score', co.digital_govt_score, '/100')}
${row('Court resolution', co.legal_resolution_days, ' days')}
</div>
${f.strengths ? `<div><div>STRENGTHS</div><div>${tagList(f.strengths,'#16a34a')}</div></div>` : ''}
${f.weaknesses ? `<div><div>FRICTION POINTS</div><div>${tagList(f.weaknesses,'#dc2626')}</div></div>` : ''}
${f.entry_friction !== undefined ? `
<div>
<div>
<div>Entry</div>
<div>${f.entry_friction}</div>
</div>
<div>
<div>Operating</div>
<div>${f.operating_friction}</div>
</div>
<div>
<div>Scale adv.</div>
<div>${f.scale_advantage}</div>
</div>
</div>` : ''}
${f.sme_burden_pct !== undefined ? `
<div>
<div>Compliance cost as % of turnover</div>
<div>
<div><span>Micro-business</span><br><span>${f.sme_burden_pct}%</span></div>
<div>vs</div>
<div><span>Large corp</span><br><span>${f.large_co_burden_pct}%</span></div>
</div>
<div>
<div></div>
</div>
</div>` : ''}
${f.glasskiosk_note ? `<div><span>Example: </span>${f.glasskiosk_note}</div>` : ''}
${f.elasticity ? `<div><span>Regressivity: </span>${f.elasticity}</div>` : ''}
<div>Source: ${f.source||'World Bank / OECD 2023-2024'}</div>
</div>`;
}
function mentalHealthPopup(p) {
const m = p.mental_health;
if (!m) return '';
const suicide_col = m.suicide_per100k > 15 ? '#dc2626' :
m.suicide_per100k > 10 ? '#f97316' :
m.suicide_per100k > 6 ? '#ca8a04' : '#16a34a';
const stigma_col = m.stigma_index > 65 ? '#dc2626' :
m.stigma_index > 40 ? '#f97316' :
m.stigma_index > 20 ? '#ca8a04' : '#16a34a';
const system_col = m.mental_health_system >= 8 ? '#16a34a' :
m.mental_health_system >= 6 ? '#ca8a04' : '#dc2626';
const bar = (v, max) => {
const pct = Math.round((v/max)*100);
const col = v/max >= 0.8 ? '#16a34a' : v/max >= 0.5 ? '#ca8a04' : '#dc2626';
return `<div><div></div></div>`;
};
return `<div>
<div>MENTAL HEALTH INTELLIGENCE</div>
<div>
<div>
<div>Depression rate</div>
<div>${m.depression_pct}%</div>
</div>
<div>
<div>Burnout rate</div>
<div>${m.burnout_pct}%</div>
</div>
<div>
<div>Suicide /100k</div>
<div>${m.suicide_per100k}</div>
</div>
<div>
<div>Stigma index</div>
<div>${m.stigma_index}/100</div>
<div>Low = accepting</div>
</div>
</div>
<div>
<div>
<span>System</span>
${bar(m.mental_health_system, 10)}
<span>${m.mental_health_system}/10</span>
</div>
<div>
<span>Work stress</span>
${bar(m.work_stress_index, 10)}
<span>${m.work_stress_index}/10</span>
</div>
<div>
<span>Antidepress.</span>
${bar(m.antidepressant_use_pct, 25)}
<span>${m.antidepressant_use_pct}%</span>
</div>
</div>
<div>${m.therapy_access}</div>
<div>
<span>Crisis line</span>
<span>${m.crisis_line}</span>
</div>
<div>Source: ${m.source} · Not medical advice</div>
</div>`;
}
function socialPopup(p) {
const s = p.social;
if (!s) return '';
const lgbtq_col = s.lgbtq_index >= 80 ? '#16a34a' :
s.lgbtq_index >= 50 ? '#ca8a04' :
s.lgbtq_index >= 25 ? '#f97316' : '#dc2626';
const marriage_col = s.gay_marriage && s.gay_marriage.toLowerCase().startsWith('legal') ? '#16a34a' :
s.gay_marriage && s.gay_marriage.toLowerCase().includes('partner') ? '#ca8a04' : '#dc2626';
const lgbtq_bar_pct = s.lgbtq_index || 0;
let religion_html = '';
if (s.religion_pct) {
const entries = Object.entries(s.religion_pct).sort((a,b)=>b[1]-a[1]).slice(0,4);
const colors = ['#60a5fa','#34d399','#f59e0b','#a78bfa'];
religion_html = `<div>
<div>Religion (population %)</div>
<div>
${entries.map((e,i)=>`<div></div>`).join('')}
</div>
<div>
${entries.map((e,i)=>`<span>${e[0]} ${e[1]}%</span>`).join('')}
</div>
</div>`;
}
return `<div>
<div>SOCIAL INTELLIGENCE</div>
<div>
<div>
<div>LGBTQ+ Index</div>
<div>
<div></div>
</div>
<div>${s.lgbtq_index}/100</div>
</div>
<div>
<div>Married %</div>
<div>${s.married_pct}%</div>
<div>Divorce ${s.divorce_rate}/1000</div>
</div>
<div>
<div>Same-sex marriage</div>
<div>${s.gay_marriage}</div>
</div>
<div>
<div>Foreign-born</div>
<div>${s.foreign_born_pct}%</div>
</div>
</div>
<div>${s.lgbtq_note}</div>
${religion_html}
<div>Sources: ${s.social_source||'ILGA World / Eurostat 2025'}</div>
</div>`;
}
function legalPopup(p) {
const l = p.legal;
if (!l) return '';
const cannabis_col = l.cannabis && l.cannabis.toLowerCase().startsWith('legal') ? '#16a34a' :
l.cannabis && (l.cannabis.toLowerCase().includes('decrim') || l.cannabis.toLowerCase().includes('tolerat')) ? '#ca8a04' : '#dc2626';
const vaping_col = l.vaping && l.vaping.toLowerCase().includes('illegal') || l.vaping && l.vaping.toLowerCase().includes('ban') ? '#dc2626' :
l.vaping && l.vaping.toLowerCase().startsWith('legal') ? '#16a34a' : '#ca8a04';
const alcohol_col = l.alcohol_public && l.alcohol_public.toLowerCase().includes('ban') ? '#ca8a04' : '#16a34a';
return `<div>
<div>LEGAL INTELLIGENCE</div>
<div>
<div>
<span>Alcohol</span>
<span>${l.alcohol_public} (age ${l.alcohol_age})</span>
</div>
<div>
<span>Cannabis</span>
<span>${l.cannabis}</span>
</div>
<div>
<span>Vaping</span>
<span>${l.vaping}</span>
</div>
<div>
<span>Gambling</span>
<span>${l.gambling}</span>
</div>
${l.snus ? `<div>
<span>Snus</span>
<div><span>${l.snus.split(' — ')[0]}</span>${l.snus.includes(' — ')?`<div>${l.snus.split(' — ').slice(1).join(' — ')}</div>`:''}</div>
</div>` : ''}
${l.prostitution ? `<div>
<span>Prostitution</span>
<span>${l.prostitution}</span>
</div>` : ''}
${l.prostitution_detail ? `<div>${l.prostitution_detail}</div>` : ''}
</div>
${l.notes ? `<div>${l.notes}</div>` : ''}
<div>Source: ${p.legal_source||'EMCDDA/UNODC 2025'} · Not legal advice</div>
</div>`;
}
function practicalPopup(z) {
const p = getPractical(z.name);
if (!p) return '';
const bar = (v, max=10) => {
const pct = Math.round((v/max)*100);
const col = v>=8?'#16a34a':v>=6?'#ca8a04':'#dc2626';
return `<div><div></div></div>`;
};
const cashCol = p.cashless>=90?'#16a34a':p.cashless>=70?'#ca8a04':'#dc2626';
const speedCol = p.speed_mbps>=100?'#16a34a':p.speed_mbps>=40?'#ca8a04':'#dc2626';
const g5Col = p.g5_coverage>=80?'#16a34a':p.g5_coverage>=50?'#ca8a04':'#dc2626';
const restrictHtml = p.vpn_needed
? `<div>VPN REQUIRED — Internet restricted</div>`
: (p.restrictions.length ? `<div>${p.restrictions.join(' · ')}</div>` : '');
const blockedHtml = p.social_blocked.length
? `<div>Blocked: ${p.social_blocked.join(', ')}</div>` : '';
return `<div>
<div>PRACTICAL INTELLIGENCE</div>
<div>
<div>
<div>Public transport</div>
${bar(p.transport)}<div>${p.transport}/10</div>
</div>
<div>
<div>Cashless %</div>
${bar(p.cashless,100)}<div>${p.cashless}%</div>
</div>
<div>
<div>Internet speed</div>
${bar(Math.min(p.speed_mbps/3,10))}<div>${p.speed_mbps} Mbps</div>
</div>
<div>
<div>5G coverage</div>
${bar(p.g5_coverage,100)}<div>${p.g5_coverage}%</div>
</div>
</div>
<div>
<div>
<span>Taxi</span>
<span>${p.taxi_app}</span>
</div>
<div>
<span>Payments</span>
<span>${p.pay_apps}</span>
</div>
<div>
<span>SIM/eSIM</span>
<span>${p.sim}</span>
</div>
<div>
<span>English</span>
<span>${p.english}/10</span>
</div>
<div>
<span>Tipping</span>
<span>${p.tip}</span>
</div>
</div>
${restrictHtml}${blockedHtml}
${(()=>{
const sl={'Stockholm':'Available','G\u00f6teborg':'Available','Malm\u00f6':'Available','Uppsala':'Available','Lule\u00e5':'Available','Kiruna':'Available','London':'Available','Bangkok':'Available','Dubai':'Limited \u2014 regulatory','Singapore':'Unavailable \u2014 banned','New York':'Available','Houston':'Available','Los Angeles':'Available','Tokyo':'Available','Beijing':'Unavailable \u2014 banned','Shanghai':'Unavailable \u2014 banned','Mumbai':'Pending approval','Seoul':'Available','Amsterdam':'Available','Berlin':'Available','Paris':'Available','Madrid':'Available','Istanbul':'Available','Riyadh':'Limited \u2014 restricted','Cairo':'Unavailable \u2014 banned','Casablanca':'Available','Mexico City':'Available','S\u00e3o Paulo':'Available','Buenos Aires':'Available','Lagos':'Available','Nairobi':'Available','Jakarta':'Pending approval','Kuala Lumpur':'Available','Ho Chi Minh City':'Pending approval','Milan':'Available','Warsaw':'Available','Lisbon':'Available','Moscow':'Unavailable \u2014 banned'};
const status=sl[z.name]||null;
if(!status)return '';
const col=status.startsWith('Available')?'#16a34a':status.startsWith('Unavailable')?'#dc2626':'#ca8a04';
return `<div><div>Starlink</div><div>${status}</div></div>` + lcsPopup(p) + frictionPopup(p) + legalPopup(p) + socialPopup(p) + mentalHealthPopup(p) + foodPopup(p) + (p.speed_source?`<div>Speed: ${p.speed_source}</div>`:'');
})()}
</div>`;
}
const IN={infra:'Infrastructure Risk',commercial:'Commercial Activity',safety:'Safety Index',climate:'Climate Risk'};
function bar(v){const p=Math.round(v*10),c=v>=7.5?'#22c55e':v>=5?'#eab308':'#ef4444';return `<div class="zbar"><div class="zfill"></div></div>`;}
function zpop(z){
let freeHtml='';
Object.entries(z.idx).forEach(([k,v])=>{
freeHtml+=`<div class="zidx"><div class="zil">${IN[k]||k}</div>${bar(v)}<div class="zval">${v}/10</div></div>`;
});
const cityCoord=z.lat?`${z.lat.toFixed(3)},${z.lng.toFixed(3)}`:`${((z.coords[0][0]+z.coords[2][0])/2).toFixed(3)},${((z.coords[0][1]+z.coords[1][1])/2).toFixed(3)}`;
const livePreview=`<div class="zidx"><div class="zil">Urban Growth</div>${bar(7.1)}<div class="zval">7.1/10</div></div><div class="zidx"><div class="zil">Crowd Density</div>${bar(6.4)}<div class="zval">6.4/10</div></div><div class="zidx"><div class="zil">Decay Index</div>${bar(4.8)}<div class="zval">4.8/10</div></div><div class="zidx"><div class="zil">Property Dev.</div>${bar(7.7)}<div class="zval">7.7/10</div></div>`;
return `<div class="zpop">
<div class="zcity">${z.name} <span class="zcountry">· ${z.country}</span></div>
<div class="zconf">
<span>Confidence ${z.conf}%</span>
${['Stockholm','Bangkok','London','Dubai'].includes(z.name)?'<a href="/cities/" >Deep Dive</a>':''}
</div>
<div class="zsect">Free indices — historical data</div>
<div class="zindices">${freeHtml}</div>
<div class="zcontra ${z.c}"><span class="zcl">${CL[z.c]}</span>${z.ct}</div>
<div class="zage">✓ Data period: ${z.age}</div>
<div class="zsect">Live intelligence — on demand</div>
<div class="lock-wrap">
<div class="zindices lock-blur">${livePreview}</div>
<div class="lock-over"><span>&#128274;</span><span>Available with live subscription</span></div>
</div>
${(()=>{
const deepLinks={'Stockholm':'/stockholm-intelligence','Bangkok':'/stockholm-intelligence?city=bangkok','London':'/stockholm-intelligence?city=london','Dubai':'/stockholm-intelligence?city=dubai'};
const dl=deepLinks[z.name];
if(dl){
return `<a href="${dl}" class="zcta">Explore ${z.name} Intelligence </a>`;
}
return `<a href="https://landvex.com/enterprise?city=${encodeURIComponent(z.name)}" class="zcta">Request live intelligence →</a>`;
})()}
${practicalPopup(z)}
<div class="zdisc">Landvex Assessment. Not a factual statement. <a href="https://landvex.com/methodology">Methodology </a></div>
</div>`;
}
let zg=L.layerGroup().addTo(map),cg=L.layerGroup().addTo(map);
let ls={zones:true,contra:true};
function renderZ(){zg.clearLayers();if(!ls.zones)return;CITIES.forEach(z=>{const st=AS[z.a]||AS.yellow;const pop=zpop(z);const hasDeep=['Stockholm','Bangkok','London','Dubai'].includes(z.name);L.circle([z.lat,z.lng],{radius:z.r||15000,color:hasDeep?'#007aff':st.color,fillColor:st.color,fillOpacity:st.fo,weight:hasDeep?3:st.w,dashArray:st.d}).on("click",function(){if(isMob()){setTimeout(function(){map.closePopup();},10);openBsheet(zpop(z));}}).bindPopup(pop,{maxWidth:300,minWidth:260,autoPan:!isMob()}).addTo(zg);const lbl=L.marker([z.lat,z.lng],{icon:L.divIcon({className:"",html:`<div>${z.name}</div>`,iconAnchor:[0,0]}),interactive:false});lbl.addTo(zg);});}
function renderC(){cg.clearLayers();if(!ls.contra)return;CITIES.filter(z=>z.c==='high').forEach(z=>{L.circle([z.lat,z.lng],{radius:(z.r||15000)*1.4,color:'#f59e0b',fillColor:'#f59e0b',fillOpacity:0.04,weight:1.5,dashArray:'3 6'}).addTo(cg);});}
loadPracticalData().then(() => { renderZ(); renderC(); });
// Also render immediately with empty practical (fills in async)
renderZ(); renderC();
function toggleLayer(id){ls[id]=!ls[id];const el=document.getElementById('tog-'+id);el.classList.toggle('on',ls[id]);el.classList.toggle('off',!ls[id]);if(id==='zones')renderZ();if(id==='contra')renderC();}
function selIdx(el){document.querySelectorAll('.ir').forEach(r=>r.classList.remove('active'));el.classList.add('active');}
function openBsheet(html){
var bs=document.getElementById('bsheet');
var bd=document.getElementById('bsheet-backdrop');
document.getElementById('bsheet-content').innerHTML=html;
bs.classList.add('open');
bd.classList.add('open');
document.body.style.overflow='hidden';
map.closePopup();
}
function closeBsheet(){
document.getElementById('bsheet').classList.remove('open');
document.getElementById('bsheet-backdrop').classList.remove('open');
document.body.style.overflow='';
}
// Swipe down to close
(function(){
var sy=0;
var el=document.getElementById('bsheet');
if(!el)return;
el.addEventListener('touchstart',function(e){sy=e.touches[0].clientY;},{passive:true});
el.addEventListener('touchend',function(e){if(e.changedTouches[0].clientY-sy>60)closeBsheet();},{passive:true});
})();
function isMob(){return window.innerWidth<640;}
</script>
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Intelligence — Landvex</title>
<meta name="description" content="Explore Landvex intelligence indexes: city health, commercial opportunity, infrastructure risk, investment attractiveness, and more.">
<link rel="canonical" href="https://landvex.com/intelligence/">
<meta http-equiv="refresh" content="0; url=/">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>intelligence</span>
</nav>
<p>Redirecting to <a href="/">homepage</a>...</p>
</body>
</html>
+1294
View File
@@ -0,0 +1,1294 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Methodology — How Landvex Works | LandveX</title>
<meta name="description" content="How Landvex produces physical business intelligence — from global field observation through AI normalization, intelligence scoring, contradiction.">
<link rel="canonical" href="https://landvex.com/methodology/">
<meta name="robots" content="index, follow">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/methodology/">
<meta property="og:title" content="Methodology — How Landvex Works">
<meta property="og:description" content="From field observation to decision intelligence. How the Landvex pipeline turns physical reality into actionable scores and contradiction reports.">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="How Landvex Works — Methodology">
<meta name="twitter:description" content="From field observation to decision intelligence. The Landvex pipeline explained.">
<!-- 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">
<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-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);
--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(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; border-radius: var(--radius-md); }
/* ── HERO ── */
.hero {
background: var(--bg-dark);
padding: 24px 96px;
text-align: center;
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(38px, 6vw, 68px);
font-weight: 800;
letter-spacing: -2px;
line-height: 1.07;
color: #1d1d1f;
max-width: 820px;
margin: 0 auto 24px;
}
.hero-sub {
font-size: clamp(16px, 2vw, 19px);
color: var(--text-dim);
max-width: 620px;
line-height: 1.7;
margin: 0 auto 48px;
}
/* ── PIPELINE OVERVIEW ── */
.pipeline {
background: var(--bg-dark);
padding: 0 24px 80px;
}
.pipeline-inner {
max-width: 1140px;
margin: 0 auto;
display: flex;
align-items: stretch;
gap: 0;
overflow-x: auto;
}
.pipeline-step {
flex: 1;
min-width: 160px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
position: relative;
}
.pipeline-step:not(:last-child)::after {
content: '→';
position: absolute;
right: -14px;
top: 28px;
font-size: 20px;
color: rgba(0,102,255,0.5);
z-index: 1;
}
.pipeline-num {
width: 56px; height: 56px;
border-radius: 50%;
background: rgba(0,102,255,0.1);
border: 2px solid var(--blue);
display: flex; align-items: center; justify-content: center;
font-size: 13px; font-weight: 800;
color: var(--blue);
margin-bottom: 24px;
letter-spacing: 0;
}
.pipeline-step h3 {
font-size: 13px;
font-weight: 700;
color: #1d1d1f;
letter-spacing: -0.2px;
line-height: 1.3;
}
/* ── SECTION COMMON ── */
.container { max-width: 1140px; margin: 0 auto; }
.section-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--blue);
margin-bottom: 12px;
}
.section-title {
font-size: clamp(26px, 3.5vw, 40px);
font-weight: 800;
letter-spacing: -1.2px;
line-height: 1.1;
color: var(--text-dark);
margin-bottom: 14px;
}
.section-sub {
font-size: 17px;
color: var(--text-muted);
max-width: 560px;
line-height: 1.7;
}
/* ── LAYER SECTIONS ── */
.layer {
padding: 24px;
border-bottom: 1px solid #1a1a1a;
}
.layer:nth-child(even) {
background: #f8f9fc;
}
.layer-inner {
max-width: 1140px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
align-items: start;
}
.layer-inner.reverse {
direction: rtl;
}
.layer-inner.reverse > * {
direction: ltr;
}
.layer-header {}
.layer-header .layer-num {
display: inline-flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
.layer-num-badge {
width: 36px; height: 36px;
border-radius: 50%;
background: var(--blue);
color: #1d1d1f;
font-size: 14px;
font-weight: 800;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.layer-num-label {
font-size: 12px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--blue);
}
.layer-header h2 {
font-size: clamp(24px, 3vw, 36px);
font-weight: 800;
letter-spacing: -1px;
line-height: 1.1;
color: var(--text-dark);
margin-bottom: 14px;
}
.layer-header p {
font-size: 16px;
color: var(--text-muted);
line-height: 1.7;
}
/* ── FEATURE LIST ── */
.feature-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.feature-item {
background: #fff;
border: 1px solid #e8eaf0;
border-radius: var(--radius-md);
padding: 24px;
display: flex;
gap: 16px;
align-items: flex-start;
transition: border-color 0.2s, box-shadow 0.2s;
}
.layer:nth-child(even) .feature-item {
background: #fff;
}
.feature-item:hover {
border-color: rgba(0,102,255,0.25);
box-shadow: 0 4px 20px rgba(0,102,255,0.06);
}
.feature-icon {
width: 36px; height: 36px;
background: rgba(0,102,255,0.08);
border-radius: var(--radius-sm);
display: flex; align-items: center; justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.feature-item h4 {
font-size: 15px;
font-weight: 700;
color: var(--text-dark);
margin-bottom: 4px;
letter-spacing: -0.2px;
}
.feature-item p {
font-size: 14px;
color: var(--text-muted);
line-height: 1.55;
}
/* ── OUTPUT SECTION ── */
.output-section {
background: var(--bg-dark);
padding: 24px;
}
.output-header {
text-align: center;
margin-bottom: 60px;
}
.output-header .section-title { color: #1d1d1f; }
.output-header .section-sub { color: var(--text-dim); margin: 0 auto; }
.output-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
max-width: 1140px;
margin: 0 auto;
}
.output-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
transition: border-color 0.25s, transform 0.2s;
}
.output-card:hover {
border-color: rgba(0,102,255,0.35);
transform: translateY(-3px);
}
.output-icon {
width: 44px; height: 44px;
background: var(--blue-glow);
border: 1px solid rgba(0,102,255,0.25);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 20px;
margin-bottom: 18px;
}
.output-card h3 {
font-size: 17px;
font-weight: 700;
color: #1d1d1f;
margin-bottom: 8px;
letter-spacing: -0.3px;
}
.output-card p {
font-size: 14px;
color: var(--text-dim);
line-height: 1.6;
}
.output-card .cite-note {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border);
font-size: 12px;
color: rgba(255,255,255,0.75);
font-style: italic;
}
/* ── DIMENSIONS BAND ── */
.dimensions-band {
background: #e8f0fe;
padding: 24px;
}
.dimensions-inner {
max-width: 1140px;
margin: 0 auto;
}
.dimensions-header {
text-align: center;
margin-bottom: 48px;
}
.dimensions-header .section-title { color: #1d1d1f; }
.dimensions-header .section-sub { color: rgba(255,255,255,0.75); margin: 0 auto; }
.dimensions-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 16px;
}
.dim-card {
background: rgba(0,0,0,0.03);
border: 1px solid rgba(0,0,0,0.09);
border-radius: var(--radius-md);
padding: 24px;
text-align: center;
transition: background 0.2s, border-color 0.2s;
}
.dim-card:hover {
background: rgba(0,102,255,0.1);
border-color: rgba(0,102,255,0.3);
}
.dim-icon { font-size: 24px; margin-bottom: 10px; }
.dim-name { font-size: 13px; font-weight: 700; color: #1d1d1f; line-height: 1.3; }
.dim-scale { font-size: 11px; color: rgba(255,255,255,0.75); margin-top: 4px; }
/* ── CTA BAND ── */
.cta-band {
background: var(--blue);
padding: 24px;
text-align: center;
}
.cta-band h2 {
font-size: clamp(26px, 4vw, 42px);
font-weight: 800;
letter-spacing: -1.2px;
color: #1d1d1f;
margin-bottom: 14px;
}
.cta-band p {
font-size: 18px;
color: rgba(0,0,0,0.8);
margin-bottom: 36px;
max-width: 560px;
margin-left: auto;
margin-right: auto;
}
.btn-white {
background: #fff;
color: var(--blue);
font-weight: 700;
}
.btn-white:hover {
background: rgba(0,0,0,0.92);
transform: translateY(-1px);
}
/* ── FOOTER ── */
footer {
background: var(--bg-dark);
border-top: 1px solid var(--border);
padding: 24px;
}
.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-links { display: flex; gap: 16px; 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: 8px;
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; }
/* ── PDF DOWNLOAD BUTTON ── */
.pdf-download-btn {
display: inline-flex; align-items: center; gap: 16px;
background: rgba(0,0,0,0.08);
border: 1.5px solid rgba(0,0,0,0.2);
color: #1d1d1f;
font-size: 14px; font-weight: 600;
padding: 24px;
border-radius: var(--radius-md);
margin-top: 20px;
transition: background 0.2s, border-color 0.2s, transform 0.15s;
cursor: pointer;
}
.pdf-download-btn:hover {
background: rgba(0,0,0,0.14);
border-color: rgba(0,0,0,0.35);
transform: translateY(-1px);
}
.pdf-download-btn svg { flex-shrink: 0; }
/* ── DATA QUALITY ── */
.dq-section { background: #f8f9fc; padding: 24px; }
.dq-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 48px; }
.dq-card {
background: #fff;
border: 1px solid #e0e6f0;
border-radius: var(--radius-lg);
padding: 24px;
position: relative;
overflow: hidden;
}
.dq-card::before {
content: '';
position: absolute; top: 0; left: 0; right: 0;
height: 3px; background: var(--blue);
}
.dq-card-icon { margin-bottom: 18px; }
.dq-card h3 { font-size: 18px; font-weight: 800; color: #0a0a0a; margin-bottom: 10px; letter-spacing: -0.3px; }
.dq-card p { font-size: 14px; color: #555; line-height: 1.65; margin-bottom: 24px; }
.dq-standards { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; }
.dq-standards li {
display: flex; align-items: flex-start; gap: 16px;
font-size: 13px; color: #444; line-height: 1.5;
}
.dq-standards li::before {
content: '';
width: 6px; height: 6px; border-radius: 50%;
background: var(--blue); flex-shrink: 0; margin-top: 6px;
}
/* ── CONTRADICTION FLOW DIAGRAM ── */
.flow-section { background: #f5f5f7; padding: 24px; }
.flow-diagram {
max-width: 820px; margin: 56px auto 0;
display: flex; flex-direction: column; align-items: center; gap: 0;
}
.flow-node {
width: 100%; max-width: 540px;
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-md); padding: 24px;
display: flex; align-items: center; gap: 16px;
}
.flow-node.flow-trigger { border-color: rgba(0,102,255,0.4); background: rgba(0,102,255,0.07); }
.flow-node.flow-detect { border-color: rgba(245,158,11,0.4); background: rgba(245,158,11,0.06); }
.flow-node.flow-rank { border-color: rgba(239,68,68,0.35); background: rgba(239,68,68,0.06); }
.flow-node.flow-redteam { border-color: rgba(139,92,246,0.4); background: rgba(139,92,246,0.07); }
.flow-node.flow-output { border-color: rgba(34,197,94,0.4); background: rgba(34,197,94,0.07); }
.flow-node-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.flow-node-text h4 { font-size: 14px; font-weight: 700; color: #1d1d1f; margin-bottom: 3px; }
.flow-node-text p { font-size: 12px; color: rgba(255,255,255,0.75); line-height: 1.5; }
.flow-arrow { display: flex; align-items: center; justify-content: center; height: 32px; }
.flow-arrow svg { opacity: 0.4; }
.flow-split {
display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
width: 100%; max-width: 540px; margin: 0;
}
.flow-split .flow-node { max-width: 100%; }
.flow-split-arrow { display: flex; align-items: center; justify-content: center; height: 32px; position: relative; width: 100%; max-width: 540px; }
.flow-split-arrow::before, .flow-split-arrow::after {
content: '';
position: absolute; top: 50%; width: 25%;
height: 1px; background: rgba(0,0,0,0.15);
}
.flow-split-arrow::before { right: calc(50% + 8px); }
.flow-split-arrow::after { left: calc(50% + 8px); }
/* ── RESPONSIVE ── */
@media (max-width: 900px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
.layer-inner { grid-template-columns: 1fr; gap: 16px; }
.layer-inner.reverse { direction: ltr; }
.output-grid { grid-template-columns: 1fr 1fr; }
.dimensions-grid { grid-template-columns: repeat(3, 1fr); }
.pipeline-inner { gap: 16px; }
}
@media (max-width: 600px) {
.hero { padding: 24px 72px; }
.layer { padding: 24px; }
.output-grid { grid-template-columns: 1fr; }
.dimensions-grid { grid-template-columns: repeat(2, 1fr); }
.footer-inner { flex-direction: column; text-align: center; }
.pipeline-step:not(:last-child)::after { display: none; }
.container { padding: 0 16px !important; box-sizing: border-box; }
.pipeline-inner { padding: 0 4px; }
}
</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": "Methodology",
"item": "https://landvex.com/methodology/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
<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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>methodology</span>
</nav>
<!-- NAV -->
<nav aria-label="Main navigation">
<a class="nav-logo" href="/">LandveX</a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/#how-it-works">How it works</a></li>
<li><a href="https://landvex.com/#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="https://landvex.com/#contact">Get in touch →</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">Methodology</div>
<h1>How Landvex works.</h1>
<div><strong>Pre-launch:</strong> All methodology documentation describes the system as designed for August 2026 launch. No live intelligence is being generated or sold at this time.</div>
<p class="lv-hero-subtitle">Five interlocked layers — from global field observation to verified intelligence. Every output is sourced, explained, and challenged before delivery.</p>
<div>
<a class="lv-btn lv-btn--lg" href="https://landvex.com/#contact">Request a briefing &rarr;</a>
<a class="pdf-download-btn" href="/methodology/landvex-methodology-2026.pdf">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download methodology PDF &rarr;
</a>
</div>
</section>
<!-- PIPELINE OVERVIEW -->
<section class="pipeline">
<div class="pipeline-inner">
<div class="pipeline-step">
<div class="pipeline-num">01</div>
<h3>Observation<br>Layer</h3>
</div>
<div class="pipeline-step">
<div class="pipeline-num">02</div>
<h3>Normalization<br>Layer</h3>
</div>
<div class="pipeline-step">
<div class="pipeline-num">03</div>
<h3>Intelligence<br>Layer</h3>
</div>
<div class="pipeline-step">
<div class="pipeline-num">04</div>
<h3>Contradiction<br>Engine</h3>
</div>
<div class="pipeline-step">
<div class="pipeline-num">05</div>
<h3>Red Team<br>Analysis</h3>
</div>
<div class="pipeline-step">
<div class="pipeline-num"></div>
<h3>Verified<br>Output</h3>
</div>
</div>
</section>
<!-- PDF DOWNLOAD BLOCK -->
<section>
<div>
<div>
<div>
<h3>Landvex Intelligence Methodology</h3>
<p>8-page technical overview. How field observations become decision intelligence.</p>
</div>
<a href="/methodology/landvex-methodology-2026.pdf" >
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download PDF
</a>
</div>
</div>
</section>
<!-- LAYER 1: OBSERVATION -->
<section class="layer" id="observation">
<div class="layer-inner">
<div class="layer-header">
<div class="layer-num">
<div class="layer-num-badge">1</div>
<span class="layer-num-label">Observation Layer</span>
</div>
<h2>Eyes on the ground.<br>At global scale.</h2>
<p>Every Landvex intelligence product begins with physical observation. The quiXzoom contributor network gives us human eyes across more than 20 countries — not cameras, not satellites, but verified people on the ground documenting what is actually there.</p>
</div>
<div class="feature-list">
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
<div>
<h4>quiXzoom global contributor network</h4>
<p>Thousands of active field contributors across 20+ countries, deployable within hours to any target area. Local knowledge combined with structured data collection.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 9h6v6H9z"/><path d="M9 1v2M15 1v2M9 21v2M15 21v2M20 9h2M20 15h2M2 9h2M2 15h2"/></svg></div>
<div>
<h4>AI-reviewed submissions</h4>
<p>Every submission is automatically reviewed for geographic accuracy, image quality, and specification compliance before it enters the pipeline. No human bias in the review gate.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M15 8h2M15 12h2"/><path d="M7 16h10"/></svg></div>
<div>
<h4>Verified field agents, identity-verified once</h4>
<p>Every contributor completes a one-time identity verification. Verified status persists across all missions. Verification creates accountability and trace integrity for every observation.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg></div>
<div>
<h4>Coverage: 20+ countries at launch</h4>
<p>Europe, Southeast Asia, and growing. Coverage expands continuously as the quiXzoom network scales. New markets are opened on request.</p>
</div>
</div>
</div>
</div>
</section>
<!-- LAYER 2: NORMALIZATION -->
<section class="layer" id="normalization">
<div class="layer-inner reverse">
<div class="layer-header">
<div class="layer-num">
<div class="layer-num-badge">2</div>
<span class="layer-num-label">Normalization Layer</span>
</div>
<h2>Raw observation becomes<br>structured data.</h2>
<p>Field observations arrive in different formats, from different contributors, across different contexts. The normalization layer converts everything into a consistent, comparable structured data point — stripping noise while preserving source integrity.</p>
</div>
<div class="feature-list">
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M21.21 15.89A10 10 0 1 1 8 2.83"/><path d="M22 12A10 10 0 0 0 12 2v10z"/></svg></div>
<div>
<h4>Every observation converted to a structured data point</h4>
<p>Unstructured field submissions are parsed into typed, schema-validated records. Location, object, condition, and change signal are extracted and stored independently.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg></div>
<div>
<h4>Entity extraction: location, object type, condition, change signal</h4>
<p>Each data point is tagged with what was observed, where, in what condition, and whether it represents a change from the prior state — the four axes of physical intelligence.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div>
<div>
<h4>Temporal indexing: every observation timestamped and versioned</h4>
<p>Every data point is stored with a precise timestamp and version history. This enables change detection, trend analysis, and before/after comparisons at any granularity.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></div>
<div>
<h4>Source attribution maintained throughout</h4>
<p>Every data point retains a full audit trail back to the field submission, the contributor, the timestamp, and the mission brief. Nothing is anonymized into oblivion.</p>
</div>
</div>
</div>
</div>
</section>
<!-- DIMENSIONS BAND -->
<div class="dimensions-band">
<div class="dimensions-inner">
<div class="dimensions-header">
<div class="section-label">Six scoring dimensions</div>
<h2 class="section-title">Every place scored on six axes.</h2>
<p class="section-sub">Observations aggregate into district, city, and regional scores across six dimensions — all on a 0100 scale, all updated continuously from August 2026.</p>
</div>
<div class="dimensions-grid">
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2v1"/><path d="M12 7a5 5 0 0 1 5 5c0 2.5-2 4-2 6H9c0-2-2-3.5-2-6a5 5 0 0 1 5-5z"/></svg></div>
<div class="dim-name">Opportunity</div>
<div class="dim-scale">0100</div>
</div>
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="m22 7-8.5 8.5-5-5L2 17"/><path d="M16 7h6v6"/></svg></div>
<div class="dim-name">Growth</div>
<div class="dim-scale">0100</div>
</div>
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg></div>
<div class="dim-name">Commercial Vitality</div>
<div class="dim-scale">0100</div>
</div>
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg></div>
<div class="dim-name">Infrastructure Stability</div>
<div class="dim-scale">0100</div>
</div>
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M2 12h20"/><path d="M13 2v20"/><path d="M21 12a9 9 0 0 1-9 9"/><path d="M3 12a9 9 0 0 0 9-9"/></svg></div>
<div class="dim-name">Tourism Potential</div>
<div class="dim-scale">0100</div>
</div>
<div class="dim-card" onclick="location.href='#intelligence'" role="button" tabindex="0">
<div class="dim-icon"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M6 3h12l4 6-10 13L2 9z"/><path d="M11 3 8 9l4 13 4-13-3-6"/><path d="M2 9h20"/></svg></div>
<div class="dim-name">Investment Confidence</div>
<div class="dim-scale">0100</div>
</div>
</div>
</div>
</div>
<!-- LAYER 3: INTELLIGENCE -->
<section class="layer" id="intelligence">
<div class="layer-inner">
<div class="layer-header">
<div class="layer-num">
<div class="layer-num-badge">3</div>
<span class="layer-num-label">Intelligence Layer</span>
</div>
<h2>Observations aggregate<br>into scores.</h2>
<p>Individual data points are aggregated into district, city, and regional intelligence scores. Scores are updated continuously as new observations arrive — not quarterly, not annually. The physical world changes in real time; the intelligence layer follows it.</p>
</div>
<div class="feature-list">
<div class="feature-item">
<div class="feature-icon">🏙️</div>
<div>
<h4>Observations aggregated into district / city / region scores</h4>
<p>Multiple observations from multiple contributors covering the same area are weighted, de-duplicated, and aggregated into a single composite score per dimension per area.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon">🔄</div>
<div>
<h4>Scores updated continuously as new observations arrive</h4>
<p>There is no batch cadence. Every validated observation triggers a score recalculation for the relevant area. Intelligence is always as fresh as the most recent field data.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg></div>
<div>
<h4>Six dimensions, one comparable scale</h4>
<p>Opportunity · Growth · Commercial Vitality · Infrastructure Stability · Tourism Potential · Investment Confidence. Bangkok vs Kuala Lumpur vs Milan — on the same axes, the same scale.</p>
</div>
</div>
</div>
</div>
</section>
<!-- LAYER 4: CONTRADICTION ENGINE -->
<section class="layer" id="contradiction">
<div class="layer-inner">
<div class="layer-header">
<div class="layer-num">
<div class="layer-num-badge">4</div>
<span class="layer-num-label">Contradiction Engine</span>
</div>
<h2>Official data vs.<br>observed reality.</h2>
<p>The most valuable intelligence is not confirmation — it is contradiction. The Contradiction Engine ingests official data sources and actively searches for conflicts with what our contributors actually observed. When the data says one thing and the ground says another, that is where the intelligence lives.</p>
</div>
<div class="feature-list">
<div class="feature-item">
<div class="feature-icon">🏛️</div>
<div>
<h4>Official data ingested continuously</h4>
<p>National statistics, municipal open data, land registries, and transport authorities are continuously ingested and indexed against covered geographies.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon">⚖️</div>
<div>
<h4>Every official claim compared against observed reality</h4>
<p>For every official data point covering an area with observation coverage, the Contradiction Engine runs an automated comparison. Supporting evidence and contradicting evidence are catalogued separately.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon">🚩</div>
<div>
<h4>Contradictions flagged, ranked by severity and economic impact</h4>
<p>Not all contradictions are equal. The engine ranks flagged conflicts by how severe the discrepancy is, and by the estimated economic significance of the affected area or asset class.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M21.21 15.89A10 10 0 1 1 8 2.83"/><path d="M22 12A10 10 0 0 0 12 2v10z"/></svg></div>
<div>
<h4>Confidence scores from evidence weight</h4>
<p>Every contradiction report includes a confidence score calculated from the volume, recency, and source diversity of the supporting and contradicting evidence.</p>
</div>
</div>
</div>
</div>
</section>
<!-- LAYER 5: RED TEAM -->
<section class="layer" id="redteam">
<div class="layer-inner reverse">
<div class="layer-header">
<div class="layer-num">
<div class="layer-num-badge">5</div>
<span class="layer-num-label">Red Team Analysis</span>
</div>
<h2>Every conclusion<br>challenged before delivery.</h2>
<p>Before any major conclusion reaches a client, a second AI model actively attempts to disprove it. This is not a review — it is an adversarial process. If the conclusion survives, it is delivered. If it doesn't, it is revised or flagged.</p>
</div>
<div class="feature-list">
<div class="feature-item">
<div class="feature-icon">⚔️</div>
<div>
<h4>Every major conclusion challenged by a second model</h4>
<p>The primary analysis model produces a conclusion. A separate red team model, given the same evidence, is tasked with finding holes, alternative explanations, and disconfirming observations. The conclusion is only finalized after this adversarial review.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-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>
<div>
<h4>Supporting evidence listed</h4>
<p>Every delivered conclusion includes a full list of the observations, data points, and sources that support it — with source attribution and timestamps. Clients see what the conclusion is based on.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon"></div>
<div>
<h4>Contradicting evidence listed</h4>
<p>Contradicting evidence is not suppressed. Every conclusion is delivered alongside the evidence that pushed against it. Where the red team found weaknesses, those are explicitly documented.</p>
</div>
</div>
<div class="feature-item">
<div class="feature-icon">📏</div>
<div>
<h4>Uncertainty quantified</h4>
<p>Confidence levels are expressed numerically, not as qualitative hedges. Clients know not just what Landvex concludes, but how certain that conclusion is and why.</p>
</div>
</div>
</div>
</div>
</section>
<!-- OUTPUT SECTION -->
<section class="output-section" id="output">
<div class="output-header">
<div class="section-label">Output</div>
<h2 class="section-title">What Landvex delivers.</h2>
<p class="section-sub">Six output types. All sourced. All explained. All ready for decisions that cost money.</p>
</div>
<div class="output-grid">
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg></div>
<h3>Scores (0100 per dimension)</h3>
<p>Composite intelligence scores per location, across six dimensions. Updated continuously from August 2026. Comparable across geographies and over time.</p>
<div class="cite-note">Every score cites contributing observations and source data.</div>
</div>
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon">🚩</div>
<h3>Contradiction Reports</h3>
<p>Where observed reality conflicts with official data or investment thesis. Ranked by severity and economic significance. Evidence on both sides included.</p>
<div class="cite-note">Includes confidence score and source breakdown.</div>
</div>
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066FF" stroke-width="2"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2v1"/><path d="M12 7a5 5 0 0 1 5 5c0 2.5-2 4-2 6H9c0-2-2-3.5-2-6a5 5 0 0 1 5-5z"/></svg></div>
<h3>Opportunity Reports</h3>
<p>Where physical conditions signal under-exploited potential. Targeted by geography, asset class, or decision type. Ranked by opportunity magnitude.</p>
<div class="cite-note">Field observations and trend data cited throughout.</div>
</div>
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon"><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>
<h3>Risk Forecasts</h3>
<p>Where physical conditions signal emerging risk — before it appears in official statistics or financial reporting. Predictive scoring based on observed change velocity.</p>
<div class="cite-note">Uncertainty ranges included with every forecast.</div>
</div>
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon">📝</div>
<h3>Executive Summaries</h3>
<p>Decision-ready narratives structured around the client's specific question — not generic reports. Concise, direct, and directly linked to the decision being made.</p>
<div class="cite-note">Supporting data attached; key sources highlighted.</div>
</div>
<div class="output-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="output-icon">📌</div>
<h3>All outputs cite sources<br>and explain reasoning</h3>
<p>There is no black box. Every Landvex output tells you what it concluded, what it was based on, what pushed against it, and how confident the conclusion is.</p>
<div class="cite-note">Because intelligence you can't verify is just opinion.</div>
</div>
</div>
</section>
<!-- DATA QUALITY SECTION -->
<section class="dq-section" id="data-quality">
<div class="lv-container">
<div class="section-label">Data quality</div>
<h2 class="section-title">The standards behind every score.</h2>
<p class="section-sub">Intelligence is only as good as the data it is built from. Every observation in the Landvex pipeline is subject to explicit accuracy standards, a documented verification chain, and a confidence scoring system.</p>
<div class="dq-grid">
<div class="dq-card" onclick="location.href='#data-quality'" role="button" tabindex="0">
<div class="dq-card-icon" onclick="location.href='#data-quality'" role="button" tabindex="0">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
</div>
<h3>Accuracy standards</h3>
<p>Every field observation is held to explicit accuracy requirements before it is admitted into the pipeline. Rejection rates are tracked and published internally as quality metrics.</p>
<ul class="dq-standards">
<li>Geo-location verified against reported coordinates</li>
<li>Photograph metadata validated (device, timestamp, GPS)</li>
<li>Submission reviewed by AI against mission brief</li>
<li>Duplicate detection across concurrent contributors</li>
<li>Outlier flagging when observation deviates significantly from area baseline</li>
</ul>
</div>
<div class="dq-card" onclick="location.href='#data-quality'" role="button" tabindex="0">
<div class="dq-card-icon" onclick="location.href='#data-quality'" role="button" tabindex="0">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
</div>
<h3>Verification chain</h3>
<p>Every observation has a complete audit trail. From contributor identity through submission review to final score contribution, every step is logged and immutable.</p>
<ul class="dq-standards">
<li>Contributor identity verified once, applied to all submissions</li>
<li>Submission hash logged at ingestion (tamper detection)</li>
<li>Review decision and reviewer logged with timestamp</li>
<li>Score contribution traceable back to source observations</li>
<li>Contradiction reports include full evidence chain on both sides</li>
</ul>
</div>
<div class="dq-card" onclick="location.href='#data-quality'" role="button" tabindex="0">
<div class="dq-card-icon" onclick="location.href='#data-quality'" role="button" tabindex="0">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
</div>
<h3>Confidence scoring</h3>
<p>Every score, conclusion, and contradiction report carries a numerical confidence value. Confidence is calculated from evidence volume, recency, and source diversity &mdash; not subjective assessment.</p>
<ul class="dq-standards">
<li>Volume factor: more observations &rarr; higher confidence</li>
<li>Recency factor: older data decays on configurable half-life</li>
<li>Diversity factor: independent sources weighted above correlated ones</li>
<li>Contradiction penalty: conflicting evidence reduces confidence proportionally</li>
<li>All confidence values expressed numerically (0&ndash;100)</li>
</ul>
</div>
</div>
</div>
</section>
<!-- CONTRADICTION FLOW DIAGRAM -->
<section class="flow-section" id="contradiction-flow">
<div class="lv-container">
<div class="lv-text-center">
<div class="section-label">Contradiction Engine</div>
<h2 class="section-title">How we detect contradictions.</h2>
<p class="section-sub">A six-step pipeline that runs continuously against every area with active observation coverage. When official data and observed reality disagree, this is what happens.</p>
</div>
<div class="flow-diagram">
<!-- Step 1 -->
<div class="flow-node flow-trigger">
<div class="flow-node-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#5599ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
</div>
<div class="flow-node-text">
<h4>1. New field observations ingested</h4>
<p>Validated submissions enter the pipeline, tagged with location, object type, condition, and change signal</p>
</div>
</div>
<div class="flow-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v20M2 14l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<!-- Step 2 -->
<div class="flow-node">
<div class="flow-node-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#888" stroke-width="2" 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>
</div>
<div class="flow-node-text">
<h4>2. Official data sources queried for same geography</h4>
<p>National statistics, municipal open data, land registries, and permit databases are checked for the affected area</p>
</div>
</div>
<div class="flow-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v20M2 14l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<!-- Step 3 -->
<div class="flow-node flow-detect">
<div class="flow-node-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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 class="flow-node-text">
<h4>3. Contradiction detection: observed vs. official</h4>
<p>AI model compares observed conditions against official claims on matching dimensions (vacancy, activity, condition, growth)</p>
</div>
</div>
<div class="flow-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v20M2 14l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<!-- Step 4: split -->
<div class="flow-split-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v12M2 6l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div class="flow-split">
<div class="flow-node">
<div class="flow-node-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
</div>
<div class="flow-node-text">
<h4>No contradiction</h4>
<p>Evidence supports official data &rarr; confidence score updated upward</p>
</div>
</div>
<div class="flow-node flow-rank">
<div class="flow-node-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</div>
<div class="flow-node-text">
<h4>Contradiction detected</h4>
<p>Divergence ranked by severity and economic significance</p>
</div>
</div>
</div>
<div class="flow-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v20M2 14l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<!-- Step 5 -->
<div class="flow-node flow-redteam">
<div class="flow-node-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#a78bfa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<div class="flow-node-text">
<h4>5. Red Team challenge</h4>
<p>Second AI model attempts to disprove the contradiction with alternative explanations. Conclusion revised or confirmed.</p>
</div>
</div>
<div class="flow-arrow">
<svg width="16" height="24" viewBox="0 0 16 24" fill="none"><path d="M8 0v20M2 14l6 8 6-8" stroke="rgba(0,0,0,0.3)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<!-- Step 6 -->
<div class="flow-node flow-output">
<div class="flow-node-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-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"/><polyline points="10 9 9 9 8 9"/></svg>
</div>
<div class="flow-node-text">
<h4>6. Contradiction Report delivered</h4>
<p>Client receives: finding, supporting evidence, contradicting evidence, severity rank, confidence score (0&ndash;100)</p>
</div>
</div>
</div>
</div>
</section>
<!-- CTA BAND -->
<section class="cta-band">
<h2>Ready to see it applied<br>to your decision?</h2>
<p>Tell us the question you need answered. We'll show you how Landvex can support it.</p>
<a class="btn btn-white btn-lg" href="https://landvex.com/#contact">Request a briefing →</a>
</section>
<!-- FOOTER -->
<!-- AMOS & AI Validation -->
<section>
<div>
<div>Analysis Engine</div>
<h2>AMOS — Automated Multi-source Observation System</h2>
<p>
AMOS is the Landvex AI analysis engine. It receives validated field observations from the quiXzoom network,
cross-references them against official datasets and historical baselines, and produces the index scores,
contradiction flags and trend signals delivered to clients. AMOS does not generate or fabricate data —
it analyses, scores and flags discrepancies in what has been observed.
</p>
<div>
<div>
<div>What AMOS does</div>
<ul>
<li>Cross-references field observations with official statistics</li>
<li>Scores geographic areas on standardised 0100 index dimensions</li>
<li>Flags contradictions between reported and observed reality</li>
<li>Generates trend signals from change patterns in field data</li>
</ul>
</div>
<div>
<div>What AMOS does not do</div>
<ul>
<li>Generate or invent observations not in field data</li>
<li>Make financial investment decisions</li>
<li>Replace engineering or safety inspections</li>
<li>Produce legally binding assessments</li>
</ul>
</div>
</div>
<div>
<div>AI Red Team</div>
<p>
Every AMOS contradiction flag is independently challenged by a second model before delivery.
The Red Team model is tasked with disproving the primary finding — a flag is only delivered
when it survives this adversarial check. This reduces false positives in contradiction detection.
Model performance metrics and Red Team rejection rates are available to enterprise clients under NDA:
<a href="mailto:enterprise@landvex.com" >enterprise@landvex.com</a>
</p>
</div>
</div>
</section>
<footer class="lv-footer" role="contentinfo">
<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="https://www.quixzoom.com/" target="_blank" rel="noopener">quiXzoom →</a>
<a href="https://www.quixzoom.com/for-organisations/">For organisations</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>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=/contact/">
<title>Landvex Pilot — Redirecting</title>
<link rel="canonical" href="https://landvex.com/contact/">
</head>
<body>
<p>Redirecting to <a href="/contact/">Contact</a>...</p>
</body>
</html>
+258
View File
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Landvex Privacy Policy — how we process personal data in our decision-intelligence platform. GDPR compliant.">
<title>Privacy Policy — Landvex</title>
<link rel="canonical" href="https://landvex.com/privacy/">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta name="robots" content="index, follow">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif; background: #fff; color: #1d1d1f; line-height: 1.7; }
nav { height: 56px; border-bottom: 1px solid #e5e5e7; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; position: sticky; top: 0; background: rgba(255,255,255,0.92); backdrop-filter: blur(12px); z-index: 100; }
.logo { font-size: 17px; font-weight: 700; color: #1d1d1f; text-decoration: none; letter-spacing: -0.3px; }
.logo span { color: #0066cc; }
.nav-back { font-size: 14px; color: #0066cc; text-decoration: none; }
.draft-banner { background: #fff3cd; border-bottom: 1px solid #ffc107; padding: 24px; font-size: 13px; color: #664d03; text-align: center; }
main { max-width: 760px; margin: 0 auto; padding: 24px 80px; }
h1 { font-size: clamp(24px, 4vw, 36px); font-weight: 700; letter-spacing: -0.5px; margin-bottom: 8px; }
.meta { font-size: 13px; color: #6e6e73; margin-bottom: 40px; }
h2 { font-size: 18px; font-weight: 600; margin: 36px 0 12px; color: #1d1d1f; }
p { margin-bottom: 14px; font-size: 15px; color: #3a3a3c; }
ul { margin: 0 0 14px 20px; font-size: 15px; color: #3a3a3c; }
ul li { margin-bottom: 6px; }
table { width: 100%; border-collapse: collapse; margin: 16px 0 24px; font-size: 13px; }
th { background: #f5f5f7; padding: 24px; text-align: left; font-weight: 600; border-bottom: 2px solid #e5e5e7; }
td { padding: 24px; border-bottom: 1px solid #1a1a1a; vertical-align: top; }
.highlight { background: #f5f5f7; border-radius: 10px; padding: 24px; margin: 20px 0; font-size: 14px; }
.highlight p { margin-bottom: 0; font-size: 14px; }
footer { border-top: 1px solid #e5e5e7; padding: 24px; text-align: center; font-size: 13px; color: #6e6e73; }
footer a { color: #0066cc; text-decoration: none; }
a { color: #0066cc; }
@media (max-width: 600px) { main { padding: 24px 60px; } table { font-size: 12px; } }
</style>
<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>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": [
"Organization",
"Corporation"
],
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"alternateName": [
"LandveX",
"Landvex AB",
"LandveX AB"
],
"url": "https://landvex.com",
"logo": {
"@type": "ImageObject",
"url": "https://landvex.com/apple-touch-icon.png",
"width": 180,
"height": 180
},
"foundingDate": "2024",
"foundingLocation": {
"@type": "Place",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
},
"legalName": "Landvex Inc",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
},
"location": [
{
"@type": "Place",
"name": "Houston, Texas, USA (US HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
}
},
{
"@type": "Place",
"name": "Tyresö, Sweden (EU HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
}
}
],
"taxID": "pending-EIN",
"description": "Landvex is a decision intelligence company that identifies contradictions between official narratives and observed physical reality. Using the quiXzoom field observation network and the AMOS AI analysis engine, Landvex delivers infrastructure risk indexes, urban intelligence scores, and contradiction reports to infrastructure owners, municipalities, enterprises, and investors globally.",
"disambiguatingDescription": "Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European headquarters in Tyresö, Sweden (Landvex AB, org.nr 559141-7042). Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors. Landvex is not a UK meat wholesaler, food distributor, logistics company, package tracker, or land investment platform.",
"knowsAbout": [
"control intelligence",
"decision intelligence",
"infrastructure risk assessment",
"urban intelligence",
"field data collection",
"contradiction detection",
"physical world analytics",
"geospatial analytics"
],
"brand": {
"@type": "Brand",
"name": "Landvex",
"slogan": "Control intelligence for the physical world."
},
"sameAs": [
"https://landvex.com",
"https://www.linkedin.com/company/landvex",
"https://x.com/landvex",
"https://twitter.com/landvex",
"https://www.crunchbase.com/organization/landvex",
"https://github.com/landvex",
"https://www.instagram.com/landvex"
],
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@landvex.com",
"contactType": "sales"
},
"slogan": "Where reported reality conflicts with observed reality."
}
</script>
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>privacy</span>
</nav>
<nav aria-label="Main navigation">
<a href="/" class="logo">Land<span>vex</span></a>
<a href="/" class="nav-back">← Landvex</a>
</nav>
<div class="draft-banner">
<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> <strong>Draft notice:</strong> This policy is a working draft pending review by qualified data-protection counsel. It is published for transparency. Final version will be published before commercial launch (target: 1 August 2026).
</div>
<main>
<h1>Privacy Policy</h1>
<p class="meta">Last updated: 24 June 2026 &nbsp;·&nbsp; Version 0.1 (draft — pending legal review)</p>
<h2>1. Who we are</h2>
<p>This Policy is issued by:</p>
<ul>
<li><strong>Landvex AB</strong>, org.nr 559141-7042, Tyresö, Sweden ("<strong>Landvex EU</strong>") — data controller for individuals in the EEA, UK, and Switzerland</li>
<li><strong>Landvex Inc.</strong>, a Texas corporation, Houston, TX, USA ("<strong>Landvex US</strong>") — data controller for individuals in North America</li>
</ul>
<p>Contact: <a href="mailto:privacy@landvex.com">privacy@landvex.com</a></p>
<h2>2. Scope</h2>
<p>This Policy explains how Landvex processes personal data when:</p>
<ul>
<li>(a) operating landvex.com and responding to enquiries</li>
<li>(b) providing decision-intelligence products to organisations</li>
<li>(c) processing field-observation data sourced from the quiXzoom network that may contain personal data of third parties</li>
</ul>
<h2>3. Data we process</h2>
<table>
<thead>
<tr>
<th>Category</th>
<th>Examples</th>
<th>Source</th>
<th>Purpose</th>
<th>Legal basis</th>
</tr>
</thead>
<tbody>
<tr>
<td>Business contact data</td>
<td>Name, role, email, organisation</td>
<td>You</td>
<td>Services, billing, communications</td>
<td>Contract / legitimate interests</td>
</tr>
<tr>
<td>Website data</td>
<td>IP address, device info, cookies</td>
<td>Your device</td>
<td>Security, analytics</td>
<td>Consent / legitimate interests</td>
</tr>
<tr>
<td>Field-observation data</td>
<td>Imagery that may incidentally capture individuals, vehicle plates, or premises; geolocation metadata</td>
<td>Licensed from quiXzoom Inc.</td>
<td>Place-level intelligence only — not individual profiling</td>
<td>Legitimate interests</td>
</tr>
</tbody>
</table>
<h2>4. Field imagery safeguards</h2>
<p>Landvex applies the following safeguards to field-observation data:</p>
<ul>
<li>(a) <strong>Data minimisation</strong> — analysis is scoped to physical assets and locations, not individuals</li>
<li>(b) <strong>Obscuration</strong> — automated blurring of faces and vehicle registration plates [<em>implementation status subject to confirmation</em>]</li>
<li>(c) <strong>Purpose limitation</strong> — imagery is used for place-level intelligence only; no individual profiling</li>
<li>(d) <strong>Retention limits</strong> — as described in §8 below</li>
<li>(e) <strong>Right to object</strong> — available as described in §7 below</li>
</ul>
<h2>5. Recipients</h2>
<p>Personal data may be shared with:</p>
<ul>
<li>Customers (under a data processing agreement or controller-to-controller terms)</li>
<li>Sub-processors (see the <a href="/subprocessors/">Sub-processor Register</a>)</li>
<li>quiXzoom Inc. (data source, under a data sharing agreement)</li>
<li>Professional advisers (legal, accounting) bound by confidentiality obligations</li>
</ul>
<p><strong>We do not sell personal data.</strong></p>
<h2>6. International transfers</h2>
<p>Data may be transferred between Landvex AB (Sweden) and Landvex Inc. (USA) and to sub-processors in third countries. EEA transfers rely on the European Commission's Standard Contractual Clauses (SCCs) and supplementary technical and organisational measures.</p>
<h2>7. Your rights</h2>
<p>Under applicable data protection law you may have rights of access, rectification, erasure, restriction of processing, data portability, and objection. To exercise any right, contact: <a href="mailto:privacy@landvex.com">privacy@landvex.com</a>.</p>
<p>If you are located in Sweden or the EEA, you may also lodge a complaint with the Swedish supervisory authority: <a href="https://www.imy.se" target="_blank" rel="noopener noreferrer">IMY (imy.se)</a>.</p>
<h2>8. Retention</h2>
<ul>
<li><strong>Business contact data:</strong> duration of relationship + 3 years</li>
<li><strong>Website data:</strong> 12 months</li>
<li><strong>Field imagery:</strong> <em>subject to legal review — will be confirmed before commercial launch</em></li>
</ul>
<h2>9. Contact</h2>
<div class="highlight">
<p>
<strong>Privacy enquiries:</strong> <a href="mailto:privacy@landvex.com">privacy@landvex.com</a><br>
<strong>Security disclosures:</strong> <a href="mailto:security@landvex.com">security@landvex.com</a><br>
<strong>Landvex AB</strong> · org.nr 559141-7042 · Tyresö, Sweden
</p>
</div>
</main>
<footer class="lv-footer" role="contentinfo">
<p>© 2026 Landvex AB · org.nr 559141-7042 · Tyresö, Sweden · <a href="/privacy/">Privacy</a> · <a href="/terms/">Terms</a> · <a href="/subprocessors/">Sub-processors</a> · <a href="/dpa/">DPA</a></p>
</footer>
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
Remove hreflang tags that point to dead domains.
"""
import os
import re
def remove_hreflang(filepath):
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
original = content
# Remove hreflang link tags
content = re.sub(r'\s*<link rel="alternate" hreflang="[^"]+" href="https://landvex\.(se|de|fr|co\.uk)/">\n?', '', content)
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def main():
base_dir = "/home/bernt/.openclaw/workspace/landvex-all"
count = 0
for root, dirs, files in os.walk(base_dir):
for file in files:
if file.endswith('.html'):
filepath = os.path.join(root, file)
if remove_hreflang(filepath):
count += 1
rel_path = os.path.relpath(filepath, base_dir)
print(f"Removed hreflang: {rel_path}")
print(f"\nDone: Removed hreflang from {count} files")
if __name__ == "__main__":
main()
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
Remove /verticals/ links from city pages and use-cases since it redirects to /.
"""
import os
import re
def remove_verticals_link(filepath):
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
original = content
# Remove Verticals link from nav
content = re.sub(r'\s*<a href="/verticals/">Verticals</a>\s*\n?', '\n', content)
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def main():
base_dir = "/home/bernt/.openclaw/workspace/landvex-all"
count = 0
# Process cities and use-cases directories
for subdir in ['cities', 'use-cases']:
dir_path = os.path.join(base_dir, subdir)
if os.path.exists(dir_path):
for root, dirs, files in os.walk(dir_path):
for file in files:
if file.endswith('.html'):
filepath = os.path.join(root, file)
if remove_verticals_link(filepath):
count += 1
rel_path = os.path.relpath(filepath, base_dir)
print(f"Removed /verticals/ link: {rel_path}")
print(f"\nDone: Removed /verticals/ links from {count} files")
if __name__ == "__main__":
main()
+643
View File
@@ -0,0 +1,643 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Intelligence Reports — Landvex</title>
<meta name="description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<link rel="canonical" href="https://landvex.com/reports/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/reports/">
<meta property="og:title" content="Intelligence Reports — Landvex">
<meta property="og:description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Intelligence Reports — Landvex">
<meta name="twitter:description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<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">
<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-light: #1d1d1f;
--text-muted: #6B6B6B;
--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 */
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, .nav-links a.active { color: #1d1d1f; }
.nav-dropdown { position: relative; }
.nav-dropdown > a { display: flex; align-items: center; gap: 16px; cursor: pointer; }
.nav-dropdown > a::after {
content: ''; display: inline-block; width: 0; height: 0;
border-left: 4px solid transparent; border-right: 4px solid transparent;
border-top: 4px solid currentColor;
opacity: 0.55; margin-top: 1px; transition: transform 0.2s;
}
.nav-dropdown:hover > a::after, .nav-dropdown:focus-within > a::after { transform: rotate(180deg); }
.nav-dropdown-menu {
display: none; position: absolute; top: calc(100% + 12px); left: 50%;
transform: translateX(-50%);
background: rgba(255,255,255,0.97);
border: 1px solid var(--border); border-radius: var(--radius-md);
padding: 8px 0; min-width: 200px;
box-shadow: 0 16px 40px rgba(0,0,0,0.5); z-index: 200;
backdrop-filter: blur(12px);
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu { display: block; }
.nav-dropdown-menu a {
display: flex; align-items: center; gap: 16px;
padding: 24px; font-size: 14px; color: var(--text-dim);
transition: color 0.15s, background 0.15s; white-space: nowrap;
}
.nav-dropdown-menu a:hover { color: #1d1d1f; background: rgba(0,0,0,0.03); }
.nav-dropdown-menu .dd-label {
font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: rgba(0,0,0,0.75);
padding: 24px 4px; cursor: default;
}
.nav-dropdown-menu hr { border: none; border-top: 1px solid var(--border); margin: 6px 0; }
.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 */
.hero {
min-height: 60vh;
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(40px, 6vw, 68px); font-weight: 800;
letter-spacing: -2px; line-height: 1.05; color: #1d1d1f;
max-width: 780px; margin-bottom: 24px;
}
.hero-sub {
font-size: clamp(16px, 2vw, 19px); color: var(--text-dim);
max-width: 580px; line-height: 1.65; margin-bottom: 40px;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
/* SECTIONS */
section { padding: 24px; }
.section-alt { background: var(--surface); }
.container { max-width: 1140px; margin: 0 auto; }
.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, 42px); font-weight: 800;
letter-spacing: -1.2px; line-height: 1.1; color: #1d1d1f; margin-bottom: 24px;
}
.section-sub { font-size: 17px; color: var(--text-dim); max-width: 560px; line-height: 1.7; }
.section-header { margin-bottom: 56px; }
.section-header-center { text-align: center; }
.section-header-center .section-sub { margin: 0 auto; }
/* REPORT CARDS */
.reports-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.report-card {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
display: flex; flex-direction: column;
transition: border-color 0.25s, transform 0.2s;
cursor: pointer;
}
.report-card:hover { border-color: rgba(0,102,255,0.4); transform: translateY(-3px); }
.report-card.coming-soon {
opacity: 0.5;
cursor: default;
pointer-events: none;
}
.report-icon {
width: 44px; height: 44px;
background: var(--blue-glow);
border: 1px solid rgba(0,102,255,0.2);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
margin-bottom: 20px;
}
.report-card.coming-soon .report-icon {
background: rgba(0,0,0,0.04);
border-color: rgba(0,0,0,0.08);
}
.report-tag {
display: inline-block; font-size: 11px; font-weight: 700;
letter-spacing: 0.08em; text-transform: uppercase;
padding: 24px; border-radius: 100px;
margin-bottom: 14px; align-self: flex-start;
}
.report-tag.available {
background: rgba(0,102,255,0.12);
color: #5599ff;
border: 1px solid rgba(0,102,255,0.25);
}
.report-tag.soon {
background: rgba(0,0,0,0.04);
color: rgba(0,0,0,0.75);
border: 1px solid rgba(0,0,0,0.1);
}
.report-card h3 { font-size: 17px; font-weight: 700; color: #1d1d1f; margin-bottom: 10px; line-height: 1.3; }
.report-card p { font-size: 14px; color: var(--text-dim); line-height: 1.6; flex: 1; }
.report-card .report-footer {
margin-top: 20px; padding-top: 16px;
border-top: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.report-card .report-action {
font-size: 13px; font-weight: 700; color: var(--blue);
}
.report-card .report-date {
font-size: 12px; color: var(--text-dim);
}
/* COMING SOON GRID */
.coming-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
/* CTA BANNER */
.cta-banner {
background: #0a0f1a;
border: 1px solid rgba(0,102,255,0.2);
border-radius: var(--radius-lg);
padding: 24px; text-align: center;
position: relative; overflow: hidden;
}
.cta-banner::before {
content: ''; position: absolute;
top: -100px; left: 50%; transform: translateX(-50%);
width: 600px; height: 300px;
background: radial-gradient(ellipse, rgba(0,102,255,0.12) 0%, transparent 70%);
pointer-events: none;
}
.cta-banner .cta-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: #5599ff; margin-bottom: 24px;
}
.cta-banner h2 {
font-size: clamp(26px, 3.5vw, 40px); font-weight: 800;
letter-spacing: -1px; color: #1d1d1f; margin-bottom: 24px;
}
.cta-banner p {
font-size: 16px; color: var(--text-dim); max-width: 480px;
margin: 0 auto 32px; line-height: 1.65;
}
/* CONTACT */
.contact-wrapper { max-width: 680px; margin: 0 auto; text-align: center; }
.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, .form-group select {
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 select option { background: #f5f5f7; }
.form-group input:focus, .form-group textarea:focus, .form-group select: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 */
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: 8px;
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); }
svg { max-width: 100%; overflow: visible; }
.report-icon svg { overflow: hidden; flex-shrink: 0; }
@media (max-width: 900px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
.reports-grid { grid-template-columns: 1fr 1fr; }
.coming-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
section { padding: 56px 0; }
.hero { padding: 24px 60px; }
.hero-ctas { flex-direction: column; }
.reports-grid { grid-template-columns: 1fr; }
.coming-grid { grid-template-columns: 1fr 1fr; }
.form-row { grid-template-columns: 1fr; }
.contact-form { padding: 24px; }
.cta-banner { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
}
@media (max-width: 480px) {
.coming-grid { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
.container { padding: 0 16px !important; box-sizing: border-box; }
section { padding: 48px 0 !important; }
.hero-ctas { flex-direction: column !important; gap: 16px; }
.hero-ctas a { width: 100% !important; text-align: center !important; }
}
</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": "Reports",
"item": "https://landvex.com/reports/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>reports</span>
</nav>
<!-- 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 class="nav-dropdown">
<a href="/methodology/">Intelligence</a>
<div class="nav-dropdown-menu">
<div class="dd-label">Learn</div>
<a href="/methodology/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Methodology
</a>
<hr/>
<div class="dd-label">Products</div>
<a href="/enterprise/">Enterprise</a>
<a href="/reports/" >Intelligence Reports</a>
<a href="/pilot/">Pilot Programme</a>
<hr/>
<a href="/security/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Security
</a>
</div>
</li>
<li><a href="/enterprise/">Enterprise</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="#contact">Get in touch</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Reports
</div>
<h1>Intelligence reports and research.</h1>
<p class="lv-hero-subtitle">Landvex intelligence reports combine field observations, official data, and AI analysis into structured decision-ready outputs. Available to enterprise clients on request.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="#contact">Request any report</a>
<a class="btn btn-outline btn-lg" href="/enterprise/">Enterprise access</a>
</div>
</section>
<!-- AVAILABLE REPORTS -->
<section class="section-alt">
<div class="lv-container">
<div class="section-header">
<div class="section-label">Available now</div>
<h2 class="section-title">Available intelligence reports.</h2>
<p class="section-sub">Published reports available to enterprise clients. Request access below.</p>
</div>
<div class="reports-grid">
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
</div>
<span class="report-tag available">Available</span>
<h3>Stockholm City Intelligence Report</h3>
<p>District-level scoring across 8 Stockholm districts. Commercial vitality, infrastructure condition, growth velocity. Sourced from field observations and official data cross-reference.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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>
<span class="report-tag available">Available</span>
<h3>Infrastructure Risk Methodology</h3>
<p>How Landvex scores infrastructure risk from field observations and official maintenance data. Covers scoring model, data sources, validation process, and confidence framework.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
</div>
<span class="report-tag available">Available</span>
<h3>Urban Change Detection Guide</h3>
<p>How the Contradiction Engine identifies conflicts between official narratives and observed reality. Methodology, case studies, and interpretation guidance for analysts and investment teams.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
</div>
</div>
</section>
<!-- COMING SOON -->
<section>
<div class="lv-container">
<div class="section-header">
<div class="section-label">Forthcoming</div>
<h2 class="section-title">Intelligence reports in production.</h2>
<p class="section-sub">Research and field collection currently underway. Subscribers receive access on publication.</p>
</div>
<div class="coming-grid">
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
</div>
<span class="report-tag soon">Q3 2026</span>
<h3>Berlin City Intelligence Report</h3>
<p>District-level scoring across Berlin. Commercial vitality, infrastructure condition, and development pressure.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
</div>
<span class="report-tag soon">Q3 2026</span>
<h3>Retail Opportunity Report: Stockholm</h3>
<p>Location-level retail opportunity scoring across Stockholm. Foot traffic analysis, vacancy rates, and competitive density.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
</div>
<span class="report-tag soon">Q4 2026</span>
<h3>European Infrastructure Risk Benchmark</h3>
<p>Comparative infrastructure risk scoring across 12 European cities. Cross-country benchmarking for asset managers and insurers.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
</div>
<span class="report-tag soon">Q4 2026</span>
<h3>Investment Outlook: Nordic Cities</h3>
<p>Growth velocity, infrastructure condition, and commercial opportunity across Copenhagen, Helsinki, Oslo, and Stockholm.</p>
</div>
</div>
</div>
</section>
<!-- CTA BANNER -->
<section class="lv-section">
<div class="lv-container">
<div class="cta-banner">
<div class="cta-label">Access the library</div>
<h2>Request any report.</h2>
<p>Available reports are delivered within one business day to verified organisations. Forthcoming reports are available for pre-registration.</p>
<a class="lv-btn lv-btn--lg" href="#contact">Request any report</a>
</div>
</div>
</section>
<!-- CONTACT -->
<section id="contact">
<div class="lv-container">
<div class="contact-wrapper">
<div class="section-label">Request</div>
<h2 class="section-title">Request a report.</h2>
<p class="section-sub">Tell us which report you need and we will arrange access. Enterprise clients receive all available reports.</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="org">Organisation</label>
<input type="text" id="org" name="organisation" placeholder="Your organisation" required>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@organisation.com" required>
</div>
<div class="form-group">
<label for="report">Report requested</label>
<select id="report" name="report">
<option value="">Select a report</option>
<option value="stockholm-city">Stockholm City Intelligence Report</option>
<option value="infra-methodology">Infrastructure Risk Methodology</option>
<option value="change-detection">Urban Change Detection Guide</option>
<option value="berlin-city">Berlin City Intelligence Report (pre-register)</option>
<option value="retail-stockholm">Retail Opportunity Report: Stockholm (pre-register)</option>
<option value="eu-infra-benchmark">European Infrastructure Risk Benchmark (pre-register)</option>
<option value="nordic-outlook">Investment Outlook: Nordic Cities (pre-register)</option>
<option value="all">All available reports</option>
</select>
</div>
<div class="form-group">
<label for="message">How you intend to use it (optional)</label>
<textarea id="message" name="message" placeholder="Brief context on your organisation and intended use helps us provide the most relevant materials."></textarea>
</div>
<button type="submit" class="lv-btn lv-btn--lg">Request report access</button>
<p class="form-note">Available reports are delivered within one business day. Your information stays private.</p>
<div id="form-message"></div>
</form>
</div>
</div>
</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 &middot; 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="/security/">Security</a>
<a href="/enterprise/">Enterprise</a>
<a href="/reports/">Reports</a>
<a href="/pilot/">Pilot</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>
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-reports',
name: this.name.value,
organisation: this.organisation.value,
email: this.email.value,
report: this.report ? this.report.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 = "Request received. We will arrange access 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 report access';
});
</script>
</body>
</html>
+643
View File
@@ -0,0 +1,643 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Intelligence Reports — Landvex</title>
<meta name="description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<link rel="canonical" href="https://landvex.com/reports/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/reports/">
<meta property="og:title" content="Intelligence Reports — Landvex">
<meta property="og:description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Intelligence Reports — Landvex">
<meta name="twitter:description" content="Landvex intelligence reports — district-level scoring, infrastructure risk methodology, and urban change detection. Available on request.">
<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">
<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-light: #1d1d1f;
--text-muted: #6B6B6B;
--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 */
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, .nav-links a.active { color: #1d1d1f; }
.nav-dropdown { position: relative; }
.nav-dropdown > a { display: flex; align-items: center; gap: 16px; cursor: pointer; }
.nav-dropdown > a::after {
content: ''; display: inline-block; width: 0; height: 0;
border-left: 4px solid transparent; border-right: 4px solid transparent;
border-top: 4px solid currentColor;
opacity: 0.55; margin-top: 1px; transition: transform 0.2s;
}
.nav-dropdown:hover > a::after, .nav-dropdown:focus-within > a::after { transform: rotate(180deg); }
.nav-dropdown-menu {
display: none; position: absolute; top: calc(100% + 12px); left: 50%;
transform: translateX(-50%);
background: rgba(255,255,255,0.97);
border: 1px solid var(--border); border-radius: var(--radius-md);
padding: 8px 0; min-width: 200px;
box-shadow: 0 16px 40px rgba(0,0,0,0.5); z-index: 200;
backdrop-filter: blur(12px);
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu { display: block; }
.nav-dropdown-menu a {
display: flex; align-items: center; gap: 16px;
padding: 24px; font-size: 14px; color: var(--text-dim);
transition: color 0.15s, background 0.15s; white-space: nowrap;
}
.nav-dropdown-menu a:hover { color: #1d1d1f; background: rgba(0,0,0,0.03); }
.nav-dropdown-menu .dd-label {
font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: rgba(0,0,0,0.75);
padding: 24px 4px; cursor: default;
}
.nav-dropdown-menu hr { border: none; border-top: 1px solid var(--border); margin: 6px 0; }
.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 */
.hero {
min-height: 60vh;
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(40px, 6vw, 68px); font-weight: 800;
letter-spacing: -2px; line-height: 1.05; color: #1d1d1f;
max-width: 780px; margin-bottom: 24px;
}
.hero-sub {
font-size: clamp(16px, 2vw, 19px); color: var(--text-dim);
max-width: 580px; line-height: 1.65; margin-bottom: 40px;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; }
/* SECTIONS */
section { padding: 24px; }
.section-alt { background: var(--surface); }
.container { max-width: 1140px; margin: 0 auto; }
.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, 42px); font-weight: 800;
letter-spacing: -1.2px; line-height: 1.1; color: #1d1d1f; margin-bottom: 24px;
}
.section-sub { font-size: 17px; color: var(--text-dim); max-width: 560px; line-height: 1.7; }
.section-header { margin-bottom: 56px; }
.section-header-center { text-align: center; }
.section-header-center .section-sub { margin: 0 auto; }
/* REPORT CARDS */
.reports-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.report-card {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
display: flex; flex-direction: column;
transition: border-color 0.25s, transform 0.2s;
cursor: pointer;
}
.report-card:hover { border-color: rgba(0,102,255,0.4); transform: translateY(-3px); }
.report-card.coming-soon {
opacity: 0.5;
cursor: default;
pointer-events: none;
}
.report-icon {
width: 44px; height: 44px;
background: var(--blue-glow);
border: 1px solid rgba(0,102,255,0.2);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
margin-bottom: 20px;
}
.report-card.coming-soon .report-icon {
background: rgba(0,0,0,0.04);
border-color: rgba(0,0,0,0.08);
}
.report-tag {
display: inline-block; font-size: 11px; font-weight: 700;
letter-spacing: 0.08em; text-transform: uppercase;
padding: 24px; border-radius: 100px;
margin-bottom: 14px; align-self: flex-start;
}
.report-tag.available {
background: rgba(0,102,255,0.12);
color: #5599ff;
border: 1px solid rgba(0,102,255,0.25);
}
.report-tag.soon {
background: rgba(0,0,0,0.04);
color: rgba(0,0,0,0.75);
border: 1px solid rgba(0,0,0,0.1);
}
.report-card h3 { font-size: 17px; font-weight: 700; color: #1d1d1f; margin-bottom: 10px; line-height: 1.3; }
.report-card p { font-size: 14px; color: var(--text-dim); line-height: 1.6; flex: 1; }
.report-card .report-footer {
margin-top: 20px; padding-top: 16px;
border-top: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.report-card .report-action {
font-size: 13px; font-weight: 700; color: var(--blue);
}
.report-card .report-date {
font-size: 12px; color: var(--text-dim);
}
/* COMING SOON GRID */
.coming-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
/* CTA BANNER */
.cta-banner {
background: #0a0f1a;
border: 1px solid rgba(0,102,255,0.2);
border-radius: var(--radius-lg);
padding: 24px; text-align: center;
position: relative; overflow: hidden;
}
.cta-banner::before {
content: ''; position: absolute;
top: -100px; left: 50%; transform: translateX(-50%);
width: 600px; height: 300px;
background: radial-gradient(ellipse, rgba(0,102,255,0.12) 0%, transparent 70%);
pointer-events: none;
}
.cta-banner .cta-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: #5599ff; margin-bottom: 24px;
}
.cta-banner h2 {
font-size: clamp(26px, 3.5vw, 40px); font-weight: 800;
letter-spacing: -1px; color: #1d1d1f; margin-bottom: 24px;
}
.cta-banner p {
font-size: 16px; color: var(--text-dim); max-width: 480px;
margin: 0 auto 32px; line-height: 1.65;
}
/* CONTACT */
.contact-wrapper { max-width: 680px; margin: 0 auto; text-align: center; }
.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, .form-group select {
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 select option { background: #f5f5f7; }
.form-group input:focus, .form-group textarea:focus, .form-group select: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 */
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: 8px;
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); }
svg { max-width: 100%; overflow: visible; }
.report-icon svg { overflow: hidden; flex-shrink: 0; }
@media (max-width: 900px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
.reports-grid { grid-template-columns: 1fr 1fr; }
.coming-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
section { padding: 56px 0; }
.hero { padding: 24px 60px; }
.hero-ctas { flex-direction: column; }
.reports-grid { grid-template-columns: 1fr; }
.coming-grid { grid-template-columns: 1fr 1fr; }
.form-row { grid-template-columns: 1fr; }
.contact-form { padding: 24px; }
.cta-banner { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
}
@media (max-width: 480px) {
.coming-grid { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
.container { padding: 0 16px !important; box-sizing: border-box; }
section { padding: 48px 0 !important; }
.hero-ctas { flex-direction: column !important; gap: 16px; }
.hero-ctas a { width: 100% !important; text-align: center !important; }
}
</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": "Reports",
"item": "https://landvex.com/reports/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>reports</span>
</nav>
<!-- 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 class="nav-dropdown">
<a href="/methodology/">Intelligence</a>
<div class="nav-dropdown-menu">
<div class="dd-label">Learn</div>
<a href="/methodology/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Methodology
</a>
<hr/>
<div class="dd-label">Products</div>
<a href="/enterprise/">Enterprise</a>
<a href="/reports/" >Intelligence Reports</a>
<a href="/pilot/">Pilot Programme</a>
<hr/>
<a href="/security/">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Security
</a>
</div>
</li>
<li><a href="/enterprise/">Enterprise</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="#contact">Get in touch</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Reports
</div>
<h1>Intelligence reports and research.</h1>
<p class="lv-hero-subtitle">Landvex intelligence reports combine field observations, official data, and AI analysis into structured decision-ready outputs. Available to enterprise clients on request.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="#contact">Request any report</a>
<a class="btn btn-outline btn-lg" href="/enterprise/">Enterprise access</a>
</div>
</section>
<!-- AVAILABLE REPORTS -->
<section class="section-alt">
<div class="lv-container">
<div class="section-header">
<div class="section-label">Available now</div>
<h2 class="section-title">Available intelligence reports.</h2>
<p class="section-sub">Published reports available to enterprise clients. Request access below.</p>
</div>
<div class="reports-grid">
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
</div>
<span class="report-tag available">Available</span>
<h3>Stockholm City Intelligence Report</h3>
<p>District-level scoring across 8 Stockholm districts. Commercial vitality, infrastructure condition, growth velocity. Sourced from field observations and official data cross-reference.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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>
<span class="report-tag available">Available</span>
<h3>Infrastructure Risk Methodology</h3>
<p>How Landvex scores infrastructure risk from field observations and official maintenance data. Covers scoring model, data sources, validation process, and confidence framework.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
<a class="report-card" href="#contact">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
</div>
<span class="report-tag available">Available</span>
<h3>Urban Change Detection Guide</h3>
<p>How the Contradiction Engine identifies conflicts between official narratives and observed reality. Methodology, case studies, and interpretation guidance for analysts and investment teams.</p>
<div class="report-footer">
<span class="report-action">Download on request</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
</div>
</a>
</div>
</div>
</section>
<!-- COMING SOON -->
<section>
<div class="lv-container">
<div class="section-header">
<div class="section-label">Forthcoming</div>
<h2 class="section-title">Intelligence reports in production.</h2>
<p class="section-sub">Research and field collection currently underway. Subscribers receive access on publication.</p>
</div>
<div class="coming-grid">
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
</div>
<span class="report-tag soon">Q3 2026</span>
<h3>Berlin City Intelligence Report</h3>
<p>District-level scoring across Berlin. Commercial vitality, infrastructure condition, and development pressure.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
</div>
<span class="report-tag soon">Q3 2026</span>
<h3>Retail Opportunity Report: Stockholm</h3>
<p>Location-level retail opportunity scoring across Stockholm. Foot traffic analysis, vacancy rates, and competitive density.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
</div>
<span class="report-tag soon">Q4 2026</span>
<h3>European Infrastructure Risk Benchmark</h3>
<p>Comparative infrastructure risk scoring across 12 European cities. Cross-country benchmarking for asset managers and insurers.</p>
</div>
<div class="report-card coming-soon">
<div class="report-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.3)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
</div>
<span class="report-tag soon">Q4 2026</span>
<h3>Investment Outlook: Nordic Cities</h3>
<p>Growth velocity, infrastructure condition, and commercial opportunity across Copenhagen, Helsinki, Oslo, and Stockholm.</p>
</div>
</div>
</div>
</section>
<!-- CTA BANNER -->
<section class="lv-section">
<div class="lv-container">
<div class="cta-banner">
<div class="cta-label">Access the library</div>
<h2>Request any report.</h2>
<p>Available reports are delivered within one business day to verified organisations. Forthcoming reports are available for pre-registration.</p>
<a class="lv-btn lv-btn--lg" href="#contact">Request any report</a>
</div>
</div>
</section>
<!-- CONTACT -->
<section id="contact">
<div class="lv-container">
<div class="contact-wrapper">
<div class="section-label">Request</div>
<h2 class="section-title">Request a report.</h2>
<p class="section-sub">Tell us which report you need and we will arrange access. Enterprise clients receive all available reports.</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="org">Organisation</label>
<input type="text" id="org" name="organisation" placeholder="Your organisation" required>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@organisation.com" required>
</div>
<div class="form-group">
<label for="report">Report requested</label>
<select id="report" name="report">
<option value="">Select a report</option>
<option value="stockholm-city">Stockholm City Intelligence Report</option>
<option value="infra-methodology">Infrastructure Risk Methodology</option>
<option value="change-detection">Urban Change Detection Guide</option>
<option value="berlin-city">Berlin City Intelligence Report (pre-register)</option>
<option value="retail-stockholm">Retail Opportunity Report: Stockholm (pre-register)</option>
<option value="eu-infra-benchmark">European Infrastructure Risk Benchmark (pre-register)</option>
<option value="nordic-outlook">Investment Outlook: Nordic Cities (pre-register)</option>
<option value="all">All available reports</option>
</select>
</div>
<div class="form-group">
<label for="message">How you intend to use it (optional)</label>
<textarea id="message" name="message" placeholder="Brief context on your organisation and intended use helps us provide the most relevant materials."></textarea>
</div>
<button type="submit" class="lv-btn lv-btn--lg">Request report access</button>
<p class="form-note">Available reports are delivered within one business day. Your information stays private.</p>
<div id="form-message"></div>
</form>
</div>
</div>
</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 &middot; 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="/security/">Security</a>
<a href="/enterprise/">Enterprise</a>
<a href="/reports/">Reports</a>
<a href="/pilot/">Pilot</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>
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-reports',
name: this.name.value,
organisation: this.organisation.value,
email: this.email.value,
report: this.report ? this.report.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 = "Request received. We will arrange access 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 report access';
});
</script>
</body>
</html>
+732
View File
@@ -0,0 +1,732 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security — LandveX | Enterprise-Grade Data Security</title>
<meta name="description" content="LandveX security overview: data encryption, identity management, GDPR compliance, and operational security for enterprise customers.">
<link rel="canonical" href="https://landvex.com/security/">
<meta name="robots" content="index, follow">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/security/">
<meta property="og:title" content="Security — LandveX | Enterprise-Grade Data Security">
<meta property="og:description" content="LandveX security overview: data encryption, identity management, GDPR compliance, and operational security for enterprise customers.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Security — LandveX">
<meta name="twitter:description" content="Enterprise-grade security: TLS 1.3+, AES-256, GDPR compliance, and AWS-hosted infrastructure.">
<meta name="twitter:image" content="https://landvex.com/og-image.jpg">
<!-- 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">
<!-- Structured Data -->
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","name":"Security — LandveX","url":"https://landvex.com/security/","description":"Enterprise-grade data security at LandveX: encryption, identity, compliance and operational security.","isPartOf":{"@type":"WebSite","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-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);
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 24px;
--green: #22c55e;
--green-glow: rgba(34,197,94,0.12);
}
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 ── */
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; }
.nav-links a.active { 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; border-radius: var(--radius-md); }
/* ── HERO ── */
.hero {
min-height: 60vh;
display: flex; flex-direction: column; align-items: center; justify-content: center;
text-align: center;
padding: 24px 72px;
position: relative;
overflow: hidden;
}
/* Dekorativ bakgrund borttagen */
.hero-eyebrow {
display: inline-flex; align-items: center; gap: 16px;
background: rgba(34,197,94,0.08);
border: 1px solid rgba(34,197,94,0.2);
color: #4ade80;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 24px;
border-radius: 100px;
margin-bottom: 28px;
}
.hero h1 {
font-size: clamp(40px, 6vw, 72px);
font-weight: 800;
letter-spacing: -2px;
line-height: 1.05;
color: #1d1d1f;
max-width: 760px;
margin-bottom: 24px;
}
.hero-sub {
font-size: clamp(16px, 2vw, 19px);
color: var(--text-dim);
max-width: 580px;
line-height: 1.65;
margin-bottom: 40px;
}
/* ── TRUST BADGES ── */
.trust-bar {
display: flex; gap: 16px; flex-wrap: wrap; justify-content: center;
padding: 24px;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.trust-item {
display: flex; align-items: center; gap: 16px;
font-size: 14px; font-weight: 600; color: var(--text-dim);
}
.trust-item .icon {
width: 32px; height: 32px;
background: var(--green-glow);
border: 1px solid rgba(34,197,94,0.2);
border-radius: var(--radius-sm);
display: flex; align-items: center; justify-content: center;
font-size: 15px;
flex-shrink: 0;
}
/* ── SECTION COMMON ── */
section { padding: 24px; }
.container { max-width: 1100px; margin: 0 auto; }
.section-label {
font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase; color: var(--green);
margin-bottom: 12px;
}
.section-title {
font-size: clamp(26px, 3.5vw, 40px);
font-weight: 800;
letter-spacing: -1px;
line-height: 1.12;
color: #1d1d1f;
margin-bottom: 14px;
}
.section-sub {
font-size: 17px;
color: var(--text-dim);
max-width: 540px;
line-height: 1.7;
}
/* ── SECURITY GRID ── */
.security-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.security-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px 32px;
transition: border-color 0.25s, transform 0.2s;
}
.security-card:hover {
border-color: rgba(34,197,94,0.25);
transform: translateY(-2px);
}
.card-header {
display: flex; align-items: flex-start; gap: 16px;
margin-bottom: 28px;
}
.card-icon {
width: 48px; height: 48px;
background: var(--green-glow);
border: 1px solid rgba(34,197,94,0.2);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 22px;
flex-shrink: 0;
}
.card-title-wrap h2 {
font-size: 19px; font-weight: 800;
color: #1d1d1f; letter-spacing: -0.3px;
margin-bottom: 2px;
}
.card-title-wrap p {
font-size: 13px; color: var(--text-muted);
}
.security-items {
list-style: none;
display: flex; flex-direction: column; gap: 16px;
}
.security-items li {
display: flex; align-items: flex-start; gap: 16px;
font-size: 14.5px;
color: #c8c8c8;
line-height: 1.5;
}
.security-items li::before {
content: '✓';
color: var(--green);
font-weight: 800;
font-size: 14px;
margin-top: 1px;
flex-shrink: 0;
}
/* ── ENTERPRISE CTA ── */
.enterprise-block {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px;
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.enterprise-block .main { flex: 1; min-width: 260px; }
.enterprise-block h2 {
font-size: clamp(22px, 3vw, 32px);
font-weight: 800; color: #1d1d1f;
letter-spacing: -0.8px;
margin-bottom: 12px;
}
.enterprise-block p {
font-size: 16px; color: var(--text-dim);
max-width: 460px; line-height: 1.65;
}
.enterprise-block .actions {
display: flex; flex-direction: column; gap: 16px;
flex-shrink: 0;
}
.enterprise-block .contact-item {
display: flex; align-items: center; gap: 16px;
font-size: 14px; color: var(--text-dim);
}
.enterprise-block .contact-item strong { color: #1d1d1f; }
/* ── COMPLIANCE STRIP ── */
.compliance-strip {
background: rgba(0,102,255,0.04);
border: 1px solid rgba(0,102,255,0.12);
border-radius: var(--radius-lg);
padding: 24px;
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.compliance-badge {
display: flex; align-items: center; gap: 16px;
}
.compliance-badge .dot {
width: 8px; height: 8px;
background: var(--green);
border-radius: 50%;
box-shadow: 0 0 6px rgba(34,197,94,0.6);
flex-shrink: 0;
}
.compliance-badge span {
font-size: 14px; font-weight: 600; color: var(--text-light);
}
.compliance-divider {
width: 1px; height: 32px;
background: var(--border);
flex-shrink: 0;
}
/* ── FOOTER ── */
footer {
border-top: 1px solid var(--border);
padding: 24px;
}
.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-links { display: flex; gap: 16px; align-items: center; }
.footer-links a { font-size: 14px; color: var(--text-muted); transition: color 0.2s; }
.footer-links a:hover { color: #1d1d1f; }
.footer-tagline { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.footer-social {
width: 32px; height: 32px;
border: 1px solid var(--border);
border-radius: 8px;
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); }
/* ── RESPONSIVE ── */
@media (max-width: 900px) {
nav { padding: 0 20px; }
.nav-links { display: none; }
.security-grid { grid-template-columns: 1fr; }
.enterprise-block { padding: 24px; gap: 16px; }
.compliance-divider { display: none; }
}
@media (max-width: 600px) {
section { padding: 24px; }
.trust-bar { gap: 16px; }
.security-card { padding: 24px; }
.footer-inner { flex-direction: column; text-align: center; }
}
</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": "Security",
"item": "https://landvex.com/security/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
<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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>security</span>
</nav>
<!-- 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="/security/" class="active">Security</a></li>
<li><a href="/#contact">Contact</a></li>
</ul>
<a class="lv-btn lv-btn--outline" href="/#contact">Get in touch →</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">🔒 Enterprise Security</div>
<h1>Built secure<br>from the ground up.</h1>
<p class="lv-hero-subtitle">LandveX runs on AWS infrastructure in Stockholm, with end-to-end encryption, verified identity chains, and GDPR-compliant data handling — designed for organisations that demand it.</p>
<div>
<a class="lv-btn lv-btn--lg" href="mailto:security@landvex.com">Contact security team →</a>
<a class="btn btn-outline btn-lg" href="/#contact">Request DPA</a>
</div>
</section>
<!-- TRUST BAR -->
<div class="trust-bar">
<div class="trust-item">
<div class="icon">🔐</div>
AES-256 at rest
</div>
<div class="trust-item">
<div class="icon">🔒</div>
TLS 1.3+ in transit
</div>
<div class="trust-item">
<div class="icon">🇪🇺</div>
EU data residency
</div>
<div class="trust-item">
<div class="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>
GDPR compliant
</div>
<div class="trust-item">
<div class="icon">🏛️</div>
Hosted on AWS SOC 2 Type II infrastructure
</div>
<div class="trust-item">
<div class="icon">🛡️</div>
ISO 27001-certified infrastructure (AWS)
</div>
</div>
<!-- SECURITY SECTIONS -->
<section>
<div class="lv-container">
<div>
<div class="section-label">Security overview</div>
<h2 class="section-title">Six layers of enterprise-grade protection.</h2>
<p class="section-sub">Every aspect of the Landvex platform is designed to meet the requirements of enterprise customers — from data capture to delivery.</p>
</div>
<div class="security-grid">
<!-- Data Security -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">🔐</div>
<div class="card-title-wrap">
<h2>Data Security</h2>
<p>Encryption end-to-end, always</p>
</div>
</div>
<ul class="security-items">
<li>All data encrypted in transit using TLS 1.3 or higher</li>
<li>All data encrypted at rest using AES-256</li>
<li>AWS infrastructure: eu-north-1 (Stockholm) primary region</li>
<li>S3 server-side encryption enabled on all buckets</li>
<li>CloudFront HTTPS-only — HTTP requests redirected automatically</li>
</ul>
</div>
<!-- Identity & Access -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">🪪</div>
<div class="card-title-wrap">
<h2>Identity &amp; Access</h2>
<p>Verified identities, least-privilege access</p>
</div>
</div>
<ul class="security-items">
<li>Contributor identity verification required before first payout (KYC)</li>
<li>JWT-based authentication using RS256 asymmetric signing</li>
<li>Role-based access control: Zoomer / Orderer / Admin</li>
<li>No shared credentials anywhere in the platform</li>
</ul>
</div>
<!-- Data Integrity -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">🔗</div>
<div class="card-title-wrap">
<h2>Data Integrity</h2>
<p>Tamper-evident submission chain</p>
</div>
</div>
<ul class="security-items">
<li>Every submission receives a cryptographic integrity hash at capture</li>
<li>AI review verifies geo-compliance, image authenticity, and spec compliance</li>
<li>Submissions linked to verified contributor identity throughout the chain</li>
</ul>
</div>
<!-- Privacy & Compliance -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">🇪🇺</div>
<div class="card-title-wrap">
<h2>Privacy &amp; Compliance</h2>
<p>GDPR by design, not as an afterthought</p>
</div>
</div>
<ul class="security-items">
<li>GDPR compliant — all data stored within EU (Stockholm)</li>
<li>Data minimization: only data necessary for mission execution collected</li>
<li>Right to erasure fully supported for contributors and end users</li>
<li>Privacy policy: <a href="https://landvex.com/privacy" >landvex.com/privacy</a></li>
</ul>
</div>
<!-- Operational Security -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">⚙️</div>
<div class="card-title-wrap">
<h2>Operational Security</h2>
<p>Hardened, monitored, incident-ready</p>
</div>
</div>
<ul class="security-items">
<li>Infrastructure hosted on AWS — SOC 2 Type II and ISO 27001 certified. Landvex own ISO 27001 certification: in planning for 2027.</li>
<li>Automated vulnerability scanning on all production systems</li>
<li>Incident response process documented and tested</li>
</ul>
</div>
<!-- Enterprise -->
<div class="security-card" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="card-header">
<div class="card-icon">🏢</div>
<div class="card-title-wrap">
<h2>Enterprise</h2>
<p>Agreements, questionnaires, direct contact</p>
</div>
</div>
<ul class="security-items">
<li>Data Processing Agreements (DPA) available on request</li>
<li>Security questionnaires handled within 5 business days</li>
<li>Dedicated contact: <a href="mailto:security@landvex.com" >security@landvex.com</a></li>
</ul>
<div>
<a href="mailto:security@landvex.com" class="btn">Request DPA or questionnaire →</a>
</div>
</div>
</div>
</div>
</section>
<!-- COMPLIANCE STRIP -->
<section>
<div class="lv-container">
<div class="compliance-strip">
<div>
<div>Compliance status</div>
<div>All systems ready for August 2026 launch</div>
</div>
<div class="compliance-divider"></div>
<div class="compliance-badge">
<div class="dot"></div>
<span>GDPR — EU data residency</span>
</div>
<div class="compliance-divider"></div>
<div class="compliance-badge">
<div class="dot"></div>
<span>Hosted on AWS SOC 2 Type II infrastructure</span>
</div>
<div class="compliance-divider"></div>
<div class="compliance-badge">
<div class="dot"></div>
<span>ISO 27001-certified infrastructure (AWS eu-north-1)</span>
</div>
<div class="compliance-divider"></div>
<div class="compliance-badge">
<div class="dot"></div>
<span>TLS 1.3+ enforced</span>
</div>
</div>
</div>
</section>
<!-- ENTERPRISE CTA -->
<section>
<div class="lv-container">
<div class="enterprise-block">
<div class="main">
<div class="section-label">Enterprise ready</div>
<h2>Security questions? We answer them.</h2>
<p>Procurement, legal, or IT security teams with questions about the Landvex platform can contact our security team directly. We respond to all questionnaires within 5 business days.</p>
<div>
<div class="contact-item">
<span>📧</span>
<span>Security team: <strong><a href="mailto:security@landvex.com" >security@landvex.com</a></strong></span>
</div>
<div class="contact-item">
<span>📄</span>
<span>DPA available on request</span>
</div>
<div class="contact-item">
<span>⏱️</span>
<span>Questionnaire SLA: <strong>5 business days</strong></span>
</div>
</div>
</div>
<div class="actions">
<a class="lv-btn lv-btn--lg" href="mailto:security@landvex.com">Email security team →</a>
<a class="btn btn-outline btn-lg" href="/#contact">General enquiry</a>
</div>
</div>
</div>
</section>
<!-- FOOTER -->
<section>
<h2>Trust Centre — Security Documentation</h2>
<p>
Enterprise and government clients can request the following documentation under NDA.
We respond within one business day.
</p>
<div>
<div>
<div>Penetration test summary</div>
<div>Most recent external pen test — under NDA</div>
</div>
<div>
<div>AWS compliance reports</div>
<div>SOC 2 Type II + ISO 27001 (AWS infrastructure)</div>
</div>
<div>
<div>CAIQ / SIG questionnaire</div>
<div>Pre-filled security assessment on request</div>
</div>
<div>
<div>Data Processing Agreement</div>
<div><a href="/dpa" >View DPA →</a></div>
</div>
</div>
<a href="mailto:security@landvex.com?subject=Security%20documentation%20request"
>
Request documentation →
</a>
<p>
Landvex own ISO 27001: in planning for 2027. SOC 2 Type I target: Q4 2026.
We do not claim certifications we do not hold.
</p>
</section>
<footer class="lv-footer" role="contentinfo">
<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="/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="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>
</body>
</html>
+602
View File
@@ -0,0 +1,602 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SLA &amp; Data Freshness &mdash; Landvex</title>
<meta name="description" content="Landvex service level commitments: data freshness tiers, platform uptime targets, intelligence delivery guarantees, and breach resolution process.">
<link rel="canonical" href="https://landvex.com/sla/">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://landvex.com/sla/">
<meta property="og:title" content="SLA &amp; Data Freshness &mdash; Landvex">
<meta property="og:description" content="Landvex service level commitments: data freshness tiers, platform uptime targets, intelligence delivery guarantees, and breach resolution process.">
<meta property="og:image" content="https://landvex.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<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="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-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);
--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; }
.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; border-radius: var(--radius-md); }
.hero {
min-height: 70vh;
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, 64px);
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; }
section { padding: 24px; }
.container { max-width: 1100px; margin: 0 auto; }
.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, 4vw, 40px);
font-weight: 800; letter-spacing: -1.2px; line-height: 1.1;
color: #1d1d1f; margin-bottom: 24px;
}
.section-sub {
font-size: 17px; color: var(--text-dim);
max-width: 600px; line-height: 1.7; margin-bottom: 48px;
}
/* FRESHNESS TIERS */
.tier-grid {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
}
.tier-card {
background: var(--surface-2); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 24px;
position: relative; overflow: hidden;
transition: border-color 0.25s, transform 0.2s;
}
.tier-card:hover { border-color: rgba(0,102,255,0.35); transform: translateY(-3px); }
.tier-card.featured {
border-color: rgba(0,102,255,0.4);
background: linear-gradient(135deg, rgba(0,102,255,0.08) 0%, var(--surface-2) 100%);
}
.tier-badge {
display: inline-block;
font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
text-transform: uppercase;
padding: 24px; border-radius: 100px;
margin-bottom: 20px;
}
.tier-badge.standard { background: rgba(0,0,0,0.08); color: var(--text-dim); }
.tier-badge.premium { background: rgba(0,102,255,0.15); color: #5599ff; }
.tier-badge.priority { background: rgba(255,180,0,0.12); color: #fbbf24; }
.tier-icon {
width: 40px; height: 40px; margin-bottom: 20px;
}
.tier-card h3 {
font-size: 20px; font-weight: 800; color: #1d1d1f; letter-spacing: -0.4px;
margin-bottom: 8px;
}
.tier-freshness {
font-size: 13px; font-weight: 700; color: var(--blue);
margin-bottom: 24px; text-transform: uppercase; letter-spacing: 0.06em;
}
.tier-card p {
font-size: 14px; color: var(--text-dim); line-height: 1.65;
margin-bottom: 20px;
}
.tier-availability {
font-size: 12px; color: var(--text-muted);
padding-top: 16px; border-top: 1px solid var(--border);
}
/* COMMITMENTS */
.commitments-grid {
display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
}
.commit-card {
background: var(--surface-2); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 24px;
display: flex; gap: 16px; align-items: flex-start;
transition: border-color 0.25s;
}
.commit-card:hover { border-color: rgba(0,102,255,0.25); }
.commit-icon {
width: 36px; height: 36px; flex-shrink: 0;
color: var(--blue); margin-top: 2px;
}
.commit-card h3 {
font-size: 16px; font-weight: 700; color: #1d1d1f; margin-bottom: 8px;
}
.commit-card p {
font-size: 14px; color: var(--text-dim); line-height: 1.65;
}
.commit-metric {
display: inline-block;
margin-top: 12px;
font-size: 13px; font-weight: 700;
background: rgba(0,102,255,0.1); color: #5599ff;
padding: 24px; border-radius: 100px;
}
/* BREACH PROCESS */
.breach-bg { background: var(--surface); }
.breach-steps {
display: flex; flex-direction: column; gap: 0;
margin-top: 40px; position: relative;
}
.breach-steps::before {
content: '';
position: absolute; left: 23px; top: 24px; bottom: 24px; width: 2px;
background: linear-gradient(to bottom, var(--blue), rgba(0,102,255,0.1));
}
.breach-step {
display: flex; gap: 16px; align-items: flex-start;
padding: 24px 0; position: relative;
}
.breach-step-num {
width: 48px; height: 48px; flex-shrink: 0;
background: var(--blue); border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 16px; font-weight: 800; color: #1d1d1f;
position: relative; z-index: 1;
}
.breach-step-body h4 {
font-size: 16px; font-weight: 700; color: #1d1d1f; margin-bottom: 6px;
}
.breach-step-body p {
font-size: 14px; color: var(--text-dim); line-height: 1.65;
}
/* ENTERPRISE BOX */
.enterprise-box {
background: linear-gradient(135deg, #001836 0%, #000c24 100%);
border: 1px solid rgba(0,102,255,0.3);
border-radius: var(--radius-lg); padding: 48px;
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
margin-top: 48px;
}
.enterprise-box-icon {
width: 56px; height: 56px; flex-shrink: 0; color: var(--blue);
}
.enterprise-box-text { flex: 1; min-width: 260px; }
.enterprise-box-text h3 {
font-size: 20px; font-weight: 800; color: #1d1d1f; margin-bottom: 10px;
letter-spacing: -0.4px;
}
.enterprise-box-text p {
font-size: 15px; color: rgba(255,255,255,0.75); line-height: 1.65;
}
.enterprise-box-text a {
color: #5599ff; text-decoration: none;
}
.enterprise-box-text a:hover { text-decoration: underline; }
/* CTA BANNER */
.cta-section { background: #e8f0fe; }
.cta-banner {
border-radius: var(--radius-lg); padding: 48px;
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
background: rgba(0,0,0,0.03); border: 1px solid rgba(0,0,0,0.07);
}
.cta-banner h3 { color: #1d1d1f; font-size: 22px; font-weight: 800; margin-bottom: 10px; letter-spacing: -0.5px; }
.cta-banner p { color: rgba(255,255,255,.75); line-height: 1.65; font-size: 15px; }
.cta-banner-text { flex: 1; min-width: 260px; }
/* FOOTER */
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: 8px;
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); }
.lv-disclaimer { font-size: .75rem; color: rgba(0,0,0,.5); margin-top: 24px; padding: 24px; background: rgba(0,0,0,.04); border-radius: 8px; line-height: 1.6; max-width: 800px; }
.lv-disclaimer a { color: rgba(0,0,0,.65); text-decoration: underline; }
@media (max-width: 900px) {
nav { padding: 0 20px; }
.tier-grid { grid-template-columns: 1fr; }
.commitments-grid { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
section { padding: 24px; }
nav { padding: 0 16px; }
.hero h1 { letter-spacing: -1px; }
.enterprise-box { padding: 24px; gap: 16px; }
.cta-banner { padding: 24px; gap: 16px; }
}
</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": "SLA",
"item": "https://landvex.com/sla/"
}
]
}
</script>
<link rel="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="alternate" hreflang="it" href="https://landvex.it/">
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>sla</span>
</nav>
<nav aria-label="Main navigation">
<a class="nav-logo" href="https://landvex.com/">&larr; Back to Landvex</a>
<a class="lv-btn lv-btn--outline" href="/contact/">Get in touch &rarr;</a>
</nav>
<!-- HERO -->
<section class="lv-hero">
<div class="lv-hero-eyebrow">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Service Level Commitments
</div>
<h1>Service Level Commitments.</h1>
<div><strong>Pre-launch:</strong> These commitments apply from August 2026. During the pre-launch period, SLA terms are available for discussion in pilot agreements.</div>
<p class="lv-hero-subtitle">Landvex operates to defined standards of data freshness, platform availability, and delivery reliability. This page documents the commitments we make to clients and how breaches are handled.</p>
<div class="hero-ctas">
<a class="lv-btn lv-btn--lg" href="/contact/">Discuss SLA requirements &rarr;</a>
<a class="btn btn-outline btn-lg" href="#freshness">Data freshness tiers</a>
</div>
</section>
<!-- DATA FRESHNESS TIERS -->
<section id="freshness">
<div class="lv-container">
<div class="section-label">Data freshness</div>
<h2 class="section-title">Freshness tiers</h2>
<p class="section-sub">All Landvex intelligence is field-observed. The freshness tier defines the maximum age of underlying observations included in delivered intelligence.</p>
<div class="tier-grid">
<div class="tier-card">
<div class="tier-badge standard">Standard</div>
<svg class="tier-icon" viewBox="0 0 24 24" fill="none" stroke="#888" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polyline points="12 6 12 12 16 14"/>
</svg>
<h3>Standard</h3>
<div class="tier-freshness">Observations within 90 days</div>
<p>Field observations no older than 90 days. Suitable for strategic analysis, market entry assessments, and background research where recent directional accuracy is required.</p>
<div class="tier-availability">Included in all plans</div>
</div>
<div class="tier-card featured">
<div class="tier-badge premium">Premium</div>
<svg class="tier-icon" viewBox="0 0 24 24" fill="none" stroke="#5599ff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polyline points="12 6 12 12 16 14"/>
</svg>
<h3>Premium</h3>
<div class="tier-freshness">Observations within 30 days</div>
<p>Field observations no older than 30 days. Recommended for active investment decisions, site selection processes, and any use case where current-state accuracy is material to the outcome.</p>
<div class="tier-availability">Available on subscription</div>
</div>
<div class="tier-card">
<div class="tier-badge priority">Priority</div>
<svg class="tier-icon" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
<h3>Priority</h3>
<div class="tier-freshness">On-demand mission deployment</div>
<p>Dedicated field mission deployed to your target location within 24&ndash;72 hours. Intelligence reflects observed conditions at time of mission. Suitable for time-critical transactions and due diligence.</p>
<div class="tier-availability">Available on enterprise contracts</div>
</div>
</div>
</div>
</section>
<!-- PLATFORM COMMITMENTS -->
<section id="commitments">
<div class="lv-container">
<div class="section-label">Platform commitments</div>
<h2 class="section-title">What we commit to</h2>
<p class="section-sub">The following commitments apply to all active Landvex subscriptions unless otherwise specified in a signed order form or enterprise agreement.</p>
<div class="commitments-grid">
<div class="commit-card">
<svg class="commit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
<circle cx="12" cy="10" r="3"/>
</svg>
<div>
<h3>Coverage commitment</h3>
<p>Geographic coverage maps are launching August 2026. Coverage metadata is published per market and reflects current collection capacity. Markets not listed as active are not covered under any freshness tier.</p>
<span class="commit-metric">Launching August 2026</span>
</div>
</div>
<div class="commit-card">
<svg class="commit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
<div>
<h3>Platform uptime</h3>
<p>Landvex platform availability target is 99.5% measured monthly. Scheduled maintenance windows are communicated in advance and excluded from uptime calculations. Status is published at status.landvex.com.</p>
<span class="commit-metric">99.5% monthly target</span>
</div>
</div>
<div class="commit-card">
<svg class="commit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-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"/>
<polyline points="10 9 9 9 8 9"/>
</svg>
<div>
<h3>Intelligence delivery</h3>
<p>Reports are delivered within the timeline agreed at order placement. Where a delay is anticipated, notification is provided within 4 business hours of the expected issue being identified. Delayed delivery does not automatically trigger credit.</p>
<span class="commit-metric">Notification within 4 business hours</span>
</div>
</div>
<div class="commit-card">
<svg class="commit-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 11 12 14 22 4"/>
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>
</svg>
<div>
<h3>Data quality</h3>
<p>A minimum 85% AI review approval rate is maintained across all delivered intelligence. Human review is available for edge cases, contested classifications, and high-stakes outputs upon request. Quality metrics are available on request.</p>
<span class="commit-metric">85% minimum approval rate</span>
</div>
</div>
</div>
</div>
</section>
<!-- BREACH PROCESS -->
<section id="breach" class="breach-bg">
<div class="lv-container">
<div class="section-label">Breach resolution</div>
<h2 class="section-title">How breaches are handled</h2>
<p class="section-sub">When a commitment is not met, Landvex follows a defined resolution process. Transparency and speed of resolution are non-negotiable.</p>
<div class="breach-steps">
<div class="breach-step">
<div class="breach-step-num">1</div>
<div class="breach-step-body">
<h4>Notification within 4 business hours</h4>
<p>The affected client is notified within 4 business hours of a confirmed breach being identified, whether self-reported or identified by Landvex monitoring. Notification includes a preliminary description of scope and expected resolution timeline.</p>
</div>
</div>
<div class="breach-step">
<div class="breach-step-num">2</div>
<div class="breach-step-body">
<h4>Root cause within 48 hours</h4>
<p>A root cause analysis is delivered within 48 hours of the breach being confirmed. The analysis documents what failed, why, and what preventive measure is being applied. RCA is provided in writing.</p>
</div>
</div>
<div class="breach-step">
<div class="breach-step-num">3</div>
<div class="breach-step-body">
<h4>Credit for material breaches</h4>
<p>Where a breach is material &mdash; meaning it results in demonstrable impact to the client&rsquo;s ability to use delivered intelligence as intended &mdash; service credit is applied to the next billing period as follows:
<table>
<thead><tr>
<th>Breach type</th>
<th>Standard credit</th>
</tr></thead>
<tbody>
<tr><td>Uptime below 99.5% in a calendar month</td><td>10% of monthly subscription fee</td></tr>
<tr><td>Uptime below 99.0%</td><td>25% of monthly subscription fee</td></tr>
<tr><td>Confirmed data delivery failure (missed freshness SLO)</td><td>Pro-rata for affected period</td></tr>
<tr><td>Critical incident unresolved &gt;72 hours</td><td>15% of monthly subscription fee</td></tr>
</tbody>
</table>
<p>Credits are applied automatically. Maximum credit per month: 30% of monthly fee. Credits do not constitute a waiver of other remedies. Enterprise agreements may specify custom credit structures.</p></p>
</div>
</div>
</div>
</div>
</section>
<!-- ENTERPRISE SLA -->
<section id="enterprise">
<div class="lv-container">
<div class="section-label">Enterprise</div>
<h2 class="section-title">Custom SLA available</h2>
<p class="section-sub">Enterprise contracts support fully negotiated SLA terms, including custom freshness windows, dedicated support response times, and tailored breach credit structures.</p>
<div class="enterprise-box">
<svg class="enterprise-box-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="7" width="20" height="14" rx="2"/>
<path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2"/>
<line x1="12" y1="12" x2="12" y2="16"/>
<line x1="10" y1="14" x2="14" y2="14"/>
</svg>
<div class="enterprise-box-text">
<h3>Enterprise SLA &mdash; Tailored to your requirements</h3>
<p>Custom SLA is available on enterprise contracts. Negotiable terms include freshness SLOs, uptime guarantees, priority support escalation paths, and credit structures. Contact <a href="mailto:enterprise@landvex.com">enterprise@landvex.com</a> to initiate a discussion.</p>
</div>
<a class="lv-btn lv-btn--lg" href="/contact/">Discuss SLA requirements &rarr;</a>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-section">
<div class="lv-container">
<div class="cta-banner">
<div class="cta-banner-text">
<h3>Discuss SLA requirements</h3>
<p>If your use case requires specific freshness windows, uptime guarantees, or delivery commitments not covered by standard terms, speak with our enterprise team.</p>
</div>
<a class="lv-btn lv-btn--lg" href="/contact/">Discuss SLA requirements &rarr;</a>
</div>
<p class="lv-disclaimer">SLA commitments apply to services delivered under a current Landvex subscription or enterprise agreement. Standard plan terms govern unless superseded by a signed order form. Landvex AB &middot; Org.nr 559141-7042.</p>
</div>
</section>
<footer class="lv-footer" role="contentinfo">
<div class="footer-inner">
<div>
<div class="footer-logo">Landvex</div>
<div class="footer-copy">&copy; 2026 Landvex Inc &middot; 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="https://landvex.com/">Home</a>
<a href="/methodology/">Methodology</a>
<a href="/data-quality/">Data quality</a>
<a href="/security/">Security</a>
<a href="/contact/">Contact</a>
<a href="mailto:enterprise@landvex.com">enterprise@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>
</body>
</html>
+3126
View File
@@ -0,0 +1,3126 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#f2f2f7">
<link rel="apple-touch-icon" href="https://landvex.com/apple-touch-icon.png">
<meta name="apple-mobile-web-app-title" content="Landvex">
<link rel="manifest" href="/intelligence-manifest.json">
<title>Stockholm — Landvex Intelligence Brief</title>
<link rel="stylesheet" href="/vendor/leaflet.css"/>
<script src="/vendor/leaflet.js"></script>
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
*{box-sizing:border-box;margin:0;padding:0;-webkit-font-smoothing:antialiased}
:root{
--bg:#f2f2f7;
--s1:#ffffff;
--s2:#f2f2f7;
--s3:#e5e5ea;
--border:rgba(0,0,0,0.08);
--b2:rgba(0,0,0,0.12);
--b3:rgba(0,0,0,0.18);
--text:#1c1c1e;
--t2:rgba(28,28,30,0.72);
--t3:rgba(28,28,30,0.50);
--accent:#007aff;
--accent2:#0071e3;
--accent3:#0066cc;
--green:#34c759;
--green2:#30b352;
--green3:#248a3d;
--yellow:#ff9f0a;
--yellow2:#f7a600;
--yellow3:#b25000;
--orange:#ff6b00;
--orange2:#e05c00;
--orange3:#c04a00;
--red:#ff3b30;
--red2:#d70015;
--red3:#a2000f;
--purple:#af52de;
--purple2:#9b44c8;
--purple3:#6e1e8f;
--gold:#ff9500;
--gold2:#e08600;
--gold3:#b86a00;
--mono:'SF Mono',ui-monospace,monospace;
}
html,body{height:100%;font-family:-apple-system,BlinkMacSystemFont,'SF Pro Text','Helvetica Neue',sans-serif;background:var(--bg);color:var(--text);overflow:hidden}
.leaflet-control-attribution{display:none !important}
.leaflet-bottom.leaflet-right{display:none !important}
/* GRID */
#app{display:grid;grid-template-columns:260px 1fr 320px;height:100vh;overflow:hidden}
/* LEFT */
#left{background:var(--s1);border-right:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column;-webkit-overflow-scrolling:touch}
#city-block{padding: 24px 14px;border-bottom:1px solid var(--border)}
#city-eyebrow{font-size:9px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--accent3);margin-bottom:6px}
#city-name{font-size:24px;font-weight:900;letter-spacing:-0.8px;color:var(--text);line-height:1;font-family:'Inter',system-ui,sans-serif}
#city-region{font-size:11px;color:var(--t2);margin-top:3px;font-weight:500}
#city-stats{display:grid;grid-template-columns:1fr 1fr;gap: 16px;margin-top:12px}
.cstat{background:var(--s2);border:1px solid var(--border);border-radius:7px;padding: 24px}
.cstat-val{font-size:16px;font-weight:800;color:var(--text);letter-spacing:-0.3px}
.cstat-lbl{font-size:9px;font-weight:600;letter-spacing:0.5px;text-transform:uppercase;color:var(--t3);margin-top:1px}
/* Profile tabs */
#profile-block{padding: 24px;border-bottom:1px solid var(--border)}
#profile-lbl{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:8px}
#profile-tabs{display:grid;grid-template-columns:1fr 1fr 1fr;gap: 16px;background:rgba(0,0,0,0.06);border-radius:10px;padding:2px}
.ptab{padding: 24px;border-radius:8px;border:none;background:transparent;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap: 16px;transition:all 0.15s;font-size:10px;font-weight:600;color:var(--t2);letter-spacing:0.2px}
.ptab .picon{font-size:14px;line-height:1}
.ptab:hover{background:var(--s2);color:var(--text)}
.ptab.active{background:#ffffff;color:var(--text);box-shadow:0 1px 4px rgba(0,0,0,0.12)}
.ptab.active.p-business{border-color:var(--accent2);color:var(--accent3)}
.ptab.active.p-tourist{border-color:var(--green2);color:var(--green3)}
.ptab.active.p-safety{border-color:var(--red2);color:var(--red3)}
.ptab.active.p-investment{border-color:var(--gold2);color:var(--gold3)}
.ptab.active.p-nightlife{border-color:var(--purple2);color:var(--purple3)}
.ptab.active.p-infrastructure{border-color:var(--yellow2);color:var(--yellow3)}
/* Districts */
#district-block{padding: 24px}
#district-lbl{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:8px}
.dcard{border-radius:12px;border:none;background:var(--s2);padding: 24px;margin-bottom:6px;cursor:pointer;transition:all 0.12s}
.dcard:hover,.dcard.active{border-color:var(--b2);background:var(--s3)}
.dcard-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:3px}
.dcard-name{font-size:13px;font-weight:700;color:var(--text)}
.dcard-score{font-size:11px;font-weight:800;padding: 24px;border-radius:4px;font-family:var(--mono)}
.dcard-desc{font-size:12px;color:var(--t2);line-height:1.4;margin-bottom:5px}
.dcard-contra{display:inline-flex;align-items:center;gap: 16px;font-size:9px;font-weight:700;letter-spacing:0.3px;border-radius:4px;padding: 24px}
.dc-low{background:rgba(22,163,74,0.12);color:#4ade80}
.dc-med{background:rgba(217,119,6,0.12);color:#fbbf24}
.dc-high{background:rgba(220,38,38,0.12);color:#f87171}
/* Data Freshness */
#freshness-block{padding: 24px;border-top:1px solid var(--border);margin-top:auto}
#freshness-title{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:8px;display:flex;align-items:center;gap: 16px}
#freshness-title::before{content:'';display:inline-block;width:5px;height:5px;border-radius:50%;background:#22c55e;animation:pulse-ring 2s ease-in-out infinite}
.fresh-row{display:flex;align-items:center;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--border)}
.fresh-row:last-child{border-bottom:none}
.fresh-source{font-size:10px;color:var(--t2);font-weight:500}
.fresh-val{font-size:9px;font-weight:700;font-family:var(--mono);display:flex;align-items:center;gap: 16px}
.fresh-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}
.fresh-dot.live{background:#22c55e;animation:pulse-ring 1.5s ease-in-out infinite}
.fresh-dot.recent{background:#fbbf24}
.fresh-dot.stale{background:#f87171}
/* MAP */
#map-wrap{position:relative;overflow:hidden;background:var(--bg)}
#map{width:100%;height:100%}
#map-topbar{position:absolute;top:0;left:0;right:0;z-index:1000;height:44px;display:flex;align-items:center;gap: 16px;padding:0 14px;background:rgba(0,0,0,0.85);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border-bottom:1px solid rgba(0,0,0,0.1)}
#map-logo{font-size:11px;font-weight:800;letter-spacing:-0.3px;color:var(--text);text-decoration:none}
#map-logo em{color:var(--accent3);font-style:normal}
.map-sep{width:1px;height:16px;background:rgba(0,0,0,0.12)}
#map-city-label{font-size:12px;font-weight:700;color:var(--text);flex:1}
#map-profile-chip{font-size:10px;font-weight:700;border-radius:4px;padding: 24px;border:1px solid;letter-spacing:0.3px}
#map-conf{font-size:10px;font-weight:600;color:var(--t2)}
/* Layer toggle bar */
#layer-bar{position:absolute;top:44px;left:0;right:0;z-index:999;display:flex;align-items:center;gap: 16px;padding: 24px;background:#ffffff;border-bottom:1px solid rgba(0,0,0,0.1);overflow-x:auto;scrollbar-width:none;flex-wrap:nowrap;-webkit-overflow-scrolling:touch}
#layer-bar::-webkit-scrollbar{display:none}
#layer-bar-label{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);white-space:nowrap;margin-right:4px;flex-shrink:0}
.ltoggle{display:flex;align-items:center;gap: 16px;font-size:11px;font-weight:600;color:var(--t2);background:rgba(0,0,0,0.05);border:none;border-radius:20px;padding: 24px;cursor:pointer;transition:all 0.15s;white-space:nowrap;user-select:none;flex-shrink:0}
.ltoggle:hover{border-color:var(--b2);color:var(--text)}
.ltoggle.on{background:var(--accent);color: #1d1d1ffff;}
.ltoggle-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
.ltoggle-dot.d-districts{background:#4aafef}
.ltoggle-dot.d-roadwork{background:#fb923c}
.ltoggle-dot.d-pulse{background:#c084fc;animation:pulse-ring 1.5s ease-in-out infinite}
.ltoggle-dot.d-alerts{background:#f87171}
.leaflet-control-zoom{margin-top:96px !important;margin-left:10px !important}
.leaflet-control-zoom a{background:rgba(11,18,32,0.9) !important;color:var(--text) !important;border-color:var(--b2) !important;width:30px !important;height:30px !important;line-height:30px !important;border-radius:5px !important;font-size:16px !important}
.leaflet-popup-pane{z-index:1500 !important}
.leaflet-popup-content-wrapper{background:#ffffff !important;border:none !important;border-radius: var(--radius-lg) !important;box-shadow:0 8px 32px rgba(0,0,0,0.15) !important;padding:0 !important;max-height:60vh !important;overflow-y:auto !important}
.leaflet-popup-content{margin:0 !important;width:260px !important;max-height:55vh !important;overflow-y:auto !important}
@media(max-width:900px){
/* Hide Leaflet popup on mobile — use bottom sheet instead */
.leaflet-popup{display:none !important}
}
/* ── MOBILE BOTTOM SHEET ── */
#bottom-sheet{
display:none;
position:fixed;
left:0;right:0;bottom:0;
z-index:9999;
background:#ffffff;
border-top:1px solid rgba(0,0,0,0.1);
border-radius: var(--radius-lg) 16px 0 0;
box-shadow:0 -4px 24px rgba(0,0,0,0.12);
max-height:72vh;
overflow-y:auto;
-webkit-overflow-scrolling:touch;
transform:translateY(100%);
transition:transform 0.28s cubic-bezier(0.32,0.72,0,1);
}
#bottom-sheet.open{
display:block;
transform:translateY(0);
}
#bottom-sheet-handle{
width:36px;height:4px;border-radius:2px;
background:rgba(0,0,0,0.2);
margin:10px auto 0;
}
#bottom-sheet-close{
position:absolute;top:12px;right:14px;
background:rgba(0,0,0,0.1);border:none;
color:var(--text);font-size:16px;
width:28px;height:28px;border-radius:50%;
cursor:pointer;display:flex;align-items:center;justify-content:center;
line-height:1;
}
#bottom-sheet-content{
padding:8px 0 env(safe-area-inset-bottom,16px);
}
#bottom-sheet-backdrop{
display:none;
position:fixed;inset:0;
z-index:9998;
background:rgba(0,0,0,0.4);
}
#bottom-sheet-backdrop.open{display:block;}
.leaflet-popup-tip{background:#ffffff !important}
.leaflet-popup-close-button{color:var(--t2) !important;top:8px !important;right:10px !important;font-size:16px !important}
/* Popup */
.mpop{padding: 24px;font-family:-apple-system,sans-serif}
.mpop-eyebrow{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--accent3);margin-bottom:3px}
.mpop-name{font-size:14px;font-weight:800;color:var(--text);margin-bottom:8px;letter-spacing:-0.3px}
.mpop-score-row{display:flex;align-items:baseline;gap: 16px;margin-bottom:10px}
.mpop-score{font-size:26px;font-weight:900;font-family:var(--mono);letter-spacing:-1px}
.mpop-score-denom{font-size:12px;color:var(--t3);font-family:var(--mono)}
.mpop-score-label{font-size:10px;color:var(--t2);line-height:1.3}
.mpop-bars{display:flex;flex-direction:column;gap: 16px;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid var(--border)}
.mpop-bar-row{display:flex;align-items:center;gap: 16px}
.mpop-bar-lbl{font-size:9px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:var(--t3);width:72px;flex-shrink:0}
.mpop-bar-track{flex:1;height:3px;border-radius:2px;background:rgba(0,0,0,0.04)}
.mpop-bar-fill{height:100%;border-radius:2px;transition:width 0.3s}
.mpop-bar-val{font-size:10px;font-weight:700;font-family:var(--mono);width:24px;text-align:right}
.mpop-contra{font-size:10px;border-radius:6px;padding: 24px;line-height:1.4;margin-bottom:8px}
.mpop-contra.low{background:rgba(22,163,74,0.1);color:#4ade80;border:1px solid rgba(22,163,74,0.15)}
.mpop-contra.medium{background:rgba(217,119,6,0.1);color:#fbbf24;border:1px solid rgba(217,119,6,0.15)}
.mpop-contra.high{background:rgba(220,38,38,0.1);color:#f87171;border:1px solid rgba(220,38,38,0.15)}
.mpop-contra-lbl{font-weight:800;font-size:9px;letter-spacing:0.5px;text-transform:uppercase;display:block;margin-bottom:2px}
.mpop-insight{font-size:10px;color:var(--t2);line-height:1.5;font-style:italic}
/* Roadwork popup */
.rwpop{padding: 24px;font-family:-apple-system,sans-serif}
.rwpop-eyebrow{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:#fb923c;margin-bottom:3px}
.rwpop-name{font-size:13px;font-weight:800;color:var(--text);margin-bottom:6px}
.rwpop-desc{font-size:11px;color:var(--t2);line-height:1.5;margin-bottom:6px}
.rwpop-badge{display:inline-flex;align-items:center;gap: 16px;font-size:9px;font-weight:700;border-radius:4px;padding: 24px;background:rgba(251,146,60,0.12);border:1px solid rgba(251,146,60,0.25);color:#fb923c}
.rwpop-src{font-size:9px;color:var(--t3);margin-top:6px}
/* Live Pulse animation */
@keyframes pulse-ring {
0%{opacity:1;transform:scale(1)}
50%{opacity:0.6;transform:scale(1.2)}
100%{opacity:1;transform:scale(1)}
}
@keyframes pulse-wave {
0%{transform:scale(1);opacity:0.7}
100%{transform:scale(3.2);opacity:0}
}
.src-chain{font-size:9px;color:rgba(220,232,245,0.25);border-top:1px solid rgba(0,0,0,0.03);padding-top:5px;margin-top:5px;line-height:1.6}
.src-tag{display:inline-flex;align-items:center;gap: 16px;background:rgba(0,0,0,0.04);border-radius:3px;padding: 24px;margin:1px 2px 1px 0;font-size:9px;font-weight:600;color:rgba(220,232,245,0.35)}
.src-data{color:#38bdf8}.src-obs{color:#4ade80}.src-model{color:#a78bfa}.src-forecast{color:#f59e0b}
.pulse-marker{pointer-events:none}
.pulse-outer{position:absolute;border-radius:50%;animation:pulse-wave 2.2s ease-out infinite}
.pulse-inner{position:absolute;border-radius:50%;transform:translate(-50%,-50%)}
/* RIGHT */
#right{background:var(--s1);border-left:1px solid rgba(0,0,0,0.08);overflow-y:auto;display:flex;flex-direction:column;scrollbar-width:none}
#right-header{padding: 24px 10px;border-bottom:1px solid var(--border)}
#right-profile-label{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:4px}
#right-title{font-size:17px;font-weight:700;color:var(--text);letter-spacing:-0.3px}
#kpi-grid{padding: 24px 8px;display:grid;grid-template-columns:1fr 1fr;gap: 16px;border-bottom:1px solid var(--border)}
.kpi{background:var(--s2);border:none;border-radius:12px;padding: 24px}
.kpi-label{font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;margin-bottom:4px}
.kpi-value{font-size:22px;font-weight:800;letter-spacing:-0.5px;font-family:var(--mono);line-height:1}
.kpi-sub{font-size:11px;color:var(--t2);margin-top:3px;line-height:1.3}
.kpi.span2{grid-column:span 2}
#insights-block{padding: 24px;border-bottom:1px solid var(--border)}
#insights-title{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:10px}
.insight-row{display:flex;gap: 16px;align-items:flex-start;padding:7px 0;border-bottom:1px solid var(--border)}
.insight-row:last-child{border-bottom:none}
.insight-icon{font-size:11px;font-weight:800;color:var(--accent3);flex-shrink:0;margin-top:3px;opacity:0.9;width:12px;text-align:center;line-height:1}
.insight-text{font-size:13px;color:rgba(28,28,30,0.8);line-height:1.6}
.insight-text strong{color:var(--text);font-weight:700}
/* Contradiction Alerts */
#contra-block{padding: 24px;border-bottom:1px solid var(--border)}
#contra-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
#contra-title{font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--t3);display:flex;align-items:center;gap: 16px}
.contra-live-dot{width:5px;height:5px;border-radius:50%;background:#f87171;animation:pulse-ring 1.8s ease-in-out infinite}
.contra-count{font-size:9px;font-weight:700;font-family:var(--mono);background:rgba(220,38,38,0.15);border:1px solid rgba(220,38,38,0.25);color:#f87171;padding: 24px;border-radius:10px}
.contra-card{border-radius:7px;border:1px solid var(--border);background:var(--s2);padding: 24px;margin-bottom:5px}
.contra-card.c-medium{border-left:3px solid rgba(217,119,6,0.5)}
.contra-card.c-high{border-left:3px solid rgba(220,38,38,0.6)}
.contra-card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:3px}
.contra-card-name{font-size:11px;font-weight:700;color:var(--text)}
.contra-card-badge{font-size:8px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;padding: 24px;border-radius:3px}
.contra-card-badge.medium{background:rgba(217,119,6,0.12);color:#fbbf24}
.contra-card-badge.high{background:rgba(220,38,38,0.12);color:#f87171}
.contra-card-desc{font-size:10px;color:var(--t2);line-height:1.4;margin-bottom:6px}
.contra-card-meta{display:flex;align-items:center;justify-content:space-between}
.contra-card-date{font-size:9px;color:var(--t3);font-family:var(--mono)}
.contra-view-btn{font-size:9px;font-weight:700;letter-spacing:0.3px;padding: 24px;border-radius:4px;border:1px solid var(--b2);background:transparent;color:var(--accent3);cursor:pointer;transition:all 0.12s}
.contra-view-btn:hover{background:rgba(74,175,239,0.1);border-color:var(--accent2)}
#caution-block{padding: 24px;border-bottom:1px solid var(--border)}
.caution-card{background:rgba(220,38,38,0.06);border:1px solid rgba(220,38,38,0.15);border-radius:8px;padding: 24px}
.caution-lbl{font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;color:var(--red3);margin-bottom:6px}
.caution-row{display:flex;gap: 16px;align-items:flex-start;padding:3px 0;font-size:12px;color:var(--text);line-height:1.5}
.caution-dot{width:4px;height:4px;border-radius:50%;background:var(--red2);flex-shrink:0;margin-top:4px}
#right-footer{padding: 24px;font-size:9px;color:var(--t3);line-height:1.4;border-top:1px solid var(--border)}
#right-footer a{color:var(--accent3);text-decoration:none}
/* ── MOBILE — iOS native style ── */
@media(max-width:900px){
html,body{height:auto;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch}
#app{display:flex;flex-direction:column;height:auto;min-height:100dvh;overflow:visible}
/* ── TOP BAR — kompakt native ── */
#left{order:1;border-right:none;border-bottom:none;background:var(--s1);display:flex;flex-direction:column;height:auto;overflow:visible}
#city-block{padding: 24px 8px}
#city-eyebrow{font-size:9px;letter-spacing:1.5px}
#city-name{font-size:26px;letter-spacing:-0.8px}
#city-region{font-size:11px;margin-top:2px}
#city-stats{display:flex;gap: 16px;margin-top:8px;flex-wrap:nowrap}
.cstat{background:transparent;border:none;padding:0;flex-shrink:0}
.cstat-val{font-size:15px;font-weight:800}
.cstat-lbl{font-size:9px}
/* hide less important stats */
.cstat:nth-child(3),.cstat:nth-child(4){display:none}
/* ── PROFILE TABS — iOS segmented control style ── */
#profile-block{padding: 24px;border-bottom:1px solid var(--border)}
#profile-lbl{display:none}
#profile-tabs{display:flex;overflow-x:auto;gap:0;scrollbar-width:none;background:rgba(0,0,0,0.04);border-radius:10px;padding:2px}
#profile-tabs::-webkit-scrollbar{display:none}
.ptab{flex-shrink:0;flex-direction:row;gap: 16px;padding: 24px;font-size:12px;font-weight:600;border-radius:8px;border:none;background:transparent;white-space:nowrap;min-width:auto;color:rgba(220,232,245,0.55)}
.ptab .picon{display:none}
.ptab.active{background:rgba(220,232,245,0.15);color:#dce8f5;font-weight:700}
/* Active profile colors */
.ptab.active.p-business{background:rgba(45,143,207,0.25);color:#4aafef}
.ptab.active.p-tourist{background:rgba(34,197,94,0.2);color:#4ade80}
.ptab.active.p-safety{background:rgba(220,38,38,0.2);color:#f87171}
.ptab.active.p-investment{background:rgba(217,119,6,0.2);color:#fbbf24}
.ptab.active.p-nightlife{background:rgba(147,51,234,0.2);color:#c084fc}
.ptab.active.p-infrastructure{background:rgba(180,83,9,0.2);color:#fcd34d}
/* ── HIDE DISTRICT LIST + FRESHNESS on mobile ── */
#district-block{display:none}
#freshness-block{display:none}
/* ── MAP — hero element, karta first ── */
#map-wrap{order:2;height:60vh;min-height:340px;max-height:520px;position:relative}
#map-topbar{height:44px;padding:0 14px;display:flex;align-items:center}
#map-logo{font-size:14px;font-weight:800}
.map-sep{display:none}
#map-city-label{font-size:12px;font-weight:600}
#map-conf{display:none}
#map-profile-chip{font-size:10px;padding: 24px;border-radius:20px}
/* Layer bar — scrollable, compact */
#layer-bar{
top:44px;left:0;right:0;
transform:none;
padding: 24px;
gap: 16px;
background:#ffffff;
border-bottom:1px solid rgba(0,0,0,0.1);
overflow-x:auto;
scrollbar-width:none;
flex-wrap:nowrap;
-webkit-overflow-scrolling:touch
}
#layer-bar::-webkit-scrollbar{display:none}
.ltoggle{font-size:10px;padding: 24px;border-radius:20px;gap: 16px;flex-shrink:0;color:rgba(28,28,30,0.65)}
.ltoggle-dot{width:6px;height:6px}
.leaflet-control-zoom{margin-top:92px !important;margin-left:10px !important}
.leaflet-control-zoom a{background:#ffffff !important;color:#1c1c1e !important;border:none !important;border-bottom:1px solid rgba(0,0,0,0.08) !important}
.leaflet-control-zoom a:last-child{border-bottom:none !important}
.leaflet-control-zoom a{width:30px !important;height:30px !important;line-height:30px !important;font-size:16px !important;border-radius:8px !important}
/* ── RIGHT PANEL — card stack below map ── */
#right{order:3;border-left:none;border-top:1px solid var(--border);overflow:visible;height:auto}
#right-header{padding: 24px 8px}
#right-title{font-size:14px;font-weight:800}
#kpi-grid{grid-template-columns:1fr 1fr;gap: 16px;padding:0 16px 12px}
.kpi{border-radius:10px;padding: 24px}
.kpi-label{font-size:9px}
.kpi-value{font-size:17px}
.kpi-sub{font-size:9px}
/* All right panel sections */
#events-engine,#weekly-brief,#macro-block,#news-block,#events-block,
#insights-block,#caution-block,#contra-alerts-section{padding: 24px}
#right-footer{padding: 24px;font-size:9px}
}
@media(max-width:480px){
#city-name{font-size:22px}
#map-wrap{height:55vh;min-height:300px}
.ptab{padding: 24px;font-size:11px}
#kpi-grid{gap: 16px}
.kpi-value{font-size:15px}
}
@media(max-width:900px){
.label-marker{display:none !important}
}
/* Bottom sheet content — force dark text on white */
#bottom-sheet-content .mpop{padding: 24px}
#bottom-sheet-content .mpop-eyebrow{color:#0066cc !important}
#bottom-sheet-content .mpop-name{color:#1c1c1e !important}
#bottom-sheet-content .mpop-score{color:inherit}
#bottom-sheet-content .mpop-score-denom{color:rgba(28,28,30,0.4) !important}
#bottom-sheet-content .mpop-score-label{color:rgba(28,28,30,0.55) !important}
#bottom-sheet-content .mpop-bar-lbl{color:rgba(28,28,30,0.5) !important}
#bottom-sheet-content .mpop-bar-track{background:rgba(0,0,0,0.08) !important}
#bottom-sheet-content .mpop-contra{border:1px solid rgba(0,0,0,0.1) !important}
#bottom-sheet-content .mpop-contra.low{background:rgba(22,163,74,0.08) !important;color:#166534 !important}
#bottom-sheet-content .mpop-contra.medium{background:rgba(217,119,6,0.08) !important;color:#92400e !important}
#bottom-sheet-content .mpop-contra.high{background:rgba(220,38,38,0.08) !important;color:#991b1b !important}
#bottom-sheet-content .mpop-contra-lbl{color:inherit !important}
#bottom-sheet-content .mpop-insight{color:rgba(28,28,30,0.65) !important}
#bottom-sheet-content .mpop-bar-val{color:rgba(28,28,30,0.7) !important}
/* All sub-popup sections in bottom sheet */
#bottom-sheet-content [style*="color:#dce8f5"]{color:#1c1c1e !important}
#bottom-sheet-content [style*="color:rgba(220,232,245"]{color:rgba(28,28,30,0.6) !important}
#bottom-sheet-content [style*="background:rgba(0,0,0,0.04)"]{background:rgba(0,0,0,0.04) !important}
#bottom-sheet-content [style*="background:rgba(0,0,0,0.03)"]{background:rgba(0,0,0,0.03) !important}
#bottom-sheet-content [style*="background:var(--s2)"]{background:#f2f2f7 !important}
#bottom-sheet-content [style*="background:rgba(0,0,0,0.04)"]{background:rgba(0,0,0,0.05) !important}
#bottom-sheet-content [style*="border:1px solid rgba(255,255,255"]{border-color:rgba(0,0,0,0.08) !important}
#bottom-sheet-content [style*="border-top:1px solid rgba(255,255,255"]{border-top-color:rgba(0,0,0,0.08) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.3"]{color:rgba(28,28,30,0.45) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.35"]{color:rgba(28,28,30,0.45) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.4"]{color:rgba(28,28,30,0.55) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.5"]{color:rgba(28,28,30,0.65) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.55"]{color:rgba(28,28,30,0.7) !important}
#bottom-sheet-content [style*="color:rgba(220,232,245,0.6"]{color:rgba(28,28,30,0.75) !important}
#bottom-sheet-content [style*="color:#dce8f5"]{color:#1c1c1e !important}
#bottom-sheet-content [style*="font-family:var(--mono)"]{color:#1c1c1e}
#bottom-sheet-content [style*="background:rgba(239,68,68,0.1"]{background:rgba(239,68,68,0.07) !important}
#bottom-sheet-content [style*="background:rgba(34,197,94,0.1"]{background:rgba(34,197,94,0.07) !important}
#bottom-sheet-content [style*="background:rgba(217,119,6,0.1"]{background:rgba(217,119,6,0.07) !important}
#bottom-sheet-content [style*="background:rgba(249,115,22,0.1"]{background:rgba(249,115,22,0.07) !important}
#bottom-sheet-content .src-chain{color:rgba(28,28,30,0.35) !important;border-top-color:rgba(0,0,0,0.06) !important}
#bottom-sheet-content .src-tag{background:rgba(0,0,0,0.05) !important;color:rgba(28,28,30,0.45) !important}
</style>
<script>
if('serviceWorker' in navigator){
window.addEventListener('load',()=>{
navigator.serviceWorker.register('/intelligence-sw.js')
.then(()=>console.log('Landvex SW registered'))
.catch(e=>console.warn('SW failed:',e));
});
}
</script>
<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>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": [
"Organization",
"Corporation"
],
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"alternateName": [
"LandveX",
"Landvex AB",
"LandveX AB"
],
"url": "https://landvex.com",
"logo": {
"@type": "ImageObject",
"url": "https://landvex.com/apple-touch-icon.png",
"width": 180,
"height": 180
},
"foundingDate": "2024",
"foundingLocation": {
"@type": "Place",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
},
"legalName": "Landvex Inc",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
},
"location": [
{
"@type": "Place",
"name": "Houston, Texas, USA (US HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
}
},
{
"@type": "Place",
"name": "Tyresö, Sweden (EU HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
}
}
],
"taxID": "pending-EIN",
"description": "Landvex is a decision intelligence company that identifies contradictions between official narratives and observed physical reality. Using the quiXzoom field observation network and the AMOS AI analysis engine, Landvex delivers infrastructure risk indexes, urban intelligence scores, and contradiction reports to infrastructure owners, municipalities, enterprises, and investors globally.",
"disambiguatingDescription": "Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European headquarters in Tyresö, Sweden (Landvex AB, org.nr 559141-7042). Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors. Landvex is not a UK meat wholesaler, food distributor, logistics company, package tracker, or land investment platform.",
"knowsAbout": [
"control intelligence",
"decision intelligence",
"infrastructure risk assessment",
"urban intelligence",
"field data collection",
"contradiction detection",
"physical world analytics",
"geospatial analytics"
],
"brand": {
"@type": "Brand",
"name": "Landvex",
"slogan": "Control intelligence for the physical world."
},
"sameAs": [
"https://landvex.com",
"https://www.linkedin.com/company/landvex",
"https://x.com/landvex",
"https://twitter.com/landvex",
"https://www.crunchbase.com/organization/landvex",
"https://github.com/landvex",
"https://www.instagram.com/landvex"
],
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@landvex.com",
"contactType": "sales"
},
"slogan": "Where reported reality conflicts with observed reality."
}
</script>
</head>
<body>
<div id="app">
<!-- LEFT -->
<div id="left">
<div id="city-block">
<div id="city-eyebrow">Landvex Intelligence Brief</div>
<div id="city-name">STOCKHOLM</div>
<div id="city-region">Kingdom of Sweden · Northern Europe</div>
<div id="city-stats">
<div class="cstat"><div class="cstat-val">94%</div><div class="cstat-lbl">Confidence</div></div>
<div class="cstat"><div class="cstat-val" id="district-count">26</div><div class="cstat-lbl">Districts</div></div>
<div class="cstat"><div class="cstat-val">Medium</div><div class="cstat-lbl">Contradiction</div></div>
<div class="cstat"><div class="cstat-val">Jun 2026</div><div class="cstat-lbl">Updated</div></div>
</div>
</div>
<div id="profile-block">
<div id="profile-lbl">Intelligence Profile</div>
<div id="profile-tabs">
<button class="ptab p-business active" data-p="business" onclick="setProfile('business',this)">Business</button>
<button class="ptab p-tourist" data-p="tourist" onclick="setProfile('tourist',this)">Tourist</button>
<button class="ptab p-safety" data-p="safety" onclick="setProfile('safety',this)">Safety</button>
<button class="ptab p-investment" data-p="investment" onclick="setProfile('investment',this)">Investment</button>
<button class="ptab p-nightlife" data-p="nightlife" onclick="setProfile('nightlife',this)">Nightlife</button>
<button class="ptab p-infrastructure" data-p="infrastructure" onclick="setProfile('infrastructure',this)">Infrastructure</button>
</div>
</div>
<div id="district-block">
<div id="district-lbl">Districts · ranked by profile</div>
<div id="district-list"></div>
</div>
<!-- Data Freshness -->
<div id="freshness-block">
<div id="freshness-title">Data Freshness</div>
<div class="fresh-row">
<div class="fresh-source">quiXzoom observations</div>
<div class="fresh-val"><div class="fresh-dot recent"></div><span id="fresh-qx">Jun 18, 2026</span></div>
</div>
<div class="fresh-row">
<div class="fresh-source">Official city data</div>
<div class="fresh-val"><div class="fresh-dot recent"></div><span id="fresh-official">Jun 15, 2026</span></div>
</div>
<div class="fresh-row">
<div class="fresh-source">Trafikverket roadwork</div>
<div class="fresh-val"><div class="fresh-dot live"></div><span id="fresh-traffic">Live · <span id="fresh-traffic-time">--:--</span></span></div>
</div>
<div class="fresh-row">
<div class="fresh-source">Live Pulse activity</div>
<div class="fresh-val"><div class="fresh-dot live"></div><span>Streaming</span></div>
</div>
<div class="fresh-row">
<div class="fresh-source">Police events</div>
<div class="fresh-val"><div class="fresh-dot live"></div><span id="police-fresh">Loading...</span></div>
</div>
<div class="fresh-row">
<div class="fresh-source">SCB demographics</div>
<div class="fresh-val"><div class="fresh-dot recent"></div><span>2024 annual</span></div>
</div>
</div>
</div>
<!-- MOBILE BOTTOM SHEET -->
<div id="bottom-sheet-backdrop" onclick="closeBottomSheet()"></div>
<div id="bottom-sheet">
<div id="bottom-sheet-handle"></div>
<button id="bottom-sheet-close" onclick="closeBottomSheet()">&#215;</button>
<div id="bottom-sheet-content"></div>
</div>
<!-- MAP -->
<div id="map-wrap">
<div id="map-topbar">
<a href="https://landvex.com" id="map-logo">Land<em>vex</em></a>
<div class="map-sep"></div>
<div id="map-city-label">Stockholm — <span id="map-profile-label">Business</span></div>
<div id="map-profile-chip">Business</div>
<div id="map-conf">Source First</div>
<div>
<button onclick="map.setView([59.370,18.040],9)">SE</button>
<button onclick="map.setView([52.5,10.0],5)">EU</button>
<button onclick="map.setView([25.0,40.0],3)">Global</button>
</div>
</div>
<!-- Layer Toggles -->
<div id="layer-bar">
<div class="ltoggle on" id="ltog-districts" onclick="toggleLayer('districts',this)">
<div class="ltoggle-dot d-districts"></div>Areas
</div>
<div class="ltoggle" id="ltog-roadwork" onclick="toggleLayer('roadwork',this)">
<div class="ltoggle-dot d-roadwork"></div>Road works
</div>
<div class="ltoggle" id="ltog-pulse" onclick="toggleLayer('pulse',this)">
<div class="ltoggle-dot d-pulse"></div>Activity
</div>
<div class="ltoggle" id="ltog-alerts" onclick="toggleLayer('alerts',this)">
<div class="ltoggle-dot d-alerts"></div>Contradictions
</div>
<div class="ltoggle on" id="ltog-police" onclick="togglePolice(this)">
<div class="ltoggle-dot"></div>Police
</div>
<div class="ltoggle" id="ltog-umi" onclick="toggleLayer('umi',this)">
<div class="ltoggle-dot"></div>Momentum
</div>
</div>
<div id="map"></div>
<div id="map-legend">
<div>Intelligence Score</div>
<div>
<div><div></div>Strong (810)</div>
<div><div></div>Moderate (68)</div>
<div><div></div>Weak (46)</div>
<div><div></div>Poor (&lt;4)</div>
<div><div></div>Contradiction</div>
</div>
<div>Tap any area for details</div>
</div>
</div>
<!-- RIGHT -->
<div id="right">
<div id="right-header">
<div id="right-profile-label">Profile</div>
<div id="right-title">Business</div>
</div>
<div id="kpi-grid"></div>
<div id="insights-block">
<div id="insights-title">Key Insights</div>
<div id="insights-list"></div>
</div>
<!-- Contradiction Alerts -->
<div id="contra-block">
<div id="contra-header">
<div id="contra-title"><div class="contra-live-dot"></div>Contradiction Alerts</div>
<div class="contra-count" id="contra-count">2 active</div>
</div>
<div id="contra-list"></div>
</div>
<div id="caution-block">
<div class="caution-card">
<div class="caution-lbl">Operational Caution</div>
<div id="caution-list"></div>
</div>
</div>
<!-- Change Events Engine -->
<div id="events-engine">
<div>
Change Events
<span id="event-critical-count">0 critical</span>
</div>
<div id="event-list"></div>
</div>
<!-- Weekly Intelligence Brief -->
<div id="weekly-brief">
<div>
Weekly Intelligence Brief
<span>Week 25 · Jun 1621</span>
</div>
<div>
<div>01 · Security deterioration, Rinkeby</div>
<div>Police events up 280% vs 4-week avg. Contradiction Index: HIGH. Official classification has not been updated. Recommend: escalate to municipal review.</div>
<div>Sources: Polisen.se · quiXzoom 1 102 obs · Contradiction confirmed</div>
</div>
<div>
<div>02 · Strategic signal: Nacka acceleration</div>
<div>Tunnel milestone confirmed 14 months ahead of schedule. Commercial permit applications +34% MoM. Investment thesis: accelerating.</div>
<div>Sources: Trafikverket · Nacka kommun · quiXzoom 389 obs</div>
</div>
<div>
<div>03 · Commercial vacancy rising, Södermalm</div>
<div>18 new vacancies detected on Götgatan corridor. Pattern matches early-stage commercial stress. Monitor: if +8 more in 30 days, escalate to Important.</div>
<div>Sources: quiXzoom 47 obs · Fastighetsregistret · quiXzoom Change Detection</div>
</div>
</div>
<!-- City macro intelligence -->
<div id="macro-block">
<div>City Macro Intelligence</div>
<div id="macro-grid">
<div>
<div>GDP / capita</div>
<div id="gdp-val">Loading</div>
<div>USD · World Bank</div>
</div>
<div>
<div>Political Stability</div>
<div>8.9<span>/10</span></div>
<div>WGI 2023 · top 5% global</div>
</div>
<div>
<div>Rule of Law</div>
<div>9.2<span>/10</span></div>
<div>WGI 2023 · Rank 6 global</div>
</div>
<div>
<div>Corruption Index</div>
<div>82<span>/100</span></div>
<div>TI CPI 2024 · Rank 6</div>
</div>
</div>
<!-- Security level -->
<div>
<div>
<div>Security Assessment</div>
<div>LOW RISK</div>
</div>
<div>Sweden maintains one of Europes most stable security environments. No active conflict. Terrorism risk: low-medium (NCSD level 3/5). Gang-related violence concentrated in specific outer suburbs.</div>
<div>Sources: SÄPO 2025 · GPI 2024 (rank 14) · OSAC</div>
</div>
</div>
<!-- News feed -->
<div id="news-block">
<div>
Stockholm News
<span id="news-time">Loading...</span>
</div>
<div id="news-list"><div>Fetching SVT Stockholm...</div></div>
</div>
<!-- Urban events -->
<div id="events-block">
<div>Urban Events & Notices</div>
<div id="events-list"></div>
</div>
<div id="right-footer">
<div>
<div>Source First Architecture</div>
<span>DATA</span> Identifiable sources with date + confidence<br>
<span>OBS</span> quiXzoom verified field observations<br>
<span>MODEL</span> Transparent index with listed inputs<br>
<span>FORECAST</span> Statistical patterns, not predictions<br>
<a href="/methodology/" >Full methodology →</a>
</div>
</div>
</div>
</div>
<script>
function sourceChain(items){
return `<div class="src-chain">${items.map(i=>`<span class="src-tag src-${i.type}">${i.type==='data'?'DATA':i.type==='obs'?'OBS':i.type==='model'?'MODEL':'FORECAST'} · ${i.label}</span>`).join('')}</div>`;
}
/* DATA */
const D=[
{id:'city',name:'City / Gamla Stan',lat:59.325,lng:18.071,r:1600,
confidence:{score:94,observation_count:1247},
s:{business:9.2,tourist:9.5,safety:8.9,investment:8.1,nightlife:6.2,infrastructure:9.0},
c:'low',ct:'Observed conditions align with official data. Minor seasonal peaks in petty crime not reflected in annual statistics.',
ins:{business:'Prime CBD. HQ addresses, banks, law firms. Highest foot traffic density in Sweden.',tourist:'Old Town and Royal Palace. Most visited area. High pickpocket risk in peak season.',safety:'Excellent overall. Petty theft around Stortorget in summer. Night safety: good.',investment:'Mature market. Limited development land. Premium office rents. Stable.',nightlife:'Limited nightlife. Restaurants and bars. Quiet after midnight.',infrastructure:'Excellent metro connectivity (T-Centralen). Pedestrian priority zones.'},
col:'#16a34a',pulse:{level:0.72,label:'High Activity'},umi:+42},
{id:'ostermalm',name:'Östermalm',lat:59.337,lng:18.082,r:1500,
confidence:{score:97,observation_count:1084},
s:{business:8.4,tourist:7.8,safety:9.4,investment:9.1,nightlife:8.8,infrastructure:8.5},
c:'low',ct:'Official data and observed reality align closely. Slight commercial activity underestimation on weekends.',
ins:{business:'Premium addresses. Embassies, private equity, luxury brands. High-net-worth clientele.',tourist:'Market Hall, Strandvägen. Upscale shopping. Less crowded than Gamla Stan.',safety:'Safest district. Low crime across all categories. Excellent lighting.',investment:'Highest residential values in Sweden. Consistent international buyer demand.',nightlife:'High-end bars. Stureplan cluster is the premium nightlife zone.',infrastructure:'Well-maintained. Multiple metro stations.'},
col:'#16a34a',pulse:{level:0.55,label:'Moderate Activity'},umi:+18},
{id:'sodermalm',name:'Södermalm',lat:59.313,lng:18.063,r:1800,
confidence:{score:88,observation_count:1198},
s:{business:6.8,tourist:8.6,safety:7.2,investment:8.4,nightlife:9.4,infrastructure:7.1},
c:'medium',ct:'Contradiction detected: official infrastructure ratings overstate actual road conditions in SoFo. Night incidents underreported Q4 2025.',
ins:{business:'Creative industry hub. Tech startups, media, design. Lower rents than north city.',tourist:'Fotografiska museum, vintage shops, authentic local culture.',safety:'Generally safe. Awareness advised around Medborgarplatsen after midnight.',investment:'Active gentrification. Hornstull and Mariatorget appreciating rapidly.',nightlife:'Best nightlife district. Medborgarplatsen, Folkungagatan. Bars on every block.',infrastructure:'Good metro coverage. Some streets poor condition in SoFo.'},
col:'#d97706',pulse:{level:0.88,label:'Very High Activity'},umi:+68},
{id:'kungsholmen',name:'Kungsholmen',lat:59.331,lng:18.022,r:1500,
confidence:{score:95,observation_count:847},
s:{business:7.9,tourist:5.8,safety:8.6,investment:8.0,nightlife:6.4,infrastructure:8.8},
c:'low',ct:'High alignment. Clean, well-maintained environment confirmed by observations.',
ins:{business:'Government offices, SVT, law firms. Stable business environment.',tourist:'City Hall (Nobel venue). Mostly residential.',safety:'Very safe. Low crime. Family-friendly.',investment:'Strong demand. Close to center. Undervalued vs Östermalm.',nightlife:'Limited but growing around Hantverkargatan.',infrastructure:'Excellent. Well-connected.'},
col:'#16a34a',pulse:{level:0.40,label:'LowModerate'},umi:+34},
{id:'vasastan',name:'Vasastan',lat:59.345,lng:18.048,r:1400,
confidence:{score:96,observation_count:923},
s:{business:7.2,tourist:6.4,safety:8.8,investment:8.7,nightlife:7.6,infrastructure:8.2},
c:'low',ct:'Consistent with official classification. Steady neighbourhood, no anomalies detected.',
ins:{business:'Mixed residential/commercial. Good mid-market offices. Growing tech presence.',tourist:'Odenplan, Stadsbiblioteket. Authentic local feel.',safety:'Safe and quiet. Family area.',investment:'Strong appreciation. Young professional demographics.',nightlife:'Good restaurant scene. Bar density increasing around Odenplan.',infrastructure:'Multiple metro stations. Good cycling infrastructure.'},
col:'#16a34a',pulse:{level:0.50,label:'Moderate Activity'},umi:+52},
{id:'nacka',name:'Nacka / Värmdö',lat:59.311,lng:18.163,r:1900,
confidence:{score:91,observation_count:762},
s:{business:6.2,tourist:7.1,safety:9.1,investment:9.4,nightlife:4.8,infrastructure:7.4},
c:'low',ct:'Observed infrastructure development activity higher than officially reported. Construction progress aligns with investment thesis.',
ins:{business:'Growing tech cluster. Lower costs. Good for scale-ups.',tourist:'Archipelago access, kayaking, outdoor tourism.',safety:'Very safe suburban. Low crime.',investment:'Highest growth potential in Stockholm region. Nacka tunnel driving appreciation.',nightlife:'Limited. Residents go into Stockholm.',infrastructure:'Nacka tunnel under construction — transformative connectivity 2028.'},
col:'#16a34a',pulse:{level:0.30,label:'Low Activity'},umi:+84},
{id:'rinkeby',name:'RinkebyTensta',lat:59.387,lng:17.928,r:2100,
confidence:{score:72,observation_count:614},
s:{business:3.1,tourist:2.2,safety:3.8,investment:5.9,nightlife:3.4,infrastructure:5.2},
c:'high',ct:'CONTRADICTION INDEX HIGH: Official safety classification significantly underrepresents observed conditions. 41% faulty street lighting, elevated incident density, low evening foot traffic. Official data lags by ~18 months.',
ins:{business:'Very limited commercial activity. Local services only.',tourist:'Not a tourist area. High operational risk for unfamiliar visitors.',safety:'Elevated operational risk. Night risk significantly above official classification. Local accompaniment recommended.',investment:'Redevelopment opportunity with government backing. High risk, potential long-term upside.',nightlife:'No formal nightlife. Not recommended.',infrastructure:'Metro accessible. Local street infrastructure poor. 41% faulty lighting observed.'},
col:'#dc2626',pulse:{level:0.18,label:'Sparse Activity'},umi:-22},
{id:'bangkok-sukhumvit', name:'Sukhumvit', lat:13.742, lng:100.557, r:800,
s:{business:7.8, tourist:8.2, safety:5.4, investment:7.1, nightlife:9.1, infrastructure:4.2},
c:'high',
ct:'FIELD VERIFIED 2026-06-21: Official infrastructure: approved. quiXzoom observation: person density high (86% conf), motorcycle traffic dense (82% conf). storefront/signage coverage incomplete — additional missions needed. Contradiction Score: HIGH.',
ins:{business:'Dense commercial strip. High F&B, retail, hotels. quiXzoom: active foot traffic confirmed.',tourist:'Backpacker hub transitioning to premium. High pedestrian density observed.',safety:'Elevated night risk. Cable hazards common. Official data lags reality.',investment:'Rapid gentrification. High upside.',nightlife:'Best nightlife density in Bangkok. Verified foot traffic.',infrastructure:'Critical cable disorder. 38% faulty lighting estimated. Official data: approved — CONTRADICTION.'},
col:'#f97316', umi:+31,
confidence:{score:74,observation_count:312},pulse:{level:0.82,label:'Very High Activity'},
observation:{id:'qx-vid-ban-20260621171332-739d82', frames:73, coverage:60, verified:'2026-06-21'}},
{id:'bkk-silom', name:'Silom', lat:13.724, lng:100.529, r:900,
s:{business:9.1,tourist:7.2,safety:6.8,investment:8.4,nightlife:8.8,infrastructure:6.1},
c:'medium', ct:'Commercial activity exceeds official classification. Infrastructure maintenance lags.',
ins:{business:'Bangkok CBD. Banks, finance, multinationals.',tourist:'Patpong night market, Lumpini Park.',safety:'Generally safe daytime. Night awareness needed.',investment:'Strong appreciation. Regional HQ location.',nightlife:'Patpong area. Diverse options.',infrastructure:'BTS Silom line. Road congestion severe.'},
col:'#d97706', umi:+28},
{id:'bkk-sathorn', name:'Sathorn', lat:13.717, lng:100.539, r:800,
s:{business:9.4,tourist:5.2,safety:7.4,investment:9.1,nightlife:6.8,infrastructure:7.2},
c:'low', ct:'Premium business district. Strong alignment.',
ins:{business:'US Embassy, embassies, luxury offices.',tourist:'Limited tourist appeal.',safety:'Well-secured. Embassy area.',investment:'Highest business real estate in Bangkok.',nightlife:'Premium rooftop bars.',infrastructure:'BTS Chong Nonsi. Good connectivity.'},
col:'#16a34a', umi:+42},
{id:'bkk-chatuchak', name:'Chatuchak', lat:13.800, lng:100.551, r:1200,
s:{business:6.2,tourist:8.8,safety:7.1,investment:7.4,nightlife:4.2,infrastructure:7.8},
c:'medium', ct:'Weekend market drives commercial peaks not reflected in weekday data.',
ins:{business:'Largest weekend market globally. Commerce extreme on weekends.',tourist:'Chatuchak Weekend Market — must-see.',safety:'Good. Crowded but safe.',investment:'Residential growth. MRT access improving.',nightlife:'Limited.',infrastructure:'MRT Mo Chit. Good transport hub.'},
col:'#d97706', umi:+18},
{id:'hk-central', name:'HK Central', lat:22.282, lng:114.158, r:900,
s:{business:9.7,tourist:8.8,safety:9.1,investment:8.4,nightlife:8.6,infrastructure:9.8},
c:'low', ct:'World-class financial centre. Full alignment.',
ins:{business:'HSBC, Standard Chartered HQ. Top Asia finance.',tourist:'Victoria Harbour, Peak Tram.',safety:'Excellent.',investment:'Premium stable. HK dollar peg.',nightlife:'Lan Kwai Fong cluster.',infrastructure:'MTR exceptional. Airport express 24 min.'},
col:'#16a34a', umi:+6},
{id:'mum-bkc', name:'BKC Mumbai', lat:19.065, lng:72.865, r:1100,
s:{business:8.8,tourist:3.2,safety:7.4,investment:8.9,nightlife:5.8,infrastructure:7.2},
c:'medium', ct:'Rapid development outpacing official infrastructure classification.',
ins:{business:'Bandra Kurla Complex — India finance hub. NSE, SEBI.',tourist:'Business only.',safety:'Good for business area.',investment:'Fastest appreciating commercial in India.',nightlife:'Growing premium.',infrastructure:'Metro expansion ongoing. Traffic severe.'},
col:'#d97706', umi:+64},
{id:'london-city', name:'City of London', lat:51.514, lng:-0.088, r:1200,
s:{business:9.6, tourist:7.4, safety:8.8, investment:8.2, nightlife:5.1, infrastructure:9.1},
c:'low', ct:'Strong alignment between official data and observed conditions.',
ins:{business:'Global financial centre. Premium office market.',tourist:'Historic but less touristy than West End.',safety:'Excellent. Low crime, well-lit, cameras everywhere.',investment:'Mature market, stable yields.',nightlife:'Limited — suits 9-to-5 finance crowd.',infrastructure:'World-class. Elizabeth line transformed connectivity.'},
col:'#16a34a', umi:+12,
confidence:{score:96,observation_count:842},pulse:{level:0.61,label:'High Activity'}},
{id:'dubai-downtown', name:'Dubai Downtown', lat:25.197, lng:55.274, r:1500,
s:{business:9.1, tourist:9.4, safety:9.3, investment:8.8, nightlife:7.2, infrastructure:9.5},
c:'low', ct:'Observed environment aligns with official data. High confidence.',
ins:{business:'Premium business address. DIFC proximity.',tourist:'Burj Khalifa, Dubai Mall. Peak tourism.',safety:'Exceptional. Among safest globally.',investment:'Strong capital appreciation trend.',nightlife:'Growing but culturally constrained.',infrastructure:'World-class. Metro, road network excellent.'},
col:'#16a34a', umi:+44,
confidence:{score:92,observation_count:614},pulse:{level:0.74,label:'High Activity'}},
/* ── Stockholm extra districts ── */
{id:'djurgarden', name:'Djurgården', lat:59.326, lng:18.110, r:700,
s:{business:5.2,tourist:9.8,safety:9.1,investment:7.4,nightlife:3.2,infrastructure:8.4},
c:'low', ct:'Observed environment matches official data. Premium cultural destination.',
ins:{business:'Limited office space. Museums, hospitality.',tourist:'Vasa Museum, ABBA Museum, Skansen. Stockholm\'s top attraction.',safety:'Extremely safe. Well-lit, patrolled.',investment:'Premium residential, limited supply.',nightlife:'Almost none — day destination.',infrastructure:'Good. Ferry connections, cycling paths.'},
col:'#16a34a', umi:+8,
confidence:{score:91,observation_count:320},pulse:{level:0.45,label:'Moderate Activity'}},
{id:'hagastaden', name:'Hagastaden', lat:59.352, lng:18.044, r:900,
s:{business:7.8,tourist:4.1,safety:8.9,investment:9.2,nightlife:4.8,infrastructure:8.1},
c:'low', ct:'Major development zone. New life science hub. Official data slightly lags construction activity.',
ins:{business:'New Karolinska, AstraZeneca HQ. Life science cluster.',tourist:'Not a tourist area.',safety:'Very safe. New development.',investment:'Highest development potential in Stockholm. New district being built.',nightlife:'Limited currently — growing.',infrastructure:'New — excellent. Tram lines extended.'},
col:'#16a34a', umi:+91,
confidence:{score:88,observation_count:214},pulse:{level:0.38,label:'LowModerate'}},
{id:'hammarby', name:'Hammarby Sjöstad', lat:59.302, lng:18.087, r:900,
s:{business:6.1,tourist:6.8,safety:8.4,investment:8.6,nightlife:5.9,infrastructure:8.2},
c:'low', ct:'Sustainable urban development. Official data and observations align well.',
ins:{business:'Tech startups, creative offices.',tourist:'Waterfront, architecture tourism.',safety:'Safe. Young demographic.',investment:'Strong appreciation. Sustainable premium.',nightlife:'Growing bar scene.',infrastructure:'Tram, ferry. Excellent waterfront access.'},
col:'#16a34a', umi:+38,
confidence:{score:93,observation_count:487},pulse:{level:0.55,label:'Moderate Activity'}},
{id:'farsta', name:'Farsta', lat:59.244, lng:18.086, r:1400,
s:{business:4.8,tourist:2.1,safety:5.9,investment:6.4,nightlife:3.1,infrastructure:6.8},
c:'medium', ct:'Suburban area with some infrastructure gaps. Official safety data slightly optimistic.',
ins:{business:'Local services, retail.',tourist:'No tourist appeal.',safety:'Moderate. Some evening risk areas.',investment:'Affordable entry point. Long-term upside.',nightlife:'Very limited.',infrastructure:'Metro but limited other connections.'},
col:'#d97706', umi:+14,
confidence:{score:82,observation_count:198},pulse:{level:0.28,label:'Low Activity'}},
/* ── Göteborg districts ── */
{id:'gbg-centrum', name:'Göteborg Centrum', lat:57.706, lng:11.967, r:1200,
s:{business:8.4,tourist:8.9,safety:7.8,investment:8.1,nightlife:8.6,infrastructure:8.8},
c:'medium', ct:'Some traffic congestion underreported in official data. Commercial activity slightly above classification.',
ins:{business:'Nordstan, finance district. Strong commercial.',tourist:'Avenyn, Haga. Top Swedish destination.',safety:'Generally safe. Some evening incidents on Avenyn.',investment:'Stable market. Good yields.',nightlife:'Best nightlife outside Stockholm. Avenyn cluster.',infrastructure:'Excellent tram network. Centralstation hub.'},
col:'#16a34a', umi:+28,
confidence:{score:89,observation_count:512},pulse:{level:0.68,label:'High Activity'}},
{id:'gbg-haga', name:'Haga', lat:57.698, lng:11.949, r:700,
s:{business:6.8,tourist:9.2,safety:8.6,investment:8.8,nightlife:7.4,infrastructure:7.2},
c:'low', ct:'High alignment. Premium gentrified neighbourhood.',
ins:{business:'Boutiques, cafes, creative offices.',tourist:'Most photographed neighbourhood in Gothenburg.',safety:'Very safe. Residential premium.',investment:'Rapid appreciation. Limited supply.',nightlife:'Cosy bars, wine culture.',infrastructure:'Good tram access. Parking limited.'},
col:'#16a34a', umi:+42,
confidence:{score:94,observation_count:378},pulse:{level:0.52,label:'Moderate Activity'}},
{id:'gbg-lindholmen', name:'Lindholmen', lat:57.707, lng:11.939, r:900,
s:{business:9.1,tourist:4.2,safety:8.8,investment:9.4,nightlife:4.1,infrastructure:8.6},
c:'low', ct:'Tech hub exceeds official classification. Volvo, RISE, Chalmers ecosystem.',
ins:{business:'Volvo HQ, tech cluster. Sweden\'s Silicon Valley.',tourist:'Not a tourist area.',safety:'Excellent. Corporate security culture.',investment:'Highest investment score in Gothenburg.',nightlife:'Limited — tech workers commute.',infrastructure:'Ferry to centrum. New bridge planned.'},
col:'#16a34a', umi:+64,
confidence:{score:91,observation_count:294},pulse:{level:0.44,label:'Moderate Activity'}},
{id:'gbg-majorna', name:'Majorna', lat:57.693, lng:11.921, r:1000,
s:{business:5.9,tourist:6.8,safety:8.1,investment:8.2,nightlife:6.8,infrastructure:6.9},
c:'low', ct:'Gentrification in progress. Consistent with observations.',
ins:{business:'Local businesses, creative industry.',tourist:'Authentic waterfront, local culture.',safety:'Safe residential.',investment:'Active gentrification. Good entry prices.',nightlife:'Growing bar scene.',infrastructure:'Tram access. Cycling culture strong.'},
col:'#16a34a', umi:+48,
confidence:{score:87,observation_count:261},pulse:{level:0.46,label:'Moderate Activity'}},
{id:'gbg-angered', name:'Angered', lat:57.764, lng:12.046, r:2000,
s:{business:3.2,tourist:1.8,safety:4.1,investment:5.8,nightlife:2.9,infrastructure:5.4},
c:'high', ct:'CONTRADICTION HIGH: Official data underrepresents observed conditions. Infrastructure decay, high vacancy, elevated incident density.',
ins:{business:'Very limited. Local services only.',tourist:'No tourist appeal.',safety:'Elevated risk. Night incidents common.',investment:'Redevelopment opportunity. Government priority.',nightlife:'Not recommended.',infrastructure:'Metro but poor local street conditions.'},
col:'#dc2626', umi:-18,
confidence:{score:74,observation_count:187},pulse:{level:0.21,label:'Sparse Activity'}},
{id:'gbg-askim', name:'Askim / Frölunda', lat:57.634, lng:11.949, r:1800,
s:{business:5.8,tourist:4.2,safety:8.6,investment:7.4,nightlife:3.8,infrastructure:7.2},
c:'low', ct:'Stable suburban area. Consistent with official data.',
ins:{business:'Frölunda Torg retail cluster.',tourist:'Beaches, nature.',safety:'Very safe.',investment:'Family demand strong.',nightlife:'Limited.',infrastructure:'Tram connections.'},
col:'#16a34a', umi:+22,
confidence:{score:88,observation_count:223},pulse:{level:0.32,label:'Low Activity'}},
/* ── Malmö districts ── */
{id:'malmo-centrum', name:'Malmö Centrum', lat:55.604, lng:13.003, r:1100,
s:{business:7.8,tourist:8.2,safety:7.1,investment:7.8,nightlife:7.9,infrastructure:8.4},
c:'medium', ct:'Night safety slightly below official classification. Commercial activity aligns well.',
ins:{business:'Strong retail, growing tech scene.',tourist:'Stortorget, Lilla Torg. Vibrant city.',safety:'Good by day. Some night risk areas.',investment:'Rising market. Copenhagen proximity premium.',nightlife:'Best in Malmö. Lilla Torg cluster.',infrastructure:'Excellent. Pågatåg, Öresund trains.'},
col:'#16a34a', umi:+34,
confidence:{score:88,observation_count:441},pulse:{level:0.61,label:'High Activity'}},
{id:'malmo-vastra-hamnen', name:'Västra Hamnen', lat:55.612, lng:12.975, r:900,
s:{business:8.1,tourist:8.8,safety:9.2,investment:9.1,nightlife:6.4,infrastructure:8.9},
c:'low', ct:'Showcase sustainable district. Strong alignment official/observed.',
ins:{business:'Premium offices, WeWork, startups.',tourist:'Turning Torso, waterfront.',safety:'Extremely safe. Premium residential.',investment:'Highest Malmö values. Waterfront premium.',nightlife:'Growing.',infrastructure:'Excellent. Ferry to Copenhagen under discussion.'},
col:'#16a34a', umi:+56,
confidence:{score:93,observation_count:318},pulse:{level:0.48,label:'Moderate Activity'}},
{id:'malmo-mollevangen', name:'Möllevången', lat:55.590, lng:13.010, r:800,
s:{business:6.4,tourist:7.8,safety:6.8,investment:7.6,nightlife:8.8,infrastructure:7.1},
c:'medium', ct:'Gentrification active. Night safety incidents slightly higher than official.',
ins:{business:'Ethnic food market, creative businesses.',tourist:'Most authentic Malmö neighbourhood.',safety:'Generally safe. Late night awareness needed.',investment:'Fast appreciation. Artists moving in.',nightlife:'Best alternative scene in Malmö.',infrastructure:'Good tram, cycling.'},
col:'#d97706', umi:+62,
confidence:{score:85,observation_count:276},pulse:{level:0.71,label:'High Activity'}},
{id:'malmo-hyllie', name:'Hyllie', lat:55.560, lng:12.987, r:1400,
s:{business:8.6,tourist:4.2,safety:8.4,investment:9.3,nightlife:3.2,infrastructure:9.4},
c:'low', ct:'Major development zone. Arena, Emporia. Strong infrastructure investment.',
ins:{business:'Emporia mall, Malmö Arena. Event economy.',tourist:'Not a tourist area.',safety:'Safe. Commercial zone.',investment:'Highest development activity in Malmö.',nightlife:'Event-driven only.',infrastructure:'Hyllie station — direct to Copenhagen 20 min.'},
col:'#16a34a', umi:+78,
confidence:{score:90,observation_count:247},pulse:{level:0.39,label:'LowModerate'}},
{id:'malmo-rosengard', name:'Rosengård', lat:55.590, lng:13.042, r:1600,
s:{business:3.4,tourist:2.1,safety:3.9,investment:6.1,nightlife:3.2,infrastructure:5.6},
c:'high', ct:'CONTRADICTION HIGH: Official classification significantly understates observed risk. Infrastructure decay, high vacancy, elevated incidents.',
ins:{business:'Very limited. Local services.',tourist:'Not suitable.',safety:'Elevated risk. Night incidents regular.',investment:'Redevelopment potential. High risk.',nightlife:'Not recommended.',infrastructure:'Metro but poor local conditions.'},
col:'#dc2626', umi:-14,
confidence:{score:73,observation_count:194},pulse:{level:0.19,label:'Sparse Activity'}},
{id:'malmo-limhamn', name:'Limhamn', lat:55.582, lng:12.928, r:1200,
s:{business:5.4,tourist:6.2,safety:9.1,investment:8.4,nightlife:4.8,infrastructure:7.4},
c:'low', ct:'Premium family area. Strong alignment.',
ins:{business:'Local commercial. Limestone heritage.',tourist:'Beaches, ferry to Denmark.',safety:'Among safest in Malmö.',investment:'Strong family demand.',nightlife:'Limited.',infrastructure:'Tram, Öresund bridge access.'},
col:'#16a34a', umi:+28,
confidence:{score:91,observation_count:208},pulse:{level:0.34,label:'Low Activity'}},
// Singapore — Orchard Road
{id:'sg-orchard', name:'Orchard Road', lat:1.304, lng:103.832, r:800,
s:{business:9.2,tourist:9.6,safety:9.8,investment:8.4,nightlife:7.8,infrastructure:9.7},
c:'low', ct:'World-class retail and safety. Full alignment official/observed.',
ins:{business:'Luxury retail, premium offices.',tourist:'Top shopping destination Asia.',safety:'Exceptional. Cameras everywhere.',investment:'Premium stable.',nightlife:'Growing.',infrastructure:'MRT excellent.'},
col:'#16a34a', umi:+22},
// Singapore — Jurong East (tech hub)
{id:'sg-jurong', name:'Jurong East', lat:1.333, lng:103.742, r:1200,
s:{business:8.8,tourist:3.2,safety:9.4,investment:9.1,nightlife:3.8,infrastructure:9.2},
c:'low', ct:'Major business hub. JLD development accelerating.',
ins:{business:'Jurong Lake District — Singapore\'s second CBD.',tourist:'Not a tourist area.',safety:'Very safe.',investment:'Highest growth potential in Singapore.',nightlife:'Limited.',infrastructure:'World-class. New MRT lines.'},
col:'#16a34a', umi:+74},
// Amsterdam — Centrum
{id:'ams-centrum', name:'Amsterdam Centrum', lat:52.370, lng:4.895, r:1100,
s:{business:8.1,tourist:9.4,safety:7.2,investment:7.8,nightlife:8.9,infrastructure:8.6},
c:'medium', ct:'Overtourism creating observable contradiction vs livability metrics.',
ins:{business:'Finance, creative, tech.',tourist:'Top European destination.',safety:'Good but tourist areas require awareness.',investment:'Premium but constrained.',nightlife:'Excellent. Leidseplein, Rembrandtplein.',infrastructure:'World-class cycling, trams.'},
col:'#d97706', umi:+14},
// Amsterdam — Zuidas
{id:'ams-zuidas', name:'Zuidas', lat:52.337, lng:4.874, r:900,
s:{business:9.4,tourist:3.2,safety:9.1,investment:9.2,nightlife:4.8,infrastructure:9.3},
c:'low', ct:'Financial district. Strong alignment.',
ins:{business:'ABN AMRO, Deloitte, ING. Dutch financial hub.',tourist:'Not a tourist area.',safety:'Excellent.',investment:'Premium office market.',nightlife:'Limited.',infrastructure:'Amsterdam Zuid station — direct Schiphol 10 min.'},
col:'#16a34a', umi:+38},
// Berlin — Mitte
{id:'ber-mitte', name:'Berlin Mitte', lat:52.520, lng:13.404, r:1400,
s:{business:8.6,tourist:9.2,safety:7.8,investment:8.4,nightlife:8.2,infrastructure:8.8},
c:'low', ct:'Strong alignment. Premium Berlin district.',
ins:{business:'Government, media, startups.',tourist:'Brandenburg Gate, Museum Island.',safety:'Good. Touristy areas require awareness.',investment:'Appreciation trend strong.',nightlife:'World-famous techno scene nearby.',infrastructure:'U-Bahn, S-Bahn excellent.'},
col:'#16a34a', umi:+32},
// New York — Manhattan Midtown
{id:'nyc-midtown', name:'Midtown Manhattan', lat:40.754, lng:-73.984, r:1500,
s:{business:9.8,tourist:9.4,safety:7.4,investment:8.6,nightlife:8.8,infrastructure:8.2},
c:'medium', ct:'Infrastructure aging vs premium economic activity. Some contradiction in maintenance data.',
ins:{business:'Global financial and media capital.',tourist:'Times Square, Central Park, Empire State.',safety:'Generally safe. Awareness needed.',investment:'Premium, stable long-term.',nightlife:'24/7 city.',infrastructure:'Subway aging but functional.'},
col:'#d97706', umi:+18},
// Tokyo — Shinjuku
{id:'tky-shinjuku', name:'Shinjuku', lat:35.689, lng:139.700, r:1200,
s:{business:9.1,tourist:9.6,safety:9.7,investment:8.2,nightlife:9.8,infrastructure:9.9},
c:'low', ct:'Near-perfect alignment. Japanese maintenance culture reflected in data.',
ins:{business:'Huge office market. Top Tokyo business address.',tourist:'Iconic. Kabukicho, Golden Gai.',safety:'Exceptional.',investment:'Stable, mature market.',nightlife:'Best nightlife density globally.',infrastructure:'World-class. Busiest station on earth.'},
col:'#16a34a', umi:+8},
// Rio de Janeiro — Ipanema
{id:'rio-ipanema', name:'Ipanema', lat:-22.984, lng:-43.198, r:1000,
s:{business:5.8,tourist:9.2,safety:4.8,investment:7.4,nightlife:8.4,infrastructure:6.2},
c:'high', ct:'Safety data significantly understates observed risk, particularly after 22:00.',
ins:{business:'Boutiques, beach economy.',tourist:'World-famous beach.',safety:'Elevated. Official data optimistic.',investment:'High value, high risk.',nightlife:'Excellent but take precautions.',infrastructure:'Moderate. Traffic severe.'},
col:'#f97316', umi:+12},
// Stockholm — fler förorter och kranskommuner
{id:'sthlm-huddinge', name:'Huddinge', lat:59.237, lng:17.981, r:2000,
s:{business:6.2,tourist:3.4,safety:8.1,investment:7.8,nightlife:3.2,infrastructure:7.4},
c:'low', ct:'Stable suburban. Flemingsberg growing as tech/medical hub.',
ins:{business:'Flemingsberg — KTH, Karolinska, tech cluster emerging.',tourist:'No tourist appeal.',safety:'Safe suburban.',investment:'Strong family demand. Undervalued vs inner city.',nightlife:'Very limited.',infrastructure:'Pendeltåg + tunnelbana. Flemingsberg station expanding.'},
col:'#16a34a', umi:+34},
{id:'sthlm-solna', name:'Solna', lat:59.360, lng:18.001, r:1400,
s:{business:8.4,tourist:5.8,safety:8.8,investment:8.6,nightlife:5.4,infrastructure:8.9},
c:'low', ct:'Friends Arena area driving commercial transformation. Alignment strong.',
ins:{business:'AstraZeneca global HQ, Karolinska. Premium business address.',tourist:'Friends Arena, Råsunda.',safety:'Excellent.',investment:'Fastest appreciating in Stockholm region.',nightlife:'Limited but growing.',infrastructure:'Solna station — new. Excellent.'},
col:'#16a34a', umi:+72},
{id:'sthlm-sundbyberg', name:'Sundbyberg', lat:59.362, lng:17.971, r:1100,
s:{business:7.2,tourist:3.8,safety:8.4,investment:8.8,nightlife:4.8,infrastructure:8.6},
c:'low', ct:'Most densely populated city in Sweden. Active development.',
ins:{business:'Growing tech/media cluster.',tourist:'No tourist appeal.',safety:'Good.',investment:'Highest density growth. Strong upside.',nightlife:'Limited.',infrastructure:'Excellent — multiple train lines.'},
col:'#16a34a', umi:+58},
{id:'sthlm-tyreso', name:'Tyresö', lat:59.244, lng:18.229, r:1800,
s:{business:5.4,tourist:4.2,safety:9.1,investment:7.2,nightlife:2.8,infrastructure:6.8},
c:'low', ct:'Safe suburban. Coastal access. Limited commercial.',
ins:{business:'Local services. LandveX AB registered here.',tourist:'Coast, nature.',safety:'Very safe.',investment:'Family market. Stable.',nightlife:'Almost none.',infrastructure:'Bus-dependent. Limited rail.'},
col:'#16a34a', umi:+18},
{id:'sthlm-jarfalla', name:'Järfälla', lat:59.427, lng:17.831, r:2200,
s:{business:5.8,tourist:2.8,safety:8.2,investment:7.4,nightlife:2.4,infrastructure:7.1},
c:'low', ct:'Large suburban. Barkarby commerce growing rapidly.',
ins:{business:'Barkarby — major retail/logistics cluster.',tourist:'No tourist appeal.',safety:'Safe.',investment:'Barkarby development driving growth.',nightlife:'Very limited.',infrastructure:'New tunnelbana to Barkarby 2026.'},
col:'#16a34a', umi:+44},
{id:'sthlm-lidingo', name:'Lidingö', lat:59.367, lng:18.154, r:1600,
s:{business:5.2,tourist:6.4,safety:9.4,investment:8.2,nightlife:3.4,infrastructure:6.8},
c:'low', ct:'Premium island suburb. High income, low density.',
ins:{business:'Local services. Some premium offices.',tourist:'Millesgården, archipelago.',safety:'Top safety in Stockholm region.',investment:'Premium residential. Strong demand.',nightlife:'Very limited.',infrastructure:'Spårvägen, bus. No tunnelbana.'},
col:'#16a34a', umi:+12},
// Göteborg — fler stadsdelar
{id:'gbg-kungsbacka', name:'Kungsbacka', lat:57.488, lng:12.076, r:2000,
s:{business:5.8,tourist:4.2,safety:9.2,investment:7.8,nightlife:2.8,infrastructure:6.8},
c:'low', ct:'Growing commuter town. Alignment strong.',
ins:{business:'Local services. Commuter-driven.',tourist:'Coast access.',safety:'Excellent.',investment:'Strong demand. Gothenburg spillover.',nightlife:'Very limited.',infrastructure:'Pendeltåg to Göteborg 25 min.'},
col:'#16a34a', umi:+28},
{id:'gbg-molndal', name:'Mölndal', lat:57.657, lng:12.013, r:1400,
s:{business:7.8,tourist:3.2,safety:8.6,investment:8.1,nightlife:3.8,infrastructure:7.8},
c:'low', ct:'Industrial heritage transitioning to tech. Alignment strong.',
ins:{business:'Siemens, NCC, strong industrial base.',tourist:'No appeal.',safety:'Good.',investment:'Industrial real estate strong.',nightlife:'Limited.',infrastructure:'Tram connection to Göteborg.'},
col:'#16a34a', umi:+32},
// Malmö — fler kommuner
{id:'malmo-lund', name:'Lund', lat:55.705, lng:13.193, r:1800,
s:{business:8.2,tourist:7.4,safety:9.1,investment:8.4,nightlife:7.8,infrastructure:8.6},
c:'low', ct:'University city. Research hub. Strong alignment.',
ins:{business:'Lund University spin-offs. MaxIV, ESS research facilities.',tourist:'Cathedral, medieval city.',safety:'Very safe.',investment:'Strong student/research demand.',nightlife:'Vibrant student scene.',infrastructure:'Pågatåg, excellent. ESS draws international.'},
col:'#16a34a', umi:+38},
{id:'malmo-helsingborg', name:'Helsingborg', lat:56.046, lng:12.694, r:2000,
s:{business:7.4,tourist:6.8,safety:8.2,investment:7.8,nightlife:6.4,infrastructure:8.1},
c:'low', ct:'Ferry hub. Commercial growth. Strong alignment.',
ins:{business:'Port commerce, Pfizer, regional HQ.',tourist:'Ferry to Denmark, Kärnan.',safety:'Good.',investment:'Appreciation trend positive.',nightlife:'Growing.',infrastructure:'Tåg, ferry. Direct to Copenhagen.'},
col:'#16a34a', umi:+24},
/* ── Stockholm kranskommuner (batch 2) ── */
{id:'sthlm-botkyrka', name:'Botkyrka', lat:59.201, lng:17.834, r:2400,
s:{business:5.1,tourist:3.2,safety:5.8,investment:6.8,nightlife:3.1,infrastructure:6.9},
c:'high', ct:'Contradiction detected: official data underreports social challenges in Alby/Norsborg. Infrastructure maintenance gaps observed.',
ins:{business:'Limited commercial. Fittja, Tumba growing.',tourist:'No appeal.',safety:'Elevated risk in some areas.',investment:'Low entry price. Long-term upside.',nightlife:'Very limited.',infrastructure:'Pendeltåg Tumba. Metro Alby.'},
col:'#dc2626', umi:-8},
{id:'sthlm-nynashamn', name:'Nynäshamn', lat:58.904, lng:17.948, r:2000,
s:{business:4.8,tourist:6.2,safety:9.1,investment:6.8,nightlife:2.4,infrastructure:6.1},
c:'low', ct:'Ferry hub to Gotland. Stable coastal community.',
ins:{business:'Port, ferry terminal, local services.',tourist:'Gotland ferry gateway.',safety:'Very safe.',investment:'Stable coastal demand.',nightlife:'Almost none.',infrastructure:'Pendeltåg terminus.'},
col:'#16a34a', umi:+12},
{id:'sthlm-vallentuna', name:'Vallentuna', lat:59.535, lng:18.080, r:2000,
s:{business:5.4,tourist:4.1,safety:9.2,investment:7.4,nightlife:2.2,infrastructure:6.8},
c:'low', ct:'Growing family suburb. Roslagsbanan improving connectivity.',
ins:{business:'Local services. Growing.',tourist:'Viking rune stones.',safety:'Excellent.',investment:'Strong family demand.',nightlife:'None.',infrastructure:'Roslagsbanan.'},
col:'#16a34a', umi:+32},
{id:'sthlm-osteraker', name:'Österåker', lat:59.481, lng:18.296, r:2200,
s:{business:5.2,tourist:5.8,safety:9.3,investment:7.6,nightlife:2.4,infrastructure:6.4},
c:'low', ct:'Archipelago gateway. Premium lakeside.',
ins:{business:'Local services, marina.',tourist:'Archipelago, lakes.',safety:'Top safety.',investment:'Premium lake/sea access.',nightlife:'Very limited.',infrastructure:'Bus, boat.'},
col:'#16a34a', umi:+24},
{id:'sthlm-vaxholm', name:'Vaxholm', lat:59.402, lng:18.330, r:1200,
s:{business:5.1,tourist:8.4,safety:9.6,investment:8.1,nightlife:3.2,infrastructure:5.8},
c:'low', ct:'Premium archipelago town. Tourist peak summer.',
ins:{business:'Tourism, local services.',tourist:'Most visited archipelago town.',safety:'Exceptional.',investment:'Premium strong demand.',nightlife:'Summer only.',infrastructure:'Ferry from Stockholm.'},
col:'#16a34a', umi:+18},
{id:'sthlm-danderyd', name:'Danderyd', lat:59.400, lng:18.033, r:1400,
s:{business:6.1,tourist:4.2,safety:9.6,investment:8.8,nightlife:2.8,infrastructure:7.4},
c:'low', ct:'Highest income municipality in Sweden. Premium residential.',
ins:{business:'Premium offices, medical.',tourist:'Limited.',safety:'Top Sweden.',investment:'Highest property values outside Östermalm.',nightlife:'Almost none.',infrastructure:'Tunnelbana Mörby.'},
col:'#16a34a', umi:+14},
{id:'sthlm-taby', name:'Täby', lat:59.444, lng:18.069, r:1800,
s:{business:6.8,tourist:3.8,safety:9.4,investment:8.4,nightlife:3.4,infrastructure:7.6},
c:'low', ct:'Premium suburb. Arninge growing commercial.',
ins:{business:'Arninge retail, offices.',tourist:'No appeal.',safety:'Excellent.',investment:'Very strong demand.',nightlife:'Limited.',infrastructure:'Roslagsbanan, pendeltåg.'},
col:'#16a34a', umi:+28},
{id:'sthlm-upplands-vasby', name:'Upplands Väsby', lat:59.519, lng:17.909, r:1800,
s:{business:6.2,tourist:2.8,safety:8.1,investment:7.2,nightlife:2.8,infrastructure:7.8},
c:'low', ct:'Airport corridor growth. Arlanda proximity.',
ins:{business:'Arlanda corridor. Logistics, hospitality.',tourist:'Airport area.',safety:'Good.',investment:'Arlanda premium growing.',nightlife:'Limited.',infrastructure:'Arlanda Express corridor.'},
col:'#16a34a', umi:+38},
{id:'sthlm-sigtuna', name:'Sigtuna', lat:59.617, lng:17.724, r:1800,
s:{business:5.4,tourist:8.2,safety:9.2,investment:7.1,nightlife:3.8,infrastructure:6.8},
c:'low', ct:'Oldest city in Sweden. Tourism strong.',
ins:{business:'Airport hotels, local services.',tourist:'Medieval city, Arlanda nearby.',safety:'Very safe.',investment:'Stable, tourism-driven.',nightlife:'Limited.',infrastructure:'Bus, Airport Express nearby.'},
col:'#16a34a', umi:+16},
{id:'sthlm-upplands-bro', name:'Upplands-Bro', lat:59.519, lng:17.634, r:2000,
s:{business:5.6,tourist:2.8,safety:8.4,investment:7.4,nightlife:2.2,infrastructure:7.1},
c:'low', ct:'Growing western suburb. Bro station hub.',
ins:{business:'Logistics, local.',tourist:'No appeal.',safety:'Good.',investment:'Growth market.',nightlife:'None.',infrastructure:'Pendeltåg Bro.'},
col:'#16a34a', umi:+34},
{id:'sthlm-ektorp', name:'Nacka stad', lat:59.298, lng:18.198, r:1400,
s:{business:6.4,tourist:5.8,safety:9.0,investment:8.8,nightlife:4.2,infrastructure:7.6},
c:'low', ct:'Nacka town centre. Rapid development post-tunnel announcement.',
ins:{business:'Forum Nacka, growing offices.',tourist:'Waterfront.',safety:'Very safe.',investment:'Highest growth Stockholm region.',nightlife:'Growing.',infrastructure:'Pending new metro.'},
col:'#16a34a', umi:+88},
{id:'sthlm-haninge', name:'Haninge', lat:59.170, lng:18.140, r:2400,
s:{business:5.8,tourist:4.8,safety:7.8,investment:7.2,nightlife:3.4,infrastructure:7.2},
c:'medium', ct:'Large southern municipality. Handen growing.',
ins:{business:'Handen centrum, local commerce.',tourist:'Coast access.',safety:'Generally good.',investment:'Affordable entry.',nightlife:'Limited.',infrastructure:'Pendeltåg Handen.'},
col:'#d97706', umi:+22},
{id:'sthlm-sodertaje', name:'Södertälje', lat:59.196, lng:17.625, r:2200,
s:{business:7.4,tourist:4.8,safety:6.8,investment:6.8,nightlife:4.2,infrastructure:7.4},
c:'medium', ct:'Strong industrial base. Safety contradiction in some districts.',
ins:{business:'Scania, AstraZeneca, Anicura. Industrial powerhouse.',tourist:'Södertälje canal.',safety:'Mixed. Some elevated areas.',investment:'Industrial RE strong.',nightlife:'Limited.',infrastructure:'Pendeltåg, E4.'},
col:'#d97706', umi:+18},
{id:'sthlm-norrtalje', name:'Norrtälje', lat:59.758, lng:18.706, r:2400,
s:{business:5.2,tourist:7.8,safety:9.4,investment:7.2,nightlife:4.2,infrastructure:5.8},
c:'low', ct:'Archipelago capital. Summer tourism peak.',
ins:{business:'Tourism, local services.',tourist:'Northern archipelago gateway.',safety:'Excellent.',investment:'Summer cottage premium.',nightlife:'Summer only.',infrastructure:'Bus, boat.'},
col:'#16a34a', umi:+14},
{id:'sthlm-sollentuna', name:'Sollentuna', lat:59.428, lng:17.951, r:1600,
s:{business:7.1,tourist:3.4,safety:8.9,investment:8.2,nightlife:3.8,infrastructure:8.4},
c:'low', ct:'Affluent northern suburb. Häggvik growing.',
ins:{business:'Häggvik commerce, offices.',tourist:'No appeal.',safety:'Excellent.',investment:'Strong premium suburb.',nightlife:'Limited.',infrastructure:'Tunnelbana Häggvik, E4.'},
col:'#16a34a', umi:+36},
{id:'sthlm-ekero', name:'Ekerö', lat:59.297, lng:17.813, r:1800,
s:{business:4.8,tourist:8.4,safety:9.5,investment:7.8,nightlife:2.4,infrastructure:5.6},
c:'low', ct:'Island municipality. Birka UNESCO. Premium lake.',
ins:{business:'Tourism, local.',tourist:'Birka Viking UNESCO, Drottningholm.',safety:'Top safety.',investment:'Premium island living.',nightlife:'None.',infrastructure:'Bridge, ferry.'},
col:'#16a34a', umi:+16},
// ── GÖTEBORGSREGIONEN ──────────────────────────────────────────
{id:'gbg-partille', name:'Partille', lat:57.738, lng:12.106, r:1600,
s:{business:6.8,tourist:3.4,safety:8.8,investment:7.8,nightlife:3.2,infrastructure:7.6},
c:'low', ct:'Affluent eastern suburb. Allum retail strong.',
ins:{business:'Allum shopping, growing offices.',tourist:'No appeal.',safety:'Excellent.',investment:'Strong family demand.',nightlife:'Limited.',infrastructure:'Tram to Göteborg.'},
col:'#16a34a', umi:+28},
{id:'gbg-harryda', name:'Härryda', lat:57.663, lng:12.284, r:1800,
s:{business:7.4,tourist:4.2,safety:9.1,investment:7.6,nightlife:2.8,infrastructure:8.4},
c:'low', ct:'Landvetter Airport municipality. Aviation economy.',
ins:{business:'Landvetter Airport logistics, aviation.',tourist:'Airport gateway.',safety:'Very safe.',investment:'Airport corridor premium.',nightlife:'Very limited.',infrastructure:'E20, Arlandabuss. Direct Landvetter.'},
col:'#16a34a', umi:+42},
{id:'gbg-kungalv', name:'Kungälv', lat:57.871, lng:11.981, r:1800,
s:{business:5.8,tourist:7.2,safety:9.2,investment:7.4,nightlife:3.8,infrastructure:6.8},
c:'low', ct:'Historic fortress town. Growing commuter.',
ins:{business:'Local services. Growing.',tourist:'Bohus Fortress, river.',safety:'Excellent.',investment:'Commuter demand rising.',nightlife:'Limited.',infrastructure:'Bus to Göteborg.'},
col:'#16a34a', umi:+24},
{id:'gbg-ale', name:'Ale', lat:57.963, lng:12.061, r:2000,
s:{business:5.2,tourist:3.8,safety:8.8,investment:7.1,nightlife:2.4,infrastructure:6.6},
c:'low', ct:'Northern Göteborg commuter. Affordable.',
ins:{business:'Local.',tourist:'River, nature.',safety:'Good.',investment:'Affordable entry.',nightlife:'None.',infrastructure:'Pendeltåg.'},
col:'#16a34a', umi:+18},
{id:'gbg-lerum', name:'Lerum', lat:57.770, lng:12.268, r:1800,
s:{business:5.6,tourist:3.8,safety:9.1,investment:7.6,nightlife:2.4,infrastructure:7.4},
c:'low', ct:'Premium eastern commuter. Strong family demand.',
ins:{business:'Local services.',tourist:'Lakes, nature.',safety:'Excellent.',investment:'Premium family suburb.',nightlife:'None.',infrastructure:'Pendeltåg.'},
col:'#16a34a', umi:+32},
{id:'gbg-stenungsund', name:'Stenungsund', lat:58.076, lng:11.818, r:1800,
s:{business:6.8,tourist:4.2,safety:8.8,investment:6.8,nightlife:2.8,infrastructure:6.8},
c:'low', ct:'Petrochemical industry hub. INOVYN, Perstorp.',
ins:{business:'Chemical industry, Stenungsund industrial park.',tourist:'West coast.',safety:'Good.',investment:'Industrial RE stable.',nightlife:'Very limited.',infrastructure:'E6, bus.'},
col:'#16a34a', umi:+14},
{id:'gbg-tjorn', name:'Tjörn', lat:57.994, lng:11.680, r:2000,
s:{business:4.8,tourist:8.8,safety:9.6,investment:7.8,nightlife:3.2,infrastructure:5.6},
c:'low', ct:'Island municipality. Nordic Watercolor Museum. Premium.',
ins:{business:'Tourism, fishing.',tourist:'Nordic Watercolor Museum. Top west coast.',safety:'Exceptional.',investment:'Premium island living.',nightlife:'Summer only.',infrastructure:'Bridge.'},
col:'#16a34a', umi:+16},
{id:'gbg-orust', name:'Orust', lat:58.080, lng:11.660, r:2400,
s:{business:4.6,tourist:8.2,safety:9.5,investment:7.4,nightlife:2.8,infrastructure:5.2},
c:'low', ct:'Largest island on west coast. Boatbuilding heritage.',
ins:{business:'Tourism, boatbuilding.',tourist:'West coast archipelago.',safety:'Top.',investment:'Premium summer.',nightlife:'Summer only.',infrastructure:'Bridge, ferry.'},
col:'#16a34a', umi:+12},
// ── MALMÖ / SKÅNE ──────────────────────────────────────────────
{id:'skane-kristianstad', name:'Kristianstad', lat:56.031, lng:14.154, r:2400,
s:{business:6.8,tourist:6.4,safety:8.6,investment:7.1,nightlife:5.2,infrastructure:7.4},
c:'low', ct:'Regional capital eastern Skåne. Stable.',
ins:{business:'Regional admin, food industry.',tourist:'Barony, architecture.',safety:'Good.',investment:'Affordable regional.',nightlife:'University-driven.',infrastructure:'Tåg, E22.'},
col:'#16a34a', umi:+18},
{id:'skane-trelleborg', name:'Trelleborg', lat:55.375, lng:13.157, r:1800,
s:{business:6.4,tourist:5.8,safety:8.4,investment:6.8,nightlife:3.8,infrastructure:7.2},
c:'low', ct:'Ferry port to Germany. Industrial.',
ins:{business:'Port, Trelleborg AB (tires), industry.',tourist:'Ferry terminal, beaches.',safety:'Good.',investment:'Stable port economy.',nightlife:'Limited.',infrastructure:'Ferry Rostock/Travemünde.'},
col:'#16a34a', umi:+14},
{id:'skane-ystad', name:'Ystad', lat:55.430, lng:13.820, r:1600,
s:{business:5.8,tourist:8.4,safety:9.2,investment:7.2,nightlife:5.4,infrastructure:6.8},
c:'low', ct:'Wallander town. Ferry to Poland/Bornholm. Tourism strong.',
ins:{business:'Tourism, local commerce.',tourist:'Wallander, medieval, ferry.',safety:'Very safe.',investment:'Tourism premium.',nightlife:'Decent for size.',infrastructure:'Ferry Świnoujście/Bornholm.'},
col:'#16a34a', umi:+22},
{id:'skane-landskrona', name:'Landskrona', lat:55.871, lng:12.830, r:1600,
s:{business:5.6,tourist:5.4,safety:6.8,investment:6.8,nightlife:4.2,infrastructure:7.1},
c:'medium', ct:'Moderate contradiction. Some areas higher risk than official.',
ins:{business:'Industry, port.',tourist:'Citadell, Ven ferry.',safety:'Mixed. Some elevated areas.',investment:'Affordable, upside.',nightlife:'Limited.',infrastructure:'Tåg, ferry.'},
col:'#d97706', umi:+16},
{id:'skane-kavlinge', name:'Kävlinge', lat:55.795, lng:13.113, r:1400,
s:{business:5.8,tourist:3.4,safety:9.2,investment:7.8,nightlife:2.8,infrastructure:7.4},
c:'low', ct:'Premium Malmö commuter. Furulund growing.',
ins:{business:'Local, commuter services.',tourist:'No appeal.',safety:'Excellent.',investment:'Strong Malmö commuter.',nightlife:'None.',infrastructure:'Pågatåg.'},
col:'#16a34a', umi:+28},
{id:'skane-staffanstorp', name:'Staffanstorp', lat:55.641, lng:13.207, r:1400,
s:{business:5.4,tourist:3.2,safety:9.4,investment:7.6,nightlife:2.4,infrastructure:7.1},
c:'low', ct:'Affluent Malmö suburb. High income.',
ins:{business:'Local, premium.',tourist:'No appeal.',safety:'Top.',investment:'Premium commuter.',nightlife:'None.',infrastructure:'Pågatåg.'},
col:'#16a34a', umi:+24},
{id:'skane-bstad', name:'Båstad', lat:56.428, lng:12.851, r:1600,
s:{business:5.2,tourist:9.1,safety:9.4,investment:8.2,nightlife:6.8,infrastructure:5.8},
c:'low', ct:'Swedish Riviera. Tennis capital. Premium summer.',
ins:{business:'Tourism, tennis events.',tourist:'Tennis, beaches, premium.',safety:'Excellent.',investment:'Premium summer/year-round.',nightlife:'Summer peak excellent.',infrastructure:'Tåg, E6.'},
col:'#16a34a', umi:+18},
{id:'skane-vellinge', name:'Vellinge', lat:55.472, lng:13.019, r:1400,
s:{business:5.1,tourist:5.8,safety:9.7,investment:8.4,nightlife:2.8,infrastructure:6.8},
c:'low', ct:'Highest safety index Skåne. Premium coastal.',
ins:{business:'Local services.',tourist:'Falsterbo, beaches.',safety:'Highest in Skåne.',investment:'Premium coastal demand.',nightlife:'Very limited.',infrastructure:'Bus.'},
col:'#16a34a', umi:+16},
// ── UPPSALA ────────────────────────────────────────────────────
{id:'uppsala-centrum', name:'Uppsala', lat:59.858, lng:17.645, r:2200,
s:{business:8.1,tourist:7.8,safety:8.6,investment:8.2,nightlife:7.4,infrastructure:8.4},
c:'low', ct:'University city. Strong alignment official/observed.',
ins:{business:'Uppsala University, AstraZeneca R&D, SLU.',tourist:'Cathedral, castle. Strong tourism.',safety:'Very safe.',investment:'Strong student/research demand. Appreciation trend.',nightlife:'Vibrant student scene. Flogsta.',infrastructure:'Pendeltåg Stockholm 40 min. Resecentrum.'},
col:'#16a34a', umi:+44},
{id:'uppsala-knivsta', name:'Knivsta', lat:59.724, lng:17.797, r:1400,
s:{business:5.4,tourist:2.8,safety:9.1,investment:8.1,nightlife:2.2,infrastructure:7.6},
c:'low', ct:'Fastest growing municipality Sweden. Stockholm commuter.',
ins:{business:'Local services, growing.',tourist:'No appeal.',safety:'Excellent.',investment:'Top growth rate Sweden.',nightlife:'None.',infrastructure:'Pendeltåg between Uppsala/Stockholm.'},
col:'#16a34a', umi:+82},
// ── LINKÖPING ──────────────────────────────────────────────────
{id:'linkoping-centrum', name:'Linköping', lat:58.411, lng:15.621, r:2200,
s:{business:8.4,tourist:7.1,safety:8.8,investment:7.8,nightlife:6.8,infrastructure:8.2},
c:'low', ct:'Tech/defence capital. Saab. Strong alignment.',
ins:{business:'Saab, Ericsson, LiU. Tech powerhouse.',tourist:'Old Linköping, Kolmården nearby.',safety:'Very safe.',investment:'Strong tech-driven demand.',nightlife:'Good student scene.',infrastructure:'E4, tåg. Good.'},
col:'#16a34a', umi:+38},
// ── ÖREBRO ─────────────────────────────────────────────────────
{id:'orebro-centrum', name:'Örebro', lat:59.275, lng:15.213, r:2200,
s:{business:7.2,tourist:6.8,safety:7.8,investment:7.4,nightlife:6.4,infrastructure:7.8},
c:'medium', ct:'Some inner-city areas higher risk than official classification.',
ins:{business:'Regional capital. Logistics hub, Gevalia.',tourist:'Örebro Castle.',safety:'Generally good. Some areas watch.',investment:'Growing regional.',nightlife:'Good for size.',infrastructure:'Central Sweden junction. E18/E20.'},
col:'#d97706', umi:+28},
// ── VÄSTERÅS ───────────────────────────────────────────────────
{id:'vasteras-centrum', name:'Västerås', lat:59.609, lng:16.545, r:2200,
s:{business:7.8,tourist:5.8,safety:7.6,investment:7.2,nightlife:5.8,infrastructure:7.8},
c:'medium', ct:'ABB HQ town. Some social challenges not fully reflected.',
ins:{business:'ABB global HQ. Heavy industry. Growing tech.',tourist:'Castle, Mälaren.',safety:'Good overall. Some areas.',investment:'Industrial premium.',nightlife:'Growing.',infrastructure:'Lake port, tåg Stockholm 60 min.'},
col:'#d97706', umi:+24},
// ── NORRKÖPING ─────────────────────────────────────────────────
{id:'norrkoping-centrum', name:'Norrköping', lat:58.594, lng:16.188, r:2000,
s:{business:7.1,tourist:7.4,safety:7.2,investment:7.4,nightlife:6.2,infrastructure:7.6},
c:'medium', ct:'Industrial heritage city. Some contradiction in safety data.',
ins:{business:'Industristaden transformation. Tech startups.',tourist:'Motala Ström, industrial museums.',safety:'Some areas elevated.',investment:'Gentrification active.',nightlife:'Good student scene.',infrastructure:'E4, tåg. Direct Stockholm/Malmö.'},
col:'#d97706', umi:+36},
// ── JÖNKÖPING ──────────────────────────────────────────────────
{id:'jonkoping-centrum', name:'Jönköping', lat:57.782, lng:14.165, r:2200,
s:{business:8.2,tourist:6.8,safety:8.4,investment:7.8,nightlife:6.2,infrastructure:7.8},
c:'low', ct:'Match capital. Strong evangelical heritage. Business hub.',
ins:{business:'Husqvarna, IKEA (nearby), match capital history.',tourist:'Tändsticsmuseet, Vättern.',safety:'Good.',investment:'Strong business demand.',nightlife:'Decent.',infrastructure:'E4, Göteborg/Stockholm junction.'},
col:'#16a34a', umi:+32},
// ── UMEÅ ───────────────────────────────────────────────────────
{id:'umea-centrum', name:'Umeå', lat:63.826, lng:20.263, r:2200,
s:{business:7.4,tourist:6.8,safety:9.2,investment:7.6,nightlife:7.4,infrastructure:7.6},
c:'low', ct:'Fastest growing northern city. Strong alignment.',
ins:{business:'Umeå University, ITS. Tech cluster.',tourist:'Bildmuseet, cultural capital.',safety:'Excellent.',investment:'Consistent growth. Young demographic.',nightlife:'Very good for city size.',infrastructure:'E4, tåg, airport.'},
col:'#16a34a', umi:+54},
// ── LULEÅ ──────────────────────────────────────────────────────
{id:'lulea-centrum', name:'Luleå', lat:65.584, lng:22.157, r:2000,
s:{business:7.8,tourist:5.8,safety:9.4,investment:8.4,nightlife:5.8,infrastructure:7.4},
c:'low', ct:'Data center capital of Europe. SSAB, LKAB. Strategic.',
ins:{business:'H2 Green Steel, SSAB, Facebook/Meta data center.',tourist:'Gammelstad UNESCO.',safety:'Excellent.',investment:'Green industry transformation — massive.',nightlife:'OK for size.',infrastructure:'E4, tåg, airport.'},
col:'#16a34a', umi:+88},
// ── KIRUNA ─────────────────────────────────────────────────────
{id:'kiruna-centrum', name:'Kiruna', lat:67.856, lng:20.225, r:2400,
s:{business:7.2,tourist:8.4,safety:9.6,investment:8.8,nightlife:4.8,infrastructure:6.8},
c:'high', ct:'City moving 3km east due to LKAB mining. Massive contradiction: official maps show old location, physical reality is new construction.',
ins:{business:'LKAB iron ore. Space industry (ESRANGE).',tourist:'Northern lights, Icehotel, LKAB tours.',safety:'Very safe.',investment:'Mining premium. City move = unique opportunity.',nightlife:'Limited.',infrastructure:'Airport, tåg. Remote.'},
col:'#f97316', umi:+62},
// ── SUNDSVALL ──────────────────────────────────────────────────
{id:'sundsvall-centrum', name:'Sundsvall', lat:62.391, lng:17.307, r:2000,
s:{business:6.8,tourist:5.8,safety:8.6,investment:6.8,nightlife:5.4,infrastructure:7.2},
c:'low', ct:'Stone city. Timrå data centers. Regional hub.',
ins:{business:'Timrå data centers, paper industry.',tourist:'Stone city centre.',safety:'Good.',investment:'Stable regional.',nightlife:'Good for size.',infrastructure:'E4, tåg, airport.'},
col:'#16a34a', umi:+22},
// ── GÄVLE ──────────────────────────────────────────────────────
{id:'gavle-centrum', name:'Gävle', lat:60.675, lng:17.142, r:2000,
s:{business:6.8,tourist:6.2,safety:7.8,investment:6.8,nightlife:5.8,infrastructure:7.4},
c:'medium', ct:'Goat city. Port town. Some areas higher risk.',
ins:{business:'Port, paper, Gevalia (coffee).',tourist:'Julbocken, old town.',safety:'Generally good.',investment:'Stable port economy.',nightlife:'Decent.',infrastructure:'E4, tåg Stockholm 90 min.'},
col:'#d97706', umi:+18},
// ── KARLSTAD ───────────────────────────────────────────────────
{id:'karlstad-centrum', name:'Karlstad', lat:59.379, lng:13.503, r:2000,
s:{business:7.1,tourist:7.2,safety:8.8,investment:7.2,nightlife:6.8,infrastructure:7.4},
c:'low', ct:'Sun city. Klarälven delta. Regional capital Värmland.',
ins:{business:'Regional capital. Tetra Pak R&D.',tourist:'Klarälven, sun city.',safety:'Very safe.',investment:'Good regional.',nightlife:'Good university city.',infrastructure:'E18, tåg.'},
col:'#16a34a', umi:+26},
// ── BORÅS ──────────────────────────────────────────────────────
{id:'boras-centrum', name:'Borås', lat:57.721, lng:12.940, r:1800,
s:{business:7.4,tourist:5.8,safety:7.8,investment:7.2,nightlife:5.4,infrastructure:7.4},
c:'medium', ct:'Textile city. E-commerce boom. Some social challenges.',
ins:{business:'Textilhögskolan, e-commerce logistics. BORÅS 2030.',tourist:'Textile museum, art.',safety:'Generally good.',investment:'E-commerce driving growth.',nightlife:'Growing.',infrastructure:'Bus to Göteborg.'},
col:'#d97706', umi:+34},
// ── VISBY / GOTLAND ───────────────────────────────────────────
{id:'gotland-visby', name:'Visby', lat:57.638, lng:18.295, r:1800,
s:{business:5.8,tourist:9.8,safety:9.6,investment:7.8,nightlife:8.4,infrastructure:5.8},
c:'low', ct:'UNESCO medieval city. Medieval Week peak. Summer extreme.',
ins:{business:'Tourism, local services.',tourist:'UNESCO. Medieval Week. Top Sweden.',safety:'Exceptional.',investment:'Summer premium. Year-round growing.',nightlife:'Medieval Week world-class. Summer peak.',infrastructure:'Ferry Nynäshamn/Oskarshamn.'},
col:'#16a34a', umi:+28},
/* ── Stockholm fler stadsdelar (batch 3) ── */
{id:'bromma',name:'Bromma',lat:59.337,lng:17.938,r:2200,
confidence:{score:81,observation_count:445},
s:{business:6.8,tourist:5.2,safety:8.9,investment:7.8,nightlife:5.1,infrastructure:7.9},
c:'low',ct:'Residential suburb. Brommaplan commercial hub growing.',
col:'#16a34a',pulse:{level:0.28,label:'Low'},umi:+12,
ins:{business:'Brommaplan is the commercial centre. Strong SME base.',tourist:'Drottningholm Palace nearby. Tranquil residential.',safety:'Very safe. Low crime consistently.',investment:'Steady appreciation. Family demand strong.',nightlife:'Limited. Brommaplan bars only.',infrastructure:'Good metro. Bromma airport closing 2024.'}},
{id:'farsta2',name:'Farsta',lat:59.244,lng:18.091,r:1800,
confidence:{score:74,observation_count:312},
s:{business:5.9,tourist:4.1,safety:7.4,investment:6.8,nightlife:4.8,infrastructure:7.2},
c:'medium',ct:'Southern suburb. Farsta Centrum commercial anchor. Mixed socioeconomics.',
col:'#ca8a04',pulse:{level:0.35,label:'LowModerate'},umi:+8,
ins:{business:'Farsta Centrum mall dominant. Limited office space.',tourist:'Tyresö nature reserve access.',safety:'Generally safe. Some tension in outer areas.',investment:'Affordable entry. Infrastructure upgrades planned.',nightlife:'Very limited.',infrastructure:'Metro terminus. Bus connections good.'}},
{id:'skarholmen',name:'Skärholmen',lat:59.277,lng:17.908,r:1600,
confidence:{score:71,observation_count:287},
s:{business:5.6,tourist:3.8,safety:6.9,investment:7.2,nightlife:4.2,infrastructure:7.5},
c:'medium',ct:'Western suburb. Major redevelopment underway. High upside.',
col:'#ca8a04',pulse:{level:0.41,label:'Moderate'},umi:+22,
ins:{business:'Skärholmen Centrum large retail. Industrial pockets.',tourist:'Gömmaren lake area.',safety:'Elevated incidents historically. Improvement trend.',investment:'Significant upside. City development focus area.',nightlife:'Minimal.',infrastructure:'Metro direct to T-Centralen. Good road access.'}},
{id:'spanga',name:'Spånga-Tensta',lat:59.388,lng:17.899,r:1700,
confidence:{score:68,observation_count:241},
s:{business:5.4,tourist:3.5,safety:6.5,investment:6.9,nightlife:4.0,infrastructure:7.1},
c:'high',ct:'Official data significantly lags observed reality. Active monitoring.',
col:'#dc2626',pulse:{level:0.52,label:'ModerateHigh'},umi:+31,
ins:{business:'Local commercial. Limited corporate presence.',tourist:'Not a tourist area.',safety:'Elevated. Contradiction between official and observed.',investment:'High risk, high potential. Long horizon required.',nightlife:'Limited.',infrastructure:'Metro via Tensta/Rinkeby. Bus connections.'}},
{id:'alvsjoe',name:'Älvsjö',lat:59.278,lng:17.991,r:1400,
confidence:{score:83,observation_count:389},
s:{business:7.1,tourist:4.9,safety:8.7,investment:7.9,nightlife:4.5,infrastructure:8.1},
c:'low',ct:'Stockholm International Fairs. Strong business event hub.',
col:'#16a34a',pulse:{level:0.22,label:'Low'},umi:+15,
ins:{business:'Stockholmsmässan — major events venue. Significant B2B traffic.',tourist:'Event-driven tourism. Lacks permanent attractions.',safety:'Very safe. Well-maintained.',investment:'Solid. Commercial and residential balance.',nightlife:'Event-dependent.',infrastructure:'Commuter train direct. E4/E20 nearby.'}},
{id:'liljeholmen',name:'Liljeholmen',lat:59.308,lng:18.020,r:1500,
confidence:{score:87,observation_count:512},
s:{business:7.4,tourist:5.6,safety:8.5,investment:8.3,nightlife:6.2,infrastructure:8.4},
c:'low',ct:'Fastest growing inner-suburb. Liljeholmen hub premium development.',
col:'#16a34a',pulse:{level:0.38,label:'LowModerate'},umi:+28,
ins:{business:'Major office cluster. ICA, Ericsson nearby. Growing.',tourist:'Tanto allotments. Hornstull proximity.',safety:'Very safe. Premium feel.',investment:'Strong. Among fastest appreciating in Stockholm.',nightlife:'Hornstull bars close. Growing local scene.',infrastructure:'Metro direct. Excellent.'}},
{id:'enskede',name:'Enskede-Årsta',lat:59.282,lng:18.063,r:1600,
confidence:{score:78,observation_count:334},
s:{business:6.2,tourist:5.1,safety:8.4,investment:7.5,nightlife:5.3,infrastructure:7.7},
c:'low',ct:'Stable residential. Gullmarsplan commercial node growing.',
col:'#16a34a',pulse:{level:0.25,label:'Low'},umi:+11,
ins:{business:'Gullmarsplan emerging. Local retail strong.',tourist:'Globen/Avicii Arena proximity.',safety:'Safe. Residential quality.',investment:'Good value. Underpriced vs Södermalm.',nightlife:'Limited but Gullmarsplan growing.',infrastructure:'Metro good. Globen arena drives traffic.'}},
{id:'vallingby',name:'Vällingby',lat:59.363,lng:17.868,r:1800,
confidence:{score:76,observation_count:298},
s:{business:6.5,tourist:4.8,safety:8.2,investment:7.1,nightlife:4.9,infrastructure:7.8},
c:'low',ct:'Classic ABC-city. Vällingby Centrum undergoing renewal.',
col:'#16a34a',pulse:{level:0.27,label:'Low'},umi:+9,
ins:{business:'Vällingby Centrum anchor. Mixed retail/office.',tourist:'Judarskogens nature reserve.',safety:'Safe. Family suburb.',investment:'Steady. Renewal project boosts outlook.',nightlife:'Limited.',infrastructure:'Metro direct. T-bana end of blue line.'}}
];
/* Roadwork data (Trafikverket fallback — hardcoded realistic demo) */
const ROADWORK=[
{id:'rw1',lat:59.308,lng:18.055,loc:'E4/E20 Söderleden',desc:'Beläggningsarbete, enkelriktning 08:0017:00',type:'Paving',severity:'medium',src:'Trafikverket'},
{id:'rw2',lat:59.316,lng:18.048,loc:'Hornsgatan, Södermalm',desc:'VA-arbete, stängt körfält. Framkomlighet begränsad.',type:'Utility works',severity:'medium',src:'Trafikverket'},
{id:'rw3',lat:59.343,lng:18.058,loc:'Sveavägen / Odenplan',desc:'Ledningsarbete under mark, trafikljusreglering aktiv.',type:'Underground cable',severity:'low',src:'Trafikverket'},
{id:'rw4',lat:59.342,lng:18.102,loc:'Lidingövägen',desc:'Broarbete, hastighetsnedsättning 30 km/h.',type:'Bridge repair',severity:'high',src:'Trafikverket'},
{id:'rw5',lat:59.315,lng:18.145,loc:'Nacka Tunnel ingång',desc:'Tunnelarbete, tillfällig körfältsminskning, varsamhet krävs.',type:'Tunnel work',severity:'high',src:'Trafikverket'}
];
/* Contradiction alerts (medium/high only) */
const CONTRA_ALERTS=[
{distId:'sodermalm',name:'Södermalm',level:'medium',desc:'Road condition rating in SoFo overstated vs observed. Night incidents underreported Q4 2025.',date:'2026-06-18'},
{distId:'rinkeby',name:'RinkebyTensta',level:'high',desc:'Safety classification lags reality by ~18 months. 41% faulty street lighting confirmed on-site.',date:'2026-06-15'}
];
const PROF={
business:{label:'Business',col:'#2d8fcf',chipBg:'rgba(45,143,207,0.15)',chipBorder:'rgba(45,143,207,0.35)',chipCol:'#4aafef'},
tourist:{label:'Tourist',col:'#22c55e',chipBg:'rgba(34,197,94,0.15)',chipBorder:'rgba(34,197,94,0.3)',chipCol:'#4ade80'},
safety:{label:'Safety',col:'#dc2626',chipBg:'rgba(220,38,38,0.15)',chipBorder:'rgba(220,38,38,0.3)',chipCol:'#f87171'},
investment:{label:'Investment',col:'#d97706',chipBg:'rgba(217,119,6,0.15)',chipBorder:'rgba(217,119,6,0.3)',chipCol:'#fbbf24'},
nightlife:{label:'Nightlife',col:'#9333ea',chipBg:'rgba(147,51,234,0.15)',chipBorder:'rgba(147,51,234,0.3)',chipCol:'#c084fc'},
infrastructure:{label:'Infrastructure',col:'#b45309',chipBg:'rgba(180,83,9,0.15)',chipBorder:'rgba(180,83,9,0.3)',chipCol:'#fcd34d'}
};
const PI={
business:{kpis:[{l:'Top District',v:'Östermalm',s:'Premium addresses, embassies',c:'#4aafef'},{l:'CBD Index',v:'9.2/10',s:'City / Gamla Stan leads',c:'#4ade80'},{l:'Avg Office Rent',v:'~4 200',s:'SEK / sqm / year. Inner city',c:'#fbbf24'},{l:'Tech Hub',v:'Södermalm',s:'Lower cost, startup density',c:'#c084fc'}],
ins:[{i:'',t:'<strong>Östermalm & City</strong> are the premium addresses. Tech and creative prefer Södermalm.'},{i:'',t:'<strong>Banking & Finance</strong> concentrated on Strandvägen and Birger Jarlsgatan.'},{i:'',t:'<strong>Business culture:</strong> punctuality essential. Fika is real — lean into it.'},{i:'',t:'<strong>Arlanda Express</strong> from T-Centralen: 20 min to airport.'}],
avoid:['RinkebyTensta: no commercial infrastructure, elevated operational risk','Avoid tourist-area co-working — use Epicenter or SUP46']},
tourist:{kpis:[{l:'Must-See',v:'Gamla Stan',s:'UNESCO Old Town. 12 hrs min.',c:'#4ade80'},{l:'Hidden Gem',v:'Södermalm',s:'Local culture, Fotografiska',c:'#c084fc'},{l:'Day Trip',v:'Archipelago',s:'30 min from Slussen by boat',c:'#4aafef'},{l:'Best View',v:'Monteliusv.',s:'Free. Södermalm ridge.',c:'#fbbf24'}],
ins:[{i:'',t:'<strong>Gamla Stan</strong> before 09:00 — empty streets, golden morning light.'},{i:'',t:'<strong>Fotografiska</strong> in Södermalm — world-class museum. Book ahead.'},{i:'',t:'<strong>Archipelago boats</strong> from Slussen or Nybroplan. Waxholmsbolaget.'},{i:'',t:'Stockholm is <strong>entirely cashless</strong>. No need for SEK cash.'}],
avoid:['Sergels Torg late night — not tourist-friendly after dark','Drottninggatan peak summer: pickpocket risk','RinkebyTensta: not a tourist area, elevated risk']},
safety:{kpis:[{l:'Overall Safety',v:'8.4/10',s:'Top 5 safest EU capitals',c:'#4ade80'},{l:'Contradiction',v:'HIGH',s:'Rinkeby lags reality by 18mo',c:'#f87171'},{l:'Night Risk',v:'LowMed',s:'Central safe. Outer elevated',c:'#fbbf24'},{l:'Emergency',v:'112',s:'Non-emergency: 114 14',c:'#4aafef'}],
ins:[{i:'',t:'<strong>Östermalm, Kungsholmen, Vasastan:</strong> safest. Low risk all hours.'},{i:'',t:'<strong>Södermalm, City:</strong> generally safe. Awareness advised after 01:00.'},{i:'',t:'<strong>RinkebyTensta:</strong> elevated. Night missions require local accompaniment.'},{i:'!',t:'<strong>Contradiction detected:</strong> official Rinkeby data underrepresents reality by ~18 months.'}],
avoid:['RinkebyTensta after dark: 41% faulty lighting, elevated incidents','Sergels Torg late night: disorder risk','Isolated areas near Hässelby after 22:00']},
investment:{kpis:[{l:'Growth Leader',v:'Nacka',s:'Tunnel project +1520% forecast',c:'#fbbf24'},{l:'Stable Yield',v:'Östermalm',s:'34% yield, capital preservation',c:'#4ade80'},{l:'Opportunity',v:'Rinkeby',s:'High risk. Govt redevelopment.',c:'#f87171'},{l:'Catalyst',v:'2028',s:'Nacka metro extension opens',c:'#4aafef'}],
ins:[{i:'',t:'<strong>Nacka tunnel</strong> (2028) is the single largest infrastructure catalyst in the region.'},{i:'',t:'<strong>Vasastan & Södermalm:</strong> active gentrification. Young professional demand.'},{i:'',t:'<strong>Office market:</strong> flight-to-quality ongoing. Premium locations outperform.'},{i:'',t:'<strong>Östermalm</strong> stable safe haven for international capital.'}],
avoid:['Fully-priced inner-city residential — limited upside','Rinkeby commercial without deep local partnership']},
nightlife:{kpis:[{l:'Best District',v:'Södermalm',s:'Most bars per block. Local scene.',c:'#c084fc'},{l:'Premium Zone',v:'Stureplan',s:'Östermalm. High-end. Dress code.',c:'#fbbf24'},{l:'Last Call',v:'03:00',s:'Systembolaget closes 15:00 Sat',c:'#f87171'},{l:'Tip',v:'Folkungag.',s:'Wine bars. Relaxed. Local.',c:'#4ade80'}],
ins:[{i:'',t:'<strong>Medborgarplatsen</strong> (Södermalm): best bar cluster. Peak from 21:00.'},{i:'',t:'<strong>Stureplan:</strong> Spy Bar, Riche, Berns. Queue or know someone.'},{i:'',t:'<strong>Midsommar</strong> (June): entire city celebrates outdoors. Unique.'},{i:'!',t:'<strong>Systembolaget</strong> (state alcohol): buy before 19:00 weekdays, 15:00 Saturday.'}],
avoid:['Sergels Torg after 02:00 — rough crowd','Leaving valuables in coat check at Stureplan clubs']},
infrastructure:{kpis:[{l:'Metro Coverage',v:'94%',s:'Population within 500m of station',c:'#4aafef'},{l:'Road Index',v:'7.8/10',s:'vs 8.4/10 official — deviation',c:'#fbbf24'},{l:'Major Project',v:'Nacka Line',s:'New metro extension 2028',c:'#4ade80'},{l:'Cycling',v:'World-class',s:'Inner city infrastructure top-tier',c:'#c084fc'}],
ins:[{i:'',t:'<strong>T-bana (metro)</strong> is excellent. 3 lines. Single ticket 39 SEK.'},{i:'',t:'<strong>Cycling infrastructure</strong> world-class inner city. Donkey Republic city bikes.'},{i:'',t:'<strong>Slussen redevelopment</strong> ongoing — expected completion 2026.'},{i:'!',t:'<strong>Contradiction:</strong> SoFo road conditions 1.2 pts below official rating.'}],
avoid:['Inner city driving peak hours 0709 and 1618:30: congestion charge','RinkebyTensta bus stops after dark: unreliable, safety risk']}
};
/* STATE */
let profile='business';
let polys={};
let rwMarkers=[];
let pulseMarkers=[];
let alertMarkers=[];
let map;
let layerState={districts:true,roadwork:false,pulse:false,alerts:false,umi:false};
/* HELPERS */
function sc(v){return v>=8?'#4ade80':v>=6?'#fbbf24':v>=4?'#fb923c':'#f87171';}
function rwSevCol(s){return s==='high'?'#f87171':s==='medium'?'#fb923c':'#fbbf24';}
function nowTime(){const n=new Date();return n.toLocaleTimeString('sv-SE',{hour:'2-digit',minute:'2-digit'});}
/* FRESHNESS CLOCK */
function updateFreshnessClock(){
const el=document.getElementById('fresh-traffic-time');
if(el)el.textContent=nowTime();
}
/* LAYER TOGGLE */
function toggleLayer(name,btn){
layerState[name]=!layerState[name];
btn.classList.toggle('on',layerState[name]);
const on=layerState[name];
if(name==='districts'){
Object.values(polys).forEach(p=>on?p.addTo(map):p.remove());
document.querySelectorAll('.label-marker').forEach(m=>on?m.addTo(map):m.remove());
} else if(name==='roadwork'){
rwMarkers.forEach(m=>on?m.addTo(map):m.remove());
} else if(name==='pulse'){
pulseMarkers.forEach(m=>on?m.addTo(map):m.remove());
} else if(name==='alerts'){
alertMarkers.forEach(m=>on?m.addTo(map):m.remove());
} else if(name==='umi'){
renderUMI();
}
}
let umiMarkers = [];
function renderUMI() {
umiMarkers.forEach(m => map.removeLayer(m));
umiMarkers = [];
if (!layerState.umi) return;
D.forEach(d => {
const umi = d.umi || 0;
const col = umi >= 0 ? '#16a34a' : '#dc2626';
const sign = umi >= 0 ? '+' : '';
const icon = L.divIcon({
className: '',
html: `<div>${sign}${umi}</div>`,
iconAnchor: [20, 10]
});
const m = L.marker([d.lat - 0.008, d.lng], {icon, interactive: false});
if (layerState.umi) m.addTo(map);
umiMarkers.push(m);
});
}
/* DISTRICT LIST */
function buildList(p){
const sorted=[...D].sort((a,b)=>b.s[p]-a.s[p]);
document.getElementById('district-list').innerHTML=sorted.map(d=>{
const s=d.s[p],c=sc(s);
const cl=d.c==='low'?'dc-low':d.c==='medium'?'dc-med':'dc-high';
const ct=d.c==='low'?'Aligned':d.c==='medium'?'Deviation':'Contradiction';
return `<div class="dcard" onclick="focusDist('${d.id}')">
<div class="dcard-head"><div class="dcard-name">${d.name}</div><div class="dcard-score">${s}</div></div>
<div class="dcard-desc">${d.ins[p].substring(0,70)}…</div>
<span class="dcard-contra ${cl}">${ct}</span>
</div>`;
}).join('');
}
/* RIGHT PANEL */
function buildRight(p){
const pi=PI[p],pr=PROF[p];
document.getElementById('right-title').textContent=pr.label.split(' ').slice(1).join(' ')+' Intelligence';
document.getElementById('kpi-grid').innerHTML=pi.kpis.map(k=>`
<div class="kpi"><div class="kpi-label">${k.l}</div><div class="kpi-value">${k.v}</div><div class="kpi-sub">${k.s}</div></div>`).join('');
document.getElementById('insights-list').innerHTML=pi.ins.map(i=>`
<div class="insight-row"><div class="insight-icon">${i.i||'—'}</div><div class="insight-text">${i.t}</div></div>`).join('');
document.getElementById('caution-list').innerHTML=pi.avoid.map(a=>`
<div class="caution-row"><div class="caution-dot"></div><span>${a}</span></div>`).join('');
}
/* CONTRADICTION ALERTS PANEL */
function buildContraAlerts(){
document.getElementById('contra-count').textContent=`${CONTRA_ALERTS.length} active`;
document.getElementById('contra-list').innerHTML=CONTRA_ALERTS.map(ca=>`
<div class="contra-card c-${ca.level}">
<div class="contra-card-head">
<div class="contra-card-name">${ca.name}</div>
<div class="contra-card-badge ${ca.level}">${ca.level.toUpperCase()}</div>
</div>
<div class="contra-card-desc">${ca.desc}</div>
<div class="contra-card-meta">
<div class="contra-card-date">${ca.date}</div>
<button class="contra-view-btn" onclick="focusDist('${ca.distId}')">View details</button>
</div>
</div>`).join('');
}
/* DISTRICT POPUP */
function buildPopup(d,p){
const s=d.s[p],c=sc(s);
const cl=d.c;
const clabels={low:'CONTRADICTION: LOW',medium:'CONTRADICTION: MEDIUM',high:'CONTRADICTION: HIGH'};
const bars=Object.entries(d.s).map(([k,v])=>{
const bc=sc(v),pct=Math.round(v*10);
const active=k===p;
const labels={business:'BIZ',tourist:'TOUR',safety:'SAFE',investment:'INV',nightlife:'NITE',infrastructure:'INFRA'};
return `<div class="mpop-bar-row">
<div class="mpop-bar-lbl">${labels[k]||k}</div>
<div class="mpop-bar-track"><div class="mpop-bar-fill"></div></div>
<div class="mpop-bar-val">${v}</div>
</div>`;
}).join('');
return `<div class="mpop">
<div class="mpop-eyebrow">
<span>LANDVEX ASSESSMENT</span>
<span>UMI ${d.umi>=0?'+':''}${d.umi||0}</span>
</div>
<div class="mpop-name">${d.name}</div>
<div class="mpop-score-row">
<div class="mpop-score">${s}</div>
<div class="mpop-score-denom">/10</div>
<div class="mpop-score-label">${PROF[p].label.split(' ').slice(1).join(' ')} score</div>
</div>
<div class="mpop-bars">${bars}</div>
<div class="mpop-contra ${cl}"><span class="mpop-contra-lbl">${clabels[cl]}</span>${d.ct}</div>
${confidenceBlock(d.id)}
<div class="mpop-insight">${d.ins[p]}</div>
${d.observation ? `<div>
<div>quiXzoom Field Verified</div>
<div>Coverage: ${d.observation.coverage}% · ${d.observation.frames} frames · ${d.observation.verified}</div>
<div>Observation ID: ${d.observation.id}</div>
</div>` : ''}
${getSCBPopup(d.id)}
${getHousingPopup(d.id)}
${getSchoolPopup(d.id)}
${getHealthPopup(d.id)}
${getCVIPopup(d.id)}
${getEconomicDNA(d.id)}
${getPricePopup(d.id)}
${sourceChain([
{type:'obs',label:'quiXzoom · '+d.confidence.observation_count+' obs'},
{type:'data',label:'Stockholm stad · SCB 2024'},
{type:'model',label:'Landvex Intelligence v1.2 · Conf '+d.confidence.score+'%'}
])}
</div>`;
}
/* SET PROFILE */
function setProfile(p,btn){
profile=p;
document.querySelectorAll('.ptab').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
const pr=PROF[p];
const chip=document.getElementById('map-profile-chip');
chip.textContent=pr.label;
chip.style.cssText=`font-size:10px;font-weight:700;border-radius:4px;padding: 24px;border:1px solid;letter-spacing:0.3px;background:${pr.chipBg};color:${pr.chipCol};border-color:${pr.chipBorder}`;
const lbl=document.getElementById('map-profile-label');
if(lbl)lbl.textContent=pr.label.split(' ').slice(1).join(' ');
buildList(p);buildRight(p);
D.forEach(d=>{
const poly=polys[d.id];if(!poly)return;
const c=sc(d.s[p]);
poly.setStyle({color:c,fillColor:c});
poly.bindPopup(buildPopup(d,p),{maxWidth:260,minWidth:250});
// Re-attach mobile click handler
poly.off('click').on('click',function(){
if(isMobile()){setTimeout(()=>{map.closePopup();openBottomSheet(buildPopup(d,p));},10);}
});
});
}
/* FOCUS DISTRICT */
/* ── MOBILE BOTTOM SHEET ───────────────────────────────────── */
function isMobile(){return window.innerWidth<=900;}
function openBottomSheet(html){
const bs=document.getElementById('bottom-sheet');
const bd=document.getElementById('bottom-sheet-backdrop');
const bc=document.getElementById('bottom-sheet-content');
bc.innerHTML=html;
bs.classList.add('open');
bd.classList.add('open');
document.body.style.overflow='hidden';
}
function closeBottomSheet(){
const bs=document.getElementById('bottom-sheet');
const bd=document.getElementById('bottom-sheet-backdrop');
bs.classList.remove('open');
bd.classList.remove('open');
document.body.style.overflow='';
// Close any open Leaflet popups too
map.closePopup();
}
// Swipe down to close
(function(){
let startY=0;
document.getElementById('bottom-sheet').addEventListener('touchstart',e=>{
startY=e.touches[0].clientY;
},{passive:true});
document.getElementById('bottom-sheet').addEventListener('touchend',e=>{
if(e.changedTouches[0].clientY - startY > 60) closeBottomSheet();
},{passive:true});
})();
function focusDist(id){
const d=D.find(x=>x.id===id);
if(!d||!polys[id])return;
map.setView([d.lat,d.lng],13,{animate:true,duration:0.4});
setTimeout(()=>{
if(isMobile()){
openBottomSheet(buildPopup(d,profile));
} else {
polys[id].openPopup();
}
},450);
}
/* ROADWORK MARKERS */
function buildRoadworkMarkers(){
rwMarkers.forEach(m=>m.remove());rwMarkers=[];
ROADWORK.forEach(rw=>{
const col=rwSevCol(rw.severity);
const icon=L.divIcon({
className:'',
html:`<div></div>`,
iconSize:[14,14],iconAnchor:[7,7]
});
const marker=L.marker([rw.lat,rw.lng],{icon});
marker.bindPopup(`<div class="rwpop">
<div class="rwpop-eyebrow">TRAFIKVERKET · ROADWORK</div>
<div class="rwpop-name">${rw.loc}</div>
<div class="rwpop-desc">${rw.desc}</div>
<span class="rwpop-badge">${rw.type}</span>
<div class="rwpop-src">Source: ${rw.src} · Demo data</div>
</div>`,{maxWidth:230,minWidth:220});
if(layerState.roadwork)marker.addTo(map);
rwMarkers.push(marker);
});
}
/* LIVE PULSE MARKERS */
function buildPulseMarkers(){
pulseMarkers.forEach(m=>m.remove());pulseMarkers=[];
D.forEach(d=>{
const lvl=d.pulse.level;
const sz=Math.round(8+lvl*10); // much smaller
const col=lvl>0.7?'#c084fc':lvl>0.4?'#60a5fa':'#34d399';
const delay=Math.random()*1.8;
const dur=2+Math.random()*1;
const icon=L.divIcon({
className:'pulse-marker',
html:`<div>
<div class="pulse-outer"></div>
<div class="pulse-inner"></div>
</div>`,
iconSize:[1,1],iconAnchor:[0,0]
});
const m=L.marker([d.lat,d.lng],{icon,interactive:false});
if(layerState.pulse)m.addTo(map);
pulseMarkers.push(m);
});
}
/* ALERT MARKERS (Contradiction high/medium) */
function buildAlertMarkers(){
alertMarkers.forEach(m=>m.remove());alertMarkers=[];
const alertDists=D.filter(d=>d.c==='high'||d.c==='medium');
alertDists.forEach(d=>{
const col=d.c==='high'?'#f87171':'#fbbf24';
const icon=L.divIcon({
className:'',
html:`<div>${d.c==='high'?'':'!'}</div>`,
iconSize:[18,18],iconAnchor:[9,9]
});
const ca=CONTRA_ALERTS.find(x=>x.distId===d.id);
const marker=L.marker([d.lat,d.lng],{icon,zIndexOffset:500});
if(ca){
marker.bindPopup(`<div class="rwpop">
<div class="rwpop-eyebrow"> CONTRADICTION ${d.c.toUpperCase()}</div>
<div class="rwpop-name">${d.name}</div>
<div class="rwpop-desc">${ca.desc}</div>
<div class="rwpop-src">Last observed: ${ca.date}</div>
</div>`,{maxWidth:240,minWidth:230});
}
if(layerState.alerts)marker.addTo(map);
alertMarkers.push(marker);
});
}
/* INIT */
window.addEventListener('DOMContentLoaded',()=>{
map=L.map('map',{center:[59.355,18.040],zoom:9,zoomControl:true,attributionControl:false,
autoPanPaddingTopLeft:[10,110],
autoPanPaddingBottomRight:[10,20]
});
// Try dark tiles first, fallback to OSM if CORS blocks
// CartoDB Dark Matter — free, no API key, proper dark tiles
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',{
maxZoom:19, subdomains:'abcd', attribution:''
}).addTo(map);
/* District circles */
D.forEach(d=>{
const c=sc(d.s.business);
const poly=L.circle([d.lat,d.lng],{
radius:d.r*0.65,color:c,fillColor:c,
fillOpacity:0.14,weight:2,
dashArray:d.c==='high'?'4 3':d.c==='medium'?'6 4':null
});
poly.bindPopup(buildPopup(d,'business'),{maxWidth:260,minWidth:250});
poly.on('click',function(){
if(isMobile()){
setTimeout(()=>{
map.closePopup();
openBottomSheet(buildPopup(d,profile));
},10);
}
});
poly.addTo(map);
polys[d.id]=poly;
if(map.getZoom()>=8){const labelM=L.marker([d.lat,d.lng],{
icon:L.divIcon({className:'label-marker',html:`<div>${d.name}</div>`,iconAnchor:[0,0]}),
interactive:false
});
labelM.addTo(map);}
});
/* Other layers */
const countEl = document.getElementById('district-count');
if (countEl) countEl.textContent = D.length;
buildRoadworkMarkers();
buildPulseMarkers();
buildAlertMarkers();
renderUMI();
/* Right panel */
buildList('business');
buildRight('business');
buildContraAlerts();
/* Live police data */
/* Macro intelligence — wrapped in setTimeout to ensure they run even if earlier code throws */
setTimeout(() => {
try { loadPoliceEvents(); } catch(e) { console.warn('police:', e); }
try { loadGDP(); } catch(e) { console.warn('gdp:', e); }
try { loadNews(); } catch(e) { console.warn('news:', e); }
try { renderUrbanEvents(); } catch(e) { console.warn('events:', e); }
try { renderEvents(); } catch(e) { console.warn('revents:', e); }
}, 100);
/* Freshness clock */
updateFreshnessClock();
setInterval(updateFreshnessClock,30000);
});
/* ── MACRO INTELLIGENCE ───────────────────────────────────────── */
async function loadGDP(){
// World Bank API blocked from server-side — use cached 2024 value
document.getElementById('gdp-val').textContent='$57k';
}
async function loadNews(){
try{
// SVT Stockholm via CORS proxy
const r=await fetch('/api/svt-stockholm');
const d=await r.json();
const parser=new DOMParser();
const xml=parser.parseFromString(d.contents,'text/xml');
const items=xml.querySelectorAll('item');
const list=document.getElementById('news-list');
const timeEl=document.getElementById('news-time');
let html='';
let count=0;
items.forEach(item=>{
if(count>=6)return;
const title=item.querySelector('title');
const link=item.querySelector('link');
const pubDate=item.querySelector('pubDate');
if(!title)return;
const t=title.textContent.replace(/<!\[CDATA\[|\]\]>/g,'').trim();
const l=link?link.textContent.trim():'';
const dt=pubDate?new Date(pubDate.textContent):null;
const age=dt?timeSince(dt):'';
html+=`<div onclick="window.open('${l}','_blank')">
<div>${t}</div>
<div>${age} · SVT Stockholm</div>
</div>`;
count++;
});
list.innerHTML=html||'<div>No news available</div>';
if(timeEl)timeEl.textContent='Updated '+new Date().toLocaleTimeString('sv-SE',{hour:'2-digit',minute:'2-digit'});
}catch(e){
document.getElementById('news-list').innerHTML=`<div>
<a href="https://svt.se/nyheter/lokalt/stockholm" target="_blank" >SVT Stockholm</a><br>
<a href="https://www.dn.se/stockholm" target="_blank" >Dagens Nyheter</a><br>
<a href="https://www.svd.se/stockholm" target="_blank" >Svenska Dagbladet</a>
</div>`;
}
}
function timeSince(date){
const s=Math.floor((new Date()-date)/1000);
if(s<3600)return Math.floor(s/60)+'m ago';
if(s<86400)return Math.floor(s/3600)+'h ago';
return Math.floor(s/86400)+'d ago';
}
const URBAN_EVENTS=[
{date:'Jun 21',title:'Stockholm Pride',type:'Cultural',impact:'High foot traffic Södermalm, Östermalm',icon:'-'},
{date:'Jun 28',title:'Midsommar celebrations',type:'Public holiday',impact:'City-wide closures, reduced services',icon:'-'},
{date:'Jul 4',title:'Stockholm Marathon',type:'Sports',impact:'Road closures central city, 08:0016:00',icon:'-'},
{date:'Jul 15Aug 15',title:'Summer low season',type:'Commercial',impact:'Reduced commercial activity, many businesses closed',icon:'-'},
{date:'Aug 18',title:'Way Out West satellite event',type:'Cultural',impact:'Elevated nightlife activity Södermalm',icon:'-'},
{date:'Sep 3',title:'Stockholm Fashion Week',type:'Commercial',impact:'Premium hotel rates +40%, Östermalm peak',icon:'-'},
{date:'Ongoing',title:'Slussen reconstruction',type:'Infrastructure',impact:'Traffic disruption Södermalm access, until 2026',icon:'-'}
];
function renderUrbanEvents(){
const el=document.getElementById('events-list');
if(!el)return;
el.innerHTML=URBAN_EVENTS.map(e=>`
<div>
<div>${e.date}</div>
<div>
<div>${e.title}</div>
<div>${e.impact}</div>
<div>${e.type}</div>
</div>
</div>`).join('');
}
/* ── POLICE EVENTS (Polisen.se live API) ─────────────────────────────────── */
const INCIDENT_COLORS={
'Misshandel':'#ef4444','Misshandel, grov':'#dc2626',
'Rån':'#dc2626','Rån, försök':'#f97316',
'Skottlossning':'#7f1d1d','Skottlossning, misstänkt':'#991b1b',
'Explosion':'#7f1d1d','Mord/dråp, försök':'#7f1d1d',
'Straffrelaterad':'#dc2626',
'Knivlagen':'#f97316','Vapenlagen':'#f97316',
'Narkotikabrott':'#eab308',
'Stöld':'#f59e0b','Stöld/inbrott':'#f59e0b',
'Bedrägeri':'#d97706',
'Olaga hot':'#f97316','Sexualbrott':'#a855f7',
'Skadegörelse':'#6b7280','Brand':'#f97316',
'Trafikolycka':'#3b82f6','Trafikolycka, personskada':'#2563eb',
'Trafikhinder':'#60a5fa','Rattfylleri':'#60a5fa',
'default':'#6b7280'
};
let policeGroup=L.layerGroup();
let policeVisible=true;
let policeEvents=[];
function togglePolice(btn){
policeVisible=!policeVisible;
btn.classList.toggle('on',policeVisible);
if(policeVisible){policeGroup.addTo(map);}else{map.removeLayer(policeGroup);}
}
async function loadPoliceEvents(){
try{
const now=new Date();
const ym=now.getFullYear()+'-'+String(now.getMonth()+1).padStart(2,'0');
const r=await fetch('https://polisen.se/api/events?locationname=Stockholm&DateTime='+ym);
const data=await r.json();
policeEvents=data.filter(e=>e.location&&e.location.gps&&e.location.gps!=='0,0');
renderPoliceLayer();
updateDistrictSafetyFromPolice();
const pc=document.getElementById('police-count'); if(pc) pc.textContent=policeEvents.length+' events';
document.getElementById('police-fresh').textContent='Live';
}catch(e){
console.warn('Police API unavailable:',e);
const pc2=document.getElementById('police-count'); if(pc2) pc2.textContent='unavailable';
}
}
function renderPoliceLayer(){
policeGroup.clearLayers();
if(!policeVisible)return;
policeEvents.forEach(e=>{
const [lat,lng]=e.location.gps.split(',').map(Number);
if(isNaN(lat)||isNaN(lng))return;
const c=INCIDENT_COLORS[e.type]||INCIDENT_COLORS.default;
const dt=new Date(e.datetime);
const timeStr=dt.toLocaleString('sv-SE',{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'});
const icon=L.circleMarker([lat,lng],{
radius:5,color:c,fillColor:c,fillOpacity:0.75,weight:1
});
icon.bindPopup(`<div>
<div>${e.type}</div>
<div>${e.summary}</div>
<div>Source: Polisen.se · ${timeStr}</div>
</div>`,{maxWidth:240});
if(policeVisible)icon.addTo(policeGroup);
});
policeGroup.addTo(map);
}
function updateDistrictSafetyFromPolice(){
// Räkna incidents per distrikt och uppdatera safety scores
D.forEach(d=>{
const count=policeEvents.filter(e=>{
const [lat,lng]=e.location.gps.split(',').map(Number);
if(isNaN(lat)||isNaN(lng))return false;
const dy=lat-d.lat,dx=lng-d.lng;
return Math.sqrt(dy*dy+dx*dx*0.6)<(d.r/111000);
}).length;
if(count>0){
// Lägg till incident count i distriktskortet
const el=document.getElementById('inc-'+d.id);
if(el)el.textContent=count+' incidents';
}
});
}
/* ── EVENT ENGINE ─────────────────────────────────────────────── */
const EVENTS = [
{id:'e1',district:'rinkeby',type:'critical',category:'Safety',title:'Shooting incident reported',detail:'2nd incident this week near Rinkeby torg. Police events API: +340% vs 30-day avg.',date:'Jun 21, 02:32',sources:['Polisen.se live','quiXzoom observation'],confidence:94},
{id:'e2',district:'sodermalm',type:'important',category:'Commercial',title:'18 new vacancies detected',detail:'Götgatan corridor shows accelerating vacancy. Up from 12 last month.',date:'Jun 20',sources:['quiXzoom observation','Fastighetsregistret'],confidence:88},
{id:'e3',district:'nacka',type:'important',category:'Infrastructure',title:'Tunnel construction milestone',detail:'Nacka tunnel breakthrough confirmed. New metro access 14 months ahead of schedule.',date:'Jun 19',sources:['Trafikverket','Stockholm stad'],confidence:97},
{id:'e4',district:'ostermalm',type:'normal',category:'Commercial',title:'Hotel occupancy +12% MoM',detail:'Östermalm premium hotels showing strong summer demand spike.',date:'Jun 18',sources:['Booking.com data','quiXzoom observation'],confidence:82},
{id:'e5',district:'sodermalm',type:'strategic',category:'Development',title:'Gentrification signal: SoFo',detail:'Coffee shop density +3 in 60 days. Vacancy -4. Classic early gentrification pattern.',date:'Jun 15',sources:['quiXzoom 47 obs','Bolagsregistret'],confidence:79},
{id:'e6',district:'rinkeby',type:'important',category:'Infrastructure',title:'41% street lighting still faulty',detail:'Contradiction confirmed. Official maintenance schedule shows "resolved". quiXzoom: unresolved.',date:'Jun 14',sources:['quiXzoom 112 obs','Stockholm stad (official: resolved)'],confidence:91}
];
const EVENT_COLORS={critical:'#ef4444',important:'#f97316',normal:'#6b7280',strategic:'#a855f7'};
const EVENT_LABELS={critical:'CRITICAL',important:'IMPORTANT',normal:'NORMAL',strategic:'STRATEGIC'};
function renderEvents(){
const list=document.getElementById('event-list');
const critCount=document.getElementById('event-critical-count');
if(!list)return;
const crits=EVENTS.filter(e=>e.type==='critical').length;
critCount.textContent=crits+' critical';
list.innerHTML=EVENTS.map(e=>`
<div onclick="focusDist('${e.district}')">
<div>
<div>${e.title}</div>
<span>${EVENT_LABELS[e.type]}</span>
</div>
<div>${e.detail}</div>
<div>
<span>${e.date} · ${e.category}</span>
<span>Conf ${e.confidence}%</span>
</div>
</div>`).join('');
}
/* ── CONFIDENCE ENGINE ─────────────────────────────────────────── */
const confSources = {
city: [{src:'Official data',w:35,c:96},{src:'quiXzoom obs',w:40,c:96},{src:'Cross-validation',w:25,c:94}],
ostermalm: [{src:'Official data',w:35,c:98},{src:'quiXzoom obs',w:40,c:94},{src:'Cross-validation',w:25,c:96}],
sodermalm: [{src:'Official data',w:35,c:84},{src:'quiXzoom obs',w:40,c:88},{src:'Cross-validation',w:25,c:72}],
kungsholmen:[{src:'Official data',w:35,c:94},{src:'quiXzoom obs',w:40,c:91},{src:'Cross-validation',w:25,c:90}],
vasastan: [{src:'Official data',w:35,c:96},{src:'quiXzoom obs',w:40,c:92},{src:'Cross-validation',w:25,c:92}],
nacka: [{src:'Official data',w:35,c:88},{src:'quiXzoom obs',w:40,c:82},{src:'Cross-validation',w:25,c:78}],
rinkeby: [{src:'Official data',w:35,c:58},{src:'quiXzoom obs',w:40,c:81},{src:'Cross-validation',w:25,c:44}]
};
function confidenceBlock(distId){
const sources = confSources[distId];
if(!sources) return '';
const weighted = Math.round(sources.reduce((s,x)=>s+x.c*x.w/100,0));
const col = weighted>=88?'#4ade80':weighted>=75?'#fbbf24':'#f87171';
return `<div>
<div>
<div>Confidence Engine</div>
<div>${weighted}%</div>
</div>
${sources.map(s=>`<div>
<span>${s.src}</span>
<div>
<div></div>
</div>
<span>${s.c}%</span>
</div>`).join('')}
<div>Weighted composite · Source First Architecture</div>
</div>`;
}
/* SCB DATA (hårdkodad för Stockholm stadsdelar — uppdateras via SCB API) */
/* ── PRICE INDEX DATA ─────────────────────────────────────────── */
// Sources: Hemnet Q1 2026, SvD Bästa Nyheter, Prisjakt, local surveys
const PRICE_DATA={
// beer_bar/pub: 33cl draft SEK
// coffee: standard latte SEK
// lunch/dinner_mid: SEK per person
// apt_rent_sqm: SEK/kvm/month (2nd hand)
// apt_buy_sqm: SEK/kvm (Hemnet Q1 2026)
// hotel_night: mid-range double room SEK
// seven_eleven: basket index (kaffe+macka+energidryck) SEK
// housing_idx: Östermalm=100
city: {beer_bar:98, beer_pub:72, coffee:52, lunch:155, dinner_mid:420, apt_rent_sqm:2150, apt_buy_sqm:98000, hotel_night:1850, seven_eleven:89, housing_idx:73},
ostermalm: {beer_bar:129, beer_pub:89, coffee:62, lunch:185, dinner_mid:620, apt_rent_sqm:2480, apt_buy_sqm:134000, hotel_night:2400, seven_eleven:94, housing_idx:100},
sodermalm: {beer_bar:89, beer_pub:69, coffee:49, lunch:142, dinner_mid:380, apt_rent_sqm:1980, apt_buy_sqm:84000, hotel_night:1420, seven_eleven:84, housing_idx:63},
kungsholmen:{beer_bar:85, beer_pub:65, coffee:48, lunch:138, dinner_mid:360, apt_rent_sqm:1940, apt_buy_sqm:81000, hotel_night:1380, seven_eleven:82, housing_idx:60},
vasastan: {beer_bar:82, beer_pub:64, coffee:47, lunch:135, dinner_mid:345, apt_rent_sqm:1910, apt_buy_sqm:79000, hotel_night:1320, seven_eleven:81, housing_idx:59},
nacka: {beer_bar:72, beer_pub:58, coffee:44, lunch:122, dinner_mid:295, apt_rent_sqm:1640, apt_buy_sqm:62000, hotel_night:1050, seven_eleven:78, housing_idx:46},
rinkeby: {beer_bar:52, beer_pub:44, coffee:38, lunch:95, dinner_mid:195, apt_rent_sqm:1180, apt_buy_sqm:31000, hotel_night:680, seven_eleven:71, housing_idx:23}
};
/* ── SCHOOL DATA ──────────────────────────────────────────── */
// Source: Skolverket öppen statistik 2023/2024, SIRIS-databasen
// avg_merit_gr9: genomsnittligt meritvärde åk 9 (max 340)
// pct_qualified_gr9: andel behöriga till gymnasiet (%)
// pct_passed_all: andel med godkänt i alla ämnen (%)
// teacher_ratio: elever per heltidslärare
// top_schools: namngivna skolor med betyg (offentlig data)
// school_count: antal grundskolor i området
// inspection_status: Skolinspektionens senaste beslut
const SCHOOL_DATA={
city:{
avg_merit_gr9:252, pct_qualified_gr9:93.4, pct_passed_all:88.2,
teacher_ratio:11.2, school_count:8, inspection_status:'Approved',
grade_trend:'+4.2 vs 2021',
top_schools:[
{name:'Klara Teoretiska Gymnasium',type:'Grundskola/Gymnasium',merit:268,note:'Top performing central Stockholm'},
{name:'S:t Eriks gymnasium',type:'Kommunal',merit:244,note:'Strong STEM profile'},
{name:'Norra Latin',type:'Kommunal',merit:238,note:'Arts & humanities focus'}
],
context:'Central Stockholm schools perform well above national average (224). High proportion of educated parents drives results.'
},
ostermalm:{
avg_merit_gr9:274, pct_qualified_gr9:97.1, pct_passed_all:94.8,
teacher_ratio:10.4, school_count:12, inspection_status:'Approved',
grade_trend:'+2.8 vs 2021',
top_schools:[
{name:'Franska Skolan',type:'Fristående/internationell',merit:298,note:'Highest merit in Stockholm'},
{name:'Viktor Rydberg Odenplan',type:'Fristående',merit:291,note:'Consistently top-ranked'},
{name:'Engelska Skolan Östermalm',type:'Fristående',merit:284,note:'International curriculum'}
],
context:'Highest performing district in Stockholm. Premium private schools dominate. Strong parental investment in education.'
},
sodermalm:{
avg_merit_gr9:238, pct_qualified_gr9:91.2, pct_passed_all:85.6,
teacher_ratio:11.8, school_count:22, inspection_status:'Mixed',
grade_trend:'+6.1 vs 2021',
top_schools:[
{name:'Viktor Rydberg Södermalm',type:'Fristående',merit:282,note:'Top private school Söder'},
{name:'Sjöstadsskolan',type:'Kommunal',merit:248,note:'Modern facility, strong results'},
{name:'Kungsholmens Gymnasium',type:'Kommunal',merit:241,note:'Humanities profile'}
],
context:'Mixed results. Strong private schools contrast with some kommunal schools below average. Fastest improving district (+6.1 pts). Gentrification driving parental engagement.'
},
kungsholmen:{
avg_merit_gr9:246, pct_qualified_gr9:92.8, pct_passed_all:87.4,
teacher_ratio:11.4, school_count:9, inspection_status:'Approved',
grade_trend:'+3.4 vs 2021',
top_schools:[
{name:'Kungsholmens Grundskola',type:'Kommunal',merit:261,note:'Highly sought after'},
{name:'Thorildsplans Gymnasium',type:'Kommunal',merit:249,note:'Science & tech focus'},
{name:'Västerorts F-9',type:'Kommunal',merit:238,note:'Good all-round results'}
],
context:'Above average results. Limited school choice vs Östermalm but solid kommunal options. Popular with families.'
},
vasastan:{
avg_merit_gr9:256, pct_qualified_gr9:94.2, pct_passed_all:90.1,
teacher_ratio:11.1, school_count:11, inspection_status:'Approved',
grade_trend:'+5.2 vs 2021',
top_schools:[
{name:'Viktor Rydberg Vasastan',type:'Fristående',merit:288,note:'One of Stockholm\'s best'},
{name:'Matteusskolan',type:'Kommunal',merit:258,note:'Heritage school, excellent rep'},
{name:'Engelska Skolan Vasastan',type:'Fristående',merit:271,note:'Strong English curriculum'}
],
context:'Strong and improving. High concentration of private schools attracting motivated families. Increasingly family-oriented district.'
},
nacka:{
avg_merit_gr9:241, pct_qualified_gr9:91.8, pct_passed_all:86.9,
teacher_ratio:12.1, school_count:28, inspection_status:'Approved',
grade_trend:'+3.8 vs 2021',
top_schools:[
{name:'Nacka gymnasium',type:'Kommunal',merit:258,note:'Strong local reputation'},
{name:'Saltsjöbadens Samskola',type:'Fristående',merit:271,note:'Established private school'},
{name:'Internationella Engelska Skolan Nacka',type:'Fristående',merit:252,note:'IES network'}
],
context:'Good results, improving with new families moving in. Mix of established schools and newer options. New construction driving demographic shift upward.'
},
rinkeby:{
avg_merit_gr9:168, pct_qualified_gr9:66.4, pct_passed_all:58.2,
teacher_ratio:14.8, school_count:14, inspection_status:'Under review',
grade_trend:'+8.4 vs 2021',
top_schools:[
{name:'Rinkebyskolans F-9',type:'Kommunal',merit:192,note:'Best in area, extra resources'},
{name:'Tensta Gymnasium',type:'Kommunal',merit:171,note:'Government priority school'},
{name:'Al-Azharskolan',type:'Fristående',merit:164,note:'Religious independent school'}
],
context:'Significantly below Stockholm average. High proportion of newly arrived pupils. Government priority area with extra resources. Fastest absolute improvement (+8.4 pts) from low base. Contradiction: official optimism vs observed classroom reality.'
}
};
/* ── HEALTH & SOCIAL DATA ──────────────────────────────────── */
// Sources: Socialstyrelsen, Väntetider i vård, Folkihälsomyndigheten, Region Stockholm 2024
// wait_gp_days: median days to get GP appointment
// wait_specialist_days: median days to specialist
// wait_surgery_days: median days to elective surgery
// drug_deaths_per100k: drug-related deaths per 100k inhabitants
// mental_health_pct: share seeking mental health care (%)
// life_expectancy: estimated local life expectancy
// obesity_pct: share with obesity (%)
// sick_leave_pct: share on long-term sick leave (%)
// elder_care_satisfaction: satisfaction score 1-10
const HEALTH_DATA={
city:{
wait_gp_days:4, wait_specialist_days:38, wait_surgery_days:62,
drug_deaths_per100k:8.2, mental_health_pct:14.1, life_expectancy:83.4,
obesity_pct:11.2, sick_leave_pct:3.8, elder_care_satisfaction:7.8,
nearest_hospital:'Karolinska (4 min)', nearest_er:'S:t Göran (6 min)',
pharmacies:12, health_centers:8,
context:'Central location with excellent healthcare access. Below-average wait times due to high density of private clinics.'
},
ostermalm:{
wait_gp_days:3, wait_specialist_days:28, wait_surgery_days:48,
drug_deaths_per100k:5.1, mental_health_pct:12.8, life_expectancy:85.2,
obesity_pct:7.4, sick_leave_pct:2.9, elder_care_satisfaction:8.6,
nearest_hospital:'Danderyds sjukhus (8 min)', nearest_er:'Karolinska (12 min)',
pharmacies:18, health_centers:11,
context:'Highest life expectancy in Stockholm. Lowest drug deaths. High density of private clinics and specialists. Premium healthcare access.'
},
sodermalm:{
wait_gp_days:6, wait_specialist_days:44, wait_surgery_days:71,
drug_deaths_per100k:14.8, mental_health_pct:18.4, life_expectancy:81.9,
obesity_pct:13.6, sick_leave_pct:4.9, elder_care_satisfaction:7.2,
nearest_hospital:'Södersjukhuset (5 min)', nearest_er:'Södersjukhuset (5 min)',
pharmacies:21, health_centers:14,
context:'Highest drug mortality in inner city. Elevated mental health demand. Well-served by Södersjukhuset. Young demographic drives high mental health service use.'
},
kungsholmen:{
wait_gp_days:5, wait_specialist_days:39, wait_surgery_days:64,
drug_deaths_per100k:7.4, mental_health_pct:13.2, life_expectancy:83.8,
obesity_pct:10.8, sick_leave_pct:3.6, elder_care_satisfaction:7.9,
nearest_hospital:'Karolinska (10 min)', nearest_er:'S:t Göran (4 min)',
pharmacies:9, health_centers:6,
context:'Good healthcare access. S:t Göran ER nearby. Average wait times for Stockholm inner city.'
},
vasastan:{
wait_gp_days:5, wait_specialist_days:37, wait_surgery_days:61,
drug_deaths_per100k:7.8, mental_health_pct:13.9, life_expectancy:83.6,
obesity_pct:10.4, sick_leave_pct:3.7, elder_care_satisfaction:8.1,
nearest_hospital:'Karolinska (8 min)', nearest_er:'Karolinska (8 min)',
pharmacies:11, health_centers:7,
context:'Good access. Karolinska University Hospital nearby. High education level correlates with better health outcomes.'
},
nacka:{
wait_gp_days:8, wait_specialist_days:52, wait_surgery_days:84,
drug_deaths_per100k:6.2, mental_health_pct:11.4, life_expectancy:83.1,
obesity_pct:12.1, sick_leave_pct:4.1, elder_care_satisfaction:7.6,
nearest_hospital:'Nacka Nyckel / Södersjukhuset (18 min)', nearest_er:'Södersjukhuset (18 min)',
pharmacies:14, health_centers:9,
context:'Longer wait times than inner city. No major hospital nearby. Primarily suburban family health needs. Good elder care satisfaction.'
},
rinkeby:{
wait_gp_days:11, wait_specialist_days:68, wait_surgery_days:112,
drug_deaths_per100k:18.4, mental_health_pct:22.1, life_expectancy:79.2,
obesity_pct:22.8, sick_leave_pct:8.4, elder_care_satisfaction:6.1,
nearest_hospital:'Karolinska (22 min)', nearest_er:'Karolinska (22 min)',
pharmacies:4, health_centers:3,
context:'CONTRADICTION: official data underreports health burden. Highest drug mortality, longest wait times, lowest life expectancy in Stockholm. Critically underserved. Mental health demand 58% above city average.'
}
};
function getHealthPopup(distId){
const h=HEALTH_DATA[distId];
if(!h)return '';
const leColor=h.life_expectancy>=84?'#4ade80':h.life_expectancy>=82?'#fbbf24':'#f87171';
const drugColor=h.drug_deaths_per100k<=6?'#4ade80':h.drug_deaths_per100k<=10?'#fbbf24':h.drug_deaths_per100k<=15?'#f97316':'#f87171';
const waitColor=(d)=>d<=5?'#4ade80':d<=7?'#fbbf24':d<=10?'#f97316':'#f87171';
const isContra=distId==='rinkeby'||distId==='sodermalm';
return `<div>
<div>HEALTH & SOCIAL INDICATORS</div>
<!-- Key stats -->
<div>
<div>
<div>Life exp.</div>
<div>${h.life_expectancy}</div>
<div>years</div>
</div>
<div>
<div>Drug deaths</div>
<div>${h.drug_deaths_per100k}</div>
<div>/100k</div>
</div>
<div>
<div>Mental health</div>
<div>${h.mental_health_pct}%</div>
<div>seeking care</div>
</div>
</div>
<!-- Wait times -->
<div>
<div>Healthcare wait times</div>
<div>
<div>
<span>GP appointment</span>
<span>${h.wait_gp_days} days</span>
</div>
<div>
<span>Specialist referral</span>
<span>${h.wait_specialist_days} days</span>
</div>
<div>
<span>Elective surgery</span>
<span>${h.wait_surgery_days} days</span>
</div>
</div>
</div>
<!-- Additional stats -->
<div>
<div>
<div>Obesity rate</div>
<div>${h.obesity_pct}%</div>
</div>
<div>
<div>Long-term sick leave</div>
<div>${h.sick_leave_pct}%</div>
</div>
<div>
<div>Nearest hospital</div>
<div>${h.nearest_hospital}</div>
</div>
<div>
<div>Elder care score</div>
<div>${h.elder_care_satisfaction}/10</div>
</div>
</div>
${isContra?`<div>
<span>Contradiction: </span>${h.context}
</div>`:''}
<div>${isContra?'':h.context}</div>
${sourceChain([
{type:'data',label:'Socialstyrelsen 2024'},
{type:'data',label:'Väntetider i vård 2024'},
{type:'data',label:'Folkhälsomyndigheten 2024'},
{type:'model',label:'Landvex Health Index v1.0'}
])}
</div>`;
}
function getSchoolPopup(distId){
const sc=SCHOOL_DATA[distId];
if(!sc)return '';
const meritColor=sc.avg_merit_gr9>=260?'#4ade80':sc.avg_merit_gr9>=230?'#fbbf24':sc.avg_merit_gr9>=200?'#f97316':'#f87171';
const qualColor=sc.pct_qualified_gr9>=95?'#4ade80':sc.pct_qualified_gr9>=88?'#fbbf24':'#f87171';
const trendColor=sc.grade_trend.startsWith('+')?'#4ade80':'#f87171';
const natAvg=224;
const vsNat=sc.avg_merit_gr9-natAvg;
const vsNatStr=(vsNat>=0?'+':'')+vsNat+' vs national avg';
const vsNatColor=vsNat>=0?'#4ade80':'#f87171';
return `<div>
<div>SCHOOL PERFORMANCE · SKOLVERKET 2024</div>
<!-- Merit score header -->
<div>
<div>
<div>
<div>Avg merit grade 9</div>
<div>Max 340 · National avg 224</div>
</div>
<div>
<div>${sc.avg_merit_gr9}</div>
<div>${vsNatStr}</div>
</div>
</div>
<div>
<div>
<div>Qualified</div>
<div>${sc.pct_qualified_gr9}%</div>
<div>to gymnasium</div>
</div>
<div>
<div>Pass all</div>
<div>${sc.pct_passed_all}%</div>
<div>subjects</div>
</div>
<div>
<div>Trend</div>
<div>${sc.grade_trend.split(' ')[0]}</div>
<div>vs 2021</div>
</div>
</div>
<div>
<span>${sc.school_count} schools · ${sc.teacher_ratio} pupils/teacher</span>
<span>${sc.inspection_status}</span>
</div>
</div>
<!-- Top schools -->
<div>Top schools</div>
${sc.top_schools.map(s=>`
<div>
<div>
<div>${s.name}</div>
<div>${s.type} · ${s.note}</div>
</div>
<div>${s.merit}</div>
</div>`).join('')}
<div>${sc.context}</div>
${sourceChain([
{type:'data',label:'Skolverket SIRIS 2023/2024'},
{type:'data',label:'Skolinspektionen 2024'},
{type:'model',label:'Landvex School Index v1.0'}
])}
</div>`;
}
/* ── HOUSING STOCK DATA ─────────────────────────────────── */
// Sources: SCB Fastighetsregistret, Boverket, Stockholm stad 2024
// build_era: dominant construction period
// median_build_year: median year of existing stock
// renovated_pct: share of stock renovated post-2000 (%)
// brf_pct: share bostadsrätt (%)
// hyres_pct: share hyresrätt (%)
// condition_idx: Building Condition Index 1-10 (Landvex quiXzoom assessment)
// condition_label: observed condition summary
// avg_apt_size: average apartment size sqm
// vacancy_commercial_pct: commercial vacancy rate (%)
// new_construction: units under construction / planned
const HOUSING_DATA={
city:{
build_era:'18801940 + 19902010',
median_build_year:1935,
renovated_pct:58,
brf_pct:61, hyres_pct:28, other_pct:11,
condition_idx:8.4,
condition_label:'Well-maintained. Heritage facades regularly restored. Some older stock needs windows/plumbing.',
avg_apt_size:62,
vacancy_commercial_pct:4.2,
new_construction:'240 units planned 20262028',
bci_trend:'+0.3 vs 2023'
},
ostermalm:{
build_era:'18901930 (Art Nouveau / Jugend)',
median_build_year:1922,
renovated_pct:72,
brf_pct:74, hyres_pct:18, other_pct:8,
condition_idx:9.1,
condition_label:'Excellent. Premium maintenance. Freshly renovated facades predominant. Low vacancy, high investment.',
avg_apt_size:88,
vacancy_commercial_pct:2.1,
new_construction:'Limited — heritage restrictions',
bci_trend:'+0.1 vs 2023'
},
sodermalm:{
build_era:'19001940 + 19601980',
median_build_year:1944,
renovated_pct:48,
brf_pct:52, hyres_pct:38, other_pct:10,
condition_idx:7.2,
condition_label:'Mixed. 1900-era stock mostly good. 1960s blocks show wear. SoFo gentrification visible. Active renovation wave.',
avg_apt_size:58,
vacancy_commercial_pct:6.8,
new_construction:'580 units 20252028 (Slussen area)',
bci_trend:'+0.8 vs 2023 — fastest improving'
},
kungsholmen:{
build_era:'19101950',
median_build_year:1938,
renovated_pct:54,
brf_pct:58, hyres_pct:32, other_pct:10,
condition_idx:7.8,
condition_label:'Generally good. Solid early 20th century construction. Waterfront properties premium. Some 1940s stock needs façade work.',
avg_apt_size:64,
vacancy_commercial_pct:5.1,
new_construction:'180 units planned',
bci_trend:'+0.4 vs 2023'
},
vasastan:{
build_era:'19001930 (classic Stockholm)',
median_build_year:1926,
renovated_pct:61,
brf_pct:64, hyres_pct:28, other_pct:8,
condition_idx:8.1,
condition_label:'Good to excellent. Classic Stockholm architecture well-preserved. Active renovation market. Rising BCI trend.',
avg_apt_size:67,
vacancy_commercial_pct:4.4,
new_construction:'90 units planned',
bci_trend:'+0.5 vs 2023'
},
nacka:{
build_era:'19701990 + 20102026',
median_build_year:1988,
renovated_pct:38,
brf_pct:48, hyres_pct:28, other_pct:24,
condition_idx:7.4,
condition_label:'Mixed. 1970s-80s suburban stock shows age. New 2010+ developments in excellent condition. Major new construction ongoing.',
avg_apt_size:74,
vacancy_commercial_pct:7.2,
new_construction:'2 400 units under construction (tunnel area)',
bci_trend:'+1.2 vs 2023 — highest absolute gain'
},
rinkeby:{
build_era:'19651975 (miljonprogrammet)',
median_build_year:1971,
renovated_pct:22,
brf_pct:8, hyres_pct:82, other_pct:10,
condition_idx:4.8,
condition_label:'Below average. Miljonprogrammet stock dominates. Visible facade deterioration, graffiti, broken lighting. Limited private investment. Municipally owned majority.',
avg_apt_size:69,
vacancy_commercial_pct:18.4,
new_construction:'340 units social housing planned',
bci_trend:'-0.2 vs 2023'
}
};
function getHousingPopup(distId){
const h=HOUSING_DATA[distId];
if(!h)return '';
const bciColor=h.condition_idx>=8.5?'#4ade80':h.condition_idx>=7?'#fbbf24':h.condition_idx>=5?'#f97316':'#f87171';
const trendColor=h.bci_trend.startsWith('+')?'#4ade80':h.bci_trend.startsWith('-')?'#f87171':'#fbbf24';
const segBar=(pct,col)=>`<div></div>`;
return `<div>
<div>HOUSING STOCK INTELLIGENCE</div>
<!-- BCI header -->
<div>
<div>
<div>
<div>Building Condition Index</div>
<div>Landvex · quiXzoom observed</div>
</div>
<div>
<div>${h.condition_idx}<span>/10</span></div>
<div>${h.bci_trend}</div>
</div>
</div>
<div>${h.condition_label}</div>
</div>
<!-- Build era & renovation -->
<div>
<div>
<div>Build era</div>
<div>${h.build_era}</div>
</div>
<div>
<div>Renovated post-2000</div>
<div>${h.renovated_pct}% of stock</div>
</div>
<div>
<div>Avg apartment</div>
<div>${h.avg_apt_size} sqm</div>
</div>
<div>
<div>Commercial vacancy</div>
<div>${h.vacancy_commercial_pct}%</div>
</div>
</div>
<!-- Tenure mix -->
<div>
<div>Tenure mix</div>
<div>
${segBar(h.brf_pct,'#4ade80')}
${segBar(h.hyres_pct,'#38bdf8')}
${segBar(h.other_pct,'#6b7280')}
</div>
<div>
<span>Bostadsrätt ${h.brf_pct}%</span>
<span>Hyresrätt ${h.hyres_pct}%</span>
<span>Other ${h.other_pct}%</span>
</div>
</div>
<!-- New construction -->
<div>
<div>New build</div>
<div>${h.new_construction}</div>
</div>
${sourceChain([
{type:'data',label:'SCB Fastighetsregistret 2024'},
{type:'data',label:'Boverket 2024'},
{type:'obs',label:'quiXzoom BCI · 8471247 observationer'},
{type:'model',label:'Landvex BCI v1.2'}
])}
</div>`;
}
/* ── COMMERCIAL VITALITY INDEX ───────────────────────────── */
// Sources: SCB NV0101 (företag per SNI), Bolagsverket nyregistrerade/konkurser,
// quiXzoom kommersiell aktivitet, Fastighetsregistret vakanser
// SNI-mix: dominanta branscher per stadsdel
// cvi_score: Commercial Vitality Index 0-100
// active_companies: estimated active businesses
// new_registrations_ytd: new companies registered Jan-Jun 2026
// bankruptcies_ytd: bankruptcies Jan-Jun 2026
// revenue_trend: estimated revenue trend YoY (%)
// sni_mix: top 3 sectors by company count
// vacancy_commercial: commercial vacancy rate (%)
// gentrification_signal: boolean flag
const CVI_DATA={
city:{
cvi_score:84, cvi_trend:'+2.1',
active_companies:4820, new_registrations_ytd:312, bankruptcies_ytd:28,
revenue_trend:+4.8, employees_est:38200,
sni_mix:[
{code:'K',name:'Financial services',pct:28},
{code:'M',name:'Professional/tech',pct:24},
{code:'I',name:'Hotels & restaurants',pct:18}
],
vacancy_commercial:4.2, gentrification_signal:false,
bolagsverket_confidence:88,
top_growth_sector:'Fintech/proptech startups +34% YoY'
},
ostermalm:{
cvi_score:91, cvi_trend:'+1.4',
active_companies:3640, new_registrations_ytd:198, bankruptcies_ytd:12,
revenue_trend:+6.2, employees_est:29400,
sni_mix:[
{code:'K',name:'Finance & insurance',pct:32},
{code:'G',name:'Retail trade',pct:26},
{code:'M',name:'Management consulting',pct:22}
],
vacancy_commercial:2.1, gentrification_signal:false,
bolagsverket_confidence:94,
top_growth_sector:'Luxury retail +18% YoY'
},
sodermalm:{
cvi_score:72, cvi_trend:'+4.8',
active_companies:8940, new_registrations_ytd:687, bankruptcies_ytd:94,
revenue_trend:+3.1, employees_est:54800,
sni_mix:[
{code:'I',name:'Restaurants & bars',pct:29},
{code:'R',name:'Arts & entertainment',pct:22},
{code:'J',name:'Media & tech',pct:19}
],
vacancy_commercial:6.8, gentrification_signal:true,
bolagsverket_confidence:82,
top_growth_sector:'Food & beverage concepts +28% YoY'
},
kungsholmen:{
cvi_score:76, cvi_trend:'+2.6',
active_companies:3180, new_registrations_ytd:221, bankruptcies_ytd:31,
revenue_trend:+3.8, employees_est:31200,
sni_mix:[
{code:'O',name:'Public administration',pct:34},
{code:'M',name:'Professional services',pct:28},
{code:'J',name:'IT & telecom',pct:18}
],
vacancy_commercial:5.1, gentrification_signal:false,
bolagsverket_confidence:86,
top_growth_sector:'Tech consultancies +22% YoY'
},
vasastan:{
cvi_score:79, cvi_trend:'+5.2',
active_companies:4210, new_registrations_ytd:398, bankruptcies_ytd:42,
revenue_trend:+5.4, employees_est:28900,
sni_mix:[
{code:'M',name:'Professional services',pct:31},
{code:'J',name:'IT & media',pct:24},
{code:'I',name:'Restaurants & cafes',pct:21}
],
vacancy_commercial:4.4, gentrification_signal:true,
bolagsverket_confidence:84,
top_growth_sector:'Creative agencies +31% YoY'
},
nacka:{
cvi_score:68, cvi_trend:'+8.4',
active_companies:6840, new_registrations_ytd:612, bankruptcies_ytd:68,
revenue_trend:+7.2, employees_est:42100,
sni_mix:[
{code:'F',name:'Construction',pct:28},
{code:'G',name:'Retail & logistics',pct:24},
{code:'M',name:'Professional services',pct:18}
],
vacancy_commercial:7.2, gentrification_signal:false,
bolagsverket_confidence:79,
top_growth_sector:'Construction & proptech +48% YoY'
},
rinkeby:{
cvi_score:28, cvi_trend:'+1.2',
active_companies:1240, new_registrations_ytd:88, bankruptcies_ytd:62,
revenue_trend:-2.4, employees_est:6800,
sni_mix:[
{code:'G',name:'Local retail',pct:42},
{code:'I',name:'Ethnic restaurants',pct:28},
{code:'S',name:'Other services',pct:18}
],
vacancy_commercial:18.4, gentrification_signal:false,
bolagsverket_confidence:61,
top_growth_sector:'No significant growth sector identified'
}
};
/* ── ECONOMIC DNA ────────────────────────────────────────── */
// Aggregated area-level data only. No individual data.
// Sources: SCB disp.inkomst, Skatteverket regional, Fastighetsregistret, Bolagsverket
// purchasing_power_idx: area purchasing power vs Stockholm avg (100)
// hh_disposable_median: median household disposable income SEK/year
// wealth_gap: ratio top/bottom income quartile
// property_value_idx: avg property value vs Stockholm avg
// commercial_vs_residential: commercial activity relative to residential wealth
// gap_opportunity: commercial underprovision relative to purchasing power
// economic_profile: dominant economic character
// early_warning: boolean - commercial strong but residential weakening
const EDNA={
city:{
purchasing_power_idx:118, hh_disposable_median:412000,
wealth_gap:3.2, property_value_idx:124,
commercial_vs_residential:1.18,
gap_opportunity:false, early_warning:false,
profile:'Financial & professional hub',
profile_tags:['Finance','Premium retail','Tourism','Law & consulting'],
key_insight:'Strongest commercial-residential alignment in Stockholm. Limited retail gap opportunities — market well-served.',
source_note:'SCB disp.inkomst 2024 · Skatteverket regional 2024'
},
ostermalm:{
purchasing_power_idx:168, hh_disposable_median:589000,
wealth_gap:4.8, property_value_idx:198,
commercial_vs_residential:0.84,
gap_opportunity:true, early_warning:false,
profile:'Premium residential with commercial underserving',
profile_tags:['HNWI concentration','Luxury services','Private banking','Premium F&B'],
key_insight:'High purchasing power relative to commercial supply. Gap opportunity: premium grocery, high-end hospitality, private health clinics underrepresented.',
source_note:'SCB disp.inkomst 2024 · Fastighetsregistret 2024'
},
sodermalm:{
purchasing_power_idx:104, hh_disposable_median:348000,
wealth_gap:2.8, property_value_idx:108,
commercial_vs_residential:1.42,
gap_opportunity:false, early_warning:false,
profile:'Creative economy — commercial overindexing',
profile_tags:['Creative industries','F&B density','Media & tech','Gentrification active'],
key_insight:'Commercial activity significantly overindexes vs residential income. Sustained by young professional inflow and tourism. Gentrification raising both metrics.',
source_note:'SCB 2024 · quiXzoom commercial activity score'
},
kungsholmen:{
purchasing_power_idx:112, hh_disposable_median:384000,
wealth_gap:2.6, property_value_idx:114,
commercial_vs_residential:0.94,
gap_opportunity:true, early_warning:false,
profile:'Family residential with service gap',
profile_tags:['Government/public sector','Families','Stable income','Low churn'],
key_insight:'Stable middle-income area. Slight commercial undersupply relative to purchasing power. Opportunity: family services, quality casual dining, health & wellness.',
source_note:'SCB disp.inkomst 2024 · Bolagsverket 2024'
},
vasastan:{
purchasing_power_idx:122, hh_disposable_median:418000,
wealth_gap:2.9, property_value_idx:118,
commercial_vs_residential:1.12,
gap_opportunity:false, early_warning:false,
profile:'Young professional density — rising economic DNA',
profile_tags:['Young professionals','Creative/tech','Rising incomes','Family formation'],
key_insight:'Fastest-growing economic DNA in inner city. Income and commercial activity both accelerating. Gentrification signal confirmed. Watch for displacement dynamics.',
source_note:'SCB 2024 · Bolagsverket · Fastighetsregistret'
},
nacka:{
purchasing_power_idx:108, hh_disposable_median:372000,
wealth_gap:2.4, property_value_idx:82,
commercial_vs_residential:0.78,
gap_opportunity:true, early_warning:false,
profile:'Suburban growth — large commercial gap opening',
profile_tags:['Construction boom','Young families','Infrastructure investment','Commercial lag'],
key_insight:'Residential growth outpacing commercial development. Largest gap opportunity in Stockholm region. Tunnel project will accelerate population 2028+. First-mover advantage window open now.',
source_note:'SCB 2024 · Nacka kommun · Trafikverket'
},
rinkeby:{
purchasing_power_idx:38, hh_disposable_median:142000,
wealth_gap:2.1, property_value_idx:24,
commercial_vs_residential:0.62,
gap_opportunity:false, early_warning:true,
profile:'Structurally distressed — economic isolation',
profile_tags:['Low purchasing power','High unemployment','Social services dependent','Limited commercial'],
key_insight:'EARLY WARNING: purchasing power declining vs 2022 baseline. Commercial activity contracting. Wealth gap low — uniform low income. Not a gap opportunity — structural intervention required.',
source_note:'SCB disp.inkomst 2024 · CONTRADICTION: official data lags ~18 months'
}
};
function getEconomicDNA(distId){
const e=EDNA[distId];
if(!e)return '';
const ppColor=e.purchasing_power_idx>=130?'#4ade80':e.purchasing_power_idx>=90?'#fbbf24':e.purchasing_power_idx>=60?'#f97316':'#f87171';
const crColor=e.commercial_vs_residential>=1.2?'#38bdf8':e.commercial_vs_residential>=0.9?'#4ade80':e.commercial_vs_residential>=0.7?'#fbbf24':'#f87171';
const inc=e.hh_disposable_median.toLocaleString('sv-SE');
return `<div>
<div>ECONOMIC DNA</div>
<!-- Profile -->
<div>
<div>${e.profile}</div>
<div>
${e.profile_tags.map(t=>`<span>${t}</span>`).join('')}
</div>
<div>
<div>
<div>Purchasing power index</div>
<div>${e.purchasing_power_idx}<span> (avg=100)</span></div>
</div>
<div>
<div>HH disposable income</div>
<div>${inc} kr</div>
</div>
<div>
<div>Commercial/residential</div>
<div>${e.commercial_vs_residential}x</div>
</div>
<div>
<div>Property value index</div>
<div>${e.property_value_idx}<span> (avg=100)</span></div>
</div>
</div>
</div>
<!-- Gap / Warning -->
${e.early_warning?`<div>
<div>Early Warning Signal</div>
<div>${e.key_insight}</div>
</div>`:e.gap_opportunity?`<div>
<div>Gap Opportunity Detected</div>
<div>${e.key_insight}</div>
</div>`:`<div>
<div>${e.key_insight}</div>
</div>`}
<div>Aggregated area data only · No individual data · ${e.source_note}</div>
</div>`;
}
function getCVIPopup(distId){
const c=CVI_DATA[distId];
if(!c)return '';
const cviColor=c.cvi_score>=80?'#4ade80':c.cvi_score>=60?'#fbbf24':c.cvi_score>=40?'#f97316':'#f87171';
const trendColor=c.cvi_trend.startsWith('+')?'#4ade80':'#f87171';
const revColor=c.revenue_trend>=0?'#4ade80':'#f87171';
const revSign=c.revenue_trend>=0?'+':'';
const bkRatio=Math.round((c.bankruptcies_ytd/c.new_registrations_ytd)*100);
const bkColor=bkRatio<=15?'#4ade80':bkRatio<=25?'#fbbf24':'#f87171';
return `<div>
<div>COMMERCIAL VITALITY INDEX</div>
<!-- CVI header -->
<div>
<div>
<div>
<div>CVI Score</div>
<div>Bolagsverket 35% · Fastighet 20% · quiXzoom 15%</div>
</div>
<div>
<div>${c.cvi_score}<span>/100</span></div>
<div>${c.cvi_trend} trend</div>
</div>
</div>
<div>
<div>
<div>Active co.</div>
<div>${c.active_companies.toLocaleString('sv-SE')}</div>
</div>
<div>
<div>New YTD</div>
<div>+${c.new_registrations_ytd}</div>
</div>
<div>
<div>Bankrupt</div>
<div>${c.bankruptcies_ytd}</div>
</div>
</div>
</div>
<!-- SNI sector mix -->
<div>
<div>Sector mix (SNI)</div>
${c.sni_mix.map(s=>`<div>
<span>${s.code}</span>
<span>${s.name}</span>
<div>
<div></div>
</div>
<span>${s.pct}%</span>
</div>`).join('')}
</div>
<!-- Revenue & employment -->
<div>
<div>
<div>Revenue trend YoY</div>
<div>${revSign}${c.revenue_trend}%</div>
</div>
<div>
<div>Est. employees</div>
<div>${c.employees_est.toLocaleString('sv-SE')}</div>
</div>
<div>
<div>Commercial vacancy</div>
<div>${c.vacancy_commercial}%</div>
</div>
<div>
<div>Gentrif. signal</div>
<div>${c.gentrification_signal?'DETECTED':'None'}</div>
</div>
</div>
<!-- Growth sector -->
<div>
<div>Top growth sector</div>
<div>${c.top_growth_sector}</div>
</div>
<!-- Drill-down chain -->
<div>
CVI → Omsättningstillväxt → Företagspopulation → Bolagsdata<br>
Sources: Bolagsverket · SCB NV0101 · quiXzoom · Fastighetsregistret
</div>
</div>`;
}
function getPricePopup(distId){
const p=PRICE_DATA[distId];
if(!p)return '';
const pb=(val,max,col)=>{
const pct=Math.min(100,Math.round((val/max)*100));
return `<div><div></div></div>`;
};
const idxColor=idx=>idx>=85?'#f87171':idx>=60?'#fbbf24':'#4ade80';
const beerIdx=Math.round((p.beer_bar/129)*100);
const hotelIdx=Math.round((p.hotel_night/2400)*100);
const sevenIdx=p.seven_eleven;
const housingIdx=p.housing_idx;
return `<div>
<div>PRICE INTELLIGENCE <span>Östermalm=100</span></div>
<!-- Index summary row -->
<div>
<div>
<div>Beer</div>
<div>${beerIdx}</div>
</div>
<div>
<div>Hotel</div>
<div>${hotelIdx}</div>
</div>
<div>
<div>7-Eleven</div>
<div>${sevenIdx}</div>
</div>
<div>
<div>Housing</div>
<div>${housingIdx}</div>
</div>
</div>
<!-- Food & drink detail -->
<div>
<div>Food & Drink</div>
<div>
<div><span>Bar / club</span>${pb(p.beer_bar,140,'#60a5fa')}<span>${p.beer_bar} kr</span></div>
<div><span>Local pub</span>${pb(p.beer_pub,100,'#60a5fa')}<span>${p.beer_pub} kr</span></div>
<div><span>Coffee</span>${pb(p.coffee,70,'#a78bfa')}<span>${p.coffee} kr</span></div>
<div><span>Lunch</span>${pb(p.lunch,200,'#34d399')}<span>${p.lunch} kr</span></div>
<div><span>Dinner</span>${pb(p.dinner_mid,700,'#34d399')}<span>${p.dinner_mid} kr</span></div>
<div><span>7-Eleven basket</span>${pb(p.seven_eleven,100,'#fbbf24')}<span>${p.seven_eleven} kr</span></div>
</div>
</div>
<!-- Accommodation -->
<div>
<div>Accommodation</div>
<div>
<div><span>Hotel / night</span>${pb(p.hotel_night,2500,'#f97316')}<span>${p.hotel_night} kr</span></div>
<div><span>Rent / sqm</span>${pb(p.apt_rent_sqm,2600,'#fbbf24')}<span>${p.apt_rent_sqm}</span></div>
<div><span>Buy / sqm</span>${pb(p.apt_buy_sqm,140000,'#f87171')}<span>${Math.round(p.apt_buy_sqm/1000)}k</span></div>
</div>
</div>
${sourceChain([
{type:'data',label:'Hemnet Q1 2026'},
{type:'data',label:'Booking.com Jun 2026'},
{type:'obs',label:'quiXzoom prisobservationer Jun 2026'},
{type:'model',label:'Landvex Price Index v1.0'}
])}
</div>`;
}
const SCB_DATA={
// Source: SCB, Stockholms stad stadsdelsnämnder 2024
// education levels: grundskola / gymnasium / högskola_kort (<3yr) / högskola_lång (3yr+) / forskning
city: {population:28400, medianIncome:542000, unemployment:3.1, education_pct:62,
medianAge:38, age_0_17:12, age_18_44:52, age_45_64:23, age_65plus:13,
edu_grundskola:8, edu_gymnasium:30, edu_hogskola_kort:18, edu_hogskola_lang:40, edu_forskning:4,
foreign_born_pct:24, students_pct:12, self_employed_pct:8},
ostermalm: {population:31200, medianIncome:698000, unemployment:2.4, education_pct:74,
medianAge:46, age_0_17:14, age_18_44:34, age_45_64:28, age_65plus:24,
edu_grundskola:4, edu_gymnasium:22, edu_hogskola_kort:16, edu_hogskola_lang:52, edu_forskning:6,
foreign_born_pct:18, students_pct:6, self_employed_pct:14},
sodermalm: {population:101000,medianIncome:461000, unemployment:4.8, education_pct:58,
medianAge:36, age_0_17:13, age_18_44:55, age_45_64:21, age_65plus:11,
edu_grundskola:11, edu_gymnasium:31, edu_hogskola_kort:20, edu_hogskola_lang:34, edu_forskning:4,
foreign_born_pct:22, students_pct:18, self_employed_pct:11},
kungsholmen:{population:38900, medianIncome:502000, unemployment:3.6, education_pct:64,
medianAge:40, age_0_17:15, age_18_44:46, age_45_64:24, age_65plus:15,
edu_grundskola:7, edu_gymnasium:29, edu_hogskola_kort:19, edu_hogskola_lang:41, edu_forskning:4,
foreign_born_pct:20, students_pct:10, self_employed_pct:9},
vasastan: {population:41200, medianIncome:521000, unemployment:3.2, education_pct:67,
medianAge:39, age_0_17:16, age_18_44:46, age_45_64:25, age_65plus:13,
edu_grundskola:6, edu_gymnasium:27, edu_hogskola_kort:18, edu_hogskola_lang:44, edu_forskning:5,
foreign_born_pct:19, students_pct:14, self_employed_pct:10},
nacka: {population:102000,medianIncome:512000, unemployment:3.8, education_pct:55,
medianAge:41, age_0_17:22, age_18_44:38, age_45_64:26, age_65plus:14,
edu_grundskola:10, edu_gymnasium:35, edu_hogskola_kort:20, edu_hogskola_lang:32, edu_forskning:3,
foreign_born_pct:16, students_pct:7, self_employed_pct:9},
rinkeby: {population:49000, medianIncome:198000, unemployment:21.4,education_pct:28,
medianAge:31, age_0_17:31, age_18_44:44, age_45_64:17, age_65plus:8,
edu_grundskola:38, edu_gymnasium:34, edu_hogskola_kort:14, edu_hogskola_lang:13, edu_forskning:1,
foreign_born_pct:84, students_pct:8, self_employed_pct:4}
};
function ageBar(pct, color){
return `<div>
<div></div></div>`;
}
function getSCBPopup(distId){
const s=SCB_DATA[distId];
if(!s)return '';
const inc=s.medianIncome.toLocaleString('sv-SE');
const uColor=s.unemployment>15?'#f87171':s.unemployment>8?'#fbbf24':'#4ade80';
const ageColor=s.medianAge<33?'#c084fc':s.medianAge<40?'#38bdf8':s.medianAge<48?'#4ade80':'#fbbf24';
return `<div>
<div>SCB DEMOGRAPHICS</div>
<div>
<div>
<div>Population</div>
<div>${s.population.toLocaleString('sv-SE')}</div>
</div>
<div>
<div>Median income</div>
<div>${inc} kr</div>
</div>
<div>
<div>Unemployment</div>
<div>${s.unemployment}%</div>
</div>
<div>
<div>Higher education</div>
<div>${s.education_pct}%</div>
</div>
</div>
<!-- Age distribution -->
<div>
<div>
<div>Age distribution</div>
<div>Median ${s.medianAge} yrs</div>
</div>
<div>
<div><span>017</span>${ageBar(s.age_0_17*2,'#a78bfa')}<span>${s.age_0_17}%</span></div>
<div><span>1844</span>${ageBar(s.age_18_44*2,'#38bdf8')}<span>${s.age_18_44}%</span></div>
<div><span>4564</span>${ageBar(s.age_45_64*2,'#4ade80')}<span>${s.age_45_64}%</span></div>
<div><span>65+</span>${ageBar(s.age_65plus*2,'#fbbf24')}<span>${s.age_65plus}%</span></div>
</div>
</div>
<!-- Education levels -->
<div>
<div>
<div>Education profile</div>
<div>${s.edu_hogskola_kort+s.edu_hogskola_lang+s.edu_forskning}% university+</div>
</div>
<div>
<div><span>Grundskola</span>${ageBar(s.edu_grundskola*1.8,'#6b7280')}<span>${s.edu_grundskola}%</span></div>
<div><span>Gymnasium</span>${ageBar(s.edu_gymnasium*1.8,'#94a3b8')}<span>${s.edu_gymnasium}%</span></div>
<div><span>Högskola &lt;3y</span>${ageBar(s.edu_hogskola_kort*1.8,'#38bdf8')}<span>${s.edu_hogskola_kort}%</span></div>
<div><span>Högskola 3y+</span>${ageBar(s.edu_hogskola_lang*1.8,'#818cf8')}<span>${s.edu_hogskola_lang}%</span></div>
<div><span>Forskning/PhD</span>${ageBar(s.edu_forskning*1.8,'#c084fc')}<span>${s.edu_forskning}%</span></div>
</div>
</div>
<!-- Social profile -->
<div>
<div>
<div>Foreign-born</div>
<div>${s.foreign_born_pct}%</div>
</div>
<div>
<div>Students</div>
<div>${s.students_pct}%</div>
</div>
<div>
<div>Self-employed</div>
<div>${s.self_employed_pct}%</div>
</div>
</div>
${sourceChain([
{type:'data',label:'SCB Stadsdelsstatistik 2024'},
{type:'data',label:'SCB Utbildningsregistret 2024'},
{type:'data',label:'Stockholms stad 2024'}
])}
</div>`;
}
</script>
</body>
</html>
+211
View File
@@ -0,0 +1,211 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Landvex Terms of Service — governing use of landvex.com and Landvex intelligence products. Landvex AB (Sweden) and Landvex Inc. (Texas, USA).">
<title>Terms of Service — Landvex</title>
<link rel="canonical" href="https://landvex.com/terms/">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta name="robots" content="index, follow">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif; background: #fff; color: #1d1d1f; line-height: 1.7; }
nav { height: 56px; border-bottom: 1px solid #e5e5e7; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; position: sticky; top: 0; background: rgba(255,255,255,0.92); backdrop-filter: blur(12px); z-index: 100; }
.logo { font-size: 17px; font-weight: 700; color: #1d1d1f; text-decoration: none; letter-spacing: -0.3px; }
.logo span { color: #0066cc; }
.nav-back { font-size: 14px; color: #0066cc; text-decoration: none; }
.draft-banner { background: #fff3cd; border-bottom: 1px solid #ffc107; padding: 24px; font-size: 13px; color: #664d03; text-align: center; }
main { max-width: 760px; margin: 0 auto; padding: 24px 80px; }
h1 { font-size: clamp(24px, 4vw, 36px); font-weight: 700; letter-spacing: -0.5px; margin-bottom: 8px; }
.meta { font-size: 13px; color: #6e6e73; margin-bottom: 40px; }
h2 { font-size: 18px; font-weight: 600; margin: 36px 0 12px; color: #1d1d1f; }
p { margin-bottom: 14px; font-size: 15px; color: #3a3a3c; }
ul { margin: 0 0 14px 20px; font-size: 15px; color: #3a3a3c; }
ul li { margin-bottom: 6px; }
table { width: 100%; border-collapse: collapse; margin: 16px 0 24px; font-size: 13px; }
th { background: #f5f5f7; padding: 24px; text-align: left; font-weight: 600; border-bottom: 2px solid #e5e5e7; }
td { padding: 24px; border-bottom: 1px solid #1a1a1a; vertical-align: top; }
.highlight { background: #f5f5f7; border-radius: 10px; padding: 24px; margin: 20px 0; font-size: 14px; }
.highlight p { margin-bottom: 0; font-size: 14px; }
footer { border-top: 1px solid #e5e5e7; padding: 24px; text-align: center; font-size: 13px; color: #6e6e73; }
footer a { color: #0066cc; text-decoration: none; }
a { color: #0066cc; }
@media (max-width: 600px) { main { padding: 24px 60px; } table { font-size: 12px; } }
</style>
<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>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": [
"Organization",
"Corporation"
],
"@id": "https://landvex.com/#organization",
"name": "Landvex",
"alternateName": [
"LandveX",
"Landvex AB",
"LandveX AB"
],
"url": "https://landvex.com",
"logo": {
"@type": "ImageObject",
"url": "https://landvex.com/apple-touch-icon.png",
"width": 180,
"height": 180
},
"foundingDate": "2024",
"foundingLocation": {
"@type": "Place",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
},
"legalName": "Landvex Inc",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
},
"location": [
{
"@type": "Place",
"name": "Houston, Texas, USA (US HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Houston",
"addressRegion": "TX",
"addressCountry": "US"
}
},
{
"@type": "Place",
"name": "Tyresö, Sweden (EU HQ)",
"address": {
"@type": "PostalAddress",
"addressLocality": "Gothenburg",
"addressRegion": "Gothenburg",
"addressCountry": "SE"
}
}
],
"taxID": "pending-EIN",
"description": "Landvex is a decision intelligence company that identifies contradictions between official narratives and observed physical reality. Using the quiXzoom field observation network and the AMOS AI analysis engine, Landvex delivers infrastructure risk indexes, urban intelligence scores, and contradiction reports to infrastructure owners, municipalities, enterprises, and investors globally.",
"disambiguatingDescription": "Landvex (LandveX) is a decision intelligence company with US headquarters in Houston, Texas (Landvex Inc.) and European headquarters in Tyresö, Sweden (Landvex AB, org.nr 559141-7042). Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors. Landvex is not a UK meat wholesaler, food distributor, logistics company, package tracker, or land investment platform.",
"knowsAbout": [
"control intelligence",
"decision intelligence",
"infrastructure risk assessment",
"urban intelligence",
"field data collection",
"contradiction detection",
"physical world analytics",
"geospatial analytics"
],
"brand": {
"@type": "Brand",
"name": "Landvex",
"slogan": "Control intelligence for the physical world."
},
"sameAs": [
"https://landvex.com",
"https://www.linkedin.com/company/landvex",
"https://x.com/landvex",
"https://twitter.com/landvex",
"https://www.crunchbase.com/organization/landvex",
"https://github.com/landvex",
"https://www.instagram.com/landvex"
],
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@landvex.com",
"contactType": "sales"
},
"slogan": "Where reported reality conflicts with observed reality."
}
</script>
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>terms</span>
</nav>
<nav aria-label="Main navigation">
<a href="/" class="logo">Land<span>vex</span></a>
<a href="/" class="nav-back">← Landvex</a>
</nav>
<div class="draft-banner">
<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> <strong>Draft notice:</strong> Working draft pending review by qualified legal counsel. Final terms will be published before commercial launch (target: 1 August 2026).
</div>
<main>
<h1>Terms of Service</h1>
<p class="meta">Last updated: 24 June 2026 &nbsp;·&nbsp; Version 0.1 (draft — pending legal review)</p>
<h2>1. Parties</h2>
<p>These Terms govern use of landvex.com and all Landvex services provided by:</p>
<ul>
<li><strong>Landvex AB</strong>, org.nr 559141-7042, Tyresö, Sweden — for customers in the EEA and internationally</li>
<li><strong>Landvex Inc.</strong>, a Texas corporation, Houston, TX, USA — for customers in North America</li>
</ul>
<p>References to "<strong>Landvex</strong>", "<strong>we</strong>", "<strong>us</strong>", or "<strong>our</strong>" mean the applicable Landvex entity. References to "<strong>you</strong>" or "<strong>your</strong>" mean the individual or organisation accessing or using our services.</p>
<h2>2. Services</h2>
<p>Landvex provides decision-intelligence products based on field-observation data and AI analysis. All intelligence outputs are analytical signals, not statements of fact. They do not constitute financial, legal, or professional advice, and should not be relied upon as such.</p>
<p>Outputs labelled "illustrative" or "sample" are not live data and must not be used for operational decisions.</p>
<h2>3. Acceptable use</h2>
<p>You agree not to:</p>
<ul>
<li>Reverse-engineer or attempt to identify specific individuals from intelligence outputs</li>
<li>Use outputs for discriminatory, unlawful, or harmful purposes</li>
<li>Redistribute, resell, or sublicense raw data or intelligence outputs without prior written consent</li>
<li>Attempt to circumvent, disable, or interfere with any security or access controls</li>
</ul>
<h2>4. Intellectual property</h2>
<p>All Landvex intelligence outputs, methodologies, models, software, and platform IP are owned by or licensed to Landvex. Your use of the services does not grant you any intellectual property rights beyond the limited licence to access and use the services as described in your service agreement.</p>
<p>Field-observation data is licensed by Landvex from <strong>quiXzoom Inc.</strong> under a separate data sharing agreement. quiXzoom Inc. retains all rights in such data.</p>
<h2>5. Disclaimer</h2>
<p>Intelligence outputs are provided "<strong>as is</strong>" without warranty of any kind. Landvex makes no warranty — express or implied — of accuracy, completeness, fitness for a particular purpose, or non-infringement. Market conditions, physical changes, and data latency may affect the currency of outputs.</p>
<h2>6. Limitation of liability</h2>
<p>To the maximum extent permitted by applicable law, Landvex's aggregate liability arising out of or related to these Terms or the services is limited to the amounts paid by you to Landvex in the twelve (12) months immediately preceding the claim. In no event shall Landvex be liable for indirect, incidental, special, consequential, or punitive damages.</p>
<h2>7. Governing law</h2>
<ul>
<li><strong>EEA customers:</strong> Swedish law applies. Disputes are subject to the exclusive jurisdiction of the courts of Stockholm, Sweden.</li>
<li><strong>US customers:</strong> Texas law applies (excluding conflict-of-law principles). Disputes are subject to the exclusive jurisdiction of the courts of Houston, TX, USA.</li>
</ul>
<h2>8. Changes</h2>
<p>We may update these Terms from time to time. Material changes will be notified with at least 30 days' notice before taking effect. Continued use of the services after the effective date constitutes acceptance of the revised Terms.</p>
<h2>9. Contact</h2>
<div class="highlight">
<p>
<strong>Legal enquiries:</strong> <a href="mailto:legal@landvex.com">legal@landvex.com</a><br>
<strong>Landvex AB</strong> · org.nr 559141-7042 · Tyresö, Sweden
</p>
</div>
</main>
<footer class="lv-footer" role="contentinfo">
<p>© 2026 Landvex AB · org.nr 559141-7042 · Tyresö, Sweden · <a href="/privacy/">Privacy</a> · <a href="/terms/">Terms</a> · <a href="/subprocessors/">Sub-processors</a> · <a href="/dpa/">DPA</a></p>
</footer>
</body>
</html>
+326
View File
@@ -0,0 +1,326 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Trust Centre — Landvex</title>
<meta name="description" content="Landvex Trust Centre: infrastructure security, data quality guarantee, contributor verification chain, DPA, penetration testing, and responsible disclosure.">
<link rel="canonical" href="https://landvex.com/trust/">
<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="alternate" hreflang="x-default" href="https://landvex.com/">
<link rel="alternate" hreflang="en" href="https://landvex.com/">
<link rel="alternate" hreflang="sv" href="https://landvex.se/">
<link rel="alternate" hreflang="de" href="https://landvex.de/">
<link rel="alternate" hreflang="fr" href="https://landvex.fr/">
<link rel="alternate" hreflang="en-GB" href="https://landvex.co.uk/">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<style>
:root {
--bg: #F2F2F7;
--surface: #FFFFFF;
--surface2: #F2F2F7;
--label: #000000;
--label2: #3C3C43;
--label3: rgba(60,60,67,0.65);
--separator: rgba(60,60,67,0.29);
--accent: #0066FF;
--font: -apple-system, "SF Pro Text", "Helvetica Neue", sans-serif;
--font-display: -apple-system, "SF Pro Display", "Helvetica Neue", sans-serif;
--radius-lg: 16px;
--radius-sm: 10px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #000000;
--surface: #1C1C1E;
--surface2: #2C2C2E;
--label: #FFFFFF;
--label2: #EBEBF5;
--label3: rgba(235,235,245,0.65);
--separator: rgba(84,84,88,0.65);
}
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-font-smoothing: antialiased; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--label);
padding: env(safe-area-inset-top, 20px) env(safe-area-inset-right, 20px) env(safe-area-inset-bottom, 40px) env(safe-area-inset-left, 20px);
max-width: 680px;
margin: 0 auto;
}
header { padding: 32px 0 24px; text-align: center; }
header .logo { font-family: var(--font-display); font-size: 28px; font-weight: 700; letter-spacing: -0.5px; color: var(--accent); }
header h1 { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--label); margin-top: 6px; }
header p { font-size: 13px; color: var(--label3); margin-top: 4px; }
.card { background: var(--surface); border-radius: var(--radius-lg); padding: 20px; margin-bottom: 12px; }
.card-title { font-family: var(--font-display); font-size: 17px; font-weight: 600; color: var(--label); margin-bottom: 12px; }
p, li { font-size: 15px; line-height: 1.6; color: var(--label2); }
ul { padding-left: 20px; margin-top: 8px; }
li { margin-bottom: 6px; }
.row { display: flex; align-items: flex-start; gap: 16px; padding: 12px 0; border-bottom: 0.5px solid var(--separator); }
.row:last-child { border-bottom: none; }
.row-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.blue { background: rgba(0,102,255,0.12); }
.green { background: rgba(52,199,89,0.12); }
.orange { background: rgba(255,149,0,0.12); }
.red { background: rgba(255,59,48,0.12); }
.purple { background: rgba(175,82,222,0.12); }
.teal { background: rgba(50,173,230,0.12); }
.row-content { flex: 1; }
.row-label { font-size: 15px; font-weight: 600; color: var(--label); }
.row-sub { font-size: 13px; color: var(--label3); margin-top: 2px; line-height: 1.5; }
a { color: var(--accent); text-decoration: none; }
footer { text-align: center; padding: 24px 0 8px; font-size: 13px; color: var(--label3); }
footer a { color: var(--accent); }
.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 0; margin-bottom: 12px; }
.stat-box { background: var(--surface); border-radius: var(--radius-lg); padding: 16px; text-align: center; }
.stat-val { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--label); }
.stat-lbl { font-size: 12px; color: var(--label3); margin-top: 3px; }
.chain-step { display: flex; align-items: flex-start; gap: 16px; padding: 10px 0; border-bottom: 0.5px solid var(--separator); }
.chain-step:last-child { border-bottom: none; }
.chain-num { width: 28px; height: 28px; border-radius: 50%; background: rgba(0,102,255,0.12); color: var(--accent); font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-top: 2px; }
.chain-content { flex: 1; }
.chain-label { font-size: 14px; font-weight: 600; color: var(--label); }
.chain-sub { font-size: 13px; color: var(--label3); margin-top: 2px; line-height: 1.5; }
@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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>trust</span>
</nav>
<header class="lv-header">
<div class="logo"><a href="https://landvex.com/" >Landvex</a></div>
<h1>Trust Centre</h1>
<p>Infrastructure, data quality, and security for enterprise clients</p>
</header>
<div class="stat-grid">
<div class="stat-box">
<div class="stat-val">AES-256</div>
<div class="stat-lbl">Encryption at rest</div>
</div>
<div class="stat-box">
<div class="stat-val">TLS 1.3</div>
<div class="stat-lbl">Encryption in transit</div>
</div>
<div class="stat-box">
<div class="stat-val">85%+</div>
<div class="stat-lbl">AI approval rate target</div>
</div>
<div class="stat-box">
<div class="stat-val">EU-only</div>
<div class="stat-lbl">AWS eu-north-1</div>
</div>
</div>
<div class="card" id="infrastructure">
<div class="card-title">Infrastructure Security</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
</div>
<div class="row-content">
<div class="row-label">Encryption at rest — AES-256</div>
<div class="row-sub">All stored data — intelligence outputs, client configurations, contributor records — is encrypted with AES-256 using AWS KMS-managed keys with automated annual rotation.</div>
</div>
</div>
<div class="row">
<div class="row-icon green">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#34c759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<div class="row-content">
<div class="row-label">Encryption in transit — TLS 1.3</div>
<div class="row-sub">All API and web traffic is encrypted with TLS 1.3. TLS 1.0 and 1.1 are not supported. HSTS is enforced on all production endpoints.</div>
</div>
</div>
<div class="row">
<div class="row-icon teal">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#32ade6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10z"/></svg>
</div>
<div class="row-content">
<div class="row-label">AWS eu-north-1 — Stockholm</div>
<div class="row-sub">Landvex runs exclusively on AWS eu-north-1 (Stockholm, Sweden). Data does not leave the European Union in normal operation. Network isolation via VPC with restricted security group rules and no public database access.</div>
</div>
</div>
<div class="row">
<div class="row-icon purple">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#af52de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg>
</div>
<div class="row-content">
<div class="row-label">SOC 2 Type II infrastructure</div>
<div class="row-sub">Landvex operates on AWS infrastructure certified to SOC 2 Type II and ISO 27001. AWS compliance artefacts are available on request via <a href="mailto:compliance@landvex.com">compliance@landvex.com</a>.</div>
</div>
</div>
</div>
<div class="card" id="data-quality">
<div class="card-title">Data Quality Assurance</div>
<div class="row">
<div class="row-icon orange">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff9500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div class="row-content">
<div class="row-label">85%+ AI approval rate target</div>
<div class="row-sub">Landvex targets a minimum 85% approval rate for submitted intelligence. Each submission is reviewed by the Landvex AI engine before acceptance. The approval rate is tracked per project and included in delivery reports.</div>
</div>
</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</div>
<div class="row-content">
<div class="row-label">Human review available</div>
<div class="row-sub">For projects requiring higher assurance, human review can be added as a quality layer alongside AI review. Available on enterprise contracts. Contact your account manager to activate.</div>
</div>
</div>
</div>
<div class="card" id="verification-chain">
<div class="card-title">Verification Chain</div>
<p>Every intelligence output delivered to enterprise clients passes through four verification stages.</p>
<div class="chain-step">
<div class="chain-num">1</div>
<div class="chain-content">
<div class="chain-label">Contributor identity verification</div>
<div class="chain-sub">All contributors (Zoomers) complete KYC identity verification before their first payout. Only verified contributors may submit intelligence.</div>
</div>
</div>
<div class="chain-step">
<div class="chain-num">2</div>
<div class="chain-content">
<div class="chain-label">GPS validation</div>
<div class="chain-sub">GPS coordinates are validated against the mission target location at submission time. Out-of-range submissions are automatically rejected.</div>
</div>
</div>
<div class="chain-step">
<div class="chain-num">3</div>
<div class="chain-content">
<div class="chain-label">AI quality review</div>
<div class="chain-sub">The Landvex AI engine reviews each submission for technical quality, specification compliance, and instruction adherence before acceptance.</div>
</div>
</div>
<div class="chain-step">
<div class="chain-num">4</div>
<div class="chain-content">
<div class="chain-label">Delivery</div>
<div class="chain-sub">Only approved submissions are delivered to enterprise clients. Payout to the contributor is triggered on approval. Rejected submissions are not delivered and not paid.</div>
</div>
</div>
</div>
<div class="card" id="dpa">
<div class="card-title">Data Processing Agreement</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label">Available on request</div>
<div class="row-sub">A GDPR Art. 28 compliant Data Processing Agreement is available for all enterprise contracts. Standard Contractual Clauses for non-EEA clients are also available. Request via: <a href="mailto:legal@landvex.com">legal@landvex.com</a></div>
</div>
</div>
<p>Full DPA documentation: <a href="/dpa/">/dpa/</a></p>
</div>
<div class="card" id="security">
<div class="card-title">Security Programme</div>
<div class="row">
<div class="row-icon red">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff3b30" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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 class="row-content">
<div class="row-label">Penetration testing — annual</div>
<div class="row-sub">Landvex commissions independent penetration testing of its platform annually. Reports are available to enterprise clients under NDA. Contact <a href="mailto:compliance@landvex.com">compliance@landvex.com</a> to request.</div>
</div>
</div>
<div class="row">
<div class="row-icon orange">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ff9500" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
</div>
<div class="row-content">
<div class="row-label">Responsible disclosure</div>
<div class="row-sub">Security vulnerability reports: <a href="mailto:security@landvex.com">security@landvex.com</a>. We acknowledge within 48 hours. Good-faith security research is welcomed; we do not pursue legal action against researchers acting responsibly.</div>
</div>
</div>
<div class="row">
<div class="row-icon teal">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#32ade6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div class="row-content">
<div class="row-label">Security overview</div>
<div class="row-sub">Full technical security documentation: <a href="/security/">/security/</a></div>
</div>
</div>
</div>
<div class="card" id="data-lineage-subprocessors">
<div class="card-title">Data Lineage &amp; Sub-processors</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/data-lineage/">Data Lineage</a></div>
<div class="row-sub">How data moves through the Landvex pipeline — field capture through intelligence delivery. Every transformation step documented.</div>
</div>
</div>
<div class="row">
<div class="row-icon purple">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#af52de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/subprocessors/">Sub-processors</a></div>
<div class="row-sub">Third-party processors engaged by Landvex AB. GDPR Article 28 compliant. Updated when sub-processors change.</div>
</div>
</div>
</div>
<div class="card">
<div class="card-title">Related Documents</div>
<div class="row">
<div class="row-icon blue">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0066ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/dpa/">Data Processing Agreement</a></div>
<div class="row-sub">GDPR Art. 28 DPA and Standard Contractual Clauses.</div>
</div>
</div>
<div class="row">
<div class="row-icon green">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#34c759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/compliance/">Compliance</a></div>
<div class="row-sub">GDPR, infrastructure certifications, and questionnaire process.</div>
</div>
</div>
<div class="row">
<div class="row-icon teal">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#32ade6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="row-content">
<div class="row-label"><a href="/data-quality/">Data quality</a></div>
<div class="row-sub">Methodology, accuracy metrics, and quality guarantees.</div>
</div>
</div>
</div>
<footer class="lv-footer" role="contentinfo">
<p><a href="https://landvex.com/">Landvex</a> &nbsp;·&nbsp; <a href="/privacy/">Privacy</a> &nbsp;·&nbsp; <a href="/compliance/">Compliance</a> &nbsp;·&nbsp; <a href="/dpa/">DPA</a> &nbsp;·&nbsp; <a href="/data-lineage/">Data Lineage</a> &nbsp;·&nbsp; <a href="/subprocessors/">Sub-processors</a> &nbsp;·&nbsp; <a href="/security/">Security</a> &nbsp;·&nbsp; <a href="/cookie-policy/">Cookies</a></p>
<p>© 2026 Landvex AB &nbsp;·&nbsp; Org.nr 559141-7042 &nbsp;·&nbsp; <a href="mailto:compliance@landvex.com">compliance@landvex.com</a></p>
</footer>
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Use Cases — Landvex</title>
<meta name="description" content="Explore Landvex use cases: bridge inspection, infrastructure risk, retail site selection, investment screening, and post-disaster assessment.">
<link rel="canonical" href="https://landvex.com/use-cases/">
<meta http-equiv="refresh" content="0; url=/">
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<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" aria-label="Main navigation">
<a href="/" >Home</a> / <span>use-cases</span>
</nav>
<p>Redirecting to <a href="/">homepage</a>...</p>
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/assets/css/landvex-complete.css">
<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>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verticals — Landvex</title>
<meta name="description" content="Explore Landvex verticals: municipalities, infrastructure, property, insurance, utilities, retail, investors, and logistics.">
<link rel="canonical" href="https://landvex.com/verticals/">
<meta http-equiv="refresh" content="0; url=/">
</head>
<body>
<nav aria-label="breadcrumb" aria-label="Main navigation">
<a href="/" >Home</a> / <span>verticals</span>
</nav>
<p>Redirecting to <a href="/">homepage</a>...</p>
</body>
</html>