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
@@ -180,7 +180,7 @@
display: flex; align-items: center; gap: 12px;
}
.decision-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;
}
.decision-chip span { font-size: 15px; font-weight: 600; color: var(--text-light); }
@@ -191,7 +191,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 {
@@ -203,7 +203,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); }
@@ -242,14 +242,14 @@
.score-icon { font-size: 1.5rem; margin-bottom: 12px; }
.score-name { font-size: 15px; font-weight: 700; color: #1d1d1f; margin-bottom: 6px; }
.score-desc { font-size: 13px; color: var(--text-dim); line-height: 1.5; margin-bottom: 20px; }
.score-bar-wrap { background: rgba(0,0,0,.06); border-radius: 6px; height: 8px; margin-bottom: 10px; }
.score-bar { height: 8px; border-radius: 6px; background: linear-gradient(90deg, var(--blue), #5599ff); }
.score-bar-wrap { background: rgba(0,0,0,.06); border-radius: var(--radius-sm); height: 8px; margin-bottom: 10px; }
.score-bar { height: 8px; border-radius: var(--radius-sm); background: linear-gradient(90deg, var(--blue), #5599ff); }
.score-value { font-size: 28px; font-weight: 800; color: var(--blue); letter-spacing: -1px; }
.score-label-sub { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
/* 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;
}
@@ -301,7 +301,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;
}
@@ -329,7 +329,7 @@
.hero h1 { letter-spacing: -1px; }
}
.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}
@@ -378,7 +378,7 @@
<p class="section-sub">From single-asset verifications to portfolio-wide intelligence missions — deployed in 2472 hours.</p>
<div class="use-case-grid">
<div class="use-case-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<span class="uc-icon">🔭</span>
<span class="uc-icon"></span>
<h3>Portfolio documentation</h3>
<p>Systematic visual documentation of portfolio assets — condition, occupancy signals, neighbourhood quality, and change over time.</p>
@@ -390,13 +390,13 @@
<div class="learn-more-hint" style="margin-top:12px;font-size:13px;font-weight:700;color:#0066ff">Learn more →</div></div>
<div class="use-case-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<span class="uc-icon">🗺️</span>
<span class="uc-icon"></span>
<h3>Site verification</h3>
<p>Confirm what's actually on the ground before committing capital. Verify access, condition, and surrounding environment.</p>
<div class="learn-more-hint" style="margin-top:12px;font-size:13px;font-weight:700;color:#0066ff">Learn more →</div></div>
<div class="use-case-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<span class="uc-icon"></span>
<span class="uc-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M9 2L5 9H8L7 14L11 7H8L9 2Z" fill="#f59e0b"/></svg></span>
<h3>Market intelligence</h3>
<p>Track commercial activity, vacancy rates, and neighbourhood trajectory across target markets — before the data appears in published indices.</p>
@@ -461,12 +461,12 @@
<div class="conflict-side conflict-official">
<div class="conflict-side-label">Official narrative</div>
<ul>
<li>&#10003; Property prices up 8.3% YoY</li><li>&#10003; Strong rental demand reported</li><li>&#10003; Low vacancy in commercial ground floor</li> </ul>
<li>&#100003 Property prices up 8.3% YoY</li><li>&#100003 Strong rental demand reported</li><li>&#100003 Low vacancy in commercial ground floor</li> </ul>
</div>
<div class="conflict-side conflict-observed">
<div class="conflict-side-label">Observed reality</div>
<ul>
<li>&#10007; Vacancy rates up 22% vs prior year visit</li><li>&#10007; Multiple businesses closed, limited new openings</li><li>&#10007; Deferred maintenance visible on 40% of sampled buildings</li><li>&#10007; Foot traffic down vs comparable streets</li> </ul>
<li>&#100007 <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Vacancy rates up 22% vs prior year visit</li><li>&#100007 <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Multiple businesses closed, limited new openings</li><li>&#100007 <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Deferred maintenance visible on 40% of sampled buildings</li><li>&#100007 <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Foot traffic down vs comparable streets</li> </ul>
</div>
</div>
<div class="conflict-footer">
@@ -503,7 +503,7 @@
<p class="section-sub">Every score is derived from field-verified observations, cross-referenced against official data, and launching August 2026.</p>
<div class="scores-grid" style="grid-template-columns:repeat(3,1fr)">
<div class="score-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="score-icon">💎</div>
<div class="score-icon"></div>
<div class="score-name">Investment Attractiveness Index</div>
<div class="score-desc">Composite score combining opportunity, risk, velocity, and quality for investment decisions.</div>
<div class="score-bar-wrap">
@@ -514,7 +514,7 @@
<div class="learn-more-hint" style="margin-top:12px;font-size:13px;font-weight:700;color:#0066ff">Request access →</div></div>
<div class="score-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="score-icon">🏪</div>
<div class="score-icon"></div>
<div class="score-name">Commercial Opportunity Index</div>
<div class="score-desc">Measures commercial vacancy, foot traffic, and business activity for location intelligence.</div>
<div class="score-bar-wrap">
@@ -525,7 +525,7 @@
<div class="learn-more-hint" style="margin-top:12px;font-size:13px;font-weight:700;color:#0066ff">Request access →</div></div>
<div class="score-card" style="cursor:pointer;" onclick="location.href='#contact'" role="button" tabindex="0">
<div class="score-icon">🚀</div>
<div class="score-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2L10 8L14 9L8 14L6 8L2 7L8 2Z" fill="#666"/></svg></div>
<div class="score-name">Growth Velocity Index</div>
<div class="score-desc">How fast is an area changing? Identifies emerging zones before they appear in official statistics.</div>
<div class="score-bar-wrap">