48ea61cdcc
- Product documentation in docs/products/ - Updated MEMORY.md with product info - quiXzoom Auth Core as AAMOS Identity product
585 lines
18 KiB
HTML
585 lines
18 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>Become a Zoomer — quiXzoom</title>
|
||
<link rel="stylesheet" >
|
||
<style>
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
body {
|
||
font-family: var(--font-text, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif);
|
||
background: var(--bg-primary, #000);
|
||
color: var(--label-primary, #fff);
|
||
min-height: 100dvh;
|
||
padding-top: env(safe-area-inset-top, 44px);
|
||
padding-bottom: env(safe-area-inset-bottom, 34px);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* Nav Bar */
|
||
.nav-bar {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 44px;
|
||
padding: 0 16px;
|
||
background: rgba(242,242,247,0.82);
|
||
backdrop-filter: saturate(180%) blur(20px);
|
||
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
||
border-bottom: 0.5px solid rgba(255,255,255,0.12);
|
||
}
|
||
|
||
.nav-bar .nav-logo {
|
||
font-family: var(--font-display, -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif);
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.41px;
|
||
background: linear-gradient(135deg, #007AFF 0%, #5856D6 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
/* Hero */
|
||
.hero {
|
||
padding: 48px 20px 32px;
|
||
text-align: center;
|
||
}
|
||
|
||
.hero-badge {
|
||
display: inline-block;
|
||
background: rgba(0,122,255,0.15);
|
||
border: 0.5px solid rgba(0,122,255,0.4);
|
||
color: #007AFF;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
padding: 5px 14px;
|
||
border-radius: var(--radius-xl);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.hero h1 {
|
||
font-family: var(--font-display, -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif);
|
||
font-size: 34px;
|
||
font-weight: 700;
|
||
line-height: 1.12;
|
||
letter-spacing: -0.8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.hero h1 .accent {
|
||
background: linear-gradient(135deg, #007AFF 0%, #5856D6 50%, #AF52DE 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.hero p {
|
||
font-size: 17px;
|
||
line-height: 1.5;
|
||
color: rgba(60,60,67,0.7);
|
||
max-width: 340px;
|
||
margin: 0 auto 28px;
|
||
}
|
||
|
||
/* Earnings Banner */
|
||
.earnings-card {
|
||
margin: 0 20px 32px;
|
||
background: linear-gradient(135deg, rgba(52,199,89,0.15) 0%, rgba(0,122,255,0.10) 100%);
|
||
border: 0.5px solid rgba(52,199,89,0.3);
|
||
border-radius: var(--radius-lg);
|
||
padding: 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
.earnings-card .amount {
|
||
font-family: var(--font-display, -apple-system, "SF Pro Display", sans-serif);
|
||
font-size: 42px;
|
||
font-weight: 700;
|
||
letter-spacing: -1px;
|
||
color: #34C759;
|
||
}
|
||
|
||
.earnings-card .amount-label {
|
||
font-size: 13px;
|
||
color: rgba(255,255,255,0.75);
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* 3-Step How It Works */
|
||
.section-title {
|
||
font-family: var(--font-display, -apple-system, "SF Pro Display", sans-serif);
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.4px;
|
||
padding: 0 20px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.steps {
|
||
padding: 0 20px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
margin-bottom: 36px;
|
||
}
|
||
|
||
.step-card {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 16px;
|
||
background: rgba(255,255,255,0.06);
|
||
border: 0.5px solid rgba(255,255,255,0.1);
|
||
border-radius: var(--radius-lg);
|
||
padding: 18px 16px;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.step-card:active {
|
||
background: rgba(255,255,255,0.1);
|
||
}
|
||
|
||
.step-icon {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 22px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.step-icon.blue { background: rgba(0,122,255,0.18); }
|
||
.step-icon.green { background: rgba(52,199,89,0.18); }
|
||
.step-icon.purple { background: rgba(88,86,214,0.18); }
|
||
|
||
.step-content .step-num {
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
color: rgba(255,255,255,0.75);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.step-content .step-title {
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.3px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.step-content .step-desc {
|
||
font-size: 15px;
|
||
color: rgba(255,255,255,0.75);
|
||
line-height: 1.4;
|
||
}
|
||
|
||
/* Live Missions */
|
||
.missions-section {
|
||
margin-bottom: 36px;
|
||
}
|
||
|
||
.missions-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 20px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.live-dot {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 13px;
|
||
color: rgba(60,60,67,0.5);
|
||
}
|
||
|
||
.live-dot::before {
|
||
content: '';
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: var(--radius-full);
|
||
background: #34C759;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; transform: scale(1); }
|
||
50% { opacity: 0.5; transform: scale(0.85); }
|
||
}
|
||
|
||
.missions-scroll {
|
||
display: flex;
|
||
gap: 12px;
|
||
overflow-x: auto;
|
||
padding: 0 20px 4px;
|
||
scrollbar-width: none;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
.missions-scroll::-webkit-scrollbar { display: none; }
|
||
|
||
.mission-card {
|
||
flex: 0 0 260px;
|
||
background: rgba(255,255,255,0.07);
|
||
border: 0.5px solid rgba(255,255,255,0.1);
|
||
border-radius: var(--radius-lg);
|
||
padding: 16px;
|
||
}
|
||
|
||
.mission-type-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
padding: 3px 10px;
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.mission-type-badge.facade { background: rgba(88,86,214,0.2); color: #5856D6; }
|
||
.mission-type-badge.roof { background: rgba(255,149,0,0.2); color: #FF9500; }
|
||
.mission-type-badge.road { background: rgba(90,200,250,0.2); color: #5AC8FA; }
|
||
.mission-type-badge.water { background: rgba(255,45,85,0.2); color: #FF2D55; }
|
||
|
||
.mission-card h3 {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.2px;
|
||
margin-bottom: 6px;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.mission-card .mission-meta {
|
||
font-size: 13px;
|
||
color: rgba(60,60,67,0.5);
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.mission-reward {
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
color: #34C759;
|
||
letter-spacing: -0.4px;
|
||
}
|
||
|
||
.mission-reward span {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: rgba(52,199,89,0.7);
|
||
}
|
||
|
||
/* CTA Buttons */
|
||
.cta-section {
|
||
padding: 0 20px;
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.btn-primary {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
height: 56px;
|
||
background: #007AFF;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: var(--radius-lg);
|
||
font-family: var(--font-text, -apple-system, sans-serif);
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.2px;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
transition: opacity 0.15s;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.btn-primary:active { opacity: 0.8; }
|
||
|
||
.btn-secondary {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
height: 50px;
|
||
background: rgba(255,255,255,0.08);
|
||
color: rgba(255,255,255,0.85);
|
||
border: 0.5px solid rgba(255,255,255,0.15);
|
||
border-radius: var(--radius-lg);
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
transition: background 0.15s;
|
||
}
|
||
|
||
.btn-secondary:active { background: rgba(255,255,255,0.14); }
|
||
|
||
/* Stats Strip */
|
||
.stats-strip {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 1px;
|
||
background: rgba(255,255,255,0.08);
|
||
border-radius: var(--radius-lg);
|
||
margin: 0 20px 36px;
|
||
overflow: hidden;
|
||
border: 0.5px solid rgba(255,255,255,0.1);
|
||
}
|
||
|
||
.stat {
|
||
background: rgba(255,255,255,0.04);
|
||
padding: 16px 12px;
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-value {
|
||
font-family: var(--font-display, -apple-system, "SF Pro Display", sans-serif);
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.4px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 12px;
|
||
color: rgba(255,255,255,0.75);
|
||
}
|
||
|
||
/* FAQ / Trust */
|
||
.trust-section {
|
||
padding: 0 20px;
|
||
margin-bottom: 48px;
|
||
}
|
||
|
||
.trust-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 14px 0;
|
||
border-bottom: 0.5px solid rgba(255,255,255,0.08);
|
||
font-size: 15px;
|
||
color: rgba(255,255,255,0.75);
|
||
}
|
||
|
||
.trust-item:last-child { border-bottom: none; }
|
||
|
||
.trust-icon {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 16px;
|
||
flex-shrink: 0;
|
||
background: rgba(52,199,89,0.15);
|
||
}
|
||
|
||
/* Loading state for missions */
|
||
.missions-loading {
|
||
padding: 0 20px;
|
||
color: rgba(255,255,255,0.75);
|
||
font-size: 15px;
|
||
}
|
||
@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>
|
||
|
||
<style id="wcag-contrast-enforcement">
|
||
/* AAMOS GLOBAL CONTRAST ENFORCEMENT — WCAG AA (4.5:1 minimum) */
|
||
/* Regel: Ingen text under 70% opacity. Aldrig. */
|
||
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
|
||
/* Fix common low-contrast patterns */
|
||
[style*="rgba(60,60,67,0.4)"] { color: rgba(60,60,67,0.65) !important; }
|
||
[style*="rgba(60,60,67,0.3)"] { color: rgba(60,60,67,0.65) !important; }
|
||
[style*="rgba(255,255,255,0.4)"] { color: rgba(255,255,255,0.72) !important; }
|
||
[style*="rgba(255,255,255,0.3)"] { color: rgba(255,255,255,0.72) !important; }
|
||
[style*="opacity: 0.4"] { opacity: 0.72 !important; }
|
||
[style*="opacity: 0.3"] { opacity: 0.72 !important; }
|
||
@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 src="i18n.js"></script>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:title" content="Become a Zoomer — quiXzoom">
|
||
<meta property="og:description" content="quiXzoom — Earn per Mission. No Platform Fee.">
|
||
<meta property="og:url" content="https://www.quixzoom.com/zoomer-start.html">
|
||
<meta property="og:image" content="https://www.quixzoom.com/images/app-screenshot.jpg">
|
||
<meta property="og:image:width" content="1200">
|
||
<meta property="og:image:height" content="630">
|
||
<meta property="og:image:alt" content="quiXzoom — start earning as a Zoomer today">
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:image" content="https://www.quixzoom.com/images/app-screenshot.jpg">
|
||
<meta name="twitter:title" content="Become a Zoomer — quiXzoom">
|
||
<script type="module" src="https://auth.quixzoom.com/site-auth-snippet.js"></script>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- Nav Bar -->
|
||
<div class="nav-bar">
|
||
<span class="nav-logo">quiXzoom</span>
|
||
</div>
|
||
|
||
<!-- Hero -->
|
||
<section class="hero">
|
||
<div class="hero-badge"> Launching August 2026</div>
|
||
<h1>Earn money on<br><span class="accent">what you see around you</span></h1>
|
||
<p>Take photo missions near you. Get paid fast. No boss, no invoicing.</p>
|
||
</section>
|
||
|
||
<!-- Earnings Banner -->
|
||
<div class="earnings-card">
|
||
<div class="amount">900 – 4 500 kr</div>
|
||
<div class="amount-label">per mission · paid out within 48h</div>
|
||
</div>
|
||
|
||
<!-- Stats -->
|
||
<div class="stats-strip">
|
||
<div class="stat">
|
||
<div class="stat-value" id="stat-missions">4</div>
|
||
<div class="stat-label">Open missions</div>
|
||
</div>
|
||
<div class="stat">
|
||
<div class="stat-value">48h</div>
|
||
<div class="stat-label">Payout time</div>
|
||
</div>
|
||
<div class="stat">
|
||
<div class="stat-value">2 100</div>
|
||
<div class="stat-label">Avg per mission</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- How It Works -->
|
||
<p class="section-title">How it works</p>
|
||
<div class="steps">
|
||
<div class="step-card">
|
||
<div class="step-icon blue"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="5" stroke="#666" stroke-width="2"/><path d="M11 11L14 14" stroke="#666" stroke-width="2" stroke-linecap="round"/></svg></div>
|
||
<div class="step-content">
|
||
<div class="step-num">Step 1</div>
|
||
<div class="step-title">Find missions near you</div>
|
||
<div class="step-desc">Open the map and find missions in your area — facade scans, roof photos, road inspections.</div>
|
||
</div>
|
||
</div>
|
||
<div class="step-card">
|
||
<div class="step-icon green"></div>
|
||
<div class="step-content">
|
||
<div class="step-num">Step 2</div>
|
||
<div class="step-title">Complete the mission</div>
|
||
<div class="step-desc">Head over, take the photos as briefed. Upload directly from the app. Usually 15–45 min.</div>
|
||
</div>
|
||
</div>
|
||
<div class="step-card">
|
||
<div class="step-icon purple"></div>
|
||
<div class="step-content">
|
||
<div class="step-num">Step 3</div>
|
||
<div class="step-title">Get paid</div>
|
||
<div class="step-desc">When the mission is approved, your payment is released immediately. No middlemen.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Live Missions -->
|
||
<div class="missions-section">
|
||
<div class="missions-header">
|
||
<p class="section-title" style="padding:0;margin:0">Live missions</p>
|
||
<div class="live-dot">Live</div>
|
||
</div>
|
||
<div class="missions-scroll" id="missions-container">
|
||
<div class="mission-card" style="opacity:0.5;text-align:center;padding:24px">
|
||
<div style="font-size:24px;margin-bottom:8px"></div>
|
||
<div style="font-size:14px;color:#aaa">Loading missions near you...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Trust signals -->
|
||
<div class="trust-section">
|
||
<p class="section-title" style="padding:0;margin-bottom:12px">Always included</p>
|
||
<div class="trust-item">
|
||
<div class="trust-icon"><svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#22c55e" stroke-width="2"/><path d="M6 10L9 13L14 7" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||
Clear brief — you know exactly what to do
|
||
</div>
|
||
<div class="trust-item">
|
||
<div class="trust-icon"></div>
|
||
Secure payout via Stripe Connect
|
||
</div>
|
||
<div class="trust-item">
|
||
<div class="trust-icon"></div>
|
||
No special gear — a smartphone is enough
|
||
</div>
|
||
<div class="trust-item">
|
||
<div class="trust-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M9 2L5 9H8L7 14L11 7H8L9 2Z" fill="#f59e0b"/></svg></div>
|
||
Approval and payment within 48 hours
|
||
</div>
|
||
<div class="trust-item">
|
||
<div class="trust-icon"></div>
|
||
Choose which missions you take
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CTA -->
|
||
<div class="cta-section">
|
||
<a href="/join" class="btn-primary">
|
||
Register as a Zoomer →
|
||
</a>
|
||
<a href="/map" class="btn-secondary">
|
||
View missions on map
|
||
</a>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = 'https://api.quixzoom.com/api/qz';
|
||
function missionEmoji(t){
|
||
if(/elledn|kabel|transfor/i.test(t)) return '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M9 2L5 9H8L7 14L11 7H8L9 2Z" fill="#f59e0b"/></svg>';
|
||
if(/vag|potthal|trottoar/i.test(t)) return '';
|
||
if(/kanal|bro/i.test(t)) return '';
|
||
if(/gatuliv|neon/i.test(t)) return '';
|
||
return '';
|
||
}
|
||
function renderMissions(missions){
|
||
const c=document.getElementById('missions-container');
|
||
if(!missions.length){c.innerHTML='<div style="text-align:center;padding:24px;color:#aaa;font-size:14px"> No missions near you right now</div>';return;}
|
||
c.innerHTML=missions.slice(0,6).map(m=>{
|
||
const d=m.distance_meters<1000?Math.round(m.distance_meters)+'m':(m.distance_meters/1000).toFixed(1)+'km';
|
||
return '<div class="mission-card" onclick="location.href=\''/zoomer-onboarding-flow\'" style="cursor:pointer">'
|
||
+'<div class="mission-type-badge road">'+missionEmoji(m.title)+' '+(m.area_name||'Mission')+'</div>'
|
||
+'<h3>'+m.title+'</h3>'
|
||
+'<div class="mission-meta"> '+d+' away · '+(m.required_photos||1)+' photo</div>'
|
||
+'<div class="mission-reward">'+m.reward_credits+' cr<span> on approval</span></div>'
|
||
+'</div>';
|
||
}).join('');
|
||
const el=document.getElementById('stat-missions');
|
||
if(el&&missions.length>0) el.textContent=missions.length+'+';
|
||
}
|
||
function load(lat,lng){
|
||
const url=lat?`${API_BASE}/missions?lat=${lat}&lng=${lng}&radius=15&limit=20`:`${API_BASE}/missions?lat=59.33&lng=18.07&radius=15&limit=20`;
|
||
fetch(url).then(r=>r.json()).then(d=>renderMissions(d.missions||[])).catch(()=>{});
|
||
}
|
||
if(navigator.geolocation){navigator.geolocation.getCurrentPosition(p=>load(p.coords.latitude,p.coords.longitude),()=>load(null,null),{timeout:5000});}
|
||
else load(null,null);
|
||
</script>
|
||
</body>
|
||
</html>
|