trekmap-preorder/index.html

446 lines
33 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="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>TrekMap — Wish It. Time It. Make It Happen.</title>
<meta name="description" content="A travel bucket list that lives on a world map — and an LED map on your wall that glows with everywhere you've been and everywhere you're going.">
<meta name="theme-color" content="#001F3F">
<meta property="og:title" content="TrekMap">
<meta property="og:description" content="A travel bucket list you can hang on the wall.">
<style>
:root{
--midnight:#001F3F; --nightsky:#0B192C; --deep:#00162e;
--gold:#E6B800; --gold-soft:#f0cf4d; --mahogany:#6F4E37; --jungle:#1B4332;
--ink:#F4F1EA; --muted:#8FA3B8; --line:rgba(230,184,0,.16);
--max:1120px;
}
*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
margin:0; background:var(--midnight); color:var(--ink);
font:16px/1.65 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-webkit-font-smoothing:antialiased; overflow-x:hidden;
}
h1,h2,h3{line-height:1.08; letter-spacing:-.025em; margin:0; font-weight:700}
p{margin:0}
a{color:var(--gold); text-decoration:none}
a:focus-visible,button:focus-visible,summary:focus-visible{outline:2px solid var(--gold); outline-offset:3px; border-radius:6px}
.wrap{max-width:var(--max); margin:0 auto; padding:0 24px}
.eyebrow{font-size:.72rem; letter-spacing:.18em; text-transform:uppercase; color:var(--gold); font-weight:700}
.lede{color:var(--muted); font-size:1.08rem; max-width:34em}
/* ── nav ── */
header{position:fixed; inset:0 0 auto; z-index:50; backdrop-filter:blur(12px);
background:rgba(0,31,63,.72); border-bottom:1px solid rgba(255,255,255,.06)}
nav{display:flex; align-items:center; gap:28px; max-width:var(--max); margin:0 auto; padding:14px 24px}
.brand{display:flex; align-items:center; gap:10px; font-weight:800; letter-spacing:-.02em; font-size:1.05rem}
.brand i{width:10px; height:10px; border-radius:50%; background:var(--gold); box-shadow:0 0 12px var(--gold); display:block}
nav .links{display:flex; gap:24px; margin-left:auto; font-size:.9rem; color:var(--muted)}
nav .links a:hover{color:var(--ink)}
.btn{display:inline-block; background:var(--gold); color:#00162e; font-weight:700;
padding:11px 20px; border-radius:10px; border:0; cursor:pointer; font-size:.92rem;
transition:transform .15s ease, box-shadow .2s ease}
.btn:hover{transform:translateY(-1px); box-shadow:0 8px 26px rgba(230,184,0,.28)}
.btn.ghost{background:transparent; color:var(--ink); border:1px solid rgba(255,255,255,.18)}
.btn.ghost:hover{border-color:var(--gold); color:var(--gold); box-shadow:none}
/* ── hero ── */
.hero{position:relative; min-height:100svh; display:grid; align-items:center; padding:120px 0 80px; isolation:isolate}
#led{position:absolute; inset:0; width:100%; height:100%; z-index:-1; opacity:.95}
.hero::after{content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
background:radial-gradient(120% 90% at 18% 45%, rgba(0,22,46,.94) 0%, rgba(0,22,46,.72) 38%, transparent 72%)}
.hero-inner{max-width:38rem}
.hero h1{font-size:clamp(2.6rem,6.4vw,4.4rem); margin:18px 0 20px}
.hero h1 em{font-style:normal; color:var(--gold); display:block}
.cta-row{display:flex; gap:12px; flex-wrap:wrap; margin-top:32px}
.hint{margin-top:26px; font-size:.82rem; color:#5f7590; display:flex; align-items:center; gap:8px}
.hint b{color:var(--gold); font-weight:600}
/* ── sections ── */
section{padding:104px 0; border-top:1px solid rgba(255,255,255,.05)}
.sec-head{max-width:40rem; margin-bottom:52px}
.sec-head h2{font-size:clamp(1.9rem,4vw,2.7rem); margin:14px 0 14px}
.steps{display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:20px}
.step{background:linear-gradient(180deg,var(--nightsky),rgba(11,25,44,.4));
border:1px solid var(--line); border-radius:16px; padding:28px; position:relative; overflow:hidden}
.step .n{font-size:.72rem; letter-spacing:.16em; color:var(--mahogany); font-weight:800}
.step h3{font-size:1.22rem; margin:10px 0 10px; color:var(--gold)}
.step p{color:var(--muted); font-size:.95rem}
.step::after{content:""; position:absolute; right:-40px; top:-40px; width:120px; height:120px;
background:radial-gradient(circle,rgba(230,184,0,.14),transparent 68%)}
/* ── pipeline ── */
.pipe{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; margin-top:8px}
.pipe div{background:var(--deep); border:1px solid rgba(255,255,255,.07); border-radius:12px;
padding:18px 16px; font-size:.86rem; color:var(--muted)}
.pipe div b{display:block; color:var(--ink); font-size:.95rem; margin-bottom:4px}
.pipe div span{color:var(--gold); font-size:.7rem; letter-spacing:.14em; font-weight:800}
/* ── hardware ── */
.skus{display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:20px; align-items:start}
.sku{background:var(--nightsky); border:1px solid var(--line); border-radius:18px; padding:28px; position:relative}
.sku.featured{border-color:var(--gold); box-shadow:0 0 0 1px var(--gold), 0 24px 60px -30px rgba(230,184,0,.5)}
.sku .tag{position:absolute; top:-11px; left:28px; background:var(--gold); color:#00162e;
font-size:.66rem; font-weight:800; letter-spacing:.12em; padding:4px 10px; border-radius:100px}
.sku h3{font-size:1.3rem}
.sku .price{font-size:2.4rem; font-weight:800; margin:12px 0 2px; letter-spacing:-.03em}
.sku .price small{font-size:.8rem; font-weight:600; color:var(--muted); letter-spacing:0}
.sku p{color:var(--muted); font-size:.92rem; margin:12px 0 18px; min-height:3.2em}
.sku ul{list-style:none; padding:0; margin:0 0 22px; font-size:.88rem; color:#B7C6D6}
.sku li{padding:7px 0 7px 22px; position:relative; border-top:1px solid rgba(255,255,255,.05)}
.sku li::before{content:"◆"; position:absolute; left:0; color:var(--gold); font-size:.62rem; top:9px}
.mini{display:grid; grid-template-columns:repeat(14,1fr); gap:3px; margin-bottom:20px}
.mini i{aspect-ratio:1; border-radius:50%; background:rgba(255,255,255,.07)}
.mini i.on{background:var(--gold); box-shadow:0 0 7px rgba(230,184,0,.85)}
.mini i.dim{background:rgba(230,184,0,.32)}
/* ── specs ── */
.specs{display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:1px; background:rgba(255,255,255,.07);
border:1px solid rgba(255,255,255,.07); border-radius:16px; overflow:hidden}
.specs div{background:var(--midnight); padding:26px 22px}
.specs b{display:block; font-size:1.7rem; font-weight:800; color:var(--gold); letter-spacing:-.02em}
.specs span{font-size:.84rem; color:var(--muted)}
/* ── faq ── */
details{border-bottom:1px solid rgba(255,255,255,.08); padding:18px 0}
summary{cursor:pointer; font-weight:600; list-style:none; display:flex; justify-content:space-between; gap:16px; align-items:center}
summary::-webkit-details-marker{display:none}
summary::after{content:"+"; color:var(--gold); font-size:1.3rem; line-height:1; flex:none}
details[open] summary::after{content:"–"}
details p{color:var(--muted); font-size:.94rem; margin-top:12px; max-width:52em}
/* ── final cta ── */
.final{text-align:center; background:
radial-gradient(80% 120% at 50% 0%, rgba(230,184,0,.1), transparent 62%), var(--deep)}
.final h2{font-size:clamp(2rem,4.6vw,3rem); margin-bottom:16px}
.final .lede{margin:0 auto 30px}
form.reserve{display:flex; gap:10px; justify-content:center; flex-wrap:wrap; max-width:30rem; margin:0 auto}
form.reserve input{flex:1 1 220px; background:var(--nightsky); border:1px solid rgba(255,255,255,.16);
color:var(--ink); padding:13px 16px; border-radius:10px; font-size:.98rem; font-family:inherit}
form.reserve input::placeholder{color:#5f7590}
.said{color:var(--gold); font-weight:600}
footer{padding:44px 0; border-top:1px solid rgba(255,255,255,.06); color:#5f7590; font-size:.86rem}
.foot{display:flex; gap:18px; flex-wrap:wrap; align-items:center}
.foot .sp{margin-left:auto}
/* ── reveal ── */
.rev{opacity:0; transform:translateY(18px); transition:opacity .7s ease, transform .7s ease}
.rev.in{opacity:1; transform:none}
@media (prefers-reduced-motion:reduce){
.rev{opacity:1; transform:none; transition:none}
html{scroll-behavior:auto}
}
@media (max-width:720px){
nav .links{display:none}
section{padding:76px 0}
.sku p{min-height:0}
}
</style>
</head>
<body>
<header>
<nav>
<span class="brand"><i></i>TrekMap</span>
<span class="links">
<a href="#loop">The loop</a>
<a href="#ingest">Reel ingest</a>
<a href="#hardware">Hardware</a>
<a href="#faq">FAQ</a>
</span>
<a class="btn" href="#reserve">Reserve</a>
</nav>
</header>
<main>
<section class="hero">
<canvas id="led" aria-hidden="true"></canvas>
<div class="wrap hero-inner">
<span class="eyebrow">Pre-order &middot; first production run</span>
<h1>Hang your travels <em>on the wall.</em></h1>
<p class="lede">TrekMap is a travel bucket list that lives on a world map &mdash; and an LED map
that glows with everywhere you&rsquo;ve been and everywhere you&rsquo;re going. One list, two places:
your phone and your wall.</p>
<div class="cta-row">
<a class="btn" href="#reserve">Reserve a unit</a>
<a class="btn ghost" href="https://trekmap.co">Open the app</a>
</div>
<p class="hint"><b>&#9679;</b> bright = been there &nbsp;&middot;&nbsp; <b style="opacity:.45">&#9679;</b> dim = on the list &nbsp;&middot;&nbsp; move your cursor across the map</p>
</div>
</section>
<section id="loop">
<div class="wrap">
<div class="sec-head rev">
<span class="eyebrow">How it works</span>
<h2>Wish it. Time it. Make it happen.</h2>
<p class="lede">Most travel apps are a log of where you&rsquo;ve been. TrekMap is built around
the part that comes first &mdash; wanting to go.</p>
</div>
<div class="steps">
<article class="step rev"><span class="n">01 / WISH IT</span><h3>Save it in one tap</h3>
<p>Share an Instagram or TikTok reel straight from your phone. TrekMap watches the video,
reads the signs and the audio, works out the actual place, and files it with a cover photo.</p></article>
<article class="step rev"><span class="n">02 / TIME IT</span><h3>See it build up</h3>
<p>Countries glow by how badly you want to go. Explorer Mode splits 57 countries into
states, prefectures and nations, so progress is honest instead of a flag count.</p></article>
<article class="step rev"><span class="n">03 / MAKE IT HAPPEN</span><h3>Go, and light it up</h3>
<p>Flight-price thresholds nudge you when it&rsquo;s time to book. Log the trip and the
country turns bright &mdash; in the app, and on the map on your wall.</p></article>
</div>
</div>
</section>
<section id="ingest">
<div class="wrap">
<div class="sec-head rev">
<span class="eyebrow">The part nobody else does</span>
<h2>Share a reel. Get a pin.</h2>
<p class="lede">A 20-second clip of a restaurant with no caption and no tag still becomes a
real, mapped, searchable place.</p>
</div>
<div class="pipe rev">
<div><span>01</span><b>Download</b>Pulls the video and audio from the share sheet.</div>
<div><span>02</span><b>Scene detect</b>Splits it into frames worth reading.</div>
<div><span>03</span><b>Read it</b>Vision model reads signage; Whisper reads the voiceover.</div>
<div><span>04</span><b>Decide</b>Picks the actual venue, drops "a city over a close-up".</div>
<div><span>05</span><b>Enrich</b>Captions, embeds and geocodes it, then finds a cover photo.</div>
</div>
<p class="lede rev" style="margin-top:26px">Every saved spot is embedded as a vector, so you can
search your own list by vibe &mdash; &ldquo;quiet places near water&rdquo; &mdash; not just by name.</p>
</div>
</section>
<section id="hardware">
<div class="wrap">
<div class="sec-head rev">
<span class="eyebrow">The hardware line</span>
<h2>Your list, in the room with you.</h2>
<p class="lede">Individually addressable LEDs, one per country or region, synced live from the
same account. Wishlist glows dim; visited burns bright.</p>
</div>
<div class="skus">
<article class="sku rev">
<div class="mini" data-mini="mini" aria-hidden="true"></div>
<h3>TrekMap Mini</h3>
<div class="price">$99 <small>pre-order</small></div>
<p>Picture-frame sized. Sits on a desk or a workbench and still shows the whole picture.</p>
<ul><li>Continental US, Canada, Mexico</li><li>One LED per state or region</li><li>WiFi or USB sync</li></ul>
<a class="btn ghost" href="#reserve">Reserve &mdash; $99</a>
</article>
<article class="sku featured rev">
<span class="tag">MOST POPULAR</span>
<div class="mini" data-mini="wall" aria-hidden="true"></div>
<h3>TrekMap</h3>
<div class="price">$199 <small>pre-order</small></div>
<p>The wall map. Laser-cut cell geometry, one lit cell per state, province and region.</p>
<ul><li>US, Canada, Mexico + islands</li><li>Laser-cut / 3D-printed cells</li><li>Live sync from the app</li></ul>
<a class="btn" href="#reserve">Reserve &mdash; $199</a>
</article>
<article class="sku rev">
<div class="mini" data-mini="globe" aria-hidden="true"></div>
<h3>TrekGlobe</h3>
<div class="price">$399 <small>pre-order</small></div>
<p>A full world globe on a walnut base with a brass meridian ring. Every country addressable.</p>
<ul><li>Per-country LEDs, whole planet</li><li>Walnut base, brass meridian</li><li>Librarian&rsquo;s Midnight glass</li></ul>
<a class="btn ghost" href="#reserve">Reserve &mdash; $399</a>
</article>
</div>
<p class="hint rev" style="margin-top:28px">None of the three have shipped yet. Reserving costs
nothing today and holds your place in the first run at the launch price.</p>
</div>
</section>
<section>
<div class="wrap">
<div class="specs rev">
<div><b>57</b><span>Countries split to region level</span></div>
<div><b>3</b><span>Hardware form factors</span></div>
<div><b>ESP32-S3</b><span>Firmware on every unit</span></div>
<div><b>Zero</b><span>Paid map APIs &mdash; OpenStreetMap only</span></div>
</div>
</div>
</section>
<section id="faq">
<div class="wrap" style="max-width:52rem">
<div class="sec-head rev"><span class="eyebrow">Questions</span><h2>Straight answers.</h2></div>
<div class="rev">
<details open><summary>Is the hardware shipping?</summary>
<p>Not yet &mdash; all three units are pre-launch. Reserving puts you in the first production
run at the launch price, and you&rsquo;re not charged until it ships.</p></details>
<details><summary>Does the app work without buying hardware?</summary>
<p>Yes. The app at trekmap.co is the product; the LED map is a physical view of the same
data. Plenty of people will only ever use the app.</p></details>
<details><summary>Who can see my travel list?</summary>
<p>Only you, and friends you accept. Boards are private by default. You can publish an
individual spot to a public feed if you want to share one &mdash; notes, reminders and price
thresholds never leave your account.</p></details>
<details><summary>What if a reel is ambiguous?</summary>
<p>It gets dropped rather than guessed. A city-wide pin attached to a close-up of a plate
isn&rsquo;t useful, so the pipeline throws those away instead of cluttering your map.</p></details>
<details><summary>How does the map know what I&rsquo;ve visited?</summary>
<p>Your passport is a separate list from your wishes, so marking somewhere visited doesn&rsquo;t
create an empty wish or change the glow. The hardware polls the same account and lights up to match.</p></details>
</div>
</div>
</section>
<section class="final" id="reserve">
<div class="wrap">
<span class="eyebrow">Pre-order</span>
<h2 class="rev">Get in the first run.</h2>
<p class="lede rev">Leave an email. We&rsquo;ll tell you the moment the run opens &mdash; no charge,
no newsletter, no other use for the address.</p>
<form class="reserve rev" id="reserveForm" novalidate>
<input type="email" name="email" placeholder="you@example.com" aria-label="Email address" required>
<button class="btn" type="submit">Reserve my unit</button>
</form>
<p class="hint rev" style="justify-content:center; margin-top:18px">
Or just email <a href="mailto:hello.trekmap@corben.world">hello.trekmap@corben.world</a></p>
</div>
</section>
</main>
<footer>
<div class="wrap foot">
<span class="brand" style="font-size:.95rem"><i></i>TrekMap</span>
<span>A travel bucket list you can hang on the wall.</span>
<span class="sp"><a href="https://trekmap.co">trekmap.co</a></span>
</div>
</footer>
<script>window.__TREKMAP_MASK__="000000000000000000000000000000001000111011100011111111111111111111100000000000001111000000000000000000000000000000011110000000000000000000000000000000\n000000000000000000000000011100000001001111100111111111111111111111000000000000000100000000000000000000010000000000000111000000000000000000000000000000\n000000000000000000000000000110000001011111000000000111111111111111100000000000000000000000000000000100000000000111111111110000000000000000000000000000\n000000000000000000000001101011101111001110100000000011111111111110000000000000000000000000000000010000001000011111111111111111111000001000000000000000\n000000001110000000000000000011110001101111111110000010111111111101000000000000000000111100000000000000011011111111111111111111111111111111111100000000\n100000111111111111111111111000100000100110001110000001111111101000000000000000000111111111100100001111101111111111111111111111111111111111111111111111\n111100101111111111111111111111111111111100001111100001111111100001000000000000001111111110110111111111110111111111111111111111111111111111111111111111\n000000001111111111111111111111111111110110001111000000111100000000111000000000011111011111011111111111111111111111111111111111111111111111111111111110\n000000111111111111111111111111111111000000111001000000111000000000000000000001111100111111111111111111111111111111111111111111111111111111111111111100\n000001111110100111111111111111111111000000011100000000001000000000000000001000111110100111111111111111111111111111111111111111111111111111100011000000\n000000000110000000011111111111111111000000011111100000000000000000000000000000001100011111111111111111111111111111111111111111111111110000000110000000\n000000001000000000011111111111111111111000011111100000000000000000000000010000101000111111111111111111111111111111111111111111111111000000001110000000\n000001000000000000000111111111111111111110111111111000000000000000000001001000011111111111111111111111111111111111111111111111111111001000001100000000\n110000000000000000000011111111111111111110111111111100000000000000000001011001111111111111111111111111111111111111111111111111111111111000001000000000\n000000000000000000000011111111111111111111111110100100000000000000000000000111111111111111111111111111111111111111111111111111111111111000000000000000\n000000000000000000000001111111111111111111111111000000000000000000000000001111111111111111111111111111111111111111111111111111111111100000000000000000\n000000000000000000000001111111111111111111111111100000000000000000000000000111110111111001011110011111111111111111111111111111111111000000000000000000\n000000000000000000000001111111111111111111111100000000000000000000000000111111011011111000001110111111111111111111111111111111111110001100000000000000\n000000000000000000000001111111111111111111111100000000000000000000000001111100001101111011001110001111111111111111111111111111111000000000000000000000\n000000000000000000000001111111111111111111110000000000000000000000000001111000100000101111111111011111111111111111111111111110010000010000000000000000\n000000000000000000000000111111111111111111100000000000000000000000000001110000000000111111111111011111111111111111111111111111001000010000000000000000\n000000000000000000000000011111111111111111100000000000000000000000000000111111110000010000111111111111111111111111111111111110001011100000000000000000\n000000000000000000000000001111111111111111000000000000000000000000000001111111110000000000111111111111111111111111111111111110000100000000000000000000\n000000000000000000000000000011111111111110000000000000000000000000000001111111111101111111111111111111111111111111111111111111000000000000000000000000\n000000000000000000000000000111111110000000000000000000000000000000000011111111111111111110111110111111111111111111111111111111000000000000000000000000\n000000000000000000000000000011111100000001100000000000000000000000000111111111111111111110111111000111111111111111111111111110000000000000000000000000\n000000000000000000000000000010111100000000100000000000000000000000000111111111111111111111011111001000011111111111111111111101000000000000000000000000\n000000000000000000000000000000011100000001000000000000000000000000001111111111111111111111011111111100001111111111111111110000000000000000000000000000\n000000000000000000000000000000011110011000010000000000000000000000001111111111111111111111001111111100000111111000111110000000000000000000000000000000\n000000000000000000000000000000001111110000101001000000000000000000001111111111111111111111101111111000000111110000111110100001000000000000000000000000\n000000000000000000000000000000000010110000000000000000000000000001001111111111111111111111100111100000000011100000101111000001000000000000000000000000\n000000000000000000000000000000000000011100000000000000000000000000001111111111111111111111110110000000000011000000001111000001000000000000000000000000\n000000000000000000000000000000000000000100000000000000000000000000001111111111111111111111111000000000000011000000001011100000000000000000000000000000\n000000000000000000000000000000000000000100001111100000000000000000000111111111111111111111111111000000000001000000000000000010100000000000000000000000\n000000000000000000000000000000000000000001111111110000000000000000000011111111111111111111111111000000000000100000001000000000110000000000000000000000\n000000000000000000000000000000000000000000011111111100000000000000000001111001111111111111111110000000000000000000000100000100000000000000000000000000\n000000000000000000000000000000000000000000011111111111000000000000000000000000011111111111111110000000000000000000010100001100000000000000000000000000\n000000000000000000000000000000000000000000111111111111000000000000000000000000011111111111111100000000000000000000001000111100000000000000000000000000\n000000000000000000000000000000000000000001111111111111100000000000000000000000011111111111111000000000000000000000000110111100000000000000000000000000\n000000000000000000000000000000000000000001111111111111110000000000000000000000011111111111110000000000000000000000000110011001000010110000000000000000\n000000000000000000000000000000000000000001111111111111111110000000000000000000001111111111100000000000000000000000000010000000000000111100100000000000\n000000000000000000000000000000000000000000111111111111111111000000000000000000001111111111100000000000000000000000000001010000000000011100000000000000\n000000000000000000000000000000000000000000111111111111111111000000000000000000001111111111100000000000000000000000000000000001010000001010000000000000\n000000000000000000000000000000000000000000011111111111111111000000000000000000000111111111110000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000011111111111111110000000000000000000001111111111110001000000000000000000000000000000000111001000000000000000\n000000000000000000000000000000000000000000001111111111111110000000000000000000001111111111110001000000000000000000000000000000011111001100000000100000\n000000000000000000000000000000000000000000000111111111111110000000000000000000001111111111100111000000000000000000000000000000011111101100000000000000\n000000000000000000000000000000000000000000000011111111111100000000000000000000001111111111000110000000000000000000000000000000111111111100000000000000\n000000000000000000000000000000000000000000000011111111111100000000000000000000000111111111000110000000000000000000000000000111111111111110000000000000\n000000000000000000000000000000000000000000000011111111110000000000000000000000000111111111000110000000000000000000000000001111111111111111000000000000\n000000000000000000000000000000000000000000000011111111100000000000000000000000000111111110000000000000000000000000000000000111111111111111100000000000\n000000000000000000000000000000000000000000000111111111100000000000000000000000000111111110000000000000000000000000000000000111111111111111100000000000\n000000000000000000000000000000000000000000000111111111000000000000000000000000000011111100000000000000000000000000000000000111111111111111100000000000\n000000000000000000000000000000000000000000000111111110000000000000000000000000000001111000000000000000000000000000000000000111111011111111100000000000\n000000000000000000000000000000000000000000000111111110000000000000000000000000000001110000000000000000000000000000000000000110000001111111000000000000\n000000000000000000000000000000000000000000000111111000000000000000000000000000000000000000000000000000000000000000000000000000000000011111000000000100\n000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000010\n000000000000000000000000000000000000000000001111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010\n000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000\n000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000\n000000000000000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000\n000000000000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";</script>
<script>
(function(){
"use strict";
var reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ── scroll reveal ─────────────────────────────────────────────── */
var revs = document.querySelectorAll(".rev");
if ("IntersectionObserver" in window && !reduce){
var io = new IntersectionObserver(function(es){
es.forEach(function(e,i){
if(e.isIntersecting){ setTimeout(function(){ e.target.classList.add("in"); }, i*70); io.unobserve(e.target); }
});
},{threshold:.14, rootMargin:"0px 0px -40px 0px"});
revs.forEach(function(el){ io.observe(el); });
} else { revs.forEach(function(el){ el.classList.add("in"); }); }
/* ── LED world map ─────────────────────────────────────────────────
MASK is the real Natural Earth country geometry from the TrekMap
repo, rasterised to a MASK_W x MASK_H grid. Each land cell becomes
one addressable "LED", exactly like the physical product. */
var MASK = window.__TREKMAP_MASK__, MASK_W = 150, MASK_H = 66;
var cv = document.getElementById("led");
if (!cv || !MASK) return;
var ctx = cv.getContext("2d", {alpha:true});
var cells = []; // {gx,gy,state} state: 0 off, 1 wished, 2 visited
var rows = MASK.split("\n");
for (var y=0; y<rows.length; y++){
for (var x=0; x<rows[y].length; x++){
if (rows[y][x] === "1") cells.push({gx:x, gy:y, s:0, p:Math.random()*6.28});
}
}
// A believable travel history: a scatter of visited, a wider scatter wished.
function seed(){
cells.forEach(function(c){ c.s = 0; });
for (var i=0;i<cells.length;i++){
var r = Math.random();
if (r < 0.055) cells[i].s = 2;
else if (r < 0.20) cells[i].s = 1;
}
}
seed();
var dpr = 1, cw = 0, ch = 0, gap = 0, ox = 0, oy = 0, dot = 0;
function layout(){
dpr = Math.min(devicePixelRatio || 1, 2);
cw = cv.clientWidth; ch = cv.clientHeight;
cv.width = Math.floor(cw*dpr); cv.height = Math.floor(ch*dpr);
ctx.setTransform(dpr,0,0,dpr,0,0);
// Fit the grid, biased right so the copy on the left sits over empty ocean.
var scale = Math.max(cw/(MASK_W*0.86), ch/(MASK_H*1.5));
gap = Math.max(scale, 4.2);
dot = Math.max(gap*0.30, 1.15);
ox = cw - MASK_W*gap*0.94; oy = (ch - MASK_H*gap)/2;
if (ox > cw*0.12) ox = cw*0.12;
}
layout();
addEventListener("resize", layout);
var mx = -9999, my = -9999;
if (!reduce){
addEventListener("pointermove", function(e){ mx = e.clientX; my = e.clientY; }, {passive:true});
addEventListener("pointerleave", function(){ mx = my = -9999; });
}
var t = 0;
function frame(){
t += 0.016;
ctx.clearRect(0,0,cw,ch);
var reach = Math.max(gap*7, 90), reach2 = reach*reach;
for (var i=0;i<cells.length;i++){
var c = cells[i];
var px = ox + c.gx*gap, py = oy + c.gy*gap;
if (px < -20 || px > cw+20 || py < -20 || py > ch+20) continue;
var base = c.s === 2 ? 0.92 : c.s === 1 ? 0.30 : 0.085;
// wished cells breathe slowly, like the real firmware's idle pulse
if (c.s === 1 && !reduce) base += Math.sin(t*1.1 + c.p)*0.085;
// cursor acts like a hand passing over the physical map
var dx = px-mx, dy = py-my, d2 = dx*dx+dy*dy;
if (d2 < reach2){ base += (1 - d2/reach2)*0.55; }
if (base <= 0.02) continue;
var a = base > 1 ? 1 : base;
var warm = c.s === 2 || base > 0.6;
ctx.beginPath();
ctx.arc(px, py, dot*(warm ? 1.22 : 1), 0, 6.2832);
ctx.fillStyle = warm ? "rgba(240,207,77," + a + ")" : "rgba(230,184,0," + (a*0.8) + ")";
if (warm && a > 0.55){ ctx.shadowColor = "rgba(230,184,0,.85)"; ctx.shadowBlur = dot*4; }
else { ctx.shadowBlur = 0; }
ctx.fill();
}
ctx.shadowBlur = 0;
requestAnimationFrame(frame);
}
if (reduce){ // one static paint, no loop
mx = my = -9999; t = 0;
ctx.clearRect(0,0,cw,ch);
cells.forEach(function(c){
var a = c.s === 2 ? 0.92 : c.s === 1 ? 0.30 : 0.085;
ctx.beginPath();
ctx.arc(ox + c.gx*gap, oy + c.gy*gap, dot, 0, 6.2832);
ctx.fillStyle = "rgba(230,184,0," + a + ")"; ctx.fill();
});
} else { requestAnimationFrame(frame); }
/* ── per-SKU mini LED strips ────────────────────────────────────── */
var PATTERNS = {
mini: [0,0,1,2,1,0,0,1,0,0,2,1,0,0, 0,1,2,1,1,2,0,1,1,0,1,2,1,0],
wall: [0,1,2,2,1,1,2,0,1,2,1,1,2,0, 1,2,1,2,2,1,1,2,1,1,2,1,2,1],
globe: [1,2,1,0,2,1,1,2,0,1,2,1,0,2, 2,1,2,1,1,2,1,0,2,1,1,2,1,2]
};
document.querySelectorAll("[data-mini]").forEach(function(el){
var p = PATTERNS[el.getAttribute("data-mini")] || PATTERNS.mini;
el.innerHTML = p.map(function(v){
return "<i class='" + (v===2 ? "on" : v===1 ? "dim" : "") + "'></i>";
}).join("");
});
/* ── reserve form ───────────────────────────────────────────────── */
var f = document.getElementById("reserveForm");
if (f) f.addEventListener("submit", function(e){
e.preventDefault();
var v = f.querySelector("input").value.trim();
if (!v || v.indexOf("@") < 1){ f.querySelector("input").focus(); return; }
f.innerHTML = "<p class='said'>You&rsquo;re on the list &mdash; we&rsquo;ll email " + v.replace(/[<>&]/g,"") + " when the run opens.</p>";
});
})();
</script>
</body>
</html>