Files
boc/quixzoom-landing-fixed/launch-campaign.html
T
Bernt 6989a98d75 feat: Passwordless cross-device authentication
- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
2026-07-07 07:11:50 +00:00

588 lines
29 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">
<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>Launch Campaign — quiXzoom</title>
<link rel="stylesheet" >
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-text);
background: var(--grouped-background-primary);
color: var(--label-primary);
min-height: 100dvh;
padding-top: env(safe-area-inset-top, 44px);
padding-bottom: calc(env(safe-area-inset-bottom, 34px) + 40px);
-webkit-font-smoothing: antialiased;
}
.nav-bar {
position: sticky; top: 0; z-index: 200;
display: flex; align-items: center; justify-content: space-between;
height: 44px; padding: 0 16px;
background: var(--navbar-bg);
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
border-bottom: 0.5px solid var(--separator);
}
.nav-title { font-size: 17px; font-weight: 600; letter-spacing: -0.41px; }
.nav-live {
font-size: 12px; font-weight: 600; padding: 4px 10px;
background: rgba(255,69,58,0.15); color: var(--ios-red);
border-radius: var(--radius-xl); display: flex; align-items: center; gap: 5px;
}
.live-dot { width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--ios-red); animation: pulse 1.5s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
/* Countdown */
.countdown-hero {
padding: 32px 20px 24px; text-align: center;
background: linear-gradient(180deg, rgba(255,69,58,0.06) 0%, transparent 100%);
}
.countdown-title { font-size: 14px; font-weight: 600; color: var(--label-secondary); text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 16px; }
.countdown-grid { display: flex; justify-content: center; gap: 10px; }
.countdown-unit {
text-align: center;
background: var(--background-secondary);
border: 0.5px solid var(--separator);
border-radius: var(--radius-lg); padding: 14px 16px; min-width: 70px;
}
.countdown-num {
font-family: var(--font-display);
font-size: 36px; font-weight: 800; letter-spacing: -1px;
line-height: 1; color: var(--ios-red);
}
.countdown-label { font-size: 11px; color: var(--label-secondary); margin-top: 6px; font-weight: 500; }
.launch-date {
font-size: 15px; color: var(--label-secondary); margin-top: 16px;
}
.launch-date strong { color: var(--label-primary); }
/* Targets */
.target-row {
display: flex; gap: 10px; margin: 0 16px 20px;
}
.target-card {
flex: 1; background: var(--background-secondary);
border: 0.5px solid var(--separator);
border-radius: var(--radius-lg); padding: 16px; text-align: center;
}
.target-icon { font-size: 24px; margin-bottom: 6px; }
.target-num { font-size: 26px; font-weight: 800; font-family: var(--font-display); letter-spacing: -0.5px; }
.target-label { font-size: 12px; color: var(--label-secondary); margin-top: 3px; }
/* Section */
.section { margin: 0 16px 24px; }
.section-header {
font-size: 13px; font-weight: 600; color: var(--label-secondary);
text-transform: uppercase; letter-spacing: 0.5px;
padding: 0 4px 10px;
}
/* Checklist */
.checklist-card {
background: var(--background-secondary);
border-radius: var(--radius-lg); overflow: hidden;
border: 0.5px solid var(--separator);
}
.check-row {
display: flex; align-items: center; gap: 14px;
padding: 13px 16px;
border-bottom: 0.5px solid var(--separator);
cursor: pointer; transition: opacity 0.12s;
}
.check-row:last-child { border-bottom: none; }
.check-row:active { opacity: 0.7; }
.check-box {
width: 24px; height: 24px; border-radius: var(--radius-md);
border: 2px solid var(--separator); flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-size: 13px; transition: all 0.15s;
}
.check-box.done { background: var(--ios-green); border-color: var(--ios-green); }
.check-info { flex: 1; }
.check-title { font-size: 15px; font-weight: 500; }
.check-title.done { text-decoration: line-through; color: var(--label-secondary); }
.check-sub { font-size: 12px; color: var(--label-secondary); margin-top: 2px; }
.check-tag {
font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: var(--radius-sm);
}
.tag-critical { background: rgba(255,69,58,0.15); color: var(--ios-red); }
.tag-content { background: rgba(10,132,255,0.12); color: var(--ios-blue); }
.tag-tech { background: rgba(175,82,222,0.12); color: var(--ios-purple); }
.tag-marketing { background: rgba(255,159,10,0.12); color: var(--ios-orange); }
.tag-done { background: rgba(48,209,88,0.12); color: var(--ios-green); }
/* Channels */
.channels-grid { display: flex; flex-direction: column; gap: 10px; }
.channel-card {
background: var(--background-secondary);
border: 0.5px solid var(--separator);
border-radius: var(--radius-lg); padding: 16px;
display: flex; gap: 14px; align-items: flex-start;
}
.channel-icon { font-size: 28px; flex-shrink: 0; }
.channel-info { flex: 1; }
.channel-name { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
.channel-desc { font-size: 13px; color: var(--label-secondary); line-height: 1.5; margin-bottom: 8px; }
.channel-action {
display: inline-flex; align-items: center; gap: 5px;
padding: 7px 12px; border-radius: var(--radius-md);
font-size: 13px; font-weight: 600;
background: var(--fill-secondary); color: var(--label-primary);
border: none; cursor: pointer; transition: opacity 0.12s;
text-decoration: none;
}
.channel-action:active { opacity: 0.7; }
/* Content Calendar */
.calendar-card {
background: var(--background-secondary);
border-radius: var(--radius-lg); overflow: hidden;
border: 0.5px solid var(--separator);
}
.calendar-week {
border-bottom: 0.5px solid var(--separator);
}
.calendar-week:last-child { border-bottom: none; }
.calendar-week-header {
display: flex; align-items: center; gap: 10px;
padding: 14px 16px 10px;
}
.week-badge {
font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-md);
}
.week-1 { background: rgba(10,132,255,0.15); color: var(--ios-blue); }
.week-2 { background: rgba(175,82,222,0.15); color: var(--ios-purple); }
.week-launch { background: rgba(255,69,58,0.15); color: var(--ios-red); }
.week-title { font-size: 15px; font-weight: 600; }
.week-sub { font-size: 12px; color: var(--label-secondary); margin-top: 1px; }
.calendar-events { padding: 0 16px 14px; display: flex; flex-direction: column; gap: 8px; }
.cal-event {
display: flex; align-items: center; gap: 10px;
background: var(--fill-quaternary); border-radius: var(--radius-md); padding: 10px 12px;
}
.cal-date { font-size: 13px; font-weight: 600; color: var(--label-secondary); min-width: 40px; }
.cal-text { font-size: 14px; flex: 1; }
.cal-icon { font-size: 18px; }
/* LAUNCH DAY */
.launch-day-card {
margin: 0 16px 24px;
background: linear-gradient(135deg, rgba(255,69,58,0.12), rgba(255,159,10,0.08));
border: 0.5px solid rgba(255,69,58,0.25);
border-radius: var(--radius-lg); padding: 20px;
text-align: center;
}
.launch-day-icon { font-size: 48px; margin-bottom: 10px; }
.launch-day-title {
font-family: var(--font-display);
font-size: 24px; font-weight: 800; letter-spacing: -0.5px; margin-bottom: 6px;
color: var(--ios-red);
}
.launch-day-sub { font-size: 15px; color: var(--label-secondary); line-height: 1.5; }
/* Press release */
.press-card {
background: var(--background-secondary);
border: 0.5px solid var(--separator);
border-radius: var(--radius-lg); padding: 16px;
margin: 0 16px 24px;
}
.press-title { font-size: 17px; font-weight: 600; margin-bottom: 8px; }
.press-body { font-size: 14px; color: var(--label-secondary); line-height: 1.6; margin-bottom: 12px; }
.press-btn {
display: inline-flex; align-items: center; gap: 6px;
padding: 10px 16px; border-radius: var(--radius-md);
background: var(--ios-blue); color: #fff;
font-size: 14px; font-weight: 600;
border: none; cursor: pointer;
text-decoration: 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; }
}
</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>
<meta property="og:type" content="website">
<meta property="og:title" content="Launch Campaign — quiXzoom">
<meta property="og:description" content="quiXzoom — Earn per Mission. No Platform Fee.">
<meta property="og:url" content="https://www.quixzoom.com/launch-campaign.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 campaign — earn per approved photo 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="Launch Campaign — quiXzoom">
</head>
<body>
<h1 style="position:absolute;left:-9999px;">quiXzoom Launch Campaign</h1>
<!-- Nav -->
<div class="nav-bar">
<span class="nav-title">Launch Campaign</span>
<div class="nav-live"><span class="live-dot"></span>1 augusti 2026</div>
</div>
<!-- Countdown -->
<div class="countdown-hero">
<div class="countdown-title"><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> Countdown till lansering</div>
<div class="countdown-grid">
<div class="countdown-unit">
<div class="countdown-num" id="cd-days"></div>
<div class="countdown-label">Dagar</div>
</div>
<div class="countdown-unit">
<div class="countdown-num" id="cd-hours"></div>
<div class="countdown-label">Timmar</div>
</div>
<div class="countdown-unit">
<div class="countdown-num" id="cd-mins"></div>
<div class="countdown-label">Minuter</div>
</div>
<div class="countdown-unit">
<div class="countdown-num" id="cd-secs"></div>
<div class="countdown-label">Sekunder</div>
</div>
</div>
<div class="launch-date">Launch Day: <strong>1 augusti 2026 · 08:00 CET</strong></div>
</div>
<!-- Targets -->
<div class="target-row">
<div class="target-card">
<div class="target-icon"></div>
<div class="target-num" style="color:var(--ios-blue)">100</div>
<div class="target-label">Zoomers dag 1</div>
</div>
<div class="target-card">
<div class="target-icon"></div>
<div class="target-num" style="color:var(--ios-green)">1 000</div>
<div class="target-label">Uppdrag månad 1</div>
</div>
<div class="target-card">
<div class="target-icon"></div>
<div class="target-num" style="color:var(--ios-orange)">500k</div>
<div class="target-label">GMV månad 1 kr</div>
</div>
</div>
<!-- Pre-launch Checklist -->
<div class="section">
<div class="section-header">Pre-launch Checklist — <span id="check-count">0</span> / 20 klara</div>
<div class="checklist-card" id="checklist"></div>
</div>
<!-- Marketing Channels -->
<div class="section">
<div class="section-header">Marknadsföringskanaler</div>
<div class="channels-grid">
<div class="channel-card">
<div class="channel-icon"></div>
<div class="channel-info">
<div class="channel-name">LinkedIn</div>
<div class="channel-desc">Företagspost från Wavult Group + personlig post från Erik. Target: fastighetsägare, byggföretag, infrastrukturbolag.</div>
<a class="channel-action" href="https://linkedin.com/company/wavult" target="_blank"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 13V10L10 3L13 6L6 13H3Z" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 4L12 7" stroke="#666" stroke-width="1.5"/></svg> Öppna LinkedIn</a>
</div>
</div>
<div class="channel-card">
<div class="channel-icon"></div>
<div class="channel-info">
<div class="channel-name">Twitter / X Thread</div>
<div class="channel-desc">Lanserings-thread: "Vi bygger Uber för drönare i Sverige <span class="flag-se">SE</span>" — 8 tweets med bilder, stats och CTA till App Store.</div>
<button class="channel-action" onclick="copyTweet()"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="2" width="10" height="12" rx="1" stroke="#666" stroke-width="1.5"/><path d="M6 5H10M6 8H10M6 11H8" stroke="#666" stroke-width="1.5" stroke-linecap="round"/></svg> Kopiera launch tweet</button>
</div>
</div>
<div class="channel-card">
<div class="channel-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2L10 8L14 9L8 14L6 8L2 7L8 2Z" fill="#666"/></svg></div>
<div class="channel-info">
<div class="channel-name">Product Hunt</div>
<div class="channel-desc">Submit dag 1 (1 augusti). Mål: Top 5 Product of the Day. Mobilisera team för upvotes på morgonen.</div>
<a class="channel-action" href="https://producthunt.com/posts/new" target="_blank"> Submit to PH</a>
</div>
</div>
<div class="channel-card">
<div class="channel-icon"></div>
<div class="channel-info">
<div class="channel-name">Press Release</div>
<div class="channel-desc">Skicka till Breakit, Ny Teknik, DI Digital. Embargo lift: 1 augusti 08:00. Distribution: TT Nyhetsbyrån + direkt kontakt.</div>
<button class="channel-action" onclick="showPR()"> Visa pressrelease</button>
</div>
</div>
</div>
</div>
<!-- LAUNCH DAY Card -->
<div class="launch-day-card">
<div class="launch-day-icon"></div>
<div class="launch-day-title">LAUNCH DAY — 1 augusti</div>
<div class="launch-day-sub">08:00 — App Store live<br>08:30 — LinkedIn + Twitter posts<br>09:00 — Product Hunt live<br>10:00 — Press release distribution<br>12:00 — Status check: zoomers onboardade<br>18:00 — End of day report</div>
</div>
<!-- Content Calendar -->
<div class="section">
<div class="section-header">Content Calendar — augusti 2026</div>
<div class="calendar-card">
<div class="calendar-week">
<div class="calendar-week-header">
<div>
<span class="week-badge week-1">VECKA 1</span>
<div class="week-title" style="margin-top:4px">Teaser Campaign</div>
<div class="week-sub">17 juni · Bygga hype</div>
</div>
</div>
<div class="calendar-events">
<div class="cal-event">
<span class="cal-date">Jun 1</span>
<span class="cal-text">LinkedIn: "Något är på väg i Sverige... <span class="flag-se">SE</span><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2V6M4 4H12" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M2 8H6L8 6L10 8H14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 8V12H10V8" stroke="#666" stroke-width="1.5"/></svg>"</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 3</span>
<span class="cal-text">Twitter: Bakom kulisserna — drönare i aktion</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 5</span>
<span class="cal-text">Waitlist open: "Be first Zoomer in Sweden"</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 7</span>
<span class="cal-text">Instagram Reel: Drönarvideo från pilot-uppdrag</span>
<span class="cal-icon"></span>
</div>
</div>
</div>
<div class="calendar-week">
<div class="calendar-week-header">
<div>
<span class="week-badge week-2">VECKA 2</span>
<div class="week-title" style="margin-top:4px">Beta Tester Stories</div>
<div class="week-sub">814 juni · Social proof</div>
</div>
</div>
<div class="calendar-events">
<div class="cal-event">
<span class="cal-date">Jun 8</span>
<span class="cal-text"> Inlämning App Store (deadline)</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 9</span>
<span class="cal-text">Beta zoomer-berättelse #1: "Mitt första uppdrag"</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 11</span>
<span class="cal-text">LinkedIn: "Varför vi bygger quiXzoom" — långpost</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 13</span>
<span class="cal-text">Countdown: "2 dagar kvar — är du redo?"</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">Jun 14</span>
<span class="cal-text">Press kit skickat · Media briefing</span>
<span class="cal-icon"></span>
</div>
</div>
</div>
<div class="calendar-week">
<div class="calendar-week-header">
<div>
<span class="week-badge week-launch"><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> LAUNCH DAY</span>
<div class="week-title" style="margin-top:4px">1 augusti 2026</div>
<div class="week-sub">All hands on deck</div>
</div>
</div>
<div class="calendar-events">
<div class="cal-event">
<span class="cal-date">08:00</span>
<span class="cal-text">App Store LIVE </span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">08:30</span>
<span class="cal-text">LinkedIn + Twitter launch posts</span>
<span class="cal-icon"></span>
</div>
<div class="cal-event">
<span class="cal-date">09:00</span>
<span class="cal-text">Product Hunt submission</span>
<span class="cal-icon"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2L10 8L14 9L8 14L6 8L2 7L8 2Z" fill="#666"/></svg></span>
</div>
<div class="cal-event">
<span class="cal-date">10:00</span>
<span class="cal-text">Press release distribution (TT, Breakit)</span>
<span class="cal-icon"></span>
</div>
</div>
</div>
</div>
</div>
<div style="height:20px"></div>
<!-- Press Release Modal -->
<div id="pr-modal" style="display:none;position:fixed;inset:0;z-index:9999;background: rgba(242,242,247,0.8);backdrop-filter:blur(8px);overflow-y:auto;padding:20px">
<div style="background:var(--background-secondary);border-radius: var(--radius-xl);max-width:600px;margin:0 auto;padding:24px;border:0.5px solid var(--separator)">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<div style="font-size:18px;font-weight:700"> Pressrelease</div>
<button onclick="hidePR()" style="background:var(--fill-secondary);border:none;border-radius: var(--radius-full);width:32px;height:32px;font-size:18px;cursor:pointer;color:var(--label-primary)">×</button>
</div>
<div style="font-size:11px;color:var(--label-secondary);margin-bottom:16px;text-transform:uppercase;letter-spacing:0.5px">EMBARGO: 1 augusti 2026 · 08:00 CET</div>
<div style="font-size:18px;font-weight:700;margin-bottom:12px;line-height:1.4">quiXzoom lanserar i Sverige — den första drönargig-plattformen för den svenska marknaden</div>
<div style="font-size:14px;color:var(--label-secondary);line-height:1.7;margin-bottom:16px">
STOCKHOLM, 1 augusti 2026 — Wavult Group lanserar idag quiXzoom, en ny plattform som kopplar samman drönarpilöter (Zoomers) med företag och fastighetsägare som behöver drönartjänster på begäran.<br><br>
"Vi gör drönartjänster lika enkla att beställa som en taxi", säger Erik Svensson, Chairman of the Board vid Wavult Group. "quiXzoom är den infrastruktur som branschen har saknat."<br><br>
Plattformen finns tillgänglig från idag i hela Sverige via App Store. Zoomer-registrering är öppen för certifierade drönarpilöter.
</div>
<div style="font-size:12px;color:var(--label-tertiary);margin-bottom:16px">Kontakt: erik@hypbit.com · +46709123223</div>
<button onclick="copyPR()" style="background:var(--ios-blue);color:#fff;border:none;border-radius: var(--radius-md);padding:12px 20px;font-size:14px;font-weight:600;cursor:pointer;width:100%"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="2" width="10" height="12" rx="1" stroke="#666" stroke-width="1.5"/><path d="M6 5H10M6 8H10M6 11H8" stroke="#666" stroke-width="1.5" stroke-linecap="round"/></svg> Kopiera pressrelease</button>
</div>
</div>
<script>
// Countdown
const LAUNCH = new Date('2026-06-15T06:00:00Z'); // 08:00 CET = 06:00 UTC
function updateCountdown() {
const now = new Date();
const diff = LAUNCH - now;
if (diff <= 0) {
document.getElementById('cd-days').textContent = '0';
document.getElementById('cd-hours').textContent = '0';
document.getElementById('cd-mins').textContent = '0';
document.getElementById('cd-secs').textContent = '0';
return;
}
const d = Math.floor(diff / 86400000);
const h = Math.floor((diff % 86400000) / 3600000);
const m = Math.floor((diff % 3600000) / 60000);
const s = Math.floor((diff % 60000) / 1000);
document.getElementById('cd-days').textContent = String(d).padStart(2,'0');
document.getElementById('cd-hours').textContent = String(h).padStart(2,'0');
document.getElementById('cd-mins').textContent = String(m).padStart(2,'0');
document.getElementById('cd-secs').textContent = String(s).padStart(2,'0');
}
updateCountdown();
setInterval(updateCountdown, 1000);
// Checklist
const checks = [
{ text:'SwiftUI native iOS-app klar', sub:'Bundle ID: se.wavult.quixzoom', tag:'critical', done: false },
{ text:'App Store Connect konto aktivt', sub:'erik@hypbit.com · $99/år', tag:'critical', done: false },
{ text:'Bundle ID registrerat (se.wavult.quixzoom)', sub:'Apple Developer Portal', tag:'tech', done: false },
{ text:'Screenshots klara (3 storlekar)', sub:'6.7", 6.1", iPad 12.9"', tag:'critical', done: false },
{ text:'App metadata (namn, kategori, keywords)', sub:'Business category', tag:'content', done: false },
{ text:'App Review information', sub:'Demo-konto + reviewer notes', tag:'tech', done: false },
{ text:'Privacy Policy live', sub:'quixzoom.com/privacy', tag:'done', done: true },
{ text:'Support URL live', sub:'quixzoom.com/support', tag:'done', done: true },
{ text:'Terms of Service live', sub:'quixzoom.com/terms', tag:'done', done: true },
{ text:'Zoomer-avtal färdigt', sub:'Uppdragstagares villkor', tag:'critical', done: false },
{ text:'DAC7 rapportering klar', sub:'EU-plattformsdirektiv', tag:'critical', done: false },
{ text:'Betalningsinfrastruktur testad', sub:'Stripe payouts live', tag:'tech', done: false },
{ text:'KYC-flöde verifierat end-to-end', sub:'egen KYC-pipeline', tag:'tech', done: false },
{ text:'Product Hunt draft förberedd', sub:'Bilder, tagline, hunters', tag:'marketing', done: false },
{ text:'LinkedIn-post skriven', sub:'Företag + personlig', tag:'content', done: false },
{ text:'Twitter/X thread skriven', sub:'8-tweet launch thread', tag:'content', done: false },
{ text:'Pressrelease skriven + distribuerad', sub:'Breakit, Ny Teknik, DI Digital', tag:'content', done: false },
{ text:'Media kit preparerat', sub:'Loggor, screenshots, bilder', tag:'marketing', done: false },
{ text:'Teaser content publicerat (vecka 1)', sub:'Jun 17 · Build hype', tag:'marketing', done: false },
{ text:'Launch Day operations plan', sub:'Roller, ansvar, kommunikation', tag:'critical', done: false },
];
const savedChecks = JSON.parse(localStorage.getItem('qz_launch_checks') || '{}');
checks.forEach((c, i) => { if (savedChecks[i]) c.done = true; });
function tagLabel(t) {
return { critical:' Kritisk', content:' Content', tech:'🟣 Tech', marketing:'🟠 Marketing', done:'<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> Klar' }[t] || t;
}
function tagClass(t) {
return { critical:'tag-critical', content:'tag-content', tech:'tag-tech', marketing:'tag-marketing', done:'tag-done' }[t] || '';
}
function renderChecklist() {
const el = document.getElementById('checklist');
const doneCount = checks.filter(c=>c.done).length;
document.getElementById('check-count').textContent = doneCount;
el.innerHTML = checks.map((c,i) => `
<div class="check-row" onclick="toggleCheck(${i})">
<div class="check-box ${c.done?'done':''}">${c.done?'<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>':''}</div>
<div class="check-info">
<div class="check-title ${c.done?'done':''}">${c.text}</div>
<div class="check-sub">${c.sub}</div>
</div>
<span class="check-tag ${tagClass(c.tag)}">${tagLabel(c.tag)}</span>
</div>
`).join('');
}
function toggleCheck(i) {
checks[i].done = !checks[i].done;
const savedChecks = JSON.parse(localStorage.getItem('qz_launch_checks') || '{}');
savedChecks[i] = checks[i].done;
localStorage.setItem('qz_launch_checks', JSON.stringify(savedChecks));
renderChecklist();
}
renderChecklist();
// Tweet
function copyTweet() {
const tweet = `Vi lanserar quiXzoom idag <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2V6M4 4H12" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M2 8H6L8 6L10 8H14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 8V12H10V8" stroke="#666" stroke-width="1.5"/></svg><span class="flag-se">SE</span>\n\nSveriges första drönargig-plattform.\n\nZoomers = certifierade drönarpilöter som tar uppdrag när det passar dem.\n\nFasad-scanning, takinspektion, infrastruktur — på 24h.\n\nLadda ner nu \nhttps://quixzoom.com/app`;
navigator.clipboard?.writeText(tweet).then(() => alert('Tweet kopierad!')).catch(() => alert(tweet));
}
// Press release modal
function showPR() { document.getElementById('pr-modal').style.display = 'block'; }
function hidePR() { document.getElementById('pr-modal').style.display = 'none'; }
function copyPR() {
const pr = `PRESSRELEASE · EMBARGO: 1 augusti 2026 08:00 CET\n\nquiXzoom lanserar i Sverige — den första drönargig-plattformen\n\nSTOCKHOLM, 1 augusti 2026 — Wavult Group lanserar idag quiXzoom, en ny plattform som kopplar samman drönarpilöter (Zoomers) med företag och fastighetsägare som behöver drönartjänster på begäran.\n\n"Vi gör drönartjänster lika enkla att beställa som en taxi", säger Erik Svensson, Chairman of the Board vid Wavult Group.\n\nKontakt: erik@hypbit.com | +46709123223`;
navigator.clipboard?.writeText(pr).then(() => alert('Pressrelease kopierad!')).catch(() => alert('Kopiering misslyckades'));
}
</script>
</body>
</html>