Design direction: D1 warmth + D3 lightness (warm off-whites, sage green, Outfit + Geist Mono). Includes desktop + mobile HTML mockup, 5 logo concepts, and 33 implementation tasks across 7 phases. Logo decision: Waypoint Dot mark (3 connected dots) + wordmark combo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1550 lines
53 KiB
HTML
1550 lines
53 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>trails.cool — Revised Direction</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&family=Geist+Mono:wght@400;500&family=Rethink+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Figtree:wght@300;400;500;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Nunito+Sans:ital,opsz,wght@0,6..12,300;0,6..12,400;0,6..12,500;0,6..12,600;0,6..12,700;1,6..12,400&family=Epilogue:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&family=Libre+Franklin:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&family=Outfit:wght@300;400;500;600;700&family=Mulish:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Work+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&display=swap" rel="stylesheet">
|
||
<style>
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
html { font-size: 14px; }
|
||
body { background: #F2EFE8; font-family: 'Outfit', sans-serif; color: #1E1C18; }
|
||
|
||
/* ─── NAV CHROME ─── */
|
||
.page-nav {
|
||
position: sticky; top: 0; z-index: 2000;
|
||
background: #1E1C18;
|
||
padding: 10px 20px;
|
||
display: flex; align-items: center; gap: 8px;
|
||
border-bottom: 1px solid #2E2C26;
|
||
}
|
||
.page-nav-label { font-size: 11px; color: #555; text-transform: uppercase; letter-spacing: .1em; margin-right: 6px; font-family: 'Outfit', sans-serif; }
|
||
.nav-btn {
|
||
padding: 5px 13px; border-radius: 5px; border: 1px solid #333;
|
||
background: transparent; color: #777; cursor: pointer;
|
||
font-size: 12px; font-family: 'Outfit', sans-serif;
|
||
transition: all .15s;
|
||
}
|
||
.nav-btn:hover { border-color: #666; color: #ccc; }
|
||
.nav-btn.active { background: #E8E3D6; color: #1E1C18; border-color: #E8E3D6; font-weight: 600; }
|
||
.nav-sep { width: 1px; height: 20px; background: #2E2C26; }
|
||
|
||
.screen { display: none; }
|
||
.screen.active { display: block; }
|
||
|
||
/* ═══════════════════════════════════════════════
|
||
DESIGN SYSTEM — trails.cool revised
|
||
Light, warm-neutral. NOT orange-heavy.
|
||
Accent: a single muted forest-sage green.
|
||
Body font: Outfit (clean, geometric, friendly)
|
||
Mono details: Geist Mono for stats/distances
|
||
The logo mark: simple wordmark, no drama
|
||
═══════════════════════════════════════════════ */
|
||
|
||
:root {
|
||
/* Surface */
|
||
--bg: #F5F2EB; /* warm off-white — like uncoated paper */
|
||
--bg-subtle: #EDEAE1; /* slightly deeper, card backgrounds */
|
||
--bg-raised: #FAF8F4; /* topbar, sidebar, elevated surfaces */
|
||
--map-tint: #E4DFD2; /* map background tone */
|
||
|
||
/* Text */
|
||
--text-hi: #1A1916; /* near-black, primary */
|
||
--text-md: #5C5847; /* secondary labels */
|
||
--text-lo: #9A9484; /* tertiary, placeholders */
|
||
--text-inv: #FAF8F4; /* on dark surfaces */
|
||
|
||
/* Accent: one muted sage-forest green */
|
||
--accent: #4A6B40; /* primary accent */
|
||
--accent-dim: #6A8B5E; /* softer variant */
|
||
--accent-bg: rgba(74,107,64,.08);
|
||
--accent-border: rgba(74,107,64,.2);
|
||
|
||
/* Overnight/stop warm tone — muted, not orange */
|
||
--stop: #8B6D3A; /* warm amber-brown for overnight markers */
|
||
--stop-bg: rgba(139,109,58,.1);
|
||
--stop-border:rgba(139,109,58,.25);
|
||
|
||
/* Danger / no-go */
|
||
--nogo: rgba(160,60,60,.12);
|
||
--nogo-border:rgba(160,60,60,.3);
|
||
|
||
/* UI chrome */
|
||
--border: #DDD9D0;
|
||
--border-md: #CAC6BC;
|
||
--shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
|
||
--shadow-md: 0 4px 12px rgba(0,0,0,.08), 0 1px 4px rgba(0,0,0,.05);
|
||
|
||
/* Elevation gradient colours (for route + chart) */
|
||
--eg-lo: #5A8F46;
|
||
--eg-mid: #C4A840;
|
||
--eg-hi: #C46040;
|
||
|
||
--font-body: 'Outfit', sans-serif;
|
||
--font-mono: 'Geist Mono', monospace;
|
||
}
|
||
|
||
/* ─── TOPBAR ─── */
|
||
.topbar {
|
||
height: 48px;
|
||
background: var(--bg-raised);
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex; align-items: center;
|
||
position: relative; z-index: 100;
|
||
}
|
||
|
||
/* Logo — clean wordmark */
|
||
.logo {
|
||
padding: 0 18px;
|
||
height: 100%;
|
||
display: flex; align-items: center; gap: 8px;
|
||
border-right: 1px solid var(--border);
|
||
text-decoration: none; flex-shrink: 0;
|
||
}
|
||
.logo-mark {
|
||
width: 22px; height: 22px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
position: relative;
|
||
}
|
||
/* Simple mountain/trail SVG icon — not emoji */
|
||
.logo-mark svg { display: block; }
|
||
.logo-wordmark {
|
||
font-family: var(--font-body);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: var(--text-hi);
|
||
letter-spacing: -.02em;
|
||
line-height: 1;
|
||
}
|
||
.logo-wordmark span {
|
||
color: var(--accent);
|
||
font-weight: 400;
|
||
}
|
||
|
||
/* Topbar sections */
|
||
.tb-section {
|
||
padding: 0 14px;
|
||
height: 100%;
|
||
display: flex; align-items: center; gap: 8px;
|
||
border-right: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.tb-label {
|
||
font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
|
||
color: var(--text-lo); font-weight: 400;
|
||
}
|
||
.profile-select {
|
||
display: flex; align-items: center; gap: 6px;
|
||
background: var(--bg-subtle);
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
padding: 4px 9px;
|
||
font-size: 12px; font-weight: 500; color: var(--text-hi);
|
||
cursor: pointer; font-family: var(--font-body);
|
||
white-space: nowrap;
|
||
}
|
||
.profile-select .chevron {
|
||
color: var(--text-lo);
|
||
margin-left: 2px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
/* ── Participant zone ── */
|
||
.participants {
|
||
padding: 0 12px;
|
||
height: 100%;
|
||
display: flex; align-items: center; gap: 8px;
|
||
border-right: 1px solid var(--border);
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Stacked avatars */
|
||
.avatar-stack {
|
||
display: flex; align-items: center;
|
||
cursor: pointer;
|
||
}
|
||
.av {
|
||
width: 26px; height: 26px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 10px; font-weight: 700; color: #fff;
|
||
border: 2px solid var(--bg-raised);
|
||
margin-left: -6px;
|
||
flex-shrink: 0;
|
||
transition: transform .12s;
|
||
position: relative; z-index: 1;
|
||
}
|
||
.av:first-child { margin-left: 0; z-index: 4; }
|
||
.av:nth-child(2) { z-index: 3; }
|
||
.av:nth-child(3) { z-index: 2; }
|
||
.avatar-stack:hover .av { transform: translateX(-2px); }
|
||
.avatar-stack:hover .av:first-child { transform: none; }
|
||
|
||
/* "You" avatar — always shown with name since it's the user */
|
||
.av-you-wrap {
|
||
display: flex; align-items: center; gap: 6px;
|
||
padding-right: 10px;
|
||
border-right: 1px solid var(--border);
|
||
margin-right: 4px;
|
||
cursor: default;
|
||
}
|
||
.av-you-name {
|
||
font-size: 12px; font-weight: 600; color: var(--text-hi); line-height: 1.1;
|
||
}
|
||
.av-you-role {
|
||
font-size: 10px; color: var(--accent); line-height: 1.2;
|
||
}
|
||
|
||
/* Overflow "+N" chip */
|
||
.av-overflow {
|
||
width: 26px; height: 26px; border-radius: 50%;
|
||
background: var(--bg-subtle);
|
||
border: 2px solid var(--bg-raised);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 9px; font-weight: 700; color: var(--text-md);
|
||
margin-left: -6px; flex-shrink: 0; z-index: 0;
|
||
}
|
||
|
||
/* Invite button — lightweight, link-share feel */
|
||
.invite-btn {
|
||
display: flex; align-items: center; gap: 5px;
|
||
padding: 4px 10px; border-radius: 5px;
|
||
border: 1px dashed var(--border-md);
|
||
background: transparent; color: var(--text-lo);
|
||
font-size: 11px; font-weight: 500; font-family: var(--font-body);
|
||
cursor: pointer; white-space: nowrap;
|
||
transition: all .12s;
|
||
}
|
||
.invite-btn:hover {
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
background: var(--accent-bg);
|
||
}
|
||
|
||
/* ── Participants panel (dropdown) ── */
|
||
.participants-panel {
|
||
position: absolute;
|
||
top: calc(100% + 6px);
|
||
left: 0;
|
||
width: 280px;
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
box-shadow: 0 8px 24px rgba(0,0,0,.1), 0 2px 6px rgba(0,0,0,.06);
|
||
z-index: 500;
|
||
overflow: hidden;
|
||
/* shown via JS toggle */
|
||
}
|
||
.pp-header {
|
||
padding: 12px 14px 10px;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
}
|
||
.pp-title {
|
||
font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .09em;
|
||
color: var(--text-lo);
|
||
}
|
||
.pp-count {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px; color: var(--text-lo);
|
||
}
|
||
.pp-list { padding: 6px 0; }
|
||
.pp-row {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 7px 14px;
|
||
transition: background .1s;
|
||
}
|
||
.pp-row:hover { background: var(--bg-subtle); }
|
||
.pp-av {
|
||
width: 28px; height: 28px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 11px; font-weight: 700; color: #fff;
|
||
flex-shrink: 0;
|
||
/* live pulse ring for online users */
|
||
position: relative;
|
||
}
|
||
.pp-av.online::after {
|
||
content: '';
|
||
position: absolute; bottom: 0; right: 0;
|
||
width: 8px; height: 8px; border-radius: 50%;
|
||
background: var(--accent);
|
||
border: 1.5px solid var(--bg-raised);
|
||
}
|
||
.pp-info { flex: 1; min-width: 0; }
|
||
.pp-name {
|
||
font-size: 12px; font-weight: 600; color: var(--text-hi);
|
||
display: flex; align-items: center; gap: 5px;
|
||
}
|
||
.pp-host-tag {
|
||
font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
|
||
color: var(--accent); background: var(--accent-bg);
|
||
border: 1px solid var(--accent-border);
|
||
border-radius: 3px; padding: 1px 4px;
|
||
}
|
||
.pp-status {
|
||
font-size: 11px; color: var(--text-lo);
|
||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||
}
|
||
.pp-cursor-dot {
|
||
width: 8px; height: 8px; border-radius: 50%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Share link row */
|
||
.pp-share {
|
||
padding: 10px 14px 12px;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
.pp-share-label {
|
||
font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
|
||
color: var(--text-lo); margin-bottom: 6px;
|
||
}
|
||
.pp-share-row {
|
||
display: flex; gap: 6px;
|
||
}
|
||
.pp-share-input {
|
||
flex: 1; background: var(--bg-subtle);
|
||
border: 1px solid var(--border); border-radius: 5px;
|
||
padding: 5px 8px;
|
||
font-size: 11px; font-family: var(--font-mono); color: var(--text-md);
|
||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||
cursor: text;
|
||
}
|
||
.pp-copy-btn {
|
||
padding: 5px 11px; border-radius: 5px;
|
||
background: var(--text-hi); color: var(--bg-raised);
|
||
font-size: 11px; font-weight: 600; font-family: var(--font-body);
|
||
border: none; cursor: pointer; white-space: nowrap;
|
||
transition: opacity .12s;
|
||
}
|
||
.pp-copy-btn:hover { opacity: .85; }
|
||
.pp-copy-btn.copied {
|
||
background: var(--accent);
|
||
}
|
||
|
||
/* Mobile participant zone */
|
||
.mob-pax-zone {
|
||
display: flex; align-items: center; gap: 6px;
|
||
position: relative;
|
||
}
|
||
.mob-av-stack { display: flex; align-items: center; cursor: pointer; }
|
||
.mob-av {
|
||
width: 24px; height: 24px; border-radius: 50%;
|
||
border: 2px solid var(--bg-raised);
|
||
font-size: 9px; font-weight: 700; color: #fff;
|
||
display: flex; align-items: center; justify-content: center;
|
||
margin-left: -6px; flex-shrink: 0;
|
||
}
|
||
.mob-av:first-child { margin-left: 0; }
|
||
.mob-av-overflow {
|
||
width: 24px; height: 24px; border-radius: 50%;
|
||
border: 2px solid var(--bg-raised);
|
||
background: var(--bg-subtle);
|
||
font-size: 9px; font-weight: 700; color: var(--text-md);
|
||
display: flex; align-items: center; justify-content: center;
|
||
margin-left: -6px; flex-shrink: 0;
|
||
}
|
||
|
||
/* p-name / p-role kept for any remaining usage */
|
||
.p-name {
|
||
font-size: 12px; font-weight: 600; color: var(--text-hi); line-height: 1.1;
|
||
}
|
||
.p-role { font-size: 10px; color: var(--text-lo); line-height: 1.2; }
|
||
.p-role.host { color: var(--accent); }
|
||
|
||
/* Topbar right actions */
|
||
.tb-actions {
|
||
margin-left: auto;
|
||
padding: 0 14px;
|
||
display: flex; align-items: center; gap: 8px;
|
||
}
|
||
.color-mode {
|
||
display: flex;
|
||
background: var(--bg-subtle);
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px; overflow: hidden;
|
||
}
|
||
.cm-btn {
|
||
padding: 4px 10px; font-size: 11px; font-weight: 500;
|
||
color: var(--text-lo); cursor: pointer;
|
||
background: none; border: none;
|
||
font-family: var(--font-body);
|
||
transition: all .12s;
|
||
}
|
||
.cm-btn.active { background: var(--text-hi); color: var(--bg-raised); }
|
||
.btn-ghost {
|
||
display: flex; align-items: center; gap: 5px;
|
||
padding: 5px 12px; border-radius: 6px;
|
||
border: 1px solid var(--border);
|
||
background: transparent; color: var(--text-md);
|
||
font-size: 12px; font-weight: 500; font-family: var(--font-body);
|
||
cursor: pointer; white-space: nowrap;
|
||
transition: all .12s;
|
||
}
|
||
.btn-ghost:hover { border-color: var(--border-md); color: var(--text-hi); }
|
||
.session-status {
|
||
display: flex; align-items: center; gap: 5px;
|
||
font-size: 11px; color: var(--text-lo);
|
||
font-family: var(--font-mono);
|
||
white-space: nowrap;
|
||
}
|
||
.session-dot {
|
||
width: 6px; height: 6px; border-radius: 50%;
|
||
background: var(--accent);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Progress bar */
|
||
.progress-bar {
|
||
position: absolute; top: 0; left: 0; height: 2px; z-index: 200;
|
||
background: linear-gradient(90deg, var(--accent), var(--eg-mid));
|
||
border-radius: 0 2px 2px 0;
|
||
animation: pb 4s ease-in-out infinite alternate;
|
||
}
|
||
@keyframes pb {
|
||
0% { width: 18%; opacity: 1; }
|
||
100% { width: 72%; opacity: .8; }
|
||
}
|
||
|
||
/* ─── MAIN LAYOUT ─── */
|
||
.main {
|
||
display: flex;
|
||
height: calc(100vh - 48px - 148px);
|
||
min-height: 380px;
|
||
}
|
||
|
||
/* ─── MAP ─── */
|
||
.map-area {
|
||
flex: 1;
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: var(--map-tint);
|
||
}
|
||
|
||
/* subtle topo crosshatch */
|
||
.map-area::before {
|
||
content: '';
|
||
position: absolute; inset: 0; z-index: 0;
|
||
background-image:
|
||
repeating-linear-gradient(90deg,
|
||
rgba(150,140,120,.1) 0, rgba(150,140,120,.1) 1px,
|
||
transparent 0, transparent 18px),
|
||
repeating-linear-gradient(0deg,
|
||
rgba(150,140,120,.1) 0, rgba(150,140,120,.1) 1px,
|
||
transparent 0, transparent 18px);
|
||
}
|
||
|
||
.map-credit {
|
||
position: absolute; bottom: 6px; right: 8px; z-index: 10;
|
||
font-size: 10px; color: rgba(0,0,0,.22);
|
||
font-family: var(--font-body);
|
||
}
|
||
|
||
/* Map controls */
|
||
.map-ctrl-group {
|
||
position: absolute; left: 12px; top: 12px; z-index: 20;
|
||
display: flex; flex-direction: column; gap: 0;
|
||
box-shadow: var(--shadow-md);
|
||
border-radius: 7px; overflow: hidden;
|
||
border: 1px solid var(--border);
|
||
}
|
||
.map-ctrl {
|
||
width: 32px; height: 32px;
|
||
background: var(--bg-raised);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 16px; font-weight: 500; cursor: pointer;
|
||
color: var(--text-md);
|
||
border-bottom: 1px solid var(--border);
|
||
transition: background .12s;
|
||
}
|
||
.map-ctrl:last-child { border-bottom: none; }
|
||
.map-ctrl:hover { background: var(--bg-subtle); }
|
||
.map-ctrl.icon { font-size: 13px; }
|
||
|
||
/* Route SVG */
|
||
.route-layer {
|
||
position: absolute; inset: 0; z-index: 5;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* No-go polygon */
|
||
.nogo {
|
||
position: absolute; z-index: 6;
|
||
background: var(--nogo);
|
||
border: 1.5px dashed var(--nogo-border);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
/* Waypoint markers */
|
||
.wpt {
|
||
position: absolute; z-index: 10;
|
||
display: flex; flex-direction: column; align-items: center;
|
||
transform: translate(-50%, -100%);
|
||
pointer-events: all;
|
||
cursor: grab;
|
||
}
|
||
.wpt-pin {
|
||
width: 26px; height: 26px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 11px; font-weight: 700; color: #fff;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,.22);
|
||
border: 2px solid rgba(255,255,255,.6);
|
||
position: relative; flex-shrink: 0;
|
||
font-family: var(--font-mono);
|
||
}
|
||
.wpt-pin.is-start { background: var(--accent); }
|
||
.wpt-pin.is-mid { background: #7A9070; } /* minor intermediate - muted */
|
||
.wpt-pin.is-overnight { background: var(--stop); }
|
||
.wpt-pin.is-end { background: var(--text-hi); }
|
||
|
||
/* Note dot on pin */
|
||
.wpt-note-dot {
|
||
position: absolute; top: -1px; right: -1px;
|
||
width: 9px; height: 9px; border-radius: 50%;
|
||
background: var(--stop);
|
||
border: 1.5px solid var(--bg-raised);
|
||
}
|
||
|
||
.wpt-label {
|
||
margin-top: 4px;
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: 5px; padding: 2px 8px;
|
||
font-size: 11px; font-weight: 500; color: var(--text-hi);
|
||
white-space: nowrap;
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* Overnight badge above pin */
|
||
.wpt-overnight-badge {
|
||
position: absolute; bottom: calc(100% + 5px);
|
||
background: var(--stop);
|
||
color: #fff;
|
||
font-size: 9px; font-weight: 600; letter-spacing: .05em;
|
||
text-transform: uppercase;
|
||
padding: 2px 7px; border-radius: 4px;
|
||
white-space: nowrap;
|
||
box-shadow: 0 1px 4px rgba(0,0,0,.15);
|
||
}
|
||
|
||
/* Day labels on map */
|
||
.day-badge {
|
||
position: absolute; z-index: 8;
|
||
background: var(--bg-raised);
|
||
border: 1px solid var(--border);
|
||
border-radius: 5px; padding: 3px 9px;
|
||
font-size: 10px; font-weight: 500; color: var(--text-md);
|
||
box-shadow: var(--shadow-sm);
|
||
white-space: nowrap;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
/* Cursor label */
|
||
.cursor {
|
||
position: absolute; z-index: 12;
|
||
display: flex; align-items: center; gap: 5px;
|
||
pointer-events: none;
|
||
}
|
||
.cursor-dot {
|
||
width: 10px; height: 10px; border-radius: 50%;
|
||
border: 2px solid var(--bg-raised);
|
||
flex-shrink: 0;
|
||
}
|
||
.cursor-label {
|
||
font-size: 11px; font-weight: 600;
|
||
color: #fff;
|
||
padding: 2px 8px; border-radius: 4px;
|
||
box-shadow: 0 1px 4px rgba(0,0,0,.2);
|
||
}
|
||
|
||
/* ─── SIDEBAR ─── */
|
||
.sidebar {
|
||
width: 276px;
|
||
background: var(--bg-raised);
|
||
border-left: 1px solid var(--border);
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.sidebar-tabs {
|
||
display: flex;
|
||
border-bottom: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.stab {
|
||
flex: 1; padding: 10px 8px; text-align: center;
|
||
font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
|
||
color: var(--text-lo); background: none; border: none; cursor: pointer;
|
||
font-family: var(--font-body);
|
||
border-bottom: 2px solid transparent; margin-bottom: -1px;
|
||
transition: color .12s;
|
||
}
|
||
.stab.active { color: var(--text-hi); border-bottom-color: var(--accent); }
|
||
|
||
.sidebar-body {
|
||
flex: 1; overflow-y: auto; padding: 14px;
|
||
}
|
||
.sidebar-body::-webkit-scrollbar { width: 3px; }
|
||
.sidebar-body::-webkit-scrollbar-thumb {
|
||
background: var(--border); border-radius: 2px;
|
||
}
|
||
|
||
/* Route header inside sidebar */
|
||
.route-header {
|
||
margin-bottom: 14px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.route-eyebrow {
|
||
font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
|
||
color: var(--text-lo); margin-bottom: 3px;
|
||
}
|
||
.route-name {
|
||
font-size: 15px; font-weight: 600; color: var(--text-hi);
|
||
line-height: 1.3; margin-bottom: 8px;
|
||
}
|
||
.route-via {
|
||
font-size: 12px; font-weight: 400; color: var(--text-md);
|
||
}
|
||
.route-stats {
|
||
display: flex; gap: 14px; flex-wrap: wrap;
|
||
}
|
||
.r-stat { display: flex; flex-direction: column; gap: 1px; }
|
||
.r-stat-val {
|
||
font-family: var(--font-mono);
|
||
font-size: 13px; font-weight: 500; color: var(--accent);
|
||
line-height: 1.1;
|
||
}
|
||
.r-stat-lbl {
|
||
font-size: 9px; text-transform: uppercase; letter-spacing: .09em;
|
||
color: var(--text-lo);
|
||
}
|
||
|
||
/* Section title */
|
||
.section-title {
|
||
font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
|
||
color: var(--text-lo);
|
||
display: flex; align-items: center; gap: 6px;
|
||
margin-bottom: 8px;
|
||
}
|
||
.soon-pill {
|
||
font-size: 9px; text-transform: uppercase; letter-spacing: .08em;
|
||
background: var(--accent-bg);
|
||
color: var(--accent);
|
||
border: 1px solid var(--accent-border);
|
||
border-radius: 3px; padding: 1px 5px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Day cards */
|
||
.day-card {
|
||
border: 1px solid var(--border);
|
||
border-radius: 7px;
|
||
margin-bottom: 7px;
|
||
overflow: hidden;
|
||
background: var(--bg);
|
||
}
|
||
.day-card-head {
|
||
display: flex; align-items: center; gap: 9px;
|
||
padding: 9px 11px; cursor: pointer;
|
||
}
|
||
.day-num {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px; font-weight: 500;
|
||
color: var(--accent);
|
||
flex-shrink: 0; min-width: 18px;
|
||
}
|
||
.day-info { flex: 1; min-width: 0; }
|
||
.day-title {
|
||
font-size: 12px; font-weight: 600; color: var(--text-hi);
|
||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||
}
|
||
.day-meta {
|
||
font-size: 11px; color: var(--text-md); font-weight: 400;
|
||
}
|
||
.day-km {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px; font-weight: 500; color: var(--text-md);
|
||
flex-shrink: 0;
|
||
}
|
||
.chevron { color: var(--text-lo); font-size: 9px; flex-shrink: 0; }
|
||
|
||
/* Expanded day body — waypoint list */
|
||
.day-card-body {
|
||
border-top: 1px solid var(--border);
|
||
padding: 8px 11px 10px 11px;
|
||
background: var(--bg-subtle);
|
||
}
|
||
.wpt-row {
|
||
display: flex; align-items: flex-start; gap: 8px;
|
||
padding: 4px 0;
|
||
}
|
||
.wpt-row-connector {
|
||
display: flex; flex-direction: column; align-items: center;
|
||
padding-top: 3px; flex-shrink: 0;
|
||
}
|
||
.wpt-dot {
|
||
width: 7px; height: 7px; border-radius: 50%;
|
||
background: var(--border-md);
|
||
flex-shrink: 0;
|
||
}
|
||
.wpt-dot.special { background: var(--stop); }
|
||
.wpt-dot.accent { background: var(--accent); }
|
||
.wpt-line {
|
||
width: 1px; flex: 1; min-height: 14px;
|
||
background: var(--border); margin: 2px 0;
|
||
}
|
||
.wpt-row-info { flex: 1; padding-top: 0; }
|
||
.wpt-row-name {
|
||
font-size: 12px; font-weight: 500; color: var(--text-hi);
|
||
display: flex; align-items: center; gap: 5px; line-height: 1.3;
|
||
}
|
||
.wpt-tag {
|
||
font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
|
||
color: var(--stop); background: var(--stop-bg);
|
||
border: 1px solid var(--stop-border);
|
||
border-radius: 3px; padding: 0 4px;
|
||
}
|
||
.wpt-note {
|
||
font-size: 11px; color: var(--text-md); font-weight: 400;
|
||
font-style: italic; margin-top: 1px;
|
||
padding-left: 1px;
|
||
}
|
||
.wpt-note::before { content: '"'; }
|
||
.wpt-note::after { content: '"'; }
|
||
|
||
/* ─── ELEVATION PANEL ─── */
|
||
.elev-panel {
|
||
height: 148px;
|
||
background: var(--bg-raised);
|
||
border-top: 1px solid var(--border);
|
||
display: flex; flex-direction: column;
|
||
flex-shrink: 0;
|
||
}
|
||
.elev-header {
|
||
display: flex; align-items: center;
|
||
padding: 8px 16px 0;
|
||
gap: 12px;
|
||
}
|
||
.elev-eyebrow {
|
||
font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
|
||
color: var(--text-lo);
|
||
}
|
||
.elev-stats {
|
||
margin-left: auto;
|
||
display: flex; gap: 20px;
|
||
}
|
||
.e-stat {
|
||
font-size: 12px; color: var(--text-md);
|
||
font-family: var(--font-mono);
|
||
}
|
||
.e-stat strong { color: var(--text-hi); font-weight: 500; }
|
||
.elev-chart {
|
||
flex: 1; padding: 4px 16px 10px; position: relative;
|
||
}
|
||
|
||
/* ══════════════════════
|
||
MOBILE LAYOUT
|
||
══════════════════════ */
|
||
.mobile-shell {
|
||
width: 390px;
|
||
background: var(--bg);
|
||
border-radius: 22px;
|
||
overflow: hidden;
|
||
box-shadow: 0 16px 56px rgba(0,0,0,.18), 0 4px 12px rgba(0,0,0,.1);
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* Mobile topbar */
|
||
.mob-topbar {
|
||
height: 48px;
|
||
background: var(--bg-raised);
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
padding: 0 16px;
|
||
position: relative;
|
||
}
|
||
.mob-logo {
|
||
font-family: var(--font-body);
|
||
font-size: 15px; font-weight: 600; color: var(--text-hi);
|
||
letter-spacing: -.02em;
|
||
display: flex; align-items: center; gap: 7px;
|
||
}
|
||
.mob-logo-mark svg { display: block; }
|
||
.mob-logo span { color: var(--accent); font-weight: 400; }
|
||
|
||
.mob-right { display: flex; align-items: center; gap: 8px; }
|
||
.mob-profile-select {
|
||
display: flex; align-items: center; gap: 5px;
|
||
background: var(--bg-subtle);
|
||
border: 1px solid var(--border);
|
||
border-radius: 5px; padding: 4px 8px;
|
||
font-size: 11px; font-weight: 500; color: var(--text-hi);
|
||
cursor: pointer;
|
||
}
|
||
.mob-participants { display: flex; }
|
||
.mob-av {
|
||
width: 24px; height: 24px; border-radius: 50%;
|
||
border: 2px solid var(--bg-raised);
|
||
font-size: 10px; font-weight: 700; color: #fff;
|
||
display: flex; align-items: center; justify-content: center;
|
||
margin-left: -6px; flex-shrink: 0;
|
||
}
|
||
.mob-av:first-child { margin-left: 0; }
|
||
|
||
/* Mobile map */
|
||
.mob-map {
|
||
height: 290px;
|
||
background: var(--map-tint);
|
||
position: relative; overflow: hidden;
|
||
}
|
||
.mob-map::before {
|
||
content: '';
|
||
position: absolute; inset: 0;
|
||
background-image:
|
||
repeating-linear-gradient(90deg, rgba(150,140,120,.1) 0, rgba(150,140,120,.1) 1px, transparent 0, transparent 18px),
|
||
repeating-linear-gradient(0deg, rgba(150,140,120,.1) 0, rgba(150,140,120,.1) 1px, transparent 0, transparent 18px);
|
||
}
|
||
|
||
/* Bottom sheet */
|
||
.mob-sheet {
|
||
background: var(--bg-raised);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
.mob-sheet-handle {
|
||
width: 32px; height: 3px; background: var(--border-md);
|
||
border-radius: 2px; margin: 9px auto 0;
|
||
}
|
||
.mob-sheet-summary {
|
||
padding: 10px 16px 10px;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex; align-items: flex-start; justify-content: space-between;
|
||
gap: 10px;
|
||
}
|
||
.mob-route-name {
|
||
font-size: 15px; font-weight: 600; color: var(--text-hi);
|
||
line-height: 1.2;
|
||
}
|
||
.mob-route-via {
|
||
font-size: 11px; color: var(--text-lo); margin-top: 2px;
|
||
}
|
||
.mob-stat-pills {
|
||
display: flex; flex-direction: column; gap: 3px; align-items: flex-end;
|
||
flex-shrink: 0;
|
||
}
|
||
.mob-stat-pill {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px; font-weight: 500; color: var(--text-md);
|
||
white-space: nowrap;
|
||
}
|
||
.mob-stat-pill.km { color: var(--accent); font-size: 13px; }
|
||
|
||
/* Mini elevation */
|
||
.mob-elev { height: 64px; padding: 6px 16px 2px; }
|
||
|
||
/* Tab bar */
|
||
.mob-tabs {
|
||
display: flex; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
|
||
}
|
||
.mob-tab {
|
||
flex: 1; padding: 9px 8px; text-align: center;
|
||
font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .09em;
|
||
color: var(--text-lo); background: none; border: none;
|
||
font-family: var(--font-body);
|
||
border-bottom: 2px solid transparent; cursor: pointer;
|
||
transition: color .12s;
|
||
}
|
||
.mob-tab.active { color: var(--text-hi); border-bottom-color: var(--accent); }
|
||
|
||
/* Mobile day rows */
|
||
.mob-days { padding: 0; }
|
||
.mob-day-row {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 10px 16px;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.mob-day-row:last-child { border-bottom: none; }
|
||
.mob-day-num {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px; font-weight: 500; color: var(--accent);
|
||
flex-shrink: 0; min-width: 20px;
|
||
}
|
||
.mob-day-info { flex: 1; }
|
||
.mob-day-title { font-size: 13px; font-weight: 600; color: var(--text-hi); }
|
||
.mob-day-meta { font-size: 11px; color: var(--text-md); font-weight: 400; }
|
||
.mob-day-km {
|
||
font-family: var(--font-mono);
|
||
font-size: 13px; font-weight: 500; color: var(--text-md);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ─── PAGE WRAPPER ─── */
|
||
.page-section {
|
||
padding: 36px 40px;
|
||
}
|
||
.screen-label {
|
||
font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--text-lo);
|
||
margin-bottom: 4px; font-family: var(--font-body);
|
||
}
|
||
.screen-heading {
|
||
font-size: 22px; font-weight: 600; color: var(--text-hi);
|
||
margin-bottom: 24px; letter-spacing: -.02em;
|
||
}
|
||
.desktop-frame {
|
||
border-radius: 10px; overflow: hidden;
|
||
box-shadow: 0 8px 32px rgba(0,0,0,.12), 0 2px 8px rgba(0,0,0,.08);
|
||
border: 1px solid var(--border);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- NAV -->
|
||
<nav class="page-nav">
|
||
<span class="page-nav-label">trails.cool v2</span>
|
||
<button class="nav-btn active" onclick="show('desktop')">Desktop</button>
|
||
<button class="nav-btn" onclick="show('mobile')">Mobile</button>
|
||
</nav>
|
||
|
||
<!-- ╔══════════════╗ -->
|
||
<!-- ║ DESKTOP ║ -->
|
||
<!-- ╚══════════════╝ -->
|
||
<div id="desktop" class="screen active">
|
||
<div class="page-section" style="background:var(--bg);">
|
||
<div class="screen-label">Revised direction — merging D1 warmth + D3 lightness</div>
|
||
<div class="screen-heading">trails.cool — Desktop</div>
|
||
|
||
<div class="desktop-frame" style="display:flex; flex-direction:column; height:calc(100vh - 180px); min-height:680px;">
|
||
|
||
<!-- TOP BAR -->
|
||
<div class="topbar">
|
||
|
||
<!-- Logo: Waypoint Dot mark + wordmark -->
|
||
<a class="logo">
|
||
<div class="logo-mark">
|
||
<svg width="24" height="22" viewBox="0 0 128 128" fill="none">
|
||
<path d="M28 90 C45 90, 50 50, 64 45 S85 70, 100 35" stroke="var(--accent)" stroke-width="6" stroke-linecap="round" fill="none"/>
|
||
<circle cx="28" cy="90" r="11" fill="var(--accent)"/>
|
||
<circle cx="64" cy="45" r="11" fill="var(--accent)"/>
|
||
<circle cx="100" cy="35" r="11" fill="var(--accent)"/>
|
||
</svg>
|
||
</div>
|
||
<span class="logo-wordmark">trails<span>.cool</span></span>
|
||
</a>
|
||
|
||
<!-- Profile -->
|
||
<div class="tb-section">
|
||
<div class="profile-select">
|
||
<svg width="13" height="13" viewBox="0 0 13 13" fill="none"><circle cx="6.5" cy="6.5" r="5.5" stroke="var(--accent)" stroke-width="1.2"/><path d="M4 7.5c.8 1 4.2 1 4.2 0M3.5 5.5h.5M9 5.5h.5" stroke="var(--accent)" stroke-width="1.1" stroke-linecap="round"/></svg>
|
||
Cycling (safe)
|
||
<span class="chevron">▾</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Participants — avatar stack, expands on click -->
|
||
<div class="participants" id="pax-zone">
|
||
|
||
<!-- You: always shown with name as it's the local user -->
|
||
<div class="av-you-wrap">
|
||
<div class="av" style="background:#4A6B40; margin-left:0;">Y</div>
|
||
<div>
|
||
<div class="av-you-name">You</div>
|
||
<div class="av-you-role">Host</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Others: stacked avatars, 3 visible max, then +N -->
|
||
<div class="avatar-stack" onclick="togglePanel()" title="View all participants">
|
||
<div class="av" style="background:#6B7FA8;">A</div>
|
||
<div class="av" style="background:#8B6D3A;">S</div>
|
||
<div class="av" style="background:#6A7B5A;">M</div>
|
||
<div class="av-overflow">+3</div>
|
||
</div>
|
||
|
||
<!-- Invite — link-based, no accounts -->
|
||
<button class="invite-btn" onclick="togglePanel()">
|
||
<svg width="11" height="11" viewBox="0 0 11 11" fill="none"><path d="M5.5 1v9M1 5.5h9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||
Invite
|
||
</button>
|
||
|
||
<!-- Participants panel -->
|
||
<div class="participants-panel" id="pax-panel" style="display:none;">
|
||
<div class="pp-header">
|
||
<span class="pp-title">In this session</span>
|
||
<span class="pp-count">6 online</span>
|
||
</div>
|
||
<div class="pp-list">
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#4A6B40;">Y</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">
|
||
You
|
||
<span class="pp-host-tag">Host</span>
|
||
</div>
|
||
<div class="pp-status">Editing route</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#4A6B40;"></div>
|
||
</div>
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#6B7FA8;">A</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">Alex</div>
|
||
<div class="pp-status">Viewing · near Dessau</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#6B7FA8;"></div>
|
||
</div>
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#8B6D3A;">S</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">Sara</div>
|
||
<div class="pp-status">Editing notes</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#8B6D3A;"></div>
|
||
</div>
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#6A7B5A;">M</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">Mika</div>
|
||
<div class="pp-status">Viewing</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#6A7B5A;"></div>
|
||
</div>
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#8A6080;">L</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">Lena</div>
|
||
<div class="pp-status">Idle</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#8A6080;"></div>
|
||
</div>
|
||
|
||
<div class="pp-row">
|
||
<div class="pp-av online" style="background:#5A7A8A;">T</div>
|
||
<div class="pp-info">
|
||
<div class="pp-name">Tom</div>
|
||
<div class="pp-status">Moving waypoint 2</div>
|
||
</div>
|
||
<div class="pp-cursor-dot" style="background:#5A7A8A;"></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Share link -->
|
||
<div class="pp-share">
|
||
<div class="pp-share-label">Share link — anyone can join</div>
|
||
<div class="pp-share-row">
|
||
<div class="pp-share-input">trails.cool/s/cb6ada8e</div>
|
||
<button class="pp-copy-btn" id="copy-btn" onclick="copyLink()">Copy</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Right actions -->
|
||
<div class="tb-actions">
|
||
<div class="color-mode">
|
||
<button class="cm-btn">Plain</button>
|
||
<button class="cm-btn active">Elevation</button>
|
||
<button class="cm-btn">Surface</button>
|
||
</div>
|
||
<button class="btn-ghost">
|
||
<svg width="11" height="11" viewBox="0 0 11 11" fill="none"><path d="M5.5 1v6.5M2.5 5l3 3.5 3-3.5M1 10h9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
Export GPX
|
||
</button>
|
||
<div class="session-status">
|
||
<div class="session-dot"></div>
|
||
Connected · cb6ada8e
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PROGRESS BAR -->
|
||
<div class="progress-bar" style="position:relative; height:0; overflow:visible;">
|
||
<div class="progress-bar" style="position:absolute; width:62%; top:0;"></div>
|
||
</div>
|
||
|
||
<!-- MAP + SIDEBAR -->
|
||
<div class="main">
|
||
<div class="map-area">
|
||
|
||
<!-- Map controls -->
|
||
<div class="map-ctrl-group">
|
||
<div class="map-ctrl">+</div>
|
||
<div class="map-ctrl">−</div>
|
||
<div class="map-ctrl icon">⊞</div>
|
||
<div class="map-ctrl icon">⊘</div>
|
||
</div>
|
||
|
||
<!-- No-go area -->
|
||
<div class="nogo" style="left:36%; top:24%; width:82px; height:60px;"></div>
|
||
|
||
<!-- Route SVG -->
|
||
<svg class="route-layer" viewBox="0 0 800 500" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="rte-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#5A8F46"/>
|
||
<stop offset="38%" style="stop-color:#9ABF50"/>
|
||
<stop offset="62%" style="stop-color:#C4A840"/>
|
||
<stop offset="84%" style="stop-color:#C46040"/>
|
||
<stop offset="100%" style="stop-color:#A03030"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<!-- Main route line -->
|
||
<path d="M 375 78
|
||
C 362 110 352 140 342 175
|
||
C 328 218 316 252 304 285
|
||
C 288 325 276 358 268 392
|
||
C 262 416 258 435 254 455"
|
||
stroke="url(#rte-grad)" stroke-width="3.5" fill="none"
|
||
stroke-linecap="round" stroke-linejoin="round" opacity=".92"/>
|
||
<!-- Day 1/2 divider hint on route — subtle tick -->
|
||
<line x1="267" y1="390" x2="280" y2="390"
|
||
stroke="var(--stop)" stroke-width="1.5"
|
||
stroke-dasharray="4,3" opacity="0.45"/>
|
||
</svg>
|
||
|
||
<!-- WAYPOINTS -->
|
||
<!-- 1: Berlin Alexanderplatz — start -->
|
||
<div class="wpt" style="left:46.9%; top:15.5%;">
|
||
<div class="wpt-pin is-start">1</div>
|
||
<div class="wpt-label">Berlin Alexanderplatz</div>
|
||
</div>
|
||
|
||
<!-- 2: Dessau — overnight stop -->
|
||
<div class="wpt" style="left:33.5%; top:78%;">
|
||
<div class="wpt-overnight-badge">Night 1</div>
|
||
<div class="wpt-pin is-overnight" style="position:relative;">
|
||
2
|
||
<div class="wpt-note-dot"></div>
|
||
</div>
|
||
<div class="wpt-label">Dessau</div>
|
||
</div>
|
||
|
||
<!-- 3: Erfurt — end -->
|
||
<div class="wpt" style="left:31.8%; top:91%;">
|
||
<div class="wpt-pin is-end">3</div>
|
||
<div class="wpt-label">Erfurt Altstadt</div>
|
||
</div>
|
||
|
||
<!-- Day labels -->
|
||
<div class="day-badge" style="left:40%; top:38%;">Day 1 · 120 km</div>
|
||
<div class="day-badge" style="left:33%; top:84.5%;">Day 2 · 130 km</div>
|
||
|
||
<!-- Multiple live cursors — 6 participants -->
|
||
<div class="cursor" style="left:48%; top:52%;">
|
||
<div class="cursor-dot" style="background:#6B7FA8;"></div>
|
||
<div class="cursor-label" style="background:#6B7FA8;">Alex</div>
|
||
</div>
|
||
<div class="cursor" style="left:55%; top:30%;">
|
||
<div class="cursor-dot" style="background:#8B6D3A;"></div>
|
||
<div class="cursor-label" style="background:#8B6D3A;">Sara</div>
|
||
</div>
|
||
<div class="cursor" style="left:28%; top:60%;">
|
||
<div class="cursor-dot" style="background:#5A7A8A;"></div>
|
||
<div class="cursor-label" style="background:#5A7A8A;">Tom</div>
|
||
</div>
|
||
|
||
<div class="map-credit">© OpenStreetMap</div>
|
||
</div>
|
||
|
||
<!-- SIDEBAR -->
|
||
<div class="sidebar">
|
||
<div class="sidebar-tabs">
|
||
<button class="stab active">Waypoints</button>
|
||
<button class="stab">Notes</button>
|
||
</div>
|
||
<div class="sidebar-body">
|
||
|
||
<!-- Route header -->
|
||
<div class="route-header">
|
||
<div class="route-eyebrow">Active route</div>
|
||
<div class="route-name">Berlin → Erfurt <span class="route-via">via Dessau</span></div>
|
||
<div class="route-stats">
|
||
<div class="r-stat">
|
||
<span class="r-stat-val">343 km</span>
|
||
<span class="r-stat-lbl">Distance</span>
|
||
</div>
|
||
<div class="r-stat">
|
||
<span class="r-stat-val">↑ 868 m</span>
|
||
<span class="r-stat-lbl">Ascent</span>
|
||
</div>
|
||
<div class="r-stat">
|
||
<span class="r-stat-val">3 days</span>
|
||
<span class="r-stat-lbl">Duration</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Day breakdown -->
|
||
<div class="section-title">
|
||
Day breakdown
|
||
<span class="soon-pill">Soon</span>
|
||
</div>
|
||
|
||
<!-- Day 1 — expanded -->
|
||
<div class="day-card">
|
||
<div class="day-card-head">
|
||
<span class="day-num">01</span>
|
||
<div class="day-info">
|
||
<div class="day-title">Berlin → Dessau</div>
|
||
<div class="day-meta">↑ 340 m ascent</div>
|
||
</div>
|
||
<span class="day-km">120 km</span>
|
||
<span class="chevron">▼</span>
|
||
</div>
|
||
<div class="day-card-body">
|
||
<!-- Waypoint list — simple, not every one is a highlight -->
|
||
<div class="wpt-row">
|
||
<div class="wpt-row-connector">
|
||
<div class="wpt-dot accent"></div>
|
||
<div class="wpt-line"></div>
|
||
</div>
|
||
<div class="wpt-row-info">
|
||
<div class="wpt-row-name">Berlin Alexanderplatz</div>
|
||
</div>
|
||
</div>
|
||
<div class="wpt-row">
|
||
<div class="wpt-row-connector">
|
||
<div class="wpt-dot"></div>
|
||
<div class="wpt-line"></div>
|
||
</div>
|
||
<div class="wpt-row-info">
|
||
<div class="wpt-row-name" style="color:var(--text-md); font-weight:400; font-size:11px;">Zossen</div>
|
||
</div>
|
||
</div>
|
||
<div class="wpt-row">
|
||
<div class="wpt-row-connector">
|
||
<div class="wpt-dot"></div>
|
||
<div class="wpt-line"></div>
|
||
</div>
|
||
<div class="wpt-row-info">
|
||
<div class="wpt-row-name" style="color:var(--text-md); font-weight:400; font-size:11px;">Jüterbog</div>
|
||
</div>
|
||
</div>
|
||
<div class="wpt-row">
|
||
<div class="wpt-row-connector">
|
||
<div class="wpt-dot special"></div>
|
||
</div>
|
||
<div class="wpt-row-info">
|
||
<div class="wpt-row-name">
|
||
Dessau
|
||
<span class="wpt-tag">Overnight</span>
|
||
</div>
|
||
<div class="wpt-note">Elbe crossing — beautiful views</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Day 2 — collapsed -->
|
||
<div class="day-card">
|
||
<div class="day-card-head">
|
||
<span class="day-num">02</span>
|
||
<div class="day-info">
|
||
<div class="day-title">Dessau → Halle</div>
|
||
<div class="day-meta">↑ 310 m ascent</div>
|
||
</div>
|
||
<span class="day-km">130 km</span>
|
||
<span class="chevron">▶</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Day 3 — collapsed -->
|
||
<div class="day-card">
|
||
<div class="day-card-head">
|
||
<span class="day-num">03</span>
|
||
<div class="day-info">
|
||
<div class="day-title">Halle → Erfurt</div>
|
||
<div class="day-meta">↑ 218 m ascent</div>
|
||
</div>
|
||
<span class="day-km">93 km</span>
|
||
<span class="chevron">▶</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ELEVATION PANEL -->
|
||
<div class="elev-panel">
|
||
<div class="elev-header">
|
||
<span class="elev-eyebrow">Elevation profile</span>
|
||
<div class="elev-stats">
|
||
<span class="e-stat"><strong>343.3 km</strong> distance</span>
|
||
<span class="e-stat"><strong>↑ 868 m</strong> ascent</span>
|
||
</div>
|
||
</div>
|
||
<div class="elev-chart">
|
||
<svg width="100%" height="100%" viewBox="0 0 960 90" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="ec-line" x1="0%" y1="0%" x2="100%" y2="0%">
|
||
<stop offset="0%" style="stop-color:#5A8F46"/>
|
||
<stop offset="35%" style="stop-color:#9ABF50"/>
|
||
<stop offset="58%" style="stop-color:#C4A840"/>
|
||
<stop offset="78%" style="stop-color:#C46040"/>
|
||
<stop offset="100%" style="stop-color:#A03030"/>
|
||
</linearGradient>
|
||
<linearGradient id="ec-fill" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#4A6B40; stop-opacity:.18"/>
|
||
<stop offset="100%" style="stop-color:#4A6B40; stop-opacity:.02"/>
|
||
</linearGradient>
|
||
</defs>
|
||
|
||
<!-- Fill -->
|
||
<path d="M 0 84 L 48 76 L 96 72 L 144 69
|
||
L 192 67 L 240 65 L 288 63 L 320 68
|
||
L 352 62 L 384 58 L 416 55 L 448 57
|
||
L 480 53 L 520 49 L 560 45 L 600 42
|
||
L 640 46 L 672 50 L 710 53 L 748 56
|
||
L 786 52 L 830 47 L 870 44 L 910 46
|
||
L 960 41
|
||
L 960 90 L 0 90 Z"
|
||
fill="url(#ec-fill)"/>
|
||
|
||
<!-- Line -->
|
||
<path d="M 0 84 L 48 76 L 96 72 L 144 69
|
||
L 192 67 L 240 65 L 288 63 L 320 68
|
||
L 352 62 L 384 58 L 416 55 L 448 57
|
||
L 480 53 L 520 49 L 560 45 L 600 42
|
||
L 640 46 L 672 50 L 710 53 L 748 56
|
||
L 786 52 L 830 47 L 870 44 L 910 46
|
||
L 960 41"
|
||
stroke="url(#ec-line)" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||
|
||
<!-- Day dividers -->
|
||
<line x1="320" y1="4" x2="320" y2="90" stroke="var(--stop)" stroke-width="1" stroke-dasharray="4,4" opacity=".35"/>
|
||
<line x1="640" y1="4" x2="640" y2="90" stroke="var(--stop)" stroke-width="1" stroke-dasharray="4,4" opacity=".35"/>
|
||
|
||
<!-- Day labels -->
|
||
<text x="160" y="13" fill="var(--text-lo)" font-size="8" text-anchor="middle" font-family="Outfit,sans-serif" letter-spacing=".06em">Day 1</text>
|
||
<text x="480" y="13" fill="var(--text-lo)" font-size="8" text-anchor="middle" font-family="Outfit,sans-serif" letter-spacing=".06em">Day 2</text>
|
||
<text x="800" y="13" fill="var(--text-lo)" font-size="8" text-anchor="middle" font-family="Outfit,sans-serif" letter-spacing=".06em">Day 3</text>
|
||
|
||
<!-- Y axis labels -->
|
||
<text x="4" y="15" fill="var(--text-lo)" font-size="7.5" font-family="Geist Mono,monospace">286m</text>
|
||
<text x="4" y="89" fill="var(--text-lo)" font-size="7.5" font-family="Geist Mono,monospace">31m</text>
|
||
<text x="4" y="90" fill="var(--text-lo)" font-size="7" font-family="Geist Mono,monospace" dy="-1">0</text>
|
||
<text x="956" y="90" fill="var(--text-lo)" font-size="7" font-family="Geist Mono,monospace" text-anchor="end" dy="-1">342 km</text>
|
||
|
||
<!-- Hover crosshair -->
|
||
<line x1="448" y1="4" x2="448" y2="90" stroke="var(--stop)" stroke-width="1" opacity=".4"/>
|
||
<circle cx="448" cy="57" r="3.5" fill="var(--stop)"/>
|
||
<!-- Tooltip -->
|
||
<rect x="452" y="44" width="50" height="17" rx="4" fill="var(--bg-raised)" stroke="var(--border)" stroke-width="1"/>
|
||
<text x="477" y="57" fill="var(--text-hi)" font-size="8" text-anchor="middle" font-family="Geist Mono,monospace">km 171</text>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /desktop-frame -->
|
||
</div><!-- /page-section -->
|
||
</div><!-- /desktop screen -->
|
||
|
||
<!-- ╔══════════════╗ -->
|
||
<!-- ║ MOBILE ║ -->
|
||
<!-- ╚══════════════╝ -->
|
||
<div id="mobile" class="screen">
|
||
<div class="page-section" style="background:var(--bg-subtle); min-height:100vh;">
|
||
<div class="screen-label">Revised direction</div>
|
||
<div class="screen-heading">trails.cool — Mobile</div>
|
||
|
||
<div class="mobile-shell">
|
||
|
||
<!-- Mobile topbar -->
|
||
<div class="mob-topbar">
|
||
<!-- Logo -->
|
||
<div class="mob-logo">
|
||
<div class="mob-logo-mark">
|
||
<svg width="20" height="18" viewBox="0 0 128 128" fill="none">
|
||
<path d="M28 90 C45 90, 50 50, 64 45 S85 70, 100 35" stroke="var(--accent)" stroke-width="8" stroke-linecap="round" fill="none"/>
|
||
<circle cx="28" cy="90" r="13" fill="var(--accent)"/>
|
||
<circle cx="64" cy="45" r="13" fill="var(--accent)"/>
|
||
<circle cx="100" cy="35" r="13" fill="var(--accent)"/>
|
||
</svg>
|
||
</div>
|
||
trails<span>.cool</span>
|
||
</div>
|
||
<div class="mob-right">
|
||
<div class="mob-profile-select">
|
||
🚲 Cycling (safe)
|
||
<span style="color:var(--text-lo); font-size:9px;">▾</span>
|
||
</div>
|
||
<div class="mob-pax-zone">
|
||
<div class="mob-av-stack">
|
||
<div class="mob-av" style="background:#4A6B40;">Y</div>
|
||
<div class="mob-av" style="background:#6B7FA8;">A</div>
|
||
<div class="mob-av" style="background:#8B6D3A;">S</div>
|
||
<div class="mob-av-overflow">+3</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Map -->
|
||
<div class="mob-map">
|
||
<!-- Progress bar -->
|
||
<div class="progress-bar" style="position:absolute; top:0; z-index:50; width:62%;"></div>
|
||
|
||
<!-- No-go -->
|
||
<div class="nogo" style="left:56%; top:28%; width:62px; height:46px;"></div>
|
||
|
||
<!-- Route -->
|
||
<svg style="position:absolute;inset:0;z-index:5;pointer-events:none;" viewBox="0 0 390 290" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="mob-rte" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#5A8F46"/>
|
||
<stop offset="50%" style="stop-color:#C4A840"/>
|
||
<stop offset="100%" style="stop-color:#C46040"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<path d="M 195 30 C 185 65 175 100 168 138 C 160 178 154 210 149 240 C 146 258 144 271 142 282"
|
||
stroke="url(#mob-rte)" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round" opacity=".9"/>
|
||
</svg>
|
||
|
||
<!-- Waypoints -->
|
||
<div class="wpt" style="left:50%; top:10%;">
|
||
<div class="wpt-pin is-start">1</div>
|
||
<div class="wpt-label">Berlin</div>
|
||
</div>
|
||
<div class="wpt" style="left:36.4%; top:83%;">
|
||
<div class="wpt-overnight-badge">Night 1</div>
|
||
<div class="wpt-pin is-overnight" style="position:relative;">2<div class="wpt-note-dot"></div></div>
|
||
<div class="wpt-label">Dessau</div>
|
||
</div>
|
||
<div class="wpt" style="left:36.4%; top:97%; transform:translate(-50%,-100%);">
|
||
<div class="wpt-pin is-end">3</div>
|
||
<div class="wpt-label">Erfurt</div>
|
||
</div>
|
||
|
||
<!-- Day label -->
|
||
<div class="day-badge" style="left:43%; top:42%;">Day 1 · 120 km</div>
|
||
|
||
<!-- Cursor -->
|
||
<div class="cursor" style="left:56%; top:52%;">
|
||
<div class="cursor-dot" style="background:#6B7FA8;"></div>
|
||
<div class="cursor-label" style="background:#6B7FA8;">Alex</div>
|
||
</div>
|
||
|
||
<div class="map-credit" style="z-index:10;">© OpenStreetMap</div>
|
||
</div>
|
||
|
||
<!-- Bottom sheet -->
|
||
<div class="mob-sheet">
|
||
<div class="mob-sheet-handle"></div>
|
||
|
||
<div class="mob-sheet-summary">
|
||
<div>
|
||
<div class="mob-route-name">Berlin → Erfurt</div>
|
||
<div class="mob-route-via">3 days · via Dessau · Elevation gradient</div>
|
||
</div>
|
||
<div class="mob-stat-pills">
|
||
<span class="mob-stat-pill km">343 km</span>
|
||
<span class="mob-stat-pill">↑ 868 m</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mini elevation -->
|
||
<div class="mob-elev">
|
||
<svg width="100%" height="100%" viewBox="0 0 358 52" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="mob-ec" x1="0%" y1="0%" x2="100%" y2="0%">
|
||
<stop offset="0%" style="stop-color:#5A8F46"/>
|
||
<stop offset="50%" style="stop-color:#C4A840"/>
|
||
<stop offset="100%" style="stop-color:#C46040"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<path d="M 0 46 L 44 38 L 88 35 L 120 32 L 155 28 L 190 25 L 219 22 L 248 25 L 280 28 L 315 22 L 358 18 L 358 52 L 0 52 Z" fill="rgba(74,107,64,.12)"/>
|
||
<path d="M 0 46 L 44 38 L 88 35 L 120 32 L 155 28 L 190 25 L 219 22 L 248 25 L 280 28 L 315 22 L 358 18" stroke="url(#mob-ec)" stroke-width="1.8" fill="none" stroke-linecap="round"/>
|
||
<line x1="120" y1="0" x2="120" y2="52" stroke="var(--stop)" stroke-width=".8" stroke-dasharray="3,3" opacity=".35"/>
|
||
<line x1="240" y1="0" x2="240" y2="52" stroke="var(--stop)" stroke-width=".8" stroke-dasharray="3,3" opacity=".35"/>
|
||
<text x="60" y="50" fill="var(--text-lo)" font-size="7" font-family="Outfit,sans-serif" text-anchor="middle">Day 1</text>
|
||
<text x="180" y="50" fill="var(--text-lo)" font-size="7" font-family="Outfit,sans-serif" text-anchor="middle">Day 2</text>
|
||
<text x="299" y="50" fill="var(--text-lo)" font-size="7" font-family="Outfit,sans-serif" text-anchor="middle">Day 3</text>
|
||
</svg>
|
||
</div>
|
||
|
||
<!-- Tab bar -->
|
||
<div class="mob-tabs">
|
||
<button class="mob-tab active">Days</button>
|
||
<button class="mob-tab">Waypoints</button>
|
||
<button class="mob-tab">Notes</button>
|
||
</div>
|
||
|
||
<!-- Day list -->
|
||
<div class="mob-days">
|
||
<div class="mob-day-row">
|
||
<span class="mob-day-num">01</span>
|
||
<div class="mob-day-info">
|
||
<div class="mob-day-title">Berlin → Dessau</div>
|
||
<div class="mob-day-meta">↑ 340 m ascent</div>
|
||
</div>
|
||
<span class="mob-day-km">120 km</span>
|
||
</div>
|
||
<div class="mob-day-row">
|
||
<span class="mob-day-num">02</span>
|
||
<div class="mob-day-info">
|
||
<div class="mob-day-title">Dessau → Halle</div>
|
||
<div class="mob-day-meta">↑ 310 m ascent</div>
|
||
</div>
|
||
<span class="mob-day-km">130 km</span>
|
||
</div>
|
||
<div class="mob-day-row">
|
||
<span class="mob-day-num">03</span>
|
||
<div class="mob-day-info">
|
||
<div class="mob-day-title">Halle → Erfurt</div>
|
||
<div class="mob-day-meta">↑ 218 m ascent</div>
|
||
</div>
|
||
<span class="mob-day-km">93 km</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /mobile-shell -->
|
||
</div><!-- /page-section -->
|
||
</div><!-- /mobile screen -->
|
||
|
||
<script>
|
||
function show(id) {
|
||
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
||
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
|
||
document.getElementById(id).classList.add('active');
|
||
event.currentTarget.classList.add('active');
|
||
window.scrollTo(0,0);
|
||
}
|
||
|
||
function togglePanel() {
|
||
const panel = document.getElementById('pax-panel');
|
||
const isOpen = panel.style.display !== 'none';
|
||
panel.style.display = isOpen ? 'none' : 'block';
|
||
}
|
||
|
||
// Close panel when clicking outside
|
||
document.addEventListener('click', function(e) {
|
||
const zone = document.getElementById('pax-zone');
|
||
const panel = document.getElementById('pax-panel');
|
||
if (panel && !zone.contains(e.target)) {
|
||
panel.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
function copyLink() {
|
||
const btn = document.getElementById('copy-btn');
|
||
btn.textContent = 'Copied!';
|
||
btn.classList.add('copied');
|
||
setTimeout(() => {
|
||
btn.textContent = 'Copy';
|
||
btn.classList.remove('copied');
|
||
}, 2000);
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|