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
917 lines
29 KiB
HTML
917 lines
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>About — quiXzoom</title>
|
|
<meta name="description" content="quiXzoom is a global field intelligence network. Learn about our mission, team, and how we're building the world's largest observation network.">
|
|
<link rel="canonical" href="https://www.quixzoom.com/about">
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:title" content="About — quiXzoom">
|
|
<meta property="og:description" content="quiXzoom is a global field intelligence network. Learn about our mission, team, and how we're building the world's largest observation network.">
|
|
<meta property="og:url" content="https://www.quixzoom.com/about">
|
|
<meta property="og:image" content="https://www.quixzoom.com/images/og-image.jpg">
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:image" content="https://www.quixzoom.com/images/og-image.jpg">
|
|
<style>
|
|
:root {
|
|
--bg-dark: #f5f5f7;
|
|
--blue: #0066FF;
|
|
--blue-dark: #0052CC;
|
|
--text-dark: #1d1d1f;
|
|
--text-body: #3a3a3a;
|
|
--text-muted: #6e6e73;
|
|
--surface: #ffffff;
|
|
--surface-2: #f5f5f7;
|
|
--border: rgba(0,0,0,0.09);
|
|
}
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Helvetica Neue', sans-serif;
|
|
background: #ffffff;
|
|
color: var(--text-dark);
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
|
|
|
|
/* Nav */
|
|
nav {
|
|
position: sticky; top: 0; z-index: 300;
|
|
background: rgba(255,255,255,0.92);
|
|
backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 64px; }
|
|
.nav-logo { font-size: 1.375rem; font-weight: 900; color: var(--text-dark); text-decoration: none; }
|
|
.nav-logo span { color: var(--blue); }
|
|
.nav-links { display: flex; gap: 32px; }
|
|
.nav-links a { color: var(--text-muted); text-decoration: none; font-weight: 500; transition: color 0.15s; }
|
|
.nav-links a:hover { color: var(--text-dark); }
|
|
.nav-links a.active { color: var(--blue); }
|
|
.btn-nav { background: var(--blue); color: #fff; border: none; border-radius: 24px; padding: 10px 24px; font-size: 0.9375rem; font-weight: 700; transition: background 0.15s; text-decoration: none; }
|
|
.btn-nav:hover { background: var(--blue-dark); }
|
|
|
|
/* Hero */
|
|
.hero { padding: 80px 0 60px; text-align: center; background: var(--surface); }
|
|
.hero h1 { font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; line-height: 1.1; margin-bottom: 20px; }
|
|
.hero p { font-size: 1.25rem; color: var(--text-body); max-width: 600px; margin: 0 auto; }
|
|
|
|
/* Content */
|
|
.content { padding: 60px 0; }
|
|
.section { margin-bottom: 60px; }
|
|
.section h2 { font-size: 2rem; font-weight: 700; margin-bottom: 20px; }
|
|
.section p { font-size: 1.1rem; color: var(--text-body); margin-bottom: 16px; max-width: 700px; }
|
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; margin-top: 32px; }
|
|
.card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
padding: 32px;
|
|
}
|
|
.card h3 { font-size: 1.25rem; font-weight: 700; margin-bottom: 12px; }
|
|
.card p { font-size: 0.95rem; color: var(--text-muted); }
|
|
|
|
/* Stats */
|
|
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin: 40px 0; }
|
|
.stat { text-align: center; }
|
|
.stat-num { font-size: 2.5rem; font-weight: 800; color: var(--blue); }
|
|
.stat-label { font-size: 0.875rem; color: var(--text-muted); margin-top: 4px; }
|
|
|
|
/* Footer */
|
|
footer { background: var(--surface); border-top: 1px solid var(--border); padding: 40px 0; margin-top: 60px; }
|
|
.footer-inner { display: flex; justify-content: space-between; align-items: center; }
|
|
.footer-links { display: flex; gap: 24px; }
|
|
.footer-links a { color: var(--text-muted); text-decoration: none; font-size: 0.875rem; }
|
|
.footer-links a:hover { color: var(--text-dark); }
|
|
|
|
@media (max-width: 768px) {
|
|
.nav-links { display: none; }
|
|
.stats { grid-template-columns: repeat(2, 1fr); }
|
|
.footer-inner { flex-direction: column; gap: 16px; text-align: center; }
|
|
}
|
|
@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; }
|
|
}
|
|
/* QUIXZOOM STANDARD — Dark Theme */
|
|
:root {
|
|
--qz-bg: #0a0a0a;
|
|
--qz-surface: #111111;
|
|
--qz-surface-2: #1a1a1a;
|
|
--qz-border: rgba(255,255,255,0.08);
|
|
--qz-text: #e8e8e8;
|
|
--qz-text-dim: #a0a0a0;
|
|
--qz-text-muted: #6b6b6b;
|
|
--qz-blue: #007AFF;
|
|
--qz-blue-dark: #0056CC;
|
|
--qz-radius: 10px;
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
|
|
background: var(--qz-bg);
|
|
color: var(--qz-text);
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* Navigation */
|
|
.qz-nav {
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 0 24px; height: 56px;
|
|
background: rgba(255,255,255,0.92);
|
|
backdrop-filter: blur(16px);
|
|
border-bottom: 1px solid var(--qz-border);
|
|
}
|
|
|
|
.qz-nav-logo { font-size: 18px; font-weight: 700; color: #fff; text-decoration: none; }
|
|
.qz-nav-links { display: flex; gap: 24px; list-style: none; }
|
|
.qz-nav-links a { font-size: 14px; color: var(--qz-text-dim); text-decoration: none; transition: color 0.2s; }
|
|
.qz-nav-links a:hover { color: #fff; }
|
|
|
|
/* Buttons */
|
|
.qz-btn {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 12px 24px; border-radius: var(--qz-radius);
|
|
font-size: 15px; font-weight: 600; text-decoration: none;
|
|
transition: all 0.2s; cursor: pointer; border: none;
|
|
}
|
|
|
|
.qz-btn-primary {
|
|
background: var(--qz-blue); color: #fff;
|
|
}
|
|
.qz-btn-primary:hover {
|
|
background: var(--qz-blue-dark); transform: translateY(-1px);
|
|
}
|
|
|
|
.qz-btn-ghost {
|
|
background: transparent; color: var(--qz-text);
|
|
border: 1px solid var(--qz-border);
|
|
}
|
|
.qz-btn-ghost:hover {
|
|
border-color: var(--qz-blue); color: var(--qz-blue);
|
|
}
|
|
|
|
/* Cards */
|
|
.qz-card {
|
|
background: var(--qz-surface);
|
|
border: 1px solid var(--qz-border);
|
|
border-radius: var(--qz-radius);
|
|
padding: 24px;
|
|
transition: transform 0.2s, border-color 0.2s;
|
|
}
|
|
.qz-card:hover {
|
|
transform: translateY(-2px);
|
|
border-color: rgba(0,122,255,0.3);
|
|
}
|
|
|
|
/* Footer */
|
|
.qz-footer {
|
|
border-top: 1px solid var(--qz-border);
|
|
padding: 40px 24px;
|
|
text-align: center;
|
|
color: var(--qz-text-dim);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Banner */
|
|
.qz-banner {
|
|
background: #001E50;
|
|
color: rgba(255,255,255,0.55);
|
|
text-align: center;
|
|
padding: 10px;
|
|
font-size: 12px;
|
|
}
|
|
.qz-banner a { color: rgba(255,255,255,0.8); text-decoration: none; }
|
|
|
|
@media (max-width: 768px) {
|
|
.qz-nav-links { display: none; }
|
|
}
|
|
</style>
|
|
<script type="module" src="https://auth.quixzoom.com/site-auth-snippet.js"></script>
|
|
<link rel="alternate" hreflang="en" href="https://www.quixzoom.com/" />
|
|
<link rel="alternate" hreflang="sv" href="https://www.quixzoom.com/sv/" />
|
|
<link rel="alternate" hreflang="de" href="https://www.quixzoom.com/de/" />
|
|
<link rel="alternate" hreflang="fr" href="https://www.quixzoom.com/fr/" />
|
|
<link rel="alternate" hreflang="es" href="https://www.quixzoom.com/es/" />
|
|
<link rel="alternate" hreflang="it" href="https://www.quixzoom.com/it/" />
|
|
<link rel="alternate" hreflang="nl" href="https://www.quixzoom.com/nl/" />
|
|
<link rel="alternate" hreflang="x-default" href="https://www.quixzoom.com/" />
|
|
</head>
|
|
<body>
|
|
<nav class="qz-nav">
|
|
<div class="container">
|
|
<div class="nav-inner">
|
|
<a href="/" class="nav-logo">qui<span>X</span>zoom</a>
|
|
<div class="nav-links">
|
|
<a href="/order/">Order</a>
|
|
<a href="/pricing/">Pricing</a>
|
|
<a href="/earn/">Earn as Zoomer</a>
|
|
<a href="/for-organisations/">For Organisations</a>
|
|
<a href="/about" class="active">About</a>
|
|
</div>
|
|
</div>
|
|
<a href="/order/" class="btn-nav">Start Order →</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<section class="hero">
|
|
<div class="container">
|
|
<h1>Building the world's<br>observation network</h1>
|
|
<p>quiXzoom connects organizations that need field data with people who can capture it. No platform fees. No middlemen. Just verified reality.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="content">
|
|
<div class="container">
|
|
<div class="stats">
|
|
<div class="stat">
|
|
<div class="stat-num">20+</div>
|
|
<div class="stat-label">Countries at launch</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-num">2,400+</div>
|
|
<div class="stat-label">Pre-registered Zoomers</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-num">100%</div>
|
|
<div class="stat-label">Zoomer earnings</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-num">0</div>
|
|
<div class="stat-label">Platform fees</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Our mission</h2>
|
|
<p>We believe that the gap between official data and ground reality is one of the most expensive problems in infrastructure, insurance, and urban planning. quiXzoom closes that gap by making field observation accessible, affordable, and verifiable at scale.</p>
|
|
<p>Every mission on quiXzoom is a data point that helps someone make a better decision — whether that's an insurer assessing risk, a municipality prioritizing repairs, or an enterprise verifying its supply chain.</p>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>How we're different</h2>
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>No platform fees</h3>
|
|
<p>Zoomers keep 100% of what they earn. We charge organizations for access to the network, not for individual transactions.</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Verified reality</h3>
|
|
<p>Every submission goes through automated AI review for completeness, quality, and geolocation accuracy before payment.</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Global from day one</h3>
|
|
<p>Launching in 5 markets in phases — Sweden first (August 2026), followed by Netherlands, Thailand, Nigeria and Kenya.</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Built for scale</h3>
|
|
<p>Missions can be configured and deployed within hours. Campaigns can range from 10 missions to 10,000.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Operated by Landvex</h2>
|
|
<p>quiXzoom is operated by Landvex AB, a decision intelligence company that transforms field observations into actionable intelligence for infrastructure owners, enterprises, and governments.</p>
|
|
<p>Landvex delivers control intelligence — infrastructure risk scores, urban intelligence, and contradiction analysis — to municipalities, enterprises, infrastructure operators and investors.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<footer class="qz-footer">
|
|
<div class="container">
|
|
<div class="footer-inner">
|
|
<div>© 2026 quiXzoom · Operated by Landvex AB</div>
|
|
<div class="footer-links">
|
|
<a href="/privacy">Privacy</a>
|
|
<a href="/terms">Terms</a>
|
|
<a href="/support">Support</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
<!-- quiXzoom Mina Sidor - Universal Header Component -->
|
|
<!-- Injicera detta i <head> på alla quiXzoom-sajter -->
|
|
|
|
<style>
|
|
.qz-auth-bar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 48px;
|
|
background: #0A0A0A;
|
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 20px;
|
|
z-index: 9999;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
|
|
}
|
|
.qz-auth-bar .qz-logo {
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
.qz-auth-bar .qz-logo span {
|
|
color: #007AFF;
|
|
}
|
|
.qz-auth-bar .qz-nav {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
.qz-auth-bar .qz-btn {
|
|
padding: 8px 16px;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
border: none;
|
|
text-decoration: none;
|
|
}
|
|
.qz-auth-bar .qz-btn-primary {
|
|
background: #007AFF;
|
|
color: white;
|
|
}
|
|
.qz-auth-bar .qz-btn-primary:hover {
|
|
background: #0056CC;
|
|
}
|
|
.qz-auth-bar .qz-btn-ghost {
|
|
background: transparent;
|
|
color: rgba(255,255,255,0.8);
|
|
}
|
|
.qz-auth-bar .qz-btn-ghost:hover {
|
|
background: rgba(255,255,255,0.1);
|
|
color: white;
|
|
}
|
|
.qz-auth-bar .qz-user {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: white;
|
|
font-size: 14px;
|
|
}
|
|
.qz-auth-bar .qz-avatar {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: #007AFF;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
}
|
|
.qz-auth-bar .qz-dropdown {
|
|
position: relative;
|
|
}
|
|
.qz-auth-bar .qz-dropdown-menu {
|
|
position: absolute;
|
|
top: 40px;
|
|
right: 0;
|
|
background: #1C1C1E;
|
|
border: 1px solid rgba(255,255,255,0.1);
|
|
border-radius: 12px;
|
|
padding: 8px;
|
|
min-width: 200px;
|
|
display: none;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
|
}
|
|
.qz-auth-bar .qz-dropdown-menu.active {
|
|
display: block;
|
|
}
|
|
.qz-auth-bar .qz-dropdown-item {
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
color: white;
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
font-size: 14px;
|
|
transition: background 0.2s;
|
|
}
|
|
.qz-auth-bar .qz-dropdown-item:hover {
|
|
background: rgba(255,255,255,0.1);
|
|
}
|
|
.qz-auth-bar .qz-dropdown-divider {
|
|
height: 1px;
|
|
background: rgba(255,255,255,0.1);
|
|
margin: 8px 0;
|
|
}
|
|
.qz-auth-bar .qz-balance {
|
|
background: rgba(0,122,255,0.15);
|
|
color: #007AFF;
|
|
padding: 4px 10px;
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
@media (max-width: 640px) {
|
|
.qz-auth-bar .qz-nav .qz-btn-ghost:not(.qz-user) {
|
|
display: none;
|
|
}
|
|
}
|
|
/* QUIXZOOM STANDARD — Dark Theme */
|
|
:root {
|
|
--qz-bg: #0a0a0a;
|
|
--qz-surface: #111111;
|
|
--qz-surface-2: #1a1a1a;
|
|
--qz-border: rgba(255,255,255,0.08);
|
|
--qz-text: #e8e8e8;
|
|
--qz-text-dim: #a0a0a0;
|
|
--qz-text-muted: #6b6b6b;
|
|
--qz-blue: #007AFF;
|
|
--qz-blue-dark: #0056CC;
|
|
--qz-radius: 10px;
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
|
|
background: var(--qz-bg);
|
|
color: var(--qz-text);
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* Navigation */
|
|
.qz-nav {
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 0 24px; height: 56px;
|
|
background: rgba(255,255,255,0.92);
|
|
backdrop-filter: blur(16px);
|
|
border-bottom: 1px solid var(--qz-border);
|
|
}
|
|
|
|
.qz-nav-logo { font-size: 18px; font-weight: 700; color: #fff; text-decoration: none; }
|
|
.qz-nav-links { display: flex; gap: 24px; list-style: none; }
|
|
.qz-nav-links a { font-size: 14px; color: var(--qz-text-dim); text-decoration: none; transition: color 0.2s; }
|
|
.qz-nav-links a:hover { color: #fff; }
|
|
|
|
/* Buttons */
|
|
.qz-btn {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 12px 24px; border-radius: var(--qz-radius);
|
|
font-size: 15px; font-weight: 600; text-decoration: none;
|
|
transition: all 0.2s; cursor: pointer; border: none;
|
|
}
|
|
|
|
.qz-btn-primary {
|
|
background: var(--qz-blue); color: #fff;
|
|
}
|
|
.qz-btn-primary:hover {
|
|
background: var(--qz-blue-dark); transform: translateY(-1px);
|
|
}
|
|
|
|
.qz-btn-ghost {
|
|
background: transparent; color: var(--qz-text);
|
|
border: 1px solid var(--qz-border);
|
|
}
|
|
.qz-btn-ghost:hover {
|
|
border-color: var(--qz-blue); color: var(--qz-blue);
|
|
}
|
|
|
|
/* Cards */
|
|
.qz-card {
|
|
background: var(--qz-surface);
|
|
border: 1px solid var(--qz-border);
|
|
border-radius: var(--qz-radius);
|
|
padding: 24px;
|
|
transition: transform 0.2s, border-color 0.2s;
|
|
}
|
|
.qz-card:hover {
|
|
transform: translateY(-2px);
|
|
border-color: rgba(0,122,255,0.3);
|
|
}
|
|
|
|
/* Footer */
|
|
.qz-footer {
|
|
border-top: 1px solid var(--qz-border);
|
|
padding: 40px 24px;
|
|
text-align: center;
|
|
color: var(--qz-text-dim);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Banner */
|
|
.qz-banner {
|
|
background: #001E50;
|
|
color: rgba(255,255,255,0.55);
|
|
text-align: center;
|
|
padding: 10px;
|
|
font-size: 12px;
|
|
}
|
|
.qz-banner a { color: rgba(255,255,255,0.8); text-decoration: none; }
|
|
|
|
@media (max-width: 768px) {
|
|
.qz-nav-links { display: none; }
|
|
}
|
|
</style>
|
|
|
|
<!--
|
|
quiXzoom Universal Auth Snippet v2.0
|
|
Add this to ALL quiXzoom sites for seamless cross-domain login
|
|
|
|
Features:
|
|
- Silent login (auto-refresh tokens)
|
|
- Cross-domain cookie sync
|
|
- Real-time auth state updates
|
|
- Mobile app compatible
|
|
-->
|
|
|
|
<!-- Auth bar styles -->
|
|
<style>
|
|
#qz-auth-bar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 48px;
|
|
background: #0A0A0A;
|
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 20px;
|
|
z-index: 9999;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
|
|
}
|
|
#qz-auth-bar .qz-logo {
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
#qz-auth-bar .qz-logo span { color: #007AFF; }
|
|
#qz-auth-bar .qz-nav {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
#qz-auth-bar .qz-btn {
|
|
padding: 8px 16px;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
border: none;
|
|
text-decoration: none;
|
|
}
|
|
#qz-auth-bar .qz-btn-primary {
|
|
background: #007AFF;
|
|
color: white;
|
|
}
|
|
#qz-auth-bar .qz-btn-primary:hover { background: #0056CC; }
|
|
#qz-auth-bar .qz-btn-ghost {
|
|
background: transparent;
|
|
color: rgba(255,255,255,0.8);
|
|
}
|
|
#qz-auth-bar .qz-btn-ghost:hover {
|
|
background: rgba(255,255,255,0.1);
|
|
color: white;
|
|
}
|
|
#qz-auth-bar .qz-user-menu {
|
|
position: relative;
|
|
}
|
|
#qz-auth-bar .qz-dropdown {
|
|
position: absolute;
|
|
top: 40px;
|
|
right: 0;
|
|
background: #1C1C1E;
|
|
border: 1px solid rgba(255,255,255,0.1);
|
|
border-radius: 12px;
|
|
padding: 8px;
|
|
min-width: 220px;
|
|
display: none;
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
|
}
|
|
#qz-auth-bar .qz-dropdown.active { display: block; }
|
|
#qz-auth-bar .qz-dropdown-item {
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
color: white;
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
font-size: 14px;
|
|
transition: background 0.2s;
|
|
}
|
|
#qz-auth-bar .qz-dropdown-item:hover { background: rgba(255,255,255,0.1); }
|
|
#qz-auth-bar .qz-dropdown-divider {
|
|
height: 1px;
|
|
background: rgba(255,255,255,0.1);
|
|
margin: 8px 0;
|
|
}
|
|
#qz-auth-bar .qz-avatar {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: #007AFF;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
color: white;
|
|
}
|
|
#qz-auth-bar .qz-balance {
|
|
background: rgba(0,122,255,0.15);
|
|
color: #007AFF;
|
|
padding: 4px 10px;
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
/* QUIXZOOM STANDARD — Dark Theme */
|
|
:root {
|
|
--qz-bg: #0a0a0a;
|
|
--qz-surface: #111111;
|
|
--qz-surface-2: #1a1a1a;
|
|
--qz-border: rgba(255,255,255,0.08);
|
|
--qz-text: #e8e8e8;
|
|
--qz-text-dim: #a0a0a0;
|
|
--qz-text-muted: #6b6b6b;
|
|
--qz-blue: #007AFF;
|
|
--qz-blue-dark: #0056CC;
|
|
--qz-radius: 10px;
|
|
}
|
|
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
|
|
background: var(--qz-bg);
|
|
color: var(--qz-text);
|
|
line-height: 1.6;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* Navigation */
|
|
.qz-nav {
|
|
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 0 24px; height: 56px;
|
|
background: rgba(255,255,255,0.92);
|
|
backdrop-filter: blur(16px);
|
|
border-bottom: 1px solid var(--qz-border);
|
|
}
|
|
|
|
.qz-nav-logo { font-size: 18px; font-weight: 700; color: #fff; text-decoration: none; }
|
|
.qz-nav-links { display: flex; gap: 24px; list-style: none; }
|
|
.qz-nav-links a { font-size: 14px; color: var(--qz-text-dim); text-decoration: none; transition: color 0.2s; }
|
|
.qz-nav-links a:hover { color: #fff; }
|
|
|
|
/* Buttons */
|
|
.qz-btn {
|
|
display: inline-flex; align-items: center; gap: 6px;
|
|
padding: 12px 24px; border-radius: var(--qz-radius);
|
|
font-size: 15px; font-weight: 600; text-decoration: none;
|
|
transition: all 0.2s; cursor: pointer; border: none;
|
|
}
|
|
|
|
.qz-btn-primary {
|
|
background: var(--qz-blue); color: #fff;
|
|
}
|
|
.qz-btn-primary:hover {
|
|
background: var(--qz-blue-dark); transform: translateY(-1px);
|
|
}
|
|
|
|
.qz-btn-ghost {
|
|
background: transparent; color: var(--qz-text);
|
|
border: 1px solid var(--qz-border);
|
|
}
|
|
.qz-btn-ghost:hover {
|
|
border-color: var(--qz-blue); color: var(--qz-blue);
|
|
}
|
|
|
|
/* Cards */
|
|
.qz-card {
|
|
background: var(--qz-surface);
|
|
border: 1px solid var(--qz-border);
|
|
border-radius: var(--qz-radius);
|
|
padding: 24px;
|
|
transition: transform 0.2s, border-color 0.2s;
|
|
}
|
|
.qz-card:hover {
|
|
transform: translateY(-2px);
|
|
border-color: rgba(0,122,255,0.3);
|
|
}
|
|
|
|
/* Footer */
|
|
.qz-footer {
|
|
border-top: 1px solid var(--qz-border);
|
|
padding: 40px 24px;
|
|
text-align: center;
|
|
color: var(--qz-text-dim);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Banner */
|
|
.qz-banner {
|
|
background: #001E50;
|
|
color: rgba(255,255,255,0.55);
|
|
text-align: center;
|
|
padding: 10px;
|
|
font-size: 12px;
|
|
}
|
|
.qz-banner a { color: rgba(255,255,255,0.8); text-decoration: none; }
|
|
|
|
@media (max-width: 768px) {
|
|
.qz-nav-links { display: none; }
|
|
}
|
|
</style>
|
|
|
|
<!-- Auth bar HTML -->
|
|
<div id="qz-auth-bar">
|
|
<a href="https://quixzoom.com" class="qz-logo">qui<span>X</span>zoom</a>
|
|
<div class="qz-nav">
|
|
<!-- Guest view -->
|
|
<div id="qz-guest-view">
|
|
<a href="https://app.quixzoom.com/login" class="qz-btn qz-btn-ghost">Logga in</a>
|
|
<a href="https://app.quixzoom.com/register" class="qz-btn qz-btn-primary">Bli Zoomer</a>
|
|
</div>
|
|
|
|
<!-- Authenticated view -->
|
|
<div id="qz-user-view" style="display:none;">
|
|
<span class="qz-balance" id="qz-balance">$0.00</span>
|
|
<div class="qz-user-menu">
|
|
<button class="qz-btn qz-btn-ghost" onclick="qzToggleMenu()" style="display:flex;align-items:center;gap:8px;">
|
|
<div class="qz-avatar" id="qz-avatar">?</div>
|
|
<span id="qz-user-name" style="color:white;">User</span>
|
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
</button>
|
|
<div class="qz-dropdown" id="qz-dropdown">
|
|
<a href="https://app.quixzoom.com/dashboard" class="qz-dropdown-item">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
|
|
<rect x="14" y="14" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/>
|
|
</svg>
|
|
Dashboard
|
|
</a>
|
|
<a href="https://app.quixzoom.com/wallet" class="qz-dropdown-item">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/>
|
|
<path d="M18 12a2 2 0 0 0 0 4h4v-4h-4z"/>
|
|
</svg>
|
|
Plånbok
|
|
</a>
|
|
<a href="https://app.quixzoom.com/missions" class="qz-dropdown-item">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/>
|
|
</svg>
|
|
Mina uppdrag
|
|
</a>
|
|
<div class="qz-dropdown-divider"></div>
|
|
<a href="https://app.quixzoom.com/settings" class="qz-dropdown-item">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="3"/>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.67 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.67 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.67a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
|
</svg>
|
|
Inställningar
|
|
</a>
|
|
<a href="#" onclick="qzLogout(); return false;" class="qz-dropdown-item">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/>
|
|
<line x1="21" y1="12" x2="9" y2="12"/>
|
|
</svg>
|
|
Logga ut
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SSO Client Script -->
|
|
<script>
|
|
(function() {
|
|
const SSO_BASE = 'https://auth.quixzoom.com';
|
|
|
|
// Check auth status on load
|
|
async function qzCheckAuth() {
|
|
try {
|
|
const res = await fetch(SSO_BASE + '/auth/silent', {
|
|
method: 'GET',
|
|
credentials: 'include',
|
|
});
|
|
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data.authenticated) {
|
|
qzShowUser(data.user);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Try check endpoint
|
|
const checkRes = await fetch(SSO_BASE + '/auth/check', {
|
|
credentials: 'include',
|
|
});
|
|
|
|
if (checkRes.ok) {
|
|
const checkData = await checkRes.json();
|
|
if (checkData.authenticated && checkData.user) {
|
|
qzShowUser(checkData.user);
|
|
return;
|
|
}
|
|
}
|
|
|
|
qzShowGuest();
|
|
} catch (e) {
|
|
console.log('[QZAuth] Check failed, showing guest');
|
|
qzShowGuest();
|
|
}
|
|
}
|
|
|
|
function qzShowUser(user) {
|
|
document.getElementById('qz-guest-view').style.display = 'none';
|
|
document.getElementById('qz-user-view').style.display = 'flex';
|
|
document.getElementById('qz-user-name').textContent = user.name || user.email;
|
|
document.getElementById('qz-avatar').textContent = (user.name || user.email)[0].toUpperCase();
|
|
|
|
// Dispatch event for other scripts
|
|
window.dispatchEvent(new CustomEvent('qz-auth-change', {
|
|
detail: { authenticated: true, user }
|
|
}));
|
|
}
|
|
|
|
function qzShowGuest() {
|
|
document.getElementById('qz-guest-view').style.display = 'flex';
|
|
document.getElementById('qz-user-view').style.display = 'none';
|
|
|
|
window.dispatchEvent(new CustomEvent('qz-auth-change', {
|
|
detail: { authenticated: false }
|
|
}));
|
|
}
|
|
|
|
window.qzToggleMenu = function() {
|
|
document.getElementById('qz-dropdown').classList.toggle('active');
|
|
};
|
|
|
|
window.qzLogout = async function() {
|
|
try {
|
|
await fetch(SSO_BASE + '/auth/logout', {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
});
|
|
} catch (e) {}
|
|
|
|
// Clear all cookies
|
|
document.cookie = 'qz_access_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;';
|
|
document.cookie = 'qz_refresh_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;';
|
|
document.cookie = 'qz_auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.quixzoom.com; path=/;';
|
|
|
|
qzShowGuest();
|
|
window.location.reload();
|
|
};
|
|
|
|
// Close dropdown on outside click
|
|
document.addEventListener('click', function(e) {
|
|
if (!e.target.closest('.qz-user-menu')) {
|
|
document.getElementById('qz-dropdown').classList.remove('active');
|
|
}
|
|
});
|
|
|
|
// Check auth on page load
|
|
qzCheckAuth();
|
|
|
|
// Re-check auth periodically (every 5 minutes)
|
|
setInterval(qzCheckAuth, 5 * 60 * 1000);
|
|
|
|
// Listen for storage events (login from other tabs)
|
|
window.addEventListener('storage', function(e) {
|
|
if (e.key === 'qz_auth_event') {
|
|
const event = JSON.parse(e.newValue || '{}');
|
|
if (event.type === 'login') {
|
|
qzCheckAuth();
|
|
} else if (event.type === 'logout') {
|
|
qzShowGuest();
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html> |