Files
boc/quixzoom-landing-fixed/launch.html
T
Bernt 1a12fb870b dev-api: add developer portal, OpenAPI spec, and Flatenbadet case study
- 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
2026-07-14 15:27:33 +00:00

1436 lines
47 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="sv" data-theme="dark">
<head>
<meta charset="UTF-8">
<link rel="canonical" href="https://www.quixzoom.com/launch.html">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>quiXzoom Launch — Sverige 2026</title>
<meta name="description" content="quiXzoom launches in Sweden 2026. Join the revolution — earn money taking photos, flexible missions, instant payouts.">
<link rel="stylesheet" >
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--ios-bg-primary: #000000;
--ios-bg-secondary: #1C1C1E;
--ios-bg-tertiary: #2C2C2E;
--ios-bg-elevated: #3A3A3C;
--ios-separator: rgba(84,84,88,0.65);
--ios-label: #FFFFFF;
--ios-label-secondary: rgba(235,235,245,0.6);
--ios-label-tertiary: rgba(235,235,245,0.3);
--ios-blue: #0A84FF;
--ios-green: #30D158;
--ios-orange: #FF9F0A;
--ios-red: #FF453A;
--ios-purple: #BF5AF2;
--ios-teal: #64D2FF;
--ios-yellow: #FFD60A;
--ios-indigo: #5E5CE6;
--ios-pink: #FF375F;
--ios-mint: #63E6E2;
--radius-card: 16px;
--radius-sm: 10px;
--font-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', system-ui, sans-serif;
--font-text: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
--spring: cubic-bezier(0.34,1.56,0.64,1);
}
body {
background: var(--ios-bg-primary);
color: var(--ios-label);
font-family: var(--font-text);
-webkit-font-smoothing: antialiased;
min-height: 100dvh;
padding-bottom: calc(40px + env(safe-area-inset-bottom, 0));
overflow-x: hidden;
}
/* Nav Bar */
.nav-bar {
position: sticky;
top: 0;
z-index: 100;
background: rgba(242,242,247,0.85);
backdrop-filter: saturate(180%) blur(24px);
-webkit-backdrop-filter: saturate(180%) blur(24px);
border-bottom: 0.5px solid var(--ios-separator);
display: flex;
align-items: center;
justify-content: space-between;
padding: calc(env(safe-area-inset-top, 0px) + 10px) 20px 10px;
min-height: 52px;
}
.nav-back {
color: var(--ios-blue);
font-size: 17px;
text-decoration: none;
display: flex;
align-items: center;
gap: 4px;
}
.nav-title {
font-size: 17px;
font-weight: 600;
font-family: var(--font-display);
letter-spacing: -0.3px;
}
.nav-pill {
font-size: 13px;
font-weight: 600;
padding: 4px 10px;
border-radius: var(--radius-xl);
background: var(--ios-bg-tertiary);
color: var(--ios-label-secondary);
}
.nav-pill.critical { background: rgba(255,69,58,0.2); color: var(--ios-red); }
.nav-pill.warning { background: rgba(255,159,10,0.2); color: var(--ios-orange); }
.nav-pill.ok { background: rgba(48,209,88,0.2); color: var(--ios-green); }
/* Hero Countdown */
.hero {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 20px 20px;
text-align: center;
background: linear-gradient(180deg, rgba(10,132,255,0.08) 0%, transparent 100%);
border-bottom: 0.5px solid var(--ios-separator);
}
.hero-eyebrow {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.5px;
text-transform: uppercase;
color: var(--ios-blue);
margin-bottom: 8px;
}
.hero-title {
font-size: 28px;
font-weight: 700;
font-family: var(--font-display);
letter-spacing: -0.5px;
margin-bottom: 24px;
}
.countdown-ring {
position: relative;
width: 160px;
height: 160px;
margin-bottom: 16px;
}
.countdown-ring svg {
width: 160px;
height: 160px;
transform: rotate(-90deg);
}
.countdown-ring circle {
fill: none;
stroke-width: 6;
stroke-linecap: round;
}
.countdown-ring .track { stroke: var(--ios-bg-tertiary); }
.countdown-ring .progress { stroke: var(--ios-blue); transition: stroke-dashoffset 1s ease; }
.countdown-inner {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.countdown-days {
font-size: 52px;
font-weight: 800;
font-family: var(--font-display);
line-height: 1;
letter-spacing: -2px;
}
.countdown-label {
font-size: 13px;
color: var(--ios-label-secondary);
font-weight: 500;
margin-top: 2px;
}
.hero-date {
font-size: 15px;
color: var(--ios-label-secondary);
margin-bottom: 4px;
}
.hero-date strong { color: var(--ios-label); font-weight: 600; }
/* Stat Row */
.stat-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1px;
background: var(--ios-separator);
border-top: 1px solid var(--ios-separator);
border-bottom: 1px solid var(--ios-separator);
margin-top: 0;
}
.stat-cell {
background: var(--ios-bg-primary);
padding: 14px 12px;
text-align: center;
}
.stat-num {
font-size: 24px;
font-weight: 700;
font-family: var(--font-display);
letter-spacing: -0.5px;
}
.stat-desc {
font-size: 11px;
color: var(--ios-label-secondary);
margin-top: 2px;
}
/* Content */
.content { padding: 0 0 20px; }
/* Section header */
.section-header {
padding: 24px 20px 8px;
display: flex;
align-items: center;
justify-content: space-between;
}
.section-title {
font-size: 20px;
font-weight: 700;
font-family: var(--font-display);
letter-spacing: -0.3px;
}
.section-badge {
font-size: 13px;
font-weight: 600;
color: var(--ios-label-secondary);
}
.section-badge.ok { color: var(--ios-green); }
.section-badge.warn { color: var(--ios-orange); }
.section-badge.crit { color: var(--ios-red); }
/* Card list */
.card-list {
margin: 0 16px;
background: var(--ios-bg-secondary);
border-radius: var(--radius-card);
overflow: hidden;
}
/* Milestone row */
.milestone-row {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-bottom: 0.5px solid var(--ios-separator);
cursor: pointer;
transition: background 0.15s;
-webkit-tap-highlight-color: transparent;
}
.milestone-row:last-child { border-bottom: none; }
.milestone-row:active { background: var(--ios-bg-tertiary); }
.checkbox {
width: 24px;
height: 24px;
border-radius: var(--radius-full);
border: 2px solid var(--ios-bg-elevated);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.2s var(--spring);
background: var(--ios-bg-secondary);
}
.checkbox.checked {
background: var(--ios-green);
border-color: var(--ios-green);
}
.checkbox.checked::after {
content: '';
width: 6px;
height: 10px;
border: 2px solid white;
border-top: none;
border-left: none;
transform: rotate(45deg) translate(-1px, -1px);
display: block;
}
.checkbox.critical { border-color: var(--ios-red); }
.milestone-text { flex: 1; min-width: 0; }
.milestone-label {
font-size: 15px;
font-weight: 500;
color: var(--ios-label);
line-height: 1.3;
}
.milestone-meta {
font-size: 12px;
color: var(--ios-label-secondary);
margin-top: 2px;
}
.milestone-row.done .milestone-label {
color: var(--ios-label-secondary);
text-decoration: line-through;
}
.blocker-tag {
font-size: 11px;
font-weight: 600;
padding: 3px 8px;
border-radius: var(--radius-sm);
background: rgba(255,69,58,0.15);
color: var(--ios-red);
flex-shrink: 0;
}
.warn-tag {
font-size: 11px;
font-weight: 600;
padding: 3px 8px;
border-radius: var(--radius-sm);
background: rgba(255,159,10,0.15);
color: var(--ios-orange);
flex-shrink: 0;
}
.ok-tag {
font-size: 11px;
font-weight: 600;
padding: 3px 8px;
border-radius: var(--radius-sm);
background: rgba(48,209,88,0.15);
color: var(--ios-green);
flex-shrink: 0;
}
/* Revenue / Tech status rows */
.status-row {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-bottom: 0.5px solid var(--ios-separator);
}
.status-row:last-child { border-bottom: none; }
.status-icon {
width: 36px;
height: 36px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.status-icon.blue { background: rgba(10,132,255,0.15); }
.status-icon.green { background: rgba(48,209,88,0.15); }
.status-icon.orange { background: rgba(255,159,10,0.15); }
.status-icon.red { background: rgba(255,69,58,0.15); }
.status-icon.purple { background: rgba(191,90,242,0.15); }
.status-text { flex: 1; min-width: 0; }
.status-label {
font-size: 15px;
font-weight: 500;
}
.status-desc {
font-size: 12px;
color: var(--ios-label-secondary);
margin-top: 2px;
}
.status-dot {
width: 10px;
height: 10px;
border-radius: var(--radius-full);
flex-shrink: 0;
}
.status-dot.red { background: var(--ios-red); }
.status-dot.orange { background: var(--ios-orange); }
.status-dot.green { background: var(--ios-green); }
.status-dot.grey { background: var(--ios-label-secondary); }
/* Team action rows */
.action-row {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 14px 16px;
border-bottom: 0.5px solid var(--ios-separator);
}
.action-row:last-child { border-bottom: none; }
.action-avatar {
width: 36px;
height: 36px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 700;
flex-shrink: 0;
}
.action-text { flex: 1; min-width: 0; }
.action-who {
font-size: 15px;
font-weight: 600;
}
.action-task {
font-size: 14px;
color: var(--ios-label-secondary);
margin-top: 2px;
line-height: 1.4;
}
.action-time {
font-size: 12px;
color: var(--ios-label-tertiary);
flex-shrink: 0;
margin-top: 2px;
}
/* Progress bar */
.progress-bar-wrap {
padding: 0 16px 16px;
margin: 0 16px;
background: var(--ios-bg-secondary);
border-radius: 0 0 var(--radius-card) var(--radius-card);
}
.progress-bar-label {
display: flex;
justify-content: space-between;
font-size: 13px;
color: var(--ios-label-secondary);
margin-bottom: 8px;
padding-top: 4px;
}
.progress-bar-track {
height: 6px;
background: var(--ios-bg-elevated);
border-radius: var(--radius-sm);
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
border-radius: var(--radius-sm);
background: var(--ios-green);
transition: width 0.8s var(--spring);
}
/* Info card */
.info-card {
margin: 16px 16px 0;
background: rgba(10,132,255,0.08);
border: 1px solid rgba(10,132,255,0.2);
border-radius: var(--radius-card);
padding: 14px 16px;
display: flex;
gap: 10px;
align-items: flex-start;
}
.info-card-icon { font-size: 20px; flex-shrink: 0; }
.info-card-text { font-size: 14px; color: var(--ios-label-secondary); line-height: 1.5; }
.info-card-text strong { color: var(--ios-blue); }
/* Last updated */
.last-updated {
text-align: center;
font-size: 12px;
color: var(--ios-label-tertiary);
padding: 20px 20px 4px;
}
/* Spinner */
.spin {
display: inline-block;
width: 14px;
height: 14px;
border: 2px solid var(--ios-label-tertiary);
border-top-color: var(--ios-blue);
border-radius: var(--radius-full);
animation: spin 0.8s linear infinite;
vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Responsive */
@media (min-width: 600px) {
.hero, .stat-row, .content { max-width: 480px; margin-left: auto; margin-right: auto; }
.nav-bar { max-width: none; }
}
@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>
<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; }
}
/* 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>
<meta property="og:type" content="website">
<meta property="og:title" content="quiXzoom Launch — Sverige 2026">
<meta property="og:description" content="quiXzoom — Earn per Mission. No Platform Fee.">
<meta property="og:url" content="https://www.quixzoom.com/launch.html">
<meta property="og:image" content="https://www.quixzoom.com/images/sweden-launch.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="quiXzoom launch August 2026 — earn per mission">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://www.quixzoom.com/images/sweden-launch.jpg">
<meta name="twitter:title" content="quiXzoom Launch — Sverige 2026">
<script type="module" src="https://auth.quixzoom.com/site-auth-snippet.js"></script>
</head>
<body>
<!-- Nav Bar -->
<nav class="qz-nav" class="nav-bar">
<a class="nav-back" href="aamos-hub/index.html">
<svg width="10" height="17" viewBox="0 0 10 17" fill="none"><path d="M9 1L1 8.5L9 16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
Hub
</a>
<span class="nav-title">quiXzoom Launch</span>
<span class="nav-pill critical" id="nav-pill"><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> <span id="nav-days"></span>d</span>
</nav>
<!-- Hero -->
<section class="hero">
<div class="hero-eyebrow"><span class="flag-se">SE</span> Sverige-lansering</div>
<h1 class="hero-title">quiXzoom Launch Tracker</h1>
<div class="countdown-ring">
<svg viewBox="0 0 160 160">
<circle class="track" cx="80" cy="80" r="70" />
<circle class="progress" cx="80" cy="80" r="70"
stroke-dasharray="439.8"
id="progress-arc"
stroke-dashoffset="0" />
</svg>
<div class="countdown-inner">
<span class="countdown-days" id="countdown-days"></span>
<span class="countdown-label">dagar kvar</span>
</div>
</div>
<p class="hero-date">Lanseringsdatum: <strong>1 augusti 2026</strong></p>
</section>
<!-- Stats -->
<div class="stat-row">
<div class="stat-cell">
<div class="stat-num" id="stat-done" style="color:var(--ios-green)">0</div>
<div class="stat-desc">Klara</div>
</div>
<div class="stat-cell">
<div class="stat-num" id="stat-remaining" style="color:var(--ios-orange)">9</div>
<div class="stat-desc">Återstår</div>
</div>
<div class="stat-cell">
<div class="stat-num" id="stat-blockers" style="color:var(--ios-red)">2</div>
<div class="stat-desc">Blockers</div>
</div>
</div>
<!-- Content -->
<div class="content">
<!-- Section 1: Kritiska Milstolpar -->
<div class="section-header">
<h2 class="section-title">Kritiska Milstolpar</h2>
<span class="section-badge crit" id="milestone-badge">0 / 9</span>
</div>
<div class="card-list" id="milestone-list">
<!-- Stripe KYC -->
<div class="milestone-row" data-id="stripe-kyc" data-blocker="true" onclick="toggleMilestone(this)">
<div class="checkbox critical" id="chk-stripe-kyc"></div>
<div class="milestone-text">
<div class="milestone-label">Stripe KYC aktiverat</div>
<div class="milestone-meta">Blockar alla betalningar · Prioritet #1</div>
</div>
<span class="blocker-tag">BLOCKER</span>
</div>
<!-- TED EU -->
<div class="milestone-row" data-id="ted-api" data-blocker="true" onclick="toggleMilestone(this)">
<div class="checkbox critical" id="chk-ted-api"></div>
<div class="milestone-text">
<div class="milestone-label">TED EU API-nyckel konfigurerad</div>
<div class="milestone-meta">5 min · gratis · Erik fixar</div>
</div>
<span class="blocker-tag">BLOCKER</span>
</div>
<!-- EIN -->
<div class="milestone-row" data-id="ein" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-ein"></div>
<div class="milestone-text">
<div class="milestone-label">EIN QuiXzoom Inc (Delaware) mottaget</div>
<div class="milestone-meta">Winston follow-up pågår</div>
</div>
<span class="warn-tag">VÄNTAR</span>
</div>
<!-- Zoomer rekrytering -->
<div class="milestone-row" data-id="zoomer-rekrytering" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-zoomer-rekrytering"></div>
<div class="milestone-text">
<div class="milestone-label">Zoomer rekryteringskampanj aktiv</div>
<div class="milestone-meta">Mål: 20+ zoomers inför soft launch</div>
</div>
<span class="warn-tag">EJ STARTAD</span>
</div>
<!-- App Store -->
<div class="milestone-row" data-id="app-store" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-app-store"></div>
<div class="milestone-text">
<div class="milestone-label">App Store-ansökan (iOS + Android)</div>
<div class="milestone-meta">Johan ansvarig · Review tar 13 dagar</div>
</div>
<span class="warn-tag">EJ STARTAT</span>
</div>
<!-- Stripe Connect -->
<div class="milestone-row" data-id="stripe-connect" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-stripe-connect"></div>
<div class="milestone-text">
<div class="milestone-label">Stripe Connect för zoomer-utbetalningar</div>
<div class="milestone-meta">Beror på Stripe KYC</div>
</div>
<span class="warn-tag">BLOCKERAS</span>
</div>
<!-- PR -->
<div class="milestone-row" data-id="pr" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-pr"></div>
<div class="milestone-text">
<div class="milestone-label">PR / pressrelease klar</div>
<div class="milestone-meta">Deadline: 25 maj 2026</div>
</div>
<span class="warn-tag">EJ KLAR</span>
</div>
<!-- Beta-test -->
<div class="milestone-row" data-id="beta" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-beta"></div>
<div class="milestone-text">
<div class="milestone-label">Beta-test genomfört (min. 10 zoomers)</div>
<div class="milestone-meta">Soft launch: 1 augusti 2026</div>
</div>
<span class="warn-tag">EJ STARTAD</span>
</div>
<!-- Legal -->
<div class="milestone-row" data-id="legal" onclick="toggleMilestone(this)">
<div class="checkbox" id="chk-legal"></div>
<div class="milestone-text">
<div class="milestone-label">Legal (terms, privacy policy) godkänt</div>
<div class="milestone-meta">GDPR Art. 13, Art. 30 + zoomer-avtal</div>
</div>
<span class="warn-tag">EJ KLART</span>
</div>
</div>
<!-- Progress bar (continuation of card) -->
<div class="progress-bar-wrap" style="margin: 0 16px; border-radius: 0 0 16px 16px; padding: 12px 16px 16px;">
<div class="progress-bar-label">
<span>Framsteg</span>
<span id="pct-label">0%</span>
</div>
<div class="progress-bar-track">
<div class="progress-bar-fill" id="progress-fill" style="width:0%"></div>
</div>
</div>
<!-- Section 2: Revenue Readiness -->
<div class="section-header">
<h2 class="section-title">Revenue Readiness</h2>
<span class="section-badge crit" id="revenue-badge"><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> Ej redo</span>
</div>
<div class="card-list">
<div class="status-row">
<div class="status-icon red"></div>
<div class="status-text">
<div class="status-label">Stripe KYC</div>
<div class="status-desc">Blockar alla live-betalningar — aktivera omedelbart</div>
</div>
<div class="status-dot red"></div>
</div>
<div class="status-row">
<div class="status-icon orange"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 8C2 11.3 4.7 14 8 14C10.5 14 12.7 12.5 13.7 10.3" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M14 8C14 4.7 11.3 2 8 2C5.5 2 3.3 3.5 2.3 5.7" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M13.5 7.5L14 10L11.5 9.5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M2.5 8.5L2 6L4.5 6.5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<div class="status-text">
<div class="status-label">Payment flow</div>
<div class="status-desc">Ej testbar utan Stripe KYC · Implementerat i kod</div>
</div>
<div class="status-dot orange"></div>
</div>
<div class="status-row">
<div class="status-icon green"></div>
<div class="status-text">
<div class="status-label">Pricing konfigurerat</div>
<div class="status-desc">quiXzoom-priser satt i systemet</div>
</div>
<div class="status-dot green"></div>
</div>
<div class="status-row">
<div class="status-icon red"></div>
<div class="status-text">
<div class="status-label">Stripe Connect (zoomer-utbetalningar)</div>
<div class="status-desc">Väntar på KYC-godkännande</div>
</div>
<div class="status-dot red"></div>
</div>
</div>
<!-- Section 3: Tech Readiness -->
<div class="section-header">
<h2 class="section-title">Tech Readiness</h2>
<span class="section-badge warn" id="tech-badge">Delvis redo</span>
</div>
<div class="card-list">
<div class="status-row">
<div class="status-icon green"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="3" stroke="#666" stroke-width="1.5"/><path d="M8 2V4M8 12V14M2 8H4M12 8H14M4.3 4.3L5.7 5.7M10.3 10.3L11.7 11.7M4.3 11.7L5.7 10.3M10.3 5.7L11.7 4.3" stroke="#666" stroke-width="1.5" stroke-linecap="round"/></svg></div>
<div class="status-text">
<div class="status-label">AAMOS backend</div>
<div class="status-desc">Live · amos.wavult.com operationell</div>
</div>
<div class="status-dot green"></div>
</div>
<div class="status-row">
<div class="status-icon green"></div>
<div class="status-text">
<div class="status-label">quixzoom.com</div>
<div class="status-desc">Landing page live</div>
</div>
<div class="status-dot green"></div>
</div>
<div class="status-row">
<div class="status-icon orange"></div>
<div class="status-text">
<div class="status-label">iOS / Android app</div>
<div class="status-desc">Under utveckling · App Store-submission ej genomförd</div>
</div>
<div class="status-dot orange"></div>
</div>
<div class="status-row">
<div class="status-icon orange"></div>
<div class="status-text">
<div class="status-label">TED EU API</div>
<div class="status-desc">API-nyckel saknas · 5 min att fixa</div>
</div>
<div class="status-dot orange"></div>
</div>
<div class="status-row">
<div class="status-icon red"></div>
<div class="status-text">
<div class="status-label">Load-test + rollback-plan</div>
<div class="status-desc">Ej genomfört · Kritisk inför launch</div>
</div>
<div class="status-dot red"></div>
</div>
<div class="status-row">
<div class="status-icon red"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="7" width="10" height="7" rx="1" stroke="#666" stroke-width="1.5"/><path d="M5 7V5C5 3.3 6.3 2 8 2C9.7 2 11 3.3 11 5V7" stroke="#666" stroke-width="1.5"/><circle cx="8" cy="10.5" r="1" fill="#666"/></svg></div>
<div class="status-text">
<div class="status-label">Pentest / säkerhetsgranskning</div>
<div class="status-desc">Ej genomförd · Måste göras inför launch</div>
</div>
<div class="status-dot red"></div>
</div>
</div>
<!-- Section 4: Team Actions Needed -->
<div class="section-header">
<h2 class="section-title">Team Actions Needed</h2>
<span class="section-badge crit">Åtgärd krävs</span>
</div>
<div class="card-list">
<div class="action-row">
<div class="action-avatar" style="background:rgba(10,132,255,0.15);color:var(--ios-blue)">ES</div>
<div class="action-text">
<div class="action-who">Erik</div>
<div class="action-task">Stripe KYC — logga in på Stripe Dashboard, slutför verifiering<br><strong style="color:var(--ios-red)">BLOCKER</strong> · Tar 3060 min</div>
</div>
<div class="action-time">Idag</div>
</div>
<div class="action-row">
<div class="action-avatar" style="background:rgba(10,132,255,0.15);color:var(--ios-blue)">ES</div>
<div class="action-text">
<div class="action-who">Erik</div>
<div class="action-task">TED EU API-nyckel — skaffa och konfigurera<br><em style="color:var(--ios-label-secondary)">Gratis · 5 min</em></div>
</div>
<div class="action-time">Idag</div>
</div>
<div class="action-row">
<div class="action-avatar" style="background:rgba(48,209,88,0.15);color:var(--ios-green)">JN</div>
<div class="action-text">
<div class="action-who">Johan</div>
<div class="action-task">App Store submission — iOS + Android<br><em style="color:var(--ios-label-secondary)">Review tar 13 dagar efter submission</em></div>
</div>
<div class="action-time">Denna vecka</div>
</div>
<div class="action-row">
<div class="action-avatar" style="background:rgba(191,90,242,0.15);color:var(--ios-purple)">WK</div>
<div class="action-text">
<div class="action-who">Winston</div>
<div class="action-task">EIN follow-up — QuiXzoom Inc Delaware<br><em style="color:var(--ios-label-secondary)">Kontakta IRS / formation-agent</em></div>
</div>
<div class="action-time">Denna vecka</div>
</div>
</div>
<div class="info-card">
<div class="info-card-icon"></div>
<div class="info-card-text">
<strong>Nästa kritiska deadline:</strong> PR/pressrelease måste vara klar senast <strong>25 maj</strong> (3 veckor innan launch). Zoomer-rekrytering bör starta omedelbart — mål: 20+ zoomers till soft launch <strong>1 augusti</strong>.
</div>
</div>
<div class="last-updated" id="last-updated">Uppdaterad <span id="updated-time"></span></div>
</div><!-- /content -->
<script>
// Launch date
const LAUNCH_DATE = new Date('2026-06-15T00:00:00+02:00');
// We assume campaign started ~90 days before launch for the ring
const CAMPAIGN_START = new Date('2026-03-17T00:00:00+02:00');
function daysUntilLaunch() {
const now = new Date();
return Math.max(0, Math.ceil((LAUNCH_DATE - now) / 86400000));
}
function updateHero() {
const days = daysUntilLaunch();
document.getElementById('countdown-days').textContent = days;
document.getElementById('nav-days').textContent = days;
// Ring: 0 = no time left, full = 100% remaining
const total = (LAUNCH_DATE - CAMPAIGN_START) / 86400000;
const remaining = (LAUNCH_DATE - new Date()) / 86400000;
const pct = Math.max(0, Math.min(1, remaining / total));
const circumference = 2 * Math.PI * 70; // r=70
const offset = circumference * (1 - pct);
document.getElementById('progress-arc').style.strokeDasharray = circumference;
document.getElementById('progress-arc').style.strokeDashoffset = offset;
// Color
const arc = document.getElementById('progress-arc');
arc.style.stroke = days <= 7 ? 'var(--ios-red)' : days <= 21 ? 'var(--ios-orange)' : 'var(--ios-blue)';
const pill = document.getElementById('nav-pill');
pill.className = 'nav-pill ' + (days <= 7 ? 'critical' : days <= 21 ? 'warning' : 'critical');
document.getElementById('updated-time').textContent = new Date().toLocaleString('sv-SE', {
day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit'
});
}
// Milestone state (persisted in localStorage)
const STORAGE_KEY = 'qx_launch_milestones_v2';
function loadState() {
try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); } catch { return {}; }
}
function saveState(state) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}
function applyState() {
const state = loadState();
let done = 0, blockers = 0;
const rows = document.querySelectorAll('.milestone-row[data-id]');
rows.forEach(row => {
const id = row.dataset.id;
const chk = document.getElementById('chk-' + id);
if (state[id]) {
chk.classList.add('checked');
row.classList.add('done');
done++;
// Remove tags when done
const tag = row.querySelector('.blocker-tag, .warn-tag, .ok-tag');
if (tag) tag.style.display = 'none';
} else {
chk.classList.remove('checked');
row.classList.remove('done');
if (row.dataset.blocker === 'true' && !state[id]) blockers++;
}
});
const remaining = rows.length - done;
document.getElementById('stat-done').textContent = done;
document.getElementById('stat-remaining').textContent = remaining;
document.getElementById('stat-blockers').textContent = blockers;
document.getElementById('milestone-badge').textContent = done + ' / ' + rows.length;
const pct = Math.round((done / rows.length) * 100);
document.getElementById('progress-fill').style.width = pct + '%';
document.getElementById('pct-label').textContent = pct + '%';
const badge = document.getElementById('milestone-badge');
badge.className = 'section-badge ' + (done === rows.length ? 'ok' : done > rows.length / 2 ? 'warn' : 'crit');
}
function toggleMilestone(row) {
const id = row.dataset.id;
const state = loadState();
state[id] = !state[id];
saveState(state);
applyState();
}
// Init
updateHero();
applyState();
setInterval(updateHero, 60000);
</script>
<!-- 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>
<div id="qz-auth-bar" class="qz-auth-bar">
<a href="https://quixzoom.com" class="qz-logo">qui<span>X</span>zoom</a>
<div class="qz-nav">
<div id="qz-auth-guest">
<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>
<div id="qz-auth-user" style="display:none;">
<span class="qz-balance" id="qz-balance">$0.00</span>
<div class="qz-dropdown">
<button class="qz-btn qz-btn-ghost qz-user" onclick="qzToggleDropdown()">
<div class="qz-avatar" id="qz-avatar">E</div>
<span id="qz-user-name">Erik</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-menu" id="qz-dropdown-menu">
<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>
<script>
(function() {
const SSO_BASE = 'https://auth.quixzoom.com';
const APP_BASE = 'https://app.quixzoom.com';
// Check auth status
async function qzCheckAuth() {
try {
const res = await fetch(SSO_BASE + '/auth/check', {
credentials: 'include',
});
if (res.ok) {
const data = await res.json();
if (data.authenticated) {
document.getElementById('qz-auth-guest').style.display = 'none';
document.getElementById('qz-auth-user').style.display = 'flex';
document.getElementById('qz-user-name').textContent = data.user.name || data.user.email;
document.getElementById('qz-avatar').textContent = (data.user.name || data.user.email)[0].toUpperCase();
if (data.user.balance !== undefined) {
document.getElementById('qz-balance').textContent = '$' + data.user.balance.toFixed(2);
}
}
}
} catch (e) {
// Silent fail - show guest state
}
}
// Toggle dropdown
window.qzToggleDropdown = function() {
document.getElementById('qz-dropdown-menu').classList.toggle('active');
};
// Close dropdown on outside click
document.addEventListener('click', function(e) {
if (!e.target.closest('.qz-dropdown')) {
document.getElementById('qz-dropdown-menu').classList.remove('active');
}
});
// Logout
window.qzLogout = async function() {
try {
await fetch(SSO_BASE + '/auth/logout', {
method: 'POST',
credentials: 'include',
});
} catch (e) {}
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=/;';
window.location.reload();
};
// Init
qzCheckAuth();
})();
</script>
</body>
</html>