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
+16 -16
View File
@@ -182,7 +182,7 @@
display: flex; align-items: center; gap: 10px;
}
.district-chip .chip-dot {
width: 8px; height: 8px; border-radius: 50%;
width: 8px; height: 8px; border-radius: var(--radius-full);
background: var(--blue); flex-shrink: 0;
}
.district-chip span { font-size: 14px; font-weight: 600; color: var(--text-light); }
@@ -256,7 +256,7 @@
.contradiction-box {
background: rgba(0,0,0,.05);
border: 1px solid rgba(0,0,0,.1);
border-radius: 16px; padding: 36px 40px; margin-bottom: 32px;
border-radius: var(--radius-lg); padding: 36px 40px; margin-bottom: 32px;
}
.conflict-header {
@@ -270,7 +270,7 @@
.conflict-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.conflict-side { border-radius: 10px; padding: 16px; }
.conflict-side { border-radius: var(--radius-md); 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); }
@@ -305,7 +305,7 @@
/* CTA BANNER */
.cta-banner {
background: #e8f0fe; border-radius: 16px; padding: 40px 48px;
background: #e8f0fe; border-radius: var(--radius-lg); padding: 40px 48px;
display: flex; align-items: center; gap: 48px; flex-wrap: wrap;
margin-top: 48px;
}
@@ -357,7 +357,7 @@
.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;
width: 32px; height: 32px; border: 1px solid var(--border); border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
transition: border-color 0.2s, background 0.2s;
}
@@ -392,7 +392,7 @@
.scores-grid { grid-template-columns: 1fr !important; }
}
.lv-disclaimer{font-size:.75rem;color:rgba(0,0,0,.75);margin-top:24px;padding:12px 16px;background:rgba(0,0,0,.04);border-radius:8px;line-height:1.6;max-width:800px}
.lv-disclaimer{font-size:.75rem;color:rgba(0,0,0,.75);margin-top:24px;padding:12px 16px;background:rgba(0,0,0,.04);border-radius: var(--radius-md);line-height:1.6;max-width:800px}
.lv-disclaimer a{color:rgba(0,0,0,.65);text-decoration:underline}
.lv-disclaimer--light{color:#888;background:#f5f5f5}
.lv-disclaimer--light a{color:#555}
@@ -565,7 +565,7 @@
<div class="container">
<div class="section-label">District scores</div>
<h2 class="section-title">Sample intelligence scores</h2>
<p class="section-sub" style="background:#fff3cd;border:2px solid #ffc107;border-radius:8px;padding:12px 16px;color:#856404;font-weight:600;">⚠️ ILLUSTRATIVE SAMPLE DATA — These scores are synthetic examples for demonstration purposes only. They do not represent actual measured values.</p>
<p class="section-sub" style="background:#fff3cd;border:2px solid #ffc107;border-radius: var(--radius-md);padding:12px 16px;color:#856404;font-weight:600;"><svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M10 3L17 17H3L10 3Z" stroke="#f59e0b" stroke-width="2"/><path d="M10 8V12M10 14V14.5" stroke="#f59e0b" stroke-width="2" stroke-linecap="round"/></svg> 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>
@@ -622,8 +622,8 @@
<p class="section-sub" style="color:rgba(0,0,0,.75);margin:0 auto;max-width:600px">When official municipal development plans diverge from observed commercial activity, Landvex surfaces the conflict &mdash; not just the consensus.</p>
</div>
<div style="background:#fff3cd;border:1px solid #ffc107;border-radius:8px;padding:12px 16px;margin-bottom:20px;font-size:13px;font-weight:600;color:#856404;text-align:center">
ILLUSTRATIVE SAMPLE — not real intelligence
<div style="background:#fff3cd;border:1px solid #ffc107;border-radius: var(--radius-md);padding:12px 16px;margin-bottom:20px;font-size:13px;font-weight:600;color:#856404;text-align:center">
ILLUSTRATIVE SAMPLE — not real intelligence
</div>
<div class="contradiction-box">
<div class="conflict-header">
@@ -640,18 +640,18 @@
<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>
<li>&#100003 Municipal investment zone: Järva priority growth</li>
<li>&#100003 Norrmalm: stable CBD with anchor tenants</li>
<li>&#100003 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>
<li>&#100007 Järva commercial vacancy above city average</li>
<li>&#100007 Norrmalm: 3 anchor retailers downsizing footprint</li>
<li>&#100007 Development activity below permit volume</li>
<li>&#100007 Nacka outperforming planned growth projections</li>
</ul>
</div>
</div>