1a12fb870b
- New /developers/ page with API docs, SDKs, pricing, use cases - OpenAPI 3.0 spec for Orders, Missions, Photos, Analytics - Case study: Glasskiosken i Flatenbadet — complete ROI analysis - Updated /order/ with recurring missions and frequency dropdown
411 lines
21 KiB
HTML
411 lines
21 KiB
HTML
<!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>Data Lineage — Landvex</title>
|
||
<meta name="description" content="Complete data lineage documentation for Landvex intelligence outputs. From field capture to delivered intelligence — every step documented.">
|
||
<link rel="canonical" href="https://landvex.com/data-lineage/">
|
||
<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="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; }
|
||
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); }
|
||
|
||
/* Pipeline steps */
|
||
.pipeline { display: flex; flex-direction: column; gap: 0; }
|
||
.step { display: flex; align-items: flex-start; gap: 16px; padding: 16px 0; border-bottom: 0.5px solid var(--separator); cursor: pointer; transition: opacity 0.15s; }
|
||
.step:last-child { border-bottom: none; }
|
||
.step:hover { opacity: 0.85; }
|
||
.step-num-wrap { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
||
.step-num { width: 32px; height: 32px; border-radius: var(--radius-full); background: rgba(0,102,255,0.12); color: var(--accent); font-size: 13px; font-weight: 700; display: flex; align-items: center; justify-content: center; }
|
||
.step-line { width: 1.5px; flex: 1; min-height: 12px; background: rgba(0,102,255,0.18); margin-top: 4px; }
|
||
.step:last-child .step-line { display: none; }
|
||
.step-icon { width: 36px; height: 36px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||
.step-body { flex: 1; }
|
||
.step-label { font-size: 15px; font-weight: 600; color: var(--label); }
|
||
.step-sub { font-size: 13px; color: var(--label3); margin-top: 3px; line-height: 1.55; }
|
||
.step-detail { margin-top: 10px; display: none; }
|
||
.step-detail.open { display: block; }
|
||
.step-detail ul { padding-left: 18px; }
|
||
.step-detail li { font-size: 13px; color: var(--label3); margin-bottom: 5px; line-height: 1.5; }
|
||
.step-toggle { font-size: 12px; color: var(--accent); margin-top: 5px; font-weight: 500; user-select: none; }
|
||
|
||
/* Colors */
|
||
.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); }
|
||
.indigo { background: rgba(94,92,230,0.12); }
|
||
.pink { background: rgba(255,45,85,0.12); }
|
||
|
||
/* Audit + residency */
|
||
.info-block { background: rgba(0,102,255,0.06); border-left: 3px solid var(--accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding: 24px; margin-bottom: 12px; }
|
||
.info-block p { font-size: 13px; color: var(--label2); line-height: 1.6; }
|
||
.info-block strong { color: var(--label); font-weight: 600; }
|
||
|
||
/* CTA */
|
||
.cta-row { display: flex; justify-content: center; margin: 16px 0 4px; }
|
||
.cta-btn { display: inline-block; background: var(--accent); color: #1d1d1f; font-size: 15px; font-weight: 600; padding: 24px; border-radius: var(--radius-md); text-decoration: none; transition: opacity 0.15s; }
|
||
.cta-btn:hover { opacity: 0.88; }
|
||
|
||
/* Related docs */
|
||
.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: var(--radius-md); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||
.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; }
|
||
@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>data-lineage</span>
|
||
</nav>
|
||
|
||
<header class="lv-header">
|
||
<div class="logo"><a href="https://landvex.com/" >Landvex</a></div>
|
||
<h1>How data moves through Landvex.</h1>
|
||
<p>From field capture to delivered intelligence — every step documented</p>
|
||
</header>
|
||
|
||
<div class="info-block">
|
||
<p><strong>Full traceability.</strong> Every intelligence output can be traced back to its source observations. This document describes each transformation step, the controls applied, and the data retained at each stage.</p>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-title">8-Step Pipeline</div>
|
||
<div class="pipeline" id="pipeline">
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">1</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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="12" cy="12" r="3"/><path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/></svg>
|
||
</div>
|
||
<div class="step-body">
|
||
<div class="step-label">Field Capture</div>
|
||
<div class="step-sub">Zoomer photographs target via quiXzoom app with GPS lock and EXIF metadata.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Zoomer accepts mission in quiXzoom app</li>
|
||
<li>GPS coordinates locked at capture start</li>
|
||
<li>Photo taken with full EXIF metadata: device model, timestamp, GPS coordinates, focal length</li>
|
||
<li>Submission uploaded with: image, GPS trace, timestamp, device fingerprint, mission ID</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">2</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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="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="step-body">
|
||
<div class="step-label">Identity Verification</div>
|
||
<div class="step-sub">Submitting Zoomer must be KYC-verified before any payout eligibility is established.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>KYC verification is completed once, before the contributor's first payout</li>
|
||
<li>Each submission is linked to a verified contributor ID</li>
|
||
<li>Contributor ID is a pseudonymised hash — it is not stored in the intelligence output delivered to clients</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">3</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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="step-body">
|
||
<div class="step-label">GPS Validation</div>
|
||
<div class="step-sub">Submitted coordinates validated against mission target with tolerance thresholds.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Submitted coordinates validated against mission target coordinates</li>
|
||
<li>Tolerance: <50 metres for standard missions; <10 metres for precision missions</li>
|
||
<li>GPS accuracy class assigned: coarse / balanced / precise</li>
|
||
<li>Submissions outside tolerance: auto-rejected or flagged for human review</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">4</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
|
||
</div>
|
||
<div class="step-body">
|
||
<div class="step-label">AI Image Review</div>
|
||
<div class="step-sub">Automated quality scoring across specification compliance, technical quality, and content relevance.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Image analysed for: specification compliance, technical quality, content relevance</li>
|
||
<li>Object detection confirms the target is present in frame</li>
|
||
<li>Quality score assigned on a scale of 0–100</li>
|
||
<li>Submissions below threshold: rejected with a reason code</li>
|
||
<li>Approval rate target: 85% or above</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">5</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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="step-body">
|
||
<div class="step-label">Human Review (edge cases)</div>
|
||
<div class="step-sub">AI-borderline submissions routed to a human reviewer with full decision logging.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>AI-borderline submissions (score 40–60) routed to a human reviewer</li>
|
||
<li>Reviewer applies the mission specification to reach a final decision</li>
|
||
<li>Decision logged with reviewer ID and timestamp</li>
|
||
<li>Appeals process available for rejected submissions</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">6</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-icon indigo">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#5e5ce6" 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="step-body">
|
||
<div class="step-label">Normalisation</div>
|
||
<div class="step-sub">Approved submissions converted to structured data points with full source attribution.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Approved submissions converted to structured data points</li>
|
||
<li>Entity extraction: location, object type, condition class, change signal</li>
|
||
<li>Temporal indexing: observation timestamped; version history maintained</li>
|
||
<li>Source attribution preserved throughout the normalisation process</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">7</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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"><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>
|
||
<div class="step-body">
|
||
<div class="step-label">Intelligence Aggregation</div>
|
||
<div class="step-sub">Observations aggregated by geographic unit; index scores calculated with confidence weighting.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Observations aggregated by geographic unit: district, city, region</li>
|
||
<li>Index scores calculated: Opportunity, Growth, Vitality, Infra Stability, Investment Confidence</li>
|
||
<li>Contradiction detection: aggregated observations compared against official data sources</li>
|
||
<li>Confidence scores calculated from: observation count, recency, and cross-validation results</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step" onclick="toggleStep(this)">
|
||
<div class="step-num-wrap">
|
||
<div class="step-num">8</div>
|
||
<div class="step-line"></div>
|
||
</div>
|
||
<div class="step-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="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>
|
||
</div>
|
||
<div class="step-body">
|
||
<div class="step-label">Output and Delivery</div>
|
||
<div class="step-sub">Intelligence reports generated with full source citations and traceable audit trails.</div>
|
||
<div class="step-toggle">Show details</div>
|
||
<div class="step-detail">
|
||
<ul>
|
||
<li>Intelligence report generated with source citations</li>
|
||
<li>Each data point is traceable to its source observations via an audit trail</li>
|
||
<li>Delivery formats: web dashboard, API, structured report (PDF / JSON / CSV)</li>
|
||
<li>Data retention: per client contract — default is intelligence outputs retained 3 years, raw observations 90 days post-delivery</li>
|
||
<li>Deletion: right to erasure supported; deletion confirmed within 30 days</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="audit-trail">
|
||
<div class="card-title">Audit Trail</div>
|
||
<div class="info-block">
|
||
<p>Every intelligence output can be traced back to its source observations. On request, Landvex provides a complete audit package including: observation timestamps, GPS accuracy classes, AI review scores, human review decisions, normalisation logs, and aggregation methodology.</p>
|
||
<p>Contact: <a href="mailto:legal@landvex.com">legal@landvex.com</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="data-residency">
|
||
<div class="card-title">Data Residency</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">EU-only — AWS eu-north-1, Stockholm</div>
|
||
<div class="row-sub">All data is stored in the EU on AWS eu-north-1 (Stockholm, Sweden). No data is transferred outside the EU without explicit client instruction and appropriate safeguards in place.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-title">Request Documentation</div>
|
||
<p>Enterprise clients may request a complete data lineage package for their contract, including normalisation logs and aggregation methodology.</p>
|
||
<div class="cta-row">
|
||
<a href="/contact/" class="cta-btn">Request data lineage documentation for your contract</a>
|
||
</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="/subprocessors/">Sub-processors</a></div>
|
||
<div class="row-sub">Third-party processors used in the Landvex pipeline. GDPR Article 28 compliant.</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"><a href="/trust/">Trust Centre</a></div>
|
||
<div class="row-sub">Infrastructure security, data quality guarantee, and verification chain.</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="/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 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"><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> · <a href="/privacy/">Privacy</a> · <a href="/terms/">Terms</a> · <a href="/dpa/">DPA</a> · <a href="/trust/">Trust</a> · <a href="/subprocessors/">Sub-processors</a> · <a href="/cookie-policy/">Cookies</a></p>
|
||
<p>© 2026 Landvex AB · Org.nr 559141-7042 · Stockholm, Sweden · <a href="mailto:legal@landvex.com">legal@landvex.com</a></p>
|
||
</footer>
|
||
|
||
<script>
|
||
function toggleStep(el) {
|
||
var detail = el.querySelector('.step-detail');
|
||
var toggle = el.querySelector('.step-toggle');
|
||
if (!detail) return;
|
||
var isOpen = detail.classList.contains('open');
|
||
detail.classList.toggle('open', !isOpen);
|
||
toggle.textContent = isOpen ? 'Show details' : 'Hide details';
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|